diff options
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 497 |
1 files changed, 358 insertions, 139 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 26127b69a275..0b4cbdc60abd 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include <linux/smp_lock.h> | 42 | #include <linux/smp_lock.h> |
43 | #include <linux/seq_file.h> | 43 | #include <linux/seq_file.h> |
44 | #include <linux/mount.h> | 44 | #include <linux/mount.h> |
45 | #include <linux/mnt_namespace.h> | ||
46 | #include <linux/namei.h> | ||
45 | #include <linux/nfs_idmap.h> | 47 | #include <linux/nfs_idmap.h> |
46 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
47 | #include <linux/inet.h> | 49 | #include <linux/inet.h> |
@@ -90,6 +92,7 @@ enum { | |||
90 | Opt_mountport, | 92 | Opt_mountport, |
91 | Opt_mountvers, | 93 | Opt_mountvers, |
92 | Opt_nfsvers, | 94 | Opt_nfsvers, |
95 | Opt_minorversion, | ||
93 | 96 | ||
94 | /* Mount options that take string arguments */ | 97 | /* Mount options that take string arguments */ |
95 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 98 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
@@ -139,22 +142,23 @@ static const match_table_t nfs_mount_option_tokens = { | |||
139 | { Opt_fscache_uniq, "fsc=%s" }, | 142 | { Opt_fscache_uniq, "fsc=%s" }, |
140 | { Opt_nofscache, "nofsc" }, | 143 | { Opt_nofscache, "nofsc" }, |
141 | 144 | ||
142 | { Opt_port, "port=%u" }, | 145 | { Opt_port, "port=%s" }, |
143 | { Opt_rsize, "rsize=%u" }, | 146 | { Opt_rsize, "rsize=%s" }, |
144 | { Opt_wsize, "wsize=%u" }, | 147 | { Opt_wsize, "wsize=%s" }, |
145 | { Opt_bsize, "bsize=%u" }, | 148 | { Opt_bsize, "bsize=%s" }, |
146 | { Opt_timeo, "timeo=%u" }, | 149 | { Opt_timeo, "timeo=%s" }, |
147 | { Opt_retrans, "retrans=%u" }, | 150 | { Opt_retrans, "retrans=%s" }, |
148 | { Opt_acregmin, "acregmin=%u" }, | 151 | { Opt_acregmin, "acregmin=%s" }, |
149 | { Opt_acregmax, "acregmax=%u" }, | 152 | { Opt_acregmax, "acregmax=%s" }, |
150 | { Opt_acdirmin, "acdirmin=%u" }, | 153 | { Opt_acdirmin, "acdirmin=%s" }, |
151 | { Opt_acdirmax, "acdirmax=%u" }, | 154 | { Opt_acdirmax, "acdirmax=%s" }, |
152 | { Opt_actimeo, "actimeo=%u" }, | 155 | { Opt_actimeo, "actimeo=%s" }, |
153 | { Opt_namelen, "namlen=%u" }, | 156 | { Opt_namelen, "namlen=%s" }, |
154 | { Opt_mountport, "mountport=%u" }, | 157 | { Opt_mountport, "mountport=%s" }, |
155 | { Opt_mountvers, "mountvers=%u" }, | 158 | { Opt_mountvers, "mountvers=%s" }, |
156 | { Opt_nfsvers, "nfsvers=%u" }, | 159 | { Opt_nfsvers, "nfsvers=%s" }, |
157 | { Opt_nfsvers, "vers=%u" }, | 160 | { Opt_nfsvers, "vers=%s" }, |
161 | { Opt_minorversion, "minorversion=%u" }, | ||
158 | 162 | ||
159 | { Opt_sec, "sec=%s" }, | 163 | { Opt_sec, "sec=%s" }, |
160 | { Opt_proto, "proto=%s" }, | 164 | { Opt_proto, "proto=%s" }, |
@@ -270,10 +274,14 @@ static const struct super_operations nfs_sops = { | |||
270 | #ifdef CONFIG_NFS_V4 | 274 | #ifdef CONFIG_NFS_V4 |
271 | static int nfs4_get_sb(struct file_system_type *fs_type, | 275 | static int nfs4_get_sb(struct file_system_type *fs_type, |
272 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
277 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, | ||
278 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | ||
273 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, | 279 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, |
274 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 280 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
275 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | 281 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, |
276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 282 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
283 | static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | ||
284 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | ||
277 | static void nfs4_kill_super(struct super_block *sb); | 285 | static void nfs4_kill_super(struct super_block *sb); |
278 | 286 | ||
279 | static struct file_system_type nfs4_fs_type = { | 287 | static struct file_system_type nfs4_fs_type = { |
@@ -284,6 +292,14 @@ static struct file_system_type nfs4_fs_type = { | |||
284 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 292 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
285 | }; | 293 | }; |
286 | 294 | ||
295 | static struct file_system_type nfs4_remote_fs_type = { | ||
296 | .owner = THIS_MODULE, | ||
297 | .name = "nfs4", | ||
298 | .get_sb = nfs4_remote_get_sb, | ||
299 | .kill_sb = nfs4_kill_super, | ||
300 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
301 | }; | ||
302 | |||
287 | struct file_system_type nfs4_xdev_fs_type = { | 303 | struct file_system_type nfs4_xdev_fs_type = { |
288 | .owner = THIS_MODULE, | 304 | .owner = THIS_MODULE, |
289 | .name = "nfs4", | 305 | .name = "nfs4", |
@@ -292,6 +308,14 @@ struct file_system_type nfs4_xdev_fs_type = { | |||
292 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 308 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
293 | }; | 309 | }; |
294 | 310 | ||
311 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
312 | .owner = THIS_MODULE, | ||
313 | .name = "nfs4", | ||
314 | .get_sb = nfs4_remote_referral_get_sb, | ||
315 | .kill_sb = nfs4_kill_super, | ||
316 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
317 | }; | ||
318 | |||
295 | struct file_system_type nfs4_referral_fs_type = { | 319 | struct file_system_type nfs4_referral_fs_type = { |
296 | .owner = THIS_MODULE, | 320 | .owner = THIS_MODULE, |
297 | .name = "nfs4", | 321 | .name = "nfs4", |
@@ -514,7 +538,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
514 | const char *nostr; | 538 | const char *nostr; |
515 | } nfs_info[] = { | 539 | } nfs_info[] = { |
516 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 540 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
517 | { NFS_MOUNT_INTR, ",intr", ",nointr" }, | ||
518 | { NFS_MOUNT_POSIX, ",posix", "" }, | 541 | { NFS_MOUNT_POSIX, ",posix", "" }, |
519 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 542 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
520 | { NFS_MOUNT_NOAC, ",noac", "" }, | 543 | { NFS_MOUNT_NOAC, ",noac", "" }, |
@@ -943,11 +966,6 @@ static int nfs_parse_security_flavors(char *value, | |||
943 | return 1; | 966 | return 1; |
944 | } | 967 | } |
945 | 968 | ||
946 | static void nfs_parse_invalid_value(const char *option) | ||
947 | { | ||
948 | dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option); | ||
949 | } | ||
950 | |||
951 | /* | 969 | /* |
952 | * Error-check and convert a string of mount options from user space into | 970 | * Error-check and convert a string of mount options from user space into |
953 | * a data structure. The whole mount string is processed; bad options are | 971 | * a data structure. The whole mount string is processed; bad options are |
@@ -958,7 +976,7 @@ static int nfs_parse_mount_options(char *raw, | |||
958 | struct nfs_parsed_mount_data *mnt) | 976 | struct nfs_parsed_mount_data *mnt) |
959 | { | 977 | { |
960 | char *p, *string, *secdata; | 978 | char *p, *string, *secdata; |
961 | int rc, sloppy = 0, errors = 0; | 979 | int rc, sloppy = 0, invalid_option = 0; |
962 | 980 | ||
963 | if (!raw) { | 981 | if (!raw) { |
964 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 982 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -982,7 +1000,9 @@ static int nfs_parse_mount_options(char *raw, | |||
982 | 1000 | ||
983 | while ((p = strsep(&raw, ",")) != NULL) { | 1001 | while ((p = strsep(&raw, ",")) != NULL) { |
984 | substring_t args[MAX_OPT_ARGS]; | 1002 | substring_t args[MAX_OPT_ARGS]; |
985 | int option, token; | 1003 | unsigned long option; |
1004 | int int_option; | ||
1005 | int token; | ||
986 | 1006 | ||
987 | if (!*p) | 1007 | if (!*p) |
988 | continue; | 1008 | continue; |
@@ -1091,114 +1111,156 @@ static int nfs_parse_mount_options(char *raw, | |||
1091 | * options that take numeric values | 1111 | * options that take numeric values |
1092 | */ | 1112 | */ |
1093 | case Opt_port: | 1113 | case Opt_port: |
1094 | if (match_int(args, &option) || | 1114 | string = match_strdup(args); |
1095 | option < 0 || option > USHORT_MAX) { | 1115 | if (string == NULL) |
1096 | errors++; | 1116 | goto out_nomem; |
1097 | nfs_parse_invalid_value("port"); | 1117 | rc = strict_strtoul(string, 10, &option); |
1098 | } else | 1118 | kfree(string); |
1099 | mnt->nfs_server.port = option; | 1119 | if (rc != 0 || option > USHORT_MAX) |
1120 | goto out_invalid_value; | ||
1121 | mnt->nfs_server.port = option; | ||
1100 | break; | 1122 | break; |
1101 | case Opt_rsize: | 1123 | case Opt_rsize: |
1102 | if (match_int(args, &option) || option < 0) { | 1124 | string = match_strdup(args); |
1103 | errors++; | 1125 | if (string == NULL) |
1104 | nfs_parse_invalid_value("rsize"); | 1126 | goto out_nomem; |
1105 | } else | 1127 | rc = strict_strtoul(string, 10, &option); |
1106 | mnt->rsize = option; | 1128 | kfree(string); |
1129 | if (rc != 0) | ||
1130 | goto out_invalid_value; | ||
1131 | mnt->rsize = option; | ||
1107 | break; | 1132 | break; |
1108 | case Opt_wsize: | 1133 | case Opt_wsize: |
1109 | if (match_int(args, &option) || option < 0) { | 1134 | string = match_strdup(args); |
1110 | errors++; | 1135 | if (string == NULL) |
1111 | nfs_parse_invalid_value("wsize"); | 1136 | goto out_nomem; |
1112 | } else | 1137 | rc = strict_strtoul(string, 10, &option); |
1113 | mnt->wsize = option; | 1138 | kfree(string); |
1139 | if (rc != 0) | ||
1140 | goto out_invalid_value; | ||
1141 | mnt->wsize = option; | ||
1114 | break; | 1142 | break; |
1115 | case Opt_bsize: | 1143 | case Opt_bsize: |
1116 | if (match_int(args, &option) || option < 0) { | 1144 | string = match_strdup(args); |
1117 | errors++; | 1145 | if (string == NULL) |
1118 | nfs_parse_invalid_value("bsize"); | 1146 | goto out_nomem; |
1119 | } else | 1147 | rc = strict_strtoul(string, 10, &option); |
1120 | mnt->bsize = option; | 1148 | kfree(string); |
1149 | if (rc != 0) | ||
1150 | goto out_invalid_value; | ||
1151 | mnt->bsize = option; | ||
1121 | break; | 1152 | break; |
1122 | case Opt_timeo: | 1153 | case Opt_timeo: |
1123 | if (match_int(args, &option) || option <= 0) { | 1154 | string = match_strdup(args); |
1124 | errors++; | 1155 | if (string == NULL) |
1125 | nfs_parse_invalid_value("timeo"); | 1156 | goto out_nomem; |
1126 | } else | 1157 | rc = strict_strtoul(string, 10, &option); |
1127 | mnt->timeo = option; | 1158 | kfree(string); |
1159 | if (rc != 0 || option == 0) | ||
1160 | goto out_invalid_value; | ||
1161 | mnt->timeo = option; | ||
1128 | break; | 1162 | break; |
1129 | case Opt_retrans: | 1163 | case Opt_retrans: |
1130 | if (match_int(args, &option) || option <= 0) { | 1164 | string = match_strdup(args); |
1131 | errors++; | 1165 | if (string == NULL) |
1132 | nfs_parse_invalid_value("retrans"); | 1166 | goto out_nomem; |
1133 | } else | 1167 | rc = strict_strtoul(string, 10, &option); |
1134 | mnt->retrans = option; | 1168 | kfree(string); |
1169 | if (rc != 0 || option == 0) | ||
1170 | goto out_invalid_value; | ||
1171 | mnt->retrans = option; | ||
1135 | break; | 1172 | break; |
1136 | case Opt_acregmin: | 1173 | case Opt_acregmin: |
1137 | if (match_int(args, &option) || option < 0) { | 1174 | string = match_strdup(args); |
1138 | errors++; | 1175 | if (string == NULL) |
1139 | nfs_parse_invalid_value("acregmin"); | 1176 | goto out_nomem; |
1140 | } else | 1177 | rc = strict_strtoul(string, 10, &option); |
1141 | mnt->acregmin = option; | 1178 | kfree(string); |
1179 | if (rc != 0) | ||
1180 | goto out_invalid_value; | ||
1181 | mnt->acregmin = option; | ||
1142 | break; | 1182 | break; |
1143 | case Opt_acregmax: | 1183 | case Opt_acregmax: |
1144 | if (match_int(args, &option) || option < 0) { | 1184 | string = match_strdup(args); |
1145 | errors++; | 1185 | if (string == NULL) |
1146 | nfs_parse_invalid_value("acregmax"); | 1186 | goto out_nomem; |
1147 | } else | 1187 | rc = strict_strtoul(string, 10, &option); |
1148 | mnt->acregmax = option; | 1188 | kfree(string); |
1189 | if (rc != 0) | ||
1190 | goto out_invalid_value; | ||
1191 | mnt->acregmax = option; | ||
1149 | break; | 1192 | break; |
1150 | case Opt_acdirmin: | 1193 | case Opt_acdirmin: |
1151 | if (match_int(args, &option) || option < 0) { | 1194 | string = match_strdup(args); |
1152 | errors++; | 1195 | if (string == NULL) |
1153 | nfs_parse_invalid_value("acdirmin"); | 1196 | goto out_nomem; |
1154 | } else | 1197 | rc = strict_strtoul(string, 10, &option); |
1155 | mnt->acdirmin = option; | 1198 | kfree(string); |
1199 | if (rc != 0) | ||
1200 | goto out_invalid_value; | ||
1201 | mnt->acdirmin = option; | ||
1156 | break; | 1202 | break; |
1157 | case Opt_acdirmax: | 1203 | case Opt_acdirmax: |
1158 | if (match_int(args, &option) || option < 0) { | 1204 | string = match_strdup(args); |
1159 | errors++; | 1205 | if (string == NULL) |
1160 | nfs_parse_invalid_value("acdirmax"); | 1206 | goto out_nomem; |
1161 | } else | 1207 | rc = strict_strtoul(string, 10, &option); |
1162 | mnt->acdirmax = option; | 1208 | kfree(string); |
1209 | if (rc != 0) | ||
1210 | goto out_invalid_value; | ||
1211 | mnt->acdirmax = option; | ||
1163 | break; | 1212 | break; |
1164 | case Opt_actimeo: | 1213 | case Opt_actimeo: |
1165 | if (match_int(args, &option) || option < 0) { | 1214 | string = match_strdup(args); |
1166 | errors++; | 1215 | if (string == NULL) |
1167 | nfs_parse_invalid_value("actimeo"); | 1216 | goto out_nomem; |
1168 | } else | 1217 | rc = strict_strtoul(string, 10, &option); |
1169 | mnt->acregmin = mnt->acregmax = | 1218 | kfree(string); |
1170 | mnt->acdirmin = mnt->acdirmax = option; | 1219 | if (rc != 0) |
1220 | goto out_invalid_value; | ||
1221 | mnt->acregmin = mnt->acregmax = | ||
1222 | mnt->acdirmin = mnt->acdirmax = option; | ||
1171 | break; | 1223 | break; |
1172 | case Opt_namelen: | 1224 | case Opt_namelen: |
1173 | if (match_int(args, &option) || option < 0) { | 1225 | string = match_strdup(args); |
1174 | errors++; | 1226 | if (string == NULL) |
1175 | nfs_parse_invalid_value("namlen"); | 1227 | goto out_nomem; |
1176 | } else | 1228 | rc = strict_strtoul(string, 10, &option); |
1177 | mnt->namlen = option; | 1229 | kfree(string); |
1230 | if (rc != 0) | ||
1231 | goto out_invalid_value; | ||
1232 | mnt->namlen = option; | ||
1178 | break; | 1233 | break; |
1179 | case Opt_mountport: | 1234 | case Opt_mountport: |
1180 | if (match_int(args, &option) || | 1235 | string = match_strdup(args); |
1181 | option < 0 || option > USHORT_MAX) { | 1236 | if (string == NULL) |
1182 | errors++; | 1237 | goto out_nomem; |
1183 | nfs_parse_invalid_value("mountport"); | 1238 | rc = strict_strtoul(string, 10, &option); |
1184 | } else | 1239 | kfree(string); |
1185 | mnt->mount_server.port = option; | 1240 | if (rc != 0 || option > USHORT_MAX) |
1241 | goto out_invalid_value; | ||
1242 | mnt->mount_server.port = option; | ||
1186 | break; | 1243 | break; |
1187 | case Opt_mountvers: | 1244 | case Opt_mountvers: |
1188 | if (match_int(args, &option) || | 1245 | string = match_strdup(args); |
1246 | if (string == NULL) | ||
1247 | goto out_nomem; | ||
1248 | rc = strict_strtoul(string, 10, &option); | ||
1249 | kfree(string); | ||
1250 | if (rc != 0 || | ||
1189 | option < NFS_MNT_VERSION || | 1251 | option < NFS_MNT_VERSION || |
1190 | option > NFS_MNT3_VERSION) { | 1252 | option > NFS_MNT3_VERSION) |
1191 | errors++; | 1253 | goto out_invalid_value; |
1192 | nfs_parse_invalid_value("mountvers"); | 1254 | mnt->mount_server.version = option; |
1193 | } else | ||
1194 | mnt->mount_server.version = option; | ||
1195 | break; | 1255 | break; |
1196 | case Opt_nfsvers: | 1256 | case Opt_nfsvers: |
1197 | if (match_int(args, &option)) { | 1257 | string = match_strdup(args); |
1198 | errors++; | 1258 | if (string == NULL) |
1199 | nfs_parse_invalid_value("nfsvers"); | 1259 | goto out_nomem; |
1200 | break; | 1260 | rc = strict_strtoul(string, 10, &option); |
1201 | } | 1261 | kfree(string); |
1262 | if (rc != 0) | ||
1263 | goto out_invalid_value; | ||
1202 | switch (option) { | 1264 | switch (option) { |
1203 | case NFS2_VERSION: | 1265 | case NFS2_VERSION: |
1204 | mnt->flags &= ~NFS_MOUNT_VER3; | 1266 | mnt->flags &= ~NFS_MOUNT_VER3; |
@@ -1207,10 +1269,16 @@ static int nfs_parse_mount_options(char *raw, | |||
1207 | mnt->flags |= NFS_MOUNT_VER3; | 1269 | mnt->flags |= NFS_MOUNT_VER3; |
1208 | break; | 1270 | break; |
1209 | default: | 1271 | default: |
1210 | errors++; | 1272 | goto out_invalid_value; |
1211 | nfs_parse_invalid_value("nfsvers"); | ||
1212 | } | 1273 | } |
1213 | break; | 1274 | break; |
1275 | case Opt_minorversion: | ||
1276 | if (match_int(args, &int_option)) | ||
1277 | return 0; | ||
1278 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | ||
1279 | return 0; | ||
1280 | mnt->minorversion = int_option; | ||
1281 | break; | ||
1214 | 1282 | ||
1215 | /* | 1283 | /* |
1216 | * options that take text values | 1284 | * options that take text values |
@@ -1222,9 +1290,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1222 | rc = nfs_parse_security_flavors(string, mnt); | 1290 | rc = nfs_parse_security_flavors(string, mnt); |
1223 | kfree(string); | 1291 | kfree(string); |
1224 | if (!rc) { | 1292 | if (!rc) { |
1225 | errors++; | ||
1226 | dfprintk(MOUNT, "NFS: unrecognized " | 1293 | dfprintk(MOUNT, "NFS: unrecognized " |
1227 | "security flavor\n"); | 1294 | "security flavor\n"); |
1295 | return 0; | ||
1228 | } | 1296 | } |
1229 | break; | 1297 | break; |
1230 | case Opt_proto: | 1298 | case Opt_proto: |
@@ -1238,23 +1306,25 @@ static int nfs_parse_mount_options(char *raw, | |||
1238 | case Opt_xprt_udp: | 1306 | case Opt_xprt_udp: |
1239 | mnt->flags &= ~NFS_MOUNT_TCP; | 1307 | mnt->flags &= ~NFS_MOUNT_TCP; |
1240 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1308 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1309 | kfree(string); | ||
1241 | break; | 1310 | break; |
1242 | case Opt_xprt_tcp: | 1311 | case Opt_xprt_tcp: |
1243 | mnt->flags |= NFS_MOUNT_TCP; | 1312 | mnt->flags |= NFS_MOUNT_TCP; |
1244 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1313 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1314 | kfree(string); | ||
1245 | break; | 1315 | break; |
1246 | case Opt_xprt_rdma: | 1316 | case Opt_xprt_rdma: |
1247 | /* vector side protocols to TCP */ | 1317 | /* vector side protocols to TCP */ |
1248 | mnt->flags |= NFS_MOUNT_TCP; | 1318 | mnt->flags |= NFS_MOUNT_TCP; |
1249 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1319 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
1250 | xprt_load_transport(string); | 1320 | xprt_load_transport(string); |
1321 | kfree(string); | ||
1251 | break; | 1322 | break; |
1252 | default: | 1323 | default: |
1253 | errors++; | ||
1254 | dfprintk(MOUNT, "NFS: unrecognized " | 1324 | dfprintk(MOUNT, "NFS: unrecognized " |
1255 | "transport protocol\n"); | 1325 | "transport protocol\n"); |
1326 | return 0; | ||
1256 | } | 1327 | } |
1257 | kfree(string); | ||
1258 | break; | 1328 | break; |
1259 | case Opt_mountproto: | 1329 | case Opt_mountproto: |
1260 | string = match_strdup(args); | 1330 | string = match_strdup(args); |
@@ -1273,9 +1343,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1273 | break; | 1343 | break; |
1274 | case Opt_xprt_rdma: /* not used for side protocols */ | 1344 | case Opt_xprt_rdma: /* not used for side protocols */ |
1275 | default: | 1345 | default: |
1276 | errors++; | ||
1277 | dfprintk(MOUNT, "NFS: unrecognized " | 1346 | dfprintk(MOUNT, "NFS: unrecognized " |
1278 | "transport protocol\n"); | 1347 | "transport protocol\n"); |
1348 | return 0; | ||
1279 | } | 1349 | } |
1280 | break; | 1350 | break; |
1281 | case Opt_addr: | 1351 | case Opt_addr: |
@@ -1331,9 +1401,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1331 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; | 1401 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; |
1332 | break; | 1402 | break; |
1333 | default: | 1403 | default: |
1334 | errors++; | ||
1335 | dfprintk(MOUNT, "NFS: invalid " | 1404 | dfprintk(MOUNT, "NFS: invalid " |
1336 | "lookupcache argument\n"); | 1405 | "lookupcache argument\n"); |
1406 | return 0; | ||
1337 | }; | 1407 | }; |
1338 | break; | 1408 | break; |
1339 | 1409 | ||
@@ -1351,20 +1421,20 @@ static int nfs_parse_mount_options(char *raw, | |||
1351 | break; | 1421 | break; |
1352 | 1422 | ||
1353 | default: | 1423 | default: |
1354 | errors++; | 1424 | invalid_option = 1; |
1355 | dfprintk(MOUNT, "NFS: unrecognized mount option " | 1425 | dfprintk(MOUNT, "NFS: unrecognized mount option " |
1356 | "'%s'\n", p); | 1426 | "'%s'\n", p); |
1357 | } | 1427 | } |
1358 | } | 1428 | } |
1359 | 1429 | ||
1360 | if (errors > 0) { | 1430 | if (!sloppy && invalid_option) |
1361 | dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", | 1431 | return 0; |
1362 | errors, (errors == 1 ? "" : "s")); | 1432 | |
1363 | if (!sloppy) | ||
1364 | return 0; | ||
1365 | } | ||
1366 | return 1; | 1433 | return 1; |
1367 | 1434 | ||
1435 | out_invalid_value: | ||
1436 | printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); | ||
1437 | return 0; | ||
1368 | out_nomem: | 1438 | out_nomem: |
1369 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1439 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
1370 | return 0; | 1440 | return 0; |
@@ -1381,6 +1451,7 @@ out_security_failure: | |||
1381 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1451 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1382 | struct nfs_fh *root_fh) | 1452 | struct nfs_fh *root_fh) |
1383 | { | 1453 | { |
1454 | unsigned int auth_flavor_len = 0; | ||
1384 | struct nfs_mount_request request = { | 1455 | struct nfs_mount_request request = { |
1385 | .sap = (struct sockaddr *) | 1456 | .sap = (struct sockaddr *) |
1386 | &args->mount_server.address, | 1457 | &args->mount_server.address, |
@@ -1388,6 +1459,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1388 | .protocol = args->mount_server.protocol, | 1459 | .protocol = args->mount_server.protocol, |
1389 | .fh = root_fh, | 1460 | .fh = root_fh, |
1390 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1461 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1462 | .auth_flav_len = &auth_flavor_len, | ||
1391 | }; | 1463 | }; |
1392 | int status; | 1464 | int status; |
1393 | 1465 | ||
@@ -2240,6 +2312,11 @@ static void nfs4_fill_super(struct super_block *sb) | |||
2240 | nfs_initialise_sb(sb); | 2312 | nfs_initialise_sb(sb); |
2241 | } | 2313 | } |
2242 | 2314 | ||
2315 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | ||
2316 | { | ||
2317 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); | ||
2318 | } | ||
2319 | |||
2243 | /* | 2320 | /* |
2244 | * Validate NFSv4 mount options | 2321 | * Validate NFSv4 mount options |
2245 | */ | 2322 | */ |
@@ -2263,6 +2340,7 @@ static int nfs4_validate_mount_data(void *options, | |||
2263 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2340 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
2264 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2341 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2265 | args->auth_flavor_len = 0; | 2342 | args->auth_flavor_len = 0; |
2343 | args->minorversion = 0; | ||
2266 | 2344 | ||
2267 | switch (data->version) { | 2345 | switch (data->version) { |
2268 | case 1: | 2346 | case 1: |
@@ -2336,6 +2414,8 @@ static int nfs4_validate_mount_data(void *options, | |||
2336 | 2414 | ||
2337 | nfs_validate_transport_protocol(args); | 2415 | nfs_validate_transport_protocol(args); |
2338 | 2416 | ||
2417 | nfs4_validate_mount_flags(args); | ||
2418 | |||
2339 | if (args->auth_flavor_len > 1) | 2419 | if (args->auth_flavor_len > 1) |
2340 | goto out_inval_auth; | 2420 | goto out_inval_auth; |
2341 | 2421 | ||
@@ -2375,12 +2455,12 @@ out_no_client_address: | |||
2375 | } | 2455 | } |
2376 | 2456 | ||
2377 | /* | 2457 | /* |
2378 | * Get the superblock for an NFS4 mountpoint | 2458 | * Get the superblock for the NFS4 root partition |
2379 | */ | 2459 | */ |
2380 | static int nfs4_get_sb(struct file_system_type *fs_type, | 2460 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, |
2381 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2461 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
2382 | { | 2462 | { |
2383 | struct nfs_parsed_mount_data *data; | 2463 | struct nfs_parsed_mount_data *data = raw_data; |
2384 | struct super_block *s; | 2464 | struct super_block *s; |
2385 | struct nfs_server *server; | 2465 | struct nfs_server *server; |
2386 | struct nfs_fh *mntfh; | 2466 | struct nfs_fh *mntfh; |
@@ -2391,18 +2471,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2391 | }; | 2471 | }; |
2392 | int error = -ENOMEM; | 2472 | int error = -ENOMEM; |
2393 | 2473 | ||
2394 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
2395 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2474 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); |
2396 | if (data == NULL || mntfh == NULL) | 2475 | if (data == NULL || mntfh == NULL) |
2397 | goto out_free_fh; | 2476 | goto out_free_fh; |
2398 | 2477 | ||
2399 | security_init_mnt_opts(&data->lsm_opts); | 2478 | security_init_mnt_opts(&data->lsm_opts); |
2400 | 2479 | ||
2401 | /* Validate the mount data */ | ||
2402 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2403 | if (error < 0) | ||
2404 | goto out; | ||
2405 | |||
2406 | /* Get a volume representation */ | 2480 | /* Get a volume representation */ |
2407 | server = nfs4_create_server(data, mntfh); | 2481 | server = nfs4_create_server(data, mntfh); |
2408 | if (IS_ERR(server)) { | 2482 | if (IS_ERR(server)) { |
@@ -2415,7 +2489,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2415 | compare_super = NULL; | 2489 | compare_super = NULL; |
2416 | 2490 | ||
2417 | /* Get a superblock - note that we may end up sharing one that already exists */ | 2491 | /* Get a superblock - note that we may end up sharing one that already exists */ |
2418 | s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); | 2492 | s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata); |
2419 | if (IS_ERR(s)) { | 2493 | if (IS_ERR(s)) { |
2420 | error = PTR_ERR(s); | 2494 | error = PTR_ERR(s); |
2421 | goto out_free; | 2495 | goto out_free; |
@@ -2452,14 +2526,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2452 | error = 0; | 2526 | error = 0; |
2453 | 2527 | ||
2454 | out: | 2528 | out: |
2455 | kfree(data->client_address); | ||
2456 | kfree(data->nfs_server.export_path); | ||
2457 | kfree(data->nfs_server.hostname); | ||
2458 | kfree(data->fscache_uniq); | ||
2459 | security_free_mnt_opts(&data->lsm_opts); | 2529 | security_free_mnt_opts(&data->lsm_opts); |
2460 | out_free_fh: | 2530 | out_free_fh: |
2461 | kfree(mntfh); | 2531 | kfree(mntfh); |
2462 | kfree(data); | ||
2463 | return error; | 2532 | return error; |
2464 | 2533 | ||
2465 | out_free: | 2534 | out_free: |
@@ -2473,16 +2542,137 @@ error_splat_super: | |||
2473 | goto out; | 2542 | goto out; |
2474 | } | 2543 | } |
2475 | 2544 | ||
2545 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
2546 | int flags, void *data, const char *hostname) | ||
2547 | { | ||
2548 | struct vfsmount *root_mnt; | ||
2549 | char *root_devname; | ||
2550 | size_t len; | ||
2551 | |||
2552 | len = strlen(hostname) + 3; | ||
2553 | root_devname = kmalloc(len, GFP_KERNEL); | ||
2554 | if (root_devname == NULL) | ||
2555 | return ERR_PTR(-ENOMEM); | ||
2556 | snprintf(root_devname, len, "%s:/", hostname); | ||
2557 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
2558 | kfree(root_devname); | ||
2559 | return root_mnt; | ||
2560 | } | ||
2561 | |||
2562 | static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | ||
2563 | { | ||
2564 | char *page = (char *) __get_free_page(GFP_KERNEL); | ||
2565 | char *devname, *tmp; | ||
2566 | |||
2567 | if (page == NULL) | ||
2568 | return; | ||
2569 | devname = nfs_path(path->mnt->mnt_devname, | ||
2570 | path->mnt->mnt_root, path->dentry, | ||
2571 | page, PAGE_SIZE); | ||
2572 | if (devname == NULL) | ||
2573 | goto out_freepage; | ||
2574 | tmp = kstrdup(devname, GFP_KERNEL); | ||
2575 | if (tmp == NULL) | ||
2576 | goto out_freepage; | ||
2577 | kfree(mnt->mnt_devname); | ||
2578 | mnt->mnt_devname = tmp; | ||
2579 | out_freepage: | ||
2580 | free_page((unsigned long)page); | ||
2581 | } | ||
2582 | |||
2583 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
2584 | const char *export_path, struct vfsmount *mnt_target) | ||
2585 | { | ||
2586 | struct mnt_namespace *ns_private; | ||
2587 | struct nameidata nd; | ||
2588 | struct super_block *s; | ||
2589 | int ret; | ||
2590 | |||
2591 | ns_private = create_mnt_ns(root_mnt); | ||
2592 | ret = PTR_ERR(ns_private); | ||
2593 | if (IS_ERR(ns_private)) | ||
2594 | goto out_mntput; | ||
2595 | |||
2596 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | ||
2597 | export_path, LOOKUP_FOLLOW, &nd); | ||
2598 | |||
2599 | put_mnt_ns(ns_private); | ||
2600 | |||
2601 | if (ret != 0) | ||
2602 | goto out_err; | ||
2603 | |||
2604 | s = nd.path.mnt->mnt_sb; | ||
2605 | atomic_inc(&s->s_active); | ||
2606 | mnt_target->mnt_sb = s; | ||
2607 | mnt_target->mnt_root = dget(nd.path.dentry); | ||
2608 | |||
2609 | /* Correct the device pathname */ | ||
2610 | nfs_fix_devname(&nd.path, mnt_target); | ||
2611 | |||
2612 | path_put(&nd.path); | ||
2613 | down_write(&s->s_umount); | ||
2614 | return 0; | ||
2615 | out_mntput: | ||
2616 | mntput(root_mnt); | ||
2617 | out_err: | ||
2618 | return ret; | ||
2619 | } | ||
2620 | |||
2621 | /* | ||
2622 | * Get the superblock for an NFS4 mountpoint | ||
2623 | */ | ||
2624 | static int nfs4_get_sb(struct file_system_type *fs_type, | ||
2625 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | ||
2626 | { | ||
2627 | struct nfs_parsed_mount_data *data; | ||
2628 | char *export_path; | ||
2629 | struct vfsmount *root_mnt; | ||
2630 | int error = -ENOMEM; | ||
2631 | |||
2632 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
2633 | if (data == NULL) | ||
2634 | goto out_free_data; | ||
2635 | |||
2636 | /* Validate the mount data */ | ||
2637 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2638 | if (error < 0) | ||
2639 | goto out; | ||
2640 | |||
2641 | export_path = data->nfs_server.export_path; | ||
2642 | data->nfs_server.export_path = "/"; | ||
2643 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
2644 | data->nfs_server.hostname); | ||
2645 | data->nfs_server.export_path = export_path; | ||
2646 | |||
2647 | error = PTR_ERR(root_mnt); | ||
2648 | if (IS_ERR(root_mnt)) | ||
2649 | goto out; | ||
2650 | |||
2651 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2652 | |||
2653 | out: | ||
2654 | kfree(data->client_address); | ||
2655 | kfree(data->nfs_server.export_path); | ||
2656 | kfree(data->nfs_server.hostname); | ||
2657 | kfree(data->fscache_uniq); | ||
2658 | out_free_data: | ||
2659 | kfree(data); | ||
2660 | dprintk("<-- nfs4_get_sb() = %d%s\n", error, | ||
2661 | error != 0 ? " [error]" : ""); | ||
2662 | return error; | ||
2663 | } | ||
2664 | |||
2476 | static void nfs4_kill_super(struct super_block *sb) | 2665 | static void nfs4_kill_super(struct super_block *sb) |
2477 | { | 2666 | { |
2478 | struct nfs_server *server = NFS_SB(sb); | 2667 | struct nfs_server *server = NFS_SB(sb); |
2479 | 2668 | ||
2669 | dprintk("--> %s\n", __func__); | ||
2480 | nfs_super_return_all_delegations(sb); | 2670 | nfs_super_return_all_delegations(sb); |
2481 | kill_anon_super(sb); | 2671 | kill_anon_super(sb); |
2482 | |||
2483 | nfs4_renewd_prepare_shutdown(server); | 2672 | nfs4_renewd_prepare_shutdown(server); |
2484 | nfs_fscache_release_super_cookie(sb); | 2673 | nfs_fscache_release_super_cookie(sb); |
2485 | nfs_free_server(server); | 2674 | nfs_free_server(server); |
2675 | dprintk("<-- %s\n", __func__); | ||
2486 | } | 2676 | } |
2487 | 2677 | ||
2488 | /* | 2678 | /* |
@@ -2568,12 +2758,9 @@ error_splat_super: | |||
2568 | return error; | 2758 | return error; |
2569 | } | 2759 | } |
2570 | 2760 | ||
2571 | /* | 2761 | static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, |
2572 | * Create an NFS4 server record on referral traversal | 2762 | int flags, const char *dev_name, void *raw_data, |
2573 | */ | 2763 | struct vfsmount *mnt) |
2574 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, | ||
2575 | const char *dev_name, void *raw_data, | ||
2576 | struct vfsmount *mnt) | ||
2577 | { | 2764 | { |
2578 | struct nfs_clone_mount *data = raw_data; | 2765 | struct nfs_clone_mount *data = raw_data; |
2579 | struct super_block *s; | 2766 | struct super_block *s; |
@@ -2652,4 +2839,36 @@ error_splat_super: | |||
2652 | return error; | 2839 | return error; |
2653 | } | 2840 | } |
2654 | 2841 | ||
2842 | /* | ||
2843 | * Create an NFS4 server record on referral traversal | ||
2844 | */ | ||
2845 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | ||
2846 | int flags, const char *dev_name, void *raw_data, | ||
2847 | struct vfsmount *mnt) | ||
2848 | { | ||
2849 | struct nfs_clone_mount *data = raw_data; | ||
2850 | char *export_path; | ||
2851 | struct vfsmount *root_mnt; | ||
2852 | int error; | ||
2853 | |||
2854 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
2855 | |||
2856 | export_path = data->mnt_path; | ||
2857 | data->mnt_path = "/"; | ||
2858 | |||
2859 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
2860 | flags, data, data->hostname); | ||
2861 | data->mnt_path = export_path; | ||
2862 | |||
2863 | error = PTR_ERR(root_mnt); | ||
2864 | if (IS_ERR(root_mnt)) | ||
2865 | goto out; | ||
2866 | |||
2867 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2868 | out: | ||
2869 | dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error, | ||
2870 | error != 0 ? " [error]" : ""); | ||
2871 | return error; | ||
2872 | } | ||
2873 | |||
2655 | #endif /* CONFIG_NFS_V4 */ | 2874 | #endif /* CONFIG_NFS_V4 */ |