diff options
author | J. Bruce Fields <bfields@redhat.com> | 2019-03-22 11:11:06 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2019-07-03 17:52:49 -0400 |
commit | e8a79fb14f6b76b502218fce10696f4df9ff19b1 (patch) | |
tree | 8206e240dba02943e8e47a0118994b67b4ab30ea | |
parent | 59f8e91b75ecf16f22d62eca0659c13901eff5f3 (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.h | 2 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 23 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 103 | ||||
-rw-r--r-- | fs/nfsd/nfsd.h | 9 | ||||
-rw-r--r-- | fs/nfsd/state.h | 6 |
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 | ||
1882 | static void __free_client(struct kref *k) | 1882 | static 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 | ||
1895 | void drop_client(struct nfs4_client *clp) | 1894 | void 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 | ||
1900 | static void | 1899 | static 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); |
2689 | out_copy: | 2696 | out_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. */ | ||
1153 | static 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 | |||
1173 | static 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 | |||
1186 | static 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 | } | ||
1203 | out: | ||
1204 | inode_unlock(dir); | ||
1205 | return dentry; | ||
1206 | out_err: | ||
1207 | dentry = ERR_PTR(ret); | ||
1208 | goto out; | ||
1209 | } | ||
1210 | |||
1211 | /* on success, returns positive number unique to that client. */ | ||
1212 | struct 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: */ | ||
1222 | void 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 | |||
1150 | static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | 1238 | static 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 | ||
1184 | static struct dentry *nfsd_mount(struct file_system_type *fs_type, | 1285 | static 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 | ||
87 | void nfsd_destroy(struct net *net); | 88 | void nfsd_destroy(struct net *net); |
88 | 89 | ||
90 | struct nfsdfs_client { | ||
91 | struct kref cl_ref; | ||
92 | void (*cl_release)(struct kref *kref); | ||
93 | }; | ||
94 | |||
95 | struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, struct nfsdfs_client *ncl, u32 id); | ||
96 | void 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 |
91 | extern const struct svc_version nfsd_acl_version2; | 100 | extern 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 | ||
43 | typedef struct { | 44 | typedef 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; |