Add filesystem context support to NFS, parsing the options in advance and attaching the information to struct nfs_fs_context. The highlights are: (*) Merge nfs_mount_info and nfs_clone_mount into nfs_fs_context. This structure represents NFS's superblock config. (*) Make use of the VFS's parsing support to split comma-separated lists (*) Pin the NFS protocol module in the nfs_fs_context. (*) Attach supplementary error information to fs_context. This has the downside that these strings must be static and can't be formatted. (*) Remove the auxiliary file_system_type structs since the information necessary can be conveyed in the nfs_fs_context struct instead. (*) Root mounts are made by duplicating the config for the requested mount so as to have the same parameters. Submounts pick up their parameters from the parent superblock. [AV -- retrans is u32, not string] [SM -- Renamed cfg to ctx in a few functions in an earlier patch] [SM -- Moved fs_context mount option parsing to an earlier patch] [SM -- Moved fs_context error logging to a later patch] [SM -- Fixed printks in nfs4_try_get_tree() and nfs4_get_referral_tree()] [SM -- Added is_remount_fc() helper] [SM -- Deferred some refactoring to a later patch] [SM -- Fixed referral mounts, which were broken in the original patch] [SM -- Fixed leak of nfs_fattr when fs_context is freed]
Unified · Split
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | * linux/fs/nfs/fs_context.c |
| 4 | 4 | * |
| 5 | 5 | * Copyright (C) 1992 Rick Sladkey |
| 6 | + * Conversion to new mount api Copyright (C) David Howells | |
| 6 | 7 | * |
| 7 | 8 | * NFS mount handling. |
| 8 | 9 | * |
| @@ -467,21 +468,31 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx, · 458 unmodified lines | ||
| 467 | 468 | /* |
| 468 | 469 | * Parse a single mount parameter. |
| 469 | 470 | */ |
| 470 | −static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx, | |
| 471 | +static int nfs_fs_context_parse_param(struct fs_context *fc, | |
| 471 | 472 | struct fs_parameter *param) |
| 472 | 473 | { |
| 473 | 474 | struct fs_parse_result result; |
| 475 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 474 | 476 | unsigned short protofamily, mountfamily; |
| 475 | 477 | unsigned int len; |
| 476 | 478 | int ret, opt; |
| 477 | 479 | |
| 478 | 480 | dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", param->key); |
| 479 | 481 | |
| 480 | − opt = fs_parse(NULL, &nfs_fs_parameters, param, &result); | |
| 482 | + opt = fs_parse(fc, &nfs_fs_parameters, param, &result); | |
| 481 | 483 | if (opt < 0) |
| 482 | 484 | return ctx->sloppy ? 1 : opt; |
| 483 | 485 | |
| 484 | 486 | switch (opt) { |
| 487 | + case Opt_source: | |
| 488 | + if (fc->source) { | |
| 489 | + dfprintk(MOUNT, "NFS: Multiple sources not supported\n"); | |
| 490 | + return -EINVAL; | |
| 491 | + } | |
| 492 | + fc->source = param->string; | |
| 493 | + param->string = NULL; | |
| 494 | + break; | |
| 495 | + | |
| 485 | 496 | /* |
| 486 | 497 | * boolean options: foo/nofoo |
| 487 | 498 | */ |
| @@ -807,112 +818,6 @@ out_of_bounds: · 319 unmodified lines | ||
| 807 | 818 | return -ERANGE; |
| 808 | 819 | } |
| 809 | 820 | |
| 810 | −/* cribbed from generic_parse_monolithic and vfs_parse_fs_string */ | |
| 811 | −static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p) | |
| 812 | −{ | |
| 813 | − int ret; | |
| 814 | − char *key = p, *value; | |
| 815 | − size_t v_size = 0; | |
| 816 | − struct fs_parameter param; | |
| 817 | − | |
| 818 | − memset(¶m, 0, sizeof(param)); | |
| 819 | − value = strchr(key, '='); | |
| 820 | − if (value && value != key) { | |
| 821 | − *value++ = 0; | |
| 822 | − v_size = strlen(value); | |
| 823 | − } | |
| 824 | − param.key = key; | |
| 825 | − param.type = fs_value_is_flag; | |
| 826 | − param.size = v_size; | |
| 827 | − if (v_size > 0) { | |
| 828 | − param.type = fs_value_is_string; | |
| 829 | − param.string = kmemdup_nul(value, v_size, GFP_KERNEL); | |
| 830 | − if (!param.string) | |
| 831 | − return -ENOMEM; | |
| 832 | − } | |
| 833 | − ret = nfs_fs_context_parse_param(ctx, ¶m); | |
| 834 | − kfree(param.string); | |
| 835 | − return ret; | |
| 836 | −} | |
| 837 | − | |
| 838 | −/* | |
| 839 | − * Error-check and convert a string of mount options from user space into | |
| 840 | − * a data structure. The whole mount string is processed; bad options are | |
| 841 | − * skipped as they are encountered. If there were no errors, return 1; | |
| 842 | − * otherwise return 0 (zero). | |
| 843 | − */ | |
| 844 | −int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx) | |
| 845 | −{ | |
| 846 | − char *p; | |
| 847 | − int rc, sloppy = 0, invalid_option = 0; | |
| 848 | − | |
| 849 | − if (!raw) { | |
| 850 | − dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | |
| 851 | − return 1; | |
| 852 | − } | |
| 853 | − dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw); | |
| 854 | − | |
| 855 | − rc = security_sb_eat_lsm_opts(raw, &ctx->lsm_opts); | |
| 856 | − if (rc) | |
| 857 | − goto out_security_failure; | |
| 858 | − | |
| 859 | − while ((p = strsep(&raw, ",")) != NULL) { | |
| 860 | − if (!*p) | |
| 861 | − continue; | |
| 862 | − if (nfs_fs_context_parse_option(ctx, p) < 0) | |
| 863 | − invalid_option = true; | |
| 864 | − } | |
| 865 | − | |
| 866 | − if (!sloppy && invalid_option) | |
| 867 | − return 0; | |
| 868 | − | |
| 869 | − if (ctx->minorversion && ctx->version != 4) | |
| 870 | − goto out_minorversion_mismatch; | |
| 871 | − | |
| 872 | − if (ctx->options & NFS_OPTION_MIGRATION && | |
| 873 | − (ctx->version != 4 || ctx->minorversion != 0)) | |
| 874 | − goto out_migration_misuse; | |
| 875 | − | |
| 876 | − /* | |
| 877 | − * verify that any proto=/mountproto= options match the address | |
| 878 | − * families in the addr=/mountaddr= options. | |
| 879 | − */ | |
| 880 | − if (ctx->protofamily != AF_UNSPEC && | |
| 881 | − ctx->protofamily != ctx->nfs_server.address.sa_family) | |
| 882 | − goto out_proto_mismatch; | |
| 883 | − | |
| 884 | − if (ctx->mountfamily != AF_UNSPEC) { | |
| 885 | − if (ctx->mount_server.addrlen) { | |
| 886 | − if (ctx->mountfamily != ctx->mount_server.address.sa_family) | |
| 887 | − goto out_mountproto_mismatch; | |
| 888 | − } else { | |
| 889 | − if (ctx->mountfamily != ctx->nfs_server.address.sa_family) | |
| 890 | − goto out_mountproto_mismatch; | |
| 891 | − } | |
| 892 | − } | |
| 893 | − | |
| 894 | − return 1; | |
| 895 | − | |
| 896 | −out_minorversion_mismatch: | |
| 897 | − printk(KERN_INFO "NFS: mount option vers=%u does not support " | |
| 898 | − "minorversion=%u\n", ctx->version, ctx->minorversion); | |
| 899 | − return 0; | |
| 900 | −out_mountproto_mismatch: | |
| 901 | − printk(KERN_INFO "NFS: mount server address does not match mountproto= " | |
| 902 | − "option\n"); | |
| 903 | − return 0; | |
| 904 | −out_proto_mismatch: | |
| 905 | − printk(KERN_INFO "NFS: server address does not match proto= option\n"); | |
| 906 | − return 0; | |
| 907 | −out_migration_misuse: | |
| 908 | − printk(KERN_INFO | |
| 909 | − "NFS: 'migration' not supported for this NFS version\n"); | |
| 910 | − return -EINVAL; | |
| 911 | −out_security_failure: | |
| 912 | − printk(KERN_INFO "NFS: security options invalid: %d\n", rc); | |
| 913 | − return 0; | |
| 914 | −} | |
| 915 | − | |
| 916 | 821 | /* |
| 917 | 822 | * Split "dev_name" into "hostname:export_path". |
| 918 | 823 | * |
| @@ -990,6 +895,11 @@ out_path: · 71 unmodified lines | ||
| 990 | 895 | return -ENAMETOOLONG; |
| 991 | 896 | } |
| 992 | 897 | |
| 898 | +static inline bool is_remount_fc(struct fs_context *fc) | |
| 899 | +{ | |
| 900 | + return fc->root != NULL; | |
| 901 | +} | |
| 902 | + | |
| 993 | 903 | /* |
| 994 | 904 | * Parse monolithic NFS2/NFS3 mount data |
| 995 | 905 | * - fills in the mount root filehandle |
| @@ -1006,12 +916,11 @@ out_path: · 10 unmodified lines | ||
| 1006 | 916 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, |
| 1007 | 917 | * mountproto=tcp after mountproto=udp, and so on |
| 1008 | 918 | */ |
| 1009 | −static int nfs23_validate_mount_data(void *options, | |
| 1010 | − struct nfs_fs_context *ctx, | |
| 1011 | − struct nfs_fh *mntfh, | |
| 1012 | − const char *dev_name) | |
| 919 | +static int nfs23_parse_monolithic(struct fs_context *fc, | |
| 920 | + struct nfs_mount_data *data) | |
| 1013 | 921 | { |
| 1014 | − struct nfs_mount_data *data = (struct nfs_mount_data *)options; | |
| 922 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 923 | + struct nfs_fh *mntfh = ctx->mount_info.mntfh; | |
| 1015 | 924 | struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; |
| 1016 | 925 | int extra_flags = NFS_MOUNT_LEGACY_INTERFACE; |
| 1017 | 926 | |
| @@ -1083,6 +992,9 @@ static int nfs23_validate_mount_data(void *options, · 65 unmodified lines | ||
| 1083 | 992 | ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
| 1084 | 993 | /* N.B. caller will free nfs_server.hostname in all cases */ |
| 1085 | 994 | ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); |
| 995 | + if (!ctx->nfs_server.hostname) | |
| 996 | + goto out_nomem; | |
| 997 | + | |
| 1086 | 998 | ctx->namlen = data->namlen; |
| 1087 | 999 | ctx->bsize = data->bsize; |
| 1088 | 1000 | |
| @@ -1090,8 +1002,6 @@ static int nfs23_validate_mount_data(void *options, · 1 unmodified line | ||
| 1090 | 1002 | ctx->selected_flavor = data->pseudoflavor; |
| 1091 | 1003 | else |
| 1092 | 1004 | ctx->selected_flavor = RPC_AUTH_UNIX; |
| 1093 | − if (!ctx->nfs_server.hostname) | |
| 1094 | − goto out_nomem; | |
| 1095 | 1005 | |
| 1096 | 1006 | if (!(data->flags & NFS_MOUNT_NONLM)) |
| 1097 | 1007 | ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK| |
| @@ -1109,12 +1019,13 @@ static int nfs23_validate_mount_data(void *options, · 11 unmodified lines | ||
| 1109 | 1019 | */ |
| 1110 | 1020 | if (data->context[0]){ |
| 1111 | 1021 | #ifdef CONFIG_SECURITY_SELINUX |
| 1112 | − int rc; | |
| 1022 | + int ret; | |
| 1023 | + | |
| 1113 | 1024 | data->context[NFS_MAX_CONTEXT_LEN] = '\0'; |
| 1114 | − rc = security_add_mnt_opt("context", data->context, | |
| 1115 | − strlen(data->context), ctx->lsm_opts); | |
| 1116 | − if (rc) | |
| 1117 | − return rc; | |
| 1025 | + ret = vfs_parse_fs_string(fc, "context", | |
| 1026 | + data->context, strlen(data->context)); | |
| 1027 | + if (ret < 0) | |
| 1028 | + return ret; | |
| 1118 | 1029 | #else |
| 1119 | 1030 | return -EINVAL; |
| 1120 | 1031 | #endif |
| @@ -1122,12 +1033,20 @@ static int nfs23_validate_mount_data(void *options, · 1 unmodified line | ||
| 1122 | 1033 | |
| 1123 | 1034 | break; |
| 1124 | 1035 | default: |
| 1125 | − return NFS_TEXT_DATA; | |
| 1036 | + goto generic; | |
| 1126 | 1037 | } |
| 1127 | 1038 | |
| 1039 | + ctx->skip_reconfig_option_check = true; | |
| 1128 | 1040 | return 0; |
| 1129 | 1041 | |
| 1042 | +generic: | |
| 1043 | + return generic_parse_monolithic(fc, data); | |
| 1044 | + | |
| 1130 | 1045 | out_no_data: |
| 1046 | + if (is_remount_fc(fc)) { | |
| 1047 | + ctx->skip_reconfig_option_check = true; | |
| 1048 | + return 0; | |
| 1049 | + } | |
| 1131 | 1050 | dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n"); |
| 1132 | 1051 | return -EINVAL; |
| 1133 | 1052 | |
| @@ -1163,12 +1082,11 @@ static void nfs4_validate_mount_flags(struct nfs_fs_context *ctx) · 29 unmodified lines | ||
| 1163 | 1082 | /* |
| 1164 | 1083 | * Validate NFSv4 mount options |
| 1165 | 1084 | */ |
| 1166 | −static int nfs4_validate_mount_data(void *options, | |
| 1167 | − struct nfs_fs_context *ctx, | |
| 1168 | − const char *dev_name) | |
| 1085 | +static int nfs4_parse_monolithic(struct fs_context *fc, | |
| 1086 | + struct nfs4_mount_data *data) | |
| 1169 | 1087 | { |
| 1088 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 1170 | 1089 | struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; |
| 1171 | − struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | |
| 1172 | 1090 | char *c; |
| 1173 | 1091 | |
| 1174 | 1092 | if (data == NULL) |
| @@ -1218,7 +1136,7 @@ static int nfs4_validate_mount_data(void *options, · 43 unmodified lines | ||
| 1218 | 1136 | ctx->client_address = c; |
| 1219 | 1137 | |
| 1220 | 1138 | /* |
| 1221 | − * Translate to nfs_fs_context, which nfs4_fill_super | |
| 1139 | + * Translate to nfs_fs_context, which nfs_fill_super | |
| 1222 | 1140 | * can deal with. |
| 1223 | 1141 | */ |
| 1224 | 1142 | |
| @@ -1238,12 +1156,20 @@ static int nfs4_validate_mount_data(void *options, · 13 unmodified lines | ||
| 1238 | 1156 | |
| 1239 | 1157 | break; |
| 1240 | 1158 | default: |
| 1241 | − return NFS_TEXT_DATA; | |
| 1159 | + goto generic; | |
| 1242 | 1160 | } |
| 1243 | 1161 | |
| 1162 | + ctx->skip_reconfig_option_check = true; | |
| 1244 | 1163 | return 0; |
| 1245 | 1164 | |
| 1165 | +generic: | |
| 1166 | + return generic_parse_monolithic(fc, data); | |
| 1167 | + | |
| 1246 | 1168 | out_no_data: |
| 1169 | + if (is_remount_fc(fc)) { | |
| 1170 | + ctx->skip_reconfig_option_check = true; | |
| 1171 | + return 0; | |
| 1172 | + } | |
| 1247 | 1173 | dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n"); |
| 1248 | 1174 | return -EINVAL; |
| 1249 | 1175 | |
| @@ -1260,39 +1186,66 @@ out_invalid_transport_udp: · 10 unmodified lines | ||
| 1260 | 1186 | dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n"); |
| 1261 | 1187 | return -EINVAL; |
| 1262 | 1188 | } |
| 1189 | +#endif | |
| 1263 | 1190 | |
| 1264 | −int nfs_validate_mount_data(struct file_system_type *fs_type, | |
| 1265 | − void *options, | |
| 1266 | − struct nfs_fs_context *ctx, | |
| 1267 | − struct nfs_fh *mntfh, | |
| 1268 | − const char *dev_name) | |
| 1269 | −{ | |
| 1270 | − if (fs_type == &nfs_fs_type) | |
| 1271 | − return nfs23_validate_mount_data(options, ctx, mntfh, dev_name); | |
| 1272 | − return nfs4_validate_mount_data(options, ctx, dev_name); | |
| 1273 | −} | |
| 1274 | −#else | |
| 1275 | −int nfs_validate_mount_data(struct file_system_type *fs_type, | |
| 1276 | − void *options, | |
| 1277 | − struct nfs_fs_context *ctx, | |
| 1278 | − struct nfs_fh *mntfh, | |
| 1279 | − const char *dev_name) | |
| 1191 | +/* | |
| 1192 | + * Parse a monolithic block of data from sys_mount(). | |
| 1193 | + */ | |
| 1194 | +static int nfs_fs_context_parse_monolithic(struct fs_context *fc, | |
| 1195 | + void *data) | |
| 1280 | 1196 | { |
| 1281 | − return nfs23_validate_mount_data(options, ctx, mntfh, dev_name); | |
| 1282 | −} | |
| 1197 | + if (fc->fs_type == &nfs_fs_type) | |
| 1198 | + return nfs23_parse_monolithic(fc, data); | |
| 1199 | + | |
| 1200 | +#if IS_ENABLED(CONFIG_NFS_V4) | |
| 1201 | + if (fc->fs_type == &nfs4_fs_type) | |
| 1202 | + return nfs4_parse_monolithic(fc, data); | |
| 1283 | 1203 | #endif |
| 1284 | 1204 | |
| 1285 | −int nfs_validate_text_mount_data(void *options, | |
| 1286 | − struct nfs_fs_context *ctx, | |
| 1287 | − const char *dev_name) | |
| 1205 | + dfprintk(MOUNT, "NFS: Unsupported monolithic data version\n"); | |
| 1206 | + return -EINVAL; | |
| 1207 | +} | |
| 1208 | + | |
| 1209 | +/* | |
| 1210 | + * Validate the preparsed information in the config. | |
| 1211 | + */ | |
| 1212 | +static int nfs_fs_context_validate(struct fs_context *fc) | |
| 1288 | 1213 | { |
| 1289 | − int port = 0; | |
| 1214 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 1215 | + struct nfs_subversion *nfs_mod; | |
| 1216 | + struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; | |
| 1290 | 1217 | int max_namelen = PAGE_SIZE; |
| 1291 | 1218 | int max_pathlen = NFS_MAXPATHLEN; |
| 1292 | − struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; | |
| 1219 | + int port = 0; | |
| 1220 | + int ret; | |
| 1293 | 1221 | |
| 1294 | − if (nfs_parse_mount_options((char *)options, ctx) == 0) | |
| 1295 | − return -EINVAL; | |
| 1222 | + if (!fc->source) | |
| 1223 | + goto out_no_device_name; | |
| 1224 | + | |
| 1225 | + /* Check for sanity first. */ | |
| 1226 | + if (ctx->minorversion && ctx->version != 4) | |
| 1227 | + goto out_minorversion_mismatch; | |
| 1228 | + | |
| 1229 | + if (ctx->options & NFS_OPTION_MIGRATION && | |
| 1230 | + (ctx->version != 4 || ctx->minorversion != 0)) | |
| 1231 | + goto out_migration_misuse; | |
| 1232 | + | |
| 1233 | + /* Verify that any proto=/mountproto= options match the address | |
| 1234 | + * families in the addr=/mountaddr= options. | |
| 1235 | + */ | |
| 1236 | + if (ctx->protofamily != AF_UNSPEC && | |
| 1237 | + ctx->protofamily != ctx->nfs_server.address.sa_family) | |
| 1238 | + goto out_proto_mismatch; | |
| 1239 | + | |
| 1240 | + if (ctx->mountfamily != AF_UNSPEC) { | |
| 1241 | + if (ctx->mount_server.addrlen) { | |
| 1242 | + if (ctx->mountfamily != ctx->mount_server.address.sa_family) | |
| 1243 | + goto out_mountproto_mismatch; | |
| 1244 | + } else { | |
| 1245 | + if (ctx->mountfamily != ctx->nfs_server.address.sa_family) | |
| 1246 | + goto out_mountproto_mismatch; | |
| 1247 | + } | |
| 1248 | + } | |
| 1296 | 1249 | |
| 1297 | 1250 | if (!nfs_verify_server_address(sap)) |
| 1298 | 1251 | goto out_no_address; |
| @@ -1320,8 +1273,24 @@ int nfs_validate_text_mount_data(void *options, · 21 unmodified lines | ||
| 1320 | 1273 | |
| 1321 | 1274 | nfs_set_port(sap, &ctx->nfs_server.port, port); |
| 1322 | 1275 | |
| 1323 | − return nfs_parse_devname(ctx, dev_name, max_namelen, max_pathlen); | |
| 1276 | + ret = nfs_parse_devname(ctx, fc->source, max_namelen, max_pathlen); | |
| 1277 | + if (ret < 0) | |
| 1278 | + return ret; | |
| 1279 | + | |
| 1280 | + /* Load the NFS protocol module if we haven't done so yet */ | |
| 1281 | + if (!ctx->mount_info.nfs_mod) { | |
| 1282 | + nfs_mod = get_nfs_version(ctx->version); | |
| 1283 | + if (IS_ERR(nfs_mod)) { | |
| 1284 | + ret = PTR_ERR(nfs_mod); | |
| 1285 | + goto out_version_unavailable; | |
| 1286 | + } | |
| 1287 | + ctx->mount_info.nfs_mod = nfs_mod; | |
| 1288 | + } | |
| 1289 | + return 0; | |
| 1324 | 1290 | |
| 1291 | +out_no_device_name: | |
| 1292 | + dfprintk(MOUNT, "NFS: Device name not specified\n"); | |
| 1293 | + return -EINVAL; | |
| 1325 | 1294 | #if !IS_ENABLED(CONFIG_NFS_V4) |
| 1326 | 1295 | out_v4_not_compiled: |
| 1327 | 1296 | dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); |
| @@ -1331,8 +1300,201 @@ out_invalid_transport_udp: · 3 unmodified lines | ||
| 1331 | 1300 | dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n"); |
| 1332 | 1301 | return -EINVAL; |
| 1333 | 1302 | #endif /* !CONFIG_NFS_V4 */ |
| 1334 | − | |
| 1335 | 1303 | out_no_address: |
| 1336 | 1304 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); |
| 1337 | 1305 | return -EINVAL; |
| 1306 | +out_mountproto_mismatch: | |
| 1307 | + dfprintk(MOUNT, "NFS: Mount server address does not match mountproto= option\n"); | |
| 1308 | + return -EINVAL; | |
| 1309 | +out_proto_mismatch: | |
| 1310 | + dfprintk(MOUNT, "NFS: Server address does not match proto= option\n"); | |
| 1311 | + return -EINVAL; | |
| 1312 | +out_minorversion_mismatch: | |
| 1313 | + dfprintk(MOUNT, "NFS: Mount option vers=%u does not support minorversion=%u\n", | |
| 1314 | + ctx->version, ctx->minorversion); | |
| 1315 | + return -EINVAL; | |
| 1316 | +out_migration_misuse: | |
| 1317 | + dfprintk(MOUNT, "NFS: 'Migration' not supported for this NFS version\n"); | |
| 1318 | + return -EINVAL; | |
| 1319 | +out_version_unavailable: | |
| 1320 | + dfprintk(MOUNT, "NFS: Version unavailable\n"); | |
| 1321 | + return ret; | |
| 1322 | +} | |
| 1323 | + | |
| 1324 | +/* | |
| 1325 | + * Create an NFS superblock by the appropriate method. | |
| 1326 | + */ | |
| 1327 | +static int nfs_get_tree(struct fs_context *fc) | |
| 1328 | +{ | |
| 1329 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 1330 | + int err = nfs_fs_context_validate(fc); | |
| 1331 | + | |
| 1332 | + if (err) | |
| 1333 | + return err; | |
| 1334 | + if (!ctx->internal) | |
| 1335 | + return ctx->mount_info.nfs_mod->rpc_ops->try_get_tree(fc); | |
| 1336 | + else | |
| 1337 | + return nfs_get_tree_common(fc); | |
| 1338 | 1338 | } |
| 1339 | + | |
| 1340 | +/* | |
| 1341 | + * Handle duplication of a configuration. The caller copied *src into *sc, but | |
| 1342 | + * it can't deal with resource pointers in the filesystem context, so we have | |
| 1343 | + * to do that. We need to clear pointers, copy data or get extra refs as | |
| 1344 | + * appropriate. | |
| 1345 | + */ | |
| 1346 | +static int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) | |
| 1347 | +{ | |
| 1348 | + struct nfs_fs_context *src = nfs_fc2context(src_fc), *ctx; | |
| 1349 | + | |
| 1350 | + ctx = kmemdup(src, sizeof(struct nfs_fs_context), GFP_KERNEL); | |
| 1351 | + if (!ctx) | |
| 1352 | + return -ENOMEM; | |
| 1353 | + | |
| 1354 | + ctx->mount_info.mntfh = nfs_alloc_fhandle(); | |
| 1355 | + if (!ctx->mount_info.mntfh) { | |
| 1356 | + kfree(ctx); | |
| 1357 | + return -ENOMEM; | |
| 1358 | + } | |
| 1359 | + nfs_copy_fh(ctx->mount_info.mntfh, src->mount_info.mntfh); | |
| 1360 | + | |
| 1361 | + __module_get(ctx->mount_info.nfs_mod->owner); | |
| 1362 | + ctx->client_address = NULL; | |
| 1363 | + ctx->mount_server.hostname = NULL; | |
| 1364 | + ctx->nfs_server.export_path = NULL; | |
| 1365 | + ctx->nfs_server.hostname = NULL; | |
| 1366 | + ctx->fscache_uniq = NULL; | |
| 1367 | + ctx->clone_data.addr = NULL; | |
| 1368 | + ctx->clone_data.fattr = NULL; | |
| 1369 | + fc->fs_private = ctx; | |
| 1370 | + return 0; | |
| 1371 | +} | |
| 1372 | + | |
| 1373 | +static void nfs_fs_context_free(struct fs_context *fc) | |
| 1374 | +{ | |
| 1375 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 1376 | + | |
| 1377 | + if (ctx) { | |
| 1378 | + if (ctx->mount_info.server) | |
| 1379 | + nfs_free_server(ctx->mount_info.server); | |
| 1380 | + if (ctx->mount_info.nfs_mod) | |
| 1381 | + put_nfs_version(ctx->mount_info.nfs_mod); | |
| 1382 | + kfree(ctx->client_address); | |
| 1383 | + kfree(ctx->mount_server.hostname); | |
| 1384 | + kfree(ctx->nfs_server.export_path); | |
| 1385 | + kfree(ctx->nfs_server.hostname); | |
| 1386 | + kfree(ctx->fscache_uniq); | |
| 1387 | + nfs_free_fhandle(ctx->mount_info.mntfh); | |
| 1388 | + kfree(ctx->clone_data.addr); | |
| 1389 | + nfs_free_fattr(ctx->clone_data.fattr); | |
| 1390 | + kfree(ctx); | |
| 1391 | + } | |
| 1392 | +} | |
| 1393 | + | |
| 1394 | +static const struct fs_context_operations nfs_fs_context_ops = { | |
| 1395 | + .free = nfs_fs_context_free, | |
| 1396 | + .dup = nfs_fs_context_dup, | |
| 1397 | + .parse_param = nfs_fs_context_parse_param, | |
| 1398 | + .parse_monolithic = nfs_fs_context_parse_monolithic, | |
| 1399 | + .get_tree = nfs_get_tree, | |
| 1400 | + .reconfigure = nfs_reconfigure, | |
| 1401 | +}; | |
| 1402 | + | |
| 1403 | +/* | |
| 1404 | + * Prepare superblock configuration. We use the namespaces attached to the | |
| 1405 | + * context. This may be the current process's namespaces, or it may be a | |
| 1406 | + * container's namespaces. | |
| 1407 | + */ | |
| 1408 | +static int nfs_init_fs_context(struct fs_context *fc) | |
| 1409 | +{ | |
| 1410 | + struct nfs_fs_context *ctx; | |
| 1411 | + | |
| 1412 | + ctx = kzalloc(sizeof(struct nfs_fs_context), GFP_KERNEL); | |
| 1413 | + if (unlikely(!ctx)) | |
| 1414 | + return -ENOMEM; | |
| 1415 | + | |
| 1416 | + ctx->mount_info.ctx = ctx; | |
| 1417 | + ctx->mount_info.mntfh = nfs_alloc_fhandle(); | |
| 1418 | + if (unlikely(!ctx->mount_info.mntfh)) { | |
| 1419 | + kfree(ctx); | |
| 1420 | + return -ENOMEM; | |
| 1421 | + } | |
| 1422 | + | |
| 1423 | + ctx->protofamily = AF_UNSPEC; | |
| 1424 | + ctx->mountfamily = AF_UNSPEC; | |
| 1425 | + ctx->mount_server.port = NFS_UNSPEC_PORT; | |
| 1426 | + | |
| 1427 | + if (fc->root) { | |
| 1428 | + /* reconfigure, start with the current config */ | |
| 1429 | + struct nfs_server *nfss = fc->root->d_sb->s_fs_info; | |
| 1430 | + struct net *net = nfss->nfs_client->cl_net; | |
| 1431 | + | |
| 1432 | + ctx->flags = nfss->flags; | |
| 1433 | + ctx->rsize = nfss->rsize; | |
| 1434 | + ctx->wsize = nfss->wsize; | |
| 1435 | + ctx->retrans = nfss->client->cl_timeout->to_retries; | |
| 1436 | + ctx->selected_flavor = nfss->client->cl_auth->au_flavor; | |
| 1437 | + ctx->acregmin = nfss->acregmin / HZ; | |
| 1438 | + ctx->acregmax = nfss->acregmax / HZ; | |
| 1439 | + ctx->acdirmin = nfss->acdirmin / HZ; | |
| 1440 | + ctx->acdirmax = nfss->acdirmax / HZ; | |
| 1441 | + ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; | |
| 1442 | + ctx->nfs_server.port = nfss->port; | |
| 1443 | + ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; | |
| 1444 | + ctx->version = nfss->nfs_client->rpc_ops->version; | |
| 1445 | + ctx->minorversion = nfss->nfs_client->cl_minorversion; | |
| 1446 | + | |
| 1447 | + memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr, | |
| 1448 | + ctx->nfs_server.addrlen); | |
| 1449 | + | |
| 1450 | + if (fc->net_ns != net) { | |
| 1451 | + put_net(fc->net_ns); | |
| 1452 | + fc->net_ns = get_net(net); | |
| 1453 | + } | |
| 1454 | + | |
| 1455 | + ctx->mount_info.nfs_mod = nfss->nfs_client->cl_nfs_mod; | |
| 1456 | + __module_get(ctx->mount_info.nfs_mod->owner); | |
| 1457 | + } else { | |
| 1458 | + /* defaults */ | |
| 1459 | + ctx->timeo = NFS_UNSPEC_TIMEO; | |
| 1460 | + ctx->retrans = NFS_UNSPEC_RETRANS; | |
| 1461 | + ctx->acregmin = NFS_DEF_ACREGMIN; | |
| 1462 | + ctx->acregmax = NFS_DEF_ACREGMAX; | |
| 1463 | + ctx->acdirmin = NFS_DEF_ACDIRMIN; | |
| 1464 | + ctx->acdirmax = NFS_DEF_ACDIRMAX; | |
| 1465 | + ctx->nfs_server.port = NFS_UNSPEC_PORT; | |
| 1466 | + ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP; | |
| 1467 | + ctx->selected_flavor = RPC_AUTH_MAXFLAVOR; | |
| 1468 | + ctx->minorversion = 0; | |
| 1469 | + ctx->need_mount = true; | |
| 1470 | + } | |
| 1471 | + ctx->net = fc->net_ns; | |
| 1472 | + fc->fs_private = ctx; | |
| 1473 | + fc->ops = &nfs_fs_context_ops; | |
| 1474 | + return 0; | |
| 1475 | +} | |
| 1476 | + | |
| 1477 | +struct file_system_type nfs_fs_type = { | |
| 1478 | + .owner = THIS_MODULE, | |
| 1479 | + .name = "nfs", | |
| 1480 | + .init_fs_context = nfs_init_fs_context, | |
| 1481 | + .parameters = &nfs_fs_parameters, | |
| 1482 | + .kill_sb = nfs_kill_super, | |
| 1483 | + .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, | |
| 1484 | +}; | |
| 1485 | +MODULE_ALIAS_FS("nfs"); | |
| 1486 | +EXPORT_SYMBOL_GPL(nfs_fs_type); | |
| 1487 | + | |
| 1488 | +#if IS_ENABLED(CONFIG_NFS_V4) | |
| 1489 | +struct file_system_type nfs4_fs_type = { | |
| 1490 | + .owner = THIS_MODULE, | |
| 1491 | + .name = "nfs4", | |
| 1492 | + .init_fs_context = nfs_init_fs_context, | |
| 1493 | + .parameters = &nfs_fs_parameters, | |
| 1494 | + .kill_sb = nfs_kill_super, | |
| 1495 | + .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, | |
| 1496 | +}; | |
| 1497 | +MODULE_ALIAS_FS("nfs4"); | |
| 1498 | +MODULE_ALIAS("nfs4"); | |
| 1499 | +EXPORT_SYMBOL_GPL(nfs4_fs_type); | |
| 1500 | +#endif /* CONFIG_NFS_V4 */ | |
| @@ -4,7 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | */ |
| 5 | 5 | |
| 6 | 6 | #include "nfs4_fs.h" |
| 7 | −#include <linux/mount.h> | |
| 7 | +#include <linux/fs_context.h> | |
| 8 | 8 | #include <linux/security.h> |
| 9 | 9 | #include <linux/crc32.h> |
| 10 | 10 | #include <linux/sunrpc/addr.h> |
| @@ -16,6 +16,7 @@ · 5 unmodified lines | ||
| 16 | 16 | extern const struct export_operations nfs_export_ops; |
| 17 | 17 | |
| 18 | 18 | struct nfs_string; |
| 19 | +struct nfs_pageio_descriptor; | |
| 19 | 20 | |
| 20 | 21 | static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr) |
| 21 | 22 | { |
| @@ -34,12 +35,13 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr) · 12 unmodified lines | ||
| 34 | 35 | |
| 35 | 36 | struct nfs_clone_mount { |
| 36 | 37 | const struct super_block *sb; |
| 37 | − const struct dentry *dentry; | |
| 38 | + struct dentry *dentry; | |
| 38 | 39 | char *hostname; |
| 39 | 40 | char *mnt_path; |
| 40 | 41 | struct sockaddr *addr; |
| 41 | 42 | size_t addrlen; |
| 42 | 43 | rpc_authflavor_t authflavor; |
| 44 | + struct nfs_fattr *fattr; | |
| 43 | 45 | }; |
| 44 | 46 | |
| 45 | 47 | /* |
| @@ -78,10 +80,23 @@ struct nfs_client_initdata { · 32 unmodified lines | ||
| 78 | 80 | const struct cred *cred; |
| 79 | 81 | }; |
| 80 | 82 | |
| 83 | +struct nfs_mount_info { | |
| 84 | + unsigned int inherited_bsize; | |
| 85 | + struct nfs_fs_context *ctx; | |
| 86 | + struct nfs_clone_mount *cloned; | |
| 87 | + struct nfs_server *server; | |
| 88 | + struct nfs_fh *mntfh; | |
| 89 | + struct nfs_subversion *nfs_mod; | |
| 90 | +}; | |
| 91 | + | |
| 81 | 92 | /* |
| 82 | 93 | * In-kernel mount arguments |
| 83 | 94 | */ |
| 84 | 95 | struct nfs_fs_context { |
| 96 | + bool internal; | |
| 97 | + bool skip_reconfig_option_check; | |
| 98 | + bool need_mount; | |
| 99 | + bool sloppy; | |
| 85 | 100 | unsigned int flags; /* NFS{,4}_MOUNT_* flags */ |
| 86 | 101 | unsigned int rsize, wsize; |
| 87 | 102 | unsigned int timeo, retrans; |
| @@ -98,8 +113,6 @@ struct nfs_fs_context { · 10 unmodified lines | ||
| 98 | 113 | char *fscache_uniq; |
| 99 | 114 | unsigned short protofamily; |
| 100 | 115 | unsigned short mountfamily; |
| 101 | − bool need_mount; | |
| 102 | − bool sloppy; | |
| 103 | 116 | |
| 104 | 117 | struct { |
| 105 | 118 | union { |
| @@ -124,14 +137,23 @@ struct nfs_fs_context { · 18 unmodified lines | ||
| 124 | 137 | int port; |
| 125 | 138 | unsigned short protocol; |
| 126 | 139 | unsigned short nconnect; |
| 140 | + unsigned short export_path_len; | |
| 127 | 141 | } nfs_server; |
| 128 | 142 | |
| 129 | 143 | void *lsm_opts; |
| 130 | 144 | struct net *net; |
| 131 | 145 | |
| 132 | 146 | char buf[32]; /* Parse buffer */ |
| 147 | + | |
| 148 | + struct nfs_mount_info mount_info; | |
| 149 | + struct nfs_clone_mount clone_data; | |
| 133 | 150 | }; |
| 134 | 151 | |
| 152 | +static inline struct nfs_fs_context *nfs_fc2context(const struct fs_context *fc) | |
| 153 | +{ | |
| 154 | + return fc->fs_private; | |
| 155 | +} | |
| 156 | + | |
| 135 | 157 | /* mount_clnt.c */ |
| 136 | 158 | struct nfs_mount_request { |
| 137 | 159 | struct sockaddr *sap; |
| @@ -147,15 +169,6 @@ struct nfs_mount_request { · 9 unmodified lines | ||
| 147 | 169 | struct net *net; |
| 148 | 170 | }; |
| 149 | 171 | |
| 150 | −struct nfs_mount_info { | |
| 151 | − unsigned int inherited_bsize; | |
| 152 | − struct nfs_fs_context *ctx; | |
| 153 | − struct nfs_clone_mount *cloned; | |
| 154 | − struct nfs_server *server; | |
| 155 | − struct nfs_fh *mntfh; | |
| 156 | − struct nfs_subversion *nfs_mod; | |
| 157 | −}; | |
| 158 | − | |
| 159 | 172 | extern int nfs_mount(struct nfs_mount_request *info); |
| 160 | 173 | extern void nfs_umount(const struct nfs_mount_request *info); |
| 161 | 174 | |
| @@ -235,22 +248,8 @@ static inline void nfs_fs_proc_exit(void) · 73 unmodified lines | ||
| 235 | 248 | extern const struct svc_version nfs4_callback_version1; |
| 236 | 249 | extern const struct svc_version nfs4_callback_version4; |
| 237 | 250 | |
| 238 | −struct nfs_pageio_descriptor; | |
| 239 | − | |
| 240 | −/* mount.c */ | |
| 241 | −#define NFS_TEXT_DATA 1 | |
| 242 | − | |
| 243 | −extern struct nfs_fs_context *nfs_alloc_parsed_mount_data(void); | |
| 244 | −extern void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx); | |
| 245 | −extern int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx); | |
| 246 | −extern int nfs_validate_mount_data(struct file_system_type *fs_type, | |
| 247 | − void *options, | |
| 248 | − struct nfs_fs_context *ctx, | |
| 249 | − struct nfs_fh *mntfh, | |
| 250 | − const char *dev_name); | |
| 251 | −extern int nfs_validate_text_mount_data(void *options, | |
| 252 | − struct nfs_fs_context *ctx, | |
| 253 | − const char *dev_name); | |
| 251 | +/* fs_context.c */ | |
| 252 | +extern struct file_system_type nfs_fs_type; | |
| 254 | 253 | |
| 255 | 254 | /* pagelist.c */ |
| 256 | 255 | extern int __init nfs_init_nfspagecache(void); |
| @@ -411,14 +410,9 @@ extern int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode); · 154 unmodified lines | ||
| 411 | 410 | |
| 412 | 411 | /* super.c */ |
| 413 | 412 | extern const struct super_operations nfs_sops; |
| 414 | −extern struct file_system_type nfs_fs_type; | |
| 415 | −extern struct file_system_type nfs_prepared_fs_type; | |
| 416 | −#if IS_ENABLED(CONFIG_NFS_V4) | |
| 417 | −extern struct file_system_type nfs4_referral_fs_type; | |
| 418 | −#endif | |
| 419 | 413 | bool nfs_auth_info_match(const struct nfs_auth_info *, rpc_authflavor_t); |
| 420 | −struct dentry *nfs_try_mount(int, const char *, struct nfs_mount_info *); | |
| 421 | −struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); | |
| 414 | +int nfs_try_get_tree(struct fs_context *); | |
| 415 | +int nfs_get_tree_common(struct fs_context *); | |
| 422 | 416 | void nfs_kill_super(struct super_block *); |
| 423 | 417 | |
| 424 | 418 | extern struct rpc_stat nfs_rpcstat; |
| @@ -446,10 +440,8 @@ static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi) · 21 unmodified lines | ||
| 446 | 440 | extern char *nfs_path(char **p, struct dentry *dentry, |
| 447 | 441 | char *buffer, ssize_t buflen, unsigned flags); |
| 448 | 442 | extern struct vfsmount *nfs_d_automount(struct path *path); |
| 449 | −struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *, | |
| 450 | − struct nfs_fh *, struct nfs_fattr *); | |
| 451 | −struct vfsmount *nfs_do_submount(struct dentry *, struct nfs_fh *, | |
| 452 | − struct nfs_fattr *, rpc_authflavor_t); | |
| 443 | +int nfs_submount(struct fs_context *, struct nfs_server *); | |
| 444 | +int nfs_do_submount(struct fs_context *); | |
| 453 | 445 | |
| 454 | 446 | /* getroot.c */ |
| 455 | 447 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, |
| @@ -476,7 +468,7 @@ int nfs_show_options(struct seq_file *, struct dentry *); · 20 unmodified lines | ||
| 476 | 468 | int nfs_show_devname(struct seq_file *, struct dentry *); |
| 477 | 469 | int nfs_show_path(struct seq_file *, struct dentry *); |
| 478 | 470 | int nfs_show_stats(struct seq_file *, struct dentry *); |
| 479 | −int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | |
| 471 | +int nfs_reconfigure(struct fs_context *); | |
| 480 | 472 | |
| 481 | 473 | /* write.c */ |
| 482 | 474 | extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
| @@ -140,34 +140,65 @@ EXPORT_SYMBOL_GPL(nfs_path); · 139 unmodified lines | ||
| 140 | 140 | */ |
| 141 | 141 | struct vfsmount *nfs_d_automount(struct path *path) |
| 142 | 142 | { |
| 143 | − struct vfsmount *mnt; | |
| 143 | + struct nfs_fs_context *ctx; | |
| 144 | + struct fs_context *fc; | |
| 145 | + struct vfsmount *mnt = ERR_PTR(-ENOMEM); | |
| 144 | 146 | struct nfs_server *server = NFS_SERVER(d_inode(path->dentry)); |
| 145 | − struct nfs_fh *fh = NULL; | |
| 146 | − struct nfs_fattr *fattr = NULL; | |
| 147 | + struct nfs_client *client = server->nfs_client; | |
| 148 | + int ret; | |
| 147 | 149 | |
| 148 | 150 | if (IS_ROOT(path->dentry)) |
| 149 | 151 | return ERR_PTR(-ESTALE); |
| 150 | 152 | |
| 151 | − mnt = ERR_PTR(-ENOMEM); | |
| 152 | − fh = nfs_alloc_fhandle(); | |
| 153 | − fattr = nfs_alloc_fattr(); | |
| 154 | − if (fh == NULL || fattr == NULL) | |
| 155 | − goto out; | |
| 153 | + /* Open a new filesystem context, transferring parameters from the | |
| 154 | + * parent superblock, including the network namespace. | |
| 155 | + */ | |
| 156 | + fc = fs_context_for_submount(&nfs_fs_type, path->dentry); | |
| 157 | + if (IS_ERR(fc)) | |
| 158 | + return ERR_CAST(fc); | |
| 156 | 159 | |
| 157 | − mnt = server->nfs_client->rpc_ops->submount(server, path->dentry, fh, fattr); | |
| 160 | + ctx = nfs_fc2context(fc); | |
| 161 | + ctx->clone_data.dentry = path->dentry; | |
| 162 | + ctx->clone_data.sb = path->dentry->d_sb; | |
| 163 | + ctx->clone_data.fattr = nfs_alloc_fattr(); | |
| 164 | + if (!ctx->clone_data.fattr) | |
| 165 | + goto out_fc; | |
| 166 | + | |
| 167 | + if (fc->net_ns != client->cl_net) { | |
| 168 | + put_net(fc->net_ns); | |
| 169 | + fc->net_ns = get_net(client->cl_net); | |
| 170 | + } | |
| 171 | + | |
| 172 | + /* for submounts we want the same server; referrals will reassign */ | |
| 173 | + memcpy(&ctx->nfs_server.address, &client->cl_addr, client->cl_addrlen); | |
| 174 | + ctx->nfs_server.addrlen = client->cl_addrlen; | |
| 175 | + ctx->nfs_server.port = server->port; | |
| 176 | + | |
| 177 | + ctx->version = client->rpc_ops->version; | |
| 178 | + ctx->minorversion = client->cl_minorversion; | |
| 179 | + ctx->mount_info.nfs_mod = client->cl_nfs_mod; | |
| 180 | + __module_get(ctx->mount_info.nfs_mod->owner); | |
| 181 | + | |
| 182 | + ret = client->rpc_ops->submount(fc, server); | |
| 183 | + if (ret < 0) { | |
| 184 | + mnt = ERR_PTR(ret); | |
| 185 | + goto out_fc; | |
| 186 | + } | |
| 187 | + | |
| 188 | + up_write(&fc->root->d_sb->s_umount); | |
| 189 | + mnt = vfs_create_mount(fc); | |
| 158 | 190 | if (IS_ERR(mnt)) |
| 159 | − goto out; | |
| 191 | + goto out_fc; | |
| 160 | 192 | |
| 161 | 193 | if (nfs_mountpoint_expiry_timeout < 0) |
| 162 | − goto out; | |
| 194 | + goto out_fc; | |
| 163 | 195 | |
| 164 | 196 | mntget(mnt); /* prevent immediate expiration */ |
| 165 | 197 | mnt_set_expiry(mnt, &nfs_automount_list); |
| 166 | 198 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); |
| 167 | 199 | |
| 168 | −out: | |
| 169 | − nfs_free_fattr(fattr); | |
| 170 | − nfs_free_fhandle(fh); | |
| 200 | +out_fc: | |
| 201 | + put_fs_context(fc); | |
| 171 | 202 | return mnt; |
| 172 | 203 | } |
| 173 | 204 | |
| @@ -222,61 +253,62 @@ void nfs_release_automount_timer(void) · 48 unmodified lines | ||
| 222 | 253 | * @authflavor: security flavor to use when performing the mount |
| 223 | 254 | * |
| 224 | 255 | */ |
| 225 | −struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh, | |
| 226 | − struct nfs_fattr *fattr, rpc_authflavor_t authflavor) | |
| 256 | +int nfs_do_submount(struct fs_context *fc) | |
| 227 | 257 | { |
| 228 | − struct super_block *sb = dentry->d_sb; | |
| 229 | − struct nfs_clone_mount mountdata = { | |
| 230 | − .sb = sb, | |
| 231 | − .dentry = dentry, | |
| 232 | − .authflavor = authflavor, | |
| 233 | − }; | |
| 234 | − struct nfs_mount_info mount_info = { | |
| 235 | − .inherited_bsize = sb->s_blocksize_bits, | |
| 236 | − .cloned = &mountdata, | |
| 237 | − .mntfh = fh, | |
| 238 | − .nfs_mod = NFS_SB(sb)->nfs_client->cl_nfs_mod, | |
| 239 | − }; | |
| 258 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 259 | + struct dentry *dentry = ctx->clone_data.dentry; | |
| 240 | 260 | struct nfs_server *server; |
| 241 | − struct vfsmount *mnt; | |
| 242 | − char *page = (char *) __get_free_page(GFP_USER); | |
| 243 | − char *devname; | |
| 261 | + char *buffer, *p; | |
| 262 | + int ret; | |
| 244 | 263 | |
| 245 | − if (page == NULL) | |
| 246 | − return ERR_PTR(-ENOMEM); | |
| 264 | + /* create a new volume representation */ | |
| 265 | + server = ctx->mount_info.nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb), | |
| 266 | + ctx->mount_info.mntfh, | |
| 267 | + ctx->clone_data.fattr, | |
| 268 | + ctx->selected_flavor); | |
| 247 | 269 | |
| 248 | − server = mount_info.nfs_mod->rpc_ops->clone_server(NFS_SB(sb), fh, | |
| 249 | − fattr, authflavor); | |
| 250 | 270 | if (IS_ERR(server)) |
| 251 | − return ERR_CAST(server); | |
| 271 | + return PTR_ERR(server); | |
| 252 | 272 | |
| 253 | − mount_info.server = server; | |
| 273 | + ctx->mount_info.server = server; | |
| 254 | 274 | |
| 255 | − devname = nfs_devname(dentry, page, PAGE_SIZE); | |
| 256 | − if (IS_ERR(devname)) | |
| 257 | − mnt = ERR_CAST(devname); | |
| 258 | − else | |
| 259 | − mnt = vfs_submount(dentry, &nfs_prepared_fs_type, devname, &mount_info); | |
| 275 | + buffer = kmalloc(4096, GFP_USER); | |
| 276 | + if (!buffer) | |
| 277 | + return -ENOMEM; | |
| 260 | 278 | |
| 261 | − if (mount_info.server) | |
| 262 | − nfs_free_server(mount_info.server); | |
| 263 | − free_page((unsigned long)page); | |
| 264 | − return mnt; | |
| 279 | + ctx->internal = true; | |
| 280 | + ctx->mount_info.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits; | |
| 281 | + | |
| 282 | + p = nfs_devname(dentry, buffer, 4096); | |
| 283 | + if (IS_ERR(p)) { | |
| 284 | + dprintk("NFS: Couldn't determine submount pathname\n"); | |
| 285 | + ret = PTR_ERR(p); | |
| 286 | + } else { | |
| 287 | + ret = vfs_parse_fs_string(fc, "source", p, buffer + 4096 - p); | |
| 288 | + if (!ret) | |
| 289 | + ret = vfs_get_tree(fc); | |
| 290 | + } | |
| 291 | + kfree(buffer); | |
| 292 | + return ret; | |
| 265 | 293 | } |
| 266 | 294 | EXPORT_SYMBOL_GPL(nfs_do_submount); |
| 267 | 295 | |
| 268 | −struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry, | |
| 269 | − struct nfs_fh *fh, struct nfs_fattr *fattr) | |
| 296 | +int nfs_submount(struct fs_context *fc, struct nfs_server *server) | |
| 270 | 297 | { |
| 271 | − int err; | |
| 298 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 299 | + struct dentry *dentry = ctx->clone_data.dentry; | |
| 272 | 300 | struct dentry *parent = dget_parent(dentry); |
| 301 | + int err; | |
| 273 | 302 | |
| 274 | 303 | /* Look it up again to get its attributes */ |
| 275 | − err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name, fh, fattr, NULL); | |
| 304 | + err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name, | |
| 305 | + ctx->mount_info.mntfh, ctx->clone_data.fattr, | |
| 306 | + NULL); | |
| 276 | 307 | dput(parent); |
| 277 | 308 | if (err != 0) |
| 278 | − return ERR_PTR(err); | |
| 309 | + return err; | |
| 279 | 310 | |
| 280 | − return nfs_do_submount(dentry, fh, fattr, server->client->cl_auth->au_flavor); | |
| 311 | + ctx->selected_flavor = server->client->cl_auth->au_flavor; | |
| 312 | + return nfs_do_submount(fc); | |
| 281 | 313 | } |
| 282 | 314 | EXPORT_SYMBOL_GPL(nfs_submount); |
| @@ -990,7 +990,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { · 989 unmodified lines | ||
| 990 | 990 | .nlmclnt_ops = &nlmclnt_fl_close_lock_ops, |
| 991 | 991 | .getroot = nfs3_proc_get_root, |
| 992 | 992 | .submount = nfs_submount, |
| 993 | − .try_mount = nfs_try_mount, | |
| 993 | + .try_get_tree = nfs_try_get_tree, | |
| 994 | 994 | .getattr = nfs3_proc_getattr, |
| 995 | 995 | .setattr = nfs3_proc_setattr, |
| 996 | 996 | .lookup = nfs3_proc_lookup, |
| @@ -268,14 +268,13 @@ extern const struct dentry_operations nfs4_dentry_operations; · 267 unmodified lines | ||
| 268 | 268 | int nfs_atomic_open(struct inode *, struct dentry *, struct file *, |
| 269 | 269 | unsigned, umode_t); |
| 270 | 270 | |
| 271 | −/* super.c */ | |
| 271 | +/* fs_context.c */ | |
| 272 | 272 | extern struct file_system_type nfs4_fs_type; |
| 273 | 273 | |
| 274 | 274 | /* nfs4namespace.c */ |
| 275 | 275 | struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *, |
| 276 | 276 | const struct qstr *); |
| 277 | −struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *, | |
| 278 | − struct nfs_fh *, struct nfs_fattr *); | |
| 277 | +int nfs4_submount(struct fs_context *, struct nfs_server *); | |
| 279 | 278 | int nfs4_replace_transport(struct nfs_server *server, |
| 280 | 279 | const struct nfs4_fs_locations *locations); |
| 281 | 280 | |
| @@ -526,7 +525,6 @@ extern const nfs4_stateid invalid_stateid; · 244 unmodified lines | ||
| 526 | 525 | /* nfs4super.c */ |
| 527 | 526 | struct nfs_mount_info; |
| 528 | 527 | extern struct nfs_subversion nfs_v4; |
| 529 | −struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *); | |
| 530 | 528 | extern bool nfs4_disable_idmapping; |
| 531 | 529 | extern unsigned short max_session_slots; |
| 532 | 530 | extern unsigned short max_session_cb_slots; |
| @@ -536,6 +534,9 @@ extern bool recover_lost_locks; · 3 unmodified lines | ||
| 536 | 534 | #define NFS4_CLIENT_ID_UNIQ_LEN (64) |
| 537 | 535 | extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN]; |
| 538 | 536 | |
| 537 | +extern int nfs4_try_get_tree(struct fs_context *); | |
| 538 | +extern int nfs4_get_referral_tree(struct fs_context *); | |
| 539 | + | |
| 539 | 540 | /* nfs4sysctl.c */ |
| 540 | 541 | #ifdef CONFIG_SYSCTL |
| 541 | 542 | int nfs4_register_sysctl(void); |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <linux/fs.h> |
| 8 | 8 | #include <linux/file.h> |
| 9 | 9 | #include <linux/falloc.h> |
| 10 | +#include <linux/mount.h> | |
| 10 | 11 | #include <linux/nfs_fs.h> |
| 11 | 12 | #include "delegation.h" |
| 12 | 13 | #include "internal.h" |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | * NFSv4 namespace |
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | +#include <linux/module.h> | |
| 11 | 12 | #include <linux/dcache.h> |
| 12 | 13 | #include <linux/mount.h> |
| 13 | 14 | #include <linux/namei.h> |
| @@ -21,37 +22,64 @@ · 7 unmodified lines | ||
| 21 | 22 | #include <linux/inet.h> |
| 22 | 23 | #include "internal.h" |
| 23 | 24 | #include "nfs4_fs.h" |
| 25 | +#include "nfs.h" | |
| 24 | 26 | #include "dns_resolve.h" |
| 25 | 27 | |
| 26 | 28 | #define NFSDBG_FACILITY NFSDBG_VFS |
| 27 | 29 | |
| 30 | +/* | |
| 31 | + * Work out the length that an NFSv4 path would render to as a standard posix | |
| 32 | + * path, with a leading slash but no terminating slash. | |
| 33 | + */ | |
| 34 | +static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname) | |
| 35 | +{ | |
| 36 | + ssize_t len = 0; | |
| 37 | + int i; | |
| 38 | + | |
| 39 | + for (i = 0; i < pathname->ncomponents; i++) { | |
| 40 | + const struct nfs4_string *component = &pathname->components[i]; | |
| 41 | + | |
| 42 | + if (component->len > NAME_MAX) | |
| 43 | + goto too_long; | |
| 44 | + len += 1 + component->len; /* Adding "/foo" */ | |
| 45 | + if (len > PATH_MAX) | |
| 46 | + goto too_long; | |
| 47 | + } | |
| 48 | + return len; | |
| 49 | + | |
| 50 | +too_long: | |
| 51 | + return -ENAMETOOLONG; | |
| 52 | +} | |
| 53 | + | |
| 28 | 54 | /* |
| 29 | 55 | * Convert the NFSv4 pathname components into a standard posix path. |
| 30 | − * | |
| 31 | − * Note that the resulting string will be placed at the end of the buffer | |
| 32 | 56 | */ |
| 33 | −static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname, | |
| 34 | − char *buffer, ssize_t buflen) | |
| 57 | +static char *nfs4_pathname_string(const struct nfs4_pathname *pathname, | |
| 58 | + unsigned short *_len) | |
| 35 | 59 | { |
| 36 | − char *end = buffer + buflen; | |
| 37 | − int n; | |
| 60 | + ssize_t len; | |
| 61 | + char *buf, *p; | |
| 62 | + int i; | |
| 63 | + | |
| 64 | + len = nfs4_pathname_len(pathname); | |
| 65 | + if (len < 0) | |
| 66 | + return ERR_PTR(len); | |
| 67 | + *_len = len; | |
| 68 | + | |
| 69 | + p = buf = kmalloc(len + 1, GFP_KERNEL); | |
| 70 | + if (!buf) | |
| 71 | + return ERR_PTR(-ENOMEM); | |
| 72 | + | |
| 73 | + for (i = 0; i < pathname->ncomponents; i++) { | |
| 74 | + const struct nfs4_string *component = &pathname->components[i]; | |
| 38 | 75 | |
| 39 | − *--end = '\0'; | |
| 40 | − buflen--; | |
| 41 | − | |
| 42 | − n = pathname->ncomponents; | |
| 43 | − while (--n >= 0) { | |
| 44 | − const struct nfs4_string *component = &pathname->components[n]; | |
| 45 | − buflen -= component->len + 1; | |
| 46 | − if (buflen < 0) | |
| 47 | − goto Elong; | |
| 48 | − end -= component->len; | |
| 49 | − memcpy(end, component->data, component->len); | |
| 50 | − *--end = '/'; | |
| 76 | + *p++ = '/'; | |
| 77 | + memcpy(p, component->data, component->len); | |
| 78 | + p += component->len; | |
| 51 | 79 | } |
| 52 | − return end; | |
| 53 | −Elong: | |
| 54 | − return ERR_PTR(-ENAMETOOLONG); | |
| 80 | + | |
| 81 | + *p = 0; | |
| 82 | + return buf; | |
| 55 | 83 | } |
| 56 | 84 | |
| 57 | 85 | /* |
| @@ -100,21 +128,32 @@ static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) · 42 unmodified lines | ||
| 100 | 128 | */ |
| 101 | 129 | static int nfs4_validate_fspath(struct dentry *dentry, |
| 102 | 130 | const struct nfs4_fs_locations *locations, |
| 103 | − char *page, char *page2) | |
| 131 | + struct nfs_fs_context *ctx) | |
| 104 | 132 | { |
| 105 | 133 | const char *path, *fs_path; |
| 134 | + char *buf; | |
| 135 | + unsigned short len; | |
| 136 | + int n; | |
| 106 | 137 | |
| 107 | − path = nfs4_path(dentry, page, PAGE_SIZE); | |
| 108 | − if (IS_ERR(path)) | |
| 138 | + buf = kmalloc(4096, GFP_KERNEL); | |
| 139 | + path = nfs4_path(dentry, buf, 4096); | |
| 140 | + if (IS_ERR(path)) { | |
| 141 | + kfree(buf); | |
| 109 | 142 | return PTR_ERR(path); |
| 143 | + } | |
| 110 | 144 | |
| 111 | − fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); | |
| 112 | − if (IS_ERR(fs_path)) | |
| 145 | + fs_path = nfs4_pathname_string(&locations->fs_path, &len); | |
| 146 | + if (IS_ERR(fs_path)) { | |
| 147 | + kfree(buf); | |
| 113 | 148 | return PTR_ERR(fs_path); |
| 149 | + } | |
| 114 | 150 | |
| 115 | − if (strncmp(path, fs_path, strlen(fs_path)) != 0) { | |
| 151 | + n = strncmp(path, fs_path, len); | |
| 152 | + kfree(buf); | |
| 153 | + kfree(fs_path); | |
| 154 | + if (n != 0) { | |
| 116 | 155 | dprintk("%s: path %s does not begin with fsroot %s\n", |
| 117 | − __func__, path, fs_path); | |
| 156 | + __func__, path, ctx->nfs_server.export_path); | |
| 118 | 157 | return -ENOENT; |
| 119 | 158 | } |
| 120 | 159 | |
| @@ -236,55 +275,83 @@ out: · 115 unmodified lines | ||
| 236 | 275 | return new; |
| 237 | 276 | } |
| 238 | 277 | |
| 239 | −static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |
| 240 | − char *page, char *page2, | |
| 241 | − const struct nfs4_fs_location *location) | |
| 278 | +static int try_location(struct fs_context *fc, | |
| 279 | + const struct nfs4_fs_location *location) | |
| 242 | 280 | { |
| 243 | 281 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); |
| 244 | − struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client); | |
| 245 | − struct vfsmount *mnt = ERR_PTR(-ENOENT); | |
| 246 | − char *mnt_path; | |
| 247 | − unsigned int maxbuflen; | |
| 248 | − unsigned int s; | |
| 282 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 283 | + unsigned int len, s; | |
| 284 | + char *export_path, *source, *p; | |
| 285 | + int ret = -ENOENT; | |
| 286 | + | |
| 287 | + /* Allocate a buffer big enough to hold any of the hostnames plus a | |
| 288 | + * terminating char and also a buffer big enough to hold the hostname | |
| 289 | + * plus a colon plus the path. | |
| 290 | + */ | |
| 291 | + len = 0; | |
| 292 | + for (s = 0; s < location->nservers; s++) { | |
| 293 | + const struct nfs4_string *buf = &location->servers[s]; | |
| 294 | + if (buf->len > len) | |
| 295 | + len = buf->len; | |
| 296 | + } | |
| 249 | 297 | |
| 250 | − mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE); | |
| 251 | − if (IS_ERR(mnt_path)) | |
| 252 | − return ERR_CAST(mnt_path); | |
| 253 | − mountdata->mnt_path = mnt_path; | |
| 254 | − maxbuflen = mnt_path - 1 - page2; | |
| 298 | + kfree(ctx->nfs_server.hostname); | |
| 299 | + ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL); | |
| 300 | + if (!ctx->nfs_server.hostname) | |
| 301 | + return -ENOMEM; | |
| 255 | 302 | |
| 256 | − mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); | |
| 257 | − if (mountdata->addr == NULL) | |
| 258 | − return ERR_PTR(-ENOMEM); | |
| 303 | + export_path = nfs4_pathname_string(&location->rootpath, | |
| 304 | + &ctx->nfs_server.export_path_len); | |
| 305 | + if (IS_ERR(export_path)) | |
| 306 | + return PTR_ERR(export_path); | |
| 259 | 307 | |
| 308 | + ctx->nfs_server.export_path = export_path; | |
| 309 | + | |
| 310 | + source = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1, | |
| 311 | + GFP_KERNEL); | |
| 312 | + if (!source) | |
| 313 | + return -ENOMEM; | |
| 314 | + | |
| 315 | + kfree(fc->source); | |
| 316 | + fc->source = source; | |
| 317 | + | |
| 318 | + ctx->clone_data.addr = kmalloc(addr_bufsize, GFP_KERNEL); | |
| 319 | + if (ctx->clone_data.addr == NULL) | |
| 320 | + return -ENOMEM; | |
| 260 | 321 | for (s = 0; s < location->nservers; s++) { |
| 261 | 322 | const struct nfs4_string *buf = &location->servers[s]; |
| 262 | 323 | |
| 263 | − if (buf->len <= 0 || buf->len >= maxbuflen) | |
| 264 | − continue; | |
| 265 | − | |
| 266 | 324 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) |
| 267 | 325 | continue; |
| 268 | 326 | |
| 269 | − mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, | |
| 270 | − mountdata->addr, addr_bufsize, net); | |
| 271 | − if (mountdata->addrlen == 0) | |
| 327 | + ctx->clone_data.addrlen = | |
| 328 | + nfs_parse_server_name(buf->data, buf->len, | |
| 329 | + ctx->clone_data.addr, | |
| 330 | + addr_bufsize, | |
| 331 | + fc->net_ns); | |
| 332 | + if (ctx->clone_data.addrlen == 0) | |
| 272 | 333 | continue; |
| 273 | 334 | |
| 274 | − memcpy(page2, buf->data, buf->len); | |
| 275 | − page2[buf->len] = '\0'; | |
| 276 | − mountdata->hostname = page2; | |
| 335 | + rpc_set_port(ctx->clone_data.addr, NFS_PORT); | |
| 277 | 336 | |
| 278 | − snprintf(page, PAGE_SIZE, "%s:%s", | |
| 279 | − mountdata->hostname, | |
| 280 | − mountdata->mnt_path); | |
| 337 | + memcpy(ctx->nfs_server.hostname, buf->data, buf->len); | |
| 338 | + ctx->nfs_server.hostname[buf->len] = '\0'; | |
| 339 | + ctx->clone_data.hostname = ctx->nfs_server.hostname; | |
| 281 | 340 | |
| 282 | − mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata); | |
| 283 | − if (!IS_ERR(mnt)) | |
| 284 | − break; | |
| 341 | + p = source; | |
| 342 | + memcpy(p, buf->data, buf->len); | |
| 343 | + p += buf->len; | |
| 344 | + *p++ = ':'; | |
| 345 | + memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len); | |
| 346 | + p += ctx->nfs_server.export_path_len; | |
| 347 | + *p = 0; | |
| 348 | + | |
| 349 | + ret = nfs4_get_referral_tree(fc); | |
| 350 | + if (ret == 0) | |
| 351 | + return 0; | |
| 285 | 352 | } |
| 286 | − kfree(mountdata->addr); | |
| 287 | − return mnt; | |
| 353 | + | |
| 354 | + return ret; | |
| 288 | 355 | } |
| 289 | 356 | |
| 290 | 357 | /** |
| @@ -293,38 +360,23 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, · 2 unmodified lines | ||
| 293 | 360 | * @locations: array of NFSv4 server location information |
| 294 | 361 | * |
| 295 | 362 | */ |
| 296 | −static struct vfsmount *nfs_follow_referral(struct dentry *dentry, | |
| 297 | − const struct nfs4_fs_locations *locations) | |
| 363 | +static int nfs_follow_referral(struct fs_context *fc, | |
| 364 | + const struct nfs4_fs_locations *locations) | |
| 298 | 365 | { |
| 299 | − struct vfsmount *mnt = ERR_PTR(-ENOENT); | |
| 300 | − struct nfs_clone_mount mountdata = { | |
| 301 | − .sb = dentry->d_sb, | |
| 302 | − .dentry = dentry, | |
| 303 | − .authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor, | |
| 304 | − }; | |
| 305 | − char *page = NULL, *page2 = NULL; | |
| 366 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 306 | 367 | int loc, error; |
| 307 | 368 | |
| 308 | 369 | if (locations == NULL || locations->nlocations <= 0) |
| 309 | − goto out; | |
| 310 | − | |
| 311 | − dprintk("%s: referral at %pd2\n", __func__, dentry); | |
| 312 | − | |
| 313 | − page = (char *) __get_free_page(GFP_USER); | |
| 314 | − if (!page) | |
| 315 | − goto out; | |
| 370 | + return -ENOENT; | |
| 316 | 371 | |
| 317 | − page2 = (char *) __get_free_page(GFP_USER); | |
| 318 | − if (!page2) | |
| 319 | − goto out; | |
| 372 | + dprintk("%s: referral at %pd2\n", __func__, ctx->clone_data.dentry); | |
| 320 | 373 | |
| 321 | 374 | /* Ensure fs path is a prefix of current dentry path */ |
| 322 | − error = nfs4_validate_fspath(dentry, locations, page, page2); | |
| 323 | − if (error < 0) { | |
| 324 | − mnt = ERR_PTR(error); | |
| 325 | − goto out; | |
| 326 | − } | |
| 375 | + error = nfs4_validate_fspath(ctx->clone_data.dentry, locations, ctx); | |
| 376 | + if (error < 0) | |
| 377 | + return error; | |
| 327 | 378 | |
| 379 | + error = -ENOENT; | |
| 328 | 380 | for (loc = 0; loc < locations->nlocations; loc++) { |
| 329 | 381 | const struct nfs4_fs_location *location = &locations->locations[loc]; |
| 330 | 382 | |
| @@ -332,15 +384,12 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry, · 1 unmodified line | ||
| 332 | 384 | location->rootpath.ncomponents == 0) |
| 333 | 385 | continue; |
| 334 | 386 | |
| 335 | − mnt = try_location(&mountdata, page, page2, location); | |
| 336 | − if (!IS_ERR(mnt)) | |
| 337 | − break; | |
| 387 | + error = try_location(fc, location); | |
| 388 | + if (error == 0) | |
| 389 | + return 0; | |
| 338 | 390 | } |
| 339 | 391 | |
| 340 | −out: | |
| 341 | − free_page((unsigned long) page); | |
| 342 | − free_page((unsigned long) page2); | |
| 343 | − return mnt; | |
| 392 | + return error; | |
| 344 | 393 | } |
| 345 | 394 | |
| 346 | 395 | /* |
| @@ -348,71 +397,73 @@ out: · 1 unmodified line | ||
| 348 | 397 | * @dentry - dentry of referral |
| 349 | 398 | * |
| 350 | 399 | */ |
| 351 | −static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry) | |
| 400 | +static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client) | |
| 352 | 401 | { |
| 353 | − struct vfsmount *mnt = ERR_PTR(-ENOMEM); | |
| 354 | − struct dentry *parent; | |
| 402 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 403 | + struct dentry *dentry, *parent; | |
| 355 | 404 | struct nfs4_fs_locations *fs_locations = NULL; |
| 356 | 405 | struct page *page; |
| 357 | − int err; | |
| 406 | + int err = -ENOMEM; | |
| 358 | 407 | |
| 359 | 408 | /* BUG_ON(IS_ROOT(dentry)); */ |
| 360 | 409 | page = alloc_page(GFP_KERNEL); |
| 361 | − if (page == NULL) | |
| 362 | − return mnt; | |
| 410 | + if (!page) | |
| 411 | + return -ENOMEM; | |
| 363 | 412 | |
| 364 | 413 | fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); |
| 365 | − if (fs_locations == NULL) | |
| 414 | + if (!fs_locations) | |
| 366 | 415 | goto out_free; |
| 367 | 416 | |
| 368 | 417 | /* Get locations */ |
| 369 | − mnt = ERR_PTR(-ENOENT); | |
| 370 | − | |
| 418 | + dentry = ctx->clone_data.dentry; | |
| 371 | 419 | parent = dget_parent(dentry); |
| 372 | 420 | dprintk("%s: getting locations for %pd2\n", |
| 373 | 421 | __func__, dentry); |
| 374 | 422 | |
| 375 | 423 | err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page); |
| 376 | 424 | dput(parent); |
| 377 | − if (err != 0 || | |
| 378 | − fs_locations->nlocations <= 0 || | |
| 425 | + if (err != 0) | |
| 426 | + goto out_free_2; | |
| 427 | + | |
| 428 | + err = -ENOENT; | |
| 429 | + if (fs_locations->nlocations <= 0 || | |
| 379 | 430 | fs_locations->fs_path.ncomponents <= 0) |
| 380 | − goto out_free; | |
| 431 | + goto out_free_2; | |
| 381 | 432 | |
| 382 | − mnt = nfs_follow_referral(dentry, fs_locations); | |
| 433 | + err = nfs_follow_referral(fc, fs_locations); | |
| 434 | +out_free_2: | |
| 435 | + kfree(fs_locations); | |
| 383 | 436 | out_free: |
| 384 | 437 | __free_page(page); |
| 385 | − kfree(fs_locations); | |
| 386 | − return mnt; | |
| 438 | + return err; | |
| 387 | 439 | } |
| 388 | 440 | |
| 389 | −struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry, | |
| 390 | − struct nfs_fh *fh, struct nfs_fattr *fattr) | |
| 441 | +int nfs4_submount(struct fs_context *fc, struct nfs_server *server) | |
| 391 | 442 | { |
| 392 | − rpc_authflavor_t flavor = server->client->cl_auth->au_flavor; | |
| 443 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 444 | + struct dentry *dentry = ctx->clone_data.dentry; | |
| 393 | 445 | struct dentry *parent = dget_parent(dentry); |
| 394 | 446 | struct inode *dir = d_inode(parent); |
| 395 | 447 | const struct qstr *name = &dentry->d_name; |
| 396 | 448 | struct rpc_clnt *client; |
| 397 | − struct vfsmount *mnt; | |
| 449 | + int ret; | |
| 398 | 450 | |
| 399 | 451 | /* Look it up again to get its attributes and sec flavor */ |
| 400 | − client = nfs4_proc_lookup_mountpoint(dir, name, fh, fattr); | |
| 452 | + client = nfs4_proc_lookup_mountpoint(dir, name, ctx->mount_info.mntfh, | |
| 453 | + ctx->clone_data.fattr); | |
| 401 | 454 | dput(parent); |
| 402 | 455 | if (IS_ERR(client)) |
| 403 | − return ERR_CAST(client); | |
| 456 | + return PTR_ERR(client); | |
| 404 | 457 | |
| 405 | − if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { | |
| 406 | − mnt = nfs_do_refmount(client, dentry); | |
| 407 | − goto out; | |
| 458 | + ctx->selected_flavor = client->cl_auth->au_flavor; | |
| 459 | + if (ctx->clone_data.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { | |
| 460 | + ret = nfs_do_refmount(fc, client); | |
| 461 | + } else { | |
| 462 | + ret = nfs_do_submount(fc); | |
| 408 | 463 | } |
| 409 | 464 | |
| 410 | − if (client->cl_auth->au_flavor != flavor) | |
| 411 | − flavor = client->cl_auth->au_flavor; | |
| 412 | − mnt = nfs_do_submount(dentry, fh, fattr, flavor); | |
| 413 | −out: | |
| 414 | 465 | rpc_shutdown_client(client); |
| 415 | − return mnt; | |
| 466 | + return ret; | |
| 416 | 467 | } |
| 417 | 468 | |
| 418 | 469 | /* |
| @@ -10001,7 +10001,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { · 10000 unmodified lines | ||
| 10001 | 10001 | .file_ops = &nfs4_file_operations, |
| 10002 | 10002 | .getroot = nfs4_proc_get_root, |
| 10003 | 10003 | .submount = nfs4_submount, |
| 10004 | − .try_mount = nfs4_try_mount, | |
| 10004 | + .try_get_tree = nfs4_try_get_tree, | |
| 10005 | 10005 | .getattr = nfs4_proc_getattr, |
| 10006 | 10006 | .setattr = nfs4_proc_setattr, |
| 10007 | 10007 | .lookup = nfs4_proc_lookup, |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | */ |
| 5 | 5 | #include <linux/init.h> |
| 6 | 6 | #include <linux/module.h> |
| 7 | +#include <linux/mount.h> | |
| 7 | 8 | #include <linux/nfs4_mount.h> |
| 8 | 9 | #include <linux/nfs_fs.h> |
| 9 | 10 | #include "delegation.h" |
| @@ -18,16 +19,6 @@ · 8 unmodified lines | ||
| 18 | 19 | |
| 19 | 20 | static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc); |
| 20 | 21 | static void nfs4_evict_inode(struct inode *inode); |
| 21 | −static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | |
| 22 | − int flags, const char *dev_name, void *raw_data); | |
| 23 | − | |
| 24 | −struct file_system_type nfs4_referral_fs_type = { | |
| 25 | − .owner = THIS_MODULE, | |
| 26 | − .name = "nfs4", | |
| 27 | − .mount = nfs4_referral_mount, | |
| 28 | − .kill_sb = nfs_kill_super, | |
| 29 | − .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, | |
| 30 | −}; | |
| 31 | 22 | |
| 32 | 23 | static const struct super_operations nfs4_sops = { |
| 33 | 24 | .alloc_inode = nfs_alloc_inode, |
| @@ -41,7 +32,6 @@ static const struct super_operations nfs4_sops = { · 7 unmodified lines | ||
| 41 | 32 | .show_devname = nfs_show_devname, |
| 42 | 33 | .show_path = nfs_show_path, |
| 43 | 34 | .show_stats = nfs_show_stats, |
| 44 | − .remount_fs = nfs_remount, | |
| 45 | 35 | }; |
| 46 | 36 | |
| 47 | 37 | struct nfs_subversion nfs_v4 = { |
| @@ -147,102 +137,121 @@ static void nfs_referral_loop_unprotect(void) · 99 unmodified lines | ||
| 147 | 137 | kfree(p); |
| 148 | 138 | } |
| 149 | 139 | |
| 150 | −static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags, | |
| 151 | − struct nfs_mount_info *info, | |
| 152 | − const char *hostname, | |
| 153 | − const char *export_path) | |
| 140 | +static int do_nfs4_mount(struct nfs_server *server, | |
| 141 | + struct fs_context *fc, | |
| 142 | + const char *hostname, | |
| 143 | + const char *export_path) | |
| 154 | 144 | { |
| 145 | + struct nfs_fs_context *root_ctx; | |
| 146 | + struct fs_context *root_fc; | |
| 155 | 147 | struct vfsmount *root_mnt; |
| 156 | 148 | struct dentry *dentry; |
| 157 | − char *root_devname; | |
| 158 | − int err; | |
| 159 | 149 | size_t len; |
| 150 | + int ret; | |
| 151 | + | |
| 152 | + struct fs_parameter param = { | |
| 153 | + .key = "source", | |
| 154 | + .type = fs_value_is_string, | |
| 155 | + .dirfd = -1, | |
| 156 | + }; | |
| 160 | 157 | |
| 161 | 158 | if (IS_ERR(server)) |
| 162 | − return ERR_CAST(server); | |
| 159 | + return PTR_ERR(server); | |
| 163 | 160 | |
| 164 | − len = strlen(hostname) + 5; | |
| 165 | − root_devname = kmalloc(len, GFP_KERNEL); | |
| 166 | − if (root_devname == NULL) { | |
| 161 | + root_fc = vfs_dup_fs_context(fc); | |
| 162 | + if (IS_ERR(root_fc)) { | |
| 167 | 163 | nfs_free_server(server); |
| 168 | − return ERR_PTR(-ENOMEM); | |
| 164 | + return PTR_ERR(root_fc); | |
| 165 | + } | |
| 166 | + kfree(root_fc->source); | |
| 167 | + root_fc->source = NULL; | |
| 168 | + | |
| 169 | + root_ctx = nfs_fc2context(root_fc); | |
| 170 | + root_ctx->internal = true; | |
| 171 | + root_ctx->mount_info.server = server; | |
| 172 | + /* We leave export_path unset as it's not used to find the root. */ | |
| 173 | + | |
| 174 | + len = strlen(hostname) + 5; | |
| 175 | + param.string = kmalloc(len, GFP_KERNEL); | |
| 176 | + if (param.string == NULL) { | |
| 177 | + put_fs_context(root_fc); | |
| 178 | + return -ENOMEM; | |
| 169 | 179 | } |
| 170 | 180 | |
| 171 | 181 | /* Does hostname needs to be enclosed in brackets? */ |
| 172 | 182 | if (strchr(hostname, ':')) |
| 173 | − snprintf(root_devname, len, "[%s]:/", hostname); | |
| 183 | + param.size = snprintf(param.string, len, "[%s]:/", hostname); | |
| 174 | 184 | else |
| 175 | − snprintf(root_devname, len, "%s:/", hostname); | |
| 176 | − info->server = server; | |
| 177 | − root_mnt = vfs_kern_mount(&nfs_prepared_fs_type, flags, root_devname, info); | |
| 178 | − if (info->server) | |
| 179 | − nfs_free_server(info->server); | |
| 180 | − info->server = NULL; | |
| 181 | − kfree(root_devname); | |
| 185 | + param.size = snprintf(param.string, len, "%s:/", hostname); | |
| 186 | + ret = vfs_parse_fs_param(root_fc, ¶m); | |
| 187 | + kfree(param.string); | |
| 188 | + if (ret < 0) { | |
| 189 | + put_fs_context(root_fc); | |
| 190 | + return ret; | |
| 191 | + } | |
| 192 | + root_mnt = fc_mount(root_fc); | |
| 193 | + put_fs_context(root_fc); | |
| 182 | 194 | |
| 183 | 195 | if (IS_ERR(root_mnt)) |
| 184 | − return ERR_CAST(root_mnt); | |
| 196 | + return PTR_ERR(root_mnt); | |
| 185 | 197 | |
| 186 | − err = nfs_referral_loop_protect(); | |
| 187 | − if (err) { | |
| 198 | + ret = nfs_referral_loop_protect(); | |
| 199 | + if (ret) { | |
| 188 | 200 | mntput(root_mnt); |
| 189 | − return ERR_PTR(err); | |
| 201 | + return ret; | |
| 190 | 202 | } |
| 191 | 203 | |
| 192 | 204 | dentry = mount_subtree(root_mnt, export_path); |
| 193 | 205 | nfs_referral_loop_unprotect(); |
| 194 | 206 | |
| 195 | − return dentry; | |
| 207 | + if (IS_ERR(dentry)) | |
| 208 | + return PTR_ERR(dentry); | |
| 209 | + | |
| 210 | + fc->root = dentry; | |
| 211 | + return 0; | |
| 196 | 212 | } |
| 197 | 213 | |
| 198 | −struct dentry *nfs4_try_mount(int flags, const char *dev_name, | |
| 199 | − struct nfs_mount_info *mount_info) | |
| 214 | +int nfs4_try_get_tree(struct fs_context *fc) | |
| 200 | 215 | { |
| 201 | − struct nfs_fs_context *ctx = mount_info->ctx; | |
| 202 | − struct dentry *res; | |
| 203 | − | |
| 204 | − dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | |
| 216 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 217 | + int err; | |
| 205 | 218 | |
| 206 | − res = do_nfs4_mount(nfs4_create_server(mount_info), | |
| 207 | − flags, mount_info, | |
| 208 | − ctx->nfs_server.hostname, | |
| 209 | − ctx->nfs_server.export_path); | |
| 219 | + dfprintk(MOUNT, "--> nfs4_try_get_tree()\n"); | |
| 210 | 220 | |
| 211 | − dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", | |
| 212 | − PTR_ERR_OR_ZERO(res), | |
| 213 | − IS_ERR(res) ? " [error]" : ""); | |
| 214 | − return res; | |
| 221 | + /* We create a mount for the server's root, walk to the requested | |
| 222 | + * location and then create another mount for that. | |
| 223 | + */ | |
| 224 | + err= do_nfs4_mount(nfs4_create_server(&ctx->mount_info), | |
| 225 | + fc, ctx->nfs_server.hostname, | |
| 226 | + ctx->nfs_server.export_path); | |
| 227 | + if (err) { | |
| 228 | + dfprintk(MOUNT, "<-- nfs4_try_get_tree() = %d [error]\n", err); | |
| 229 | + } else { | |
| 230 | + dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n"); | |
| 231 | + } | |
| 232 | + return err; | |
| 215 | 233 | } |
| 216 | 234 | |
| 217 | 235 | /* |
| 218 | 236 | * Create an NFS4 server record on referral traversal |
| 219 | 237 | */ |
| 220 | −static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | |
| 221 | − int flags, const char *dev_name, void *raw_data) | |
| 238 | +int nfs4_get_referral_tree(struct fs_context *fc) | |
| 222 | 239 | { |
| 223 | − struct nfs_clone_mount *data = raw_data; | |
| 224 | − struct nfs_mount_info mount_info = { | |
| 225 | − .cloned = data, | |
| 226 | − .nfs_mod = &nfs_v4, | |
| 227 | − }; | |
| 228 | − struct dentry *res; | |
| 240 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 241 | + int err; | |
| 229 | 242 | |
| 230 | 243 | dprintk("--> nfs4_referral_mount()\n"); |
| 231 | 244 | |
| 232 | − mount_info.mntfh = nfs_alloc_fhandle(); | |
| 233 | − if (!mount_info.mntfh) | |
| 234 | − return ERR_PTR(-ENOMEM); | |
| 235 | − | |
| 236 | − res = do_nfs4_mount(nfs4_create_referral_server(mount_info.cloned, | |
| 237 | − mount_info.mntfh), | |
| 238 | − flags, &mount_info, data->hostname, data->mnt_path); | |
| 239 | − | |
| 240 | − dprintk("<-- nfs4_referral_mount() = %d%s\n", | |
| 241 | − PTR_ERR_OR_ZERO(res), | |
| 242 | − IS_ERR(res) ? " [error]" : ""); | |
| 243 | − | |
| 244 | − nfs_free_fhandle(mount_info.mntfh); | |
| 245 | − return res; | |
| 245 | + /* create a new volume representation */ | |
| 246 | + err = do_nfs4_mount(nfs4_create_referral_server(&ctx->clone_data, ctx->mount_info.mntfh), | |
| 247 | + fc, ctx->nfs_server.hostname, | |
| 248 | + ctx->nfs_server.export_path); | |
| 249 | + if (err) { | |
| 250 | + dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = %d [error]\n", err); | |
| 251 | + } else { | |
| 252 | + dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n"); | |
| 253 | + } | |
| 254 | + return err; | |
| 246 | 255 | } |
| 247 | 256 | |
| 248 | 257 | |
| @@ -710,7 +710,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = { · 709 unmodified lines | ||
| 710 | 710 | .file_ops = &nfs_file_operations, |
| 711 | 711 | .getroot = nfs_proc_get_root, |
| 712 | 712 | .submount = nfs_submount, |
| 713 | − .try_mount = nfs_try_mount, | |
| 713 | + .try_get_tree = nfs_try_get_tree, | |
| 714 | 714 | .getattr = nfs_proc_getattr, |
| 715 | 715 | .setattr = nfs_proc_setattr, |
| 716 | 716 | .lookup = nfs_proc_lookup, |
| @@ -70,28 +70,6 @@ · 69 unmodified lines | ||
| 70 | 70 | |
| 71 | 71 | #define NFSDBG_FACILITY NFSDBG_VFS |
| 72 | 72 | |
| 73 | −static struct dentry *nfs_prepared_mount(struct file_system_type *fs_type, | |
| 74 | − int flags, const char *dev_name, void *raw_data); | |
| 75 | − | |
| 76 | −struct file_system_type nfs_fs_type = { | |
| 77 | − .owner = THIS_MODULE, | |
| 78 | − .name = "nfs", | |
| 79 | − .mount = nfs_fs_mount, | |
| 80 | − .kill_sb = nfs_kill_super, | |
| 81 | − .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, | |
| 82 | −}; | |
| 83 | −MODULE_ALIAS_FS("nfs"); | |
| 84 | −EXPORT_SYMBOL_GPL(nfs_fs_type); | |
| 85 | − | |
| 86 | −struct file_system_type nfs_prepared_fs_type = { | |
| 87 | − .owner = THIS_MODULE, | |
| 88 | − .name = "nfs", | |
| 89 | − .mount = nfs_prepared_mount, | |
| 90 | − .kill_sb = nfs_kill_super, | |
| 91 | − .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, | |
| 92 | −}; | |
| 93 | −EXPORT_SYMBOL_GPL(nfs_prepared_fs_type); | |
| 94 | − | |
| 95 | 73 | const struct super_operations nfs_sops = { |
| 96 | 74 | .alloc_inode = nfs_alloc_inode, |
| 97 | 75 | .free_inode = nfs_free_inode, |
| @@ -104,22 +82,10 @@ const struct super_operations nfs_sops = { · 6 unmodified lines | ||
| 104 | 82 | .show_devname = nfs_show_devname, |
| 105 | 83 | .show_path = nfs_show_path, |
| 106 | 84 | .show_stats = nfs_show_stats, |
| 107 | − .remount_fs = nfs_remount, | |
| 108 | 85 | }; |
| 109 | 86 | EXPORT_SYMBOL_GPL(nfs_sops); |
| 110 | 87 | |
| 111 | 88 | #if IS_ENABLED(CONFIG_NFS_V4) |
| 112 | −struct file_system_type nfs4_fs_type = { | |
| 113 | − .owner = THIS_MODULE, | |
| 114 | − .name = "nfs4", | |
| 115 | − .mount = nfs_fs_mount, | |
| 116 | − .kill_sb = nfs_kill_super, | |
| 117 | − .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA, | |
| 118 | −}; | |
| 119 | −MODULE_ALIAS_FS("nfs4"); | |
| 120 | −MODULE_ALIAS("nfs4"); | |
| 121 | −EXPORT_SYMBOL_GPL(nfs4_fs_type); | |
| 122 | − | |
| 123 | 89 | static int __init register_nfs4_fs(void) |
| 124 | 90 | { |
| 125 | 91 | return register_filesystem(&nfs4_fs_type); |
| @@ -911,20 +877,19 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf · 785 unmodified lines | ||
| 911 | 877 | return nfs_mod->rpc_ops->create_server(mount_info); |
| 912 | 878 | } |
| 913 | 879 | |
| 914 | −static struct dentry *nfs_fs_mount_common(int, const char *, struct nfs_mount_info *); | |
| 915 | − | |
| 916 | −struct dentry *nfs_try_mount(int flags, const char *dev_name, | |
| 917 | − struct nfs_mount_info *mount_info) | |
| 880 | +int nfs_try_get_tree(struct fs_context *fc) | |
| 918 | 881 | { |
| 919 | − struct nfs_subversion *nfs_mod = mount_info->nfs_mod; | |
| 920 | − if (mount_info->ctx->need_mount) | |
| 921 | − mount_info->server = nfs_try_mount_request(mount_info); | |
| 882 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 883 | + | |
| 884 | + if (ctx->need_mount) | |
| 885 | + ctx->mount_info.server = nfs_try_mount_request(&ctx->mount_info); | |
| 922 | 886 | else |
| 923 | − mount_info->server = nfs_mod->rpc_ops->create_server(mount_info); | |
| 887 | + ctx->mount_info.server = ctx->mount_info.nfs_mod->rpc_ops->create_server(&ctx->mount_info); | |
| 924 | 888 | |
| 925 | − return nfs_fs_mount_common(flags, dev_name, mount_info); | |
| 889 | + return nfs_get_tree_common(fc); | |
| 926 | 890 | } |
| 927 | −EXPORT_SYMBOL_GPL(nfs_try_mount); | |
| 891 | +EXPORT_SYMBOL_GPL(nfs_try_get_tree); | |
| 892 | + | |
| 928 | 893 | |
| 929 | 894 | #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \ |
| 930 | 895 | | NFS_MOUNT_SECURE \ |
| @@ -965,15 +930,11 @@ nfs_compare_remount_data(struct nfs_server *nfss, · 34 unmodified lines | ||
| 965 | 930 | return 0; |
| 966 | 931 | } |
| 967 | 932 | |
| 968 | −int | |
| 969 | −nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |
| 933 | +int nfs_reconfigure(struct fs_context *fc) | |
| 970 | 934 | { |
| 971 | − int error; | |
| 935 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 936 | + struct super_block *sb = fc->root->d_sb; | |
| 972 | 937 | struct nfs_server *nfss = sb->s_fs_info; |
| 973 | − struct nfs_fs_context *ctx; | |
| 974 | − struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data; | |
| 975 | − struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data; | |
| 976 | − u32 nfsvers = nfss->nfs_client->rpc_ops->version; | |
| 977 | 938 | |
| 978 | 939 | sync_filesystem(sb); |
| 979 | 940 | |
| @@ -983,57 +944,24 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) · 3 unmodified lines | ||
| 983 | 944 | * ones were explicitly specified. Fall back to legacy behavior and |
| 984 | 945 | * just return success. |
| 985 | 946 | */ |
| 986 | − if ((nfsvers == 4 && (!options4 || options4->version == 1)) || | |
| 987 | − (nfsvers <= 3 && (!options || (options->version >= 1 && | |
| 988 | − options->version <= 6)))) | |
| 947 | + if (ctx->skip_reconfig_option_check) | |
| 989 | 948 | return 0; |
| 990 | 949 | |
| 991 | − ctx = nfs_alloc_parsed_mount_data(); | |
| 992 | − if (ctx == NULL) | |
| 993 | − return -ENOMEM; | |
| 994 | − | |
| 995 | − /* fill out struct with values from existing mount */ | |
| 996 | − ctx->flags = nfss->flags; | |
| 997 | − ctx->rsize = nfss->rsize; | |
| 998 | − ctx->wsize = nfss->wsize; | |
| 999 | − ctx->retrans = nfss->client->cl_timeout->to_retries; | |
| 1000 | − ctx->selected_flavor = nfss->client->cl_auth->au_flavor; | |
| 1001 | − ctx->acregmin = nfss->acregmin / HZ; | |
| 1002 | − ctx->acregmax = nfss->acregmax / HZ; | |
| 1003 | − ctx->acdirmin = nfss->acdirmin / HZ; | |
| 1004 | − ctx->acdirmax = nfss->acdirmax / HZ; | |
| 1005 | − ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ; | |
| 1006 | − ctx->nfs_server.port = nfss->port; | |
| 1007 | − ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen; | |
| 1008 | − ctx->version = nfsvers; | |
| 1009 | − ctx->minorversion = nfss->nfs_client->cl_minorversion; | |
| 1010 | − ctx->net = current->nsproxy->net_ns; | |
| 1011 | − memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr, | |
| 1012 | − ctx->nfs_server.addrlen); | |
| 1013 | − | |
| 1014 | − /* overwrite those values with any that were specified */ | |
| 1015 | − error = -EINVAL; | |
| 1016 | − if (!nfs_parse_mount_options((char *)options, ctx)) | |
| 1017 | − goto out; | |
| 1018 | − | |
| 1019 | 950 | /* |
| 1020 | 951 | * noac is a special case. It implies -o sync, but that's not |
| 1021 | − * necessarily reflected in the mtab options. do_remount_sb | |
| 952 | + * necessarily reflected in the mtab options. reconfigure_super | |
| 1022 | 953 | * will clear SB_SYNCHRONOUS if -o sync wasn't specified in the |
| 1023 | 954 | * remount options, so we have to explicitly reset it. |
| 1024 | 955 | */ |
| 1025 | − if (ctx->flags & NFS_MOUNT_NOAC) | |
| 1026 | − *flags |= SB_SYNCHRONOUS; | |
| 956 | + if (ctx->flags & NFS_MOUNT_NOAC) { | |
| 957 | + fc->sb_flags |= SB_SYNCHRONOUS; | |
| 958 | + fc->sb_flags_mask |= SB_SYNCHRONOUS; | |
| 959 | + } | |
| 1027 | 960 | |
| 1028 | 961 | /* compare new mount options with old ones */ |
| 1029 | − error = nfs_compare_remount_data(nfss, ctx); | |
| 1030 | − if (!error) | |
| 1031 | − error = security_sb_remount(sb, ctx->lsm_opts); | |
| 1032 | −out: | |
| 1033 | − nfs_free_parsed_mount_data(ctx); | |
| 1034 | − return error; | |
| 962 | + return nfs_compare_remount_data(nfss, ctx); | |
| 1035 | 963 | } |
| 1036 | −EXPORT_SYMBOL_GPL(nfs_remount); | |
| 964 | +EXPORT_SYMBOL_GPL(nfs_reconfigure); | |
| 1037 | 965 | |
| 1038 | 966 | /* |
| 1039 | 967 | * Finish setting up an NFS superblock |
| @@ -1112,19 +1040,11 @@ Ebusy: · 72 unmodified lines | ||
| 1112 | 1040 | return 0; |
| 1113 | 1041 | } |
| 1114 | 1042 | |
| 1115 | −struct nfs_sb_mountdata { | |
| 1116 | − struct nfs_server *server; | |
| 1117 | − int mntflags; | |
| 1118 | −}; | |
| 1119 | − | |
| 1120 | −static int nfs_set_super(struct super_block *s, void *data) | |
| 1043 | +static int nfs_set_super(struct super_block *s, struct fs_context *fc) | |
| 1121 | 1044 | { |
| 1122 | − struct nfs_sb_mountdata *sb_mntdata = data; | |
| 1123 | − struct nfs_server *server = sb_mntdata->server; | |
| 1045 | + struct nfs_server *server = fc->s_fs_info; | |
| 1124 | 1046 | int ret; |
| 1125 | 1047 | |
| 1126 | − s->s_flags = sb_mntdata->mntflags; | |
| 1127 | − s->s_fs_info = server; | |
| 1128 | 1048 | s->s_d_op = server->nfs_client->rpc_ops->dentry_ops; |
| 1129 | 1049 | ret = set_anon_super(s, server); |
| 1130 | 1050 | if (ret == 0) |
| @@ -1189,11 +1109,9 @@ static int nfs_compare_userns(const struct nfs_server *old, · 58 unmodified lines | ||
| 1189 | 1109 | return 1; |
| 1190 | 1110 | } |
| 1191 | 1111 | |
| 1192 | −static int nfs_compare_super(struct super_block *sb, void *data) | |
| 1112 | +static int nfs_compare_super(struct super_block *sb, struct fs_context *fc) | |
| 1193 | 1113 | { |
| 1194 | − struct nfs_sb_mountdata *sb_mntdata = data; | |
| 1195 | − struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); | |
| 1196 | − int mntflags = sb_mntdata->mntflags; | |
| 1114 | + struct nfs_server *server = fc->s_fs_info, *old = NFS_SB(sb); | |
| 1197 | 1115 | |
| 1198 | 1116 | if (!nfs_compare_super_address(old, server)) |
| 1199 | 1117 | return 0; |
| @@ -1204,13 +1122,12 @@ static int nfs_compare_super(struct super_block *sb, void *data) · 4 unmodified lines | ||
| 1204 | 1122 | return 0; |
| 1205 | 1123 | if (!nfs_compare_userns(old, server)) |
| 1206 | 1124 | return 0; |
| 1207 | − return nfs_compare_mount_options(sb, server, mntflags); | |
| 1125 | + return nfs_compare_mount_options(sb, server, fc->sb_flags); | |
| 1208 | 1126 | } |
| 1209 | 1127 | |
| 1210 | 1128 | #ifdef CONFIG_NFS_FSCACHE |
| 1211 | 1129 | static void nfs_get_cache_cookie(struct super_block *sb, |
| 1212 | − struct nfs_fs_context *ctx, | |
| 1213 | − struct nfs_clone_mount *cloned) | |
| 1130 | + struct nfs_fs_context *ctx) | |
| 1214 | 1131 | { |
| 1215 | 1132 | struct nfs_server *nfss = NFS_SB(sb); |
| 1216 | 1133 | char *uniq = NULL; |
| @@ -1219,30 +1136,32 @@ static void nfs_get_cache_cookie(struct super_block *sb, · 2 unmodified lines | ||
| 1219 | 1136 | nfss->fscache_key = NULL; |
| 1220 | 1137 | nfss->fscache = NULL; |
| 1221 | 1138 | |
| 1222 | − if (ctx) { | |
| 1223 | − if (!(ctx->options & NFS_OPTION_FSCACHE)) | |
| 1224 | − return; | |
| 1225 | − if (ctx->fscache_uniq) { | |
| 1226 | − uniq = ctx->fscache_uniq; | |
| 1227 | − ulen = strlen(ctx->fscache_uniq); | |
| 1228 | − } | |
| 1229 | − } else if (cloned) { | |
| 1230 | − struct nfs_server *mnt_s = NFS_SB(cloned->sb); | |
| 1139 | + if (!ctx) | |
| 1140 | + return; | |
| 1141 | + | |
| 1142 | + if (ctx->clone_data.sb) { | |
| 1143 | + struct nfs_server *mnt_s = NFS_SB(ctx->clone_data.sb); | |
| 1231 | 1144 | if (!(mnt_s->options & NFS_OPTION_FSCACHE)) |
| 1232 | 1145 | return; |
| 1233 | 1146 | if (mnt_s->fscache_key) { |
| 1234 | 1147 | uniq = mnt_s->fscache_key->key.uniquifier; |
| 1235 | 1148 | ulen = mnt_s->fscache_key->key.uniq_len; |
| 1236 | 1149 | } |
| 1237 | − } else | |
| 1150 | + } else { | |
| 1151 | + if (!(ctx->options & NFS_OPTION_FSCACHE)) | |
| 1152 | + return; | |
| 1153 | + if (ctx->fscache_uniq) { | |
| 1154 | + uniq = ctx->fscache_uniq; | |
| 1155 | + ulen = strlen(ctx->fscache_uniq); | |
| 1156 | + } | |
| 1238 | 1157 | return; |
| 1158 | + } | |
| 1239 | 1159 | |
| 1240 | 1160 | nfs_fscache_get_super_cookie(sb, uniq, ulen); |
| 1241 | 1161 | } |
| 1242 | 1162 | #else |
| 1243 | 1163 | static void nfs_get_cache_cookie(struct super_block *sb, |
| 1244 | − struct nfs_fs_context *parsed, | |
| 1245 | − struct nfs_clone_mount *cloned) | |
| 1164 | + struct nfs_fs_context *ctx) | |
| 1246 | 1165 | { |
| 1247 | 1166 | } |
| 1248 | 1167 | #endif |
| @@ -1254,40 +1173,41 @@ static void nfs_set_readahead(struct backing_dev_info *bdi, · 5 unmodified lines | ||
| 1254 | 1173 | bdi->io_pages = iomax_pages; |
| 1255 | 1174 | } |
| 1256 | 1175 | |
| 1257 | −static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name, | |
| 1258 | − struct nfs_mount_info *mount_info) | |
| 1176 | +int nfs_get_tree_common(struct fs_context *fc) | |
| 1259 | 1177 | { |
| 1178 | + struct nfs_fs_context *ctx = nfs_fc2context(fc); | |
| 1260 | 1179 | struct super_block *s; |
| 1261 | 1180 | struct dentry *mntroot = ERR_PTR(-ENOMEM); |
| 1262 | − int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | |
| 1263 | − struct nfs_server *server = mount_info->server; | |
| 1181 | + int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super; | |
| 1182 | + struct nfs_server *server = ctx->mount_info.server; | |
| 1264 | 1183 | unsigned long kflags = 0, kflags_out = 0; |
| 1265 | − struct nfs_sb_mountdata sb_mntdata = { | |
| 1266 | − .mntflags = flags, | |
| 1267 | − .server = server, | |
| 1268 | − }; | |
| 1269 | 1184 | int error; |
| 1270 | 1185 | |
| 1271 | − mount_info->server = NULL; | |
| 1186 | + ctx->mount_info.server = NULL; | |
| 1272 | 1187 | if (IS_ERR(server)) |
| 1273 | − return ERR_CAST(server); | |
| 1188 | + return PTR_ERR(server); | |
| 1274 | 1189 | |
| 1275 | 1190 | if (server->flags & NFS_MOUNT_UNSHARED) |
| 1276 | 1191 | compare_super = NULL; |
| 1277 | 1192 | |
| 1278 | 1193 | /* -o noac implies -o sync */ |
| 1279 | 1194 | if (server->flags & NFS_MOUNT_NOAC) |
| 1280 | − sb_mntdata.mntflags |= SB_SYNCHRONOUS; | |
| 1195 | + fc->sb_flags |= SB_SYNCHRONOUS; | |
| 1196 | + | |
| 1197 | + if (ctx->clone_data.sb) | |
| 1198 | + if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS) | |
| 1199 | + fc->sb_flags |= SB_SYNCHRONOUS; | |
| 1281 | 1200 | |
| 1282 | − if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL) | |
| 1283 | − if (mount_info->cloned->sb->s_flags & SB_SYNCHRONOUS) | |
| 1284 | − sb_mntdata.mntflags |= SB_SYNCHRONOUS; | |
| 1201 | + if (server->caps & NFS_CAP_SECURITY_LABEL) | |
| 1202 | + fc->lsm_flags |= SECURITY_LSM_NATIVE_LABELS; | |
| 1285 | 1203 | |
| 1286 | 1204 | /* Get a superblock - note that we may end up sharing one that already exists */ |
| 1287 | − s = sget(mount_info->nfs_mod->nfs_fs, compare_super, nfs_set_super, | |
| 1288 | − flags, &sb_mntdata); | |
| 1205 | + fc->s_fs_info = server; | |
| 1206 | + s = sget_fc(fc, compare_super, nfs_set_super); | |
| 1207 | + fc->s_fs_info = NULL; | |
| 1289 | 1208 | if (IS_ERR(s)) { |
| 1290 | − mntroot = ERR_CAST(s); | |
| 1209 | + error = PTR_ERR(s); | |
| 1210 | + dfprintk(MOUNT, "NFS: Couldn't get superblock\n"); | |
| 1291 | 1211 | goto out_err_nosb; |
| 1292 | 1212 | } |
| 1293 | 1213 | |
| @@ -1297,44 +1217,43 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name, · 3 unmodified lines | ||
| 1297 | 1217 | } else { |
| 1298 | 1218 | error = super_setup_bdi_name(s, "%u:%u", MAJOR(server->s_dev), |
| 1299 | 1219 | MINOR(server->s_dev)); |
| 1300 | − if (error) { | |
| 1301 | − mntroot = ERR_PTR(error); | |
| 1220 | + if (error) | |
| 1302 | 1221 | goto error_splat_super; |
| 1303 | − } | |
| 1304 | 1222 | nfs_set_readahead(s->s_bdi, server->rpages); |
| 1305 | 1223 | server->super = s; |
| 1306 | 1224 | } |
| 1307 | 1225 | |
| 1308 | 1226 | if (!s->s_root) { |
| 1309 | − unsigned bsize = mount_info->inherited_bsize; | |
| 1227 | + unsigned bsize = ctx->mount_info.inherited_bsize; | |
| 1310 | 1228 | /* initial superblock/root creation */ |
| 1311 | − nfs_fill_super(s, mount_info); | |
| 1229 | + nfs_fill_super(s, &ctx->mount_info); | |
| 1312 | 1230 | if (bsize) { |
| 1313 | 1231 | s->s_blocksize_bits = bsize; |
| 1314 | 1232 | s->s_blocksize = 1U << bsize; |
| 1315 | 1233 | } |
| 1316 | − nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned); | |
| 1317 | − if (!(server->flags & NFS_MOUNT_UNSHARED)) | |
| 1318 | − s->s_iflags |= SB_I_MULTIROOT; | |
| 1234 | + nfs_get_cache_cookie(s, ctx); | |
| 1319 | 1235 | } |
| 1320 | 1236 | |
| 1321 | − mntroot = nfs_get_root(s, mount_info->mntfh, dev_name); | |
| 1322 | − if (IS_ERR(mntroot)) | |
| 1237 | + mntroot = nfs_get_root(s, ctx->mount_info.mntfh, fc->source); | |
| 1238 | + if (IS_ERR(mntroot)) { | |
| 1239 | + error = PTR_ERR(mntroot); | |
| 1240 | + dfprintk(MOUNT, "NFS: Couldn't get root dentry\n"); | |
| 1323 | 1241 | goto error_splat_super; |
| 1324 | − | |
| 1242 | + } | |
| 1243 | + fc->root = mntroot; | |
| 1325 | 1244 | |
| 1326 | 1245 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) |
| 1327 | 1246 | kflags |= SECURITY_LSM_NATIVE_LABELS; |
| 1328 | − if (mount_info->cloned) { | |
| 1329 | − if (d_inode(mntroot)->i_fop != &nfs_dir_operations) { | |
| 1247 | + if (ctx->clone_data.sb) { | |
| 1248 | + if (d_inode(fc->root)->i_fop != &nfs_dir_operations) { | |
| 1330 | 1249 | error = -ESTALE; |
| 1331 | 1250 | goto error_splat_root; |
| 1332 | 1251 | } |
| 1333 | 1252 | /* clone any lsm security options from the parent to the new sb */ |
| 1334 | − error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags, | |
| 1253 | + error = security_sb_clone_mnt_opts(ctx->clone_data.sb, s, kflags, | |
| 1335 | 1254 | &kflags_out); |
| 1336 | 1255 | } else { |
| 1337 | − error = security_sb_set_mnt_opts(s, mount_info->ctx->lsm_opts, | |
| 1256 | + error = security_sb_set_mnt_opts(s, fc->security, | |
| 1338 | 1257 | kflags, &kflags_out); |
| 1339 | 1258 | } |
| 1340 | 1259 | if (error) |
| @@ -1342,67 +1261,25 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name, · 1 unmodified line | ||
| 1342 | 1261 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && |
| 1343 | 1262 | !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) |
| 1344 | 1263 | NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; |
| 1345 | − if (error) | |
| 1346 | − goto error_splat_root; | |
| 1347 | 1264 | |
| 1348 | 1265 | s->s_flags |= SB_ACTIVE; |
| 1266 | + error = 0; | |
| 1349 | 1267 | |
| 1350 | 1268 | out: |
| 1351 | − return mntroot; | |
| 1269 | + return error; | |
| 1352 | 1270 | |
| 1353 | 1271 | out_err_nosb: |
| 1354 | 1272 | nfs_free_server(server); |
| 1355 | 1273 | goto out; |
| 1356 | 1274 | |
| 1357 | 1275 | error_splat_root: |
| 1358 | − dput(mntroot); | |
| 1359 | − mntroot = ERR_PTR(error); | |
| 1276 | + dput(fc->root); | |
| 1277 | + fc->root = NULL; | |
| 1360 | 1278 | error_splat_super: |
| 1361 | 1279 | deactivate_locked_super(s); |
| 1362 | 1280 | goto out; |
| 1363 | 1281 | } |
| 1364 | 1282 | |
| 1365 | −struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | |
| 1366 | − int flags, const char *dev_name, void *raw_data) | |
| 1367 | −{ | |
| 1368 | − struct nfs_mount_info mount_info = { | |
| 1369 | − }; | |
| 1370 | − struct dentry *mntroot = ERR_PTR(-ENOMEM); | |
| 1371 | − struct nfs_subversion *nfs_mod; | |
| 1372 | − int error; | |
| 1373 | − | |
| 1374 | − mount_info.ctx = nfs_alloc_parsed_mount_data(); | |
| 1375 | − mount_info.mntfh = nfs_alloc_fhandle(); | |
| 1376 | − if (mount_info.ctx == NULL || mount_info.mntfh == NULL) | |
| 1377 | − goto out; | |
| 1378 | − | |
| 1379 | − /* Validate the mount data */ | |
| 1380 | − error = nfs_validate_mount_data(fs_type, raw_data, mount_info.ctx, mount_info.mntfh, dev_name); | |
| 1381 | − if (error == NFS_TEXT_DATA) | |
| 1382 | − error = nfs_validate_text_mount_data(raw_data, | |
| 1383 | − mount_info.ctx, dev_name); | |
| 1384 | − if (error < 0) { | |
| 1385 | − mntroot = ERR_PTR(error); | |
| 1386 | − goto out; | |
| 1387 | − } | |
| 1388 | − | |
| 1389 | − nfs_mod = get_nfs_version(mount_info.ctx->version); | |
| 1390 | − if (IS_ERR(nfs_mod)) { | |
| 1391 | − mntroot = ERR_CAST(nfs_mod); | |
| 1392 | − goto out; | |
| 1393 | − } | |
| 1394 | − mount_info.nfs_mod = nfs_mod; | |
| 1395 | − | |
| 1396 | − mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info); | |
| 1397 | − | |
| 1398 | − put_nfs_version(nfs_mod); | |
| 1399 | −out: | |
| 1400 | − nfs_free_parsed_mount_data(mount_info.ctx); | |
| 1401 | − nfs_free_fhandle(mount_info.mntfh); | |
| 1402 | − return mntroot; | |
| 1403 | −} | |
| 1404 | −EXPORT_SYMBOL_GPL(nfs_fs_mount); | |
| 1405 | − | |
| 1406 | 1283 | /* |
| 1407 | 1284 | * Destroy an NFS2/3 superblock |
| 1408 | 1285 | */ |
| @@ -1420,17 +1297,6 @@ void nfs_kill_super(struct super_block *s) · 11 unmodified lines | ||
| 1420 | 1297 | } |
| 1421 | 1298 | EXPORT_SYMBOL_GPL(nfs_kill_super); |
| 1422 | 1299 | |
| 1423 | −/* | |
| 1424 | − * Internal use only: mount_info is already set up by caller. | |
| 1425 | − * Used for mountpoint crossings and for nfs4 root. | |
| 1426 | − */ | |
| 1427 | −static struct dentry * | |
| 1428 | −nfs_prepared_mount(struct file_system_type *fs_type, int flags, | |
| 1429 | − const char *dev_name, void *raw_data) | |
| 1430 | −{ | |
| 1431 | − return nfs_fs_mount_common(flags, dev_name, raw_data); | |
| 1432 | −} | |
| 1433 | − | |
| 1434 | 1300 | #if IS_ENABLED(CONFIG_NFS_V4) |
| 1435 | 1301 | |
| 1436 | 1302 | /* |
| @@ -1639,6 +1639,7 @@ struct nfs_subversion; · 1638 unmodified lines | ||
| 1639 | 1639 | struct nfs_mount_info; |
| 1640 | 1640 | struct nfs_client_initdata; |
| 1641 | 1641 | struct nfs_pageio_descriptor; |
| 1642 | +struct fs_context; | |
| 1642 | 1643 | |
| 1643 | 1644 | /* |
| 1644 | 1645 | * RPC procedure vector for NFSv2/NFSv3 demuxing |
| @@ -1653,9 +1654,8 @@ struct nfs_rpc_ops { · 8 unmodified lines | ||
| 1653 | 1654 | |
| 1654 | 1655 | int (*getroot) (struct nfs_server *, struct nfs_fh *, |
| 1655 | 1656 | struct nfs_fsinfo *); |
| 1656 | − struct vfsmount *(*submount) (struct nfs_server *, struct dentry *, | |
| 1657 | − struct nfs_fh *, struct nfs_fattr *); | |
| 1658 | − struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *); | |
| 1657 | + int (*submount) (struct fs_context *, struct nfs_server *); | |
| 1658 | + int (*try_get_tree) (struct fs_context *); | |
| 1659 | 1659 | int (*getattr) (struct nfs_server *, struct nfs_fh *, |
| 1660 | 1660 | struct nfs_fattr *, struct nfs4_label *, |
| 1661 | 1661 | struct inode *); |