aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-13 13:37:30 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-13 13:37:30 -0400
commit2897c684d1d5140e0e0302e73660c7cb97981b27 (patch)
tree8132776c20aeaa8ec6703ea782afd44ffc76e3ce /fs/afs
parentc029b55af7d6b02b993e8a5add78d062da7a3940 (diff)
parent3f43231230664c23f4a7513232171dcb6ce9f068 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: [NFS] Set CONFIG_KEYS when CONFIG_NFS_USE_KERNEL_DNS is set AFS: Implement an autocell mount capability [ver #2] DNS: If the DNS server returns an error, allow that to be cached [ver #2] NFS: Use kernel DNS resolver [ver #2] cifs: update README to include details about 'fsc' option
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/cell.c56
-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, 254 insertions, 46 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index ffea35c63879..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);
@@ -73,6 +72,10 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
73 if (!vllist || strlen(vllist) < 7) { 72 if (!vllist || strlen(vllist) < 7) {
74 ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL); 73 ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL);
75 if (ret < 0) { 74 if (ret < 0) {
75 if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY)
76 /* translate these errors into something
77 * userspace might understand */
78 ret = -EDESTADDRREQ;
76 _leave(" = %d", ret); 79 _leave(" = %d", ret);
77 return ERR_PTR(ret); 80 return ERR_PTR(ret);
78 } 81 }
@@ -138,26 +141,29 @@ error:
138} 141}
139 142
140/* 143/*
141 * create a cell record 144 * afs_cell_crate() - create a cell record
142 * - "name" is the name of the cell 145 * @name: is the name of the cell.
143 * - "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.
144 */ 149 */
145struct 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)
146{ 152{
147 struct afs_cell *cell; 153 struct afs_cell *cell;
148 int ret; 154 int ret;
149 155
150 _enter("%s,%s", name, vllist); 156 _enter("%*.*s,%s", namesz, namesz, name ?: "", vllist);
151 157
152 down_write(&afs_cells_sem); 158 down_write(&afs_cells_sem);
153 read_lock(&afs_cells_lock); 159 read_lock(&afs_cells_lock);
154 list_for_each_entry(cell, &afs_cells, link) { 160 list_for_each_entry(cell, &afs_cells, link) {
155 if (strcasecmp(cell->name, name) == 0) 161 if (strncasecmp(cell->name, name, namesz) == 0)
156 goto duplicate_name; 162 goto duplicate_name;
157 } 163 }
158 read_unlock(&afs_cells_lock); 164 read_unlock(&afs_cells_lock);
159 165
160 cell = afs_cell_alloc(name, vllist); 166 cell = afs_cell_alloc(name, namesz, vllist);
161 if (IS_ERR(cell)) { 167 if (IS_ERR(cell)) {
162 _leave(" = %ld", PTR_ERR(cell)); 168 _leave(" = %ld", PTR_ERR(cell));
163 up_write(&afs_cells_sem); 169 up_write(&afs_cells_sem);
@@ -197,8 +203,18 @@ error:
197 return ERR_PTR(ret); 203 return ERR_PTR(ret);
198 204
199duplicate_name: 205duplicate_name:
206 if (retref && !IS_ERR(cell))
207 afs_get_cell(cell);
208
200 read_unlock(&afs_cells_lock); 209 read_unlock(&afs_cells_lock);
201 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");
202 return ERR_PTR(-EEXIST); 218 return ERR_PTR(-EEXIST);
203} 219}
204 220
@@ -229,7 +245,7 @@ int afs_cell_init(char *rootcell)
229 *cp++ = 0; 245 *cp++ = 0;
230 246
231 /* allocate a cell record for the root cell */ 247 /* allocate a cell record for the root cell */
232 new_root = afs_cell_create(rootcell, cp); 248 new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false);
233 if (IS_ERR(new_root)) { 249 if (IS_ERR(new_root)) {
234 _leave(" = %ld", PTR_ERR(new_root)); 250 _leave(" = %ld", PTR_ERR(new_root));
235 return PTR_ERR(new_root); 251 return PTR_ERR(new_root);
@@ -249,11 +265,12 @@ int afs_cell_init(char *rootcell)
249/* 265/*
250 * lookup a cell record 266 * lookup a cell record
251 */ 267 */
252struct 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)
253{ 270{
254 struct afs_cell *cell; 271 struct afs_cell *cell;
255 272
256 _enter("\"%*.*s\",", namesz, namesz, name ? name : ""); 273 _enter("\"%*.*s\",", namesz, namesz, name ?: "");
257 274
258 down_read(&afs_cells_sem); 275 down_read(&afs_cells_sem);
259 read_lock(&afs_cells_lock); 276 read_lock(&afs_cells_lock);
@@ -267,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
267 } 284 }
268 } 285 }
269 cell = ERR_PTR(-ENOENT); 286 cell = ERR_PTR(-ENOENT);
287 if (dns_cell)
288 goto create_cell;
270 found: 289 found:
271 ; 290 ;
272 } else { 291 } else {
@@ -289,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
289 up_read(&afs_cells_sem); 308 up_read(&afs_cells_sem);
290 _leave(" = %p", cell); 309 _leave(" = %p", cell);
291 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;
292} 320}
293 321
294#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 c6c93f180707..cca8eef736fc 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)