patch-2.1.67 linux/fs/nfsd/export.c

Next file: linux/fs/nfsd/nfsfh.c
Previous file: linux/fs/nfs/dir.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.66/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
@@ -26,6 +26,9 @@
 #include <linux/nfsd/syscall.h>
 #include <linux/lockd/bind.h>
 
+#define NFSDDBG_FACILITY	NFSDDBG_EXPORT
+#define NFSD_PARANOIA 1
+
 typedef struct svc_client	svc_client;
 typedef struct svc_export	svc_export;
 
@@ -37,9 +40,7 @@
 static void		exp_freeclient(svc_client *clp);
 static void		exp_unhashclient(svc_client *clp);
 static int		exp_verify_string(char *cp, int max);
-struct inode *		exp_lnamei(char *pathname, int *errp);
 
-#define NFSDDBG_FACILITY	NFSDDBG_EXPORT
 #define CLIENT_HASHBITS		6
 #define CLIENT_HASHMAX		(1 << CLIENT_HASHBITS)
 #define CLIENT_HASHMASK		(CLIENT_HASHMAX - 1)
@@ -65,7 +66,7 @@
 #define WRITELOCK		1
 
 /*
- * Find the export entry matching xdev/xino.
+ * Find a client's export for a device.
  */
 static inline svc_export *
 exp_find(svc_client *clp, dev_t dev)
@@ -78,6 +79,9 @@
 	return exp;
 }
 
+/*
+ * Find the client's export entry matching xdev/xino.
+ */
 svc_export *
 exp_get(svc_client *clp, dev_t dev, ino_t ino)
 {
@@ -90,8 +94,22 @@
 }
 
 /*
- * Look up the root inode of the parent fs.
- * We have to go through iget in order to allow for wait_on_inode.
+ * Check whether there are any exports for a device.
+ */
+static int
+exp_device_in_use(dev_t dev)
+{
+	struct svc_client *clp;
+
+	for (clp = clients; clp; clp = clp->cl_next) {
+		if (exp_find(clp, dev))
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Look up the device of the parent fs.
  */
 static inline int
 nfsd_parentdev(dev_t *devp)
@@ -153,13 +171,12 @@
 
 	/* Try to lock the export table for update */
 	if ((err = exp_writelock()) < 0)
-		return err;
+		goto out;
 
 	/* Look up client info */
-	if (!(clp = exp_getclientbyname(nxp->ex_client))) {
-		err = -EINVAL;
-		goto finish;
-	}
+	err = -EINVAL;
+	if (!(clp = exp_getclientbyname(nxp->ex_client)))
+		goto out_unlock;
 
 	/*
 	 * If there's already an export for this file, assume this
@@ -167,22 +184,22 @@
 	 */
 	if ((exp = exp_find(clp, dev)) != NULL) {
 		/* Ensure there's only one export per FS. */
-		if (exp->ex_ino != ino) {
-			err = -EPERM;
-		} else {
+		err = -EPERM;
+		if (exp->ex_ino == ino) {
 			exp->ex_flags    = nxp->ex_flags;
 			exp->ex_anon_uid = nxp->ex_anon_uid;
 			exp->ex_anon_gid = nxp->ex_anon_gid;
 			err = 0;
 		}
-		goto finish;
+		goto out_unlock;
 	}
 
 	/* Look up the dentry */
 	err = -EINVAL;
 	dentry = lookup_dentry(nxp->ex_path, NULL, 0);
 	if (IS_ERR(dentry))
-		goto finish;
+		goto out_unlock;
+
 	err = -ENOENT;
 	inode = dentry->d_inode;
 	if(!inode)
@@ -199,11 +216,15 @@
 		goto finish;
 
 	/* If this is a sub-export, must be root of FS */
+	err = -EINVAL;
 	if ((parent = exp_parent(clp, dev)) != NULL) {
 		struct super_block *sb = inode->i_sb;
 
-		if (sb && (inode != sb->s_root->d_inode)) {
-			err = -EINVAL;
+		if (inode != sb->s_root->d_inode) {
+#ifdef NFSD_PARANOIA
+printk("exp_export: sub-export %s not root of device %s\n",
+nxp->ex_path, kdevname(sb->s_dev));
+#endif
 			goto finish;
 		}
 	}
@@ -242,14 +263,16 @@
 
 	err = 0;
 
-finish:
-	/* Release dentry */
-	if (err < 0 && !IS_ERR(dentry))
-		dput(dentry);
-
 	/* Unlock hashtable */
+out_unlock:
 	exp_unlock();
+out:
 	return err;
+
+	/* Release the dentry */
+finish:
+	dput(dentry);
+	goto out_unlock;
 }
 
 /*
@@ -273,12 +296,21 @@
 				exp->ex_parent = unexp->ex_parent;
 	}
 
+	/*
+	 * Check whether this is the last export for this device,
+	 * and if so flush any cached dentries.
+	 */
+	if (!exp_device_in_use(unexp->ex_dev)) {
+printk("exp_do_unexport: %s last use, flushing cache\n",
+kdevname(unexp->ex_dev));
+		nfsd_fh_flush(unexp->ex_dev);
+	}
+
 	dentry = unexp->ex_dentry;
 	inode = dentry->d_inode;
 	if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
 		printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
-	else
-		dput(dentry);
+	dput(dentry);
 
 	kfree(unexp);
 }
@@ -321,15 +353,19 @@
 		return -EINVAL;
 
 	if ((err = exp_writelock()) < 0)
-		return err;
+		goto out;
 
 	err = -EINVAL;
-	if ((clp = exp_getclientbyname(nxp->ex_client)) != NULL) {
+	clp = exp_getclientbyname(nxp->ex_client);
+	if (clp) {
+printk("exp_unexport: found client %s\n", nxp->ex_client);
 		expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev);
 		while ((exp = *expp) != NULL) {
 			if (exp->ex_dev == nxp->ex_dev) {
-				if (exp->ex_ino != nxp->ex_ino)
+				if (exp->ex_ino != nxp->ex_ino) {
+printk("exp_unexport: ino mismatch, %ld not %ld\n", exp->ex_ino, nxp->ex_ino);
 					break;
+				}
 				*expp = exp->ex_next;
 				exp_do_unexport(exp);
 				err = 0;
@@ -340,6 +376,7 @@
 	}
 
 	exp_unlock();
+out:
 	return err;
 }
 
@@ -477,27 +514,27 @@
 	int			i, err, change = 0, ilen;
 
 	/* First, consistency check. */
+	err = -EINVAL;
 	if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)))
-		return -EINVAL;
+		goto out;
 	if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
-		return -EINVAL;
+		goto out;
 
 	/* Lock the hashtable */
 	if ((err = exp_writelock()) < 0)
-		return err;
+		goto out;
 
 	/* First check if this is a change request for a client. */
 	for (clp = clients; clp; clp = clp->cl_next)
 		if (!strcmp(clp->cl_ident, ncp->cl_ident))
 			break;
 
+	err = -ENOMEM;
 	if (clp) {
 		change = 1;
 	} else {
-		if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL))) {
-			exp_unlock();
-			return -ENOMEM;
-		}
+		if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
+			goto out_unlock;
 		memset(clp, 0, sizeof(*clp));
 
 		dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
@@ -508,13 +545,13 @@
 
 	/* Allocate hash buckets */
 	for (i = 0; i < ncp->cl_naddr; i++) {
-		if (!(ch[i] = kmalloc(GFP_KERNEL, sizeof(ch[0])))) {
+		ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL);
+		if (!ch[i]) {
 			while (i--)
 				kfree(ch[i]);
 			if (!change)
 				kfree(clp);
-			exp_unlock();
-			return -ENOMEM;
+			goto out_unlock;
 		}
 	}
 
@@ -544,9 +581,12 @@
 		clp->cl_next = clients;
 		clients = clp;
 	}
+	err = 0;
 
+out_unlock:
 	exp_unlock();
-	return 0;
+out:
+	return err;
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov