Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfsd: make nfs4_client_reclaim use an xdr_netobj instead of a fixed char array

This will allow the reclaim_str_hashtbl to store either the recovery
directory names used by the legacy client tracking code or the full
client strings used by the nfsdcld client tracking code.

Signed-off-by: Scott Mayhew <smayhew@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>

authored by

Scott Mayhew and committed by
J. Bruce Fields
6b189105 9d69338c

+110 -37
+91 -18
fs/nfsd/nfs4recover.c
··· 170 170 } 171 171 172 172 static void 173 + __nfsd4_create_reclaim_record_grace(struct nfs4_client *clp, 174 + const char *dname, int len, struct nfsd_net *nn) 175 + { 176 + struct xdr_netobj name; 177 + struct nfs4_client_reclaim *crp; 178 + 179 + name.data = kmemdup(dname, len, GFP_KERNEL); 180 + if (!name.data) { 181 + dprintk("%s: failed to allocate memory for name.data!\n", 182 + __func__); 183 + return; 184 + } 185 + name.len = len; 186 + crp = nfs4_client_to_reclaim(name, nn); 187 + if (!crp) { 188 + kfree(name.data); 189 + return; 190 + } 191 + crp->cr_clp = clp; 192 + } 193 + 194 + static void 173 195 nfsd4_create_clid_dir(struct nfs4_client *clp) 174 196 { 175 197 const struct cred *original_cred; 176 198 char dname[HEXDIR_LEN]; 177 199 struct dentry *dir, *dentry; 178 - struct nfs4_client_reclaim *crp; 179 200 int status; 180 201 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 181 202 ··· 242 221 out_unlock: 243 222 inode_unlock(d_inode(dir)); 244 223 if (status == 0) { 245 - if (nn->in_grace) { 246 - crp = nfs4_client_to_reclaim(dname, nn); 247 - if (crp) 248 - crp->cr_clp = clp; 249 - } 224 + if (nn->in_grace) 225 + __nfsd4_create_reclaim_record_grace(clp, dname, 226 + HEXDIR_LEN, nn); 250 227 vfs_fsync(nn->rec_file, 0); 251 228 } else { 252 229 printk(KERN_ERR "NFSD: failed to write recovery record" ··· 365 346 } 366 347 367 348 static void 349 + __nfsd4_remove_reclaim_record_grace(const char *dname, int len, 350 + struct nfsd_net *nn) 351 + { 352 + struct xdr_netobj name; 353 + struct nfs4_client_reclaim *crp; 354 + 355 + name.data = kmemdup(dname, len, GFP_KERNEL); 356 + if (!name.data) { 357 + dprintk("%s: failed to allocate memory for name.data!\n", 358 + __func__); 359 + return; 360 + } 361 + name.len = len; 362 + crp = nfsd4_find_reclaim_client(name, nn); 363 + kfree(name.data); 364 + if (crp) 365 + nfs4_remove_reclaim_record(crp, nn); 366 + } 367 + 368 + static void 368 369 nfsd4_remove_clid_dir(struct nfs4_client *clp) 369 370 { 370 371 const struct cred *original_cred; 371 - struct nfs4_client_reclaim *crp; 372 372 char dname[HEXDIR_LEN]; 373 373 int status; 374 374 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); ··· 412 374 nfs4_reset_creds(original_cred); 413 375 if (status == 0) { 414 376 vfs_fsync(nn->rec_file, 0); 415 - if (nn->in_grace) { 416 - /* remove reclaim record */ 417 - crp = nfsd4_find_reclaim_client(dname, nn); 418 - if (crp) 419 - nfs4_remove_reclaim_record(crp, nn); 420 - } 377 + if (nn->in_grace) 378 + __nfsd4_remove_reclaim_record_grace(dname, 379 + HEXDIR_LEN, nn); 421 380 } 422 381 out_drop_write: 423 382 mnt_drop_write_file(nn->rec_file); ··· 428 393 purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) 429 394 { 430 395 int status; 396 + struct xdr_netobj name; 431 397 432 - if (nfs4_has_reclaimed_state(child->d_name.name, nn)) 398 + if (child->d_name.len != HEXDIR_LEN - 1) { 399 + printk("%s: illegal name %pd in recovery directory\n", 400 + __func__, child); 401 + /* Keep trying; maybe the others are OK: */ 433 402 return 0; 403 + } 404 + name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL); 405 + if (!name.data) { 406 + dprintk("%s: failed to allocate memory for name.data!\n", 407 + __func__); 408 + goto out; 409 + } 410 + name.len = HEXDIR_LEN; 411 + if (nfs4_has_reclaimed_state(name, nn)) 412 + goto out_free; 434 413 435 414 status = vfs_rmdir(d_inode(parent), child); 436 415 if (status) 437 416 printk("failed to remove client recovery directory %pd\n", 438 417 child); 418 + out_free: 419 + kfree(name.data); 420 + out: 439 421 /* Keep trying, success or failure: */ 440 422 return 0; 441 423 } ··· 482 430 static int 483 431 load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) 484 432 { 433 + struct xdr_netobj name; 434 + 485 435 if (child->d_name.len != HEXDIR_LEN - 1) { 486 - printk("nfsd4: illegal name %pd in recovery directory\n", 487 - child); 436 + printk("%s: illegal name %pd in recovery directory\n", 437 + __func__, child); 488 438 /* Keep trying; maybe the others are OK: */ 489 439 return 0; 490 440 } 491 - nfs4_client_to_reclaim(child->d_name.name, nn); 441 + name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL); 442 + if (!name.data) { 443 + dprintk("%s: failed to allocate memory for name.data!\n", 444 + __func__); 445 + goto out; 446 + } 447 + name.len = HEXDIR_LEN; 448 + if (!nfs4_client_to_reclaim(name, nn)) 449 + kfree(name.data); 450 + out: 492 451 return 0; 493 452 } 494 453 ··· 679 616 char dname[HEXDIR_LEN]; 680 617 struct nfs4_client_reclaim *crp; 681 618 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 619 + struct xdr_netobj name; 682 620 683 621 /* did we already find that this client is stable? */ 684 622 if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) ··· 692 628 } 693 629 694 630 /* look for it in the reclaim hashtable otherwise */ 695 - crp = nfsd4_find_reclaim_client(dname, nn); 631 + name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL); 632 + if (!name.data) { 633 + dprintk("%s: failed to allocate memory for name.data!\n", 634 + __func__); 635 + goto out_enoent; 636 + } 637 + name.len = HEXDIR_LEN; 638 + crp = nfsd4_find_reclaim_client(name, nn); 639 + kfree(name.data); 696 640 if (crp) { 697 641 set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); 698 642 crp->cr_clp = clp; 699 643 return 0; 700 644 } 701 645 646 + out_enoent: 702 647 return -ENOENT; 703 648 } 704 649
+15 -15
fs/nfsd/nfs4state.c
··· 1067 1067 return id & CLIENT_HASH_MASK; 1068 1068 } 1069 1069 1070 - static unsigned int clientstr_hashval(const char *name) 1070 + static unsigned int clientstr_hashval(struct xdr_netobj name) 1071 1071 { 1072 - return opaque_hashval(name, 8) & CLIENT_HASH_MASK; 1072 + return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK; 1073 1073 } 1074 1074 1075 1075 /* ··· 2046 2046 if (o1->len > o2->len) 2047 2047 return 1; 2048 2048 return memcmp(o1->data, o2->data, o1->len); 2049 - } 2050 - 2051 - static int same_name(const char *n1, const char *n2) 2052 - { 2053 - return 0 == memcmp(n1, n2, HEXDIR_LEN); 2054 2049 } 2055 2050 2056 2051 static int ··· 6452 6457 } 6453 6458 6454 6459 bool 6455 - nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) 6460 + nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) 6456 6461 { 6457 6462 struct nfs4_client_reclaim *crp; 6458 6463 ··· 6462 6467 6463 6468 /* 6464 6469 * failure => all reset bets are off, nfserr_no_grace... 6470 + * 6471 + * The caller is responsible for freeing name.data if NULL is returned (it 6472 + * will be freed in nfs4_remove_reclaim_record in the normal case). 6465 6473 */ 6466 6474 struct nfs4_client_reclaim * 6467 - nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) 6475 + nfs4_client_to_reclaim(struct xdr_netobj name, struct nfsd_net *nn) 6468 6476 { 6469 6477 unsigned int strhashval; 6470 6478 struct nfs4_client_reclaim *crp; 6471 6479 6472 - dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); 6480 + dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", name.len, name.data); 6473 6481 crp = alloc_reclaim(); 6474 6482 if (crp) { 6475 6483 strhashval = clientstr_hashval(name); 6476 6484 INIT_LIST_HEAD(&crp->cr_strhash); 6477 6485 list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 6478 - memcpy(crp->cr_recdir, name, HEXDIR_LEN); 6486 + crp->cr_name.data = name.data; 6487 + crp->cr_name.len = name.len; 6479 6488 crp->cr_clp = NULL; 6480 6489 nn->reclaim_str_hashtbl_size++; 6481 6490 } ··· 6490 6491 nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 6491 6492 { 6492 6493 list_del(&crp->cr_strhash); 6494 + kfree(crp->cr_name.data); 6493 6495 kfree(crp); 6494 6496 nn->reclaim_str_hashtbl_size--; 6495 6497 } ··· 6514 6514 /* 6515 6515 * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 6516 6516 struct nfs4_client_reclaim * 6517 - nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) 6517 + nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) 6518 6518 { 6519 6519 unsigned int strhashval; 6520 6520 struct nfs4_client_reclaim *crp = NULL; 6521 6521 6522 - dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); 6522 + dprintk("NFSD: nfs4_find_reclaim_client for name %.*s\n", name.len, name.data); 6523 6523 6524 - strhashval = clientstr_hashval(recdir); 6524 + strhashval = clientstr_hashval(name); 6525 6525 list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 6526 - if (same_name(crp->cr_recdir, recdir)) { 6526 + if (compare_blob(&crp->cr_name, &name) == 0) { 6527 6527 return crp; 6528 6528 } 6529 6529 }
+4 -4
fs/nfsd/state.h
··· 368 368 struct nfs4_client_reclaim { 369 369 struct list_head cr_strhash; /* hash by cr_name */ 370 370 struct nfs4_client *cr_clp; /* pointer to associated clp */ 371 - char cr_recdir[HEXDIR_LEN]; /* recover dir */ 371 + struct xdr_netobj cr_name; /* recovery dir name */ 372 372 }; 373 373 374 374 /* A reasonable value for REPLAY_ISIZE was estimated as follows: ··· 620 620 void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); 621 621 void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); 622 622 extern void nfs4_release_reclaim(struct nfsd_net *); 623 - extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, 623 + extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct xdr_netobj name, 624 624 struct nfsd_net *nn); 625 625 extern __be32 nfs4_check_open_reclaim(clientid_t *clid, 626 626 struct nfsd4_compound_state *cstate, struct nfsd_net *nn); ··· 635 635 extern void nfsd4_shutdown_callback(struct nfs4_client *); 636 636 extern void nfsd4_shutdown_copy(struct nfs4_client *clp); 637 637 extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp); 638 - extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name, 638 + extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name, 639 639 struct nfsd_net *nn); 640 - extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn); 640 + extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn); 641 641 642 642 struct nfs4_file *find_file(struct knfsd_fh *fh); 643 643 void put_nfs4_file(struct nfs4_file *fi);