Skip to content

Commit

Permalink
NFS: Add server and volume lists to /proc
Browse files Browse the repository at this point in the history
Make two new proc files available:

	/proc/fs/nfsfs/servers
	/proc/fs/nfsfs/volumes

The first lists the servers with which we are currently dealing (struct
nfs_client), and the second lists the volumes we have on those servers (struct
nfs_server).

Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
David Howells authored and Trond Myklebust committed Sep 23, 2006
1 parent 54ceac4 commit 6aaca56
Show file tree
Hide file tree
Showing 3 changed files with 303 additions and 0 deletions.
284 changes: 284 additions & 0 deletions fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1148,3 +1148,287 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
dprintk("<-- nfs_clone_server() = error %d\n", error);
return ERR_PTR(error);
}

#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_fs_nfs;

static int nfs_server_list_open(struct inode *inode, struct file *file);
static void *nfs_server_list_start(struct seq_file *p, loff_t *pos);
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos);
static void nfs_server_list_stop(struct seq_file *p, void *v);
static int nfs_server_list_show(struct seq_file *m, void *v);

static struct seq_operations nfs_server_list_ops = {
.start = nfs_server_list_start,
.next = nfs_server_list_next,
.stop = nfs_server_list_stop,
.show = nfs_server_list_show,
};

static struct file_operations nfs_server_list_fops = {
.open = nfs_server_list_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};

static int nfs_volume_list_open(struct inode *inode, struct file *file);
static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos);
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos);
static void nfs_volume_list_stop(struct seq_file *p, void *v);
static int nfs_volume_list_show(struct seq_file *m, void *v);

static struct seq_operations nfs_volume_list_ops = {
.start = nfs_volume_list_start,
.next = nfs_volume_list_next,
.stop = nfs_volume_list_stop,
.show = nfs_volume_list_show,
};

static struct file_operations nfs_volume_list_fops = {
.open = nfs_volume_list_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};

/*
* open "/proc/fs/nfsfs/servers" which provides a summary of servers with which
* we're dealing
*/
static int nfs_server_list_open(struct inode *inode, struct file *file)
{
struct seq_file *m;
int ret;

ret = seq_open(file, &nfs_server_list_ops);
if (ret < 0)
return ret;

m = file->private_data;
m->private = PDE(inode)->data;

return 0;
}

/*
* set up the iterator to start reading from the server list and return the first item
*/
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
{
struct list_head *_p;
loff_t pos = *_pos;

/* lock the list against modification */
spin_lock(&nfs_client_lock);

/* allow for the header line */
if (!pos)
return SEQ_START_TOKEN;
pos--;

/* find the n'th element in the list */
list_for_each(_p, &nfs_client_list)
if (!pos--)
break;

return _p != &nfs_client_list ? _p : NULL;
}

/*
* move to next server
*/
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
{
struct list_head *_p;

(*pos)++;

_p = v;
_p = (v == SEQ_START_TOKEN) ? nfs_client_list.next : _p->next;

return _p != &nfs_client_list ? _p : NULL;
}

/*
* clean up after reading from the transports list
*/
static void nfs_server_list_stop(struct seq_file *p, void *v)
{
spin_unlock(&nfs_client_lock);
}

/*
* display a header line followed by a load of call lines
*/
static int nfs_server_list_show(struct seq_file *m, void *v)
{
struct nfs_client *clp;

/* display header on line 1 */
if (v == SEQ_START_TOKEN) {
seq_puts(m, "NV SERVER PORT USE HOSTNAME\n");
return 0;
}

/* display one transport per line on subsequent lines */
clp = list_entry(v, struct nfs_client, cl_share_link);

seq_printf(m, "v%d %02x%02x%02x%02x %4hx %3d %s\n",
clp->cl_nfsversion,
NIPQUAD(clp->cl_addr.sin_addr),
ntohs(clp->cl_addr.sin_port),
atomic_read(&clp->cl_count),
clp->cl_hostname);

return 0;
}

/*
* open "/proc/fs/nfsfs/volumes" which provides a summary of extant volumes
*/
static int nfs_volume_list_open(struct inode *inode, struct file *file)
{
struct seq_file *m;
int ret;

ret = seq_open(file, &nfs_volume_list_ops);
if (ret < 0)
return ret;

m = file->private_data;
m->private = PDE(inode)->data;

return 0;
}

/*
* set up the iterator to start reading from the volume list and return the first item
*/
static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
{
struct list_head *_p;
loff_t pos = *_pos;

/* lock the list against modification */
spin_lock(&nfs_client_lock);

/* allow for the header line */
if (!pos)
return SEQ_START_TOKEN;
pos--;

/* find the n'th element in the list */
list_for_each(_p, &nfs_volume_list)
if (!pos--)
break;

return _p != &nfs_volume_list ? _p : NULL;
}

/*
* move to next volume
*/
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
{
struct list_head *_p;

(*pos)++;

_p = v;
_p = (v == SEQ_START_TOKEN) ? nfs_volume_list.next : _p->next;

return _p != &nfs_volume_list ? _p : NULL;
}

/*
* clean up after reading from the transports list
*/
static void nfs_volume_list_stop(struct seq_file *p, void *v)
{
spin_unlock(&nfs_client_lock);
}

/*
* display a header line followed by a load of call lines
*/
static int nfs_volume_list_show(struct seq_file *m, void *v)
{
struct nfs_server *server;
struct nfs_client *clp;
char dev[8], fsid[17];

/* display header on line 1 */
if (v == SEQ_START_TOKEN) {
seq_puts(m, "NV SERVER PORT DEV FSID\n");
return 0;
}
/* display one transport per line on subsequent lines */
server = list_entry(v, struct nfs_server, master_link);
clp = server->nfs_client;

snprintf(dev, 8, "%u:%u",
MAJOR(server->s_dev), MINOR(server->s_dev));

snprintf(fsid, 17, "%llx:%llx",
server->fsid.major, server->fsid.minor);

seq_printf(m, "v%d %02x%02x%02x%02x %4hx %-7s %-17s\n",
clp->cl_nfsversion,
NIPQUAD(clp->cl_addr.sin_addr),
ntohs(clp->cl_addr.sin_port),
dev,
fsid);

return 0;
}

/*
* initialise the /proc/fs/nfsfs/ directory
*/
int __init nfs_fs_proc_init(void)
{
struct proc_dir_entry *p;

proc_fs_nfs = proc_mkdir("nfsfs", proc_root_fs);
if (!proc_fs_nfs)
goto error_0;

proc_fs_nfs->owner = THIS_MODULE;

/* a file of servers with which we're dealing */
p = create_proc_entry("servers", S_IFREG|S_IRUGO, proc_fs_nfs);
if (!p)
goto error_1;

p->proc_fops = &nfs_server_list_fops;
p->owner = THIS_MODULE;

/* a file of volumes that we have mounted */
p = create_proc_entry("volumes", S_IFREG|S_IRUGO, proc_fs_nfs);
if (!p)
goto error_2;

p->proc_fops = &nfs_volume_list_fops;
p->owner = THIS_MODULE;
return 0;

error_2:
remove_proc_entry("servers", proc_fs_nfs);
error_1:
remove_proc_entry("nfsfs", proc_root_fs);
error_0:
return -ENOMEM;
}

/*
* clean up the /proc/fs/nfsfs/ directory
*/
void nfs_fs_proc_exit(void)
{
remove_proc_entry("volumes", proc_fs_nfs);
remove_proc_entry("servers", proc_fs_nfs);
remove_proc_entry("nfsfs", proc_root_fs);
}

#endif /* CONFIG_PROC_FS */
7 changes: 7 additions & 0 deletions fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,10 @@ static int __init init_nfs_fs(void)
{
int err;

err = nfs_fs_proc_init();
if (err)
goto out5;

err = nfs_init_nfspagecache();
if (err)
goto out4;
Expand Down Expand Up @@ -1181,6 +1185,8 @@ static int __init init_nfs_fs(void)
out3:
nfs_destroy_nfspagecache();
out4:
nfs_fs_proc_exit();
out5:
return err;
}

Expand All @@ -1195,6 +1201,7 @@ static void __exit exit_nfs_fs(void)
rpc_proc_unregister("nfs");
#endif
unregister_nfs_fs();
nfs_fs_proc_exit();
}

/* Not quite true; I just maintain it */
Expand Down
12 changes: 12 additions & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ extern void nfs_free_server(struct nfs_server *server);
extern struct nfs_server *nfs_clone_server(struct nfs_server *,
struct nfs_fh *,
struct nfs_fattr *);
#ifdef CONFIG_PROC_FS
extern int __init nfs_fs_proc_init(void);
extern void nfs_fs_proc_exit(void);
#else
static inline int nfs_fs_proc_init(void)
{
return 0;
}
static inline void nfs_fs_proc_exit(void)
{
}
#endif

/* nfs4namespace.c */
#ifdef CONFIG_NFS_V4
Expand Down

0 comments on commit 6aaca56

Please sign in to comment.