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 }; 33 34 const struct inode_operations afs_mntpt_inode_operations = { 35 .lookup = afs_mntpt_lookup, 36 .follow_link = afs_mntpt_follow_link, 37 .readlink = page_readlink, 38 .getattr = afs_getattr, 39 }; 40 41 static LIST_HEAD(afs_vfsmounts); 42 static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); 43 44 static unsigned long afs_mntpt_expiry_timeout = 10 * 60; 45 46 /* 47 * check a symbolic link to see whether it actually encodes a mountpoint 48 * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately 49 */ 50 int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) 51 { 52 struct page *page; 53 size_t size; 54 char *buf; 55 int ret; 56 57 _enter("{%x:%u,%u}", 58 vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); 59 60 /* read the contents of the symlink into the pagecache */ 61 page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, 62 afs_page_filler, key); 63 if (IS_ERR(page)) { 64 ret = PTR_ERR(page); 65 goto out; 66 } 67 68 ret = -EIO; 69 if (PageError(page)) 70 goto out_free; 71 72 buf = kmap(page); 73 74 /* examine the symlink's contents */ 75 size = vnode->status.size; 76 _debug("symlink to %*.*s", (int) size, (int) size, buf); 77 78 if (size > 2 && 79 (buf[0] == '%' || buf[0] == '#') && 80 buf[size - 1] == '.' 81 ) { 82 _debug("symlink is a mountpoint"); 83 spin_lock(&vnode->lock); 84 set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); 85 spin_unlock(&vnode->lock); 86 } 87 88 ret = 0; 89 90 kunmap(page); 91 out_free: 92 page_cache_release(page); 93 out: 94 _leave(" = %d", ret); 95 return ret; 96 } 97 98 /* 99 * no valid lookup procedure on this sort of dir 100 */ 101 static struct dentry *afs_mntpt_lookup(struct inode *dir, 102 struct dentry *dentry, 103 struct nameidata *nd) 104 { 105 _enter("%p,%p{%p{%s},%s}", 106 dir, 107 dentry, 108 dentry->d_parent, 109 dentry->d_parent ? 110 dentry->d_parent->d_name.name : (const unsigned char *) "", 111 dentry->d_name.name); 112 113 return ERR_PTR(-EREMOTE); 114 } 115 116 /* 117 * no valid open procedure on this sort of dir 118 */ 119 static int afs_mntpt_open(struct inode *inode, struct file *file) 120 { 121 _enter("%p,%p{%p{%s},%s}", 122 inode, file, 123 file->f_path.dentry->d_parent, 124 file->f_path.dentry->d_parent ? 125 file->f_path.dentry->d_parent->d_name.name : 126 (const unsigned char *) "", 127 file->f_path.dentry->d_name.name); 128 129 return -EREMOTE; 130 } 131 132 /* 133 * create a vfsmount to be automounted 134 */ 135 static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) 136 { 137 struct afs_super_info *super; 138 struct vfsmount *mnt; 139 struct page *page; 140 size_t size; 141 char *buf, *devname, *options; 142 int ret; 143 144 _enter("{%s}", mntpt->d_name.name); 145 146 BUG_ON(!mntpt->d_inode); 147 148 ret = -EINVAL; 149 size = mntpt->d_inode->i_size; 150 if (size > PAGE_SIZE - 1) 151 goto error_no_devname; 152 153 ret = -ENOMEM; 154 devname = (char *) get_zeroed_page(GFP_KERNEL); 155 if (!devname) 156 goto error_no_devname; 157 158 options = (char *) get_zeroed_page(GFP_KERNEL); 159 if (!options) 160 goto error_no_options; 161 162 /* read the contents of the AFS special symlink */ 163 page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); 164 if (IS_ERR(page)) { 165 ret = PTR_ERR(page); 166 goto error_no_page; 167 } 168 169 ret = -EIO; 170 if (PageError(page)) 171 goto error; 172 173 buf = kmap_atomic(page, KM_USER0); 174 memcpy(devname, buf, size); 175 kunmap_atomic(buf, KM_USER0); 176 page_cache_release(page); 177 page = NULL; 178 179 /* work out what options we want */ 180 super = AFS_FS_S(mntpt->d_sb); 181 memcpy(options, "cell=", 5); 182 strcpy(options + 5, super->volume->cell->name); 183 if (super->volume->type == AFSVL_RWVOL) 184 strcat(options, ",rwpath"); 185 186 /* try and do the mount */ 187 _debug("--- attempting mount %s -o %s ---", devname, options); 188 mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); 189 _debug("--- mount result %p ---", mnt); 190 191 free_page((unsigned long) devname); 192 free_page((unsigned long) options); 193 _leave(" = %p", mnt); 194 return mnt; 195 196 error: 197 page_cache_release(page); 198 error_no_page: 199 free_page((unsigned long) options); 200 error_no_options: 201 free_page((unsigned long) devname); 202 error_no_devname: 203 _leave(" = %d", ret); 204 return ERR_PTR(ret); 205 } 206 207 /* 208 * follow a link from a mountpoint directory, thus causing it to be mounted 209 */ 210 static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) 211 { 212 struct vfsmount *newmnt; 213 int err; 214 215 _enter("%p{%s},{%s:%p{%s},}", 216 dentry, 217 dentry->d_name.name, 218 nd->path.mnt->mnt_devname, 219 dentry, 220 nd->path.dentry->d_name.name); 221 222 dput(nd->path.dentry); 223 nd->path.dentry = dget(dentry); 224 225 newmnt = afs_mntpt_do_automount(nd->path.dentry); 226 if (IS_ERR(newmnt)) { 227 path_put(&nd->path); 228 return (void *)newmnt; 229 } 230 231 mntget(newmnt); 232 err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts); 233 switch (err) { 234 case 0: 235 path_put(&nd->path); 236 nd->path.mnt = newmnt; 237 nd->path.dentry = dget(newmnt->mnt_root); 238 schedule_delayed_work(&afs_mntpt_expiry_timer, 239 afs_mntpt_expiry_timeout * HZ); 240 break; 241 case -EBUSY: 242 /* someone else made a mount here whilst we were busy */ 243 while (d_mountpoint(nd->path.dentry) && 244 follow_down(&nd->path)) 245 ; 246 err = 0; 247 default: 248 mntput(newmnt); 249 break; 250 } 251 252 _leave(" = %d", err); 253 return ERR_PTR(err); 254 } 255 256 /* 257 * handle mountpoint expiry timer going off 258 */ 259 static void afs_mntpt_expiry_timed_out(struct work_struct *work) 260 { 261 _enter(""); 262 263 if (!list_empty(&afs_vfsmounts)) { 264 mark_mounts_for_expiry(&afs_vfsmounts); 265 schedule_delayed_work(&afs_mntpt_expiry_timer, 266 afs_mntpt_expiry_timeout * HZ); 267 } 268 269 _leave(""); 270 } 271 272 /* 273 * kill the AFS mountpoint timer if it's still running 274 */ 275 void afs_mntpt_kill_timer(void) 276 { 277 _enter(""); 278 279 ASSERT(list_empty(&afs_vfsmounts)); 280 cancel_delayed_work(&afs_mntpt_expiry_timer); 281 flush_scheduled_work(); 282 } 283