Skip to content

Commit bec5eb6

Browse files
weylanSteve French
authored andcommitted
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 <[email protected]> Signed-off-by: David Howells <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 4a2d789 commit bec5eb6

File tree

7 files changed

+250
-46
lines changed

7 files changed

+250
-46
lines changed

fs/afs/cell.c

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,20 @@ static struct afs_cell *afs_cell_root;
3131
* allocate a cell record and fill in its name, VL server address list and
3232
* allocate an anonymous key
3333
*/
34-
static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
34+
static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen,
35+
char *vllist)
3536
{
3637
struct afs_cell *cell;
3738
struct key *key;
38-
size_t namelen;
3939
char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
4040
char *dvllist = NULL, *_vllist = NULL;
4141
char delimiter = ':';
4242
int ret;
4343

44-
_enter("%s,%s", name, vllist);
44+
_enter("%*.*s,%s", namelen, namelen, name ?: "", vllist);
4545

4646
BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
4747

48-
namelen = strlen(name);
4948
if (namelen > AFS_MAXCELLNAME) {
5049
_leave(" = -ENAMETOOLONG");
5150
return ERR_PTR(-ENAMETOOLONG);
@@ -142,26 +141,29 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
142141
}
143142

144143
/*
145-
* create a cell record
146-
* - "name" is the name of the cell
147-
* - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
144+
* afs_cell_crate() - create a cell record
145+
* @name: is the name of the cell.
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.
148149
*/
149-
struct afs_cell *afs_cell_create(const char *name, char *vllist)
150+
struct afs_cell *afs_cell_create(const char *name, unsigned namesz,
151+
char *vllist, bool retref)
150152
{
151153
struct afs_cell *cell;
152154
int ret;
153155

154-
_enter("%s,%s", name, vllist);
156+
_enter("%*.*s,%s", namesz, namesz, name ?: "", vllist);
155157

156158
down_write(&afs_cells_sem);
157159
read_lock(&afs_cells_lock);
158160
list_for_each_entry(cell, &afs_cells, link) {
159-
if (strcasecmp(cell->name, name) == 0)
161+
if (strncasecmp(cell->name, name, namesz) == 0)
160162
goto duplicate_name;
161163
}
162164
read_unlock(&afs_cells_lock);
163165

164-
cell = afs_cell_alloc(name, vllist);
166+
cell = afs_cell_alloc(name, namesz, vllist);
165167
if (IS_ERR(cell)) {
166168
_leave(" = %ld", PTR_ERR(cell));
167169
up_write(&afs_cells_sem);
@@ -201,8 +203,18 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist)
201203
return ERR_PTR(ret);
202204

203205
duplicate_name:
206+
if (retref && !IS_ERR(cell))
207+
afs_get_cell(cell);
208+
204209
read_unlock(&afs_cells_lock);
205210
up_write(&afs_cells_sem);
211+
212+
if (retref) {
213+
_leave(" = %p", cell);
214+
return cell;
215+
}
216+
217+
_leave(" = -EEXIST");
206218
return ERR_PTR(-EEXIST);
207219
}
208220

@@ -233,7 +245,7 @@ int afs_cell_init(char *rootcell)
233245
*cp++ = 0;
234246

235247
/* 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);
237249
if (IS_ERR(new_root)) {
238250
_leave(" = %ld", PTR_ERR(new_root));
239251
return PTR_ERR(new_root);
@@ -253,11 +265,12 @@ int afs_cell_init(char *rootcell)
253265
/*
254266
* lookup a cell record
255267
*/
256-
struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
268+
struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,
269+
bool dns_cell)
257270
{
258271
struct afs_cell *cell;
259272

260-
_enter("\"%*.*s\",", namesz, namesz, name ? name : "");
273+
_enter("\"%*.*s\",", namesz, namesz, name ?: "");
261274

262275
down_read(&afs_cells_sem);
263276
read_lock(&afs_cells_lock);
@@ -271,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
271284
}
272285
}
273286
cell = ERR_PTR(-ENOENT);
287+
if (dns_cell)
288+
goto create_cell;
274289
found:
275290
;
276291
} else {
@@ -293,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
293308
up_read(&afs_cells_sem);
294309
_leave(" = %p", cell);
295310
return cell;
311+
312+
create_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;
296320
}
297321

298322
#if 0

fs/afs/dir.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,40 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
476476
return 0;
477477
}
478478

479+
/*
480+
* Try to auto mount the mountpoint with pseudo directory, if the autocell
481+
* operation is setted.
482+
*/
483+
static 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+
508+
out:
509+
_leave("= %d", ret);
510+
return ERR_PTR(ret);
511+
}
512+
479513
/*
480514
* look up an entry in a directory
481515
*/
@@ -520,6 +554,13 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
520554

521555
ret = afs_do_lookup(dir, dentry, &fid, key);
522556
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);
523564
key_put(key);
524565
if (ret == -ENOENT) {
525566
d_add(dentry, NULL);
@@ -539,6 +580,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
539580
return ERR_CAST(inode);
540581
}
541582

583+
success:
542584
dentry->d_op = &afs_fs_dentry_operations;
543585

544586
d_add(dentry, inode);
@@ -696,8 +738,9 @@ static int afs_d_delete(struct dentry *dentry)
696738
goto zap;
697739

698740
if (dentry->d_inode &&
699-
test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags))
700-
goto zap;
741+
(test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags) ||
742+
test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(dentry->d_inode)->flags)))
743+
goto zap;
701744

702745
_leave(" = 0 [keep]");
703746
return 0;

fs/afs/inode.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <linux/fs.h>
2020
#include <linux/pagemap.h>
2121
#include <linux/sched.h>
22+
#include <linux/mount.h>
23+
#include <linux/namei.h>
2224
#include "internal.h"
2325

2426
struct afs_iget_data {
@@ -101,6 +103,16 @@ static int afs_iget5_test(struct inode *inode, void *opaque)
101103
inode->i_version == data->fid.unique;
102104
}
103105

106+
/*
107+
* iget5() comparator for inode created by autocell operations
108+
*
109+
* These pseudo inodes don't match anything.
110+
*/
111+
static int afs_iget5_autocell_test(struct inode *inode, void *opaque)
112+
{
113+
return 0;
114+
}
115+
104116
/*
105117
* iget5() inode initialiser
106118
*/
@@ -117,6 +129,67 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
117129
return 0;
118130
}
119131

132+
/*
133+
* inode retrieval for autocell
134+
*/
135+
struct 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+
120193
/*
121194
* inode retrieval
122195
*/
@@ -313,6 +386,19 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
313386
return 0;
314387
}
315388

389+
/*
390+
* discard an AFS inode
391+
*/
392+
int 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+
316402
/*
317403
* clear an AFS inode
318404
*/

fs/afs/internal.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ typedef enum {
4242
struct afs_mount_params {
4343
bool rwpath; /* T if the parent should be considered R/W */
4444
bool force; /* T to force cell type */
45+
bool autocell; /* T if set auto mount operation */
4546
afs_voltype_t type; /* type of volume requested */
4647
int volnamesz; /* size of volume name */
4748
const char *volname; /* name of volume to mount */
@@ -358,6 +359,8 @@ struct afs_vnode {
358359
#define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */
359360
#define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */
360361
#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 */
361364

362365
long acl_order; /* ACL check count (callback break count) */
363366

@@ -468,8 +471,8 @@ extern struct list_head afs_proc_cells;
468471

469472
#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
470473
extern int afs_cell_init(char *);
471-
extern struct afs_cell *afs_cell_create(const char *, char *);
472-
extern struct afs_cell *afs_cell_lookup(const char *, unsigned);
474+
extern struct afs_cell *afs_cell_create(const char *, unsigned, char *, bool);
475+
extern struct afs_cell *afs_cell_lookup(const char *, unsigned, bool);
473476
extern struct afs_cell *afs_grab_cell(struct afs_cell *);
474477
extern void afs_put_cell(struct afs_cell *);
475478
extern void afs_cell_purge(void);
@@ -558,6 +561,8 @@ extern int afs_fs_release_lock(struct afs_server *, struct key *,
558561
/*
559562
* inode.c
560563
*/
564+
extern struct inode *afs_iget_autocell(struct inode *, const char *, int,
565+
struct key *);
561566
extern struct inode *afs_iget(struct super_block *, struct key *,
562567
struct afs_fid *, struct afs_file_status *,
563568
struct afs_callback *);
@@ -566,6 +571,7 @@ extern int afs_validate(struct afs_vnode *, struct key *);
566571
extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
567572
extern int afs_setattr(struct dentry *, struct iattr *);
568573
extern void afs_evict_inode(struct inode *);
574+
extern int afs_drop_inode(struct inode *);
569575

570576
/*
571577
* main.c
@@ -581,6 +587,7 @@ extern int afs_abort_to_error(u32);
581587
* mntpt.c
582588
*/
583589
extern const struct inode_operations afs_mntpt_inode_operations;
590+
extern const struct inode_operations afs_autocell_inode_operations;
584591
extern const struct file_operations afs_mntpt_file_operations;
585592

586593
extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);

0 commit comments

Comments
 (0)