diff options
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 284 |
1 files changed, 77 insertions, 207 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index d3286583009a..2b8e9a5e366a 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -1008,6 +1008,27 @@ static int nfs_parse_security_flavors(char *value, | |||
1008 | return 1; | 1008 | return 1; |
1009 | } | 1009 | } |
1010 | 1010 | ||
1011 | static int nfs_get_option_str(substring_t args[], char **option) | ||
1012 | { | ||
1013 | kfree(*option); | ||
1014 | *option = match_strdup(args); | ||
1015 | return !option; | ||
1016 | } | ||
1017 | |||
1018 | static int nfs_get_option_ul(substring_t args[], unsigned long *option) | ||
1019 | { | ||
1020 | int rc; | ||
1021 | char *string; | ||
1022 | |||
1023 | string = match_strdup(args); | ||
1024 | if (string == NULL) | ||
1025 | return -ENOMEM; | ||
1026 | rc = strict_strtoul(string, 10, option); | ||
1027 | kfree(string); | ||
1028 | |||
1029 | return rc; | ||
1030 | } | ||
1031 | |||
1011 | /* | 1032 | /* |
1012 | * Error-check and convert a string of mount options from user space into | 1033 | * Error-check and convert a string of mount options from user space into |
1013 | * a data structure. The whole mount string is processed; bad options are | 1034 | * a data structure. The whole mount string is processed; bad options are |
@@ -1156,155 +1177,82 @@ static int nfs_parse_mount_options(char *raw, | |||
1156 | * options that take numeric values | 1177 | * options that take numeric values |
1157 | */ | 1178 | */ |
1158 | case Opt_port: | 1179 | case Opt_port: |
1159 | string = match_strdup(args); | 1180 | if (nfs_get_option_ul(args, &option) || |
1160 | if (string == NULL) | 1181 | option > USHRT_MAX) |
1161 | goto out_nomem; | ||
1162 | rc = strict_strtoul(string, 10, &option); | ||
1163 | kfree(string); | ||
1164 | if (rc != 0 || option > USHRT_MAX) | ||
1165 | goto out_invalid_value; | 1182 | goto out_invalid_value; |
1166 | mnt->nfs_server.port = option; | 1183 | mnt->nfs_server.port = option; |
1167 | break; | 1184 | break; |
1168 | case Opt_rsize: | 1185 | case Opt_rsize: |
1169 | string = match_strdup(args); | 1186 | if (nfs_get_option_ul(args, &option)) |
1170 | if (string == NULL) | ||
1171 | goto out_nomem; | ||
1172 | rc = strict_strtoul(string, 10, &option); | ||
1173 | kfree(string); | ||
1174 | if (rc != 0) | ||
1175 | goto out_invalid_value; | 1187 | goto out_invalid_value; |
1176 | mnt->rsize = option; | 1188 | mnt->rsize = option; |
1177 | break; | 1189 | break; |
1178 | case Opt_wsize: | 1190 | case Opt_wsize: |
1179 | string = match_strdup(args); | 1191 | if (nfs_get_option_ul(args, &option)) |
1180 | if (string == NULL) | ||
1181 | goto out_nomem; | ||
1182 | rc = strict_strtoul(string, 10, &option); | ||
1183 | kfree(string); | ||
1184 | if (rc != 0) | ||
1185 | goto out_invalid_value; | 1192 | goto out_invalid_value; |
1186 | mnt->wsize = option; | 1193 | mnt->wsize = option; |
1187 | break; | 1194 | break; |
1188 | case Opt_bsize: | 1195 | case Opt_bsize: |
1189 | string = match_strdup(args); | 1196 | if (nfs_get_option_ul(args, &option)) |
1190 | if (string == NULL) | ||
1191 | goto out_nomem; | ||
1192 | rc = strict_strtoul(string, 10, &option); | ||
1193 | kfree(string); | ||
1194 | if (rc != 0) | ||
1195 | goto out_invalid_value; | 1197 | goto out_invalid_value; |
1196 | mnt->bsize = option; | 1198 | mnt->bsize = option; |
1197 | break; | 1199 | break; |
1198 | case Opt_timeo: | 1200 | case Opt_timeo: |
1199 | string = match_strdup(args); | 1201 | if (nfs_get_option_ul(args, &option) || option == 0) |
1200 | if (string == NULL) | ||
1201 | goto out_nomem; | ||
1202 | rc = strict_strtoul(string, 10, &option); | ||
1203 | kfree(string); | ||
1204 | if (rc != 0 || option == 0) | ||
1205 | goto out_invalid_value; | 1202 | goto out_invalid_value; |
1206 | mnt->timeo = option; | 1203 | mnt->timeo = option; |
1207 | break; | 1204 | break; |
1208 | case Opt_retrans: | 1205 | case Opt_retrans: |
1209 | string = match_strdup(args); | 1206 | if (nfs_get_option_ul(args, &option) || option == 0) |
1210 | if (string == NULL) | ||
1211 | goto out_nomem; | ||
1212 | rc = strict_strtoul(string, 10, &option); | ||
1213 | kfree(string); | ||
1214 | if (rc != 0 || option == 0) | ||
1215 | goto out_invalid_value; | 1207 | goto out_invalid_value; |
1216 | mnt->retrans = option; | 1208 | mnt->retrans = option; |
1217 | break; | 1209 | break; |
1218 | case Opt_acregmin: | 1210 | case Opt_acregmin: |
1219 | string = match_strdup(args); | 1211 | if (nfs_get_option_ul(args, &option)) |
1220 | if (string == NULL) | ||
1221 | goto out_nomem; | ||
1222 | rc = strict_strtoul(string, 10, &option); | ||
1223 | kfree(string); | ||
1224 | if (rc != 0) | ||
1225 | goto out_invalid_value; | 1212 | goto out_invalid_value; |
1226 | mnt->acregmin = option; | 1213 | mnt->acregmin = option; |
1227 | break; | 1214 | break; |
1228 | case Opt_acregmax: | 1215 | case Opt_acregmax: |
1229 | string = match_strdup(args); | 1216 | if (nfs_get_option_ul(args, &option)) |
1230 | if (string == NULL) | ||
1231 | goto out_nomem; | ||
1232 | rc = strict_strtoul(string, 10, &option); | ||
1233 | kfree(string); | ||
1234 | if (rc != 0) | ||
1235 | goto out_invalid_value; | 1217 | goto out_invalid_value; |
1236 | mnt->acregmax = option; | 1218 | mnt->acregmax = option; |
1237 | break; | 1219 | break; |
1238 | case Opt_acdirmin: | 1220 | case Opt_acdirmin: |
1239 | string = match_strdup(args); | 1221 | if (nfs_get_option_ul(args, &option)) |
1240 | if (string == NULL) | ||
1241 | goto out_nomem; | ||
1242 | rc = strict_strtoul(string, 10, &option); | ||
1243 | kfree(string); | ||
1244 | if (rc != 0) | ||
1245 | goto out_invalid_value; | 1222 | goto out_invalid_value; |
1246 | mnt->acdirmin = option; | 1223 | mnt->acdirmin = option; |
1247 | break; | 1224 | break; |
1248 | case Opt_acdirmax: | 1225 | case Opt_acdirmax: |
1249 | string = match_strdup(args); | 1226 | if (nfs_get_option_ul(args, &option)) |
1250 | if (string == NULL) | ||
1251 | goto out_nomem; | ||
1252 | rc = strict_strtoul(string, 10, &option); | ||
1253 | kfree(string); | ||
1254 | if (rc != 0) | ||
1255 | goto out_invalid_value; | 1227 | goto out_invalid_value; |
1256 | mnt->acdirmax = option; | 1228 | mnt->acdirmax = option; |
1257 | break; | 1229 | break; |
1258 | case Opt_actimeo: | 1230 | case Opt_actimeo: |
1259 | string = match_strdup(args); | 1231 | if (nfs_get_option_ul(args, &option)) |
1260 | if (string == NULL) | ||
1261 | goto out_nomem; | ||
1262 | rc = strict_strtoul(string, 10, &option); | ||
1263 | kfree(string); | ||
1264 | if (rc != 0) | ||
1265 | goto out_invalid_value; | 1232 | goto out_invalid_value; |
1266 | mnt->acregmin = mnt->acregmax = | 1233 | mnt->acregmin = mnt->acregmax = |
1267 | mnt->acdirmin = mnt->acdirmax = option; | 1234 | mnt->acdirmin = mnt->acdirmax = option; |
1268 | break; | 1235 | break; |
1269 | case Opt_namelen: | 1236 | case Opt_namelen: |
1270 | string = match_strdup(args); | 1237 | if (nfs_get_option_ul(args, &option)) |
1271 | if (string == NULL) | ||
1272 | goto out_nomem; | ||
1273 | rc = strict_strtoul(string, 10, &option); | ||
1274 | kfree(string); | ||
1275 | if (rc != 0) | ||
1276 | goto out_invalid_value; | 1238 | goto out_invalid_value; |
1277 | mnt->namlen = option; | 1239 | mnt->namlen = option; |
1278 | break; | 1240 | break; |
1279 | case Opt_mountport: | 1241 | case Opt_mountport: |
1280 | string = match_strdup(args); | 1242 | if (nfs_get_option_ul(args, &option) || |
1281 | if (string == NULL) | 1243 | option > USHRT_MAX) |
1282 | goto out_nomem; | ||
1283 | rc = strict_strtoul(string, 10, &option); | ||
1284 | kfree(string); | ||
1285 | if (rc != 0 || option > USHRT_MAX) | ||
1286 | goto out_invalid_value; | 1244 | goto out_invalid_value; |
1287 | mnt->mount_server.port = option; | 1245 | mnt->mount_server.port = option; |
1288 | break; | 1246 | break; |
1289 | case Opt_mountvers: | 1247 | case Opt_mountvers: |
1290 | string = match_strdup(args); | 1248 | if (nfs_get_option_ul(args, &option) || |
1291 | if (string == NULL) | ||
1292 | goto out_nomem; | ||
1293 | rc = strict_strtoul(string, 10, &option); | ||
1294 | kfree(string); | ||
1295 | if (rc != 0 || | ||
1296 | option < NFS_MNT_VERSION || | 1249 | option < NFS_MNT_VERSION || |
1297 | option > NFS_MNT3_VERSION) | 1250 | option > NFS_MNT3_VERSION) |
1298 | goto out_invalid_value; | 1251 | goto out_invalid_value; |
1299 | mnt->mount_server.version = option; | 1252 | mnt->mount_server.version = option; |
1300 | break; | 1253 | break; |
1301 | case Opt_nfsvers: | 1254 | case Opt_nfsvers: |
1302 | string = match_strdup(args); | 1255 | if (nfs_get_option_ul(args, &option)) |
1303 | if (string == NULL) | ||
1304 | goto out_nomem; | ||
1305 | rc = strict_strtoul(string, 10, &option); | ||
1306 | kfree(string); | ||
1307 | if (rc != 0) | ||
1308 | goto out_invalid_value; | 1256 | goto out_invalid_value; |
1309 | switch (option) { | 1257 | switch (option) { |
1310 | case NFS2_VERSION: | 1258 | case NFS2_VERSION: |
@@ -1324,12 +1272,7 @@ static int nfs_parse_mount_options(char *raw, | |||
1324 | } | 1272 | } |
1325 | break; | 1273 | break; |
1326 | case Opt_minorversion: | 1274 | case Opt_minorversion: |
1327 | string = match_strdup(args); | 1275 | if (nfs_get_option_ul(args, &option)) |
1328 | if (string == NULL) | ||
1329 | goto out_nomem; | ||
1330 | rc = strict_strtoul(string, 10, &option); | ||
1331 | kfree(string); | ||
1332 | if (rc != 0) | ||
1333 | goto out_invalid_value; | 1276 | goto out_invalid_value; |
1334 | if (option > NFS4_MAX_MINOR_VERSION) | 1277 | if (option > NFS4_MAX_MINOR_VERSION) |
1335 | goto out_invalid_value; | 1278 | goto out_invalid_value; |
@@ -1365,21 +1308,18 @@ static int nfs_parse_mount_options(char *raw, | |||
1365 | case Opt_xprt_udp: | 1308 | case Opt_xprt_udp: |
1366 | mnt->flags &= ~NFS_MOUNT_TCP; | 1309 | mnt->flags &= ~NFS_MOUNT_TCP; |
1367 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1310 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1368 | kfree(string); | ||
1369 | break; | 1311 | break; |
1370 | case Opt_xprt_tcp6: | 1312 | case Opt_xprt_tcp6: |
1371 | protofamily = AF_INET6; | 1313 | protofamily = AF_INET6; |
1372 | case Opt_xprt_tcp: | 1314 | case Opt_xprt_tcp: |
1373 | mnt->flags |= NFS_MOUNT_TCP; | 1315 | mnt->flags |= NFS_MOUNT_TCP; |
1374 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1316 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1375 | kfree(string); | ||
1376 | break; | 1317 | break; |
1377 | case Opt_xprt_rdma: | 1318 | case Opt_xprt_rdma: |
1378 | /* vector side protocols to TCP */ | 1319 | /* vector side protocols to TCP */ |
1379 | mnt->flags |= NFS_MOUNT_TCP; | 1320 | mnt->flags |= NFS_MOUNT_TCP; |
1380 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1321 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
1381 | xprt_load_transport(string); | 1322 | xprt_load_transport(string); |
1382 | kfree(string); | ||
1383 | break; | 1323 | break; |
1384 | default: | 1324 | default: |
1385 | dfprintk(MOUNT, "NFS: unrecognized " | 1325 | dfprintk(MOUNT, "NFS: unrecognized " |
@@ -1387,6 +1327,7 @@ static int nfs_parse_mount_options(char *raw, | |||
1387 | kfree(string); | 1327 | kfree(string); |
1388 | return 0; | 1328 | return 0; |
1389 | } | 1329 | } |
1330 | kfree(string); | ||
1390 | break; | 1331 | break; |
1391 | case Opt_mountproto: | 1332 | case Opt_mountproto: |
1392 | string = match_strdup(args); | 1333 | string = match_strdup(args); |
@@ -1429,18 +1370,13 @@ static int nfs_parse_mount_options(char *raw, | |||
1429 | goto out_invalid_address; | 1370 | goto out_invalid_address; |
1430 | break; | 1371 | break; |
1431 | case Opt_clientaddr: | 1372 | case Opt_clientaddr: |
1432 | string = match_strdup(args); | 1373 | if (nfs_get_option_str(args, &mnt->client_address)) |
1433 | if (string == NULL) | ||
1434 | goto out_nomem; | 1374 | goto out_nomem; |
1435 | kfree(mnt->client_address); | ||
1436 | mnt->client_address = string; | ||
1437 | break; | 1375 | break; |
1438 | case Opt_mounthost: | 1376 | case Opt_mounthost: |
1439 | string = match_strdup(args); | 1377 | if (nfs_get_option_str(args, |
1440 | if (string == NULL) | 1378 | &mnt->mount_server.hostname)) |
1441 | goto out_nomem; | 1379 | goto out_nomem; |
1442 | kfree(mnt->mount_server.hostname); | ||
1443 | mnt->mount_server.hostname = string; | ||
1444 | break; | 1380 | break; |
1445 | case Opt_mountaddr: | 1381 | case Opt_mountaddr: |
1446 | string = match_strdup(args); | 1382 | string = match_strdup(args); |
@@ -1480,11 +1416,8 @@ static int nfs_parse_mount_options(char *raw, | |||
1480 | }; | 1416 | }; |
1481 | break; | 1417 | break; |
1482 | case Opt_fscache_uniq: | 1418 | case Opt_fscache_uniq: |
1483 | string = match_strdup(args); | 1419 | if (nfs_get_option_str(args, &mnt->fscache_uniq)) |
1484 | if (string == NULL) | ||
1485 | goto out_nomem; | 1420 | goto out_nomem; |
1486 | kfree(mnt->fscache_uniq); | ||
1487 | mnt->fscache_uniq = string; | ||
1488 | mnt->options |= NFS_OPTION_FSCACHE; | 1421 | mnt->options |= NFS_OPTION_FSCACHE; |
1489 | break; | 1422 | break; |
1490 | case Opt_local_lock: | 1423 | case Opt_local_lock: |
@@ -1694,99 +1627,59 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1694 | return nfs_walk_authlist(args, &request); | 1627 | return nfs_walk_authlist(args, &request); |
1695 | } | 1628 | } |
1696 | 1629 | ||
1697 | static int nfs_parse_simple_hostname(const char *dev_name, | 1630 | /* |
1698 | char **hostname, size_t maxnamlen, | 1631 | * Split "dev_name" into "hostname:export_path". |
1699 | char **export_path, size_t maxpathlen) | 1632 | * |
1633 | * The leftmost colon demarks the split between the server's hostname | ||
1634 | * and the export path. If the hostname starts with a left square | ||
1635 | * bracket, then it may contain colons. | ||
1636 | * | ||
1637 | * Note: caller frees hostname and export path, even on error. | ||
1638 | */ | ||
1639 | static int nfs_parse_devname(const char *dev_name, | ||
1640 | char **hostname, size_t maxnamlen, | ||
1641 | char **export_path, size_t maxpathlen) | ||
1700 | { | 1642 | { |
1701 | size_t len; | 1643 | size_t len; |
1702 | char *colon, *comma; | 1644 | char *end; |
1703 | 1645 | ||
1704 | colon = strchr(dev_name, ':'); | 1646 | /* Is the host name protected with square brakcets? */ |
1705 | if (colon == NULL) | 1647 | if (*dev_name == '[') { |
1706 | goto out_bad_devname; | 1648 | end = strchr(++dev_name, ']'); |
1707 | 1649 | if (end == NULL || end[1] != ':') | |
1708 | len = colon - dev_name; | ||
1709 | if (len > maxnamlen) | ||
1710 | goto out_hostname; | ||
1711 | |||
1712 | /* N.B. caller will free nfs_server.hostname in all cases */ | ||
1713 | *hostname = kstrndup(dev_name, len, GFP_KERNEL); | ||
1714 | if (!*hostname) | ||
1715 | goto out_nomem; | ||
1716 | |||
1717 | /* kill possible hostname list: not supported */ | ||
1718 | comma = strchr(*hostname, ','); | ||
1719 | if (comma != NULL) { | ||
1720 | if (comma == *hostname) | ||
1721 | goto out_bad_devname; | 1650 | goto out_bad_devname; |
1722 | *comma = '\0'; | ||
1723 | } | ||
1724 | |||
1725 | colon++; | ||
1726 | len = strlen(colon); | ||
1727 | if (len > maxpathlen) | ||
1728 | goto out_path; | ||
1729 | *export_path = kstrndup(colon, len, GFP_KERNEL); | ||
1730 | if (!*export_path) | ||
1731 | goto out_nomem; | ||
1732 | |||
1733 | dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path); | ||
1734 | return 0; | ||
1735 | |||
1736 | out_bad_devname: | ||
1737 | dfprintk(MOUNT, "NFS: device name not in host:path format\n"); | ||
1738 | return -EINVAL; | ||
1739 | 1651 | ||
1740 | out_nomem: | 1652 | len = end - dev_name; |
1741 | dfprintk(MOUNT, "NFS: not enough memory to parse device name\n"); | 1653 | end++; |
1742 | return -ENOMEM; | 1654 | } else { |
1743 | 1655 | char *comma; | |
1744 | out_hostname: | ||
1745 | dfprintk(MOUNT, "NFS: server hostname too long\n"); | ||
1746 | return -ENAMETOOLONG; | ||
1747 | |||
1748 | out_path: | ||
1749 | dfprintk(MOUNT, "NFS: export pathname too long\n"); | ||
1750 | return -ENAMETOOLONG; | ||
1751 | } | ||
1752 | |||
1753 | /* | ||
1754 | * Hostname has square brackets around it because it contains one or | ||
1755 | * more colons. We look for the first closing square bracket, and a | ||
1756 | * colon must follow it. | ||
1757 | */ | ||
1758 | static int nfs_parse_protected_hostname(const char *dev_name, | ||
1759 | char **hostname, size_t maxnamlen, | ||
1760 | char **export_path, size_t maxpathlen) | ||
1761 | { | ||
1762 | size_t len; | ||
1763 | char *start, *end; | ||
1764 | 1656 | ||
1765 | start = (char *)(dev_name + 1); | 1657 | end = strchr(dev_name, ':'); |
1658 | if (end == NULL) | ||
1659 | goto out_bad_devname; | ||
1660 | len = end - dev_name; | ||
1766 | 1661 | ||
1767 | end = strchr(start, ']'); | 1662 | /* kill possible hostname list: not supported */ |
1768 | if (end == NULL) | 1663 | comma = strchr(dev_name, ','); |
1769 | goto out_bad_devname; | 1664 | if (comma != NULL && comma < end) |
1770 | if (*(end + 1) != ':') | 1665 | *comma = 0; |
1771 | goto out_bad_devname; | 1666 | } |
1772 | 1667 | ||
1773 | len = end - start; | ||
1774 | if (len > maxnamlen) | 1668 | if (len > maxnamlen) |
1775 | goto out_hostname; | 1669 | goto out_hostname; |
1776 | 1670 | ||
1777 | /* N.B. caller will free nfs_server.hostname in all cases */ | 1671 | /* N.B. caller will free nfs_server.hostname in all cases */ |
1778 | *hostname = kstrndup(start, len, GFP_KERNEL); | 1672 | *hostname = kstrndup(dev_name, len, GFP_KERNEL); |
1779 | if (*hostname == NULL) | 1673 | if (*hostname == NULL) |
1780 | goto out_nomem; | 1674 | goto out_nomem; |
1781 | 1675 | len = strlen(++end); | |
1782 | end += 2; | ||
1783 | len = strlen(end); | ||
1784 | if (len > maxpathlen) | 1676 | if (len > maxpathlen) |
1785 | goto out_path; | 1677 | goto out_path; |
1786 | *export_path = kstrndup(end, len, GFP_KERNEL); | 1678 | *export_path = kstrndup(end, len, GFP_KERNEL); |
1787 | if (!*export_path) | 1679 | if (!*export_path) |
1788 | goto out_nomem; | 1680 | goto out_nomem; |
1789 | 1681 | ||
1682 | dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path); | ||
1790 | return 0; | 1683 | return 0; |
1791 | 1684 | ||
1792 | out_bad_devname: | 1685 | out_bad_devname: |
@@ -1807,29 +1700,6 @@ out_path: | |||
1807 | } | 1700 | } |
1808 | 1701 | ||
1809 | /* | 1702 | /* |
1810 | * Split "dev_name" into "hostname:export_path". | ||
1811 | * | ||
1812 | * The leftmost colon demarks the split between the server's hostname | ||
1813 | * and the export path. If the hostname starts with a left square | ||
1814 | * bracket, then it may contain colons. | ||
1815 | * | ||
1816 | * Note: caller frees hostname and export path, even on error. | ||
1817 | */ | ||
1818 | static int nfs_parse_devname(const char *dev_name, | ||
1819 | char **hostname, size_t maxnamlen, | ||
1820 | char **export_path, size_t maxpathlen) | ||
1821 | { | ||
1822 | if (*dev_name == '[') | ||
1823 | return nfs_parse_protected_hostname(dev_name, | ||
1824 | hostname, maxnamlen, | ||
1825 | export_path, maxpathlen); | ||
1826 | |||
1827 | return nfs_parse_simple_hostname(dev_name, | ||
1828 | hostname, maxnamlen, | ||
1829 | export_path, maxpathlen); | ||
1830 | } | ||
1831 | |||
1832 | /* | ||
1833 | * Validate the NFS2/NFS3 mount data | 1703 | * Validate the NFS2/NFS3 mount data |
1834 | * - fills in the mount root filehandle | 1704 | * - fills in the mount root filehandle |
1835 | * | 1705 | * |