Skip to content

Commit 6b18910

Browse files
scottmayhewJ. Bruce Fields
authored and
J. Bruce Fields
committed
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 <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent 9d69338 commit 6b18910

File tree

3 files changed

+110
-37
lines changed

3 files changed

+110
-37
lines changed

fs/nfsd/nfs4recover.c

Lines changed: 91 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,34 @@ legacy_recdir_name_error(struct nfs4_client *clp, int error)
169169
}
170170
}
171171

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+
172194
static void
173195
nfsd4_create_clid_dir(struct nfs4_client *clp)
174196
{
175197
const struct cred *original_cred;
176198
char dname[HEXDIR_LEN];
177199
struct dentry *dir, *dentry;
178-
struct nfs4_client_reclaim *crp;
179200
int status;
180201
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
181202

@@ -221,11 +242,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
221242
out_unlock:
222243
inode_unlock(d_inode(dir));
223244
if (status == 0) {
224-
if (nn->in_grace) {
225-
crp = nfs4_client_to_reclaim(dname, nn);
226-
if (crp)
227-
crp->cr_clp = clp;
228-
}
245+
if (nn->in_grace)
246+
__nfsd4_create_reclaim_record_grace(clp, dname,
247+
HEXDIR_LEN, nn);
229248
vfs_fsync(nn->rec_file, 0);
230249
} else {
231250
printk(KERN_ERR "NFSD: failed to write recovery record"
@@ -345,11 +364,30 @@ nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn)
345364
return status;
346365
}
347366

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+
348387
static void
349388
nfsd4_remove_clid_dir(struct nfs4_client *clp)
350389
{
351390
const struct cred *original_cred;
352-
struct nfs4_client_reclaim *crp;
353391
char dname[HEXDIR_LEN];
354392
int status;
355393
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
@@ -374,12 +412,9 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
374412
nfs4_reset_creds(original_cred);
375413
if (status == 0) {
376414
vfs_fsync(nn->rec_file, 0);
377-
if (nn->in_grace) {
378-
/* remove reclaim record */
379-
crp = nfsd4_find_reclaim_client(dname, nn);
380-
if (crp)
381-
nfs4_remove_reclaim_record(crp, nn);
382-
}
415+
if (nn->in_grace)
416+
__nfsd4_remove_reclaim_record_grace(dname,
417+
HEXDIR_LEN, nn);
383418
}
384419
out_drop_write:
385420
mnt_drop_write_file(nn->rec_file);
@@ -393,14 +428,31 @@ static int
393428
purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
394429
{
395430
int status;
431+
struct xdr_netobj name;
396432

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: */
398437
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;
399448

400449
status = vfs_rmdir(d_inode(parent), child);
401450
if (status)
402451
printk("failed to remove client recovery directory %pd\n",
403452
child);
453+
out_free:
454+
kfree(name.data);
455+
out:
404456
/* Keep trying, success or failure: */
405457
return 0;
406458
}
@@ -430,13 +482,24 @@ nfsd4_recdir_purge_old(struct nfsd_net *nn)
430482
static int
431483
load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
432484
{
485+
struct xdr_netobj name;
486+
433487
if (child->d_name.len != HEXDIR_LEN - 1) {
434-
printk("nfsd4: illegal name %pd in recovery directory\n",
435-
child);
488+
printk("%s: illegal name %pd in recovery directory\n",
489+
__func__, child);
436490
/* Keep trying; maybe the others are OK: */
437491
return 0;
438492
}
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:
440503
return 0;
441504
}
442505

@@ -616,6 +679,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
616679
char dname[HEXDIR_LEN];
617680
struct nfs4_client_reclaim *crp;
618681
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
682+
struct xdr_netobj name;
619683

620684
/* did we already find that this client is stable? */
621685
if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
@@ -628,13 +692,22 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
628692
}
629693

630694
/* 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);
632704
if (crp) {
633705
set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
634706
crp->cr_clp = clp;
635707
return 0;
636708
}
637709

710+
out_enoent:
638711
return -ENOENT;
639712
}
640713

fs/nfsd/nfs4state.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,9 +1067,9 @@ static unsigned int clientid_hashval(u32 id)
10671067
return id & CLIENT_HASH_MASK;
10681068
}
10691069

1070-
static unsigned int clientstr_hashval(const char *name)
1070+
static unsigned int clientstr_hashval(struct xdr_netobj name)
10711071
{
1072-
return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
1072+
return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK;
10731073
}
10741074

10751075
/*
@@ -2048,11 +2048,6 @@ compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
20482048
return memcmp(o1->data, o2->data, o1->len);
20492049
}
20502050

2051-
static int same_name(const char *n1, const char *n2)
2052-
{
2053-
return 0 == memcmp(n1, n2, HEXDIR_LEN);
2054-
}
2055-
20562051
static int
20572052
same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
20582053
{
@@ -6457,7 +6452,7 @@ alloc_reclaim(void)
64576452
}
64586453

64596454
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)
64616456
{
64626457
struct nfs4_client_reclaim *crp;
64636458

@@ -6467,20 +6462,24 @@ nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
64676462

64686463
/*
64696464
* 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).
64706468
*/
64716469
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)
64736471
{
64746472
unsigned int strhashval;
64756473
struct nfs4_client_reclaim *crp;
64766474

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);
64786476
crp = alloc_reclaim();
64796477
if (crp) {
64806478
strhashval = clientstr_hashval(name);
64816479
INIT_LIST_HEAD(&crp->cr_strhash);
64826480
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;
64846483
crp->cr_clp = NULL;
64856484
nn->reclaim_str_hashtbl_size++;
64866485
}
@@ -6491,6 +6490,7 @@ void
64916490
nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
64926491
{
64936492
list_del(&crp->cr_strhash);
6493+
kfree(crp->cr_name.data);
64946494
kfree(crp);
64956495
nn->reclaim_str_hashtbl_size--;
64966496
}
@@ -6514,16 +6514,16 @@ nfs4_release_reclaim(struct nfsd_net *nn)
65146514
/*
65156515
* called from OPEN, CLAIM_PREVIOUS with a new clientid. */
65166516
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)
65186518
{
65196519
unsigned int strhashval;
65206520
struct nfs4_client_reclaim *crp = NULL;
65216521

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);
65236523

6524-
strhashval = clientstr_hashval(recdir);
6524+
strhashval = clientstr_hashval(name);
65256525
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) {
65276527
return crp;
65286528
}
65296529
}

fs/nfsd/state.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ struct nfs4_client {
368368
struct nfs4_client_reclaim {
369369
struct list_head cr_strhash; /* hash by cr_name */
370370
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 */
372372
};
373373

374374
/* A reasonable value for REPLAY_ISIZE was estimated as follows:
@@ -620,7 +620,7 @@ void nfs4_put_stid(struct nfs4_stid *s);
620620
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
621621
void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *);
622622
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,
624624
struct nfsd_net *nn);
625625
extern __be32 nfs4_check_open_reclaim(clientid_t *clid,
626626
struct nfsd4_compound_state *cstate, struct nfsd_net *nn);
@@ -635,9 +635,9 @@ extern void nfsd4_destroy_callback_queue(void);
635635
extern void nfsd4_shutdown_callback(struct nfs4_client *);
636636
extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
637637
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,
639639
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);
641641

642642
struct nfs4_file *find_file(struct knfsd_fh *fh);
643643
void put_nfs4_file(struct nfs4_file *fi);

0 commit comments

Comments
 (0)