diff options
author | Scott Mayhew <smayhew@redhat.com> | 2019-03-26 18:06:26 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2019-04-24 09:46:34 -0400 |
commit | 6b1891052a3f8e3c3217e8512bbed2fd6252977b (patch) | |
tree | 4968ba406e795b3e4cd9fd7d245f1aede666f303 | |
parent | 9d69338c8c5fc68e9ae3ab23d01356ca024b789e (diff) |
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>
-rw-r--r-- | fs/nfsd/nfs4recover.c | 109 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 30 | ||||
-rw-r--r-- | fs/nfsd/state.h | 8 |
3 files changed, 110 insertions, 37 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 5188f9f70c78..2243b909b407 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -170,12 +170,33 @@ legacy_recdir_name_error(struct nfs4_client *clp, int error) | |||
170 | } | 170 | } |
171 | 171 | ||
172 | static void | 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 | nfsd4_create_clid_dir(struct nfs4_client *clp) | 195 | nfsd4_create_clid_dir(struct nfs4_client *clp) |
174 | { | 196 | { |
175 | const struct cred *original_cred; | 197 | const struct cred *original_cred; |
176 | char dname[HEXDIR_LEN]; | 198 | char dname[HEXDIR_LEN]; |
177 | struct dentry *dir, *dentry; | 199 | struct dentry *dir, *dentry; |
178 | struct nfs4_client_reclaim *crp; | ||
179 | int status; | 200 | int status; |
180 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | 201 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
181 | 202 | ||
@@ -221,11 +242,9 @@ out_put: | |||
221 | out_unlock: | 242 | out_unlock: |
222 | inode_unlock(d_inode(dir)); | 243 | inode_unlock(d_inode(dir)); |
223 | if (status == 0) { | 244 | if (status == 0) { |
224 | if (nn->in_grace) { | 245 | if (nn->in_grace) |
225 | crp = nfs4_client_to_reclaim(dname, nn); | 246 | __nfsd4_create_reclaim_record_grace(clp, dname, |
226 | if (crp) | 247 | HEXDIR_LEN, nn); |
227 | crp->cr_clp = clp; | ||
228 | } | ||
229 | vfs_fsync(nn->rec_file, 0); | 248 | vfs_fsync(nn->rec_file, 0); |
230 | } else { | 249 | } else { |
231 | printk(KERN_ERR "NFSD: failed to write recovery record" | 250 | printk(KERN_ERR "NFSD: failed to write recovery record" |
@@ -346,10 +365,29 @@ out_unlock: | |||
346 | } | 365 | } |
347 | 366 | ||
348 | static void | 367 | static void |
368 | __nfsd4_remove_reclaim_record_grace(const char *dname, int len, | ||
369 | struct nfsd_net *nn) | ||
370 | { | ||
371 | struct xdr_netobj name; | ||
372 | struct nfs4_client_reclaim *crp; | ||
373 | |||
374 | name.data = kmemdup(dname, len, GFP_KERNEL); | ||
375 | if (!name.data) { | ||
376 | dprintk("%s: failed to allocate memory for name.data!\n", | ||
377 | __func__); | ||
378 | return; | ||
379 | } | ||
380 | name.len = len; | ||
381 | crp = nfsd4_find_reclaim_client(name, nn); | ||
382 | kfree(name.data); | ||
383 | if (crp) | ||
384 | nfs4_remove_reclaim_record(crp, nn); | ||
385 | } | ||
386 | |||
387 | static void | ||
349 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | 388 | nfsd4_remove_clid_dir(struct nfs4_client *clp) |
350 | { | 389 | { |
351 | const struct cred *original_cred; | 390 | const struct cred *original_cred; |
352 | struct nfs4_client_reclaim *crp; | ||
353 | char dname[HEXDIR_LEN]; | 391 | char dname[HEXDIR_LEN]; |
354 | int status; | 392 | int status; |
355 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | 393 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
@@ -374,12 +412,9 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp) | |||
374 | nfs4_reset_creds(original_cred); | 412 | nfs4_reset_creds(original_cred); |
375 | if (status == 0) { | 413 | if (status == 0) { |
376 | vfs_fsync(nn->rec_file, 0); | 414 | vfs_fsync(nn->rec_file, 0); |
377 | if (nn->in_grace) { | 415 | if (nn->in_grace) |
378 | /* remove reclaim record */ | 416 | __nfsd4_remove_reclaim_record_grace(dname, |
379 | crp = nfsd4_find_reclaim_client(dname, nn); | 417 | HEXDIR_LEN, nn); |
380 | if (crp) | ||
381 | nfs4_remove_reclaim_record(crp, nn); | ||
382 | } | ||
383 | } | 418 | } |
384 | out_drop_write: | 419 | out_drop_write: |
385 | mnt_drop_write_file(nn->rec_file); | 420 | mnt_drop_write_file(nn->rec_file); |
@@ -393,14 +428,31 @@ static int | |||
393 | purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) | 428 | purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) |
394 | { | 429 | { |
395 | int status; | 430 | int status; |
431 | struct xdr_netobj name; | ||
396 | 432 | ||
397 | if (nfs4_has_reclaimed_state(child->d_name.name, nn)) | 433 | if (child->d_name.len != HEXDIR_LEN - 1) { |
434 | printk("%s: illegal name %pd in recovery directory\n", | ||
435 | __func__, child); | ||
436 | /* Keep trying; maybe the others are OK: */ | ||
398 | return 0; | 437 | return 0; |
438 | } | ||
439 | name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL); | ||
440 | if (!name.data) { | ||
441 | dprintk("%s: failed to allocate memory for name.data!\n", | ||
442 | __func__); | ||
443 | goto out; | ||
444 | } | ||
445 | name.len = HEXDIR_LEN; | ||
446 | if (nfs4_has_reclaimed_state(name, nn)) | ||
447 | goto out_free; | ||
399 | 448 | ||
400 | status = vfs_rmdir(d_inode(parent), child); | 449 | status = vfs_rmdir(d_inode(parent), child); |
401 | if (status) | 450 | if (status) |
402 | printk("failed to remove client recovery directory %pd\n", | 451 | printk("failed to remove client recovery directory %pd\n", |
403 | child); | 452 | child); |
453 | out_free: | ||
454 | kfree(name.data); | ||
455 | out: | ||
404 | /* Keep trying, success or failure: */ | 456 | /* Keep trying, success or failure: */ |
405 | return 0; | 457 | return 0; |
406 | } | 458 | } |
@@ -430,13 +482,24 @@ out: | |||
430 | static int | 482 | static int |
431 | load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) | 483 | load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) |
432 | { | 484 | { |
485 | struct xdr_netobj name; | ||
486 | |||
433 | if (child->d_name.len != HEXDIR_LEN - 1) { | 487 | if (child->d_name.len != HEXDIR_LEN - 1) { |
434 | printk("nfsd4: illegal name %pd in recovery directory\n", | 488 | printk("%s: illegal name %pd in recovery directory\n", |
435 | child); | 489 | __func__, child); |
436 | /* Keep trying; maybe the others are OK: */ | 490 | /* Keep trying; maybe the others are OK: */ |
437 | return 0; | 491 | return 0; |
438 | } | 492 | } |
439 | nfs4_client_to_reclaim(child->d_name.name, nn); | 493 | name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL); |
494 | if (!name.data) { | ||
495 | dprintk("%s: failed to allocate memory for name.data!\n", | ||
496 | __func__); | ||
497 | goto out; | ||
498 | } | ||
499 | name.len = HEXDIR_LEN; | ||
500 | if (!nfs4_client_to_reclaim(name, nn)) | ||
501 | kfree(name.data); | ||
502 | out: | ||
440 | return 0; | 503 | return 0; |
441 | } | 504 | } |
442 | 505 | ||
@@ -616,6 +679,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) | |||
616 | char dname[HEXDIR_LEN]; | 679 | char dname[HEXDIR_LEN]; |
617 | struct nfs4_client_reclaim *crp; | 680 | struct nfs4_client_reclaim *crp; |
618 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | 681 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); |
682 | struct xdr_netobj name; | ||
619 | 683 | ||
620 | /* did we already find that this client is stable? */ | 684 | /* did we already find that this client is stable? */ |
621 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) | 685 | if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) |
@@ -628,13 +692,22 @@ nfsd4_check_legacy_client(struct nfs4_client *clp) | |||
628 | } | 692 | } |
629 | 693 | ||
630 | /* look for it in the reclaim hashtable otherwise */ | 694 | /* look for it in the reclaim hashtable otherwise */ |
631 | crp = nfsd4_find_reclaim_client(dname, nn); | 695 | name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL); |
696 | if (!name.data) { | ||
697 | dprintk("%s: failed to allocate memory for name.data!\n", | ||
698 | __func__); | ||
699 | goto out_enoent; | ||
700 | } | ||
701 | name.len = HEXDIR_LEN; | ||
702 | crp = nfsd4_find_reclaim_client(name, nn); | ||
703 | kfree(name.data); | ||
632 | if (crp) { | 704 | if (crp) { |
633 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); | 705 | set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags); |
634 | crp->cr_clp = clp; | 706 | crp->cr_clp = clp; |
635 | return 0; | 707 | return 0; |
636 | } | 708 | } |
637 | 709 | ||
710 | out_enoent: | ||
638 | return -ENOENT; | 711 | return -ENOENT; |
639 | } | 712 | } |
640 | 713 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f056b1d3fecd..e601416aaf5f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1067,9 +1067,9 @@ static unsigned int clientid_hashval(u32 id) | |||
1067 | return id & CLIENT_HASH_MASK; | 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 | /* |
@@ -2048,11 +2048,6 @@ compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) | |||
2048 | return memcmp(o1->data, o2->data, o1->len); | 2048 | return memcmp(o1->data, o2->data, o1->len); |
2049 | } | 2049 | } |
2050 | 2050 | ||
2051 | static int same_name(const char *n1, const char *n2) | ||
2052 | { | ||
2053 | return 0 == memcmp(n1, n2, HEXDIR_LEN); | ||
2054 | } | ||
2055 | |||
2056 | static int | 2051 | static int |
2057 | same_verf(nfs4_verifier *v1, nfs4_verifier *v2) | 2052 | same_verf(nfs4_verifier *v1, nfs4_verifier *v2) |
2058 | { | 2053 | { |
@@ -6457,7 +6452,7 @@ alloc_reclaim(void) | |||
6457 | } | 6452 | } |
6458 | 6453 | ||
6459 | bool | 6454 | bool |
6460 | nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) | 6455 | nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) |
6461 | { | 6456 | { |
6462 | struct nfs4_client_reclaim *crp; | 6457 | struct nfs4_client_reclaim *crp; |
6463 | 6458 | ||
@@ -6467,20 +6462,24 @@ nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) | |||
6467 | 6462 | ||
6468 | /* | 6463 | /* |
6469 | * failure => all reset bets are off, nfserr_no_grace... | 6464 | * failure => all reset bets are off, nfserr_no_grace... |
6465 | * | ||
6466 | * The caller is responsible for freeing name.data if NULL is returned (it | ||
6467 | * will be freed in nfs4_remove_reclaim_record in the normal case). | ||
6470 | */ | 6468 | */ |
6471 | struct nfs4_client_reclaim * | 6469 | struct nfs4_client_reclaim * |
6472 | nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) | 6470 | nfs4_client_to_reclaim(struct xdr_netobj name, struct nfsd_net *nn) |
6473 | { | 6471 | { |
6474 | unsigned int strhashval; | 6472 | unsigned int strhashval; |
6475 | struct nfs4_client_reclaim *crp; | 6473 | struct nfs4_client_reclaim *crp; |
6476 | 6474 | ||
6477 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); | 6475 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", name.len, name.data); |
6478 | crp = alloc_reclaim(); | 6476 | crp = alloc_reclaim(); |
6479 | if (crp) { | 6477 | if (crp) { |
6480 | strhashval = clientstr_hashval(name); | 6478 | strhashval = clientstr_hashval(name); |
6481 | INIT_LIST_HEAD(&crp->cr_strhash); | 6479 | INIT_LIST_HEAD(&crp->cr_strhash); |
6482 | list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); | 6480 | list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); |
6483 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); | 6481 | crp->cr_name.data = name.data; |
6482 | crp->cr_name.len = name.len; | ||
6484 | crp->cr_clp = NULL; | 6483 | crp->cr_clp = NULL; |
6485 | nn->reclaim_str_hashtbl_size++; | 6484 | nn->reclaim_str_hashtbl_size++; |
6486 | } | 6485 | } |
@@ -6491,6 +6490,7 @@ void | |||
6491 | nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) | 6490 | nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) |
6492 | { | 6491 | { |
6493 | list_del(&crp->cr_strhash); | 6492 | list_del(&crp->cr_strhash); |
6493 | kfree(crp->cr_name.data); | ||
6494 | kfree(crp); | 6494 | kfree(crp); |
6495 | nn->reclaim_str_hashtbl_size--; | 6495 | nn->reclaim_str_hashtbl_size--; |
6496 | } | 6496 | } |
@@ -6514,16 +6514,16 @@ nfs4_release_reclaim(struct nfsd_net *nn) | |||
6514 | /* | 6514 | /* |
6515 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ | 6515 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ |
6516 | struct nfs4_client_reclaim * | 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 | unsigned int strhashval; | 6519 | unsigned int strhashval; |
6520 | struct nfs4_client_reclaim *crp = NULL; | 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 | list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { | 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 | return crp; | 6527 | return crp; |
6528 | } | 6528 | } |
6529 | } | 6529 | } |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 9d6cb246c6c5..0b74d371ed67 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -368,7 +368,7 @@ struct nfs4_client { | |||
368 | struct nfs4_client_reclaim { | 368 | struct nfs4_client_reclaim { |
369 | struct list_head cr_strhash; /* hash by cr_name */ | 369 | struct list_head cr_strhash; /* hash by cr_name */ |
370 | struct nfs4_client *cr_clp; /* pointer to associated clp */ | 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 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: | 374 | /* A reasonable value for REPLAY_ISIZE was estimated as follows: |
@@ -620,7 +620,7 @@ void nfs4_put_stid(struct nfs4_stid *s); | |||
620 | void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); | 620 | void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); |
621 | void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); | 621 | void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); |
622 | extern void nfs4_release_reclaim(struct nfsd_net *); | 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 | struct nfsd_net *nn); | 624 | struct nfsd_net *nn); |
625 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid, | 625 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid, |
626 | struct nfsd4_compound_state *cstate, struct nfsd_net *nn); | 626 | struct nfsd4_compound_state *cstate, struct nfsd_net *nn); |
@@ -635,9 +635,9 @@ extern void nfsd4_destroy_callback_queue(void); | |||
635 | extern void nfsd4_shutdown_callback(struct nfs4_client *); | 635 | extern void nfsd4_shutdown_callback(struct nfs4_client *); |
636 | extern void nfsd4_shutdown_copy(struct nfs4_client *clp); | 636 | extern void nfsd4_shutdown_copy(struct nfs4_client *clp); |
637 | extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp); | 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 | struct nfsd_net *nn); | 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 | struct nfs4_file *find_file(struct knfsd_fh *fh); | 642 | struct nfs4_file *find_file(struct knfsd_fh *fh); |
643 | void put_nfs4_file(struct nfs4_file *fi); | 643 | void put_nfs4_file(struct nfs4_file *fi); |