aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwanglei <wang840925@gmail.com>2010-08-11 04:38:04 -0400
committerSteve French <sfrench@us.ibm.com>2010-08-11 13:11:29 -0400
commitbec5eb6141308a30a73682330cb045a40e442b8c (patch)
treeae514575d62e65a07d6089746fbd880f816ee382
parent4a2d789267e00b5a1175ecd2ddefcc78b83fbf09 (diff)
AFS: Implement an autocell mount capability [ver #2]
Implement the ability for the root directory of a mounted AFS filesystem to accept lookups of arbitrary directory names, to interpet the names as the names of cells, to look the cell names up in the DNS for AFSDB records and to mount the root.cell volume of the nominated cell on the pseudo-directory created by lookup. This facility is requested by passing: -o autocell to the mountpoint for which this is desired, usually the /afs mount. To use this facility, a DNS upcall program is required for AFSDB records. This can be obtained from: http://people.redhat.com/~dhowells/afs/dns.afsdb.c It should be compiled with -lresolv and -lkeyutils and installed as, say: /usr/sbin/dns.afsdb Then the following line needs to be added to /sbin/request-key.conf: create dns_resolver afsdb:* * /usr/sbin/dns.afsdb %k This can be tested by mounting AFS, say: insmod dns_resolver.ko insmod af-rxrpc.ko insmod kafs.ko rootcell=grand.central.org mount -t afs "#grand.central.org:root.cell." /afs -o autocell and doing: ls /afs/grand.central.org/ which should show: archive/ cvs/ doc/ local/ project/ service/ software/ user/ www/ if it works. Signed-off-by: Wang Lei <wang840925@gmail.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/afs/cell.c52
-rw-r--r--fs/afs/dir.c47
-rw-r--r--fs/afs/inode.c86
-rw-r--r--fs/afs/internal.h11
-rw-r--r--fs/afs/mntpt.c78
-rw-r--r--fs/afs/proc.c2
-rw-r--r--fs/afs/super.c20
7 files changed, 250 insertions, 46 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index d0765883430e..0d5eeadf6121 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -31,21 +31,20 @@ static struct afs_cell *afs_cell_root;
31 * allocate a cell record and fill in its name, VL server address list and 31 * allocate a cell record and fill in its name, VL server address list and
32 * allocate an anonymous key 32 * allocate an anonymous key
33 */ 33 */
34static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) 34static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen,
35 char *vllist)
35{ 36{
36 struct afs_cell *cell; 37 struct afs_cell *cell;
37 struct key *key; 38 struct key *key;
38 size_t namelen;
39 char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; 39 char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
40 char *dvllist = NULL, *_vllist = NULL; 40 char *dvllist = NULL, *_vllist = NULL;
41 char delimiter = ':'; 41 char delimiter = ':';
42 int ret; 42 int ret;
43 43
44 _enter("%s,%s", name, vllist); 44 _enter("%*.*s,%s", namelen, namelen, name ?: "", vllist);
45 45
46 BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ 46 BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
47 47
48 namelen = strlen(name);
49 if (namelen > AFS_MAXCELLNAME) { 48 if (namelen > AFS_MAXCELLNAME) {
50 _leave(" = -ENAMETOOLONG"); 49 _leave(" = -ENAMETOOLONG");
51 return ERR_PTR(-ENAMETOOLONG); 50 return ERR_PTR(-ENAMETOOLONG);
@@ -142,26 +141,29 @@ error:
142} 141}
143 142
144/* 143/*
145 * create a cell record 144 * afs_cell_crate() - create a cell record
146 * - "name" is the name of the cell 145 * @name: is the name of the cell.
147 * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format 146 * @namsesz: is the strlen of the cell name.
147 * @vllist: is a colon separated list of IP addresses in "a.b.c.d" format.
148 * @retref: is T to return the cell reference when the cell exists.
148 */ 149 */
149struct afs_cell *afs_cell_create(const char *name, char *vllist) 150struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
151 char *vllist, bool retref)
150{ 152{
151 struct afs_cell *cell; 153 struct afs_cell *cell;
152 int ret; 154 int ret;
153 155
154 _enter("%s,%s", name, vllist); 156 _enter("%*.*s,%s", namesz, namesz, name ?: "", vllist);
155 157
156 down_write(&afs_cells_sem); 158 down_write(&afs_cells_sem);
157 read_lock(&afs_cells_lock); 159 read_lock(&afs_cells_lock);
158 list_for_each_entry(cell, &afs_cells, link) { 160 list_for_each_entry(cell, &afs_cells, link) {
159 if (strcasecmp(cell->name, name) == 0) 161 if (strncasecmp(cell->name, name, namesz) == 0)
160 goto duplicate_name; 162 goto duplicate_name;
161 } 163 }
162 read_unlock(&afs_cells_lock); 164 read_unlock(&afs_cells_lock);
163 165
164 cell = afs_cell_alloc(name, vllist); 166 cell = afs_cell_alloc(name, namesz, vllist);
165 if (IS_ERR(cell)) { 167 if (IS_ERR(cell)) {
166 _leave(" = %ld", PTR_ERR(cell)); 168 _leave(" = %ld", PTR_ERR(cell));
167 up_write(&afs_cells_sem); 169 up_write(&afs_cells_sem);
@@ -201,8 +203,18 @@ error:
201 return ERR_PTR(ret); 203 return ERR_PTR(ret);
202 204
203duplicate_name: 205duplicate_name:
206 if (retref && !IS_ERR(cell))
207 afs_get_cell(cell);
208
204 read_unlock(&afs_cells_lock); 209 read_unlock(&afs_cells_lock);
205 up_write(&afs_cells_sem); 210 up_write(&afs_cells_sem);
211
212 if (retref) {
213 _leave(" = %p", cell);
214 return cell;
215 }
216
217 _leave(" = -EEXIST");
206 return ERR_PTR(-EEXIST); 218 return ERR_PTR(-EEXIST);
207} 219}
208 220
@@ -233,7 +245,7 @@ int afs_cell_init(char *rootcell)
233 *cp++ = 0; 245 *cp++ = 0;
234 246
235 /* allocate a cell record for the root cell */ 247 /* allocate a cell record for the root cell */
236 new_root = afs_cell_create(rootcell, cp); 248 new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false);
237 if (IS_ERR(new_root)) { 249 if (IS_ERR(new_root)) {
238 _leave(" = %ld", PTR_ERR(new_root)); 250 _leave(" = %ld", PTR_ERR(new_root));
239 return PTR_ERR(new_root); 251 return PTR_ERR(new_root);
@@ -253,11 +265,12 @@ int afs_cell_init(char *rootcell)
253/* 265/*
254 * lookup a cell record 266 * lookup a cell record
255 */ 267 */
256struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) 268struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,
269 bool dns_cell)
257{ 270{
258 struct afs_cell *cell; 271 struct afs_cell *cell;
259 272
260 _enter("\"%*.*s\",", namesz, namesz, name ? name : ""); 273 _enter("\"%*.*s\",", namesz, namesz, name ?: "");
261 274
262 down_read(&afs_cells_sem); 275 down_read(&afs_cells_sem);
263 read_lock(&afs_cells_lock); 276 read_lock(&afs_cells_lock);
@@ -271,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
271 } 284 }
272 } 285 }
273 cell = ERR_PTR(-ENOENT); 286 cell = ERR_PTR(-ENOENT);
287 if (dns_cell)
288 goto create_cell;
274 found: 289 found:
275 ; 290 ;
276 } else { 291 } else {
@@ -293,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
293 up_read(&afs_cells_sem); 308 up_read(&afs_cells_sem);
294 _leave(" = %p", cell); 309 _leave(" = %p", cell);
295 return cell; 310 return cell;
311
312create_cell:
313 read_unlock(&afs_cells_lock);
314 up_read(&afs_cells_sem);
315
316 cell = afs_cell_create(name, namesz, NULL, true);
317
318 _leave(" = %p", cell);
319 return cell;
296} 320}
297 321
298#if 0 322#if 0
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index b42d5cc1d6d2..0d38c09bd55e 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -477,6 +477,40 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
477} 477}
478 478
479/* 479/*
480 * Try to auto mount the mountpoint with pseudo directory, if the autocell
481 * operation is setted.
482 */
483static struct inode *afs_try_auto_mntpt(
484 int ret, struct dentry *dentry, struct inode *dir, struct key *key,
485 struct afs_fid *fid)
486{
487 const char *devname = dentry->d_name.name;
488 struct afs_vnode *vnode = AFS_FS_I(dir);
489 struct inode *inode;
490
491 _enter("%d, %p{%s}, {%x:%u}, %p",
492 ret, dentry, devname, vnode->fid.vid, vnode->fid.vnode, key);
493
494 if (ret != -ENOENT ||
495 !test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
496 goto out;
497
498 inode = afs_iget_autocell(dir, devname, strlen(devname), key);
499 if (IS_ERR(inode)) {
500 ret = PTR_ERR(inode);
501 goto out;
502 }
503
504 *fid = AFS_FS_I(inode)->fid;
505 _leave("= %p", inode);
506 return inode;
507
508out:
509 _leave("= %d", ret);
510 return ERR_PTR(ret);
511}
512
513/*
480 * look up an entry in a directory 514 * look up an entry in a directory
481 */ 515 */
482static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, 516static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
@@ -520,6 +554,13 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
520 554
521 ret = afs_do_lookup(dir, dentry, &fid, key); 555 ret = afs_do_lookup(dir, dentry, &fid, key);
522 if (ret < 0) { 556 if (ret < 0) {
557 inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid);
558 if (!IS_ERR(inode)) {
559 key_put(key);
560 goto success;
561 }
562
563 ret = PTR_ERR(inode);
523 key_put(key); 564 key_put(key);
524 if (ret == -ENOENT) { 565 if (ret == -ENOENT) {
525 d_add(dentry, NULL); 566 d_add(dentry, NULL);
@@ -539,6 +580,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
539 return ERR_CAST(inode); 580 return ERR_CAST(inode);
540 } 581 }
541 582
583success:
542 dentry->d_op = &afs_fs_dentry_operations; 584 dentry->d_op = &afs_fs_dentry_operations;
543 585
544 d_add(dentry, inode); 586 d_add(dentry, inode);
@@ -696,8 +738,9 @@ static int afs_d_delete(struct dentry *dentry)
696 goto zap; 738 goto zap;
697 739
698 if (dentry->d_inode && 740 if (dentry->d_inode &&
699 test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags)) 741 (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags) ||
700 goto zap; 742 test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(dentry->d_inode)->flags)))
743 goto zap;
701 744
702 _leave(" = 0 [keep]"); 745 _leave(" = 0 [keep]");
703 return 0; 746 return 0;
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 320ffef11574..0747339011c3 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -19,6 +19,8 @@
19#include <linux/fs.h> 19#include <linux/fs.h>
20#include <linux/pagemap.h> 20#include <linux/pagemap.h>
21#include <linux/sched.h> 21#include <linux/sched.h>
22#include <linux/mount.h>
23#include <linux/namei.h>
22#include "internal.h" 24#include "internal.h"
23 25
24struct afs_iget_data { 26struct afs_iget_data {
@@ -102,6 +104,16 @@ static int afs_iget5_test(struct inode *inode, void *opaque)
102} 104}
103 105
104/* 106/*
107 * iget5() comparator for inode created by autocell operations
108 *
109 * These pseudo inodes don't match anything.
110 */
111static int afs_iget5_autocell_test(struct inode *inode, void *opaque)
112{
113 return 0;
114}
115
116/*
105 * iget5() inode initialiser 117 * iget5() inode initialiser
106 */ 118 */
107static int afs_iget5_set(struct inode *inode, void *opaque) 119static int afs_iget5_set(struct inode *inode, void *opaque)
@@ -118,6 +130,67 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
118} 130}
119 131
120/* 132/*
133 * inode retrieval for autocell
134 */
135struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
136 int namesz, struct key *key)
137{
138 struct afs_iget_data data;
139 struct afs_super_info *as;
140 struct afs_vnode *vnode;
141 struct super_block *sb;
142 struct inode *inode;
143 static atomic_t afs_autocell_ino;
144
145 _enter("{%x:%u},%*.*s,",
146 AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode,
147 namesz, namesz, dev_name ?: "");
148
149 sb = dir->i_sb;
150 as = sb->s_fs_info;
151 data.volume = as->volume;
152 data.fid.vid = as->volume->vid;
153 data.fid.unique = 0;
154 data.fid.vnode = 0;
155
156 inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino),
157 afs_iget5_autocell_test, afs_iget5_set,
158 &data);
159 if (!inode) {
160 _leave(" = -ENOMEM");
161 return ERR_PTR(-ENOMEM);
162 }
163
164 _debug("GOT INODE %p { ino=%lu, vl=%x, vn=%x, u=%x }",
165 inode, inode->i_ino, data.fid.vid, data.fid.vnode,
166 data.fid.unique);
167
168 vnode = AFS_FS_I(inode);
169
170 /* there shouldn't be an existing inode */
171 BUG_ON(!(inode->i_state & I_NEW));
172
173 inode->i_size = 0;
174 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
175 inode->i_op = &afs_autocell_inode_operations;
176 inode->i_nlink = 2;
177 inode->i_uid = 0;
178 inode->i_gid = 0;
179 inode->i_ctime.tv_sec = get_seconds();
180 inode->i_ctime.tv_nsec = 0;
181 inode->i_atime = inode->i_mtime = inode->i_ctime;
182 inode->i_blocks = 0;
183 inode->i_version = 0;
184 inode->i_generation = 0;
185
186 set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
187 inode->i_flags |= S_NOATIME;
188 unlock_new_inode(inode);
189 _leave(" = %p", inode);
190 return inode;
191}
192
193/*
121 * inode retrieval 194 * inode retrieval
122 */ 195 */
123struct inode *afs_iget(struct super_block *sb, struct key *key, 196struct inode *afs_iget(struct super_block *sb, struct key *key,
@@ -314,6 +387,19 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
314} 387}
315 388
316/* 389/*
390 * discard an AFS inode
391 */
392int afs_drop_inode(struct inode *inode)
393{
394 _enter("");
395
396 if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags))
397 return generic_delete_inode(inode);
398 else
399 return generic_drop_inode(inode);
400}
401
402/*
317 * clear an AFS inode 403 * clear an AFS inode
318 */ 404 */
319void afs_evict_inode(struct inode *inode) 405void afs_evict_inode(struct inode *inode)
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 8679089ce9a1..ce12a2b06f8f 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -42,6 +42,7 @@ typedef enum {
42struct afs_mount_params { 42struct afs_mount_params {
43 bool rwpath; /* T if the parent should be considered R/W */ 43 bool rwpath; /* T if the parent should be considered R/W */
44 bool force; /* T to force cell type */ 44 bool force; /* T to force cell type */
45 bool autocell; /* T if set auto mount operation */
45 afs_voltype_t type; /* type of volume requested */ 46 afs_voltype_t type; /* type of volume requested */
46 int volnamesz; /* size of volume name */ 47 int volnamesz; /* size of volume name */
47 const char *volname; /* name of volume to mount */ 48 const char *volname; /* name of volume to mount */
@@ -358,6 +359,8 @@ struct afs_vnode {
358#define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */ 359#define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */
359#define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */ 360#define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */
360#define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */ 361#define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */
362#define AFS_VNODE_AUTOCELL 10 /* set if Vnode is an auto mount point */
363#define AFS_VNODE_PSEUDODIR 11 /* set if Vnode is a pseudo directory */
361 364
362 long acl_order; /* ACL check count (callback break count) */ 365 long acl_order; /* ACL check count (callback break count) */
363 366
@@ -468,8 +471,8 @@ extern struct list_head afs_proc_cells;
468 471
469#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) 472#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
470extern int afs_cell_init(char *); 473extern int afs_cell_init(char *);
471extern struct afs_cell *afs_cell_create(const char *, char *); 474extern struct afs_cell *afs_cell_create(const char *, unsigned, char *, bool);
472extern struct afs_cell *afs_cell_lookup(const char *, unsigned); 475extern struct afs_cell *afs_cell_lookup(const char *, unsigned, bool);
473extern struct afs_cell *afs_grab_cell(struct afs_cell *); 476extern struct afs_cell *afs_grab_cell(struct afs_cell *);
474extern void afs_put_cell(struct afs_cell *); 477extern void afs_put_cell(struct afs_cell *);
475extern void afs_cell_purge(void); 478extern void afs_cell_purge(void);
@@ -558,6 +561,8 @@ extern int afs_fs_release_lock(struct afs_server *, struct key *,
558/* 561/*
559 * inode.c 562 * inode.c
560 */ 563 */
564extern struct inode *afs_iget_autocell(struct inode *, const char *, int,
565 struct key *);
561extern struct inode *afs_iget(struct super_block *, struct key *, 566extern struct inode *afs_iget(struct super_block *, struct key *,
562 struct afs_fid *, struct afs_file_status *, 567 struct afs_fid *, struct afs_file_status *,
563 struct afs_callback *); 568 struct afs_callback *);
@@ -566,6 +571,7 @@ extern int afs_validate(struct afs_vnode *, struct key *);
566extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *); 571extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
567extern int afs_setattr(struct dentry *, struct iattr *); 572extern int afs_setattr(struct dentry *, struct iattr *);
568extern void afs_evict_inode(struct inode *); 573extern void afs_evict_inode(struct inode *);
574extern int afs_drop_inode(struct inode *);
569 575
570/* 576/*
571 * main.c 577 * main.c
@@ -581,6 +587,7 @@ extern int afs_abort_to_error(u32);
581 * mntpt.c 587 * mntpt.c
582 */ 588 */
583extern const struct inode_operations afs_mntpt_inode_operations; 589extern const struct inode_operations afs_mntpt_inode_operations;
590extern const struct inode_operations afs_autocell_inode_operations;
584extern const struct file_operations afs_mntpt_file_operations; 591extern const struct file_operations afs_mntpt_file_operations;
585 592
586extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); 593extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
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
41const struct inode_operations afs_autocell_inode_operations = {
42 .follow_link = afs_mntpt_follow_link,
43 .getattr = afs_getattr,
44};
45
41static LIST_HEAD(afs_vfsmounts); 46static LIST_HEAD(afs_vfsmounts);
42static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); 47static 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 */
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 852739d262a9..096b23f821a1 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -294,7 +294,7 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
294 if (strcmp(kbuf, "add") == 0) { 294 if (strcmp(kbuf, "add") == 0) {
295 struct afs_cell *cell; 295 struct afs_cell *cell;
296 296
297 cell = afs_cell_create(name, args); 297 cell = afs_cell_create(name, strlen(name), args, false);
298 if (IS_ERR(cell)) { 298 if (IS_ERR(cell)) {
299 ret = PTR_ERR(cell); 299 ret = PTR_ERR(cell);
300 goto done; 300 goto done;
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 9cf80f02da16..77e1e5a61154 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -16,6 +16,7 @@
16 16
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/mount.h>
19#include <linux/init.h> 20#include <linux/init.h>
20#include <linux/slab.h> 21#include <linux/slab.h>
21#include <linux/smp_lock.h> 22#include <linux/smp_lock.h>
@@ -48,6 +49,7 @@ struct file_system_type afs_fs_type = {
48static const struct super_operations afs_super_ops = { 49static const struct super_operations afs_super_ops = {
49 .statfs = afs_statfs, 50 .statfs = afs_statfs,
50 .alloc_inode = afs_alloc_inode, 51 .alloc_inode = afs_alloc_inode,
52 .drop_inode = afs_drop_inode,
51 .destroy_inode = afs_destroy_inode, 53 .destroy_inode = afs_destroy_inode,
52 .evict_inode = afs_evict_inode, 54 .evict_inode = afs_evict_inode,
53 .put_super = afs_put_super, 55 .put_super = afs_put_super,
@@ -62,12 +64,14 @@ enum {
62 afs_opt_cell, 64 afs_opt_cell,
63 afs_opt_rwpath, 65 afs_opt_rwpath,
64 afs_opt_vol, 66 afs_opt_vol,
67 afs_opt_autocell,
65}; 68};
66 69
67static const match_table_t afs_options_list = { 70static const match_table_t afs_options_list = {
68 { afs_opt_cell, "cell=%s" }, 71 { afs_opt_cell, "cell=%s" },
69 { afs_opt_rwpath, "rwpath" }, 72 { afs_opt_rwpath, "rwpath" },
70 { afs_opt_vol, "vol=%s" }, 73 { afs_opt_vol, "vol=%s" },
74 { afs_opt_autocell, "autocell" },
71 { afs_no_opt, NULL }, 75 { afs_no_opt, NULL },
72}; 76};
73 77
@@ -151,7 +155,8 @@ static int afs_parse_options(struct afs_mount_params *params,
151 switch (token) { 155 switch (token) {
152 case afs_opt_cell: 156 case afs_opt_cell:
153 cell = afs_cell_lookup(args[0].from, 157 cell = afs_cell_lookup(args[0].from,
154 args[0].to - args[0].from); 158 args[0].to - args[0].from,
159 false);
155 if (IS_ERR(cell)) 160 if (IS_ERR(cell))
156 return PTR_ERR(cell); 161 return PTR_ERR(cell);
157 afs_put_cell(params->cell); 162 afs_put_cell(params->cell);
@@ -166,6 +171,10 @@ static int afs_parse_options(struct afs_mount_params *params,
166 *devname = args[0].from; 171 *devname = args[0].from;
167 break; 172 break;
168 173
174 case afs_opt_autocell:
175 params->autocell = 1;
176 break;
177
169 default: 178 default:
170 printk(KERN_ERR "kAFS:" 179 printk(KERN_ERR "kAFS:"
171 " Unknown or invalid mount option: '%s'\n", p); 180 " Unknown or invalid mount option: '%s'\n", p);
@@ -252,10 +261,10 @@ static int afs_parse_device_name(struct afs_mount_params *params,
252 261
253 /* lookup the cell record */ 262 /* lookup the cell record */
254 if (cellname || !params->cell) { 263 if (cellname || !params->cell) {
255 cell = afs_cell_lookup(cellname, cellnamesz); 264 cell = afs_cell_lookup(cellname, cellnamesz, true);
256 if (IS_ERR(cell)) { 265 if (IS_ERR(cell)) {
257 printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n", 266 printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n",
258 cellname ?: ""); 267 cellnamesz, cellnamesz, cellname ?: "");
259 return PTR_ERR(cell); 268 return PTR_ERR(cell);
260 } 269 }
261 afs_put_cell(params->cell); 270 afs_put_cell(params->cell);
@@ -321,6 +330,9 @@ static int afs_fill_super(struct super_block *sb, void *data)
321 if (IS_ERR(inode)) 330 if (IS_ERR(inode))
322 goto error_inode; 331 goto error_inode;
323 332
333 if (params->autocell)
334 set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
335
324 ret = -ENOMEM; 336 ret = -ENOMEM;
325 root = d_alloc_root(inode); 337 root = d_alloc_root(inode);
326 if (!root) 338 if (!root)