diff options
Diffstat (limited to 'fs/afs/mntpt.c')
| -rw-r--r-- | fs/afs/mntpt.c | 78 |
1 files changed, 55 insertions, 23 deletions
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index a9e23039ea34..6d552686c498 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -38,6 +38,11 @@ const struct inode_operations afs_mntpt_inode_operations = { | |||
| 38 | .getattr = afs_getattr, | 38 | .getattr = afs_getattr, |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | const struct inode_operations afs_autocell_inode_operations = { | ||
| 42 | .follow_link = afs_mntpt_follow_link, | ||
| 43 | .getattr = afs_getattr, | ||
| 44 | }; | ||
| 45 | |||
| 41 | static LIST_HEAD(afs_vfsmounts); | 46 | static LIST_HEAD(afs_vfsmounts); |
| 42 | static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); | 47 | static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); |
| 43 | 48 | ||
| @@ -136,20 +141,16 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
| 136 | { | 141 | { |
| 137 | struct afs_super_info *super; | 142 | struct afs_super_info *super; |
| 138 | struct vfsmount *mnt; | 143 | struct vfsmount *mnt; |
| 144 | struct afs_vnode *vnode; | ||
| 139 | struct page *page; | 145 | struct page *page; |
| 140 | size_t size; | 146 | char *devname, *options; |
| 141 | char *buf, *devname, *options; | 147 | bool rwpath = false; |
| 142 | int ret; | 148 | int ret; |
| 143 | 149 | ||
| 144 | _enter("{%s}", mntpt->d_name.name); | 150 | _enter("{%s}", mntpt->d_name.name); |
| 145 | 151 | ||
| 146 | BUG_ON(!mntpt->d_inode); | 152 | BUG_ON(!mntpt->d_inode); |
| 147 | 153 | ||
| 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 | ret = -ENOMEM; |
| 154 | devname = (char *) get_zeroed_page(GFP_KERNEL); | 155 | devname = (char *) get_zeroed_page(GFP_KERNEL); |
| 155 | if (!devname) | 156 | if (!devname) |
| @@ -159,28 +160,59 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
| 159 | if (!options) | 160 | if (!options) |
| 160 | goto error_no_options; | 161 | goto error_no_options; |
| 161 | 162 | ||
| 162 | /* read the contents of the AFS special symlink */ | 163 | vnode = AFS_FS_I(mntpt->d_inode); |
| 163 | page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); | 164 | if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) { |
| 164 | if (IS_ERR(page)) { | 165 | /* if the directory is a pseudo directory, use the d_name */ |
| 165 | ret = PTR_ERR(page); | 166 | static const char afs_root_cell[] = ":root.cell."; |
| 166 | goto error_no_page; | 167 | unsigned size = mntpt->d_name.len; |
| 168 | |||
| 169 | ret = -ENOENT; | ||
| 170 | if (size < 2 || size > AFS_MAXCELLNAME) | ||
| 171 | goto error_no_page; | ||
| 172 | |||
| 173 | if (mntpt->d_name.name[0] == '.') { | ||
| 174 | devname[0] = '#'; | ||
| 175 | memcpy(devname + 1, mntpt->d_name.name, size - 1); | ||
| 176 | memcpy(devname + size, afs_root_cell, | ||
| 177 | sizeof(afs_root_cell)); | ||
| 178 | rwpath = true; | ||
| 179 | } else { | ||
| 180 | devname[0] = '%'; | ||
| 181 | memcpy(devname + 1, mntpt->d_name.name, size); | ||
| 182 | memcpy(devname + size + 1, afs_root_cell, | ||
| 183 | sizeof(afs_root_cell)); | ||
| 184 | } | ||
| 185 | } else { | ||
| 186 | /* read the contents of the AFS special symlink */ | ||
| 187 | loff_t size = i_size_read(mntpt->d_inode); | ||
| 188 | char *buf; | ||
| 189 | |||
| 190 | ret = -EINVAL; | ||
| 191 | if (size > PAGE_SIZE - 1) | ||
| 192 | goto error_no_page; | ||
| 193 | |||
| 194 | page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); | ||
| 195 | if (IS_ERR(page)) { | ||
| 196 | ret = PTR_ERR(page); | ||
| 197 | goto error_no_page; | ||
| 198 | } | ||
| 199 | |||
| 200 | ret = -EIO; | ||
| 201 | if (PageError(page)) | ||
| 202 | goto error; | ||
| 203 | |||
| 204 | buf = kmap_atomic(page, KM_USER0); | ||
| 205 | memcpy(devname, buf, size); | ||
| 206 | kunmap_atomic(buf, KM_USER0); | ||
| 207 | page_cache_release(page); | ||
| 208 | page = NULL; | ||
| 167 | } | 209 | } |
| 168 | 210 | ||
| 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 */ | 211 | /* work out what options we want */ |
| 180 | super = AFS_FS_S(mntpt->d_sb); | 212 | super = AFS_FS_S(mntpt->d_sb); |
| 181 | memcpy(options, "cell=", 5); | 213 | memcpy(options, "cell=", 5); |
| 182 | strcpy(options + 5, super->volume->cell->name); | 214 | strcpy(options + 5, super->volume->cell->name); |
| 183 | if (super->volume->type == AFSVL_RWVOL) | 215 | if (super->volume->type == AFSVL_RWVOL || rwpath) |
| 184 | strcat(options, ",rwpath"); | 216 | strcat(options, ",rwpath"); |
| 185 | 217 | ||
| 186 | /* try and do the mount */ | 218 | /* try and do the mount */ |
