aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r--fs/nfs/super.c497
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
271static int nfs4_get_sb(struct file_system_type *fs_type, 275static 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);
277static int nfs4_remote_get_sb(struct file_system_type *fs_type,
278 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
273static int nfs4_xdev_get_sb(struct file_system_type *fs_type, 279static 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);
275static int nfs4_referral_get_sb(struct file_system_type *fs_type, 281static 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);
283static 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);
277static void nfs4_kill_super(struct super_block *sb); 285static void nfs4_kill_super(struct super_block *sb);
278 286
279static struct file_system_type nfs4_fs_type = { 287static 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
295static 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
287struct file_system_type nfs4_xdev_fs_type = { 303struct 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
311static 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
295struct file_system_type nfs4_referral_fs_type = { 319struct 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
946static 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
1435out_invalid_value:
1436 printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p);
1437 return 0;
1368out_nomem: 1438out_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:
1381static int nfs_try_mount(struct nfs_parsed_mount_data *args, 1451static 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
2315static 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 */
2380static int nfs4_get_sb(struct file_system_type *fs_type, 2460static 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
2454out: 2528out:
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);
2460out_free_fh: 2530out_free_fh:
2461 kfree(mntfh); 2531 kfree(mntfh);
2462 kfree(data);
2463 return error; 2532 return error;
2464 2533
2465out_free: 2534out_free:
@@ -2473,16 +2542,137 @@ error_splat_super:
2473 goto out; 2542 goto out;
2474} 2543}
2475 2544
2545static 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
2562static 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;
2579out_freepage:
2580 free_page((unsigned long)page);
2581}
2582
2583static 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;
2615out_mntput:
2616 mntput(root_mnt);
2617out_err:
2618 return ret;
2619}
2620
2621/*
2622 * Get the superblock for an NFS4 mountpoint
2623 */
2624static 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
2653out:
2654 kfree(data->client_address);
2655 kfree(data->nfs_server.export_path);
2656 kfree(data->nfs_server.hostname);
2657 kfree(data->fscache_uniq);
2658out_free_data:
2659 kfree(data);
2660 dprintk("<-- nfs4_get_sb() = %d%s\n", error,
2661 error != 0 ? " [error]" : "");
2662 return error;
2663}
2664
2476static void nfs4_kill_super(struct super_block *sb) 2665static 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/* 2761static 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)
2574static 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 */
2845static 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);
2868out:
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 */