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 */ |