summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2019-04-09 15:56:57 -0400
committerJ. Bruce Fields <bfields@redhat.com>2019-07-03 17:52:50 -0400
commit97ad4031e29521894fc28765f14247e79b0ef263 (patch)
treedaec545c5697807abc3b7182f15b2c8086fd71a2
parentbf5ed3e3bb84c39d70ad10b2f8e47ec62f4c63b1 (diff)
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>
-rw-r--r--fs/nfsd/nfs4state.c38
-rw-r--r--fs/nfsd/nfsctl.c114
-rw-r--r--fs/nfsd/nfsd.h4
3 files changed, 148 insertions, 8 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8f9747d84525..a6c722dc7e5e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2214,6 +2214,41 @@ find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask)
2214 return s; 2214 return s;
2215} 2215}
2216 2216
2217static int client_info_show(struct seq_file *m, void *v)
2218{
2219 struct inode *inode = m->private;
2220 struct nfsdfs_client *nc;
2221 struct nfs4_client *clp;
2222 u64 clid;
2223
2224 nc = get_nfsdfs_client(inode);
2225 if (!nc)
2226 return -ENXIO;
2227 clp = container_of(nc, struct nfs4_client, cl_nfsdfs);
2228 memcpy(&clid, &clp->cl_clientid, sizeof(clid));
2229 seq_printf(m, "clientid: 0x%llx\n", clid);
2230 drop_client(clp);
2231
2232 return 0;
2233}
2234
2235static int client_info_open(struct inode *inode, struct file *file)
2236{
2237 return single_open(file, client_info_show, inode);
2238}
2239
2240static const struct file_operations client_info_fops = {
2241 .open = client_info_open,
2242 .read = seq_read,
2243 .llseek = seq_lseek,
2244 .release = single_release,
2245};
2246
2247static const struct tree_descr client_files[] = {
2248 [0] = {"info", &client_info_fops, S_IRUSR},
2249 [1] = {""},
2250};
2251
2217static struct nfs4_client *create_client(struct xdr_netobj name, 2252static struct nfs4_client *create_client(struct xdr_netobj name,
2218 struct svc_rqst *rqstp, nfs4_verifier *verf) 2253 struct svc_rqst *rqstp, nfs4_verifier *verf)
2219{ 2254{
@@ -2242,7 +2277,8 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
2242 clp->cl_cb_session = NULL; 2277 clp->cl_cb_session = NULL;
2243 clp->net = net; 2278 clp->net = net;
2244 clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs, 2279 clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs,
2245 clp->cl_clientid.cl_id - nn->clientid_base); 2280 clp->cl_clientid.cl_id - nn->clientid_base,
2281 client_files);
2246 if (!clp->cl_nfsd_dentry) { 2282 if (!clp->cl_nfsd_dentry) {
2247 free_client(clp); 2283 free_client(clp);
2248 return NULL; 2284 return NULL;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 599d600f0658..4683ba5c69c7 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1208,14 +1208,116 @@ out_err:
1208 goto out; 1208 goto out;
1209} 1209}
1210 1210
1211static void clear_ncl(struct inode *inode)
1212{
1213 struct nfsdfs_client *ncl = inode->i_private;
1214
1215 inode->i_private = NULL;
1216 synchronize_rcu();
1217 kref_put(&ncl->cl_ref, ncl->cl_release);
1218}
1219
1220
1221struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode)
1222{
1223 struct nfsdfs_client *nc = inode->i_private;
1224
1225 if (nc)
1226 kref_get(&nc->cl_ref);
1227 return nc;
1228}
1229
1230struct nfsdfs_client *get_nfsdfs_client(struct inode *inode)
1231{
1232 struct nfsdfs_client *nc;
1233
1234 rcu_read_lock();
1235 nc = __get_nfsdfs_client(inode);
1236 rcu_read_unlock();
1237 return nc;
1238}
1239/* from __rpc_unlink */
1240static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry)
1241{
1242 int ret;
1243
1244 clear_ncl(d_inode(dentry));
1245 dget(dentry);
1246 ret = simple_unlink(dir, dentry);
1247 d_delete(dentry);
1248 dput(dentry);
1249 WARN_ON_ONCE(ret);
1250}
1251
1252static void nfsdfs_remove_files(struct dentry *root)
1253{
1254 struct dentry *dentry, *tmp;
1255
1256 list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) {
1257 if (!simple_positive(dentry)) {
1258 WARN_ON_ONCE(1); /* I think this can't happen? */
1259 continue;
1260 }
1261 nfsdfs_remove_file(d_inode(root), dentry);
1262 }
1263}
1264
1265/* XXX: cut'n'paste from simple_fill_super; figure out if we could share
1266 * code instead. */
1267static int nfsdfs_create_files(struct dentry *root,
1268 const struct tree_descr *files)
1269{
1270 struct inode *dir = d_inode(root);
1271 struct inode *inode;
1272 struct dentry *dentry;
1273 int i;
1274
1275 inode_lock(dir);
1276 for (i = 0; files->name && files->name[0]; i++, files++) {
1277 if (!files->name)
1278 continue;
1279 dentry = d_alloc_name(root, files->name);
1280 if (!dentry)
1281 goto out;
1282 inode = nfsd_get_inode(d_inode(root)->i_sb,
1283 S_IFREG | files->mode);
1284 if (!inode) {
1285 dput(dentry);
1286 goto out;
1287 }
1288 inode->i_fop = files->ops;
1289 inode->i_private = __get_nfsdfs_client(dir);
1290 d_add(dentry, inode);
1291 fsnotify_create(dir, dentry);
1292 }
1293 inode_unlock(dir);
1294 return 0;
1295out:
1296 nfsdfs_remove_files(root);
1297 inode_unlock(dir);
1298 return -ENOMEM;
1299}
1300
1211/* on success, returns positive number unique to that client. */ 1301/* on success, returns positive number unique to that client. */
1212struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, struct nfsdfs_client *ncl, u32 id) 1302struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
1303 struct nfsdfs_client *ncl, u32 id,
1304 const struct tree_descr *files)
1213{ 1305{
1306 struct dentry *dentry;
1214 char name[11]; 1307 char name[11];
1308 int ret;
1215 1309
1216 sprintf(name, "%u", id); 1310 sprintf(name, "%u", id);
1217 1311
1218 return nfsd_mkdir(nn->nfsd_client_dir, ncl, name); 1312 dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
1313 if (IS_ERR(dentry)) /* XXX: tossing errors? */
1314 return NULL;
1315 ret = nfsdfs_create_files(dentry, files);
1316 if (ret) {
1317 nfsd_client_rmdir(dentry);
1318 return NULL;
1319 }
1320 return dentry;
1219} 1321}
1220 1322
1221/* Taken from __rpc_rmdir: */ 1323/* Taken from __rpc_rmdir: */
@@ -1223,16 +1325,16 @@ void nfsd_client_rmdir(struct dentry *dentry)
1223{ 1325{
1224 struct inode *dir = d_inode(dentry->d_parent); 1326 struct inode *dir = d_inode(dentry->d_parent);
1225 struct inode *inode = d_inode(dentry); 1327 struct inode *inode = d_inode(dentry);
1226 struct nfsdfs_client *ncl = inode->i_private;
1227 int ret; 1328 int ret;
1228 1329
1229 inode->i_private = NULL; 1330 inode_lock(dir);
1230 synchronize_rcu(); 1331 nfsdfs_remove_files(dentry);
1231 kref_put(&ncl->cl_ref, ncl->cl_release); 1332 clear_ncl(inode);
1232 dget(dentry); 1333 dget(dentry);
1233 ret = simple_rmdir(dir, dentry); 1334 ret = simple_rmdir(dir, dentry);
1234 WARN_ON_ONCE(ret); 1335 WARN_ON_ONCE(ret);
1235 d_delete(dentry); 1336 d_delete(dentry);
1337 inode_unlock(dir);
1236} 1338}
1237 1339
1238static int nfsd_fill_super(struct super_block * sb, void * data, int silent) 1340static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 85525dcbf77d..af2947551e9c 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -92,7 +92,9 @@ struct nfsdfs_client {
92 void (*cl_release)(struct kref *kref); 92 void (*cl_release)(struct kref *kref);
93}; 93};
94 94
95struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, struct nfsdfs_client *ncl, u32 id); 95struct nfsdfs_client *get_nfsdfs_client(struct inode *);
96struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
97 struct nfsdfs_client *ncl, u32 id, const struct tree_descr *);
96void nfsd_client_rmdir(struct dentry *dentry); 98void nfsd_client_rmdir(struct dentry *dentry);
97 99
98#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) 100#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)