1 /* 2 * linux/fs/nfs/namespace.c 3 * 4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com> 5 * - Modified by David Howells <dhowells@redhat.com> 6 * 7 * NFS namespace 8 */ 9 10 #include <linux/dcache.h> 11 #include <linux/gfp.h> 12 #include <linux/mount.h> 13 #include <linux/namei.h> 14 #include <linux/nfs_fs.h> 15 #include <linux/string.h> 16 #include <linux/sunrpc/clnt.h> 17 #include <linux/vfs.h> 18 #include "internal.h" 19 20 #define NFSDBG_FACILITY NFSDBG_VFS 21 22 static void nfs_expire_automounts(struct work_struct *work); 23 24 static LIST_HEAD(nfs_automount_list); 25 static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); 26 int nfs_mountpoint_expiry_timeout = 500 * HZ; 27 28 static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, 29 const struct dentry *dentry, 30 struct nfs_fh *fh, 31 struct nfs_fattr *fattr); 32 33 /* 34 * nfs_path - reconstruct the path given an arbitrary dentry 35 * @base - arbitrary string to prepend to the path 36 * @droot - pointer to root dentry for mountpoint 37 * @dentry - pointer to dentry 38 * @buffer - result buffer 39 * @buflen - length of buffer 40 * 41 * Helper function for constructing the path from the 42 * root dentry to an arbitrary hashed dentry. 43 * 44 * This is mainly for use in figuring out the path on the 45 * server side when automounting on top of an existing partition. 46 */ 47 char *nfs_path(const char *base, 48 const struct dentry *droot, 49 const struct dentry *dentry, 50 char *buffer, ssize_t buflen) 51 { 52 char *end = buffer+buflen; 53 int namelen; 54 55 *--end = '\0'; 56 buflen--; 57 spin_lock(&dcache_lock); 58 while (!IS_ROOT(dentry) && dentry != droot) { 59 namelen = dentry->d_name.len; 60 buflen -= namelen + 1; 61 if (buflen < 0) 62 goto Elong_unlock; 63 end -= namelen; 64 memcpy(end, dentry->d_name.name, namelen); 65 *--end = '/'; 66 dentry = dentry->d_parent; 67 } 68 spin_unlock(&dcache_lock); 69 if (*end != '/') { 70 if (--buflen < 0) 71 goto Elong; 72 *--end = '/'; 73 } 74 namelen = strlen(base); 75 /* Strip off excess slashes in base string */ 76 while (namelen > 0 && base[namelen - 1] == '/') 77 namelen--; 78 buflen -= namelen; 79 if (buflen < 0) 80 goto Elong; 81 end -= namelen; 82 memcpy(end, base, namelen); 83 return end; 84 Elong_unlock: 85 spin_unlock(&dcache_lock); 86 Elong: 87 return ERR_PTR(-ENAMETOOLONG); 88 } 89 90 /* 91 * nfs_follow_mountpoint - handle crossing a mountpoint on the server 92 * @dentry - dentry of mountpoint 93 * @nd - nameidata info 94 * 95 * When we encounter a mountpoint on the server, we want to set up 96 * a mountpoint on the client too, to prevent inode numbers from 97 * colliding, and to allow "df" to work properly. 98 * On NFSv4, we also want to allow for the fact that different 99 * filesystems may be migrated to different servers in a failover 100 * situation, and that different filesystems may want to use 101 * different security flavours. 102 */ 103 static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) 104 { 105 struct vfsmount *mnt; 106 struct nfs_server *server = NFS_SERVER(dentry->d_inode); 107 struct dentry *parent; 108 struct nfs_fh fh; 109 struct nfs_fattr fattr; 110 int err; 111 112 dprintk("--> nfs_follow_mountpoint()\n"); 113 114 err = -ESTALE; 115 if (IS_ROOT(dentry)) 116 goto out_err; 117 118 dprintk("%s: enter\n", __func__); 119 dput(nd->path.dentry); 120 nd->path.dentry = dget(dentry); 121 122 /* Look it up again */ 123 parent = dget_parent(nd->path.dentry); 124 err = server->nfs_client->rpc_ops->lookup(parent->d_inode, 125 &nd->path.dentry->d_name, 126 &fh, &fattr); 127 dput(parent); 128 if (err != 0) 129 goto out_err; 130 131 if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) 132 mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); 133 else 134 mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, &fh, 135 &fattr); 136 err = PTR_ERR(mnt); 137 if (IS_ERR(mnt)) 138 goto out_err; 139 140 mntget(mnt); 141 err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, 142 &nfs_automount_list); 143 if (err < 0) { 144 mntput(mnt); 145 if (err == -EBUSY) 146 goto out_follow; 147 goto out_err; 148 } 149 path_put(&nd->path); 150 nd->path.mnt = mnt; 151 nd->path.dentry = dget(mnt->mnt_root); 152 schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); 153 out: 154 dprintk("%s: done, returned %d\n", __func__, err); 155 156 dprintk("<-- nfs_follow_mountpoint() = %d\n", err); 157 return ERR_PTR(err); 158 out_err: 159 path_put(&nd->path); 160 goto out; 161 out_follow: 162 while (d_mountpoint(nd->path.dentry) && 163 follow_down(&nd->path)) 164 ; 165 err = 0; 166 goto out; 167 } 168 169 const struct inode_operations nfs_mountpoint_inode_operations = { 170 .follow_link = nfs_follow_mountpoint, 171 .getattr = nfs_getattr, 172 }; 173 174 const struct inode_operations nfs_referral_inode_operations = { 175 .follow_link = nfs_follow_mountpoint, 176 }; 177 178 static void nfs_expire_automounts(struct work_struct *work) 179 { 180 struct list_head *list = &nfs_automount_list; 181 182 mark_mounts_for_expiry(list); 183 if (!list_empty(list)) 184 schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); 185 } 186 187 void nfs_release_automount_timer(void) 188 { 189 if (list_empty(&nfs_automount_list)) 190 cancel_delayed_work(&nfs_automount_task); 191 } 192 193 /* 194 * Clone a mountpoint of the appropriate type 195 */ 196 static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, 197 const char *devname, 198 struct nfs_clone_mount *mountdata) 199 { 200 #ifdef CONFIG_NFS_V4 201 struct vfsmount *mnt = ERR_PTR(-EINVAL); 202 switch (server->nfs_client->rpc_ops->version) { 203 case 2: 204 case 3: 205 mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); 206 break; 207 case 4: 208 mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata); 209 } 210 return mnt; 211 #else 212 return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata); 213 #endif 214 } 215 216 /** 217 * nfs_do_submount - set up mountpoint when crossing a filesystem boundary 218 * @mnt_parent - mountpoint of parent directory 219 * @dentry - parent directory 220 * @fh - filehandle for new root dentry 221 * @fattr - attributes for new root inode 222 * 223 */ 224 static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, 225 const struct dentry *dentry, 226 struct nfs_fh *fh, 227 struct nfs_fattr *fattr) 228 { 229 struct nfs_clone_mount mountdata = { 230 .sb = mnt_parent->mnt_sb, 231 .dentry = dentry, 232 .fh = fh, 233 .fattr = fattr, 234 }; 235 struct vfsmount *mnt = ERR_PTR(-ENOMEM); 236 char *page = (char *) __get_free_page(GFP_USER); 237 char *devname; 238 239 dprintk("--> nfs_do_submount()\n"); 240 241 dprintk("%s: submounting on %s/%s\n", __func__, 242 dentry->d_parent->d_name.name, 243 dentry->d_name.name); 244 if (page == NULL) 245 goto out; 246 devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); 247 mnt = (struct vfsmount *)devname; 248 if (IS_ERR(devname)) 249 goto free_page; 250 mnt = nfs_do_clone_mount(NFS_SB(mnt_parent->mnt_sb), devname, &mountdata); 251 free_page: 252 free_page((unsigned long)page); 253 out: 254 dprintk("%s: done\n", __func__); 255 256 dprintk("<-- nfs_do_submount() = %p\n", mnt); 257 return mnt; 258 } 259