aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/inode.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-06-23 05:02:57 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-23 10:42:45 -0400
commit454e2398be9b9fa30433fccc548db34d19aa9958 (patch)
tree1f61cb0c3716a33b661cfc8977e9beeb480a322c /fs/nfs/inode.c
parent1ad5544098a69d7dc1fa508cbb17e13a7a952fd8 (diff)
[PATCH] VFS: Permit filesystem to override root dentry on mount
Extend the get_sb() filesystem operation to take an extra argument that permits the VFS to pass in the target vfsmount that defines the mountpoint. The filesystem is then required to manually set the superblock and root dentry pointers. For most filesystems, this should be done with simple_set_mnt() which will set the superblock pointer and then set the root dentry to the superblock's s_root (as per the old default behaviour). The get_sb() op now returns an integer as there's now no need to return the superblock pointer. This patch permits a superblock to be implicitly shared amongst several mount points, such as can be done with NFS to avoid potential inode aliasing. In such a case, simple_set_mnt() would not be called, and instead the mnt_root and mnt_sb would be set directly. The patch also makes the following changes: (*) the get_sb_*() convenience functions in the core kernel now take a vfsmount pointer argument and return an integer, so most filesystems have to change very little. (*) If one of the convenience function is not used, then get_sb() should normally call simple_set_mnt() to instantiate the vfsmount. This will always return 0, and so can be tail-called from get_sb(). (*) generic_shutdown_super() now calls shrink_dcache_sb() to clean up the dcache upon superblock destruction rather than shrink_dcache_anon(). This is required because the superblock may now have multiple trees that aren't actually bound to s_root, but that still need to be cleaned up. The currently called functions assume that the whole tree is rooted at s_root, and that anonymous dentries are not the roots of trees which results in dentries being left unculled. However, with the way NFS superblock sharing are currently set to be implemented, these assumptions are violated: the root of the filesystem is simply a dummy dentry and inode (the real inode for '/' may well be inaccessible), and all the vfsmounts are rooted on anonymous[*] dentries with child trees. [*] Anonymous until discovered from another tree. (*) The documentation has been adjusted, including the additional bit of changing ext2_* into foo_* in the documentation. [akpm@osdl.org: convert ipath_fs, do other stuff] Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Al Viro <viro@zeniv.linux.org.uk> Cc: Nathan Scott <nathans@sgi.com> Cc: Roland Dreier <rolandd@cisco.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r--fs/nfs/inode.c96
1 files changed, 58 insertions, 38 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index d0b991a92327..ff645a961bc8 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1690,8 +1690,8 @@ static int nfs_compare_super(struct super_block *sb, void *data)
1690 return !nfs_compare_fh(&old->fh, &server->fh); 1690 return !nfs_compare_fh(&old->fh, &server->fh);
1691} 1691}
1692 1692
1693static struct super_block *nfs_get_sb(struct file_system_type *fs_type, 1693static int nfs_get_sb(struct file_system_type *fs_type,
1694 int flags, const char *dev_name, void *raw_data) 1694 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
1695{ 1695{
1696 int error; 1696 int error;
1697 struct nfs_server *server = NULL; 1697 struct nfs_server *server = NULL;
@@ -1699,14 +1699,14 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
1699 struct nfs_fh *root; 1699 struct nfs_fh *root;
1700 struct nfs_mount_data *data = raw_data; 1700 struct nfs_mount_data *data = raw_data;
1701 1701
1702 s = ERR_PTR(-EINVAL); 1702 error = -EINVAL;
1703 if (data == NULL) { 1703 if (data == NULL) {
1704 dprintk("%s: missing data argument\n", __FUNCTION__); 1704 dprintk("%s: missing data argument\n", __FUNCTION__);
1705 goto out_err; 1705 goto out_err_noserver;
1706 } 1706 }
1707 if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) { 1707 if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
1708 dprintk("%s: bad mount version\n", __FUNCTION__); 1708 dprintk("%s: bad mount version\n", __FUNCTION__);
1709 goto out_err; 1709 goto out_err_noserver;
1710 } 1710 }
1711 switch (data->version) { 1711 switch (data->version) {
1712 case 1: 1712 case 1:
@@ -1718,7 +1718,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
1718 dprintk("%s: mount structure version %d does not support NFSv3\n", 1718 dprintk("%s: mount structure version %d does not support NFSv3\n",
1719 __FUNCTION__, 1719 __FUNCTION__,
1720 data->version); 1720 data->version);
1721 goto out_err; 1721 goto out_err_noserver;
1722 } 1722 }
1723 data->root.size = NFS2_FHSIZE; 1723 data->root.size = NFS2_FHSIZE;
1724 memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); 1724 memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
@@ -1727,24 +1727,24 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
1727 dprintk("%s: mount structure version %d does not support strong security\n", 1727 dprintk("%s: mount structure version %d does not support strong security\n",
1728 __FUNCTION__, 1728 __FUNCTION__,
1729 data->version); 1729 data->version);
1730 goto out_err; 1730 goto out_err_noserver;
1731 } 1731 }
1732 case 5: 1732 case 5:
1733 memset(data->context, 0, sizeof(data->context)); 1733 memset(data->context, 0, sizeof(data->context));
1734 } 1734 }
1735#ifndef CONFIG_NFS_V3 1735#ifndef CONFIG_NFS_V3
1736 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */ 1736 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
1737 s = ERR_PTR(-EPROTONOSUPPORT); 1737 error = -EPROTONOSUPPORT;
1738 if (data->flags & NFS_MOUNT_VER3) { 1738 if (data->flags & NFS_MOUNT_VER3) {
1739 dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__); 1739 dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
1740 goto out_err; 1740 goto out_err_noserver;
1741 } 1741 }
1742#endif /* CONFIG_NFS_V3 */ 1742#endif /* CONFIG_NFS_V3 */
1743 1743
1744 s = ERR_PTR(-ENOMEM); 1744 error = -ENOMEM;
1745 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); 1745 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
1746 if (!server) 1746 if (!server)
1747 goto out_err; 1747 goto out_err_noserver;
1748 /* Zero out the NFS state stuff */ 1748 /* Zero out the NFS state stuff */
1749 init_nfsv4_state(server); 1749 init_nfsv4_state(server);
1750 server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); 1750 server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
@@ -1754,7 +1754,7 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
1754 root->size = data->root.size; 1754 root->size = data->root.size;
1755 else 1755 else
1756 root->size = NFS2_FHSIZE; 1756 root->size = NFS2_FHSIZE;
1757 s = ERR_PTR(-EINVAL); 1757 error = -EINVAL;
1758 if (root->size > sizeof(root->data)) { 1758 if (root->size > sizeof(root->data)) {
1759 dprintk("%s: invalid root filehandle\n", __FUNCTION__); 1759 dprintk("%s: invalid root filehandle\n", __FUNCTION__);
1760 goto out_err; 1760 goto out_err;
@@ -1770,15 +1770,20 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
1770 } 1770 }
1771 1771
1772 /* Fire up rpciod if not yet running */ 1772 /* Fire up rpciod if not yet running */
1773 s = ERR_PTR(rpciod_up()); 1773 error = rpciod_up();
1774 if (IS_ERR(s)) { 1774 if (error < 0) {
1775 dprintk("%s: couldn't start rpciod! Error = %ld\n", 1775 dprintk("%s: couldn't start rpciod! Error = %d\n",
1776 __FUNCTION__, PTR_ERR(s)); 1776 __FUNCTION__, error);
1777 goto out_err; 1777 goto out_err;
1778 } 1778 }
1779 1779
1780 s = sget(fs_type, nfs_compare_super, nfs_set_super, server); 1780 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
1781 if (IS_ERR(s) || s->s_root) 1781 if (IS_ERR(s)) {
1782 error = PTR_ERR(s);
1783 goto out_err_rpciod;
1784 }
1785
1786 if (s->s_root)
1782 goto out_rpciod_down; 1787 goto out_rpciod_down;
1783 1788
1784 s->s_flags = flags; 1789 s->s_flags = flags;
@@ -1787,15 +1792,22 @@ static struct super_block *nfs_get_sb(struct file_system_type *fs_type,
1787 if (error) { 1792 if (error) {
1788 up_write(&s->s_umount); 1793 up_write(&s->s_umount);
1789 deactivate_super(s); 1794 deactivate_super(s);
1790 return ERR_PTR(error); 1795 return error;
1791 } 1796 }
1792 s->s_flags |= MS_ACTIVE; 1797 s->s_flags |= MS_ACTIVE;
1793 return s; 1798 return simple_set_mnt(mnt, s);
1799
1794out_rpciod_down: 1800out_rpciod_down:
1795 rpciod_down(); 1801 rpciod_down();
1802 kfree(server);
1803 return simple_set_mnt(mnt, s);
1804
1805out_err_rpciod:
1806 rpciod_down();
1796out_err: 1807out_err:
1797 kfree(server); 1808 kfree(server);
1798 return s; 1809out_err_noserver:
1810 return error;
1799} 1811}
1800 1812
1801static void nfs_kill_super(struct super_block *s) 1813static void nfs_kill_super(struct super_block *s)
@@ -2032,8 +2044,8 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
2032 return dst; 2044 return dst;
2033} 2045}
2034 2046
2035static struct super_block *nfs4_get_sb(struct file_system_type *fs_type, 2047static int nfs4_get_sb(struct file_system_type *fs_type,
2036 int flags, const char *dev_name, void *raw_data) 2048 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
2037{ 2049{
2038 int error; 2050 int error;
2039 struct nfs_server *server; 2051 struct nfs_server *server;
@@ -2043,16 +2055,16 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
2043 2055
2044 if (data == NULL) { 2056 if (data == NULL) {
2045 dprintk("%s: missing data argument\n", __FUNCTION__); 2057 dprintk("%s: missing data argument\n", __FUNCTION__);
2046 return ERR_PTR(-EINVAL); 2058 return -EINVAL;
2047 } 2059 }
2048 if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) { 2060 if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
2049 dprintk("%s: bad mount version\n", __FUNCTION__); 2061 dprintk("%s: bad mount version\n", __FUNCTION__);
2050 return ERR_PTR(-EINVAL); 2062 return -EINVAL;
2051 } 2063 }
2052 2064
2053 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); 2065 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
2054 if (!server) 2066 if (!server)
2055 return ERR_PTR(-ENOMEM); 2067 return -ENOMEM;
2056 /* Zero out the NFS state stuff */ 2068 /* Zero out the NFS state stuff */
2057 init_nfsv4_state(server); 2069 init_nfsv4_state(server);
2058 server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL); 2070 server->client = server->client_sys = server->client_acl = ERR_PTR(-EINVAL);
@@ -2074,33 +2086,41 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
2074 2086
2075 /* We now require that the mount process passes the remote address */ 2087 /* We now require that the mount process passes the remote address */
2076 if (data->host_addrlen != sizeof(server->addr)) { 2088 if (data->host_addrlen != sizeof(server->addr)) {
2077 s = ERR_PTR(-EINVAL); 2089 error = -EINVAL;
2078 goto out_free; 2090 goto out_free;
2079 } 2091 }
2080 if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) { 2092 if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
2081 s = ERR_PTR(-EFAULT); 2093 error = -EFAULT;
2082 goto out_free; 2094 goto out_free;
2083 } 2095 }
2084 if (server->addr.sin_family != AF_INET || 2096 if (server->addr.sin_family != AF_INET ||
2085 server->addr.sin_addr.s_addr == INADDR_ANY) { 2097 server->addr.sin_addr.s_addr == INADDR_ANY) {
2086 dprintk("%s: mount program didn't pass remote IP address!\n", 2098 dprintk("%s: mount program didn't pass remote IP address!\n",
2087 __FUNCTION__); 2099 __FUNCTION__);
2088 s = ERR_PTR(-EINVAL); 2100 error = -EINVAL;
2089 goto out_free; 2101 goto out_free;
2090 } 2102 }
2091 2103
2092 /* Fire up rpciod if not yet running */ 2104 /* Fire up rpciod if not yet running */
2093 s = ERR_PTR(rpciod_up()); 2105 error = rpciod_up();
2094 if (IS_ERR(s)) { 2106 if (error < 0) {
2095 dprintk("%s: couldn't start rpciod! Error = %ld\n", 2107 dprintk("%s: couldn't start rpciod! Error = %d\n",
2096 __FUNCTION__, PTR_ERR(s)); 2108 __FUNCTION__, error);
2097 goto out_free; 2109 goto out_free;
2098 } 2110 }
2099 2111
2100 s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); 2112 s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
2101 2113 if (IS_ERR(s)) {
2102 if (IS_ERR(s) || s->s_root) 2114 error = PTR_ERR(s);
2103 goto out_free; 2115 goto out_free;
2116 }
2117
2118 if (s->s_root) {
2119 kfree(server->mnt_path);
2120 kfree(server->hostname);
2121 kfree(server);
2122 return simple_set_mnt(mnt, s);
2123 }
2104 2124
2105 s->s_flags = flags; 2125 s->s_flags = flags;
2106 2126
@@ -2108,17 +2128,17 @@ static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
2108 if (error) { 2128 if (error) {
2109 up_write(&s->s_umount); 2129 up_write(&s->s_umount);
2110 deactivate_super(s); 2130 deactivate_super(s);
2111 return ERR_PTR(error); 2131 return error;
2112 } 2132 }
2113 s->s_flags |= MS_ACTIVE; 2133 s->s_flags |= MS_ACTIVE;
2114 return s; 2134 return simple_set_mnt(mnt, s);
2115out_err: 2135out_err:
2116 s = (struct super_block *)p; 2136 error = PTR_ERR(p);
2117out_free: 2137out_free:
2118 kfree(server->mnt_path); 2138 kfree(server->mnt_path);
2119 kfree(server->hostname); 2139 kfree(server->hostname);
2120 kfree(server); 2140 kfree(server);
2121 return s; 2141 return error;
2122} 2142}
2123 2143
2124static void nfs4_kill_super(struct super_block *sb) 2144static void nfs4_kill_super(struct super_block *sb)