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 | * linux/fs/nfs/fs_context.c | 3 | * linux/fs/nfs/fs_context.c |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 1992 Rick Sladkey | 5 | * Copyright (C) 1992 Rick Sladkey |
| 6 | * Conversion to new mount api Copyright (C) David Howells | ||
| 6 | * | 7 | * |
| 7 | * NFS mount handling. | 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 | * Parse a single mount parameter. | 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 | struct fs_parameter *param) | 472 | struct fs_parameter *param) |
| 472 | { | 473 | { |
| 473 | struct fs_parse_result result; | 474 | struct fs_parse_result result; |
| 475 | struct nfs_fs_context *ctx = nfs_fc2context(fc); | ||
| 474 | unsigned short protofamily, mountfamily; | 476 | unsigned short protofamily, mountfamily; |
| 475 | unsigned int len; | 477 | unsigned int len; |
| 476 | int ret, opt; | 478 | int ret, opt; |
| 477 | 479 | ||
| 478 | dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", param->key); | 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 | if (opt < 0) | 483 | if (opt < 0) |
| 482 | return ctx->sloppy ? 1 : opt; | 484 | return ctx->sloppy ? 1 : opt; |
| 483 | 485 | ||
| 484 | switch (opt) { | 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 | * boolean options: foo/nofoo | 497 | * boolean options: foo/nofoo |
| 487 | */ | 498 | */ |
| @@ -807,112 +818,6 @@ out_of_bounds: · 319 unmodified lines | |||
| 807 | return -ERANGE; | 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 | * Split "dev_name" into "hostname:export_path". | 822 | * Split "dev_name" into "hostname:export_path". |
| 918 | * | 823 | * |
| @@ -990,6 +895,11 @@ out_path: · 71 unmodified lines | |||
| 990 | return -ENAMETOOLONG; | 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 | * Parse monolithic NFS2/NFS3 mount data | 904 | * Parse monolithic NFS2/NFS3 mount data |
| 995 | * - fills in the mount root filehandle | 905 | * - fills in the mount root filehandle |
| @@ -1006,12 +916,11 @@ out_path: · 10 unmodified lines | |||
| 1006 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, | 916 | * + breaking back: trying proto=udp after proto=tcp, v2 after v3, |
| 1007 | * mountproto=tcp after mountproto=udp, and so on | 917 | * mountproto=tcp after mountproto=udp, and so on |
| 1008 | */ | 918 | */ |
| 1009 | static int nfs23_validate_mount_data(void *options, | 919 | static int nfs23_parse_monolithic(struct fs_context *fc, |
| 1010 | struct nfs_fs_context *ctx, | 920 | struct nfs_mount_data *data) |
| 1011 | struct nfs_fh *mntfh, | ||
| 1012 | const char *dev_name) | ||
| 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 | struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; | 924 | struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; |
| 1016 | int extra_flags = NFS_MOUNT_LEGACY_INTERFACE; | 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 | ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 992 | ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
| 1084 | /* N.B. caller will free nfs_server.hostname in all cases */ | 993 | /* N.B. caller will free nfs_server.hostname in all cases */ |
| 1085 | ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); | 994 | ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); |
| 995 | if (!ctx->nfs_server.hostname) | ||
| 996 | goto out_nomem; | ||
| 997 | |||
| 1086 | ctx->namlen = data->namlen; | 998 | ctx->namlen = data->namlen; |
| 1087 | ctx->bsize = data->bsize; | 999 | ctx->bsize = data->bsize; |
| 1088 | 1000 | ||
| @@ -1090,8 +1002,6 @@ static int nfs23_validate_mount_data(void *options, · 1 unmodified line | |||
| 1090 | ctx->selected_flavor = data->pseudoflavor; | 1002 | ctx->selected_flavor = data->pseudoflavor; |
| 1091 | else | 1003 | else |
| 1092 | ctx->selected_flavor = RPC_AUTH_UNIX; | 1004 | ctx->selected_flavor = RPC_AUTH_UNIX; |
| 1093 | if (!ctx->nfs_server.hostname) | ||
| 1094 | goto out_nomem; | ||
| 1095 | 1005 | ||
| 1096 | if (!(data->flags & NFS_MOUNT_NONLM)) | 1006 | if (!(data->flags & NFS_MOUNT_NONLM)) |
| 1097 | ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK| | 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 | if (data->context[0]){ | 1020 | if (data->context[0]){ |
| 1111 | #ifdef CONFIG_SECURITY_SELINUX | 1021 | #ifdef CONFIG_SECURITY_SELINUX |
| 1112 | int rc; | 1022 | int ret; |
| 1023 | |||
| 1113 | data->context[NFS_MAX_CONTEXT_LEN] = '\0'; | 1024 | data->context[NFS_MAX_CONTEXT_LEN] = '\0'; |
| 1114 | rc = security_add_mnt_opt("context", data->context, | 1025 | ret = vfs_parse_fs_string(fc, "context", |
| 1115 | strlen(data->context), ctx->lsm_opts); | 1026 | data->context, strlen(data->context)); |
| 1116 | if (rc) | 1027 | if (ret < 0) |
| 1117 | return rc; | 1028 | return ret; |
| 1118 | #else | 1029 | #else |
| 1119 | return -EINVAL; | 1030 | return -EINVAL; |
| 1120 | #endif | 1031 | #endif |
| @@ -1122,12 +1033,20 @@ static int nfs23_validate_mount_data(void *options, · 1 unmodified line | |||
| 1122 | 1033 | ||
| 1123 | break; | 1034 | break; |
| 1124 | default: | 1035 | default: |
| 1125 | return NFS_TEXT_DATA; | 1036 | goto generic; |
| 1126 | } | 1037 | } |
| 1127 | 1038 | ||
| 1039 | ctx->skip_reconfig_option_check = true; | ||
| 1128 | return 0; | 1040 | return 0; |
| 1129 | 1041 | ||
| 1042 | generic: | ||
| 1043 | return generic_parse_monolithic(fc, data); | ||
| 1044 | |||
| 1130 | out_no_data: | 1045 | out_no_data: |
| 1046 | if (is_remount_fc(fc)) { | ||
| 1047 | ctx->skip_reconfig_option_check = true; | ||
| 1048 | return 0; | ||
| 1049 | } | ||
| 1131 | dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n"); | 1050 | dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n"); |
| 1132 | return -EINVAL; | 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 | * Validate NFSv4 mount options | 1083 | * Validate NFSv4 mount options |
| 1165 | */ | 1084 | */ |
| 1166 | static int nfs4_validate_mount_data(void *options, | 1085 | static int nfs4_parse_monolithic(struct fs_context *fc, |
| 1167 | struct nfs_fs_context *ctx, | 1086 | struct nfs4_mount_data *data) |
| 1168 | const char *dev_name) | ||
| 1169 | { | 1087 | { |
| 1088 | struct nfs_fs_context *ctx = nfs_fc2context(fc); | ||
| 1170 | struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; | 1089 | struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address; |
| 1171 | struct nfs4_mount_data *data = (struct nfs4_mount_data *)options; | ||
| 1172 | char *c; | 1090 | char *c; |
| 1173 | 1091 | ||
| 1174 | if (data == NULL) | 1092 | if (data == NULL) |
| @@ -1218,7 +1136,7 @@ static int nfs4_validate_mount_data(void *options, · 43 unmodified lines | |||
| 1218 | ctx->client_address = c; | 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 | * can deal with. | 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 | break; | 1157 | break; |
| 1240 | default: | 1158 | default: |
| 1241 | return NFS_TEXT_DATA; | 1159 | goto generic; |
| 1242 | } | 1160 | } |
| 1243 | 1161 | ||
| 1162 | ctx->skip_reconfig_option_check = true; | ||
| 1244 | return 0; | 1163 | return 0; |
| 1245 | 1164 | ||
| 1165 | generic: | ||
| 1166 | return generic_parse_monolithic(fc, data); | ||
| 1167 | |||
| 1246 | out_no_data: | 1168 | out_no_data: |
| 1169 | if (is_remount_fc(fc)) { | ||
| 1170 | ctx->skip_reconfig_option_check = true; | ||
| 1171 | return 0; | ||
| 1172 | } | ||
| 1247 | dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n"); | 1173 | dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n"); |
| 1248 | return -EINVAL; | 1174 | return -EINVAL; |
| 1249 | 1175 | ||
| @@ -1260,39 +1186,66 @@ out_invalid_transport_udp: · 10 unmodified lines | |||
| 1260 | dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n"); | 1186 | dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n"); |
| 1261 | return -EINVAL; | 1187 | return -EINVAL; |
| 1262 | } | 1188 | } |
| 1189 | #endif | ||
| 1263 | 1190 | ||
| 1264 | int nfs_validate_mount_data(struct file_system_type *fs_type, | 1191 | /* |
| 1265 | void *options, | 1192 | * Parse a monolithic block of data from sys_mount(). |
| 1266 | struct nfs_fs_context *ctx, | 1193 | */ |
| 1267 | struct nfs_fh *mntfh, | 1194 | static int nfs_fs_context_parse_monolithic(struct fs_context *fc, |
| 1268 | const char *dev_name) | 1195 | void *data) |
| 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) | ||
| 1280 | { | 1196 | { |
| 1281 | return nfs23_validate_mount_data(options, ctx, mntfh, dev_name); | 1197 | if (fc->fs_type == &nfs_fs_type) |
| 1282 | } | 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 | #endif | 1203 | #endif |
| 1284 | 1204 | ||
| 1285 | int nfs_validate_text_mount_data(void *options, | 1205 | dfprintk(MOUNT, "NFS: Unsupported monolithic data version\n"); |
| 1286 | struct nfs_fs_context *ctx, | 1206 | return -EINVAL; |
| 1287 | const char *dev_name) | 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 | int max_namelen = PAGE_SIZE; | 1217 | int max_namelen = PAGE_SIZE; |
| 1291 | int max_pathlen = NFS_MAXPATHLEN; | 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) | 1222 | if (!fc->source) |
| 1295 | return -EINVAL; | 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 | if (!nfs_verify_server_address(sap)) | 1250 | if (!nfs_verify_server_address(sap)) |
| 1298 | goto out_no_address; | 1251 | goto out_no_address; |
| @@ -1320,8 +1273,24 @@ int nfs_validate_text_mount_data(void *options, · 21 unmodified lines | |||
| 1320 | 1273 | ||
| 1321 | nfs_set_port(sap, &ctx->nfs_server.port, port); | 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 | #if !IS_ENABLED(CONFIG_NFS_V4) | 1294 | #if !IS_ENABLED(CONFIG_NFS_V4) |
| 1326 | out_v4_not_compiled: | 1295 | out_v4_not_compiled: |
| 1327 | dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); | 1296 | dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n"); |
| @@ -1331,8 +1300,201 @@ out_invalid_transport_udp: · 3 unmodified lines | |||
| 1331 | dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n"); | 1300 | dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n"); |
| 1332 | return -EINVAL; | 1301 | return -EINVAL; |
| 1333 | #endif /* !CONFIG_NFS_V4 */ | 1302 | #endif /* !CONFIG_NFS_V4 */ |
| 1334 | |||
| 1335 | out_no_address: | 1303 | out_no_address: |
| 1336 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); | 1304 | dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); |
| 1337 | return -EINVAL; | 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 | #include "nfs4_fs.h" | 6 | #include "nfs4_fs.h" |
| 7 | #include <linux/mount.h> | 7 | #include <linux/fs_context.h> |
| 8 | #include <linux/security.h> | 8 | #include <linux/security.h> |
| 9 | #include <linux/crc32.h> | 9 | #include <linux/crc32.h> |
| 10 | #include <linux/sunrpc/addr.h> | 10 | #include <linux/sunrpc/addr.h> |
| @@ -16,6 +16,7 @@ · 5 unmodified lines | |||
| 16 | extern const struct export_operations nfs_export_ops; | 16 | extern const struct export_operations nfs_export_ops; |
| 17 | 17 | ||
| 18 | struct nfs_string; | 18 | struct nfs_string; |
| 19 | struct nfs_pageio_descriptor; | ||
| 19 | 20 | ||
| 20 | static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr) | 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 | struct nfs_clone_mount { | 36 | struct nfs_clone_mount { |
| 36 | const struct super_block *sb; | 37 | const struct super_block *sb; |
| 37 | const struct dentry *dentry; | 38 | struct dentry *dentry; |
| 38 | char *hostname; | 39 | char *hostname; |
| 39 | char *mnt_path; | 40 | char *mnt_path; |
| 40 | struct sockaddr *addr; | 41 | struct sockaddr *addr; |
| 41 | size_t addrlen; | 42 | size_t addrlen; |
| 42 | rpc_authflavor_t authflavor; | 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 | const struct cred *cred; | 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 | * In-kernel mount arguments | 93 | * In-kernel mount arguments |
| 83 | */ | 94 | */ |
| 84 | struct nfs_fs_context { | 95 | struct nfs_fs_context { |
| 96 | bool internal; | ||
| 97 | bool skip_reconfig_option_check; | ||
| 98 | bool need_mount; | ||
| 99 | bool sloppy; | ||
| 85 | unsigned int flags; /* NFS{,4}_MOUNT_* flags */ | 100 | unsigned int flags; /* NFS{,4}_MOUNT_* flags */ |
| 86 | unsigned int rsize, wsize; | 101 | unsigned int rsize, wsize; |
| 87 | unsigned int timeo, retrans; | 102 | unsigned int timeo, retrans; |
| @@ -98,8 +113,6 @@ struct nfs_fs_context { · 10 unmodified lines | |||
| 98 | char *fscache_uniq; | 113 | char *fscache_uniq; |
| 99 | unsigned short protofamily; | 114 | unsigned short protofamily; |
| 100 | unsigned short mountfamily; | 115 | unsigned short mountfamily; |
| 101 | bool need_mount; | ||
| 102 | bool sloppy; | ||
| 103 | 116 | ||
| 104 | struct { | 117 | struct { |
| 105 | union { | 118 | union { |
| @@ -124,14 +137,23 @@ struct nfs_fs_context { · 18 unmodified lines | |||
| 124 | int port; | 137 | int port; |
| 125 | unsigned short protocol; | 138 | unsigned short protocol; |
| 126 | unsigned short nconnect; | 139 | unsigned short nconnect; |
| 140 | unsigned short export_path_len; | ||
| 127 | } nfs_server; | 141 | } nfs_server; |
| 128 | 142 | ||
| 129 | void *lsm_opts; | 143 | void *lsm_opts; |
| 130 | struct net *net; | 144 | struct net *net; |
| 131 | 145 | ||
| 132 | char buf[32]; /* Parse buffer */ | 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 | /* mount_clnt.c */ | 157 | /* mount_clnt.c */ |
| 136 | struct nfs_mount_request { | 158 | struct nfs_mount_request { |
| 137 | struct sockaddr *sap; | 159 | struct sockaddr *sap; |
| @@ -147,15 +169,6 @@ struct nfs_mount_request { · 9 unmodified lines | |||
| 147 | struct net *net; | 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 | extern int nfs_mount(struct nfs_mount_request *info); | 172 | extern int nfs_mount(struct nfs_mount_request *info); |
| 160 | extern void nfs_umount(const struct nfs_mount_request *info); | 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 | extern const struct svc_version nfs4_callback_version1; | 248 | extern const struct svc_version nfs4_callback_version1; |
| 236 | extern const struct svc_version nfs4_callback_version4; | 249 | extern const struct svc_version nfs4_callback_version4; |
| 237 | 250 | ||
| 238 | struct nfs_pageio_descriptor; | 251 | /* fs_context.c */ |
| 239 | 252 | extern struct file_system_type nfs_fs_type; | |
| 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); | ||
| 254 | 253 | ||
| 255 | /* pagelist.c */ | 254 | /* pagelist.c */ |
| 256 | extern int __init nfs_init_nfspagecache(void); | 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 | /* super.c */ | 411 | /* super.c */ |
| 413 | extern const struct super_operations nfs_sops; | 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 | bool nfs_auth_info_match(const struct nfs_auth_info *, rpc_authflavor_t); | 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 *); | 414 | int nfs_try_get_tree(struct fs_context *); |
| 421 | struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); | 415 | int nfs_get_tree_common(struct fs_context *); |
| 422 | void nfs_kill_super(struct super_block *); | 416 | void nfs_kill_super(struct super_block *); |
| 423 | 417 | ||
| 424 | extern struct rpc_stat nfs_rpcstat; | 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 | extern char *nfs_path(char **p, struct dentry *dentry, | 440 | extern char *nfs_path(char **p, struct dentry *dentry, |
| 447 | char *buffer, ssize_t buflen, unsigned flags); | 441 | char *buffer, ssize_t buflen, unsigned flags); |
| 448 | extern struct vfsmount *nfs_d_automount(struct path *path); | 442 | extern struct vfsmount *nfs_d_automount(struct path *path); |
| 449 | struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *, | 443 | int nfs_submount(struct fs_context *, struct nfs_server *); |
| 450 | struct nfs_fh *, struct nfs_fattr *); | 444 | int nfs_do_submount(struct fs_context *); |
| 451 | struct vfsmount *nfs_do_submount(struct dentry *, struct nfs_fh *, | ||
| 452 | struct nfs_fattr *, rpc_authflavor_t); | ||
| 453 | 445 | ||
| 454 | /* getroot.c */ | 446 | /* getroot.c */ |
| 455 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, | 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 | int nfs_show_devname(struct seq_file *, struct dentry *); | 468 | int nfs_show_devname(struct seq_file *, struct dentry *); |
| 477 | int nfs_show_path(struct seq_file *, struct dentry *); | 469 | int nfs_show_path(struct seq_file *, struct dentry *); |
| 478 | int nfs_show_stats(struct seq_file *, struct dentry *); | 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 | /* write.c */ | 473 | /* write.c */ |
| 482 | extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 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 | struct vfsmount *nfs_d_automount(struct path *path) | 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 | struct nfs_server *server = NFS_SERVER(d_inode(path->dentry)); | 146 | struct nfs_server *server = NFS_SERVER(d_inode(path->dentry)); |
| 145 | struct nfs_fh *fh = NULL; | 147 | struct nfs_client *client = server->nfs_client; |
| 146 | struct nfs_fattr *fattr = NULL; | 148 | int ret; |
| 147 | 149 | ||
| 148 | if (IS_ROOT(path->dentry)) | 150 | if (IS_ROOT(path->dentry)) |
| 149 | return ERR_PTR(-ESTALE); | 151 | return ERR_PTR(-ESTALE); |
| 150 | 152 | ||
| 151 | mnt = ERR_PTR(-ENOMEM); | 153 | /* Open a new filesystem context, transferring parameters from the |
| 152 | fh = nfs_alloc_fhandle(); | 154 | * parent superblock, including the network namespace. |
| 153 | fattr = nfs_alloc_fattr(); | 155 | */ |
| 154 | if (fh == NULL || fattr == NULL) | 156 | fc = fs_context_for_submount(&nfs_fs_type, path->dentry); |
| 155 | goto out; | 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 | if (IS_ERR(mnt)) | 190 | if (IS_ERR(mnt)) |
| 159 | goto out; | 191 | goto out_fc; |
| 160 | 192 | ||
| 161 | if (nfs_mountpoint_expiry_timeout < 0) | 193 | if (nfs_mountpoint_expiry_timeout < 0) |
| 162 | goto out; | 194 | goto out_fc; |
| 163 | 195 | ||
| 164 | mntget(mnt); /* prevent immediate expiration */ | 196 | mntget(mnt); /* prevent immediate expiration */ |
| 165 | mnt_set_expiry(mnt, &nfs_automount_list); | 197 | mnt_set_expiry(mnt, &nfs_automount_list); |
| 166 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | 198 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); |
| 167 | 199 | ||
| 168 | out: | 200 | out_fc: |
| 169 | nfs_free_fattr(fattr); | 201 | put_fs_context(fc); |
| 170 | nfs_free_fhandle(fh); | ||
| 171 | return mnt; | 202 | return mnt; |
| 172 | } | 203 | } |
| 173 | 204 | ||
| @@ -222,61 +253,62 @@ void nfs_release_automount_timer(void) · 48 unmodified lines | |||
| 222 | * @authflavor: security flavor to use when performing the mount | 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, | 256 | int nfs_do_submount(struct fs_context *fc) |
| 226 | struct nfs_fattr *fattr, rpc_authflavor_t authflavor) | ||
| 227 | { | 257 | { |
| 228 | struct super_block *sb = dentry->d_sb; | 258 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 229 | struct nfs_clone_mount mountdata = { | 259 | struct dentry *dentry = ctx->clone_data.dentry; |
| 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 | }; | ||
| 240 | struct nfs_server *server; | 260 | struct nfs_server *server; |
| 241 | struct vfsmount *mnt; | 261 | char *buffer, *p; |
| 242 | char *page = (char *) __get_free_page(GFP_USER); | 262 | int ret; |
| 243 | char *devname; | ||
| 244 | 263 | ||
| 245 | if (page == NULL) | 264 | /* create a new volume representation */ |
| 246 | return ERR_PTR(-ENOMEM); | 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 | if (IS_ERR(server)) | 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); | 275 | buffer = kmalloc(4096, GFP_USER); |
| 256 | if (IS_ERR(devname)) | 276 | if (!buffer) |
| 257 | mnt = ERR_CAST(devname); | 277 | return -ENOMEM; |
| 258 | else | ||
| 259 | mnt = vfs_submount(dentry, &nfs_prepared_fs_type, devname, &mount_info); | ||
| 260 | 278 | ||
| 261 | if (mount_info.server) | 279 | ctx->internal = true; |
| 262 | nfs_free_server(mount_info.server); | 280 | ctx->mount_info.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits; |
| 263 | free_page((unsigned long)page); | 281 | |
| 264 | return mnt; | 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 | EXPORT_SYMBOL_GPL(nfs_do_submount); | 294 | EXPORT_SYMBOL_GPL(nfs_do_submount); |
| 267 | 295 | ||
| 268 | struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry, | 296 | int nfs_submount(struct fs_context *fc, struct nfs_server *server) |
| 269 | struct nfs_fh *fh, struct nfs_fattr *fattr) | ||
| 270 | { | 297 | { |
| 271 | int err; | 298 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 299 | struct dentry *dentry = ctx->clone_data.dentry; | ||
| 272 | struct dentry *parent = dget_parent(dentry); | 300 | struct dentry *parent = dget_parent(dentry); |
| 301 | int err; | ||
| 273 | 302 | ||
| 274 | /* Look it up again to get its attributes */ | 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 | dput(parent); | 307 | dput(parent); |
| 277 | if (err != 0) | 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 | EXPORT_SYMBOL_GPL(nfs_submount); | 314 | EXPORT_SYMBOL_GPL(nfs_submount); |
| @@ -990,7 +990,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { · 989 unmodified lines | |||
| 990 | .nlmclnt_ops = &nlmclnt_fl_close_lock_ops, | 990 | .nlmclnt_ops = &nlmclnt_fl_close_lock_ops, |
| 991 | .getroot = nfs3_proc_get_root, | 991 | .getroot = nfs3_proc_get_root, |
| 992 | .submount = nfs_submount, | 992 | .submount = nfs_submount, |
| 993 | .try_mount = nfs_try_mount, | 993 | .try_get_tree = nfs_try_get_tree, |
| 994 | .getattr = nfs3_proc_getattr, | 994 | .getattr = nfs3_proc_getattr, |
| 995 | .setattr = nfs3_proc_setattr, | 995 | .setattr = nfs3_proc_setattr, |
| 996 | .lookup = nfs3_proc_lookup, | 996 | .lookup = nfs3_proc_lookup, |
| @@ -268,14 +268,13 @@ extern const struct dentry_operations nfs4_dentry_operations; · 267 unmodified lines | |||
| 268 | int nfs_atomic_open(struct inode *, struct dentry *, struct file *, | 268 | int nfs_atomic_open(struct inode *, struct dentry *, struct file *, |
| 269 | unsigned, umode_t); | 269 | unsigned, umode_t); |
| 270 | 270 | ||
| 271 | /* super.c */ | 271 | /* fs_context.c */ |
| 272 | extern struct file_system_type nfs4_fs_type; | 272 | extern struct file_system_type nfs4_fs_type; |
| 273 | 273 | ||
| 274 | /* nfs4namespace.c */ | 274 | /* nfs4namespace.c */ |
| 275 | struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *, | 275 | struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *, |
| 276 | const struct qstr *); | 276 | const struct qstr *); |
| 277 | struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *, | 277 | int nfs4_submount(struct fs_context *, struct nfs_server *); |
| 278 | struct nfs_fh *, struct nfs_fattr *); | ||
| 279 | int nfs4_replace_transport(struct nfs_server *server, | 278 | int nfs4_replace_transport(struct nfs_server *server, |
| 280 | const struct nfs4_fs_locations *locations); | 279 | const struct nfs4_fs_locations *locations); |
| 281 | 280 | ||
| @@ -526,7 +525,6 @@ extern const nfs4_stateid invalid_stateid; · 244 unmodified lines | |||
| 526 | /* nfs4super.c */ | 525 | /* nfs4super.c */ |
| 527 | struct nfs_mount_info; | 526 | struct nfs_mount_info; |
| 528 | extern struct nfs_subversion nfs_v4; | 527 | extern struct nfs_subversion nfs_v4; |
| 529 | struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *); | ||
| 530 | extern bool nfs4_disable_idmapping; | 528 | extern bool nfs4_disable_idmapping; |
| 531 | extern unsigned short max_session_slots; | 529 | extern unsigned short max_session_slots; |
| 532 | extern unsigned short max_session_cb_slots; | 530 | extern unsigned short max_session_cb_slots; |
| @@ -536,6 +534,9 @@ extern bool recover_lost_locks; · 3 unmodified lines | |||
| 536 | #define NFS4_CLIENT_ID_UNIQ_LEN (64) | 534 | #define NFS4_CLIENT_ID_UNIQ_LEN (64) |
| 537 | extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN]; | 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 | /* nfs4sysctl.c */ | 540 | /* nfs4sysctl.c */ |
| 540 | #ifdef CONFIG_SYSCTL | 541 | #ifdef CONFIG_SYSCTL |
| 541 | int nfs4_register_sysctl(void); | 542 | int nfs4_register_sysctl(void); |
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | #include <linux/fs.h> | 7 | #include <linux/fs.h> |
| 8 | #include <linux/file.h> | 8 | #include <linux/file.h> |
| 9 | #include <linux/falloc.h> | 9 | #include <linux/falloc.h> |
| 10 | #include <linux/mount.h> | ||
| 10 | #include <linux/nfs_fs.h> | 11 | #include <linux/nfs_fs.h> |
| 11 | #include "delegation.h" | 12 | #include "delegation.h" |
| 12 | #include "internal.h" | 13 | #include "internal.h" |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | * NFSv4 namespace | 8 | * NFSv4 namespace |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/module.h> | ||
| 11 | #include <linux/dcache.h> | 12 | #include <linux/dcache.h> |
| 12 | #include <linux/mount.h> | 13 | #include <linux/mount.h> |
| 13 | #include <linux/namei.h> | 14 | #include <linux/namei.h> |
| @@ -21,37 +22,64 @@ · 7 unmodified lines | |||
| 21 | #include <linux/inet.h> | 22 | #include <linux/inet.h> |
| 22 | #include "internal.h" | 23 | #include "internal.h" |
| 23 | #include "nfs4_fs.h" | 24 | #include "nfs4_fs.h" |
| 25 | #include "nfs.h" | ||
| 24 | #include "dns_resolve.h" | 26 | #include "dns_resolve.h" |
| 25 | 27 | ||
| 26 | #define NFSDBG_FACILITY NFSDBG_VFS | 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 | * Convert the NFSv4 pathname components into a standard posix path. | 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, | 57 | static char *nfs4_pathname_string(const struct nfs4_pathname *pathname, |
| 34 | char *buffer, ssize_t buflen) | 58 | unsigned short *_len) |
| 35 | { | 59 | { |
| 36 | char *end = buffer + buflen; | 60 | ssize_t len; |
| 37 | int n; | 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'; | 76 | *p++ = '/'; |
| 40 | buflen--; | 77 | memcpy(p, component->data, component->len); |
| 41 | 78 | p += component->len; | |
| 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 = '/'; | ||
| 51 | } | 79 | } |
| 52 | return end; | 80 | |
| 53 | Elong: | 81 | *p = 0; |
| 54 | return ERR_PTR(-ENAMETOOLONG); | 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 | static int nfs4_validate_fspath(struct dentry *dentry, | 129 | static int nfs4_validate_fspath(struct dentry *dentry, |
| 102 | const struct nfs4_fs_locations *locations, | 130 | const struct nfs4_fs_locations *locations, |
| 103 | char *page, char *page2) | 131 | struct nfs_fs_context *ctx) |
| 104 | { | 132 | { |
| 105 | const char *path, *fs_path; | 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); | 138 | buf = kmalloc(4096, GFP_KERNEL); |
| 108 | if (IS_ERR(path)) | 139 | path = nfs4_path(dentry, buf, 4096); |
| 140 | if (IS_ERR(path)) { | ||
| 141 | kfree(buf); | ||
| 109 | return PTR_ERR(path); | 142 | return PTR_ERR(path); |
| 143 | } | ||
| 110 | 144 | ||
| 111 | fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE); | 145 | fs_path = nfs4_pathname_string(&locations->fs_path, &len); |
| 112 | if (IS_ERR(fs_path)) | 146 | if (IS_ERR(fs_path)) { |
| 147 | kfree(buf); | ||
| 113 | return PTR_ERR(fs_path); | 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 | dprintk("%s: path %s does not begin with fsroot %s\n", | 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 | return -ENOENT; | 157 | return -ENOENT; |
| 119 | } | 158 | } |
| 120 | 159 | ||
| @@ -236,55 +275,83 @@ out: · 115 unmodified lines | |||
| 236 | return new; | 275 | return new; |
| 237 | } | 276 | } |
| 238 | 277 | ||
| 239 | static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | 278 | static int try_location(struct fs_context *fc, |
| 240 | char *page, char *page2, | 279 | const struct nfs4_fs_location *location) |
| 241 | const struct nfs4_fs_location *location) | ||
| 242 | { | 280 | { |
| 243 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); | 281 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); |
| 244 | struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client); | 282 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 245 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 283 | unsigned int len, s; |
| 246 | char *mnt_path; | 284 | char *export_path, *source, *p; |
| 247 | unsigned int maxbuflen; | 285 | int ret = -ENOENT; |
| 248 | unsigned int s; | 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); | 298 | kfree(ctx->nfs_server.hostname); |
| 251 | if (IS_ERR(mnt_path)) | 299 | ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL); |
| 252 | return ERR_CAST(mnt_path); | 300 | if (!ctx->nfs_server.hostname) |
| 253 | mountdata->mnt_path = mnt_path; | 301 | return -ENOMEM; |
| 254 | maxbuflen = mnt_path - 1 - page2; | ||
| 255 | 302 | ||
| 256 | mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); | 303 | export_path = nfs4_pathname_string(&location->rootpath, |
| 257 | if (mountdata->addr == NULL) | 304 | &ctx->nfs_server.export_path_len); |
| 258 | return ERR_PTR(-ENOMEM); | 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 | for (s = 0; s < location->nservers; s++) { | 321 | for (s = 0; s < location->nservers; s++) { |
| 261 | const struct nfs4_string *buf = &location->servers[s]; | 322 | const struct nfs4_string *buf = &location->servers[s]; |
| 262 | 323 | ||
| 263 | if (buf->len <= 0 || buf->len >= maxbuflen) | ||
| 264 | continue; | ||
| 265 | |||
| 266 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) | 324 | if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len)) |
| 267 | continue; | 325 | continue; |
| 268 | 326 | ||
| 269 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, | 327 | ctx->clone_data.addrlen = |
| 270 | mountdata->addr, addr_bufsize, net); | 328 | nfs_parse_server_name(buf->data, buf->len, |
| 271 | if (mountdata->addrlen == 0) | 329 | ctx->clone_data.addr, |
| 330 | addr_bufsize, | ||
| 331 | fc->net_ns); | ||
| 332 | if (ctx->clone_data.addrlen == 0) | ||
| 272 | continue; | 333 | continue; |
| 273 | 334 | ||
| 274 | memcpy(page2, buf->data, buf->len); | 335 | rpc_set_port(ctx->clone_data.addr, NFS_PORT); |
| 275 | page2[buf->len] = '\0'; | ||
| 276 | mountdata->hostname = page2; | ||
| 277 | 336 | ||
| 278 | snprintf(page, PAGE_SIZE, "%s:%s", | 337 | memcpy(ctx->nfs_server.hostname, buf->data, buf->len); |
| 279 | mountdata->hostname, | 338 | ctx->nfs_server.hostname[buf->len] = '\0'; |
| 280 | mountdata->mnt_path); | 339 | ctx->clone_data.hostname = ctx->nfs_server.hostname; |
| 281 | 340 | ||
| 282 | mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata); | 341 | p = source; |
| 283 | if (!IS_ERR(mnt)) | 342 | memcpy(p, buf->data, buf->len); |
| 284 | break; | 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); | 353 | |
| 287 | return mnt; | 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 | * @locations: array of NFSv4 server location information | 360 | * @locations: array of NFSv4 server location information |
| 294 | * | 361 | * |
| 295 | */ | 362 | */ |
| 296 | static struct vfsmount *nfs_follow_referral(struct dentry *dentry, | 363 | static int nfs_follow_referral(struct fs_context *fc, |
| 297 | const struct nfs4_fs_locations *locations) | 364 | const struct nfs4_fs_locations *locations) |
| 298 | { | 365 | { |
| 299 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 366 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 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; | ||
| 306 | int loc, error; | 367 | int loc, error; |
| 307 | 368 | ||
| 308 | if (locations == NULL || locations->nlocations <= 0) | 369 | if (locations == NULL || locations->nlocations <= 0) |
| 309 | goto out; | 370 | return -ENOENT; |
| 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; | ||
| 316 | 371 | ||
| 317 | page2 = (char *) __get_free_page(GFP_USER); | 372 | dprintk("%s: referral at %pd2\n", __func__, ctx->clone_data.dentry); |
| 318 | if (!page2) | ||
| 319 | goto out; | ||
| 320 | 373 | ||
| 321 | /* Ensure fs path is a prefix of current dentry path */ | 374 | /* Ensure fs path is a prefix of current dentry path */ |
| 322 | error = nfs4_validate_fspath(dentry, locations, page, page2); | 375 | error = nfs4_validate_fspath(ctx->clone_data.dentry, locations, ctx); |
| 323 | if (error < 0) { | 376 | if (error < 0) |
| 324 | mnt = ERR_PTR(error); | 377 | return error; |
| 325 | goto out; | ||
| 326 | } | ||
| 327 | 378 | ||
| 379 | error = -ENOENT; | ||
| 328 | for (loc = 0; loc < locations->nlocations; loc++) { | 380 | for (loc = 0; loc < locations->nlocations; loc++) { |
| 329 | const struct nfs4_fs_location *location = &locations->locations[loc]; | 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 | location->rootpath.ncomponents == 0) | 384 | location->rootpath.ncomponents == 0) |
| 333 | continue; | 385 | continue; |
| 334 | 386 | ||
| 335 | mnt = try_location(&mountdata, page, page2, location); | 387 | error = try_location(fc, location); |
| 336 | if (!IS_ERR(mnt)) | 388 | if (error == 0) |
| 337 | break; | 389 | return 0; |
| 338 | } | 390 | } |
| 339 | 391 | ||
| 340 | out: | 392 | return error; |
| 341 | free_page((unsigned long) page); | ||
| 342 | free_page((unsigned long) page2); | ||
| 343 | return mnt; | ||
| 344 | } | 393 | } |
| 345 | 394 | ||
| 346 | /* | 395 | /* |
| @@ -348,71 +397,73 @@ out: · 1 unmodified line | |||
| 348 | * @dentry - dentry of referral | 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); | 402 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 354 | struct dentry *parent; | 403 | struct dentry *dentry, *parent; |
| 355 | struct nfs4_fs_locations *fs_locations = NULL; | 404 | struct nfs4_fs_locations *fs_locations = NULL; |
| 356 | struct page *page; | 405 | struct page *page; |
| 357 | int err; | 406 | int err = -ENOMEM; |
| 358 | 407 | ||
| 359 | /* BUG_ON(IS_ROOT(dentry)); */ | 408 | /* BUG_ON(IS_ROOT(dentry)); */ |
| 360 | page = alloc_page(GFP_KERNEL); | 409 | page = alloc_page(GFP_KERNEL); |
| 361 | if (page == NULL) | 410 | if (!page) |
| 362 | return mnt; | 411 | return -ENOMEM; |
| 363 | 412 | ||
| 364 | fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); | 413 | fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); |
| 365 | if (fs_locations == NULL) | 414 | if (!fs_locations) |
| 366 | goto out_free; | 415 | goto out_free; |
| 367 | 416 | ||
| 368 | /* Get locations */ | 417 | /* Get locations */ |
| 369 | mnt = ERR_PTR(-ENOENT); | 418 | dentry = ctx->clone_data.dentry; |
| 370 | |||
| 371 | parent = dget_parent(dentry); | 419 | parent = dget_parent(dentry); |
| 372 | dprintk("%s: getting locations for %pd2\n", | 420 | dprintk("%s: getting locations for %pd2\n", |
| 373 | __func__, dentry); | 421 | __func__, dentry); |
| 374 | 422 | ||
| 375 | err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page); | 423 | err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page); |
| 376 | dput(parent); | 424 | dput(parent); |
| 377 | if (err != 0 || | 425 | if (err != 0) |
| 378 | fs_locations->nlocations <= 0 || | 426 | goto out_free_2; |
| 427 | |||
| 428 | err = -ENOENT; | ||
| 429 | if (fs_locations->nlocations <= 0 || | ||
| 379 | fs_locations->fs_path.ncomponents <= 0) | 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 | out_free: | 436 | out_free: |
| 384 | __free_page(page); | 437 | __free_page(page); |
| 385 | kfree(fs_locations); | 438 | return err; |
| 386 | return mnt; | ||
| 387 | } | 439 | } |
| 388 | 440 | ||
| 389 | struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry, | 441 | int nfs4_submount(struct fs_context *fc, struct nfs_server *server) |
| 390 | struct nfs_fh *fh, struct nfs_fattr *fattr) | ||
| 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 | struct dentry *parent = dget_parent(dentry); | 445 | struct dentry *parent = dget_parent(dentry); |
| 394 | struct inode *dir = d_inode(parent); | 446 | struct inode *dir = d_inode(parent); |
| 395 | const struct qstr *name = &dentry->d_name; | 447 | const struct qstr *name = &dentry->d_name; |
| 396 | struct rpc_clnt *client; | 448 | struct rpc_clnt *client; |
| 397 | struct vfsmount *mnt; | 449 | int ret; |
| 398 | 450 | ||
| 399 | /* Look it up again to get its attributes and sec flavor */ | 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 | dput(parent); | 454 | dput(parent); |
| 402 | if (IS_ERR(client)) | 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) { | 458 | ctx->selected_flavor = client->cl_auth->au_flavor; |
| 406 | mnt = nfs_do_refmount(client, dentry); | 459 | if (ctx->clone_data.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
| 407 | goto out; | 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 | rpc_shutdown_client(client); | 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 | .file_ops = &nfs4_file_operations, | 10001 | .file_ops = &nfs4_file_operations, |
| 10002 | .getroot = nfs4_proc_get_root, | 10002 | .getroot = nfs4_proc_get_root, |
| 10003 | .submount = nfs4_submount, | 10003 | .submount = nfs4_submount, |
| 10004 | .try_mount = nfs4_try_mount, | 10004 | .try_get_tree = nfs4_try_get_tree, |
| 10005 | .getattr = nfs4_proc_getattr, | 10005 | .getattr = nfs4_proc_getattr, |
| 10006 | .setattr = nfs4_proc_setattr, | 10006 | .setattr = nfs4_proc_setattr, |
| 10007 | .lookup = nfs4_proc_lookup, | 10007 | .lookup = nfs4_proc_lookup, |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | |||
| 4 | */ | 4 | */ |
| 5 | #include <linux/init.h> | 5 | #include <linux/init.h> |
| 6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
| 7 | #include <linux/mount.h> | ||
| 7 | #include <linux/nfs4_mount.h> | 8 | #include <linux/nfs4_mount.h> |
| 8 | #include <linux/nfs_fs.h> | 9 | #include <linux/nfs_fs.h> |
| 9 | #include "delegation.h" | 10 | #include "delegation.h" |
| @@ -18,16 +19,6 @@ · 8 unmodified lines | |||
| 18 | 19 | ||
| 19 | static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc); | 20 | static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc); |
| 20 | static void nfs4_evict_inode(struct inode *inode); | 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 | static const struct super_operations nfs4_sops = { | 23 | static const struct super_operations nfs4_sops = { |
| 33 | .alloc_inode = nfs_alloc_inode, | 24 | .alloc_inode = nfs_alloc_inode, |
| @@ -41,7 +32,6 @@ static const struct super_operations nfs4_sops = { · 7 unmodified lines | |||
| 41 | .show_devname = nfs_show_devname, | 32 | .show_devname = nfs_show_devname, |
| 42 | .show_path = nfs_show_path, | 33 | .show_path = nfs_show_path, |
| 43 | .show_stats = nfs_show_stats, | 34 | .show_stats = nfs_show_stats, |
| 44 | .remount_fs = nfs_remount, | ||
| 45 | }; | 35 | }; |
| 46 | 36 | ||
| 47 | struct nfs_subversion nfs_v4 = { | 37 | struct nfs_subversion nfs_v4 = { |
| @@ -147,102 +137,121 @@ static void nfs_referral_loop_unprotect(void) · 99 unmodified lines | |||
| 147 | kfree(p); | 137 | kfree(p); |
| 148 | } | 138 | } |
| 149 | 139 | ||
| 150 | static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags, | 140 | static int do_nfs4_mount(struct nfs_server *server, |
| 151 | struct nfs_mount_info *info, | 141 | struct fs_context *fc, |
| 152 | const char *hostname, | 142 | const char *hostname, |
| 153 | const char *export_path) | 143 | const char *export_path) |
| 154 | { | 144 | { |
| 145 | struct nfs_fs_context *root_ctx; | ||
| 146 | struct fs_context *root_fc; | ||
| 155 | struct vfsmount *root_mnt; | 147 | struct vfsmount *root_mnt; |
| 156 | struct dentry *dentry; | 148 | struct dentry *dentry; |
| 157 | char *root_devname; | ||
| 158 | int err; | ||
| 159 | size_t len; | 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 | if (IS_ERR(server)) | 158 | if (IS_ERR(server)) |
| 162 | return ERR_CAST(server); | 159 | return PTR_ERR(server); |
| 163 | 160 | ||
| 164 | len = strlen(hostname) + 5; | 161 | root_fc = vfs_dup_fs_context(fc); |
| 165 | root_devname = kmalloc(len, GFP_KERNEL); | 162 | if (IS_ERR(root_fc)) { |
| 166 | if (root_devname == NULL) { | ||
| 167 | nfs_free_server(server); | 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 | /* Does hostname needs to be enclosed in brackets? */ | 181 | /* Does hostname needs to be enclosed in brackets? */ |
| 172 | if (strchr(hostname, ':')) | 182 | if (strchr(hostname, ':')) |
| 173 | snprintf(root_devname, len, "[%s]:/", hostname); | 183 | param.size = snprintf(param.string, len, "[%s]:/", hostname); |
| 174 | else | 184 | else |
| 175 | snprintf(root_devname, len, "%s:/", hostname); | 185 | param.size = snprintf(param.string, len, "%s:/", hostname); |
| 176 | info->server = server; | 186 | ret = vfs_parse_fs_param(root_fc, ¶m); |
| 177 | root_mnt = vfs_kern_mount(&nfs_prepared_fs_type, flags, root_devname, info); | 187 | kfree(param.string); |
| 178 | if (info->server) | 188 | if (ret < 0) { |
| 179 | nfs_free_server(info->server); | 189 | put_fs_context(root_fc); |
| 180 | info->server = NULL; | 190 | return ret; |
| 181 | kfree(root_devname); | 191 | } |
| 192 | root_mnt = fc_mount(root_fc); | ||
| 193 | put_fs_context(root_fc); | ||
| 182 | 194 | ||
| 183 | if (IS_ERR(root_mnt)) | 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(); | 198 | ret = nfs_referral_loop_protect(); |
| 187 | if (err) { | 199 | if (ret) { |
| 188 | mntput(root_mnt); | 200 | mntput(root_mnt); |
| 189 | return ERR_PTR(err); | 201 | return ret; |
| 190 | } | 202 | } |
| 191 | 203 | ||
| 192 | dentry = mount_subtree(root_mnt, export_path); | 204 | dentry = mount_subtree(root_mnt, export_path); |
| 193 | nfs_referral_loop_unprotect(); | 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, | 214 | int nfs4_try_get_tree(struct fs_context *fc) |
| 199 | struct nfs_mount_info *mount_info) | ||
| 200 | { | 215 | { |
| 201 | struct nfs_fs_context *ctx = mount_info->ctx; | 216 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 202 | struct dentry *res; | 217 | int err; |
| 203 | |||
| 204 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
| 205 | 218 | ||
| 206 | res = do_nfs4_mount(nfs4_create_server(mount_info), | 219 | dfprintk(MOUNT, "--> nfs4_try_get_tree()\n"); |
| 207 | flags, mount_info, | ||
| 208 | ctx->nfs_server.hostname, | ||
| 209 | ctx->nfs_server.export_path); | ||
| 210 | 220 | ||
| 211 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", | 221 | /* We create a mount for the server's root, walk to the requested |
| 212 | PTR_ERR_OR_ZERO(res), | 222 | * location and then create another mount for that. |
| 213 | IS_ERR(res) ? " [error]" : ""); | 223 | */ |
| 214 | return res; | 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 | * Create an NFS4 server record on referral traversal | 236 | * Create an NFS4 server record on referral traversal |
| 219 | */ | 237 | */ |
| 220 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | 238 | int nfs4_get_referral_tree(struct fs_context *fc) |
| 221 | int flags, const char *dev_name, void *raw_data) | ||
| 222 | { | 239 | { |
| 223 | struct nfs_clone_mount *data = raw_data; | 240 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 224 | struct nfs_mount_info mount_info = { | 241 | int err; |
| 225 | .cloned = data, | ||
| 226 | .nfs_mod = &nfs_v4, | ||
| 227 | }; | ||
| 228 | struct dentry *res; | ||
| 229 | 242 | ||
| 230 | dprintk("--> nfs4_referral_mount()\n"); | 243 | dprintk("--> nfs4_referral_mount()\n"); |
| 231 | 244 | ||
| 232 | mount_info.mntfh = nfs_alloc_fhandle(); | 245 | /* create a new volume representation */ |
| 233 | if (!mount_info.mntfh) | 246 | err = do_nfs4_mount(nfs4_create_referral_server(&ctx->clone_data, ctx->mount_info.mntfh), |
| 234 | return ERR_PTR(-ENOMEM); | 247 | fc, ctx->nfs_server.hostname, |
| 235 | 248 | ctx->nfs_server.export_path); | |
| 236 | res = do_nfs4_mount(nfs4_create_referral_server(mount_info.cloned, | 249 | if (err) { |
| 237 | mount_info.mntfh), | 250 | dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = %d [error]\n", err); |
| 238 | flags, &mount_info, data->hostname, data->mnt_path); | 251 | } else { |
| 239 | 252 | dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n"); | |
| 240 | dprintk("<-- nfs4_referral_mount() = %d%s\n", | 253 | } |
| 241 | PTR_ERR_OR_ZERO(res), | 254 | return err; |
| 242 | IS_ERR(res) ? " [error]" : ""); | ||
| 243 | |||
| 244 | nfs_free_fhandle(mount_info.mntfh); | ||
| 245 | return res; | ||
| 246 | } | 255 | } |
| 247 | 256 | ||
| 248 | 257 | ||
| @@ -710,7 +710,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = { · 709 unmodified lines | |||
| 710 | .file_ops = &nfs_file_operations, | 710 | .file_ops = &nfs_file_operations, |
| 711 | .getroot = nfs_proc_get_root, | 711 | .getroot = nfs_proc_get_root, |
| 712 | .submount = nfs_submount, | 712 | .submount = nfs_submount, |
| 713 | .try_mount = nfs_try_mount, | 713 | .try_get_tree = nfs_try_get_tree, |
| 714 | .getattr = nfs_proc_getattr, | 714 | .getattr = nfs_proc_getattr, |
| 715 | .setattr = nfs_proc_setattr, | 715 | .setattr = nfs_proc_setattr, |
| 716 | .lookup = nfs_proc_lookup, | 716 | .lookup = nfs_proc_lookup, |
| @@ -70,28 +70,6 @@ · 69 unmodified lines | |||
| 70 | 70 | ||
| 71 | #define NFSDBG_FACILITY NFSDBG_VFS | 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 | const struct super_operations nfs_sops = { | 73 | const struct super_operations nfs_sops = { |
| 96 | .alloc_inode = nfs_alloc_inode, | 74 | .alloc_inode = nfs_alloc_inode, |
| 97 | .free_inode = nfs_free_inode, | 75 | .free_inode = nfs_free_inode, |
| @@ -104,22 +82,10 @@ const struct super_operations nfs_sops = { · 6 unmodified lines | |||
| 104 | .show_devname = nfs_show_devname, | 82 | .show_devname = nfs_show_devname, |
| 105 | .show_path = nfs_show_path, | 83 | .show_path = nfs_show_path, |
| 106 | .show_stats = nfs_show_stats, | 84 | .show_stats = nfs_show_stats, |
| 107 | .remount_fs = nfs_remount, | ||
| 108 | }; | 85 | }; |
| 109 | EXPORT_SYMBOL_GPL(nfs_sops); | 86 | EXPORT_SYMBOL_GPL(nfs_sops); |
| 110 | 87 | ||
| 111 | #if IS_ENABLED(CONFIG_NFS_V4) | 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 | static int __init register_nfs4_fs(void) | 89 | static int __init register_nfs4_fs(void) |
| 124 | { | 90 | { |
| 125 | return register_filesystem(&nfs4_fs_type); | 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 | return nfs_mod->rpc_ops->create_server(mount_info); | 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 *); | 880 | int nfs_try_get_tree(struct fs_context *fc) |
| 915 | |||
| 916 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | ||
| 917 | struct nfs_mount_info *mount_info) | ||
| 918 | { | 881 | { |
| 919 | struct nfs_subversion *nfs_mod = mount_info->nfs_mod; | 882 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 920 | if (mount_info->ctx->need_mount) | 883 | |
| 921 | mount_info->server = nfs_try_mount_request(mount_info); | 884 | if (ctx->need_mount) |
| 885 | ctx->mount_info.server = nfs_try_mount_request(&ctx->mount_info); | ||
| 922 | else | 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 | #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \ | 894 | #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \ |
| 930 | | NFS_MOUNT_SECURE \ | 895 | | NFS_MOUNT_SECURE \ |
| @@ -965,15 +930,11 @@ nfs_compare_remount_data(struct nfs_server *nfss, · 34 unmodified lines | |||
| 965 | return 0; | 930 | return 0; |
| 966 | } | 931 | } |
| 967 | 932 | ||
| 968 | int | 933 | int nfs_reconfigure(struct fs_context *fc) |
| 969 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) | ||
| 970 | { | 934 | { |
| 971 | int error; | 935 | struct nfs_fs_context *ctx = nfs_fc2context(fc); |
| 936 | struct super_block *sb = fc->root->d_sb; | ||
| 972 | struct nfs_server *nfss = sb->s_fs_info; | 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 | sync_filesystem(sb); | 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 | * ones were explicitly specified. Fall back to legacy behavior and | 944 | * ones were explicitly specified. Fall back to legacy behavior and |
| 984 | * just return success. | 945 | * just return success. |
| 985 | */ | 946 | */ |
| 986 | if ((nfsvers == 4 && (!options4 || options4->version == 1)) || | 947 | if (ctx->skip_reconfig_option_check) |
| 987 | (nfsvers <= 3 && (!options || (options->version >= 1 && | ||
| 988 | options->version <= 6)))) | ||
| 989 | return 0; | 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 | * noac is a special case. It implies -o sync, but that's not | 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 | * will clear SB_SYNCHRONOUS if -o sync wasn't specified in the | 953 | * will clear SB_SYNCHRONOUS if -o sync wasn't specified in the |
| 1023 | * remount options, so we have to explicitly reset it. | 954 | * remount options, so we have to explicitly reset it. |
| 1024 | */ | 955 | */ |
| 1025 | if (ctx->flags & NFS_MOUNT_NOAC) | 956 | if (ctx->flags & NFS_MOUNT_NOAC) { |
| 1026 | *flags |= SB_SYNCHRONOUS; | 957 | fc->sb_flags |= SB_SYNCHRONOUS; |
| 958 | fc->sb_flags_mask |= SB_SYNCHRONOUS; | ||
| 959 | } | ||
| 1027 | 960 | ||
| 1028 | /* compare new mount options with old ones */ | 961 | /* compare new mount options with old ones */ |
| 1029 | error = nfs_compare_remount_data(nfss, ctx); | 962 | return 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; | ||
| 1035 | } | 963 | } |
| 1036 | EXPORT_SYMBOL_GPL(nfs_remount); | 964 | EXPORT_SYMBOL_GPL(nfs_reconfigure); |
| 1037 | 965 | ||
| 1038 | /* | 966 | /* |
| 1039 | * Finish setting up an NFS superblock | 967 | * Finish setting up an NFS superblock |
| @@ -1112,19 +1040,11 @@ Ebusy: · 72 unmodified lines | |||
| 1112 | return 0; | 1040 | return 0; |
| 1113 | } | 1041 | } |
| 1114 | 1042 | ||
| 1115 | struct nfs_sb_mountdata { | 1043 | static int nfs_set_super(struct super_block *s, struct fs_context *fc) |
| 1116 | struct nfs_server *server; | ||
| 1117 | int mntflags; | ||
| 1118 | }; | ||
| 1119 | |||
| 1120 | static int nfs_set_super(struct super_block *s, void *data) | ||
| 1121 | { | 1044 | { |
| 1122 | struct nfs_sb_mountdata *sb_mntdata = data; | 1045 | struct nfs_server *server = fc->s_fs_info; |
| 1123 | struct nfs_server *server = sb_mntdata->server; | ||
| 1124 | int ret; | 1046 | int ret; |
| 1125 | 1047 | ||
| 1126 | s->s_flags = sb_mntdata->mntflags; | ||
| 1127 | s->s_fs_info = server; | ||
| 1128 | s->s_d_op = server->nfs_client->rpc_ops->dentry_ops; | 1048 | s->s_d_op = server->nfs_client->rpc_ops->dentry_ops; |
| 1129 | ret = set_anon_super(s, server); | 1049 | ret = set_anon_super(s, server); |
| 1130 | if (ret == 0) | 1050 | if (ret == 0) |
| @@ -1189,11 +1109,9 @@ static int nfs_compare_userns(const struct nfs_server *old, · 58 unmodified lines | |||
| 1189 | return 1; | 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; | 1114 | struct nfs_server *server = fc->s_fs_info, *old = NFS_SB(sb); |
| 1195 | struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); | ||
| 1196 | int mntflags = sb_mntdata->mntflags; | ||
| 1197 | 1115 | ||
| 1198 | if (!nfs_compare_super_address(old, server)) | 1116 | if (!nfs_compare_super_address(old, server)) |
| 1199 | return 0; | 1117 | return 0; |
| @@ -1204,13 +1122,12 @@ static int nfs_compare_super(struct super_block *sb, void *data) · 4 unmodified lines | |||
| 1204 | return 0; | 1122 | return 0; |
| 1205 | if (!nfs_compare_userns(old, server)) | 1123 | if (!nfs_compare_userns(old, server)) |
| 1206 | return 0; | 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 | #ifdef CONFIG_NFS_FSCACHE | 1128 | #ifdef CONFIG_NFS_FSCACHE |
| 1211 | static void nfs_get_cache_cookie(struct super_block *sb, | 1129 | static void nfs_get_cache_cookie(struct super_block *sb, |
| 1212 | struct nfs_fs_context *ctx, | 1130 | struct nfs_fs_context *ctx) |
| 1213 | struct nfs_clone_mount *cloned) | ||
| 1214 | { | 1131 | { |
| 1215 | struct nfs_server *nfss = NFS_SB(sb); | 1132 | struct nfs_server *nfss = NFS_SB(sb); |
| 1216 | char *uniq = NULL; | 1133 | char *uniq = NULL; |
| @@ -1219,30 +1136,32 @@ static void nfs_get_cache_cookie(struct super_block *sb, · 2 unmodified lines | |||
| 1219 | nfss->fscache_key = NULL; | 1136 | nfss->fscache_key = NULL; |
| 1220 | nfss->fscache = NULL; | 1137 | nfss->fscache = NULL; |
| 1221 | 1138 | ||
| 1222 | if (ctx) { | 1139 | if (!ctx) |
| 1223 | if (!(ctx->options & NFS_OPTION_FSCACHE)) | 1140 | return; |
| 1224 | return; | 1141 | |
| 1225 | if (ctx->fscache_uniq) { | 1142 | if (ctx->clone_data.sb) { |
| 1226 | uniq = ctx->fscache_uniq; | 1143 | struct nfs_server *mnt_s = NFS_SB(ctx->clone_data.sb); |
| 1227 | ulen = strlen(ctx->fscache_uniq); | ||
| 1228 | } | ||
| 1229 | } else if (cloned) { | ||
| 1230 | struct nfs_server *mnt_s = NFS_SB(cloned->sb); | ||
| 1231 | if (!(mnt_s->options & NFS_OPTION_FSCACHE)) | 1144 | if (!(mnt_s->options & NFS_OPTION_FSCACHE)) |
| 1232 | return; | 1145 | return; |
| 1233 | if (mnt_s->fscache_key) { | 1146 | if (mnt_s->fscache_key) { |
| 1234 | uniq = mnt_s->fscache_key->key.uniquifier; | 1147 | uniq = mnt_s->fscache_key->key.uniquifier; |
| 1235 | ulen = mnt_s->fscache_key->key.uniq_len; | 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 | return; | 1157 | return; |
| 1158 | } | ||
| 1239 | 1159 | ||
| 1240 | nfs_fscache_get_super_cookie(sb, uniq, ulen); | 1160 | nfs_fscache_get_super_cookie(sb, uniq, ulen); |
| 1241 | } | 1161 | } |
| 1242 | #else | 1162 | #else |
| 1243 | static void nfs_get_cache_cookie(struct super_block *sb, | 1163 | static void nfs_get_cache_cookie(struct super_block *sb, |
| 1244 | struct nfs_fs_context *parsed, | 1164 | struct nfs_fs_context *ctx) |
| 1245 | struct nfs_clone_mount *cloned) | ||
| 1246 | { | 1165 | { |
| 1247 | } | 1166 | } |
| 1248 | #endif | 1167 | #endif |
| @@ -1254,40 +1173,41 @@ static void nfs_set_readahead(struct backing_dev_info *bdi, · 5 unmodified lines | |||
| 1254 | bdi->io_pages = iomax_pages; | 1173 | bdi->io_pages = iomax_pages; |
| 1255 | } | 1174 | } |
| 1256 | 1175 | ||
| 1257 | static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name, | 1176 | int nfs_get_tree_common(struct fs_context *fc) |
| 1258 | struct nfs_mount_info *mount_info) | ||
| 1259 | { | 1177 | { |
| 1178 | struct nfs_fs_context *ctx = nfs_fc2context(fc); | ||
| 1260 | struct super_block *s; | 1179 | struct super_block *s; |
| 1261 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | 1180 | struct dentry *mntroot = ERR_PTR(-ENOMEM); |
| 1262 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | 1181 | int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super; |
| 1263 | struct nfs_server *server = mount_info->server; | 1182 | struct nfs_server *server = ctx->mount_info.server; |
| 1264 | unsigned long kflags = 0, kflags_out = 0; | 1183 | unsigned long kflags = 0, kflags_out = 0; |
| 1265 | struct nfs_sb_mountdata sb_mntdata = { | ||
| 1266 | .mntflags = flags, | ||
| 1267 | .server = server, | ||
| 1268 | }; | ||
| 1269 | int error; | 1184 | int error; |
| 1270 | 1185 | ||
| 1271 | mount_info->server = NULL; | 1186 | ctx->mount_info.server = NULL; |
| 1272 | if (IS_ERR(server)) | 1187 | if (IS_ERR(server)) |
| 1273 | return ERR_CAST(server); | 1188 | return PTR_ERR(server); |
| 1274 | 1189 | ||
| 1275 | if (server->flags & NFS_MOUNT_UNSHARED) | 1190 | if (server->flags & NFS_MOUNT_UNSHARED) |
| 1276 | compare_super = NULL; | 1191 | compare_super = NULL; |
| 1277 | 1192 | ||
| 1278 | /* -o noac implies -o sync */ | 1193 | /* -o noac implies -o sync */ |
| 1279 | if (server->flags & NFS_MOUNT_NOAC) | 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) | 1201 | if (server->caps & NFS_CAP_SECURITY_LABEL) |
| 1283 | if (mount_info->cloned->sb->s_flags & SB_SYNCHRONOUS) | 1202 | fc->lsm_flags |= SECURITY_LSM_NATIVE_LABELS; |
| 1284 | sb_mntdata.mntflags |= SB_SYNCHRONOUS; | ||
| 1285 | 1203 | ||
| 1286 | /* Get a superblock - note that we may end up sharing one that already exists */ | 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, | 1205 | fc->s_fs_info = server; |
| 1288 | flags, &sb_mntdata); | 1206 | s = sget_fc(fc, compare_super, nfs_set_super); |
| 1207 | fc->s_fs_info = NULL; | ||
| 1289 | if (IS_ERR(s)) { | 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 | goto out_err_nosb; | 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 | } else { | 1217 | } else { |
| 1298 | error = super_setup_bdi_name(s, "%u:%u", MAJOR(server->s_dev), | 1218 | error = super_setup_bdi_name(s, "%u:%u", MAJOR(server->s_dev), |
| 1299 | MINOR(server->s_dev)); | 1219 | MINOR(server->s_dev)); |
| 1300 | if (error) { | 1220 | if (error) |
| 1301 | mntroot = ERR_PTR(error); | ||
| 1302 | goto error_splat_super; | 1221 | goto error_splat_super; |
| 1303 | } | ||
| 1304 | nfs_set_readahead(s->s_bdi, server->rpages); | 1222 | nfs_set_readahead(s->s_bdi, server->rpages); |
| 1305 | server->super = s; | 1223 | server->super = s; |
| 1306 | } | 1224 | } |
| 1307 | 1225 | ||
| 1308 | if (!s->s_root) { | 1226 | if (!s->s_root) { |
| 1309 | unsigned bsize = mount_info->inherited_bsize; | 1227 | unsigned bsize = ctx->mount_info.inherited_bsize; |
| 1310 | /* initial superblock/root creation */ | 1228 | /* initial superblock/root creation */ |
| 1311 | nfs_fill_super(s, mount_info); | 1229 | nfs_fill_super(s, &ctx->mount_info); |
| 1312 | if (bsize) { | 1230 | if (bsize) { |
| 1313 | s->s_blocksize_bits = bsize; | 1231 | s->s_blocksize_bits = bsize; |
| 1314 | s->s_blocksize = 1U << bsize; | 1232 | s->s_blocksize = 1U << bsize; |
| 1315 | } | 1233 | } |
| 1316 | nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned); | 1234 | nfs_get_cache_cookie(s, ctx); |
| 1317 | if (!(server->flags & NFS_MOUNT_UNSHARED)) | ||
| 1318 | s->s_iflags |= SB_I_MULTIROOT; | ||
| 1319 | } | 1235 | } |
| 1320 | 1236 | ||
| 1321 | mntroot = nfs_get_root(s, mount_info->mntfh, dev_name); | 1237 | mntroot = nfs_get_root(s, ctx->mount_info.mntfh, fc->source); |
| 1322 | if (IS_ERR(mntroot)) | 1238 | if (IS_ERR(mntroot)) { |
| 1239 | error = PTR_ERR(mntroot); | ||
| 1240 | dfprintk(MOUNT, "NFS: Couldn't get root dentry\n"); | ||
| 1323 | goto error_splat_super; | 1241 | goto error_splat_super; |
| 1324 | 1242 | } | |
| 1243 | fc->root = mntroot; | ||
| 1325 | 1244 | ||
| 1326 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) | 1245 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) |
| 1327 | kflags |= SECURITY_LSM_NATIVE_LABELS; | 1246 | kflags |= SECURITY_LSM_NATIVE_LABELS; |
| 1328 | if (mount_info->cloned) { | 1247 | if (ctx->clone_data.sb) { |
| 1329 | if (d_inode(mntroot)->i_fop != &nfs_dir_operations) { | 1248 | if (d_inode(fc->root)->i_fop != &nfs_dir_operations) { |
| 1330 | error = -ESTALE; | 1249 | error = -ESTALE; |
| 1331 | goto error_splat_root; | 1250 | goto error_splat_root; |
| 1332 | } | 1251 | } |
| 1333 | /* clone any lsm security options from the parent to the new sb */ | 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 | &kflags_out); | 1254 | &kflags_out); |
| 1336 | } else { | 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 | kflags, &kflags_out); | 1257 | kflags, &kflags_out); |
| 1339 | } | 1258 | } |
| 1340 | if (error) | 1259 | if (error) |
| @@ -1342,67 +1261,25 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name, · 1 unmodified line | |||
| 1342 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && | 1261 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && |
| 1343 | !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) | 1262 | !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) |
| 1344 | NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; | 1263 | NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; |
| 1345 | if (error) | ||
| 1346 | goto error_splat_root; | ||
| 1347 | 1264 | ||
| 1348 | s->s_flags |= SB_ACTIVE; | 1265 | s->s_flags |= SB_ACTIVE; |
| 1266 | error = 0; | ||
| 1349 | 1267 | ||
| 1350 | out: | 1268 | out: |
| 1351 | return mntroot; | 1269 | return error; |
| 1352 | 1270 | ||
| 1353 | out_err_nosb: | 1271 | out_err_nosb: |
| 1354 | nfs_free_server(server); | 1272 | nfs_free_server(server); |
| 1355 | goto out; | 1273 | goto out; |
| 1356 | 1274 | ||
| 1357 | error_splat_root: | 1275 | error_splat_root: |
| 1358 | dput(mntroot); | 1276 | dput(fc->root); |
| 1359 | mntroot = ERR_PTR(error); | 1277 | fc->root = NULL; |
| 1360 | error_splat_super: | 1278 | error_splat_super: |
| 1361 | deactivate_locked_super(s); | 1279 | deactivate_locked_super(s); |
| 1362 | goto out; | 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 | * Destroy an NFS2/3 superblock | 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 | EXPORT_SYMBOL_GPL(nfs_kill_super); | 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 | #if IS_ENABLED(CONFIG_NFS_V4) | 1300 | #if IS_ENABLED(CONFIG_NFS_V4) |
| 1435 | 1301 | ||
| 1436 | /* | 1302 | /* |
| @@ -1639,6 +1639,7 @@ struct nfs_subversion; · 1638 unmodified lines | |||
| 1639 | struct nfs_mount_info; | 1639 | struct nfs_mount_info; |
| 1640 | struct nfs_client_initdata; | 1640 | struct nfs_client_initdata; |
| 1641 | struct nfs_pageio_descriptor; | 1641 | struct nfs_pageio_descriptor; |
| 1642 | struct fs_context; | ||
| 1642 | 1643 | ||
| 1643 | /* | 1644 | /* |
| 1644 | * RPC procedure vector for NFSv2/NFSv3 demuxing | 1645 | * RPC procedure vector for NFSv2/NFSv3 demuxing |
| @@ -1653,9 +1654,8 @@ struct nfs_rpc_ops { · 8 unmodified lines | |||
| 1653 | 1654 | ||
| 1654 | int (*getroot) (struct nfs_server *, struct nfs_fh *, | 1655 | int (*getroot) (struct nfs_server *, struct nfs_fh *, |
| 1655 | struct nfs_fsinfo *); | 1656 | struct nfs_fsinfo *); |
| 1656 | struct vfsmount *(*submount) (struct nfs_server *, struct dentry *, | 1657 | int (*submount) (struct fs_context *, struct nfs_server *); |
| 1657 | struct nfs_fh *, struct nfs_fattr *); | 1658 | int (*try_get_tree) (struct fs_context *); |
| 1658 | struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *); | ||
| 1659 | int (*getattr) (struct nfs_server *, struct nfs_fh *, | 1659 | int (*getattr) (struct nfs_server *, struct nfs_fh *, |
| 1660 | struct nfs_fattr *, struct nfs4_label *, | 1660 | struct nfs_fattr *, struct nfs4_label *, |
| 1661 | struct inode *); | 1661 | struct inode *); |