Skip to content

Commit 4552f4e

Browse files
neilbrownchucklever
authored andcommitted
nfsd: change nfs4_client_to_reclaim() to allocate data
The calling convention for nfs4_client_to_reclaim() is clumsy in that the caller needs to free memory if the function fails. It is much cleaner if the function frees its own memory. This patch changes nfs4_client_to_reclaim() to re-allocate the .data fields to be stored in the newly allocated struct nfs4_client_reclaim, and to free everything on failure. __cld_pipe_inprogress_downcall() needs to allocate the data anyway to copy it from user-space, so now that data is allocated twice. I think that is a small price to pay for a cleaner interface. Signed-off-by: NeilBrown <neil@brown.name> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 89bd77c commit 4552f4e

2 files changed

Lines changed: 42 additions & 47 deletions

File tree

fs/nfsd/nfs4recover.c

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -147,24 +147,13 @@ legacy_recdir_name_error(struct nfs4_client *clp, int error)
147147

148148
static void
149149
__nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
150-
const char *dname, int len, struct nfsd_net *nn)
150+
char *dname, struct nfsd_net *nn)
151151
{
152-
struct xdr_netobj name;
152+
struct xdr_netobj name = { .len = strlen(dname), .data = dname };
153153
struct xdr_netobj princhash = { .len = 0, .data = NULL };
154154
struct nfs4_client_reclaim *crp;
155155

156-
name.data = kmemdup(dname, len, GFP_KERNEL);
157-
if (!name.data) {
158-
dprintk("%s: failed to allocate memory for name.data!\n",
159-
__func__);
160-
return;
161-
}
162-
name.len = len;
163156
crp = nfs4_client_to_reclaim(name, princhash, nn);
164-
if (!crp) {
165-
kfree(name.data);
166-
return;
167-
}
168157
crp->cr_clp = clp;
169158
}
170159

@@ -223,8 +212,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
223212
inode_unlock(d_inode(dir));
224213
if (status == 0) {
225214
if (nn->in_grace)
226-
__nfsd4_create_reclaim_record_grace(clp, dname,
227-
HEXDIR_LEN, nn);
215+
__nfsd4_create_reclaim_record_grace(clp, dname, nn);
228216
vfs_fsync(nn->rec_file, 0);
229217
} else {
230218
printk(KERN_ERR "NFSD: failed to write recovery record"
@@ -461,7 +449,7 @@ nfsd4_recdir_purge_old(struct nfsd_net *nn)
461449
static int
462450
load_recdir(struct dentry *parent, char *cname, struct nfsd_net *nn)
463451
{
464-
struct xdr_netobj name;
452+
struct xdr_netobj name = { .len = HEXDIR_LEN, .data = cname };
465453
struct xdr_netobj princhash = { .len = 0, .data = NULL };
466454

467455
if (strlen(cname) != HEXDIR_LEN - 1) {
@@ -470,16 +458,7 @@ load_recdir(struct dentry *parent, char *cname, struct nfsd_net *nn)
470458
/* Keep trying; maybe the others are OK: */
471459
return 0;
472460
}
473-
name.data = kstrdup(cname, GFP_KERNEL);
474-
if (!name.data) {
475-
dprintk("%s: failed to allocate memory for name.data!\n",
476-
__func__);
477-
goto out;
478-
}
479-
name.len = HEXDIR_LEN;
480-
if (!nfs4_client_to_reclaim(name, princhash, nn))
481-
kfree(name.data);
482-
out:
461+
nfs4_client_to_reclaim(name, princhash, nn);
483462
return 0;
484463
}
485464

@@ -777,6 +756,8 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
777756
{
778757
uint8_t cmd, princhashlen;
779758
struct xdr_netobj name, princhash = { .len = 0, .data = NULL };
759+
char *namecopy __free(kfree) = NULL;
760+
char *princhashcopy __free(kfree) = NULL;
780761
uint16_t namelen;
781762

782763
if (get_user(cmd, &cmsg->cm_cmd)) {
@@ -794,19 +775,19 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
794775
dprintk("%s: invalid namelen (%u)", __func__, namelen);
795776
return -EINVAL;
796777
}
797-
name.data = memdup_user(&ci->cc_name.cn_id, namelen);
798-
if (IS_ERR(name.data))
799-
return PTR_ERR(name.data);
778+
namecopy = memdup_user(&ci->cc_name.cn_id, namelen);
779+
if (IS_ERR(namecopy))
780+
return PTR_ERR(namecopy);
781+
name.data = namecopy;
800782
name.len = namelen;
801783
get_user(princhashlen, &ci->cc_princhash.cp_len);
802784
if (princhashlen > 0) {
803-
princhash.data = memdup_user(
804-
&ci->cc_princhash.cp_data,
805-
princhashlen);
806-
if (IS_ERR(princhash.data)) {
807-
kfree(name.data);
808-
return PTR_ERR(princhash.data);
809-
}
785+
princhashcopy = memdup_user(
786+
&ci->cc_princhash.cp_data,
787+
princhashlen);
788+
if (IS_ERR(princhashcopy))
789+
return PTR_ERR(princhashcopy);
790+
princhash.data = princhashcopy;
810791
princhash.len = princhashlen;
811792
} else
812793
princhash.len = 0;
@@ -820,25 +801,23 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
820801
dprintk("%s: invalid namelen (%u)", __func__, namelen);
821802
return -EINVAL;
822803
}
823-
name.data = memdup_user(&cnm->cn_id, namelen);
824-
if (IS_ERR(name.data))
825-
return PTR_ERR(name.data);
804+
namecopy = memdup_user(&cnm->cn_id, namelen);
805+
if (IS_ERR(namecopy))
806+
return PTR_ERR(namecopy);
807+
name.data = namecopy;
826808
name.len = namelen;
827809
}
828810
#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
829811
if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) {
830812
struct cld_net *cn = nn->cld_net;
831813

832814
name.len = name.len - 5;
833-
memmove(name.data, name.data + 5, name.len);
815+
name.data = name.data + 5;
834816
cn->cn_has_legacy = true;
835817
}
836818
#endif
837-
if (!nfs4_client_to_reclaim(name, princhash, nn)) {
838-
kfree(name.data);
839-
kfree(princhash.data);
819+
if (!nfs4_client_to_reclaim(name, princhash, nn))
840820
return -EFAULT;
841-
}
842821
return nn->client_tracking_ops->msglen;
843822
}
844823
return -EFAULT;

fs/nfsd/nfs4state.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8801,9 +8801,6 @@ nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn)
88018801

88028802
/*
88038803
* failure => all reset bets are off, nfserr_no_grace...
8804-
*
8805-
* The caller is responsible for freeing name.data if NULL is returned (it
8806-
* will be freed in nfs4_remove_reclaim_record in the normal case).
88078804
*/
88088805
struct nfs4_client_reclaim *
88098806
nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash,
@@ -8812,6 +8809,22 @@ nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash,
88128809
unsigned int strhashval;
88138810
struct nfs4_client_reclaim *crp;
88148811

8812+
name.data = kmemdup(name.data, name.len, GFP_KERNEL);
8813+
if (!name.data) {
8814+
dprintk("%s: failed to allocate memory for name.data!\n",
8815+
__func__);
8816+
return NULL;
8817+
}
8818+
if (princhash.len) {
8819+
princhash.data = kmemdup(princhash.data, princhash.len, GFP_KERNEL);
8820+
if (!princhash.data) {
8821+
dprintk("%s: failed to allocate memory for princhash.data!\n",
8822+
__func__);
8823+
kfree(name.data);
8824+
return NULL;
8825+
}
8826+
} else
8827+
princhash.data = NULL;
88158828
crp = alloc_reclaim();
88168829
if (crp) {
88178830
strhashval = clientstr_hashval(name);
@@ -8823,6 +8836,9 @@ nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash,
88238836
crp->cr_princhash.len = princhash.len;
88248837
crp->cr_clp = NULL;
88258838
nn->reclaim_str_hashtbl_size++;
8839+
} else {
8840+
kfree(name.data);
8841+
kfree(princhash.data);
88268842
}
88278843
return crp;
88288844
}

0 commit comments

Comments
 (0)