Skip to content

Commit 8115333

Browse files
committed
Merge tag 'afs-next-20180208' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull afs updates from David Howells: "Four fixes: - add a missing put - two fixes to reset the address iteration cursor correctly - fix setting up the fileserver iteration cursor. Two cleanups: - remove some dead code - rearrange a function to be more logically laid out And one new feature: - Support AFS dynamic root. With this one should be able to do, say: mkdir /afs mount -t afs none /afs -o dyn to create a dynamic root and then, provided you have keyutils installed, do: ls /afs/grand.central.org and: ls /afs/umich.edu to list the root volumes of both those organisations' AFS cells without requiring any other setup (the kernel upcall to a program in the keyutils package to do DNS access as does NFS)" * tag 'afs-next-20180208' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs: afs: Support the AFS dynamic root afs: Rearrange afs_select_fileserver() a little afs: Remove unused code afs: Fix server list handling afs: Need to clear responded flag in addr cursor afs: Fix missing cursor clearance afs: Add missing afs_put_cell()
2 parents ef9417e + 4d673da commit 8115333

File tree

12 files changed

+324
-415
lines changed

12 files changed

+324
-415
lines changed

Documentation/filesystems/afs.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Contents:
77
- Overview.
88
- Usage.
99
- Mountpoints.
10+
- Dynamic root.
1011
- Proc filesystem.
1112
- The cell database.
1213
- Security.
@@ -127,6 +128,22 @@ mounted on /afs in one go by doing:
127128
umount /afs
128129

129130

131+
============
132+
DYNAMIC ROOT
133+
============
134+
135+
A mount option is available to create a serverless mount that is only usable
136+
for dynamic lookup. Creating such a mount can be done by, for example:
137+
138+
mount -t afs none /afs -o dyn
139+
140+
This creates a mount that just has an empty directory at the root. Attempting
141+
to look up a name in this directory will cause a mountpoint to be created that
142+
looks up a cell of the same name, for example:
143+
144+
ls /afs/grand.central.org/
145+
146+
130147
===============
131148
PROC FILESYSTEM
132149
===============

fs/afs/addr_list.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,11 +332,18 @@ bool afs_iterate_addresses(struct afs_addr_cursor *ac)
332332
*/
333333
int afs_end_cursor(struct afs_addr_cursor *ac)
334334
{
335-
if (ac->responded && ac->index != ac->start)
336-
WRITE_ONCE(ac->alist->index, ac->index);
335+
struct afs_addr_list *alist;
336+
337+
alist = ac->alist;
338+
if (alist) {
339+
if (ac->responded && ac->index != ac->start)
340+
WRITE_ONCE(alist->index, ac->index);
341+
afs_put_addrlist(alist);
342+
}
337343

338-
afs_put_addrlist(ac->alist);
344+
ac->addr = NULL;
339345
ac->alist = NULL;
346+
ac->begun = false;
340347
return ac->error;
341348
}
342349

fs/afs/dir.c

Lines changed: 108 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
#include <linux/pagemap.h>
1818
#include <linux/ctype.h>
1919
#include <linux/sched.h>
20+
#include <linux/dns_resolver.h>
2021
#include "internal.h"
2122

2223
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
2324
unsigned int flags);
25+
static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
26+
unsigned int flags);
2427
static int afs_dir_open(struct inode *inode, struct file *file);
2528
static int afs_readdir(struct file *file, struct dir_context *ctx);
2629
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
@@ -64,6 +67,17 @@ const struct inode_operations afs_dir_inode_operations = {
6467
.listxattr = afs_listxattr,
6568
};
6669

70+
const struct file_operations afs_dynroot_file_operations = {
71+
.open = dcache_dir_open,
72+
.release = dcache_dir_close,
73+
.iterate_shared = dcache_readdir,
74+
.llseek = dcache_dir_lseek,
75+
};
76+
77+
const struct inode_operations afs_dynroot_inode_operations = {
78+
.lookup = afs_dynroot_lookup,
79+
};
80+
6781
const struct dentry_operations afs_fs_dentry_operations = {
6882
.d_revalidate = afs_d_revalidate,
6983
.d_delete = afs_d_delete,
@@ -467,26 +481,59 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
467481
return 0;
468482
}
469483

484+
/*
485+
* Probe to see if a cell may exist. This prevents positive dentries from
486+
* being created unnecessarily.
487+
*/
488+
static int afs_probe_cell_name(struct dentry *dentry)
489+
{
490+
struct afs_cell *cell;
491+
const char *name = dentry->d_name.name;
492+
size_t len = dentry->d_name.len;
493+
int ret;
494+
495+
/* Names prefixed with a dot are R/W mounts. */
496+
if (name[0] == '.') {
497+
if (len == 1)
498+
return -EINVAL;
499+
name++;
500+
len--;
501+
}
502+
503+
cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
504+
if (!IS_ERR(cell)) {
505+
afs_put_cell(afs_d2net(dentry), cell);
506+
return 0;
507+
}
508+
509+
ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL);
510+
if (ret == -ENODATA)
511+
ret = -EDESTADDRREQ;
512+
return ret;
513+
}
514+
470515
/*
471516
* Try to auto mount the mountpoint with pseudo directory, if the autocell
472517
* operation is setted.
473518
*/
474-
static struct inode *afs_try_auto_mntpt(
475-
int ret, struct dentry *dentry, struct inode *dir, struct key *key,
476-
struct afs_fid *fid)
519+
static struct inode *afs_try_auto_mntpt(struct dentry *dentry,
520+
struct inode *dir, struct afs_fid *fid)
477521
{
478-
const char *devname = dentry->d_name.name;
479522
struct afs_vnode *vnode = AFS_FS_I(dir);
480523
struct inode *inode;
524+
int ret = -ENOENT;
481525

482-
_enter("%d, %p{%pd}, {%x:%u}, %p",
483-
ret, dentry, dentry, vnode->fid.vid, vnode->fid.vnode, key);
526+
_enter("%p{%pd}, {%x:%u}",
527+
dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
528+
529+
if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
530+
goto out;
484531

485-
if (ret != -ENOENT ||
486-
!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
532+
ret = afs_probe_cell_name(dentry);
533+
if (ret < 0)
487534
goto out;
488535

489-
inode = afs_iget_autocell(dir, devname, strlen(devname), key);
536+
inode = afs_iget_pseudo_dir(dir->i_sb, false);
490537
if (IS_ERR(inode)) {
491538
ret = PTR_ERR(inode);
492539
goto out;
@@ -545,13 +592,16 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
545592

546593
ret = afs_do_lookup(dir, dentry, &fid, key);
547594
if (ret < 0) {
548-
inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid);
549-
if (!IS_ERR(inode)) {
550-
key_put(key);
551-
goto success;
595+
if (ret == -ENOENT) {
596+
inode = afs_try_auto_mntpt(dentry, dir, &fid);
597+
if (!IS_ERR(inode)) {
598+
key_put(key);
599+
goto success;
600+
}
601+
602+
ret = PTR_ERR(inode);
552603
}
553604

554-
ret = PTR_ERR(inode);
555605
key_put(key);
556606
if (ret == -ENOENT) {
557607
d_add(dentry, NULL);
@@ -582,13 +632,54 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
582632
return NULL;
583633
}
584634

635+
/*
636+
* Look up an entry in a dynroot directory.
637+
*/
638+
static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
639+
unsigned int flags)
640+
{
641+
struct afs_vnode *vnode;
642+
struct afs_fid fid;
643+
struct inode *inode;
644+
int ret;
645+
646+
vnode = AFS_FS_I(dir);
647+
648+
_enter("%pd", dentry);
649+
650+
ASSERTCMP(d_inode(dentry), ==, NULL);
651+
652+
if (dentry->d_name.len >= AFSNAMEMAX) {
653+
_leave(" = -ENAMETOOLONG");
654+
return ERR_PTR(-ENAMETOOLONG);
655+
}
656+
657+
inode = afs_try_auto_mntpt(dentry, dir, &fid);
658+
if (IS_ERR(inode)) {
659+
ret = PTR_ERR(inode);
660+
if (ret == -ENOENT) {
661+
d_add(dentry, NULL);
662+
_leave(" = NULL [negative]");
663+
return NULL;
664+
}
665+
_leave(" = %d [do]", ret);
666+
return ERR_PTR(ret);
667+
}
668+
669+
d_add(dentry, inode);
670+
_leave(" = 0 { ino=%lu v=%u }",
671+
d_inode(dentry)->i_ino, d_inode(dentry)->i_generation);
672+
return NULL;
673+
}
674+
585675
/*
586676
* check that a dentry lookup hit has found a valid entry
587677
* - NOTE! the hit can be a negative hit too, so we can't assume we have an
588678
* inode
589679
*/
590680
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
591681
{
682+
struct afs_super_info *as = dentry->d_sb->s_fs_info;
592683
struct afs_vnode *vnode, *dir;
593684
struct afs_fid uninitialized_var(fid);
594685
struct dentry *parent;
@@ -600,6 +691,9 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
600691
if (flags & LOOKUP_RCU)
601692
return -ECHILD;
602693

694+
if (as->dyn_root)
695+
return 1;
696+
603697
if (d_really_is_positive(dentry)) {
604698
vnode = AFS_FS_I(d_inode(dentry));
605699
_enter("{v={%x:%u} n=%pd fl=%lx},",

fs/afs/inode.c

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ int afs_iget5_test(struct inode *inode, void *opaque)
147147
*
148148
* These pseudo inodes don't match anything.
149149
*/
150-
static int afs_iget5_autocell_test(struct inode *inode, void *opaque)
150+
static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque)
151151
{
152152
return 0;
153153
}
@@ -169,31 +169,34 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
169169
}
170170

171171
/*
172-
* inode retrieval for autocell
172+
* Create an inode for a dynamic root directory or an autocell dynamic
173+
* automount dir.
173174
*/
174-
struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
175-
int namesz, struct key *key)
175+
struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root)
176176
{
177177
struct afs_iget_data data;
178178
struct afs_super_info *as;
179179
struct afs_vnode *vnode;
180-
struct super_block *sb;
181180
struct inode *inode;
182181
static atomic_t afs_autocell_ino;
183182

184-
_enter("{%x:%u},%*.*s,",
185-
AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode,
186-
namesz, namesz, dev_name ?: "");
183+
_enter("");
187184

188-
sb = dir->i_sb;
189185
as = sb->s_fs_info;
190-
data.volume = as->volume;
191-
data.fid.vid = as->volume->vid;
192-
data.fid.unique = 0;
193-
data.fid.vnode = 0;
186+
if (as->volume) {
187+
data.volume = as->volume;
188+
data.fid.vid = as->volume->vid;
189+
}
190+
if (root) {
191+
data.fid.vnode = 1;
192+
data.fid.unique = 1;
193+
} else {
194+
data.fid.vnode = atomic_inc_return(&afs_autocell_ino);
195+
data.fid.unique = 0;
196+
}
194197

195-
inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino),
196-
afs_iget5_autocell_test, afs_iget5_set,
198+
inode = iget5_locked(sb, data.fid.vnode,
199+
afs_iget5_pseudo_dir_test, afs_iget5_set,
197200
&data);
198201
if (!inode) {
199202
_leave(" = -ENOMEM");
@@ -211,7 +214,12 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
211214

212215
inode->i_size = 0;
213216
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
214-
inode->i_op = &afs_autocell_inode_operations;
217+
if (root) {
218+
inode->i_op = &afs_dynroot_inode_operations;
219+
inode->i_fop = &afs_dynroot_file_operations;
220+
} else {
221+
inode->i_op = &afs_autocell_inode_operations;
222+
}
215223
set_nlink(inode, 2);
216224
inode->i_uid = GLOBAL_ROOT_UID;
217225
inode->i_gid = GLOBAL_ROOT_GID;
@@ -223,8 +231,12 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
223231
inode->i_generation = 0;
224232

225233
set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
226-
set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
227-
inode->i_flags |= S_AUTOMOUNT | S_NOATIME;
234+
if (!root) {
235+
set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
236+
inode->i_flags |= S_AUTOMOUNT;
237+
}
238+
239+
inode->i_flags |= S_NOATIME;
228240
unlock_new_inode(inode);
229241
_leave(" = %p", inode);
230242
return inode;

fs/afs/internal.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct afs_mount_params {
3636
bool rwpath; /* T if the parent should be considered R/W */
3737
bool force; /* T to force cell type */
3838
bool autocell; /* T if set auto mount operation */
39+
bool dyn_root; /* T if dynamic root */
3940
afs_voltype_t type; /* type of volume requested */
4041
int volnamesz; /* size of volume name */
4142
const char *volname; /* name of volume to mount */
@@ -186,6 +187,7 @@ struct afs_super_info {
186187
struct afs_net *net; /* Network namespace */
187188
struct afs_cell *cell; /* The cell in which the volume resides */
188189
struct afs_volume *volume; /* volume record */
190+
bool dyn_root; /* True if dynamic root */
189191
};
190192

191193
static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
@@ -634,10 +636,13 @@ extern bool afs_cm_incoming_call(struct afs_call *);
634636
/*
635637
* dir.c
636638
*/
637-
extern bool afs_dir_check_page(struct inode *, struct page *);
639+
extern const struct file_operations afs_dir_file_operations;
638640
extern const struct inode_operations afs_dir_inode_operations;
641+
extern const struct file_operations afs_dynroot_file_operations;
642+
extern const struct inode_operations afs_dynroot_inode_operations;
639643
extern const struct dentry_operations afs_fs_dentry_operations;
640-
extern const struct file_operations afs_dir_file_operations;
644+
645+
extern bool afs_dir_check_page(struct inode *, struct page *);
641646

642647
/*
643648
* file.c
@@ -695,8 +700,7 @@ extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *,
695700
*/
696701
extern int afs_fetch_status(struct afs_vnode *, struct key *);
697702
extern int afs_iget5_test(struct inode *, void *);
698-
extern struct inode *afs_iget_autocell(struct inode *, const char *, int,
699-
struct key *);
703+
extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool);
700704
extern struct inode *afs_iget(struct super_block *, struct key *,
701705
struct afs_fid *, struct afs_file_status *,
702706
struct afs_callback *,

0 commit comments

Comments
 (0)