Commit 6b189105 authored by Scott Mayhew's avatar Scott Mayhew Committed by J. Bruce Fields
Browse files

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: default avatarScott Mayhew <smayhew@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 9d69338c
Loading
Loading
Loading
Loading
+91 −18
Original line number Diff line number Diff line
@@ -169,13 +169,34 @@ legacy_recdir_name_error(struct nfs4_client *clp, int error)
	}
}

static void
__nfsd4_create_reclaim_record_grace(struct nfs4_client *clp,
		const char *dname, int len, struct nfsd_net *nn)
{
	struct xdr_netobj name;
	struct nfs4_client_reclaim *crp;

	name.data = kmemdup(dname, len, GFP_KERNEL);
	if (!name.data) {
		dprintk("%s: failed to allocate memory for name.data!\n",
			__func__);
		return;
	}
	name.len = len;
	crp = nfs4_client_to_reclaim(name, nn);
	if (!crp) {
		kfree(name.data);
		return;
	}
	crp->cr_clp = clp;
}

static void
nfsd4_create_clid_dir(struct nfs4_client *clp)
{
	const struct cred *original_cred;
	char dname[HEXDIR_LEN];
	struct dentry *dir, *dentry;
	struct nfs4_client_reclaim *crp;
	int status;
	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);

@@ -221,11 +242,9 @@ out_put:
out_unlock:
	inode_unlock(d_inode(dir));
	if (status == 0) {
		if (nn->in_grace) {
			crp = nfs4_client_to_reclaim(dname, nn);
			if (crp)
				crp->cr_clp = clp;
		}
		if (nn->in_grace)
			__nfsd4_create_reclaim_record_grace(clp, dname,
					HEXDIR_LEN, nn);
		vfs_fsync(nn->rec_file, 0);
	} else {
		printk(KERN_ERR "NFSD: failed to write recovery record"
@@ -345,11 +364,30 @@ out_unlock:
	return status;
}

static void
__nfsd4_remove_reclaim_record_grace(const char *dname, int len,
		struct nfsd_net *nn)
{
	struct xdr_netobj name;
	struct nfs4_client_reclaim *crp;

	name.data = kmemdup(dname, len, GFP_KERNEL);
	if (!name.data) {
		dprintk("%s: failed to allocate memory for name.data!\n",
			__func__);
		return;
	}
	name.len = len;
	crp = nfsd4_find_reclaim_client(name, nn);
	kfree(name.data);
	if (crp)
		nfs4_remove_reclaim_record(crp, nn);
}

static void
nfsd4_remove_clid_dir(struct nfs4_client *clp)
{
	const struct cred *original_cred;
	struct nfs4_client_reclaim *crp;
	char dname[HEXDIR_LEN];
	int status;
	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
@@ -374,12 +412,9 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
	nfs4_reset_creds(original_cred);
	if (status == 0) {
		vfs_fsync(nn->rec_file, 0);
		if (nn->in_grace) {
			/* remove reclaim record */
			crp = nfsd4_find_reclaim_client(dname, nn);
			if (crp)
				nfs4_remove_reclaim_record(crp, nn);
		}
		if (nn->in_grace)
			__nfsd4_remove_reclaim_record_grace(dname,
					HEXDIR_LEN, nn);
	}
out_drop_write:
	mnt_drop_write_file(nn->rec_file);
@@ -393,14 +428,31 @@ static int
purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
{
	int status;
	struct xdr_netobj name;

	if (nfs4_has_reclaimed_state(child->d_name.name, nn))
	if (child->d_name.len != HEXDIR_LEN - 1) {
		printk("%s: illegal name %pd in recovery directory\n",
				__func__, child);
		/* Keep trying; maybe the others are OK: */
		return 0;
	}
	name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL);
	if (!name.data) {
		dprintk("%s: failed to allocate memory for name.data!\n",
			__func__);
		goto out;
	}
	name.len = HEXDIR_LEN;
	if (nfs4_has_reclaimed_state(name, nn))
		goto out_free;

	status = vfs_rmdir(d_inode(parent), child);
	if (status)
		printk("failed to remove client recovery directory %pd\n",
				child);
out_free:
	kfree(name.data);
out:
	/* Keep trying, success or failure: */
	return 0;
}
@@ -430,13 +482,24 @@ out:
static int
load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
{
	struct xdr_netobj name;

	if (child->d_name.len != HEXDIR_LEN - 1) {
		printk("nfsd4: illegal name %pd in recovery directory\n",
				child);
		printk("%s: illegal name %pd in recovery directory\n",
				__func__, child);
		/* Keep trying; maybe the others are OK: */
		return 0;
	}
	nfs4_client_to_reclaim(child->d_name.name, nn);
	name.data = kmemdup_nul(child->d_name.name, child->d_name.len, GFP_KERNEL);
	if (!name.data) {
		dprintk("%s: failed to allocate memory for name.data!\n",
			__func__);
		goto out;
	}
	name.len = HEXDIR_LEN;
	if (!nfs4_client_to_reclaim(name, nn))
		kfree(name.data);
out:
	return 0;
}

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

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

	/* look for it in the reclaim hashtable otherwise */
	crp = nfsd4_find_reclaim_client(dname, nn);
	name.data = kmemdup(dname, HEXDIR_LEN, GFP_KERNEL);
	if (!name.data) {
		dprintk("%s: failed to allocate memory for name.data!\n",
			__func__);
		goto out_enoent;
	}
	name.len = HEXDIR_LEN;
	crp = nfsd4_find_reclaim_client(name, nn);
	kfree(name.data);
	if (crp) {
		set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
		crp->cr_clp = clp;
		return 0;
	}

out_enoent:
	return -ENOENT;
}

+15 −15
Original line number Diff line number Diff line
@@ -1067,9 +1067,9 @@ static unsigned int clientid_hashval(u32 id)
	return id & CLIENT_HASH_MASK;
}

static unsigned int clientstr_hashval(const char *name)
static unsigned int clientstr_hashval(struct xdr_netobj name)
{
	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
	return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK;
}

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

static int same_name(const char *n1, const char *n2)
{
	return 0 == memcmp(n1, n2, HEXDIR_LEN);
}

static int
same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
{
@@ -6457,7 +6452,7 @@ alloc_reclaim(void)
}

bool
nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn)
{
	struct nfs4_client_reclaim *crp;

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

/*
 * failure => all reset bets are off, nfserr_no_grace...
 *
 * The caller is responsible for freeing name.data if NULL is returned (it
 * will be freed in nfs4_remove_reclaim_record in the normal case).
 */
struct nfs4_client_reclaim *
nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
nfs4_client_to_reclaim(struct xdr_netobj name, struct nfsd_net *nn)
{
	unsigned int strhashval;
	struct nfs4_client_reclaim *crp;

	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", name.len, name.data);
	crp = alloc_reclaim();
	if (crp) {
		strhashval = clientstr_hashval(name);
		INIT_LIST_HEAD(&crp->cr_strhash);
		list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
		memcpy(crp->cr_recdir, name, HEXDIR_LEN);
		crp->cr_name.data = name.data;
		crp->cr_name.len = name.len;
		crp->cr_clp = NULL;
		nn->reclaim_str_hashtbl_size++;
	}
@@ -6491,6 +6490,7 @@ void
nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
{
	list_del(&crp->cr_strhash);
	kfree(crp->cr_name.data);
	kfree(crp);
	nn->reclaim_str_hashtbl_size--;
}
@@ -6514,16 +6514,16 @@ nfs4_release_reclaim(struct nfsd_net *nn)
/*
 * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
struct nfs4_client_reclaim *
nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn)
{
	unsigned int strhashval;
	struct nfs4_client_reclaim *crp = NULL;

	dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
	dprintk("NFSD: nfs4_find_reclaim_client for name %.*s\n", name.len, name.data);

	strhashval = clientstr_hashval(recdir);
	strhashval = clientstr_hashval(name);
	list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
		if (same_name(crp->cr_recdir, recdir)) {
		if (compare_blob(&crp->cr_name, &name) == 0) {
			return crp;
		}
	}
+4 −4
Original line number Diff line number Diff line
@@ -368,7 +368,7 @@ struct nfs4_client {
struct nfs4_client_reclaim {
	struct list_head	cr_strhash;	/* hash by cr_name */
	struct nfs4_client	*cr_clp;	/* pointer to associated clp */
	char			cr_recdir[HEXDIR_LEN]; /* recover dir */
	struct xdr_netobj	cr_name;	/* recovery dir name */
};

/* A reasonable value for REPLAY_ISIZE was estimated as follows:  
@@ -620,7 +620,7 @@ void nfs4_put_stid(struct nfs4_stid *s);
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *);
extern void nfs4_release_reclaim(struct nfsd_net *);
extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir,
extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct xdr_netobj name,
							struct nfsd_net *nn);
extern __be32 nfs4_check_open_reclaim(clientid_t *clid,
		struct nfsd4_compound_state *cstate, struct nfsd_net *nn);
@@ -635,9 +635,9 @@ extern void nfsd4_destroy_callback_queue(void);
extern void nfsd4_shutdown_callback(struct nfs4_client *);
extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp);
extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name,
							struct nfsd_net *nn);
extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn);
extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn);

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