2 * linux/fs/nfs/namespace.c
4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
5 * - Modified by David Howells <dhowells@redhat.com>
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 <linux/sunrpc/gss_api.h>
21 #define NFSDBG_FACILITY NFSDBG_VFS
23 static void nfs_expire_automounts(struct work_struct
*work
);
25 static LIST_HEAD(nfs_automount_list
);
26 static DECLARE_DELAYED_WORK(nfs_automount_task
, nfs_expire_automounts
);
27 int nfs_mountpoint_expiry_timeout
= 500 * HZ
;
30 * nfs_path - reconstruct the path given an arbitrary dentry
31 * @base - used to return pointer to the end of devname part of path
32 * @dentry - pointer to dentry
33 * @buffer - result buffer
34 * @buflen - length of buffer
36 * Helper function for constructing the server pathname
37 * by arbitrary hashed dentry.
39 * This is mainly for use in figuring out the path on the
40 * server side when automounting on top of an existing partition
41 * and in generating /proc/mounts and friends.
43 char *nfs_path(char **p
, struct dentry
*dentry
, char *buffer
, ssize_t buflen
)
55 seq
= read_seqbegin(&rename_lock
);
58 spin_lock(&dentry
->d_lock
);
61 namelen
= dentry
->d_name
.len
;
62 buflen
-= namelen
+ 1;
66 memcpy(end
, dentry
->d_name
.name
, namelen
);
68 spin_unlock(&dentry
->d_lock
);
69 dentry
= dentry
->d_parent
;
71 if (read_seqretry(&rename_lock
, seq
)) {
72 spin_unlock(&dentry
->d_lock
);
78 spin_unlock(&dentry
->d_lock
);
85 base
= dentry
->d_fsdata
;
87 spin_unlock(&dentry
->d_lock
);
92 namelen
= strlen(base
);
93 /* Strip off excess slashes in base string */
94 while (namelen
> 0 && base
[namelen
- 1] == '/')
98 spin_unlock(&dentry
->d_lock
);
103 memcpy(end
, base
, namelen
);
104 spin_unlock(&dentry
->d_lock
);
108 spin_unlock(&dentry
->d_lock
);
110 if (read_seqretry(&rename_lock
, seq
))
113 return ERR_PTR(-ENAMETOOLONG
);
117 * nfs_d_automount - Handle crossing a mountpoint on the server
118 * @path - The mountpoint
120 * When we encounter a mountpoint on the server, we want to set up
121 * a mountpoint on the client too, to prevent inode numbers from
122 * colliding, and to allow "df" to work properly.
123 * On NFSv4, we also want to allow for the fact that different
124 * filesystems may be migrated to different servers in a failover
125 * situation, and that different filesystems may want to use
126 * different security flavours.
128 struct vfsmount
*nfs_d_automount(struct path
*path
)
130 struct vfsmount
*mnt
;
131 struct nfs_server
*server
= NFS_SERVER(path
->dentry
->d_inode
);
132 struct nfs_fh
*fh
= NULL
;
133 struct nfs_fattr
*fattr
= NULL
;
135 dprintk("--> nfs_d_automount()\n");
137 mnt
= ERR_PTR(-ESTALE
);
138 if (IS_ROOT(path
->dentry
))
141 mnt
= ERR_PTR(-ENOMEM
);
142 fh
= nfs_alloc_fhandle();
143 fattr
= nfs_alloc_fattr();
144 if (fh
== NULL
|| fattr
== NULL
)
147 dprintk("%s: enter\n", __func__
);
149 mnt
= server
->nfs_client
->rpc_ops
->submount(server
, path
->dentry
, fh
, fattr
);
153 dprintk("%s: done, success\n", __func__
);
154 mntget(mnt
); /* prevent immediate expiration */
155 mnt_set_expiry(mnt
, &nfs_automount_list
);
156 schedule_delayed_work(&nfs_automount_task
, nfs_mountpoint_expiry_timeout
);
159 nfs_free_fattr(fattr
);
160 nfs_free_fhandle(fh
);
163 dprintk("<-- %s(): error %ld\n", __func__
, PTR_ERR(mnt
));
165 dprintk("<-- %s() = %p\n", __func__
, mnt
);
169 const struct inode_operations nfs_mountpoint_inode_operations
= {
170 .getattr
= nfs_getattr
,
173 const struct inode_operations nfs_referral_inode_operations
= {
176 static void nfs_expire_automounts(struct work_struct
*work
)
178 struct list_head
*list
= &nfs_automount_list
;
180 mark_mounts_for_expiry(list
);
181 if (!list_empty(list
))
182 schedule_delayed_work(&nfs_automount_task
, nfs_mountpoint_expiry_timeout
);
185 void nfs_release_automount_timer(void)
187 if (list_empty(&nfs_automount_list
))
188 cancel_delayed_work(&nfs_automount_task
);
192 * Clone a mountpoint of the appropriate type
194 static struct vfsmount
*nfs_do_clone_mount(struct nfs_server
*server
,
196 struct nfs_clone_mount
*mountdata
)
199 struct vfsmount
*mnt
= ERR_PTR(-EINVAL
);
200 switch (server
->nfs_client
->rpc_ops
->version
) {
203 mnt
= vfs_kern_mount(&nfs_xdev_fs_type
, 0, devname
, mountdata
);
206 mnt
= vfs_kern_mount(&nfs4_xdev_fs_type
, 0, devname
, mountdata
);
210 return vfs_kern_mount(&nfs_xdev_fs_type
, 0, devname
, mountdata
);
215 * nfs_do_submount - set up mountpoint when crossing a filesystem boundary
216 * @dentry - parent directory
217 * @fh - filehandle for new root dentry
218 * @fattr - attributes for new root inode
219 * @authflavor - security flavor to use when performing the mount
222 struct vfsmount
*nfs_do_submount(struct dentry
*dentry
, struct nfs_fh
*fh
,
223 struct nfs_fattr
*fattr
, rpc_authflavor_t authflavor
)
225 struct nfs_clone_mount mountdata
= {
230 .authflavor
= authflavor
,
232 struct vfsmount
*mnt
= ERR_PTR(-ENOMEM
);
233 char *page
= (char *) __get_free_page(GFP_USER
);
236 dprintk("--> nfs_do_submount()\n");
238 dprintk("%s: submounting on %s/%s\n", __func__
,
239 dentry
->d_parent
->d_name
.name
,
240 dentry
->d_name
.name
);
243 devname
= nfs_devname(dentry
, page
, PAGE_SIZE
);
244 mnt
= (struct vfsmount
*)devname
;
247 mnt
= nfs_do_clone_mount(NFS_SB(dentry
->d_sb
), devname
, &mountdata
);
249 free_page((unsigned long)page
);
251 dprintk("%s: done\n", __func__
);
253 dprintk("<-- nfs_do_submount() = %p\n", mnt
);
257 struct vfsmount
*nfs_submount(struct nfs_server
*server
, struct dentry
*dentry
,
258 struct nfs_fh
*fh
, struct nfs_fattr
*fattr
)
261 struct dentry
*parent
= dget_parent(dentry
);
263 /* Look it up again to get its attributes */
264 err
= server
->nfs_client
->rpc_ops
->lookup(parent
->d_inode
, &dentry
->d_name
, fh
, fattr
);
269 return nfs_do_submount(dentry
, fh
, fattr
, server
->client
->cl_auth
->au_flavor
);