summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2019-03-22 11:11:06 -0400
committerJ. Bruce Fields <bfields@redhat.com>2019-07-03 17:52:49 -0400
commite8a79fb14f6b76b502218fce10696f4df9ff19b1 (patch)
tree8206e240dba02943e8e47a0118994b67b4ab30ea
parent59f8e91b75ecf16f22d62eca0659c13901eff5f3 (diff)
nfsd: add nfsd/clients directory
I plan to expose some information about nfsv4 clients here. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/netns.h2
-rw-r--r--fs/nfsd/nfs4state.c23
-rw-r--r--fs/nfsd/nfsctl.c103
-rw-r--r--fs/nfsd/nfsd.h9
-rw-r--r--fs/nfsd/state.h6
5 files changed, 133 insertions, 10 deletions
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index df4ba4b8b540..ad1d74383d67 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -45,6 +45,8 @@ struct nfsd_net {
45 /* internal mount of the "nfsd" pseudofilesystem: */ 45 /* internal mount of the "nfsd" pseudofilesystem: */
46 struct vfsmount *nfsd_mnt; 46 struct vfsmount *nfsd_mnt;
47 47
48 struct dentry *nfsd_client_dir;
49
48 /* 50 /*
49 * reclaim_str_hashtbl[] holds known client info from previous reset/reboot 51 * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
50 * used in reboot/reset lease grace period processing 52 * used in reboot/reset lease grace period processing
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index de68c3cbea2b..7d8d1fcc8831 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1881,20 +1881,19 @@ err_no_name:
1881 1881
1882static void __free_client(struct kref *k) 1882static void __free_client(struct kref *k)
1883{ 1883{
1884 struct nfs4_client *clp = container_of(k, struct nfs4_client, cl_ref); 1884 struct nfsdfs_client *c = container_of(k, struct nfsdfs_client, cl_ref);
1885 struct nfs4_client *clp = container_of(c, struct nfs4_client, cl_nfsdfs);
1885 1886
1886 free_svc_cred(&clp->cl_cred); 1887 free_svc_cred(&clp->cl_cred);
1887 kfree(clp->cl_ownerstr_hashtbl); 1888 kfree(clp->cl_ownerstr_hashtbl);
1888 kfree(clp->cl_name.data); 1889 kfree(clp->cl_name.data);
1889 idr_destroy(&clp->cl_stateids); 1890 idr_destroy(&clp->cl_stateids);
1890 if (clp->cl_nfsd_dentry)
1891 nfsd_client_rmdir(clp->cl_nfsd_dentry);
1892 kmem_cache_free(client_slab, clp); 1891 kmem_cache_free(client_slab, clp);
1893} 1892}
1894 1893
1895void drop_client(struct nfs4_client *clp) 1894void drop_client(struct nfs4_client *clp)
1896{ 1895{
1897 kref_put(&clp->cl_ref, __free_client); 1896 kref_put(&clp->cl_nfsdfs.cl_ref, __free_client);
1898} 1897}
1899 1898
1900static void 1899static void
@@ -1909,6 +1908,8 @@ free_client(struct nfs4_client *clp)
1909 free_session(ses); 1908 free_session(ses);
1910 } 1909 }
1911 rpc_destroy_wait_queue(&clp->cl_cb_waitq); 1910 rpc_destroy_wait_queue(&clp->cl_cb_waitq);
1911 if (clp->cl_nfsd_dentry)
1912 nfsd_client_rmdir(clp->cl_nfsd_dentry);
1912 drop_client(clp); 1913 drop_client(clp);
1913} 1914}
1914 1915
@@ -2220,6 +2221,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
2220 struct sockaddr *sa = svc_addr(rqstp); 2221 struct sockaddr *sa = svc_addr(rqstp);
2221 int ret; 2222 int ret;
2222 struct net *net = SVC_NET(rqstp); 2223 struct net *net = SVC_NET(rqstp);
2224 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
2223 2225
2224 clp = alloc_client(name); 2226 clp = alloc_client(name);
2225 if (clp == NULL) 2227 if (clp == NULL)
@@ -2230,8 +2232,8 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
2230 free_client(clp); 2232 free_client(clp);
2231 return NULL; 2233 return NULL;
2232 } 2234 }
2233 2235 gen_clid(clp, nn);
2234 kref_init(&clp->cl_ref); 2236 kref_init(&clp->cl_nfsdfs.cl_ref);
2235 nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 2237 nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL);
2236 clp->cl_time = get_seconds(); 2238 clp->cl_time = get_seconds();
2237 clear_bit(0, &clp->cl_cb_slot_busy); 2239 clear_bit(0, &clp->cl_cb_slot_busy);
@@ -2239,6 +2241,12 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
2239 rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); 2241 rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
2240 clp->cl_cb_session = NULL; 2242 clp->cl_cb_session = NULL;
2241 clp->net = net; 2243 clp->net = net;
2244 clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs,
2245 clp->cl_clientid.cl_id);
2246 if (!clp->cl_nfsd_dentry) {
2247 free_client(clp);
2248 return NULL;
2249 }
2242 return clp; 2250 return clp;
2243} 2251}
2244 2252
@@ -2683,7 +2691,6 @@ out_new:
2683 new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 2691 new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0];
2684 new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 2692 new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1];
2685 2693
2686 gen_clid(new, nn);
2687 add_to_unconfirmed(new); 2694 add_to_unconfirmed(new);
2688 swap(new, conf); 2695 swap(new, conf);
2689out_copy: 2696out_copy:
@@ -3427,7 +3434,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3427 copy_clid(new, conf); 3434 copy_clid(new, conf);
3428 gen_confirm(new, nn); 3435 gen_confirm(new, nn);
3429 } else /* case 4 (new client) or cases 2, 3 (client reboot): */ 3436 } else /* case 4 (new client) or cases 2, 3 (client reboot): */
3430 gen_clid(new, nn); 3437 ;
3431 new->cl_minorversion = 0; 3438 new->cl_minorversion = 0;
3432 gen_callback(new, setclid, rqstp); 3439 gen_callback(new, setclid, rqstp);
3433 add_to_unconfirmed(new); 3440 add_to_unconfirmed(new);
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 25910a7d21cc..5a1920a2de27 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -16,6 +16,7 @@
16#include <linux/sunrpc/gss_krb5_enctypes.h> 16#include <linux/sunrpc/gss_krb5_enctypes.h>
17#include <linux/sunrpc/rpc_pipe_fs.h> 17#include <linux/sunrpc/rpc_pipe_fs.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/fsnotify.h>
19 20
20#include "idmap.h" 21#include "idmap.h"
21#include "nfsd.h" 22#include "nfsd.h"
@@ -53,6 +54,7 @@ enum {
53 NFSD_RecoveryDir, 54 NFSD_RecoveryDir,
54 NFSD_V4EndGrace, 55 NFSD_V4EndGrace,
55#endif 56#endif
57 NFSD_MaxReserved
56}; 58};
57 59
58/* 60/*
@@ -1147,8 +1149,99 @@ static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
1147 * populating the filesystem. 1149 * populating the filesystem.
1148 */ 1150 */
1149 1151
1152/* Basically copying rpc_get_inode. */
1153static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode)
1154{
1155 struct inode *inode = new_inode(sb);
1156 if (!inode)
1157 return NULL;
1158 /* Following advice from simple_fill_super documentation: */
1159 inode->i_ino = iunique(sb, NFSD_MaxReserved);
1160 inode->i_mode = mode;
1161 inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
1162 switch (mode & S_IFMT) {
1163 case S_IFDIR:
1164 inode->i_fop = &simple_dir_operations;
1165 inode->i_op = &simple_dir_inode_operations;
1166 inc_nlink(inode);
1167 default:
1168 break;
1169 }
1170 return inode;
1171}
1172
1173static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1174{
1175 struct inode *inode;
1176
1177 inode = nfsd_get_inode(dir->i_sb, mode);
1178 if (!inode)
1179 return -ENOMEM;
1180 d_add(dentry, inode);
1181 inc_nlink(dir);
1182 fsnotify_mkdir(dir, dentry);
1183 return 0;
1184}
1185
1186static struct dentry *nfsd_mkdir(struct dentry *parent, struct nfsdfs_client *ncl, char *name)
1187{
1188 struct inode *dir = parent->d_inode;
1189 struct dentry *dentry;
1190 int ret = -ENOMEM;
1191
1192 inode_lock(dir);
1193 dentry = d_alloc_name(parent, name);
1194 if (!dentry)
1195 goto out_err;
1196 ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600);
1197 if (ret)
1198 goto out_err;
1199 if (ncl) {
1200 d_inode(dentry)->i_private = ncl;
1201 kref_get(&ncl->cl_ref);
1202 }
1203out:
1204 inode_unlock(dir);
1205 return dentry;
1206out_err:
1207 dentry = ERR_PTR(ret);
1208 goto out;
1209}
1210
1211/* on success, returns positive number unique to that client. */
1212struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, struct nfsdfs_client *ncl, u32 id)
1213{
1214 char name[11];
1215
1216 sprintf(name, "%d", id++);
1217
1218 return nfsd_mkdir(nn->nfsd_client_dir, ncl, name);
1219}
1220
1221/* Taken from __rpc_rmdir: */
1222void nfsd_client_rmdir(struct dentry *dentry)
1223{
1224 struct inode *dir = d_inode(dentry->d_parent);
1225 struct inode *inode = d_inode(dentry);
1226 struct nfsdfs_client *ncl = inode->i_private;
1227 int ret;
1228
1229 inode->i_private = NULL;
1230 synchronize_rcu();
1231 kref_put(&ncl->cl_ref, ncl->cl_release);
1232 dget(dentry);
1233 ret = simple_rmdir(dir, dentry);
1234 WARN_ON_ONCE(ret);
1235 d_delete(dentry);
1236}
1237
1150static int nfsd_fill_super(struct super_block * sb, void * data, int silent) 1238static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1151{ 1239{
1240 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
1241 nfsd_net_id);
1242 struct dentry *dentry;
1243 int ret;
1244
1152 static const struct tree_descr nfsd_files[] = { 1245 static const struct tree_descr nfsd_files[] = {
1153 [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO}, 1246 [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO},
1154 [NFSD_Export_features] = {"export_features", 1247 [NFSD_Export_features] = {"export_features",
@@ -1178,7 +1271,15 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
1178 /* last one */ {""} 1271 /* last one */ {""}
1179 }; 1272 };
1180 get_net(sb->s_fs_info); 1273 get_net(sb->s_fs_info);
1181 return simple_fill_super(sb, 0x6e667364, nfsd_files); 1274 ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
1275 if (ret)
1276 return ret;
1277 dentry = nfsd_mkdir(sb->s_root, NULL, "clients");
1278 if (IS_ERR(dentry))
1279 return PTR_ERR(dentry);
1280 nn->nfsd_client_dir = dentry;
1281 return 0;
1282
1182} 1283}
1183 1284
1184static struct dentry *nfsd_mount(struct file_system_type *fs_type, 1285static struct dentry *nfsd_mount(struct file_system_type *fs_type,
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 24187b5dd638..85525dcbf77d 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -22,6 +22,7 @@
22 22
23#include <uapi/linux/nfsd/debug.h> 23#include <uapi/linux/nfsd/debug.h>
24 24
25#include "netns.h"
25#include "stats.h" 26#include "stats.h"
26#include "export.h" 27#include "export.h"
27 28
@@ -86,6 +87,14 @@ int nfsd_pool_stats_release(struct inode *, struct file *);
86 87
87void nfsd_destroy(struct net *net); 88void nfsd_destroy(struct net *net);
88 89
90struct nfsdfs_client {
91 struct kref cl_ref;
92 void (*cl_release)(struct kref *kref);
93};
94
95struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, struct nfsdfs_client *ncl, u32 id);
96void nfsd_client_rmdir(struct dentry *dentry);
97
89#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) 98#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
90#ifdef CONFIG_NFSD_V2_ACL 99#ifdef CONFIG_NFSD_V2_ACL
91extern const struct svc_version nfsd_acl_version2; 100extern const struct svc_version nfsd_acl_version2;
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 8eacdbc50cd7..81852cbf6b0a 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -39,6 +39,7 @@
39#include <linux/refcount.h> 39#include <linux/refcount.h>
40#include <linux/sunrpc/svc_xprt.h> 40#include <linux/sunrpc/svc_xprt.h>
41#include "nfsfh.h" 41#include "nfsfh.h"
42#include "nfsd.h"
42 43
43typedef struct { 44typedef struct {
44 u32 cl_boot; 45 u32 cl_boot;
@@ -348,9 +349,12 @@ struct nfs4_client {
348 u32 cl_exchange_flags; 349 u32 cl_exchange_flags;
349 /* number of rpc's in progress over an associated session: */ 350 /* number of rpc's in progress over an associated session: */
350 atomic_t cl_rpc_users; 351 atomic_t cl_rpc_users;
351 struct kref cl_ref; 352 struct nfsdfs_client cl_nfsdfs;
352 struct nfs4_op_map cl_spo_must_allow; 353 struct nfs4_op_map cl_spo_must_allow;
353 354
355 /* debugging info directory under nfsd/clients/ : */
356 struct dentry *cl_nfsd_dentry;
357
354 /* for nfs41 callbacks */ 358 /* for nfs41 callbacks */
355 /* We currently support a single back channel with a single slot */ 359 /* We currently support a single back channel with a single slot */
356 unsigned long cl_cb_slot_busy; 360 unsigned long cl_cb_slot_busy;