Merge branch 'next' into upstream-merge
[pandora-kernel.git] / fs / afs / mntpt.c
1 /* mountpoint management
2  *
3  * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/fs.h>
16 #include <linux/pagemap.h>
17 #include <linux/mount.h>
18 #include <linux/namei.h>
19 #include <linux/gfp.h>
20 #include "internal.h"
21
22
23 static struct dentry *afs_mntpt_lookup(struct inode *dir,
24                                        struct dentry *dentry,
25                                        struct nameidata *nd);
26 static int afs_mntpt_open(struct inode *inode, struct file *file);
27 static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
28 static void afs_mntpt_expiry_timed_out(struct work_struct *work);
29
30 const struct file_operations afs_mntpt_file_operations = {
31         .open           = afs_mntpt_open,
32         .llseek         = noop_llseek,
33 };
34
35 const struct inode_operations afs_mntpt_inode_operations = {
36         .lookup         = afs_mntpt_lookup,
37         .follow_link    = afs_mntpt_follow_link,
38         .readlink       = page_readlink,
39         .getattr        = afs_getattr,
40 };
41
42 const struct inode_operations afs_autocell_inode_operations = {
43         .follow_link    = afs_mntpt_follow_link,
44         .getattr        = afs_getattr,
45 };
46
47 static LIST_HEAD(afs_vfsmounts);
48 static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
49
50 static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
51
52 /*
53  * check a symbolic link to see whether it actually encodes a mountpoint
54  * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately
55  */
56 int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
57 {
58         struct page *page;
59         size_t size;
60         char *buf;
61         int ret;
62
63         _enter("{%x:%u,%u}",
64                vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
65
66         /* read the contents of the symlink into the pagecache */
67         page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0,
68                                afs_page_filler, key);
69         if (IS_ERR(page)) {
70                 ret = PTR_ERR(page);
71                 goto out;
72         }
73
74         ret = -EIO;
75         if (PageError(page))
76                 goto out_free;
77
78         buf = kmap(page);
79
80         /* examine the symlink's contents */
81         size = vnode->status.size;
82         _debug("symlink to %*.*s", (int) size, (int) size, buf);
83
84         if (size > 2 &&
85             (buf[0] == '%' || buf[0] == '#') &&
86             buf[size - 1] == '.'
87             ) {
88                 _debug("symlink is a mountpoint");
89                 spin_lock(&vnode->lock);
90                 set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
91                 spin_unlock(&vnode->lock);
92         }
93
94         ret = 0;
95
96         kunmap(page);
97 out_free:
98         page_cache_release(page);
99 out:
100         _leave(" = %d", ret);
101         return ret;
102 }
103
104 /*
105  * no valid lookup procedure on this sort of dir
106  */
107 static struct dentry *afs_mntpt_lookup(struct inode *dir,
108                                        struct dentry *dentry,
109                                        struct nameidata *nd)
110 {
111         _enter("%p,%p{%p{%s},%s}",
112                dir,
113                dentry,
114                dentry->d_parent,
115                dentry->d_parent ?
116                dentry->d_parent->d_name.name : (const unsigned char *) "",
117                dentry->d_name.name);
118
119         return ERR_PTR(-EREMOTE);
120 }
121
122 /*
123  * no valid open procedure on this sort of dir
124  */
125 static int afs_mntpt_open(struct inode *inode, struct file *file)
126 {
127         _enter("%p,%p{%p{%s},%s}",
128                inode, file,
129                file->f_path.dentry->d_parent,
130                file->f_path.dentry->d_parent ?
131                file->f_path.dentry->d_parent->d_name.name :
132                (const unsigned char *) "",
133                file->f_path.dentry->d_name.name);
134
135         return -EREMOTE;
136 }
137
138 /*
139  * create a vfsmount to be automounted
140  */
141 static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
142 {
143         struct afs_super_info *super;
144         struct vfsmount *mnt;
145         struct afs_vnode *vnode;
146         struct page *page;
147         char *devname, *options;
148         bool rwpath = false;
149         int ret;
150
151         _enter("{%s}", mntpt->d_name.name);
152
153         BUG_ON(!mntpt->d_inode);
154
155         ret = -ENOMEM;
156         devname = (char *) get_zeroed_page(GFP_KERNEL);
157         if (!devname)
158                 goto error_no_devname;
159
160         options = (char *) get_zeroed_page(GFP_KERNEL);
161         if (!options)
162                 goto error_no_options;
163
164         vnode = AFS_FS_I(mntpt->d_inode);
165         if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) {
166                 /* if the directory is a pseudo directory, use the d_name */
167                 static const char afs_root_cell[] = ":root.cell.";
168                 unsigned size = mntpt->d_name.len;
169
170                 ret = -ENOENT;
171                 if (size < 2 || size > AFS_MAXCELLNAME)
172                         goto error_no_page;
173
174                 if (mntpt->d_name.name[0] == '.') {
175                         devname[0] = '#';
176                         memcpy(devname + 1, mntpt->d_name.name, size - 1);
177                         memcpy(devname + size, afs_root_cell,
178                                sizeof(afs_root_cell));
179                         rwpath = true;
180                 } else {
181                         devname[0] = '%';
182                         memcpy(devname + 1, mntpt->d_name.name, size);
183                         memcpy(devname + size + 1, afs_root_cell,
184                                sizeof(afs_root_cell));
185                 }
186         } else {
187                 /* read the contents of the AFS special symlink */
188                 loff_t size = i_size_read(mntpt->d_inode);
189                 char *buf;
190
191                 ret = -EINVAL;
192                 if (size > PAGE_SIZE - 1)
193                         goto error_no_page;
194
195                 page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL);
196                 if (IS_ERR(page)) {
197                         ret = PTR_ERR(page);
198                         goto error_no_page;
199                 }
200
201                 ret = -EIO;
202                 if (PageError(page))
203                         goto error;
204
205                 buf = kmap_atomic(page, KM_USER0);
206                 memcpy(devname, buf, size);
207                 kunmap_atomic(buf, KM_USER0);
208                 page_cache_release(page);
209                 page = NULL;
210         }
211
212         /* work out what options we want */
213         super = AFS_FS_S(mntpt->d_sb);
214         memcpy(options, "cell=", 5);
215         strcpy(options + 5, super->volume->cell->name);
216         if (super->volume->type == AFSVL_RWVOL || rwpath)
217                 strcat(options, ",rwpath");
218
219         /* try and do the mount */
220         _debug("--- attempting mount %s -o %s ---", devname, options);
221         mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
222         _debug("--- mount result %p ---", mnt);
223
224         free_page((unsigned long) devname);
225         free_page((unsigned long) options);
226         _leave(" = %p", mnt);
227         return mnt;
228
229 error:
230         page_cache_release(page);
231 error_no_page:
232         free_page((unsigned long) options);
233 error_no_options:
234         free_page((unsigned long) devname);
235 error_no_devname:
236         _leave(" = %d", ret);
237         return ERR_PTR(ret);
238 }
239
240 /*
241  * follow a link from a mountpoint directory, thus causing it to be mounted
242  */
243 static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
244 {
245         struct vfsmount *newmnt;
246         int err;
247
248         _enter("%p{%s},{%s:%p{%s},}",
249                dentry,
250                dentry->d_name.name,
251                nd->path.mnt->mnt_devname,
252                dentry,
253                nd->path.dentry->d_name.name);
254
255         dput(nd->path.dentry);
256         nd->path.dentry = dget(dentry);
257
258         newmnt = afs_mntpt_do_automount(nd->path.dentry);
259         if (IS_ERR(newmnt)) {
260                 path_put(&nd->path);
261                 return (void *)newmnt;
262         }
263
264         mntget(newmnt);
265         err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts);
266         switch (err) {
267         case 0:
268                 path_put(&nd->path);
269                 nd->path.mnt = newmnt;
270                 nd->path.dentry = dget(newmnt->mnt_root);
271                 schedule_delayed_work(&afs_mntpt_expiry_timer,
272                                       afs_mntpt_expiry_timeout * HZ);
273                 break;
274         case -EBUSY:
275                 /* someone else made a mount here whilst we were busy */
276                 while (d_mountpoint(nd->path.dentry) &&
277                        follow_down(&nd->path))
278                         ;
279                 err = 0;
280         default:
281                 mntput(newmnt);
282                 break;
283         }
284
285         _leave(" = %d", err);
286         return ERR_PTR(err);
287 }
288
289 /*
290  * handle mountpoint expiry timer going off
291  */
292 static void afs_mntpt_expiry_timed_out(struct work_struct *work)
293 {
294         _enter("");
295
296         if (!list_empty(&afs_vfsmounts)) {
297                 mark_mounts_for_expiry(&afs_vfsmounts);
298                 schedule_delayed_work(&afs_mntpt_expiry_timer,
299                                       afs_mntpt_expiry_timeout * HZ);
300         }
301
302         _leave("");
303 }
304
305 /*
306  * kill the AFS mountpoint timer if it's still running
307  */
308 void afs_mntpt_kill_timer(void)
309 {
310         _enter("");
311
312         ASSERT(list_empty(&afs_vfsmounts));
313         cancel_delayed_work(&afs_mntpt_expiry_timer);
314         flush_scheduled_work();
315 }