nfsctl.c (4ccdaba5ab560862f89d1d971fbcc2ef424e1867) | nfsctl.c (499aa1ca4eb6602df38afaecb88fc14edf50cdbb) |
---|---|
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Syscall interface to knfsd. 4 * 5 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 6 */ 7 8#include <linux/slab.h> --- 62 unchanged lines hidden (view full) --- 71static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); 72static ssize_t write_versions(struct file *file, char *buf, size_t size); 73static ssize_t write_ports(struct file *file, char *buf, size_t size); 74static ssize_t write_maxblksize(struct file *file, char *buf, size_t size); 75static ssize_t write_maxconn(struct file *file, char *buf, size_t size); 76#ifdef CONFIG_NFSD_V4 77static ssize_t write_leasetime(struct file *file, char *buf, size_t size); 78static ssize_t write_gracetime(struct file *file, char *buf, size_t size); | 1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Syscall interface to knfsd. 4 * 5 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 6 */ 7 8#include <linux/slab.h> --- 62 unchanged lines hidden (view full) --- 71static ssize_t write_pool_threads(struct file *file, char *buf, size_t size); 72static ssize_t write_versions(struct file *file, char *buf, size_t size); 73static ssize_t write_ports(struct file *file, char *buf, size_t size); 74static ssize_t write_maxblksize(struct file *file, char *buf, size_t size); 75static ssize_t write_maxconn(struct file *file, char *buf, size_t size); 76#ifdef CONFIG_NFSD_V4 77static ssize_t write_leasetime(struct file *file, char *buf, size_t size); 78static ssize_t write_gracetime(struct file *file, char *buf, size_t size); |
79#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING |
|
79static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | 80static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); |
81#endif |
|
80static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size); 81#endif 82 83static ssize_t (*const write_op[])(struct file *, char *, size_t) = { 84 [NFSD_Fh] = write_filehandle, 85 [NFSD_FO_UnlockIP] = write_unlock_ip, 86 [NFSD_FO_UnlockFS] = write_unlock_fs, 87 [NFSD_Threads] = write_threads, 88 [NFSD_Pool_Threads] = write_pool_threads, 89 [NFSD_Versions] = write_versions, 90 [NFSD_Ports] = write_ports, 91 [NFSD_MaxBlkSize] = write_maxblksize, 92 [NFSD_MaxConnections] = write_maxconn, 93#ifdef CONFIG_NFSD_V4 94 [NFSD_Leasetime] = write_leasetime, 95 [NFSD_Gracetime] = write_gracetime, | 82static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size); 83#endif 84 85static ssize_t (*const write_op[])(struct file *, char *, size_t) = { 86 [NFSD_Fh] = write_filehandle, 87 [NFSD_FO_UnlockIP] = write_unlock_ip, 88 [NFSD_FO_UnlockFS] = write_unlock_fs, 89 [NFSD_Threads] = write_threads, 90 [NFSD_Pool_Threads] = write_pool_threads, 91 [NFSD_Versions] = write_versions, 92 [NFSD_Ports] = write_ports, 93 [NFSD_MaxBlkSize] = write_maxblksize, 94 [NFSD_MaxConnections] = write_maxconn, 95#ifdef CONFIG_NFSD_V4 96 [NFSD_Leasetime] = write_leasetime, 97 [NFSD_Gracetime] = write_gracetime, |
98#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING |
|
96 [NFSD_RecoveryDir] = write_recoverydir, | 99 [NFSD_RecoveryDir] = write_recoverydir, |
100#endif |
|
97 [NFSD_V4EndGrace] = write_v4_end_grace, 98#endif 99}; 100 101static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) 102{ 103 ino_t ino = file_inode(file)->i_ino; 104 char *data; --- 69 unchanged lines hidden (view full) --- 174} 175 176DEFINE_SHOW_ATTRIBUTE(export_features); 177 178static const struct file_operations pool_stats_operations = { 179 .open = nfsd_pool_stats_open, 180 .read = seq_read, 181 .llseek = seq_lseek, | 101 [NFSD_V4EndGrace] = write_v4_end_grace, 102#endif 103}; 104 105static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) 106{ 107 ino_t ino = file_inode(file)->i_ino; 108 char *data; --- 69 unchanged lines hidden (view full) --- 178} 179 180DEFINE_SHOW_ATTRIBUTE(export_features); 181 182static const struct file_operations pool_stats_operations = { 183 .open = nfsd_pool_stats_open, 184 .read = seq_read, 185 .llseek = seq_lseek, |
182 .release = nfsd_pool_stats_release, | 186 .release = seq_release, |
183}; 184 185DEFINE_SHOW_ATTRIBUTE(nfsd_reply_cache_stats); 186 187DEFINE_SHOW_ATTRIBUTE(nfsd_file_cache_stats); 188 189/*----------------------------------------------------------------------------*/ 190/* --- 497 unchanged lines hidden (view full) --- 688 * a socket of a supported family/protocol, and we use it as an 689 * nfsd listener. 690 */ 691static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred *cred) 692{ 693 char *mesg = buf; 694 int fd, err; 695 struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 187}; 188 189DEFINE_SHOW_ATTRIBUTE(nfsd_reply_cache_stats); 190 191DEFINE_SHOW_ATTRIBUTE(nfsd_file_cache_stats); 192 193/*----------------------------------------------------------------------------*/ 194/* --- 497 unchanged lines hidden (view full) --- 692 * a socket of a supported family/protocol, and we use it as an 693 * nfsd listener. 694 */ 695static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred *cred) 696{ 697 char *mesg = buf; 698 int fd, err; 699 struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
700 struct svc_serv *serv; |
|
696 697 err = get_int(&mesg, &fd); 698 if (err != 0 || fd < 0) 699 return -EINVAL; 700 trace_nfsd_ctl_ports_addfd(net, fd); 701 702 err = nfsd_create_serv(net); 703 if (err != 0) 704 return err; 705 | 701 702 err = get_int(&mesg, &fd); 703 if (err != 0 || fd < 0) 704 return -EINVAL; 705 trace_nfsd_ctl_ports_addfd(net, fd); 706 707 err = nfsd_create_serv(net); 708 if (err != 0) 709 return err; 710 |
706 err = svc_addsock(nn->nfsd_serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); | 711 serv = nn->nfsd_serv; 712 err = svc_addsock(serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); |
707 | 713 |
708 if (err < 0 && !nn->nfsd_serv->sv_nrthreads && !nn->keep_active) 709 nfsd_last_thread(net); 710 else if (err >= 0 && 711 !nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) 712 svc_get(nn->nfsd_serv); | 714 if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks)) 715 nfsd_destroy_serv(net); |
713 | 716 |
714 nfsd_put(net); | |
715 return err; 716} 717 718/* 719 * A transport listener is added by writing its transport name and 720 * a port number. 721 */ 722static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cred *cred) 723{ 724 char transport[16]; 725 struct svc_xprt *xprt; 726 int port, err; 727 struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 717 return err; 718} 719 720/* 721 * A transport listener is added by writing its transport name and 722 * a port number. 723 */ 724static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cred *cred) 725{ 726 char transport[16]; 727 struct svc_xprt *xprt; 728 int port, err; 729 struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
730 struct svc_serv *serv; |
|
728 729 if (sscanf(buf, "%15s %5u", transport, &port) != 2) 730 return -EINVAL; 731 732 if (port < 1 || port > USHRT_MAX) 733 return -EINVAL; 734 trace_nfsd_ctl_ports_addxprt(net, transport, port); 735 736 err = nfsd_create_serv(net); 737 if (err != 0) 738 return err; 739 | 731 732 if (sscanf(buf, "%15s %5u", transport, &port) != 2) 733 return -EINVAL; 734 735 if (port < 1 || port > USHRT_MAX) 736 return -EINVAL; 737 trace_nfsd_ctl_ports_addxprt(net, transport, port); 738 739 err = nfsd_create_serv(net); 740 if (err != 0) 741 return err; 742 |
740 err = svc_xprt_create(nn->nfsd_serv, transport, net, | 743 serv = nn->nfsd_serv; 744 err = svc_xprt_create(serv, transport, net, |
741 PF_INET, port, SVC_SOCK_ANONYMOUS, cred); 742 if (err < 0) 743 goto out_err; 744 | 745 PF_INET, port, SVC_SOCK_ANONYMOUS, cred); 746 if (err < 0) 747 goto out_err; 748 |
745 err = svc_xprt_create(nn->nfsd_serv, transport, net, | 749 err = svc_xprt_create(serv, transport, net, |
746 PF_INET6, port, SVC_SOCK_ANONYMOUS, cred); 747 if (err < 0 && err != -EAFNOSUPPORT) 748 goto out_close; 749 | 750 PF_INET6, port, SVC_SOCK_ANONYMOUS, cred); 751 if (err < 0 && err != -EAFNOSUPPORT) 752 goto out_close; 753 |
750 if (!nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) 751 svc_get(nn->nfsd_serv); 752 753 nfsd_put(net); | |
754 return 0; 755out_close: | 754 return 0; 755out_close: |
756 xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port); | 756 xprt = svc_find_xprt(serv, transport, net, PF_INET, port); |
757 if (xprt != NULL) { 758 svc_xprt_close(xprt); 759 svc_xprt_put(xprt); 760 } 761out_err: | 757 if (xprt != NULL) { 758 svc_xprt_close(xprt); 759 svc_xprt_put(xprt); 760 } 761out_err: |
762 if (!nn->nfsd_serv->sv_nrthreads && !nn->keep_active) 763 nfsd_last_thread(net); | 762 if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks)) 763 nfsd_destroy_serv(net); |
764 | 764 |
765 nfsd_put(net); | |
766 return err; 767} 768 769static ssize_t __write_ports(struct file *file, char *buf, size_t size, 770 struct net *net) 771{ 772 if (size == 0) 773 return __write_ports_names(buf, net); --- 239 unchanged lines hidden (view full) --- 1013 * anyway.) 1014 */ 1015static ssize_t write_gracetime(struct file *file, char *buf, size_t size) 1016{ 1017 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id); 1018 return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn); 1019} 1020 | 765 return err; 766} 767 768static ssize_t __write_ports(struct file *file, char *buf, size_t size, 769 struct net *net) 770{ 771 if (size == 0) 772 return __write_ports_names(buf, net); --- 239 unchanged lines hidden (view full) --- 1012 * anyway.) 1013 */ 1014static ssize_t write_gracetime(struct file *file, char *buf, size_t size) 1015{ 1016 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id); 1017 return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn); 1018} 1019 |
1020#ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING |
|
1021static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size, 1022 struct nfsd_net *nn) 1023{ 1024 char *mesg = buf; 1025 char *recdir; 1026 int len, status; 1027 1028 if (size > 0) { --- 44 unchanged lines hidden (view full) --- 1073 ssize_t rv; 1074 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id); 1075 1076 mutex_lock(&nfsd_mutex); 1077 rv = __write_recoverydir(file, buf, size, nn); 1078 mutex_unlock(&nfsd_mutex); 1079 return rv; 1080} | 1021static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size, 1022 struct nfsd_net *nn) 1023{ 1024 char *mesg = buf; 1025 char *recdir; 1026 int len, status; 1027 1028 if (size > 0) { --- 44 unchanged lines hidden (view full) --- 1073 ssize_t rv; 1074 struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id); 1075 1076 mutex_lock(&nfsd_mutex); 1077 rv = __write_recoverydir(file, buf, size, nn); 1078 mutex_unlock(&nfsd_mutex); 1079 return rv; 1080} |
1081#endif |
|
1081 1082/* 1083 * write_v4_end_grace - release grace period for nfsd's v4.x lock manager 1084 * 1085 * Input: 1086 * buf: ignored 1087 * size: zero 1088 * OR --- 147 unchanged lines hidden (view full) --- 1236#else 1237static inline void _nfsd_symlink(struct dentry *parent, const char *name, 1238 const char *content) 1239{ 1240} 1241 1242#endif 1243 | 1082 1083/* 1084 * write_v4_end_grace - release grace period for nfsd's v4.x lock manager 1085 * 1086 * Input: 1087 * buf: ignored 1088 * size: zero 1089 * OR --- 147 unchanged lines hidden (view full) --- 1237#else 1238static inline void _nfsd_symlink(struct dentry *parent, const char *name, 1239 const char *content) 1240{ 1241} 1242 1243#endif 1244 |
1244static void clear_ncl(struct inode *inode) | 1245static void clear_ncl(struct dentry *dentry) |
1245{ | 1246{ |
1247 struct inode *inode = d_inode(dentry); |
|
1246 struct nfsdfs_client *ncl = inode->i_private; 1247 | 1248 struct nfsdfs_client *ncl = inode->i_private; 1249 |
1250 spin_lock(&inode->i_lock); |
|
1248 inode->i_private = NULL; | 1251 inode->i_private = NULL; |
1252 spin_unlock(&inode->i_lock); |
|
1249 kref_put(&ncl->cl_ref, ncl->cl_release); 1250} 1251 | 1253 kref_put(&ncl->cl_ref, ncl->cl_release); 1254} 1255 |
1252static struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode) | 1256struct nfsdfs_client *get_nfsdfs_client(struct inode *inode) |
1253{ | 1257{ |
1254 struct nfsdfs_client *nc = inode->i_private; | 1258 struct nfsdfs_client *nc; |
1255 | 1259 |
1260 spin_lock(&inode->i_lock); 1261 nc = inode->i_private; |
|
1256 if (nc) 1257 kref_get(&nc->cl_ref); | 1262 if (nc) 1263 kref_get(&nc->cl_ref); |
1264 spin_unlock(&inode->i_lock); |
|
1258 return nc; 1259} 1260 | 1265 return nc; 1266} 1267 |
1261struct nfsdfs_client *get_nfsdfs_client(struct inode *inode) 1262{ 1263 struct nfsdfs_client *nc; 1264 1265 inode_lock_shared(inode); 1266 nc = __get_nfsdfs_client(inode); 1267 inode_unlock_shared(inode); 1268 return nc; 1269} 1270/* from __rpc_unlink */ 1271static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry) 1272{ 1273 int ret; 1274 1275 clear_ncl(d_inode(dentry)); 1276 dget(dentry); 1277 ret = simple_unlink(dir, dentry); 1278 d_drop(dentry); 1279 fsnotify_unlink(dir, dentry); 1280 dput(dentry); 1281 WARN_ON_ONCE(ret); 1282} 1283 1284static void nfsdfs_remove_files(struct dentry *root) 1285{ 1286 struct dentry *dentry, *tmp; 1287 1288 list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) { 1289 if (!simple_positive(dentry)) { 1290 WARN_ON_ONCE(1); /* I think this can't happen? */ 1291 continue; 1292 } 1293 nfsdfs_remove_file(d_inode(root), dentry); 1294 } 1295} 1296 | |
1297/* XXX: cut'n'paste from simple_fill_super; figure out if we could share 1298 * code instead. */ 1299static int nfsdfs_create_files(struct dentry *root, 1300 const struct tree_descr *files, | 1268/* XXX: cut'n'paste from simple_fill_super; figure out if we could share 1269 * code instead. */ 1270static int nfsdfs_create_files(struct dentry *root, 1271 const struct tree_descr *files, |
1272 struct nfsdfs_client *ncl, |
|
1301 struct dentry **fdentries) 1302{ 1303 struct inode *dir = d_inode(root); 1304 struct inode *inode; 1305 struct dentry *dentry; 1306 int i; 1307 1308 inode_lock(dir); 1309 for (i = 0; files->name && files->name[0]; i++, files++) { 1310 dentry = d_alloc_name(root, files->name); 1311 if (!dentry) 1312 goto out; 1313 inode = nfsd_get_inode(d_inode(root)->i_sb, 1314 S_IFREG | files->mode); 1315 if (!inode) { 1316 dput(dentry); 1317 goto out; 1318 } | 1273 struct dentry **fdentries) 1274{ 1275 struct inode *dir = d_inode(root); 1276 struct inode *inode; 1277 struct dentry *dentry; 1278 int i; 1279 1280 inode_lock(dir); 1281 for (i = 0; files->name && files->name[0]; i++, files++) { 1282 dentry = d_alloc_name(root, files->name); 1283 if (!dentry) 1284 goto out; 1285 inode = nfsd_get_inode(d_inode(root)->i_sb, 1286 S_IFREG | files->mode); 1287 if (!inode) { 1288 dput(dentry); 1289 goto out; 1290 } |
1291 kref_get(&ncl->cl_ref); |
|
1319 inode->i_fop = files->ops; | 1292 inode->i_fop = files->ops; |
1320 inode->i_private = __get_nfsdfs_client(dir); | 1293 inode->i_private = ncl; |
1321 d_add(dentry, inode); 1322 fsnotify_create(dir, dentry); 1323 if (fdentries) 1324 fdentries[i] = dentry; 1325 } 1326 inode_unlock(dir); 1327 return 0; 1328out: | 1294 d_add(dentry, inode); 1295 fsnotify_create(dir, dentry); 1296 if (fdentries) 1297 fdentries[i] = dentry; 1298 } 1299 inode_unlock(dir); 1300 return 0; 1301out: |
1329 nfsdfs_remove_files(root); | |
1330 inode_unlock(dir); 1331 return -ENOMEM; 1332} 1333 1334/* on success, returns positive number unique to that client. */ 1335struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, 1336 struct nfsdfs_client *ncl, u32 id, 1337 const struct tree_descr *files, 1338 struct dentry **fdentries) 1339{ 1340 struct dentry *dentry; 1341 char name[11]; 1342 int ret; 1343 1344 sprintf(name, "%u", id); 1345 1346 dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name); 1347 if (IS_ERR(dentry)) /* XXX: tossing errors? */ 1348 return NULL; | 1302 inode_unlock(dir); 1303 return -ENOMEM; 1304} 1305 1306/* on success, returns positive number unique to that client. */ 1307struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, 1308 struct nfsdfs_client *ncl, u32 id, 1309 const struct tree_descr *files, 1310 struct dentry **fdentries) 1311{ 1312 struct dentry *dentry; 1313 char name[11]; 1314 int ret; 1315 1316 sprintf(name, "%u", id); 1317 1318 dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name); 1319 if (IS_ERR(dentry)) /* XXX: tossing errors? */ 1320 return NULL; |
1349 ret = nfsdfs_create_files(dentry, files, fdentries); | 1321 ret = nfsdfs_create_files(dentry, files, ncl, fdentries); |
1350 if (ret) { 1351 nfsd_client_rmdir(dentry); 1352 return NULL; 1353 } 1354 return dentry; 1355} 1356 1357/* Taken from __rpc_rmdir: */ 1358void nfsd_client_rmdir(struct dentry *dentry) 1359{ | 1322 if (ret) { 1323 nfsd_client_rmdir(dentry); 1324 return NULL; 1325 } 1326 return dentry; 1327} 1328 1329/* Taken from __rpc_rmdir: */ 1330void nfsd_client_rmdir(struct dentry *dentry) 1331{ |
1360 struct inode *dir = d_inode(dentry->d_parent); 1361 struct inode *inode = d_inode(dentry); 1362 int ret; 1363 1364 inode_lock(dir); 1365 nfsdfs_remove_files(dentry); 1366 clear_ncl(inode); 1367 dget(dentry); 1368 ret = simple_rmdir(dir, dentry); 1369 WARN_ON_ONCE(ret); 1370 d_drop(dentry); 1371 fsnotify_rmdir(dir, dentry); 1372 dput(dentry); 1373 inode_unlock(dir); | 1332 simple_recursive_removal(dentry, clear_ncl); |
1374} 1375 1376static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) 1377{ 1378 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 1379 nfsd_net_id); 1380 struct dentry *dentry; 1381 int ret; --- 457 unchanged lines hidden --- | 1333} 1334 1335static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) 1336{ 1337 struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 1338 nfsd_net_id); 1339 struct dentry *dentry; 1340 int ret; --- 457 unchanged lines hidden --- |