nfsd4: add a client info file
Add a new nfsd/clients/#/info file with some basic information about each NFSv4 client. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
bf5ed3e3bb
commit
97ad4031e2
|
@ -2214,6 +2214,41 @@ find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
|
|||
return s;
|
||||
}
|
||||
|
||||
static int client_info_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct inode *inode = m->private;
|
||||
struct nfsdfs_client *nc;
|
||||
struct nfs4_client *clp;
|
||||
u64 clid;
|
||||
|
||||
nc = get_nfsdfs_client(inode);
|
||||
if (!nc)
|
||||
return -ENXIO;
|
||||
clp = container_of(nc, struct nfs4_client, cl_nfsdfs);
|
||||
memcpy(&clid, &clp->cl_clientid, sizeof(clid));
|
||||
seq_printf(m, "clientid: 0x%llx\n", clid);
|
||||
drop_client(clp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, client_info_show, inode);
|
||||
}
|
||||
|
||||
static const struct file_operations client_info_fops = {
|
||||
.open = client_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static const struct tree_descr client_files[] = {
|
||||
[0] = {"info", &client_info_fops, S_IRUSR},
|
||||
[1] = {""},
|
||||
};
|
||||
|
||||
static struct nfs4_client *create_client(struct xdr_netobj name,
|
||||
struct svc_rqst *rqstp, nfs4_verifier *verf)
|
||||
{
|
||||
|
@ -2242,7 +2277,8 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
|
|||
clp->cl_cb_session = NULL;
|
||||
clp->net = net;
|
||||
clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs,
|
||||
clp->cl_clientid.cl_id - nn->clientid_base);
|
||||
clp->cl_clientid.cl_id - nn->clientid_base,
|
||||
client_files);
|
||||
if (!clp->cl_nfsd_dentry) {
|
||||
free_client(clp);
|
||||
return NULL;
|
||||
|
|
116
fs/nfsd/nfsctl.c
116
fs/nfsd/nfsctl.c
|
@ -1208,14 +1208,116 @@ out_err:
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* on success, returns positive number unique to that client. */
|
||||
struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, struct nfsdfs_client *ncl, u32 id)
|
||||
static void clear_ncl(struct inode *inode)
|
||||
{
|
||||
struct nfsdfs_client *ncl = inode->i_private;
|
||||
|
||||
inode->i_private = NULL;
|
||||
synchronize_rcu();
|
||||
kref_put(&ncl->cl_ref, ncl->cl_release);
|
||||
}
|
||||
|
||||
|
||||
struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode)
|
||||
{
|
||||
struct nfsdfs_client *nc = inode->i_private;
|
||||
|
||||
if (nc)
|
||||
kref_get(&nc->cl_ref);
|
||||
return nc;
|
||||
}
|
||||
|
||||
struct nfsdfs_client *get_nfsdfs_client(struct inode *inode)
|
||||
{
|
||||
struct nfsdfs_client *nc;
|
||||
|
||||
rcu_read_lock();
|
||||
nc = __get_nfsdfs_client(inode);
|
||||
rcu_read_unlock();
|
||||
return nc;
|
||||
}
|
||||
/* from __rpc_unlink */
|
||||
static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
int ret;
|
||||
|
||||
clear_ncl(d_inode(dentry));
|
||||
dget(dentry);
|
||||
ret = simple_unlink(dir, dentry);
|
||||
d_delete(dentry);
|
||||
dput(dentry);
|
||||
WARN_ON_ONCE(ret);
|
||||
}
|
||||
|
||||
static void nfsdfs_remove_files(struct dentry *root)
|
||||
{
|
||||
struct dentry *dentry, *tmp;
|
||||
|
||||
list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) {
|
||||
if (!simple_positive(dentry)) {
|
||||
WARN_ON_ONCE(1); /* I think this can't happen? */
|
||||
continue;
|
||||
}
|
||||
nfsdfs_remove_file(d_inode(root), dentry);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: cut'n'paste from simple_fill_super; figure out if we could share
|
||||
* code instead. */
|
||||
static int nfsdfs_create_files(struct dentry *root,
|
||||
const struct tree_descr *files)
|
||||
{
|
||||
struct inode *dir = d_inode(root);
|
||||
struct inode *inode;
|
||||
struct dentry *dentry;
|
||||
int i;
|
||||
|
||||
inode_lock(dir);
|
||||
for (i = 0; files->name && files->name[0]; i++, files++) {
|
||||
if (!files->name)
|
||||
continue;
|
||||
dentry = d_alloc_name(root, files->name);
|
||||
if (!dentry)
|
||||
goto out;
|
||||
inode = nfsd_get_inode(d_inode(root)->i_sb,
|
||||
S_IFREG | files->mode);
|
||||
if (!inode) {
|
||||
dput(dentry);
|
||||
goto out;
|
||||
}
|
||||
inode->i_fop = files->ops;
|
||||
inode->i_private = __get_nfsdfs_client(dir);
|
||||
d_add(dentry, inode);
|
||||
fsnotify_create(dir, dentry);
|
||||
}
|
||||
inode_unlock(dir);
|
||||
return 0;
|
||||
out:
|
||||
nfsdfs_remove_files(root);
|
||||
inode_unlock(dir);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* on success, returns positive number unique to that client. */
|
||||
struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
|
||||
struct nfsdfs_client *ncl, u32 id,
|
||||
const struct tree_descr *files)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
char name[11];
|
||||
int ret;
|
||||
|
||||
sprintf(name, "%u", id);
|
||||
|
||||
return nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
|
||||
dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
|
||||
if (IS_ERR(dentry)) /* XXX: tossing errors? */
|
||||
return NULL;
|
||||
ret = nfsdfs_create_files(dentry, files);
|
||||
if (ret) {
|
||||
nfsd_client_rmdir(dentry);
|
||||
return NULL;
|
||||
}
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/* Taken from __rpc_rmdir: */
|
||||
|
@ -1223,16 +1325,16 @@ void nfsd_client_rmdir(struct dentry *dentry)
|
|||
{
|
||||
struct inode *dir = d_inode(dentry->d_parent);
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct nfsdfs_client *ncl = inode->i_private;
|
||||
int ret;
|
||||
|
||||
inode->i_private = NULL;
|
||||
synchronize_rcu();
|
||||
kref_put(&ncl->cl_ref, ncl->cl_release);
|
||||
inode_lock(dir);
|
||||
nfsdfs_remove_files(dentry);
|
||||
clear_ncl(inode);
|
||||
dget(dentry);
|
||||
ret = simple_rmdir(dir, dentry);
|
||||
WARN_ON_ONCE(ret);
|
||||
d_delete(dentry);
|
||||
inode_unlock(dir);
|
||||
}
|
||||
|
||||
static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
|
||||
|
|
|
@ -92,7 +92,9 @@ struct nfsdfs_client {
|
|||
void (*cl_release)(struct kref *kref);
|
||||
};
|
||||
|
||||
struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, struct nfsdfs_client *ncl, u32 id);
|
||||
struct nfsdfs_client *get_nfsdfs_client(struct inode *);
|
||||
struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
|
||||
struct nfsdfs_client *ncl, u32 id, const struct tree_descr *);
|
||||
void nfsd_client_rmdir(struct dentry *dentry);
|
||||
|
||||
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
|
||||
|
|
Loading…
Reference in New Issue