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
- Lines: 538
- Date:
Fri Aug 2 17:39:45 2002
- Orig file:
linux-2.4.18/fs/nfsd/export.c
- Orig date:
Wed Oct 3 22:57:36 2001
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)