diff options
author | Sage Weil <sage@inktank.com> | 2013-08-15 14:11:45 -0400 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-08-15 14:11:45 -0400 |
commit | ee3e542fec6e69bc9fb668698889a37d93950ddf (patch) | |
tree | e74ee766a4764769ef1d3d45d266b4dea64101d3 /fs/nfs/super.c | |
parent | fe2a801b50c0bb8039d627e5ae1fec249d10ff39 (diff) | |
parent | f1d6e17f540af37bb1891480143669ba7636c4cf (diff) |
Merge remote-tracking branch 'linus/master' into testing
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r-- | fs/nfs/super.c | 203 |
1 files changed, 119 insertions, 84 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2d7525fbcf25..f6db66d8f647 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -269,7 +269,7 @@ static match_table_t nfs_local_lock_tokens = { | |||
269 | 269 | ||
270 | enum { | 270 | enum { |
271 | Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0, | 271 | Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0, |
272 | Opt_vers_4_1, | 272 | Opt_vers_4_1, Opt_vers_4_2, |
273 | 273 | ||
274 | Opt_vers_err | 274 | Opt_vers_err |
275 | }; | 275 | }; |
@@ -280,6 +280,7 @@ static match_table_t nfs_vers_tokens = { | |||
280 | { Opt_vers_4, "4" }, | 280 | { Opt_vers_4, "4" }, |
281 | { Opt_vers_4_0, "4.0" }, | 281 | { Opt_vers_4_0, "4.0" }, |
282 | { Opt_vers_4_1, "4.1" }, | 282 | { Opt_vers_4_1, "4.1" }, |
283 | { Opt_vers_4_2, "4.2" }, | ||
283 | 284 | ||
284 | { Opt_vers_err, NULL } | 285 | { Opt_vers_err, NULL } |
285 | }; | 286 | }; |
@@ -832,6 +833,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
832 | seq_printf(m, "\n\tnfsv4:\t"); | 833 | seq_printf(m, "\n\tnfsv4:\t"); |
833 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); | 834 | seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); |
834 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); | 835 | seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); |
836 | seq_printf(m, ",bm2=0x%x", nfss->attr_bitmask[2]); | ||
835 | seq_printf(m, ",acl=0x%x", nfss->acl_bitmask); | 837 | seq_printf(m, ",acl=0x%x", nfss->acl_bitmask); |
836 | show_sessions(m, nfss); | 838 | show_sessions(m, nfss); |
837 | show_pnfs(m, nfss); | 839 | show_pnfs(m, nfss); |
@@ -1097,6 +1099,10 @@ static int nfs_parse_version_string(char *string, | |||
1097 | mnt->version = 4; | 1099 | mnt->version = 4; |
1098 | mnt->minorversion = 1; | 1100 | mnt->minorversion = 1; |
1099 | break; | 1101 | break; |
1102 | case Opt_vers_4_2: | ||
1103 | mnt->version = 4; | ||
1104 | mnt->minorversion = 2; | ||
1105 | break; | ||
1100 | default: | 1106 | default: |
1101 | return 0; | 1107 | return 0; |
1102 | } | 1108 | } |
@@ -1608,29 +1614,13 @@ out_security_failure: | |||
1608 | } | 1614 | } |
1609 | 1615 | ||
1610 | /* | 1616 | /* |
1611 | * Select a security flavor for this mount. The selected flavor | 1617 | * Ensure that the specified authtype in args->auth_flavors[0] is supported by |
1612 | * is planted in args->auth_flavors[0]. | 1618 | * the server. Returns 0 if it's ok, and -EACCES if not. |
1613 | * | ||
1614 | * Returns 0 on success, -EACCES on failure. | ||
1615 | */ | 1619 | */ |
1616 | static int nfs_select_flavor(struct nfs_parsed_mount_data *args, | 1620 | static int nfs_verify_authflavor(struct nfs_parsed_mount_data *args, |
1617 | struct nfs_mount_request *request) | 1621 | rpc_authflavor_t *server_authlist, unsigned int count) |
1618 | { | 1622 | { |
1619 | unsigned int i, count = *(request->auth_flav_len); | 1623 | unsigned int i; |
1620 | rpc_authflavor_t flavor; | ||
1621 | |||
1622 | /* | ||
1623 | * The NFSv2 MNT operation does not return a flavor list. | ||
1624 | */ | ||
1625 | if (args->mount_server.version != NFS_MNT3_VERSION) | ||
1626 | goto out_default; | ||
1627 | |||
1628 | /* | ||
1629 | * Certain releases of Linux's mountd return an empty | ||
1630 | * flavor list in some cases. | ||
1631 | */ | ||
1632 | if (count == 0) | ||
1633 | goto out_default; | ||
1634 | 1624 | ||
1635 | /* | 1625 | /* |
1636 | * If the sec= mount option is used, the specified flavor or AUTH_NULL | 1626 | * If the sec= mount option is used, the specified flavor or AUTH_NULL |
@@ -1640,60 +1630,19 @@ static int nfs_select_flavor(struct nfs_parsed_mount_data *args, | |||
1640 | * means that the server will ignore the rpc creds, so any flavor | 1630 | * means that the server will ignore the rpc creds, so any flavor |
1641 | * can be used. | 1631 | * can be used. |
1642 | */ | 1632 | */ |
1643 | if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) { | ||
1644 | for (i = 0; i < count; i++) { | ||
1645 | if (args->auth_flavors[0] == request->auth_flavs[i] || | ||
1646 | request->auth_flavs[i] == RPC_AUTH_NULL) | ||
1647 | goto out; | ||
1648 | } | ||
1649 | dfprintk(MOUNT, "NFS: auth flavor %d not supported by server\n", | ||
1650 | args->auth_flavors[0]); | ||
1651 | goto out_err; | ||
1652 | } | ||
1653 | |||
1654 | /* | ||
1655 | * RFC 2623, section 2.7 suggests we SHOULD prefer the | ||
1656 | * flavor listed first. However, some servers list | ||
1657 | * AUTH_NULL first. Avoid ever choosing AUTH_NULL. | ||
1658 | */ | ||
1659 | for (i = 0; i < count; i++) { | ||
1660 | struct rpcsec_gss_info info; | ||
1661 | |||
1662 | flavor = request->auth_flavs[i]; | ||
1663 | switch (flavor) { | ||
1664 | case RPC_AUTH_UNIX: | ||
1665 | goto out_set; | ||
1666 | case RPC_AUTH_NULL: | ||
1667 | continue; | ||
1668 | default: | ||
1669 | if (rpcauth_get_gssinfo(flavor, &info) == 0) | ||
1670 | goto out_set; | ||
1671 | } | ||
1672 | } | ||
1673 | |||
1674 | /* | ||
1675 | * As a last chance, see if the server list contains AUTH_NULL - | ||
1676 | * if it does, use the default flavor. | ||
1677 | */ | ||
1678 | for (i = 0; i < count; i++) { | 1633 | for (i = 0; i < count; i++) { |
1679 | if (request->auth_flavs[i] == RPC_AUTH_NULL) | 1634 | if (args->auth_flavors[0] == server_authlist[i] || |
1680 | goto out_default; | 1635 | server_authlist[i] == RPC_AUTH_NULL) |
1636 | goto out; | ||
1681 | } | 1637 | } |
1682 | 1638 | ||
1683 | dfprintk(MOUNT, "NFS: no auth flavors in common with server\n"); | 1639 | dfprintk(MOUNT, "NFS: auth flavor %u not supported by server\n", |
1684 | goto out_err; | 1640 | args->auth_flavors[0]); |
1641 | return -EACCES; | ||
1685 | 1642 | ||
1686 | out_default: | ||
1687 | /* use default if flavor not already set */ | ||
1688 | flavor = (args->auth_flavors[0] == RPC_AUTH_MAXFLAVOR) ? | ||
1689 | RPC_AUTH_UNIX : args->auth_flavors[0]; | ||
1690 | out_set: | ||
1691 | args->auth_flavors[0] = flavor; | ||
1692 | out: | 1643 | out: |
1693 | dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]); | 1644 | dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]); |
1694 | return 0; | 1645 | return 0; |
1695 | out_err: | ||
1696 | return -EACCES; | ||
1697 | } | 1646 | } |
1698 | 1647 | ||
1699 | /* | 1648 | /* |
@@ -1701,10 +1650,10 @@ out_err: | |||
1701 | * corresponding to the provided path. | 1650 | * corresponding to the provided path. |
1702 | */ | 1651 | */ |
1703 | static int nfs_request_mount(struct nfs_parsed_mount_data *args, | 1652 | static int nfs_request_mount(struct nfs_parsed_mount_data *args, |
1704 | struct nfs_fh *root_fh) | 1653 | struct nfs_fh *root_fh, |
1654 | rpc_authflavor_t *server_authlist, | ||
1655 | unsigned int *server_authlist_len) | ||
1705 | { | 1656 | { |
1706 | rpc_authflavor_t server_authlist[NFS_MAX_SECFLAVORS]; | ||
1707 | unsigned int server_authlist_len = ARRAY_SIZE(server_authlist); | ||
1708 | struct nfs_mount_request request = { | 1657 | struct nfs_mount_request request = { |
1709 | .sap = (struct sockaddr *) | 1658 | .sap = (struct sockaddr *) |
1710 | &args->mount_server.address, | 1659 | &args->mount_server.address, |
@@ -1712,7 +1661,7 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, | |||
1712 | .protocol = args->mount_server.protocol, | 1661 | .protocol = args->mount_server.protocol, |
1713 | .fh = root_fh, | 1662 | .fh = root_fh, |
1714 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1663 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1715 | .auth_flav_len = &server_authlist_len, | 1664 | .auth_flav_len = server_authlist_len, |
1716 | .auth_flavs = server_authlist, | 1665 | .auth_flavs = server_authlist, |
1717 | .net = args->net, | 1666 | .net = args->net, |
1718 | }; | 1667 | }; |
@@ -1756,24 +1705,92 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args, | |||
1756 | return status; | 1705 | return status; |
1757 | } | 1706 | } |
1758 | 1707 | ||
1759 | return nfs_select_flavor(args, &request); | 1708 | return 0; |
1760 | } | 1709 | } |
1761 | 1710 | ||
1762 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | 1711 | static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info, |
1763 | struct nfs_mount_info *mount_info, | 1712 | struct nfs_subversion *nfs_mod) |
1764 | struct nfs_subversion *nfs_mod) | ||
1765 | { | 1713 | { |
1766 | int status; | 1714 | int status; |
1767 | struct nfs_server *server; | 1715 | unsigned int i; |
1716 | bool tried_auth_unix = false; | ||
1717 | bool auth_null_in_list = false; | ||
1718 | struct nfs_server *server = ERR_PTR(-EACCES); | ||
1719 | struct nfs_parsed_mount_data *args = mount_info->parsed; | ||
1720 | rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS]; | ||
1721 | unsigned int authlist_len = ARRAY_SIZE(authlist); | ||
1722 | |||
1723 | status = nfs_request_mount(args, mount_info->mntfh, authlist, | ||
1724 | &authlist_len); | ||
1725 | if (status) | ||
1726 | return ERR_PTR(status); | ||
1768 | 1727 | ||
1769 | if (mount_info->parsed->need_mount) { | 1728 | /* |
1770 | status = nfs_request_mount(mount_info->parsed, mount_info->mntfh); | 1729 | * Was a sec= authflavor specified in the options? First, verify |
1730 | * whether the server supports it, and then just try to use it if so. | ||
1731 | */ | ||
1732 | if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) { | ||
1733 | status = nfs_verify_authflavor(args, authlist, authlist_len); | ||
1734 | dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]); | ||
1771 | if (status) | 1735 | if (status) |
1772 | return ERR_PTR(status); | 1736 | return ERR_PTR(status); |
1737 | return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1738 | } | ||
1739 | |||
1740 | /* | ||
1741 | * No sec= option was provided. RFC 2623, section 2.7 suggests we | ||
1742 | * SHOULD prefer the flavor listed first. However, some servers list | ||
1743 | * AUTH_NULL first. Avoid ever choosing AUTH_NULL. | ||
1744 | */ | ||
1745 | for (i = 0; i < authlist_len; ++i) { | ||
1746 | rpc_authflavor_t flavor; | ||
1747 | struct rpcsec_gss_info info; | ||
1748 | |||
1749 | flavor = authlist[i]; | ||
1750 | switch (flavor) { | ||
1751 | case RPC_AUTH_UNIX: | ||
1752 | tried_auth_unix = true; | ||
1753 | break; | ||
1754 | case RPC_AUTH_NULL: | ||
1755 | auth_null_in_list = true; | ||
1756 | continue; | ||
1757 | default: | ||
1758 | if (rpcauth_get_gssinfo(flavor, &info) != 0) | ||
1759 | continue; | ||
1760 | /* Fallthrough */ | ||
1761 | } | ||
1762 | dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor); | ||
1763 | args->auth_flavors[0] = flavor; | ||
1764 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1765 | if (!IS_ERR(server)) | ||
1766 | return server; | ||
1773 | } | 1767 | } |
1774 | 1768 | ||
1775 | /* Get a volume representation */ | 1769 | /* |
1776 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | 1770 | * Nothing we tried so far worked. At this point, give up if we've |
1771 | * already tried AUTH_UNIX or if the server's list doesn't contain | ||
1772 | * AUTH_NULL | ||
1773 | */ | ||
1774 | if (tried_auth_unix || !auth_null_in_list) | ||
1775 | return server; | ||
1776 | |||
1777 | /* Last chance! Try AUTH_UNIX */ | ||
1778 | dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX); | ||
1779 | args->auth_flavors[0] = RPC_AUTH_UNIX; | ||
1780 | return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1781 | } | ||
1782 | |||
1783 | struct dentry *nfs_try_mount(int flags, const char *dev_name, | ||
1784 | struct nfs_mount_info *mount_info, | ||
1785 | struct nfs_subversion *nfs_mod) | ||
1786 | { | ||
1787 | struct nfs_server *server; | ||
1788 | |||
1789 | if (mount_info->parsed->need_mount) | ||
1790 | server = nfs_try_mount_request(mount_info, nfs_mod); | ||
1791 | else | ||
1792 | server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); | ||
1793 | |||
1777 | if (IS_ERR(server)) | 1794 | if (IS_ERR(server)) |
1778 | return ERR_CAST(server); | 1795 | return ERR_CAST(server); |
1779 | 1796 | ||
@@ -2412,7 +2429,21 @@ static int nfs_bdi_register(struct nfs_server *server) | |||
2412 | int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, | 2429 | int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, |
2413 | struct nfs_mount_info *mount_info) | 2430 | struct nfs_mount_info *mount_info) |
2414 | { | 2431 | { |
2415 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); | 2432 | int error; |
2433 | unsigned long kflags = 0, kflags_out = 0; | ||
2434 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) | ||
2435 | kflags |= SECURITY_LSM_NATIVE_LABELS; | ||
2436 | |||
2437 | error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts, | ||
2438 | kflags, &kflags_out); | ||
2439 | if (error) | ||
2440 | goto err; | ||
2441 | |||
2442 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && | ||
2443 | !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) | ||
2444 | NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; | ||
2445 | err: | ||
2446 | return error; | ||
2416 | } | 2447 | } |
2417 | EXPORT_SYMBOL_GPL(nfs_set_sb_security); | 2448 | EXPORT_SYMBOL_GPL(nfs_set_sb_security); |
2418 | 2449 | ||
@@ -2447,6 +2478,10 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, | |||
2447 | if (server->flags & NFS_MOUNT_NOAC) | 2478 | if (server->flags & NFS_MOUNT_NOAC) |
2448 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | 2479 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; |
2449 | 2480 | ||
2481 | if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL) | ||
2482 | if (mount_info->cloned->sb->s_flags & MS_SYNCHRONOUS) | ||
2483 | sb_mntdata.mntflags |= MS_SYNCHRONOUS; | ||
2484 | |||
2450 | /* Get a superblock - note that we may end up sharing one that already exists */ | 2485 | /* Get a superblock - note that we may end up sharing one that already exists */ |
2451 | s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata); | 2486 | s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata); |
2452 | if (IS_ERR(s)) { | 2487 | if (IS_ERR(s)) { |