2 * linux/fs/nfs/namespace.c
4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
9 #include <linux/config.h>
11 #include <linux/dcache.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>
19 #define NFSDBG_FACILITY NFSDBG_VFS
21 LIST_HEAD(nfs_automount_list
);
22 static void nfs_expire_automounts(void *list
);
23 static DECLARE_WORK(nfs_automount_task
, nfs_expire_automounts
, &nfs_automount_list
);
24 int nfs_mountpoint_expiry_timeout
= 500 * HZ
;
27 * nfs_follow_mountpoint - handle crossing a mountpoint on the server
28 * @dentry - dentry of mountpoint
29 * @nd - nameidata info
31 * When we encounter a mountpoint on the server, we want to set up
32 * a mountpoint on the client too, to prevent inode numbers from
33 * colliding, and to allow "df" to work properly.
34 * On NFSv4, we also want to allow for the fact that different
35 * filesystems may be migrated to different servers in a failover
36 * situation, and that different filesystems may want to use
37 * different security flavours.
39 static void * nfs_follow_mountpoint(struct dentry
*dentry
, struct nameidata
*nd
)
42 struct nfs_server
*server
= NFS_SERVER(dentry
->d_inode
);
43 struct dentry
*parent
;
45 struct nfs_fattr fattr
;
48 BUG_ON(IS_ROOT(dentry
));
49 dprintk("%s: enter\n", __FUNCTION__
);
51 nd
->dentry
= dget(dentry
);
52 if (d_mountpoint(nd
->dentry
))
54 /* Look it up again */
55 parent
= dget_parent(nd
->dentry
);
56 err
= server
->rpc_ops
->lookup(parent
->d_inode
, &nd
->dentry
->d_name
, &fh
, &fattr
);
61 if (fattr
.valid
& NFS_ATTR_FATTR_V4_REFERRAL
)
62 mnt
= nfs_do_refmount(nd
->mnt
, nd
->dentry
);
64 mnt
= nfs_do_submount(nd
->mnt
, nd
->dentry
, &fh
, &fattr
);
70 err
= do_add_mount(mnt
, nd
, nd
->mnt
->mnt_flags
|MNT_SHRINKABLE
, &nfs_automount_list
);
80 nd
->dentry
= dget(mnt
->mnt_root
);
81 schedule_delayed_work(&nfs_automount_task
, nfs_mountpoint_expiry_timeout
);
83 dprintk("%s: done, returned %d\n", __FUNCTION__
, err
);
89 while(d_mountpoint(nd
->dentry
) && follow_down(&nd
->mnt
, &nd
->dentry
))
95 struct inode_operations nfs_mountpoint_inode_operations
= {
96 .follow_link
= nfs_follow_mountpoint
,
97 .getattr
= nfs_getattr
,
100 struct inode_operations nfs_referral_inode_operations
= {
101 .follow_link
= nfs_follow_mountpoint
,
104 static void nfs_expire_automounts(void *data
)
106 struct list_head
*list
= (struct list_head
*)data
;
108 mark_mounts_for_expiry(list
);
109 if (!list_empty(list
))
110 schedule_delayed_work(&nfs_automount_task
, nfs_mountpoint_expiry_timeout
);
113 void nfs_release_automount_timer(void)
115 if (list_empty(&nfs_automount_list
)) {
116 cancel_delayed_work(&nfs_automount_task
);
117 flush_scheduled_work();