.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Syscall interface to knfsd. |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | #include <linux/slab.h> |
---|
8 | 9 | #include <linux/namei.h> |
---|
9 | 10 | #include <linux/ctype.h> |
---|
| 11 | +#include <linux/fs_context.h> |
---|
10 | 12 | |
---|
11 | 13 | #include <linux/sunrpc/svcsock.h> |
---|
12 | 14 | #include <linux/lockd/lockd.h> |
---|
.. | .. |
---|
15 | 17 | #include <linux/sunrpc/gss_krb5_enctypes.h> |
---|
16 | 18 | #include <linux/sunrpc/rpc_pipe_fs.h> |
---|
17 | 19 | #include <linux/module.h> |
---|
| 20 | +#include <linux/fsnotify.h> |
---|
18 | 21 | |
---|
19 | 22 | #include "idmap.h" |
---|
20 | 23 | #include "nfsd.h" |
---|
.. | .. |
---|
52 | 55 | NFSD_RecoveryDir, |
---|
53 | 56 | NFSD_V4EndGrace, |
---|
54 | 57 | #endif |
---|
| 58 | + NFSD_MaxReserved |
---|
55 | 59 | }; |
---|
56 | 60 | |
---|
57 | 61 | /* |
---|
.. | .. |
---|
153 | 157 | return exports_net_open(current->nsproxy->net_ns, file); |
---|
154 | 158 | } |
---|
155 | 159 | |
---|
156 | | -static const struct file_operations exports_proc_operations = { |
---|
157 | | - .open = exports_proc_open, |
---|
158 | | - .read = seq_read, |
---|
159 | | - .llseek = seq_lseek, |
---|
160 | | - .release = seq_release, |
---|
| 160 | +static const struct proc_ops exports_proc_ops = { |
---|
| 161 | + .proc_open = exports_proc_open, |
---|
| 162 | + .proc_read = seq_read, |
---|
| 163 | + .proc_lseek = seq_lseek, |
---|
| 164 | + .proc_release = seq_release, |
---|
161 | 165 | }; |
---|
162 | 166 | |
---|
163 | 167 | static int exports_nfsd_open(struct inode *inode, struct file *file) |
---|
.. | .. |
---|
234 | 238 | return file_inode(file)->i_sb->s_fs_info; |
---|
235 | 239 | } |
---|
236 | 240 | |
---|
237 | | -/** |
---|
| 241 | +/* |
---|
238 | 242 | * write_unlock_ip - Release all locks used by a client |
---|
239 | 243 | * |
---|
240 | 244 | * Experimental. |
---|
.. | .. |
---|
273 | 277 | return nlmsvc_unlock_all_by_ip(sap); |
---|
274 | 278 | } |
---|
275 | 279 | |
---|
276 | | -/** |
---|
| 280 | +/* |
---|
277 | 281 | * write_unlock_fs - Release all locks on a local file system |
---|
278 | 282 | * |
---|
279 | 283 | * Experimental. |
---|
.. | .. |
---|
323 | 327 | return error; |
---|
324 | 328 | } |
---|
325 | 329 | |
---|
326 | | -/** |
---|
| 330 | +/* |
---|
327 | 331 | * write_filehandle - Get a variable-length NFS file handle by path |
---|
328 | 332 | * |
---|
329 | 333 | * On input, the buffer contains a '\n'-terminated C string comprised of |
---|
.. | .. |
---|
347 | 351 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size) |
---|
348 | 352 | { |
---|
349 | 353 | char *dname, *path; |
---|
350 | | - int uninitialized_var(maxsize); |
---|
| 354 | + int maxsize; |
---|
351 | 355 | char *mesg = buf; |
---|
352 | 356 | int len; |
---|
353 | 357 | struct auth_domain *dom; |
---|
.. | .. |
---|
398 | 402 | return mesg - buf; |
---|
399 | 403 | } |
---|
400 | 404 | |
---|
401 | | -/** |
---|
| 405 | +/* |
---|
402 | 406 | * write_threads - Start NFSD, or report the current number of running threads |
---|
403 | 407 | * |
---|
404 | 408 | * Input: |
---|
.. | .. |
---|
439 | 443 | return rv; |
---|
440 | 444 | if (newthreads < 0) |
---|
441 | 445 | return -EINVAL; |
---|
442 | | - rv = nfsd_svc(newthreads, net); |
---|
| 446 | + rv = nfsd_svc(newthreads, net, file->f_cred); |
---|
443 | 447 | if (rv < 0) |
---|
444 | 448 | return rv; |
---|
445 | 449 | } else |
---|
.. | .. |
---|
448 | 452 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); |
---|
449 | 453 | } |
---|
450 | 454 | |
---|
451 | | -/** |
---|
| 455 | +/* |
---|
452 | 456 | * write_pool_threads - Set or report the current number of threads per pool |
---|
453 | 457 | * |
---|
454 | 458 | * Input: |
---|
.. | .. |
---|
537 | 541 | } |
---|
538 | 542 | |
---|
539 | 543 | static ssize_t |
---|
540 | | -nfsd_print_version_support(char *buf, int remaining, const char *sep, |
---|
541 | | - unsigned vers, int minor) |
---|
| 544 | +nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining, |
---|
| 545 | + const char *sep, unsigned vers, int minor) |
---|
542 | 546 | { |
---|
543 | 547 | const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u"; |
---|
544 | | - bool supported = !!nfsd_vers(vers, NFSD_TEST); |
---|
| 548 | + bool supported = !!nfsd_vers(nn, vers, NFSD_TEST); |
---|
545 | 549 | |
---|
546 | 550 | if (vers == 4 && minor >= 0 && |
---|
547 | | - !nfsd_minorversion(minor, NFSD_TEST)) |
---|
| 551 | + !nfsd_minorversion(nn, minor, NFSD_TEST)) |
---|
548 | 552 | supported = false; |
---|
549 | 553 | if (minor == 0 && supported) |
---|
550 | 554 | /* |
---|
.. | .. |
---|
599 | 603 | switch(num) { |
---|
600 | 604 | case 2: |
---|
601 | 605 | case 3: |
---|
602 | | - nfsd_vers(num, cmd); |
---|
| 606 | + nfsd_vers(nn, num, cmd); |
---|
603 | 607 | break; |
---|
604 | 608 | case 4: |
---|
605 | 609 | if (*minorp == '.') { |
---|
606 | | - if (nfsd_minorversion(minor, cmd) < 0) |
---|
| 610 | + if (nfsd_minorversion(nn, minor, cmd) < 0) |
---|
607 | 611 | return -EINVAL; |
---|
608 | | - } else if ((cmd == NFSD_SET) != nfsd_vers(num, NFSD_TEST)) { |
---|
| 612 | + } else if ((cmd == NFSD_SET) != nfsd_vers(nn, num, NFSD_TEST)) { |
---|
609 | 613 | /* |
---|
610 | 614 | * Either we have +4 and no minors are enabled, |
---|
611 | 615 | * or we have -4 and at least one minor is enabled. |
---|
612 | 616 | * In either case, propagate 'cmd' to all minors. |
---|
613 | 617 | */ |
---|
614 | 618 | minor = 0; |
---|
615 | | - while (nfsd_minorversion(minor, cmd) >= 0) |
---|
| 619 | + while (nfsd_minorversion(nn, minor, cmd) >= 0) |
---|
616 | 620 | minor++; |
---|
617 | 621 | } |
---|
618 | 622 | break; |
---|
.. | .. |
---|
624 | 628 | /* If all get turned off, turn them back on, as |
---|
625 | 629 | * having no versions is BAD |
---|
626 | 630 | */ |
---|
627 | | - nfsd_reset_versions(); |
---|
| 631 | + nfsd_reset_versions(nn); |
---|
628 | 632 | } |
---|
629 | 633 | |
---|
630 | 634 | /* Now write current state into reply buffer */ |
---|
.. | .. |
---|
633 | 637 | remaining = SIMPLE_TRANSACTION_LIMIT; |
---|
634 | 638 | for (num=2 ; num <= 4 ; num++) { |
---|
635 | 639 | int minor; |
---|
636 | | - if (!nfsd_vers(num, NFSD_AVAIL)) |
---|
| 640 | + if (!nfsd_vers(nn, num, NFSD_AVAIL)) |
---|
637 | 641 | continue; |
---|
638 | 642 | |
---|
639 | 643 | minor = -1; |
---|
640 | 644 | do { |
---|
641 | | - len = nfsd_print_version_support(buf, remaining, |
---|
| 645 | + len = nfsd_print_version_support(nn, buf, remaining, |
---|
642 | 646 | sep, num, minor); |
---|
643 | 647 | if (len >= remaining) |
---|
644 | 648 | goto out; |
---|
.. | .. |
---|
657 | 661 | return tlen + len; |
---|
658 | 662 | } |
---|
659 | 663 | |
---|
660 | | -/** |
---|
| 664 | +/* |
---|
661 | 665 | * write_versions - Set or report the available NFS protocol versions |
---|
662 | 666 | * |
---|
663 | 667 | * Input: |
---|
.. | .. |
---|
717 | 721 | * a socket of a supported family/protocol, and we use it as an |
---|
718 | 722 | * nfsd listener. |
---|
719 | 723 | */ |
---|
720 | | -static ssize_t __write_ports_addfd(char *buf, struct net *net) |
---|
| 724 | +static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred *cred) |
---|
721 | 725 | { |
---|
722 | 726 | char *mesg = buf; |
---|
723 | 727 | int fd, err; |
---|
.. | .. |
---|
736 | 740 | if (err != 0) |
---|
737 | 741 | return err; |
---|
738 | 742 | |
---|
739 | | - err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
---|
| 743 | + err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); |
---|
740 | 744 | if (err < 0) { |
---|
741 | 745 | nfsd_destroy(net); |
---|
742 | 746 | return err; |
---|
.. | .. |
---|
751 | 755 | * A transport listener is added by writing it's transport name and |
---|
752 | 756 | * a port number. |
---|
753 | 757 | */ |
---|
754 | | -static ssize_t __write_ports_addxprt(char *buf, struct net *net) |
---|
| 758 | +static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cred *cred) |
---|
755 | 759 | { |
---|
756 | 760 | char transport[16]; |
---|
757 | 761 | struct svc_xprt *xprt; |
---|
.. | .. |
---|
769 | 773 | return err; |
---|
770 | 774 | |
---|
771 | 775 | err = svc_create_xprt(nn->nfsd_serv, transport, net, |
---|
772 | | - PF_INET, port, SVC_SOCK_ANONYMOUS); |
---|
| 776 | + PF_INET, port, SVC_SOCK_ANONYMOUS, cred); |
---|
773 | 777 | if (err < 0) |
---|
774 | 778 | goto out_err; |
---|
775 | 779 | |
---|
776 | 780 | err = svc_create_xprt(nn->nfsd_serv, transport, net, |
---|
777 | | - PF_INET6, port, SVC_SOCK_ANONYMOUS); |
---|
| 781 | + PF_INET6, port, SVC_SOCK_ANONYMOUS, cred); |
---|
778 | 782 | if (err < 0 && err != -EAFNOSUPPORT) |
---|
779 | 783 | goto out_close; |
---|
780 | 784 | |
---|
.. | .. |
---|
802 | 806 | return __write_ports_names(buf, net); |
---|
803 | 807 | |
---|
804 | 808 | if (isdigit(buf[0])) |
---|
805 | | - return __write_ports_addfd(buf, net); |
---|
| 809 | + return __write_ports_addfd(buf, net, file->f_cred); |
---|
806 | 810 | |
---|
807 | 811 | if (isalpha(buf[0])) |
---|
808 | | - return __write_ports_addxprt(buf, net); |
---|
| 812 | + return __write_ports_addxprt(buf, net, file->f_cred); |
---|
809 | 813 | |
---|
810 | 814 | return -EINVAL; |
---|
811 | 815 | } |
---|
812 | 816 | |
---|
813 | | -/** |
---|
| 817 | +/* |
---|
814 | 818 | * write_ports - Pass a socket file descriptor or transport name to listen on |
---|
815 | 819 | * |
---|
816 | 820 | * Input: |
---|
.. | .. |
---|
866 | 870 | |
---|
867 | 871 | int nfsd_max_blksize; |
---|
868 | 872 | |
---|
869 | | -/** |
---|
| 873 | +/* |
---|
870 | 874 | * write_maxblksize - Set or report the current NFS blksize |
---|
871 | 875 | * |
---|
872 | 876 | * Input: |
---|
.. | .. |
---|
916 | 920 | nfsd_max_blksize); |
---|
917 | 921 | } |
---|
918 | 922 | |
---|
919 | | -/** |
---|
| 923 | +/* |
---|
920 | 924 | * write_maxconn - Set or report the current max number of connections |
---|
921 | 925 | * |
---|
922 | 926 | * Input: |
---|
.. | .. |
---|
955 | 959 | |
---|
956 | 960 | #ifdef CONFIG_NFSD_V4 |
---|
957 | 961 | static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, |
---|
958 | | - time_t *time, struct nfsd_net *nn) |
---|
| 962 | + time64_t *time, struct nfsd_net *nn) |
---|
959 | 963 | { |
---|
960 | 964 | char *mesg = buf; |
---|
961 | 965 | int rv, i; |
---|
.. | .. |
---|
983 | 987 | *time = i; |
---|
984 | 988 | } |
---|
985 | 989 | |
---|
986 | | - return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time); |
---|
| 990 | + return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%lld\n", *time); |
---|
987 | 991 | } |
---|
988 | 992 | |
---|
989 | 993 | static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, |
---|
990 | | - time_t *time, struct nfsd_net *nn) |
---|
| 994 | + time64_t *time, struct nfsd_net *nn) |
---|
991 | 995 | { |
---|
992 | 996 | ssize_t rv; |
---|
993 | 997 | |
---|
.. | .. |
---|
997 | 1001 | return rv; |
---|
998 | 1002 | } |
---|
999 | 1003 | |
---|
1000 | | -/** |
---|
| 1004 | +/* |
---|
1001 | 1005 | * write_leasetime - Set or report the current NFSv4 lease time |
---|
1002 | 1006 | * |
---|
1003 | 1007 | * Input: |
---|
.. | .. |
---|
1024 | 1028 | return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn); |
---|
1025 | 1029 | } |
---|
1026 | 1030 | |
---|
1027 | | -/** |
---|
| 1031 | +/* |
---|
1028 | 1032 | * write_gracetime - Set or report current NFSv4 grace period time |
---|
1029 | 1033 | * |
---|
1030 | 1034 | * As above, but sets the time of the NFSv4 grace period. |
---|
.. | .. |
---|
1068 | 1072 | nfs4_recoverydir()); |
---|
1069 | 1073 | } |
---|
1070 | 1074 | |
---|
1071 | | -/** |
---|
| 1075 | +/* |
---|
1072 | 1076 | * write_recoverydir - Set or report the pathname of the recovery directory |
---|
1073 | 1077 | * |
---|
1074 | 1078 | * Input: |
---|
.. | .. |
---|
1100 | 1104 | return rv; |
---|
1101 | 1105 | } |
---|
1102 | 1106 | |
---|
1103 | | -/** |
---|
| 1107 | +/* |
---|
1104 | 1108 | * write_v4_end_grace - release grace period for nfsd's v4.x lock manager |
---|
1105 | 1109 | * |
---|
1106 | 1110 | * Input: |
---|
.. | .. |
---|
1149 | 1153 | * populating the filesystem. |
---|
1150 | 1154 | */ |
---|
1151 | 1155 | |
---|
1152 | | -static int nfsd_fill_super(struct super_block * sb, void * data, int silent) |
---|
| 1156 | +/* Basically copying rpc_get_inode. */ |
---|
| 1157 | +static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode) |
---|
1153 | 1158 | { |
---|
| 1159 | + struct inode *inode = new_inode(sb); |
---|
| 1160 | + if (!inode) |
---|
| 1161 | + return NULL; |
---|
| 1162 | + /* Following advice from simple_fill_super documentation: */ |
---|
| 1163 | + inode->i_ino = iunique(sb, NFSD_MaxReserved); |
---|
| 1164 | + inode->i_mode = mode; |
---|
| 1165 | + inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); |
---|
| 1166 | + switch (mode & S_IFMT) { |
---|
| 1167 | + case S_IFDIR: |
---|
| 1168 | + inode->i_fop = &simple_dir_operations; |
---|
| 1169 | + inode->i_op = &simple_dir_inode_operations; |
---|
| 1170 | + inc_nlink(inode); |
---|
| 1171 | + default: |
---|
| 1172 | + break; |
---|
| 1173 | + } |
---|
| 1174 | + return inode; |
---|
| 1175 | +} |
---|
| 1176 | + |
---|
| 1177 | +static int __nfsd_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode, struct nfsdfs_client *ncl) |
---|
| 1178 | +{ |
---|
| 1179 | + struct inode *inode; |
---|
| 1180 | + |
---|
| 1181 | + inode = nfsd_get_inode(dir->i_sb, mode); |
---|
| 1182 | + if (!inode) |
---|
| 1183 | + return -ENOMEM; |
---|
| 1184 | + if (ncl) { |
---|
| 1185 | + inode->i_private = ncl; |
---|
| 1186 | + kref_get(&ncl->cl_ref); |
---|
| 1187 | + } |
---|
| 1188 | + d_add(dentry, inode); |
---|
| 1189 | + inc_nlink(dir); |
---|
| 1190 | + fsnotify_mkdir(dir, dentry); |
---|
| 1191 | + return 0; |
---|
| 1192 | +} |
---|
| 1193 | + |
---|
| 1194 | +static struct dentry *nfsd_mkdir(struct dentry *parent, struct nfsdfs_client *ncl, char *name) |
---|
| 1195 | +{ |
---|
| 1196 | + struct inode *dir = parent->d_inode; |
---|
| 1197 | + struct dentry *dentry; |
---|
| 1198 | + int ret = -ENOMEM; |
---|
| 1199 | + |
---|
| 1200 | + inode_lock(dir); |
---|
| 1201 | + dentry = d_alloc_name(parent, name); |
---|
| 1202 | + if (!dentry) |
---|
| 1203 | + goto out_err; |
---|
| 1204 | + ret = __nfsd_mkdir(d_inode(parent), dentry, S_IFDIR | 0600, ncl); |
---|
| 1205 | + if (ret) |
---|
| 1206 | + goto out_err; |
---|
| 1207 | +out: |
---|
| 1208 | + inode_unlock(dir); |
---|
| 1209 | + return dentry; |
---|
| 1210 | +out_err: |
---|
| 1211 | + dput(dentry); |
---|
| 1212 | + dentry = ERR_PTR(ret); |
---|
| 1213 | + goto out; |
---|
| 1214 | +} |
---|
| 1215 | + |
---|
| 1216 | +static void clear_ncl(struct inode *inode) |
---|
| 1217 | +{ |
---|
| 1218 | + struct nfsdfs_client *ncl = inode->i_private; |
---|
| 1219 | + |
---|
| 1220 | + inode->i_private = NULL; |
---|
| 1221 | + kref_put(&ncl->cl_ref, ncl->cl_release); |
---|
| 1222 | +} |
---|
| 1223 | + |
---|
| 1224 | +static struct nfsdfs_client *__get_nfsdfs_client(struct inode *inode) |
---|
| 1225 | +{ |
---|
| 1226 | + struct nfsdfs_client *nc = inode->i_private; |
---|
| 1227 | + |
---|
| 1228 | + if (nc) |
---|
| 1229 | + kref_get(&nc->cl_ref); |
---|
| 1230 | + return nc; |
---|
| 1231 | +} |
---|
| 1232 | + |
---|
| 1233 | +struct nfsdfs_client *get_nfsdfs_client(struct inode *inode) |
---|
| 1234 | +{ |
---|
| 1235 | + struct nfsdfs_client *nc; |
---|
| 1236 | + |
---|
| 1237 | + inode_lock_shared(inode); |
---|
| 1238 | + nc = __get_nfsdfs_client(inode); |
---|
| 1239 | + inode_unlock_shared(inode); |
---|
| 1240 | + return nc; |
---|
| 1241 | +} |
---|
| 1242 | +/* from __rpc_unlink */ |
---|
| 1243 | +static void nfsdfs_remove_file(struct inode *dir, struct dentry *dentry) |
---|
| 1244 | +{ |
---|
| 1245 | + int ret; |
---|
| 1246 | + |
---|
| 1247 | + clear_ncl(d_inode(dentry)); |
---|
| 1248 | + dget(dentry); |
---|
| 1249 | + ret = simple_unlink(dir, dentry); |
---|
| 1250 | + d_drop(dentry); |
---|
| 1251 | + fsnotify_unlink(dir, dentry); |
---|
| 1252 | + dput(dentry); |
---|
| 1253 | + WARN_ON_ONCE(ret); |
---|
| 1254 | +} |
---|
| 1255 | + |
---|
| 1256 | +static void nfsdfs_remove_files(struct dentry *root) |
---|
| 1257 | +{ |
---|
| 1258 | + struct dentry *dentry, *tmp; |
---|
| 1259 | + |
---|
| 1260 | + list_for_each_entry_safe(dentry, tmp, &root->d_subdirs, d_child) { |
---|
| 1261 | + if (!simple_positive(dentry)) { |
---|
| 1262 | + WARN_ON_ONCE(1); /* I think this can't happen? */ |
---|
| 1263 | + continue; |
---|
| 1264 | + } |
---|
| 1265 | + nfsdfs_remove_file(d_inode(root), dentry); |
---|
| 1266 | + } |
---|
| 1267 | +} |
---|
| 1268 | + |
---|
| 1269 | +/* XXX: cut'n'paste from simple_fill_super; figure out if we could share |
---|
| 1270 | + * code instead. */ |
---|
| 1271 | +static int nfsdfs_create_files(struct dentry *root, |
---|
| 1272 | + const struct tree_descr *files) |
---|
| 1273 | +{ |
---|
| 1274 | + struct inode *dir = d_inode(root); |
---|
| 1275 | + struct inode *inode; |
---|
| 1276 | + struct dentry *dentry; |
---|
| 1277 | + int i; |
---|
| 1278 | + |
---|
| 1279 | + inode_lock(dir); |
---|
| 1280 | + for (i = 0; files->name && files->name[0]; i++, files++) { |
---|
| 1281 | + if (!files->name) |
---|
| 1282 | + continue; |
---|
| 1283 | + dentry = d_alloc_name(root, files->name); |
---|
| 1284 | + if (!dentry) |
---|
| 1285 | + goto out; |
---|
| 1286 | + inode = nfsd_get_inode(d_inode(root)->i_sb, |
---|
| 1287 | + S_IFREG | files->mode); |
---|
| 1288 | + if (!inode) { |
---|
| 1289 | + dput(dentry); |
---|
| 1290 | + goto out; |
---|
| 1291 | + } |
---|
| 1292 | + inode->i_fop = files->ops; |
---|
| 1293 | + inode->i_private = __get_nfsdfs_client(dir); |
---|
| 1294 | + d_add(dentry, inode); |
---|
| 1295 | + fsnotify_create(dir, dentry); |
---|
| 1296 | + } |
---|
| 1297 | + inode_unlock(dir); |
---|
| 1298 | + return 0; |
---|
| 1299 | +out: |
---|
| 1300 | + nfsdfs_remove_files(root); |
---|
| 1301 | + inode_unlock(dir); |
---|
| 1302 | + return -ENOMEM; |
---|
| 1303 | +} |
---|
| 1304 | + |
---|
| 1305 | +/* on success, returns positive number unique to that client. */ |
---|
| 1306 | +struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, |
---|
| 1307 | + struct nfsdfs_client *ncl, u32 id, |
---|
| 1308 | + const struct tree_descr *files) |
---|
| 1309 | +{ |
---|
| 1310 | + struct dentry *dentry; |
---|
| 1311 | + char name[11]; |
---|
| 1312 | + int ret; |
---|
| 1313 | + |
---|
| 1314 | + sprintf(name, "%u", id); |
---|
| 1315 | + |
---|
| 1316 | + dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name); |
---|
| 1317 | + if (IS_ERR(dentry)) /* XXX: tossing errors? */ |
---|
| 1318 | + return NULL; |
---|
| 1319 | + ret = nfsdfs_create_files(dentry, files); |
---|
| 1320 | + if (ret) { |
---|
| 1321 | + nfsd_client_rmdir(dentry); |
---|
| 1322 | + return NULL; |
---|
| 1323 | + } |
---|
| 1324 | + return dentry; |
---|
| 1325 | +} |
---|
| 1326 | + |
---|
| 1327 | +/* Taken from __rpc_rmdir: */ |
---|
| 1328 | +void nfsd_client_rmdir(struct dentry *dentry) |
---|
| 1329 | +{ |
---|
| 1330 | + struct inode *dir = d_inode(dentry->d_parent); |
---|
| 1331 | + struct inode *inode = d_inode(dentry); |
---|
| 1332 | + int ret; |
---|
| 1333 | + |
---|
| 1334 | + inode_lock(dir); |
---|
| 1335 | + nfsdfs_remove_files(dentry); |
---|
| 1336 | + clear_ncl(inode); |
---|
| 1337 | + dget(dentry); |
---|
| 1338 | + ret = simple_rmdir(dir, dentry); |
---|
| 1339 | + WARN_ON_ONCE(ret); |
---|
| 1340 | + d_drop(dentry); |
---|
| 1341 | + fsnotify_rmdir(dir, dentry); |
---|
| 1342 | + dput(dentry); |
---|
| 1343 | + inode_unlock(dir); |
---|
| 1344 | +} |
---|
| 1345 | + |
---|
| 1346 | +static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) |
---|
| 1347 | +{ |
---|
| 1348 | + struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, |
---|
| 1349 | + nfsd_net_id); |
---|
| 1350 | + struct dentry *dentry; |
---|
| 1351 | + int ret; |
---|
| 1352 | + |
---|
1154 | 1353 | static const struct tree_descr nfsd_files[] = { |
---|
1155 | 1354 | [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO}, |
---|
1156 | 1355 | [NFSD_Export_features] = {"export_features", |
---|
.. | .. |
---|
1179 | 1378 | #endif |
---|
1180 | 1379 | /* last one */ {""} |
---|
1181 | 1380 | }; |
---|
1182 | | - get_net(sb->s_fs_info); |
---|
1183 | | - return simple_fill_super(sb, 0x6e667364, nfsd_files); |
---|
| 1381 | + |
---|
| 1382 | + ret = simple_fill_super(sb, 0x6e667364, nfsd_files); |
---|
| 1383 | + if (ret) |
---|
| 1384 | + return ret; |
---|
| 1385 | + dentry = nfsd_mkdir(sb->s_root, NULL, "clients"); |
---|
| 1386 | + if (IS_ERR(dentry)) |
---|
| 1387 | + return PTR_ERR(dentry); |
---|
| 1388 | + nn->nfsd_client_dir = dentry; |
---|
| 1389 | + return 0; |
---|
1184 | 1390 | } |
---|
1185 | 1391 | |
---|
1186 | | -static struct dentry *nfsd_mount(struct file_system_type *fs_type, |
---|
1187 | | - int flags, const char *dev_name, void *data) |
---|
| 1392 | +static int nfsd_fs_get_tree(struct fs_context *fc) |
---|
1188 | 1393 | { |
---|
1189 | | - struct net *net = current->nsproxy->net_ns; |
---|
1190 | | - return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super); |
---|
| 1394 | + return get_tree_keyed(fc, nfsd_fill_super, get_net(fc->net_ns)); |
---|
| 1395 | +} |
---|
| 1396 | + |
---|
| 1397 | +static void nfsd_fs_free_fc(struct fs_context *fc) |
---|
| 1398 | +{ |
---|
| 1399 | + if (fc->s_fs_info) |
---|
| 1400 | + put_net(fc->s_fs_info); |
---|
| 1401 | +} |
---|
| 1402 | + |
---|
| 1403 | +static const struct fs_context_operations nfsd_fs_context_ops = { |
---|
| 1404 | + .free = nfsd_fs_free_fc, |
---|
| 1405 | + .get_tree = nfsd_fs_get_tree, |
---|
| 1406 | +}; |
---|
| 1407 | + |
---|
| 1408 | +static int nfsd_init_fs_context(struct fs_context *fc) |
---|
| 1409 | +{ |
---|
| 1410 | + put_user_ns(fc->user_ns); |
---|
| 1411 | + fc->user_ns = get_user_ns(fc->net_ns->user_ns); |
---|
| 1412 | + fc->ops = &nfsd_fs_context_ops; |
---|
| 1413 | + return 0; |
---|
1191 | 1414 | } |
---|
1192 | 1415 | |
---|
1193 | 1416 | static void nfsd_umount(struct super_block *sb) |
---|
1194 | 1417 | { |
---|
1195 | 1418 | struct net *net = sb->s_fs_info; |
---|
| 1419 | + |
---|
| 1420 | + nfsd_shutdown_threads(net); |
---|
1196 | 1421 | |
---|
1197 | 1422 | kill_litter_super(sb); |
---|
1198 | 1423 | put_net(net); |
---|
.. | .. |
---|
1201 | 1426 | static struct file_system_type nfsd_fs_type = { |
---|
1202 | 1427 | .owner = THIS_MODULE, |
---|
1203 | 1428 | .name = "nfsd", |
---|
1204 | | - .mount = nfsd_mount, |
---|
| 1429 | + .init_fs_context = nfsd_init_fs_context, |
---|
1205 | 1430 | .kill_sb = nfsd_umount, |
---|
1206 | 1431 | }; |
---|
1207 | 1432 | MODULE_ALIAS_FS("nfsd"); |
---|
.. | .. |
---|
1214 | 1439 | entry = proc_mkdir("fs/nfs", NULL); |
---|
1215 | 1440 | if (!entry) |
---|
1216 | 1441 | return -ENOMEM; |
---|
1217 | | - entry = proc_create("exports", 0, entry, |
---|
1218 | | - &exports_proc_operations); |
---|
| 1442 | + entry = proc_create("exports", 0, entry, &exports_proc_ops); |
---|
1219 | 1443 | if (!entry) { |
---|
1220 | 1444 | remove_proc_entry("fs/nfs", NULL); |
---|
1221 | 1445 | return -ENOMEM; |
---|
.. | .. |
---|
1242 | 1466 | retval = nfsd_idmap_init(net); |
---|
1243 | 1467 | if (retval) |
---|
1244 | 1468 | goto out_idmap_error; |
---|
| 1469 | + nn->nfsd_versions = NULL; |
---|
| 1470 | + nn->nfsd4_minorversions = NULL; |
---|
| 1471 | + retval = nfsd_reply_cache_init(nn); |
---|
| 1472 | + if (retval) |
---|
| 1473 | + goto out_drc_error; |
---|
1245 | 1474 | nn->nfsd4_lease = 90; /* default lease time */ |
---|
1246 | 1475 | nn->nfsd4_grace = 90; |
---|
1247 | 1476 | nn->somebody_reclaimed = false; |
---|
| 1477 | + nn->track_reclaim_completes = false; |
---|
1248 | 1478 | nn->clverifier_counter = prandom_u32(); |
---|
1249 | | - nn->clientid_counter = prandom_u32(); |
---|
| 1479 | + nn->clientid_base = prandom_u32(); |
---|
| 1480 | + nn->clientid_counter = nn->clientid_base + 1; |
---|
| 1481 | + nn->s2s_cp_cl_id = nn->clientid_counter++; |
---|
1250 | 1482 | |
---|
1251 | 1483 | atomic_set(&nn->ntf_refcnt, 0); |
---|
1252 | 1484 | init_waitqueue_head(&nn->ntf_wq); |
---|
| 1485 | + seqlock_init(&nn->boot_lock); |
---|
| 1486 | + |
---|
1253 | 1487 | return 0; |
---|
1254 | 1488 | |
---|
| 1489 | +out_drc_error: |
---|
| 1490 | + nfsd_idmap_shutdown(net); |
---|
1255 | 1491 | out_idmap_error: |
---|
1256 | 1492 | nfsd_export_shutdown(net); |
---|
1257 | 1493 | out_export_error: |
---|
.. | .. |
---|
1260 | 1496 | |
---|
1261 | 1497 | static __net_exit void nfsd_exit_net(struct net *net) |
---|
1262 | 1498 | { |
---|
| 1499 | + struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
---|
| 1500 | + |
---|
| 1501 | + nfsd_reply_cache_shutdown(nn); |
---|
1263 | 1502 | nfsd_idmap_shutdown(net); |
---|
1264 | 1503 | nfsd_export_shutdown(net); |
---|
| 1504 | + nfsd_netns_free_versions(net_generic(net, nfsd_net_id)); |
---|
1265 | 1505 | } |
---|
1266 | 1506 | |
---|
1267 | 1507 | static struct pernet_operations nfsd_net_ops = { |
---|
.. | .. |
---|
1276 | 1516 | int retval; |
---|
1277 | 1517 | printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); |
---|
1278 | 1518 | |
---|
1279 | | - retval = register_pernet_subsys(&nfsd_net_ops); |
---|
1280 | | - if (retval < 0) |
---|
1281 | | - return retval; |
---|
1282 | | - retval = register_cld_notifier(); |
---|
1283 | | - if (retval) |
---|
1284 | | - goto out_unregister_pernet; |
---|
1285 | 1519 | retval = nfsd4_init_slabs(); |
---|
1286 | 1520 | if (retval) |
---|
1287 | | - goto out_unregister_notifier; |
---|
| 1521 | + return retval; |
---|
1288 | 1522 | retval = nfsd4_init_pnfs(); |
---|
1289 | 1523 | if (retval) |
---|
1290 | 1524 | goto out_free_slabs; |
---|
1291 | | - retval = nfsd_fault_inject_init(); /* nfsd fault injection controls */ |
---|
1292 | | - if (retval) |
---|
1293 | | - goto out_exit_pnfs; |
---|
1294 | 1525 | nfsd_stat_init(); /* Statistics */ |
---|
1295 | | - retval = nfsd_reply_cache_init(); |
---|
| 1526 | + retval = nfsd_drc_slab_create(); |
---|
1296 | 1527 | if (retval) |
---|
1297 | 1528 | goto out_free_stat; |
---|
1298 | 1529 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ |
---|
.. | .. |
---|
1301 | 1532 | goto out_free_lockd; |
---|
1302 | 1533 | retval = register_filesystem(&nfsd_fs_type); |
---|
1303 | 1534 | if (retval) |
---|
| 1535 | + goto out_free_exports; |
---|
| 1536 | + retval = register_pernet_subsys(&nfsd_net_ops); |
---|
| 1537 | + if (retval < 0) |
---|
| 1538 | + goto out_free_filesystem; |
---|
| 1539 | + retval = register_cld_notifier(); |
---|
| 1540 | + if (retval) |
---|
1304 | 1541 | goto out_free_all; |
---|
1305 | 1542 | return 0; |
---|
1306 | 1543 | out_free_all: |
---|
| 1544 | + unregister_pernet_subsys(&nfsd_net_ops); |
---|
| 1545 | +out_free_filesystem: |
---|
| 1546 | + unregister_filesystem(&nfsd_fs_type); |
---|
| 1547 | +out_free_exports: |
---|
1307 | 1548 | remove_proc_entry("fs/nfs/exports", NULL); |
---|
1308 | 1549 | remove_proc_entry("fs/nfs", NULL); |
---|
1309 | 1550 | out_free_lockd: |
---|
1310 | 1551 | nfsd_lockd_shutdown(); |
---|
1311 | | - nfsd_reply_cache_shutdown(); |
---|
| 1552 | + nfsd_drc_slab_free(); |
---|
1312 | 1553 | out_free_stat: |
---|
1313 | 1554 | nfsd_stat_shutdown(); |
---|
1314 | | - nfsd_fault_inject_cleanup(); |
---|
1315 | | -out_exit_pnfs: |
---|
1316 | 1555 | nfsd4_exit_pnfs(); |
---|
1317 | 1556 | out_free_slabs: |
---|
1318 | 1557 | nfsd4_free_slabs(); |
---|
1319 | | -out_unregister_notifier: |
---|
1320 | | - unregister_cld_notifier(); |
---|
1321 | | -out_unregister_pernet: |
---|
1322 | | - unregister_pernet_subsys(&nfsd_net_ops); |
---|
1323 | 1558 | return retval; |
---|
1324 | 1559 | } |
---|
1325 | 1560 | |
---|
1326 | 1561 | static void __exit exit_nfsd(void) |
---|
1327 | 1562 | { |
---|
1328 | | - nfsd_reply_cache_shutdown(); |
---|
| 1563 | + unregister_cld_notifier(); |
---|
| 1564 | + unregister_pernet_subsys(&nfsd_net_ops); |
---|
| 1565 | + nfsd_drc_slab_free(); |
---|
1329 | 1566 | remove_proc_entry("fs/nfs/exports", NULL); |
---|
1330 | 1567 | remove_proc_entry("fs/nfs", NULL); |
---|
1331 | 1568 | nfsd_stat_shutdown(); |
---|
1332 | 1569 | nfsd_lockd_shutdown(); |
---|
1333 | 1570 | nfsd4_free_slabs(); |
---|
1334 | 1571 | nfsd4_exit_pnfs(); |
---|
1335 | | - nfsd_fault_inject_cleanup(); |
---|
1336 | 1572 | unregister_filesystem(&nfsd_fs_type); |
---|
1337 | | - unregister_cld_notifier(); |
---|
1338 | | - unregister_pernet_subsys(&nfsd_net_ops); |
---|
1339 | 1573 | } |
---|
1340 | 1574 | |
---|
1341 | 1575 | MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); |
---|
1342 | 1576 | MODULE_LICENSE("GPL"); |
---|
| 1577 | +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
1343 | 1578 | module_init(init_nfsd) |
---|
1344 | 1579 | module_exit(exit_nfsd) |
---|