Skip to contentSkip to conversation

Introduction

PATCH New NeilBrown 1 participant 17 messages Apr 8, 2005

Subsystems (2)
lore
Share & tools
lore

NeilBrown

author
#0 lore raw

PATCH 1/1 Introduction

16 patches for knfsd.
The first three are bug fixes that would be good to get into 2.6.12 The rest are continuing work on tidying and extending the V4 server.

Thanks,
NeilBrown

[PATCH kNFSd 001 of 16] nfsd: clear signals before exiting the nfsd() thread [PATCH kNFSd 002 of 16] nfsd4: callback create rpc client returns [PATCH kNFSd 003 of 16] nfsd4: fix struct file leak

[PATCH kNFSd 004 of 16] nfsd4: find_delegation_file()
[PATCH kNFSd 005 of 16] nfsd4: nfs4_check_delegmode
[PATCH kNFSd 006 of 16] nfsd4: don't reopen for delegated client [PATCH kNFSd 007 of 16] nfsd4: add open state code for CLAIM_DELEGATE_CUR [PATCH kNFSd 008 of 16] nfsd4: support CLAIM_DELEGATE_CUR [PATCH kNFSd 009 of 16] nfsd4: fix fh_expire_type
[PATCH kNFSd 010 of 16] nfsd4: block metadata ops during grace period [PATCH kNFSd 011 of 16] nfsd4: slabify nfs4_files
[PATCH kNFSd 012 of 16] nfsd4: slabify stateids
[PATCH kNFSd 013 of 16] nfsd4: slabify delegations
[PATCH kNFSd 014 of 16] nfsd4: remove debugging counters [PATCH kNFSd 015 of 16] nfsd4: rename nfs4_file fields
[PATCH kNFSd 016 of 16] nfsd4: reference count struct nfs4_file

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#1 lore raw

PATCH 1/1 nfsd: clear signals before exiting the nfsd() thread

Fixes the error "RPC: failed to contact portmap (errno -512)." when the server later tries to unregister from the portmapper.

### Diffstat output

 ./fs/nfsd/nfssvc.c |    2 ++
 1 files changed, 2 insertions(+)
fs/nfsd/nfssvc.c renamed from fs/nfsd/nfssvc.c~current~ +2 -0
diff ./fs/nfsd/nfssvc.c~current~ ./fs/nfsd/nfssvc.c
@@ -259,6 +259,8 @@ nfsd(struct svc_rqst *rqstp)
 				break;
 		err = signo;
 	}
+	/* Clear signals before calling lockd_down() and svc_exit_thread() */
+	flush_signals(current);
 
 	lock_kernel();
 

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#2 lore raw

PATCH 1/1 nfsd4: callback create rpc client returns

In reply to NeilBrown

rpc_create_clnt and friends return errors, not NULL, on failure.

### Diffstat output

 ./fs/nfsd/nfs4callback.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
fs/nfsd/nfs4callback.c renamed from fs/nfsd/nfs4callback.c~current~ +4 -2
diff ./fs/nfsd/nfs4callback.c~current~ ./fs/nfsd/nfs4callback.c
@@ -405,7 +405,8 @@ nfsd4_probe_callback(struct nfs4_client 
 	timeparms.to_exponential = 1;
 
 	/* Create RPC transport */
-	if (!(xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms))) {
+	xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms);
+	if (IS_ERR(xprt)) {
 		dprintk("NFSD: couldn't create callback transport!\n");
 		goto out_err;
 	}
@@ -426,7 +427,8 @@ nfsd4_probe_callback(struct nfs4_client 
 	 * XXX AUTH_UNIX only - need AUTH_GSS....
 	 */
 	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr));
-	if (!(clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX))) {
+	clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
+	if (IS_ERR(clnt)) {
 		dprintk("NFSD: couldn't create callback client\n");
 		goto out_err;
 	}

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#3 lore raw

PATCH 1/1 nfsd4: find_delegation_file()

In reply to NeilBrown

Factor out a bit of common code that will be useful elsewhere.

### Diffstat output

 ./fs/nfsd/nfs4state.c |   25 ++++++++++++++-----------
 1 files changed, 14 insertions(+), 11 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +14 -11
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -1526,6 +1526,18 @@ out:
 	return status;
 }
 
+static struct nfs4_delegation *
+find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
+{
+	struct nfs4_delegation *dp;
+
+	list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) {
+		if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
+			return dp;
+	}
+	return NULL;
+}
+
 static int
 nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
 {
@@ -2419,24 +2431,15 @@ find_stateid(stateid_t *stid, int flags)
 static struct nfs4_delegation *
 find_delegation_stateid(struct inode *ino, stateid_t *stid)
 {
-	struct nfs4_delegation *dp = NULL;
 	struct nfs4_file *fp = NULL;
-	u32 st_id;
 
 	dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n",
                     stid->si_boot, stid->si_stateownerid,
                     stid->si_fileid, stid->si_generation);
 
-	st_id = stid->si_stateownerid;
 	fp = find_file(ino);
-	if (fp) {
-		list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) {
-			if(dp->dl_stateid.si_stateownerid == st_id) {
-				dprintk("NFSD: find_delegation dp %p\n",dp);
-				return dp;
-			}
-		}
-	}
+	if (fp)
+		return find_delegation_file(fp, stid);
 	return NULL;
 }
 

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#4 lore raw

PATCH 1/1 nfsd4: nfs4_check_delegmode

In reply to NeilBrown

Additional minor code reshuffling to prepare for claim_deleg_cur support.

### Diffstat output

 ./fs/nfsd/nfs4state.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +9 -9
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -1526,6 +1526,15 @@ out:
 	return status;
 }
 
+static inline int
+nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
+{
+	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
+		return nfserr_openmode;
+	else
+		return nfs_ok;
+}
+
 static struct nfs4_delegation *
 find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
 {
@@ -1961,15 +1970,6 @@ out:
 }
 
 static inline int
-nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
-{
-	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
-		return nfserr_openmode;
-	else
-		return nfs_ok;
-}
-
-static inline int
 check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
 {
 	/* Trying to call delegreturn with a special stateid? Yuch: */

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#5 lore raw

PATCH 1/1 nfsd4: don't reopen for delegated client

In reply to NeilBrown

We don't really need to be doing a separate open for every stateid. And in the case of an open from a client that already has a delegation on a file, it unnecessarily results in a delegation recall.

### Diffstat output

 ./fs/nfsd/nfs4state.c |   44 ++++++++++++++++++++++++++++++++++++--------
 1 files changed, 36 insertions(+), 8 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +36 -8
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -1547,6 +1547,24 @@ find_delegation_file(struct nfs4_file *f
 	return NULL;
 }
 
+static void
+nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
+		struct nfs4_delegation **dp)
+{
+	int flags;
+	int status;
+
+	*dp = find_delegation_file(fp, &open->op_delegate_stateid);
+	if (*dp == NULL)
+		return;
+	flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?
+						RD_STATE : WR_STATE;
+	status = nfs4_check_delegmode(*dp, flags);
+	if (status)
+		*dp = NULL;
+	return;
+}
+
 static int
 nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
 {
@@ -1572,21 +1590,28 @@ out:
 
 static int
 nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
+		struct nfs4_delegation *dp,
 		struct svc_fh *cur_fh, int flags)
 {
 	struct nfs4_stateid *stp;
-	int status;
 
 	stp = kmalloc(sizeof(struct nfs4_stateid), GFP_KERNEL);
 	if (stp == NULL)
 		return nfserr_resource;
 
-	status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, &stp->st_vfs_file);
-	if (status) {
-		if (status == nfserr_dropit)
-			status = nfserr_jukebox;
-		kfree(stp);
-		return status;
+	if (dp) {
+		get_file(dp->dl_vfs_file);
+		stp->st_vfs_file = dp->dl_vfs_file;
+	} else {
+		int status;
+		status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
+				&stp->st_vfs_file);
+		if (status) {
+			if (status == nfserr_dropit)
+				status = nfserr_jukebox;
+			kfree(stp);
+			return status;
+		}
 	}
 	vfsopen++;
 	*stpp = stp;
@@ -1720,6 +1745,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	struct nfs4_file *fp = NULL;
 	struct inode *ino = current_fh->fh_dentry->d_inode;
 	struct nfs4_stateid *stp = NULL;
+	struct nfs4_delegation *dp = NULL;
 	int status;
 
 	status = nfserr_inval;
@@ -1734,6 +1760,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	if (fp) {
 		if ((status = nfs4_check_open(fp, open, &stp)))
 			goto out;
+		nfs4_check_deleg(fp, open, &dp);
 	} else {
 		status = nfserr_resource;
 		fp = alloc_init_file(ino);
@@ -1757,7 +1784,8 @@ nfsd4_process_open2(struct svc_rqst *rqs
 			flags = MAY_WRITE;
 		else
 			flags = MAY_READ;
-		if ((status = nfs4_new_open(rqstp, &stp, current_fh, flags)))
+		status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
+		if (status)
 			goto out;
 		init_stateid(stp, fp, open);
 		status = nfsd4_truncate(rqstp, current_fh, open);

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#6 lore raw

PATCH 1/1 nfsd4: add open state code for CLAIM_DELEGATE_CUR

In reply to NeilBrown

State logic for OPEN with claim type CLAIM_DELEGATE_CUR, which the NFSv4 client uses to report local OPENs on a delegated file back to the NFSv4 server.

nfs4_check_deleg() performs input delegation stateid lookup and sanity check.

### Diffstat output

 ./fs/nfsd/nfs4state.c |   21 ++++++++++++++++-----
 1 files changed, 16 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +16 -5
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -1547,22 +1547,28 @@ find_delegation_file(struct nfs4_file *f
 	return NULL;
 }
 
-static void
+static int
 nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
 		struct nfs4_delegation **dp)
 {
 	int flags;
-	int status;
+	int status = nfserr_bad_stateid;
 
 	*dp = find_delegation_file(fp, &open->op_delegate_stateid);
 	if (*dp == NULL)
-		return;
+		goto out;
 	flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?
 						RD_STATE : WR_STATE;
 	status = nfs4_check_delegmode(*dp, flags);
 	if (status)
 		*dp = NULL;
-	return;
+out:
+	if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR)
+		return nfs_ok;
+	if (status)
+		return status;
+	open->op_stateowner->so_confirmed = 1;
+	return nfs_ok;
 }
 
 static int
@@ -1760,8 +1766,13 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	if (fp) {
 		if ((status = nfs4_check_open(fp, open, &stp)))
 			goto out;
-		nfs4_check_deleg(fp, open, &dp);
+		status = nfs4_check_deleg(fp, open, &dp);
+		if (status)
+			goto out;
 	} else {
+		status = nfserr_bad_stateid;
+		if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
+			goto out;
 		status = nfserr_resource;
 		fp = alloc_init_file(ino);
 		if (fp == NULL)

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#7 lore raw

PATCH 1/1 nfsd4: support CLAIM_DELEGATE_CUR

In reply to NeilBrown

Add OPEN claim type NFS4_OPEN_CLAIM_DELEGATE_CUR to nfsd4_open().

A delegation stateid and a name are provided. OPEN with O_CREAT is not legal with this claim type; otherwise, use the NFS4_OPEN_CLAIM_NULL code path to lookup the filename to be opened.

### Diffstat output

 ./fs/nfsd/nfs4proc.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletion(-)
fs/nfsd/nfs4proc.c renamed from fs/nfsd/nfs4proc.c~current~ +5 -1
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
@@ -198,6 +198,11 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 	if (status)
 		goto out;
 	switch (open->op_claim_type) {
+		case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+			status = nfserr_inval;
+			if (open->op_create)
+				goto out;
+			/* fall through */
 		case NFS4_OPEN_CLAIM_NULL:
 			/*
 			 * (1) set CURRENT_FH to the file being opened,
@@ -220,7 +225,6 @@ nfsd4_open(struct svc_rqst *rqstp, struc
 			if (status)
 				goto out;
 			break;
-		case NFS4_OPEN_CLAIM_DELEGATE_CUR:
              	case NFS4_OPEN_CLAIM_DELEGATE_PREV:
 			printk("NFSD: unsupported OPEN claim type %d\n",
 				open->op_claim_type);

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#8 lore raw

PATCH 1/1 nfsd4: fix fh_expire_type

In reply to NeilBrown

We're returning NFS4_FH_NOEXPIRE_WITH_OPEN | NFS4_FH_VOL_RENAME for the fh_expire_type attribute. This is incorrect:
1. The spec actually only allows NOEXPIRE_WITH_OPEN when VOLATILE_ANY is also set.
2. Filehandles for open files can expire, if the file is removed and there is a reboot.
3. Filehandles are only volatile on rename in the nosubtree check case.

Unfortunately, there's no way to indicate that we only expire on remove. So our only choice is FH4_VOLATILE_ANY. Although it's redundant, we also set FH4_VOL_RENAME in the subtree check case, since subtreecheck does actually cause problems in practice and it seems possibly useful to give clients some way to distinguish that case.

Fix a mispelled #define while we're at it.

### Diffstat output

 ./fs/nfsd/nfs4xdr.c    |    5 ++++-
 ./include/linux/nfs4.h |    2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)
fs/nfsd/nfs4xdr.c renamed from fs/nfsd/nfs4xdr.c~current~ +4 -1
diff ./fs/nfsd/nfs4xdr.c~current~ ./fs/nfsd/nfs4xdr.c
@@ -1366,7 +1366,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
 	if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
 		if ((buflen -= 4) < 0)
 			goto out_resource;
-		WRITE32( NFS4_FH_NOEXPIRE_WITH_OPEN | NFS4_FH_VOL_RENAME );
+		if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
+			WRITE32(NFS4_FH_VOLATILE_ANY);
+		else
+			WRITE32(NFS4_FH_VOLATILE_ANY|NFS4_FH_VOL_RENAME);
 	}
 	if (bmval0 & FATTR4_WORD0_CHANGE) {
 		/*
include/linux/nfs4.h renamed from include/linux/nfs4.h~current~ +1 -1
diff ./include/linux/nfs4.h~current~ ./include/linux/nfs4.h
@@ -28,7 +28,7 @@
 #define NFS4_ACCESS_DELETE      0x0010
 #define NFS4_ACCESS_EXECUTE     0x0020
 
-#define NFS4_FH_PERISTENT		0x0000
+#define NFS4_FH_PERSISTENT		0x0000
 #define NFS4_FH_NOEXPIRE_WITH_OPEN	0x0001
 #define NFS4_FH_VOLATILE_ANY		0x0002
 #define NFS4_FH_VOL_MIGRATION		0x0004

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#9 lore raw

PATCH 1/1 nfsd4: block metadata ops during grace period

In reply to NeilBrown

We currently return err_grace if a user attempts a non-reclaim open during the grace period. But we also need to prevent renames and removes, at least, to ensure clients have the chance to recover state on files before they are moved or deleted.

Of course, local users could also do renames and removes during the lease period, and there's not much we can do about that. This at least will help with remote users.

### Diffstat output

 ./fs/nfsd/nfs4proc.c |    5 +++++
 1 files changed, 5 insertions(+)
fs/nfsd/nfs4proc.c renamed from fs/nfsd/nfs4proc.c~current~ +5 -0
diff ./fs/nfsd/nfs4proc.c~current~ ./fs/nfsd/nfs4proc.c
@@ -536,6 +536,8 @@ nfsd4_remove(struct svc_rqst *rqstp, str
 {
 	int status;
 
+	if (nfs4_in_grace())
+		return nfserr_grace;
 	status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen);
 	if (status == nfserr_symlink)
 		return nfserr_notdir;
@@ -554,6 +556,9 @@ nfsd4_rename(struct svc_rqst *rqstp, str
 
 	if (!save_fh->fh_dentry)
 		return status;
+	if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags
+					& NFSEXP_NOSUBTREECHECK))
+		return nfserr_grace;
 	status = nfsd_rename(rqstp, save_fh, rename->rn_sname,
 			     rename->rn_snamelen, current_fh,
 			     rename->rn_tname, rename->rn_tnamelen);

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#10 lore raw

PATCH 1/1 nfsd4: slabify nfs4_files

In reply to NeilBrown

The structures the server uses to keep track of various pieces of nfsv4 state (open files, outstanding delegations, etc.) are likely to be allocated and deallocated frequently and seem reasonable candidates for slab caches.

While we're at it, the slab code keeps statistics that help catch leaks and such, so we may as well take this chance to eliminate some debugging counters that we've been keeping ourselves.

Start with the struct nfs4_file.

### Diffstat output

 ./fs/nfsd/nfs4state.c |   58 +++++++++++++++++++++++++++++---------------------
 1 files changed, 34 insertions(+), 24 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +34 -24
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -70,8 +70,6 @@ u32 list_add_perfile = 0; 
 u32 list_del_perfile = 0;
 u32 add_perclient = 0;
 u32 del_perclient = 0;
-u32 alloc_file = 0;
-u32 free_file = 0;
 u32 vfsopen = 0;
 u32 vfsclose = 0;
 u32 alloc_delegation= 0;
@@ -90,6 +88,9 @@ static void release_stateid_lockowners(s
  */
 static DECLARE_MUTEX(client_sema);
 
+kmem_cache_t *stateowner_slab = NULL;
+kmem_cache_t *file_slab = NULL;
+
 void
 nfs4_lock_state(void)
 {
@@ -961,14 +962,14 @@ alloc_init_file(struct inode *ino)
 	struct nfs4_file *fp;
 	unsigned int hashval = file_hashval(ino);
 
-	if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) {
+	fp = kmem_cache_alloc(file_slab, GFP_KERNEL);
+	if (fp) {
 		INIT_LIST_HEAD(&fp->fi_hash);
 		INIT_LIST_HEAD(&fp->fi_perfile);
 		INIT_LIST_HEAD(&fp->fi_del_perfile);
 		list_add(&fp->fi_hash, &file_hashtbl[hashval]);
 		fp->fi_inode = igrab(ino);
 		fp->fi_id = current_fileid++;
-		alloc_file++;
 		return fp;
 	}
 	return NULL;
@@ -992,29 +993,41 @@ release_all_files(void)
 	}
 }
 
-kmem_cache_t *stateowner_slab = NULL;
-
-static int
-nfsd4_init_slabs(void)
+static void
+nfsd4_free_slab(kmem_cache_t **slab)
 {
-	stateowner_slab = kmem_cache_create("nfsd4_stateowners",
-			sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
-	if (stateowner_slab == NULL) {
-		dprintk("nfsd4: out of memory while initializing nfsv4\n");
-		return -ENOMEM;
-	}
-	return 0;
+	int status;
+
+	if (*slab == NULL)
+		return;
+	status = kmem_cache_destroy(*slab);
+	*slab = NULL;
+	WARN_ON(status);
 }
 
 static void
 nfsd4_free_slabs(void)
 {
-	int status = 0;
+	nfsd4_free_slab(&stateowner_slab);
+	nfsd4_free_slab(&file_slab);
+}
 
-	if (stateowner_slab)
-		status = kmem_cache_destroy(stateowner_slab);
-	stateowner_slab = NULL;
-	BUG_ON(status);
+static int
+nfsd4_init_slabs(void)
+{
+	stateowner_slab = kmem_cache_create("nfsd4_stateowners",
+			sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
+	if (stateowner_slab == NULL)
+		goto out_nomem;
+	file_slab = kmem_cache_create("nfsd4_files",
+			sizeof(struct nfs4_file), 0, 0, NULL, NULL);
+	if (file_slab == NULL)
+		goto out_nomem;
+	return 0;
+out_nomem:
+	nfsd4_free_slabs();
+	dprintk("nfsd4: out of memory while initializing nfsv4\n");
+	return -ENOMEM;
 }
 
 void
@@ -1167,10 +1180,9 @@ release_stateid(struct nfs4_stateid *stp
 static void
 release_file(struct nfs4_file *fp)
 {
-	free_file++;
 	list_del(&fp->fi_hash);
 	iput(fp->fi_inode);
-	kfree(fp);
+	kmem_cache_free(file_slab, fp);
 }	
 
 void
@@ -3286,8 +3298,6 @@ __nfs4_state_shutdown(void)
 			list_add_perfile, list_del_perfile);
 	dprintk("NFSD: add_perclient %d del_perclient %d\n",
 			add_perclient, del_perclient);
-	dprintk("NFSD: alloc_file %d free_file %d\n",
-			alloc_file, free_file);
 	dprintk("NFSD: vfsopen %d vfsclose %d\n",
 			vfsopen, vfsclose);
 	dprintk("NFSD: alloc_delegation %d free_delegation %d\n",

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#11 lore raw

PATCH 1/1 nfsd4: slabify stateids

In reply to NeilBrown

Allocate stateid's from a slab cache.

### Diffstat output

 ./fs/nfsd/nfs4state.c |   22 +++++++++++++++++-----
 1 files changed, 17 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +17 -5
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -90,6 +90,7 @@ static DECLARE_MUTEX(client_sema);
 
 kmem_cache_t *stateowner_slab = NULL;
 kmem_cache_t *file_slab = NULL;
+kmem_cache_t *stateid_slab = NULL;
 
 void
 nfs4_lock_state(void)
@@ -1010,6 +1011,7 @@ nfsd4_free_slabs(void)
 {
 	nfsd4_free_slab(&stateowner_slab);
 	nfsd4_free_slab(&file_slab);
+	nfsd4_free_slab(&stateid_slab);
 }
 
 static int
@@ -1023,6 +1025,10 @@ nfsd4_init_slabs(void)
 			sizeof(struct nfs4_file), 0, 0, NULL, NULL);
 	if (file_slab == NULL)
 		goto out_nomem;
+	stateid_slab = kmem_cache_create("nfsd4_stateids",
+			sizeof(struct nfs4_stateid), 0, 0, NULL, NULL);
+	if (stateid_slab == NULL)
+		goto out_nomem;
 	return 0;
 out_nomem:
 	nfsd4_free_slabs();
@@ -1173,7 +1179,7 @@ release_stateid(struct nfs4_stateid *stp
 		vfsclose++;
 	} else if (flags & LOCK_STATE)
 		locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
-	kfree(stp);
+	kmem_cache_free(stateid_slab, stp);
 	stp = NULL;
 }
 
@@ -1606,6 +1612,12 @@ out:
 	return status;
 }
 
+static inline struct nfs4_stateid *
+nfs4_alloc_stateid(void)
+{
+	return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
+}
+
 static int
 nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
 		struct nfs4_delegation *dp,
@@ -1613,7 +1625,7 @@ nfs4_new_open(struct svc_rqst *rqstp, st
 {
 	struct nfs4_stateid *stp;
 
-	stp = kmalloc(sizeof(struct nfs4_stateid), GFP_KERNEL);
+	stp = nfs4_alloc_stateid();
 	if (stp == NULL)
 		return nfserr_resource;
 
@@ -1627,7 +1639,7 @@ nfs4_new_open(struct svc_rqst *rqstp, st
 		if (status) {
 			if (status == nfserr_dropit)
 				status = nfserr_jukebox;
-			kfree(stp);
+			kmem_cache_free(stateid_slab, stp);
 			return status;
 		}
 	}
@@ -2627,8 +2639,8 @@ alloc_init_lock_stateid(struct nfs4_stat
 	struct nfs4_stateid *stp;
 	unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
 
-	if ((stp = kmalloc(sizeof(struct nfs4_stateid), 
-					GFP_KERNEL)) == NULL)
+	stp = nfs4_alloc_stateid();
+	if (stp == NULL)
 		goto out;
 	INIT_LIST_HEAD(&stp->st_hash);
 	INIT_LIST_HEAD(&stp->st_perfile);

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#12 lore raw

PATCH 1/1 nfsd4: slabify delegations

In reply to NeilBrown

Allocate delegations from a slab cache.

### Diffstat output

 ./fs/nfsd/nfs4state.c |   19 +++++++++----------
 1 files changed, 9 insertions(+), 10 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +9 -10
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -72,8 +72,6 @@ u32 add_perclient = 0;
 u32 del_perclient = 0;
 u32 vfsopen = 0;
 u32 vfsclose = 0;
-u32 alloc_delegation= 0;
-u32 free_delegation= 0;
 
 /* forward declarations */
 struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
@@ -91,6 +89,7 @@ static DECLARE_MUTEX(client_sema);
 kmem_cache_t *stateowner_slab = NULL;
 kmem_cache_t *file_slab = NULL;
 kmem_cache_t *stateid_slab = NULL;
+kmem_cache_t *deleg_slab = NULL;
 
 void
 nfs4_lock_state(void)
@@ -138,8 +137,8 @@ alloc_init_deleg(struct nfs4_client *clp
 	struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
 
 	dprintk("NFSD alloc_init_deleg\n");
-	if ((dp = kmalloc(sizeof(struct nfs4_delegation),
-		GFP_KERNEL)) == NULL)
+	dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
+	if (dp == NULL)
 		return dp;
 	INIT_LIST_HEAD(&dp->dl_del_perfile);
 	INIT_LIST_HEAD(&dp->dl_del_perclnt);
@@ -164,7 +163,6 @@ alloc_init_deleg(struct nfs4_client *clp
 	atomic_set(&dp->dl_count, 1);
 	list_add(&dp->dl_del_perfile, &fp->fi_del_perfile);
 	list_add(&dp->dl_del_perclnt, &clp->cl_del_perclnt);
-	alloc_delegation++;
 	return dp;
 }
 
@@ -173,8 +171,7 @@ nfs4_put_delegation(struct nfs4_delegati
 {
 	if (atomic_dec_and_test(&dp->dl_count)) {
 		dprintk("NFSD: freeing dp %p\n",dp);
-		kfree(dp);
-		free_delegation++;
+		kmem_cache_free(deleg_slab, dp);
 	}
 }
 
@@ -1012,6 +1009,7 @@ nfsd4_free_slabs(void)
 	nfsd4_free_slab(&stateowner_slab);
 	nfsd4_free_slab(&file_slab);
 	nfsd4_free_slab(&stateid_slab);
+	nfsd4_free_slab(&deleg_slab);
 }
 
 static int
@@ -1029,6 +1027,10 @@ nfsd4_init_slabs(void)
 			sizeof(struct nfs4_stateid), 0, 0, NULL, NULL);
 	if (stateid_slab == NULL)
 		goto out_nomem;
+	deleg_slab = kmem_cache_create("nfsd4_delegations",
+			sizeof(struct nfs4_delegation), 0, 0, NULL, NULL);
+	if (deleg_slab == NULL)
+		goto out_nomem;
 	return 0;
 out_nomem:
 	nfsd4_free_slabs();
@@ -3312,9 +3314,6 @@ __nfs4_state_shutdown(void)
 			add_perclient, del_perclient);
 	dprintk("NFSD: vfsopen %d vfsclose %d\n",
 			vfsopen, vfsclose);
-	dprintk("NFSD: alloc_delegation %d free_delegation %d\n",
-			alloc_delegation, free_delegation);
-
 }
 
 void

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#13 lore raw

PATCH 1/1 nfsd4: fix struct file leak

In reply to NeilBrown

We were failing to close on an error path, resulting in a leak of struct files which could take a v4 server down fairly quickly....
So call nfs4_close_delegation instead of just open-coding parts of it.

Simplify the cleanup on delegation failure while we're at it.

### Diffstat output

 ./fs/nfsd/nfs4state.c |    8 +++-----
 1 files changed, 3 insertions(+), 5 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +3 -5
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -190,7 +190,8 @@ nfs4_close_delegation(struct nfs4_delega
 	dp->dl_vfs_file = NULL;
 	/* The following nfsd_close may not actually close the file,
 	 * but we want to remove the lease in any case. */
-	setlease(filp, F_UNLCK, &dp->dl_flock);
+	if (dp->dl_flock)
+		setlease(filp, F_UNLCK, &dp->dl_flock);
 	nfsd_close(filp);
 	vfsclose++;
 }
@@ -1673,10 +1674,7 @@ nfs4_open_delegation(struct svc_fh *fh, 
 	if ((status = setlease(stp->st_vfs_file,
 		flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
 		dprintk("NFSD: setlease failed [%d], no delegation\n", status);
-		list_del(&dp->dl_del_perfile);
-		list_del(&dp->dl_del_perclnt);
-		nfs4_put_delegation(dp);
-		free_delegation++;
+		unhash_delegation(dp);
 		flag = NFS4_OPEN_DELEGATE_NONE;
 		goto out;
 	}

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#14 lore raw

PATCH 1/1 nfsd4: remove debugging counters

In reply to NeilBrown

These remaining debugging counters haven't proved that useful.

### Diffstat output

 ./fs/nfsd/nfs4state.c |   25 +------------------------
 1 files changed, 1 insertion(+), 24 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +1 -24
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -65,14 +65,6 @@ static u32 nfs4_init;
 stateid_t zerostateid;             /* bits all 0 */
 stateid_t onestateid;              /* bits all 1 */
 
-/* debug counters */
-u32 list_add_perfile = 0; 
-u32 list_del_perfile = 0;
-u32 add_perclient = 0;
-u32 del_perclient = 0;
-u32 vfsopen = 0;
-u32 vfsclose = 0;
-
 /* forward declarations */
 struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
 static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
@@ -192,7 +184,6 @@ nfs4_close_delegation(struct nfs4_delega
 	if (dp->dl_flock)
 		setlease(filp, F_UNLCK, &dp->dl_flock);
 	nfsd_close(filp);
-	vfsclose++;
 }
 
 /* Called under the state lock. */
@@ -1083,7 +1074,6 @@ alloc_init_open_stateowner(unsigned int 
 	list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
 	list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
 	list_add(&sop->so_perclient, &clp->cl_perclient);
-	add_perclient++;
 	sop->so_is_open_owner = 1;
 	sop->so_id = current_ownerid++;
 	sop->so_client = clp;
@@ -1117,10 +1107,8 @@ unhash_stateowner(struct nfs4_stateowner
 
 	list_del(&sop->so_idhash);
 	list_del(&sop->so_strhash);
-	if (sop->so_is_open_owner) {
+	if (sop->so_is_open_owner)
 		list_del(&sop->so_perclient);
-		del_perclient++;
-	}
 	list_del(&sop->so_perlockowner);
 	while (!list_empty(&sop->so_perfilestate)) {
 		stp = list_entry(sop->so_perfilestate.next, 
@@ -1151,7 +1139,6 @@ init_stateid(struct nfs4_stateid *stp, s
 	INIT_LIST_HEAD(&stp->st_perfile);
 	list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
 	list_add(&stp->st_perfilestate, &sop->so_perfilestate);
-	list_add_perfile++;
 	list_add(&stp->st_perfile, &fp->fi_perfile);
 	stp->st_stateowner = sop;
 	stp->st_file = fp;
@@ -1171,14 +1158,12 @@ release_stateid(struct nfs4_stateid *stp
 	struct file *filp = stp->st_vfs_file;
 
 	list_del(&stp->st_hash);
-	list_del_perfile++;
 	list_del(&stp->st_perfile);
 	list_del(&stp->st_perfilestate);
 	if (flags & OPEN_STATE) {
 		release_stateid_lockowners(stp);
 		stp->st_vfs_file = NULL;
 		nfsd_close(filp);
-		vfsclose++;
 	} else if (flags & LOCK_STATE)
 		locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
 	kmem_cache_free(stateid_slab, stp);
@@ -1645,7 +1630,6 @@ nfs4_new_open(struct svc_rqst *rqstp, st
 			return status;
 		}
 	}
-	vfsopen++;
 	*stpp = stp;
 	return 0;
 }
@@ -2650,7 +2634,6 @@ alloc_init_lock_stateid(struct nfs4_stat
 	INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */
 	list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);
 	list_add(&stp->st_perfile, &fp->fi_perfile);
-	list_add_perfile++;
 	list_add(&stp->st_perfilestate, &sop->so_perfilestate);
 	stp->st_stateowner = sop;
 	stp->st_file = fp;
@@ -3308,12 +3291,6 @@ __nfs4_state_shutdown(void)
 	cancel_delayed_work(&laundromat_work);
 	flush_scheduled_work();
 	nfs4_init = 0;
-	dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n",
-			list_add_perfile, list_del_perfile);
-	dprintk("NFSD: add_perclient %d del_perclient %d\n",
-			add_perclient, del_perclient);
-	dprintk("NFSD: vfsopen %d vfsclose %d\n",
-			vfsopen, vfsclose);
 }
 
 void

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#15 lore raw

PATCH 1/1 nfsd4: rename nfs4_file fields

In reply to NeilBrown

Trivial renaming patch:

I can never remember, while looking at various lists relating the nfsd4 state structures, which are the "heads" and which are items on other lists, or which structures are actually on the various lists. The following convention helps
me: given structures foo and bar, with foo containing the head of a list of bars, use "bars" for the name of the head of the list contained in the struct foo, and use "per_foo" for the entries in the struct bars.

Go ahead and do this for struct nfs4_file.

### Diffstat output

 ./fs/nfsd/nfs4state.c        |   22 +++++++++++-----------
 ./include/linux/nfsd/state.h |    4 ++--
 2 files changed, 13 insertions(+), 13 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +11 -11
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -153,7 +153,7 @@ alloc_init_deleg(struct nfs4_client *clp
 		        current_fh->fh_handle.fh_size);
 	dp->dl_time = 0;
 	atomic_set(&dp->dl_count, 1);
-	list_add(&dp->dl_del_perfile, &fp->fi_del_perfile);
+	list_add(&dp->dl_del_perfile, &fp->fi_delegations);
 	list_add(&dp->dl_del_perclnt, &clp->cl_del_perclnt);
 	return dp;
 }
@@ -954,8 +954,8 @@ alloc_init_file(struct inode *ino)
 	fp = kmem_cache_alloc(file_slab, GFP_KERNEL);
 	if (fp) {
 		INIT_LIST_HEAD(&fp->fi_hash);
-		INIT_LIST_HEAD(&fp->fi_perfile);
-		INIT_LIST_HEAD(&fp->fi_del_perfile);
+		INIT_LIST_HEAD(&fp->fi_stateids);
+		INIT_LIST_HEAD(&fp->fi_delegations);
 		list_add(&fp->fi_hash, &file_hashtbl[hashval]);
 		fp->fi_inode = igrab(ino);
 		fp->fi_id = current_fileid++;
@@ -974,7 +974,7 @@ release_all_files(void)
 		while (!list_empty(&file_hashtbl[i])) {
 			fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash);
 			/* this should never be more than once... */
-			if (!list_empty(&fp->fi_perfile) || !list_empty(&fp->fi_del_perfile)) {
+			if (!list_empty(&fp->fi_stateids) || !list_empty(&fp->fi_delegations)) {
 				printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);
 			}
 			release_file(fp);
@@ -1139,7 +1139,7 @@ init_stateid(struct nfs4_stateid *stp, s
 	INIT_LIST_HEAD(&stp->st_perfile);
 	list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
 	list_add(&stp->st_perfilestate, &sop->so_perfilestate);
-	list_add(&stp->st_perfile, &fp->fi_perfile);
+	list_add(&stp->st_perfile, &fp->fi_stateids);
 	stp->st_stateowner = sop;
 	stp->st_file = fp;
 	stp->st_stateid.si_boot = boot_time;
@@ -1204,7 +1204,7 @@ release_state_owner(struct nfs4_stateid 
 	if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
 		move_to_close_lru(sop);
 	/* unused nfs4_file's are releseed. XXX slab cache? */
-	if (list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile)) {
+	if (list_empty(&fp->fi_stateids) && list_empty(&fp->fi_delegations)) {
 		release_file(fp);
 	}
 }
@@ -1294,7 +1294,7 @@ nfs4_share_conflict(struct svc_fh *curre
 	fp = find_file(ino);
 	if (fp) {
 	/* Search for conflicting share reservations */
-		list_for_each_entry(stp, &fp->fi_perfile, st_perfile) {
+		list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
 			if (test_bit(deny_type, &stp->st_deny_bmap) ||
 			    test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
 				return nfserr_share_denied;
@@ -1545,7 +1545,7 @@ find_delegation_file(struct nfs4_file *f
 {
 	struct nfs4_delegation *dp;
 
-	list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) {
+	list_for_each_entry(dp, &fp->fi_delegations, dl_del_perfile) {
 		if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
 			return dp;
 	}
@@ -1583,7 +1583,7 @@ nfs4_check_open(struct nfs4_file *fp, st
 	int status = nfserr_share_denied;
 	struct nfs4_stateowner *sop = open->op_stateowner;
 
-	list_for_each_entry(local, &fp->fi_perfile, st_perfile) {
+	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
 		/* ignore lock owners */
 		if (local->st_stateowner->so_is_open_owner == 0)
 			continue;
@@ -1830,7 +1830,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	            stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
 out:
 	/* take the opportunity to clean up unused state */
-	if (fp && list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile))
+	if (fp && list_empty(&fp->fi_stateids) && list_empty(&fp->fi_delegations))
 		release_file(fp);
 
 	/* CLAIM_PREVIOUS has different error returns */
@@ -2633,7 +2633,7 @@ alloc_init_lock_stateid(struct nfs4_stat
 	INIT_LIST_HEAD(&stp->st_perfilestate);
 	INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */
 	list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);
-	list_add(&stp->st_perfile, &fp->fi_perfile);
+	list_add(&stp->st_perfile, &fp->fi_stateids);
 	list_add(&stp->st_perfilestate, &sop->so_perfilestate);
 	stp->st_stateowner = sop;
 	stp->st_file = fp;
include/linux/nfsd/state.h renamed from include/linux/nfsd/state.h~current~ +2 -2
diff ./include/linux/nfsd/state.h~current~ ./include/linux/nfsd/state.h
@@ -218,8 +218,8 @@ struct nfs4_stateowner {
 */
 struct nfs4_file {
 	struct list_head        fi_hash;    /* hash by "struct inode *" */
-	struct list_head        fi_perfile; /* list: nfs4_stateid */
-	struct list_head	fi_del_perfile; /* list: nfs4_delegation */
+	struct list_head        fi_stateids;
+	struct list_head	fi_delegations;
 	struct inode		*fi_inode;
 	u32                     fi_id;      /* used with stateowner->so_id 
 					     * for stateid_hashtbl hash */

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

author
#16 lore raw

PATCH 1/1 nfsd4: reference count struct nfs4_file

In reply to NeilBrown

Add a struct kref to each nfs4_file and take a reference to it from each stateid and delegation that refers to it. The atomicity guarantees are overkill given that all this stuff is done under the single nfsd4 state lock, but a) we'd like finer-grained locking some day, and b) this simplifies the cleanup of the structures a bit, something that has previously been a bit complicated and bug-prone.

### Diffstat output

 ./fs/nfsd/nfs4state.c        |  100 +++++++++++++++++++++----------------------
 ./include/linux/nfsd/state.h |    1 
 2 files changed, 52 insertions(+), 49 deletions(-)
fs/nfsd/nfs4state.c renamed from fs/nfsd/nfs4state.c~current~ +51 -49
diff ./fs/nfsd/nfs4state.c~current~ ./fs/nfsd/nfs4state.c
@@ -111,7 +111,6 @@ opaque_hashval(const void *ptr, int nbyt
 /* forward declarations */
 static void release_stateowner(struct nfs4_stateowner *sop);
 static void release_stateid(struct nfs4_stateid *stp, int flags);
-static void release_file(struct nfs4_file *fp);
 
 /*
  * Delegation state
@@ -121,6 +120,27 @@ static void release_file(struct nfs4_fil
 spinlock_t recall_lock;
 static struct list_head del_recall_lru;
 
+static void
+free_nfs4_file(struct kref *kref)
+{
+	struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref);
+	list_del(&fp->fi_hash);
+	iput(fp->fi_inode);
+	kmem_cache_free(file_slab, fp);
+}
+
+static inline void
+put_nfs4_file(struct nfs4_file *fi)
+{
+	kref_put(&fi->fi_ref, free_nfs4_file);
+}
+
+static inline void
+get_nfs4_file(struct nfs4_file *fi)
+{
+	kref_get(&fi->fi_ref);
+}
+
 static struct nfs4_delegation *
 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
 {
@@ -136,6 +156,7 @@ alloc_init_deleg(struct nfs4_client *clp
 	INIT_LIST_HEAD(&dp->dl_del_perclnt);
 	INIT_LIST_HEAD(&dp->dl_recall_lru);
 	dp->dl_client = clp;
+	get_nfs4_file(fp);
 	dp->dl_file = fp;
 	dp->dl_flock = NULL;
 	get_file(stp->st_vfs_file);
@@ -163,6 +184,7 @@ nfs4_put_delegation(struct nfs4_delegati
 {
 	if (atomic_dec_and_test(&dp->dl_count)) {
 		dprintk("NFSD: freeing dp %p\n",dp);
+		put_nfs4_file(dp->dl_file);
 		kmem_cache_free(deleg_slab, dp);
 	}
 }
@@ -953,6 +975,7 @@ alloc_init_file(struct inode *ino)
 
 	fp = kmem_cache_alloc(file_slab, GFP_KERNEL);
 	if (fp) {
+		kref_init(&fp->fi_ref);
 		INIT_LIST_HEAD(&fp->fi_hash);
 		INIT_LIST_HEAD(&fp->fi_stateids);
 		INIT_LIST_HEAD(&fp->fi_delegations);
@@ -965,24 +988,6 @@ alloc_init_file(struct inode *ino)
 }
 
 static void
-release_all_files(void)
-{
-	int i;
-	struct nfs4_file *fp;
-
-	for (i=0;i<FILE_HASH_SIZE;i++) {
-		while (!list_empty(&file_hashtbl[i])) {
-			fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash);
-			/* this should never be more than once... */
-			if (!list_empty(&fp->fi_stateids) || !list_empty(&fp->fi_delegations)) {
-				printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);
-			}
-			release_file(fp);
-		}
-	}
-}
-
-static void
 nfsd4_free_slab(kmem_cache_t **slab)
 {
 	int status;
@@ -1141,6 +1146,7 @@ init_stateid(struct nfs4_stateid *stp, s
 	list_add(&stp->st_perfilestate, &sop->so_perfilestate);
 	list_add(&stp->st_perfile, &fp->fi_stateids);
 	stp->st_stateowner = sop;
+	get_nfs4_file(fp);
 	stp->st_file = fp;
 	stp->st_stateid.si_boot = boot_time;
 	stp->st_stateid.si_stateownerid = sop->so_id;
@@ -1166,18 +1172,11 @@ release_stateid(struct nfs4_stateid *stp
 		nfsd_close(filp);
 	} else if (flags & LOCK_STATE)
 		locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
+	put_nfs4_file(stp->st_file);
 	kmem_cache_free(stateid_slab, stp);
 	stp = NULL;
 }
 
-static void
-release_file(struct nfs4_file *fp)
-{
-	list_del(&fp->fi_hash);
-	iput(fp->fi_inode);
-	kmem_cache_free(file_slab, fp);
-}	
-
 void
 move_to_close_lru(struct nfs4_stateowner *sop)
 {
@@ -1192,7 +1191,6 @@ void
 release_state_owner(struct nfs4_stateid *stp, int flag)
 {
 	struct nfs4_stateowner *sop = stp->st_stateowner;
-	struct nfs4_file *fp = stp->st_file;
 
 	dprintk("NFSD: release_state_owner\n");
 	release_stateid(stp, flag);
@@ -1203,10 +1201,6 @@ release_state_owner(struct nfs4_stateid 
 	 */
 	if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
 		move_to_close_lru(sop);
-	/* unused nfs4_file's are releseed. XXX slab cache? */
-	if (list_empty(&fp->fi_stateids) && list_empty(&fp->fi_delegations)) {
-		release_file(fp);
-	}
 }
 
 static int
@@ -1236,8 +1230,10 @@ find_file(struct inode *ino)
 	struct nfs4_file *fp;
 
 	list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
-		if (fp->fi_inode == ino)
+		if (fp->fi_inode == ino) {
+			get_nfs4_file(fp);
 			return fp;
+		}
 	}
 	return NULL;
 }
@@ -1288,19 +1284,24 @@ nfs4_share_conflict(struct svc_fh *curre
 	struct inode *ino = current_fh->fh_dentry->d_inode;
 	struct nfs4_file *fp;
 	struct nfs4_stateid *stp;
+	int ret;
 
 	dprintk("NFSD: nfs4_share_conflict\n");
 
 	fp = find_file(ino);
-	if (fp) {
+	if (!fp)
+		return nfs_ok;
+	ret = nfserr_share_denied;
 	/* Search for conflicting share reservations */
-		list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
-			if (test_bit(deny_type, &stp->st_deny_bmap) ||
-			    test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
-				return nfserr_share_denied;
-		}
+	list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
+		if (test_bit(deny_type, &stp->st_deny_bmap) ||
+		    test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
+			goto out;
 	}
-	return nfs_ok;
+	ret = nfs_ok;
+out:
+	put_nfs4_file(fp);
+	return ret;
 }
 
 static inline void
@@ -1829,10 +1830,8 @@ nfsd4_process_open2(struct svc_rqst *rqs
 	            stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid,
 	            stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
 out:
-	/* take the opportunity to clean up unused state */
-	if (fp && list_empty(&fp->fi_stateids) && list_empty(&fp->fi_delegations))
-		release_file(fp);
-
+	if (fp)
+		put_nfs4_file(fp);
 	/* CLAIM_PREVIOUS has different error returns */
 	nfs4_set_claim_prev(open, &status);
 	/*
@@ -2480,16 +2479,19 @@ find_stateid(stateid_t *stid, int flags)
 static struct nfs4_delegation *
 find_delegation_stateid(struct inode *ino, stateid_t *stid)
 {
-	struct nfs4_file *fp = NULL;
+	struct nfs4_file *fp;
+	struct nfs4_delegation *dl;
 
 	dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n",
                     stid->si_boot, stid->si_stateownerid,
                     stid->si_fileid, stid->si_generation);
 
 	fp = find_file(ino);
-	if (fp)
-		return find_delegation_file(fp, stid);
-	return NULL;
+	if (!fp)
+		return NULL;
+	dl = find_delegation_file(fp, stid);
+	put_nfs4_file(fp);
+	return dl;
 }
 
 /*
@@ -2636,6 +2638,7 @@ alloc_init_lock_stateid(struct nfs4_stat
 	list_add(&stp->st_perfile, &fp->fi_stateids);
 	list_add(&stp->st_perfilestate, &sop->so_perfilestate);
 	stp->st_stateowner = sop;
+	get_nfs4_file(fp);
 	stp->st_file = fp;
 	stp->st_stateid.si_boot = boot_time;
 	stp->st_stateid.si_stateownerid = sop->so_id;
@@ -3287,7 +3290,6 @@ __nfs4_state_shutdown(void)
 		unhash_delegation(dp);
 	}
 
-	release_all_files();
 	cancel_delayed_work(&laundromat_work);
 	flush_scheduled_work();
 	nfs4_init = 0;
include/linux/nfsd/state.h renamed from include/linux/nfsd/state.h~current~ +1 -0
diff ./include/linux/nfsd/state.h~current~ ./include/linux/nfsd/state.h
@@ -217,6 +217,7 @@ struct nfs4_stateowner {
 *      share_acces, share_deny on the file.
 */
 struct nfs4_file {
+	struct kref		fi_ref;
 	struct list_head        fi_hash;    /* hash by "struct inode *" */
 	struct list_head        fi_stateids;
 	struct list_head	fi_delegations;

-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users. Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs