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

Next file: linux-2.4.19/fs/nfsd/nfs3proc.c
Previous file: linux-2.4.19/fs/nfs/write.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.18/fs/nfsd/export.c linux-2.4.19/fs/nfsd/export.c
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/in.h>
+#include <linux/seq_file.h>
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -31,7 +32,6 @@
 typedef struct svc_client	svc_client;
 typedef struct svc_export	svc_export;
 
-static svc_export *	exp_find(svc_client *clp, kdev_t dev);
 static svc_export *	exp_parent(svc_client *clp, kdev_t dev,
 					struct dentry *dentry);
 static svc_export *	exp_child(svc_client *clp, kdev_t dev,
@@ -65,41 +65,25 @@
 static int			hash_count;
 static DECLARE_WAIT_QUEUE_HEAD(	hash_wait );
 
-
-/*
- * Find a client's export for a device.
- */
-static inline svc_export *
-exp_find(svc_client *clp, kdev_t dev)
-{
-	svc_export *	exp;
-
-	exp = clp->cl_export[EXPORT_HASH(dev)];
-	while (exp && exp->ex_dev != dev)
-		exp = exp->ex_next;
-	return exp;
-}
-
 /*
  * Find the client's export entry matching xdev/xino.
  */
 svc_export *
 exp_get(svc_client *clp, kdev_t dev, ino_t ino)
 {
-	svc_export *	exp;
+	struct list_head *head, *p;
 
 	if (!clp)
 		return NULL;
 
-	exp = clp->cl_export[EXPORT_HASH(dev)];
-	if (exp)
-		do {
-			if (exp->ex_ino == ino && exp->ex_dev == dev)
-				goto out;
-		} while (NULL != (exp = exp->ex_next));
-	exp = NULL;
-out:
-	return exp;
+	head = &clp->cl_export[EXPORT_HASH(dev)];
+	list_for_each(p, head) {
+		svc_export *exp = list_entry(p, svc_export, ex_hash);
+		if (exp->ex_ino == ino && exp->ex_dev == dev)
+			return exp;
+	}
+
+	return NULL;
 }
 
 /*
@@ -108,15 +92,15 @@
 static svc_export *
 exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry)
 {
-	svc_export      *exp;
+	struct list_head *head = &clp->cl_export[EXPORT_HASH(dev)];
+	struct list_head *p;
 
-	if (clp == NULL)
-		return NULL;
-
-	for (exp = clp->cl_export[EXPORT_HASH(dev)]; exp; exp = exp->ex_next)
+	list_for_each(p,head) {
+		svc_export *exp = list_entry(p, svc_export, ex_hash);
 		if (is_subdir(dentry, exp->ex_dentry))
-			break;
-	return exp;
+			return exp;
+	}
+	return NULL;
 }
 
 /*
@@ -127,17 +111,31 @@
 static svc_export *
 exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry)
 {
-	svc_export      *exp;
+	struct list_head *head = &clp->cl_export[EXPORT_HASH(dev)];
+	struct list_head *p;
 
-	if (clp == NULL)
-		return NULL;
 
-	for (exp = clp->cl_export[EXPORT_HASH(dev)]; exp; exp = exp->ex_next) {
-		struct dentry	*ndentry = exp->ex_dentry;
+	list_for_each(p, head) {
+		svc_export *exp = list_entry(p, svc_export, ex_hash);
+		struct dentry *ndentry = exp->ex_dentry;
+
 		if (ndentry && is_subdir(ndentry->d_parent, dentry))
-			break;
+			return exp;
+	}
+	return NULL;
+}
+
+/* Update parent pointers of all exports */
+static void exp_change_parents(svc_client *clp, svc_export *old, svc_export *new)
+{
+	struct list_head *head = &clp->cl_list;
+	struct list_head *p;
+
+	list_for_each(p, head) {
+		svc_export *exp = list_entry(p, svc_export, ex_list);
+		if (exp->ex_parent == old)
+			exp->ex_parent = new;
 	}
-	return exp;
 }
 
 /*
@@ -148,10 +146,9 @@
 {
 	svc_client	*clp;
 	svc_export	*exp, *parent;
-	svc_export	**head;
 	struct nameidata nd;
 	struct inode	*inode = NULL;
-	int		i, err;
+	int		err;
 	kdev_t		dev;
 	ino_t		ino;
 
@@ -237,8 +234,8 @@
 	strcpy(exp->ex_path, nxp->ex_path);
 	exp->ex_client = clp;
 	exp->ex_parent = parent;
-	exp->ex_dentry = nd.dentry;
-	exp->ex_mnt = nd.mnt;
+	exp->ex_dentry = dget(nd.dentry);
+	exp->ex_mnt = mntget(nd.mnt);
 	exp->ex_flags = nxp->ex_flags;
 	exp->ex_dev = dev;
 	exp->ex_ino = ino;
@@ -246,34 +243,20 @@
 	exp->ex_anon_gid = nxp->ex_anon_gid;
 
 	/* Update parent pointers of all exports */
-	if (parent) {
-		for (i = 0; i < NFSCLNT_EXPMAX; i++) {
-			svc_export *temp = clp->cl_export[i];
-
-			while (temp) {
-				if (temp->ex_parent == parent)
-					temp->ex_parent = exp;
-				temp = temp->ex_next;
-			}
-		}
-	}
+	if (parent)
+		exp_change_parents(clp, parent, exp);
 
-	head = clp->cl_export + EXPORT_HASH(dev);
-	exp->ex_next = *head;
-	*head = exp;
+	list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev));
+	list_add_tail(&exp->ex_list, &clp->cl_list);
 
 	err = 0;
 
-	/* Unlock hashtable */
+finish:
+	path_release(&nd);
 out_unlock:
 	exp_unlock();
 out:
 	return err;
-
-	/* Release the dentry */
-finish:
-	path_release(&nd);
-	goto out_unlock;
 }
 
 /*
@@ -283,20 +266,14 @@
 static void
 exp_do_unexport(svc_export *unexp)
 {
-	svc_export	*exp;
-	svc_client	*clp;
 	struct dentry	*dentry;
 	struct vfsmount *mnt;
 	struct inode	*inode;
-	int		i;
 
-	/* Update parent pointers. */
-	clp = unexp->ex_client;
-	for (i = 0; i < NFSCLNT_EXPMAX; i++) {
-		for (exp = clp->cl_export[i]; exp; exp = exp->ex_next)
-			if (exp->ex_parent == unexp)
-				exp->ex_parent = unexp->ex_parent;
-	}
+	list_del(&unexp->ex_hash);
+	list_del(&unexp->ex_list);
+
+	exp_change_parents(unexp->ex_client, unexp, unexp->ex_parent);
 
 	dentry = unexp->ex_dentry;
 	mnt = unexp->ex_mnt;
@@ -317,18 +294,13 @@
 static void
 exp_unexport_all(svc_client *clp)
 {
-	svc_export	*exp;
-	int		i;
+	struct list_head *p = &clp->cl_list;
 
 	dprintk("unexporting all fs's for clnt %p\n", clp);
-	for (i = 0; i < NFSCLNT_EXPMAX; i++) {
-		exp = clp->cl_export[i];
-		clp->cl_export[i] = NULL;
-		while (exp) {
-			svc_export *next = exp->ex_next;
-			exp_do_unexport(exp);
-			exp = next;
-		}
+
+	while (!list_empty(p)) {
+		svc_export *exp = list_entry(p->next, svc_export, ex_list);
+		exp_do_unexport(exp);
 	}
 }
 
@@ -339,7 +311,6 @@
 exp_unexport(struct nfsctl_export *nxp)
 {
 	svc_client	*clp;
-	svc_export	**expp, *exp = NULL;
 	int		err;
 
 	/* Consistency check */
@@ -352,17 +323,10 @@
 	err = -EINVAL;
 	clp = exp_getclientbyname(nxp->ex_client);
 	if (clp) {
-		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) {
-					*expp = exp->ex_next;
-					exp_do_unexport(exp);
-					err = 0;
-					break;
-				}
-			}
-			expp = &(exp->ex_next);
+		svc_export *exp = exp_get(clp, nxp->ex_dev, nxp->ex_ino);
+		if (exp) {
+			exp_do_unexport(exp);
+			err = 0;
 		}
 	}
 
@@ -542,6 +506,68 @@
 	return NULL;
 }
 
+/* Iterator */
+
+static void *e_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t n = *pos;
+	unsigned client, export;
+	svc_client *clp;
+	struct list_head *p;
+	
+	exp_readlock();
+	if (!n--)
+		return (void *)1;
+	client = n >> 32;
+	export = n & ((1LL<<32) - 1);
+	for (clp = clients; client && clp; clp = clp->cl_next, client--)
+		;
+	if (!clp)
+		return NULL;
+	list_for_each(p, &clp->cl_list)
+		if (!export--)
+			return list_entry(p, svc_export, ex_list);
+	n &= ~((1LL<<32) - 1);
+	do {
+		clp = clp->cl_next;
+		n += 1LL<<32;
+	} while(clp && list_empty(&clp->cl_list));
+	if (!clp)
+		return NULL;
+	*pos = n+1;
+	return list_entry(clp->cl_list.next, svc_export, ex_list);
+}
+
+static void *e_next(struct seq_file *m, void *p, loff_t *pos)
+{
+	svc_export *exp = p;
+	svc_client *clp;
+
+	if (p == (void *)1)
+		clp = clients;
+	else if (exp->ex_list.next == &exp->ex_client->cl_list) {
+		clp = exp->ex_client->cl_next;
+		*pos += 1LL<<32;
+	} else {
+		++*pos;
+		return list_entry(exp->ex_list.next, svc_export, ex_list);
+	}
+	*pos &= ~((1LL<<32) - 1);
+	while (clp && list_empty(&clp->cl_list)) {
+		clp = clp->cl_next;
+		*pos += 1LL<<32;
+	}
+	if (!clp)
+		return NULL;
+	++*pos;
+	return list_entry(clp->cl_list.next, svc_export, ex_list);
+}
+
+static void e_stop(struct seq_file *m, void *p)
+{
+	exp_unlock();
+}
+
 struct flags {
 	int flag;
 	char *name[2];
@@ -564,128 +590,77 @@
 	{ 0, {"", ""}}
 };
 
-static int
-exp_flags(char *buffer, int flag)
+static void exp_flags(struct seq_file *m, int flag)
 {
-    int len = 0, first = 0;
-    struct flags *flg = expflags;
+	int first = 0;
+	struct flags *flg;
 
-    for (;flg->flag;flg++) {
-        int state = (flg->flag & flag)?0:1;
-        if (!flg->flag)
-		break;
-        if (*flg->name[state]) {
-		len += sprintf(buffer + len, "%s%s",
-                               first++?",":"", flg->name[state]);
-        }
-    }
-    return len;
+	for (flg = expflags; flg->flag; flg++) {
+		int state = (flg->flag & flag)?0:1;
+		if (*flg->name[state])
+			seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
+	}
 }
 
-
-
-/* mangling borrowed from fs/super.c */
-/* Use octal escapes, like mount does, for embedded spaces etc. */
-static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
-
-static int
-mangle(const unsigned char *s, char *buf, int len) {
-        char *sp;
-        int n;
-
-        sp = buf;
-        while(*s && sp-buf < len-3) {
-                for (n = 0; n < sizeof(need_escaping); n++) {
-                        if (*s == need_escaping[n]) {
-                                *sp++ = '\\';
-                                *sp++ = '0' + ((*s & 0300) >> 6);
-                                *sp++ = '0' + ((*s & 070) >> 3);
-                                *sp++ = '0' + (*s & 07);
-                                goto next;
-                        }
-                }
-                *sp++ = *s;
-        next:
-                s++;
-        }
-        return sp - buf;	/* no trailing NUL */
+static inline void mangle(struct seq_file *m, const char *s)
+{
+	seq_escape(m, s, " \t\n\\");
 }
 
-#define FREEROOM	((int)PAGE_SIZE-200-len)
-#define MANGLE(s)	len += mangle((s), buffer+len, FREEROOM);
-
-int
-exp_procfs_exports(char *buffer, char **start, off_t offset,
-                             int length, int *eof, void *data)
+static int e_show(struct seq_file *m, void *p)
 {
-	struct svc_clnthash	**hp, **head, *tmp;
-	struct svc_client	*clp;
-	svc_export *exp;
-	off_t	pos = 0;
-        off_t	begin = 0;
-        int	len = 0;
-	int	i,j;
+	struct svc_export *exp = p;
+	struct svc_client *clp;
+	int j, first = 0;
 
-        len += sprintf(buffer, "# Version 1.1\n");
-        len += sprintf(buffer+len, "# Path Client(Flags) # IPs\n");
-
-	for (clp = clients; clp; clp = clp->cl_next) {
-		for (i = 0; i < NFSCLNT_EXPMAX; i++) {
-			exp = clp->cl_export[i];
-			while (exp) {
-				int first = 0;
-				MANGLE(exp->ex_path);
-				buffer[len++]='\t';
-				MANGLE(clp->cl_ident);
-				buffer[len++]='(';
-
-				len += exp_flags(buffer+len, exp->ex_flags);
-				len += sprintf(buffer+len, ") # ");
-				for (j = 0; j < clp->cl_naddr; j++) {
-					struct in_addr	addr = clp->cl_addr[j]; 
-
-					head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
-					for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
-						if (tmp->h_addr.s_addr == addr.s_addr) {
-							if (first++) len += sprintf(buffer+len, "%s", " ");
-							if (tmp->h_client != clp)
-								len += sprintf(buffer+len, "(");
-							len += sprintf(buffer+len, "%d.%d.%d.%d",
-									htonl(addr.s_addr) >> 24 & 0xff,
-									htonl(addr.s_addr) >> 16 & 0xff,
-									htonl(addr.s_addr) >>  8 & 0xff,
-									htonl(addr.s_addr) >>  0 & 0xff);
-							if (tmp->h_client != clp)
-							  len += sprintf(buffer+len, ")");
-							break;
-						}
-					}
-				}
-				exp = exp->ex_next;
-
-				buffer[len++]='\n';
-
-				pos=begin+len;
-				if(pos<offset) {
-					len=0;
-					begin=pos;
-				}
-				if (pos > offset + length)
-					goto done;
-			}
-		}
+	if (p == (void *)1) {
+		seq_puts(m, "# Version 1.1\n");
+		seq_puts(m, "# Path Client(Flags) # IPs\n");
+		return 0;
 	}
 
-	*eof = 1;
+	clp = exp->ex_client;
 
-done:
-	*start = buffer + (offset - begin);
-	len -= (offset - begin);
-	if ( len > length )
-		len = length;
-	return len;
+	mangle(m, exp->ex_path);
+	seq_putc(m, '\t');
+	mangle(m, clp->cl_ident);
+	seq_putc(m, '(');
+	exp_flags(m, exp->ex_flags);
+	seq_puts(m, ") # ");
+	for (j = 0; j < clp->cl_naddr; j++) {
+		struct svc_clnthash **hp, **head, *tmp;
+		struct in_addr addr = clp->cl_addr[j]; 
+
+		head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
+		for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
+			if (tmp->h_addr.s_addr == addr.s_addr)
+				break;
+		}
+		if (tmp) {
+			if (first++)
+				seq_putc(m, ' ');
+			if (tmp->h_client != clp)
+				seq_putc(m, '(');
+			seq_printf(m, "%d.%d.%d.%d",
+				htonl(addr.s_addr) >> 24 & 0xff,
+				htonl(addr.s_addr) >> 16 & 0xff,
+				htonl(addr.s_addr) >>  8 & 0xff,
+				htonl(addr.s_addr) >>  0 & 0xff);
+			if (tmp->h_client != clp)
+				seq_putc(m, ')');
+		}
+	}
+	seq_putc(m, '\n');
+	return 0;
 }
 
+struct seq_operations nfs_exports_op = {
+	start:	e_start,
+	next:	e_next,
+	stop:	e_stop,
+	show:	e_show,
+};
+
 /*
  * Add or modify a client.
  * Change requests may involve the list of host addresses. The list of
@@ -721,6 +696,9 @@
 		if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
 			goto out_unlock;
 		memset(clp, 0, sizeof(*clp));
+		for (i = 0; i < NFSCLNT_EXPMAX; i++)
+			INIT_LIST_HEAD(&clp->cl_export[i]);
+		INIT_LIST_HEAD(&clp->cl_list);
 
 		dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)