aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-02-06 01:26:30 -0500
committerDavid Howells <dhowells@redhat.com>2018-02-06 09:43:37 -0500
commit4d673da14533b32fe8d3125b5b7be4fea14e39a8 (patch)
treed0780b5603a48614696e7e9afebe5b61552c6cd1
parent16280a15be751b9994e94c5dc944e93fa4293199 (diff)
afs: Support the AFS dynamic root
Support the AFS dynamic root which is a pseudo-volume that doesn't connect to any server resource, but rather is just a root directory that dynamically creates mountpoint directories where the name of such a directory is the name of the cell. Such a mount can be created thus: mount -t afs none /afs -o dyn Dynamic root superblocks aren't shared except by bind mounts and propagation. Cell root volumes can then be mounted by referring to them by name, e.g.: ls /afs/grand.central.org/ ls /afs/.grand.central.org/ The kernel will upcall to consult the DNS if the address wasn't supplied directly. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--Documentation/filesystems/afs.txt17
-rw-r--r--fs/afs/dir.c122
-rw-r--r--fs/afs/inode.c48
-rw-r--r--fs/afs/internal.h12
-rw-r--r--fs/afs/mntpt.c20
-rw-r--r--fs/afs/super.c132
-rw-r--r--net/dns_resolver/dns_query.c22
7 files changed, 276 insertions, 97 deletions
diff --git a/Documentation/filesystems/afs.txt b/Documentation/filesystems/afs.txt
index ba99b5ac4fd8..c5254f6d234d 100644
--- a/Documentation/filesystems/afs.txt
+++ b/Documentation/filesystems/afs.txt
@@ -7,6 +7,7 @@ Contents:
7 - Overview. 7 - Overview.
8 - Usage. 8 - Usage.
9 - Mountpoints. 9 - Mountpoints.
10 - Dynamic root.
10 - Proc filesystem. 11 - Proc filesystem.
11 - The cell database. 12 - The cell database.
12 - Security. 13 - Security.
@@ -127,6 +128,22 @@ mounted on /afs in one go by doing:
127 umount /afs 128 umount /afs
128 129
129 130
131============
132DYNAMIC ROOT
133============
134
135A mount option is available to create a serverless mount that is only usable
136for dynamic lookup. Creating such a mount can be done by, for example:
137
138 mount -t afs none /afs -o dyn
139
140This creates a mount that just has an empty directory at the root. Attempting
141to look up a name in this directory will cause a mountpoint to be created that
142looks up a cell of the same name, for example:
143
144 ls /afs/grand.central.org/
145
146
130=============== 147===============
131PROC FILESYSTEM 148PROC FILESYSTEM
132=============== 149===============
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 23c7f395d718..ba2b458b36d1 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -17,10 +17,13 @@
17#include <linux/pagemap.h> 17#include <linux/pagemap.h>
18#include <linux/ctype.h> 18#include <linux/ctype.h>
19#include <linux/sched.h> 19#include <linux/sched.h>
20#include <linux/dns_resolver.h>
20#include "internal.h" 21#include "internal.h"
21 22
22static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, 23static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
23 unsigned int flags); 24 unsigned int flags);
25static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
26 unsigned int flags);
24static int afs_dir_open(struct inode *inode, struct file *file); 27static int afs_dir_open(struct inode *inode, struct file *file);
25static int afs_readdir(struct file *file, struct dir_context *ctx); 28static int afs_readdir(struct file *file, struct dir_context *ctx);
26static int afs_d_revalidate(struct dentry *dentry, unsigned int flags); 29static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
@@ -64,6 +67,17 @@ const struct inode_operations afs_dir_inode_operations = {
64 .listxattr = afs_listxattr, 67 .listxattr = afs_listxattr,
65}; 68};
66 69
70const 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
77const struct inode_operations afs_dynroot_inode_operations = {
78 .lookup = afs_dynroot_lookup,
79};
80
67const struct dentry_operations afs_fs_dentry_operations = { 81const struct dentry_operations afs_fs_dentry_operations = {
68 .d_revalidate = afs_d_revalidate, 82 .d_revalidate = afs_d_revalidate,
69 .d_delete = afs_d_delete, 83 .d_delete = afs_d_delete,
@@ -468,25 +482,58 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
468} 482}
469 483
470/* 484/*
485 * Probe to see if a cell may exist. This prevents positive dentries from
486 * being created unnecessarily.
487 */
488static 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
515/*
471 * Try to auto mount the mountpoint with pseudo directory, if the autocell 516 * Try to auto mount the mountpoint with pseudo directory, if the autocell
472 * operation is setted. 517 * operation is setted.
473 */ 518 */
474static struct inode *afs_try_auto_mntpt( 519static struct inode *afs_try_auto_mntpt(struct dentry *dentry,
475 int ret, struct dentry *dentry, struct inode *dir, struct key *key, 520 struct inode *dir, struct afs_fid *fid)
476 struct afs_fid *fid)
477{ 521{
478 const char *devname = dentry->d_name.name;
479 struct afs_vnode *vnode = AFS_FS_I(dir); 522 struct afs_vnode *vnode = AFS_FS_I(dir);
480 struct inode *inode; 523 struct inode *inode;
524 int ret = -ENOENT;
481 525
482 _enter("%d, %p{%pd}, {%x:%u}, %p", 526 _enter("%p{%pd}, {%x:%u}",
483 ret, dentry, dentry, vnode->fid.vid, vnode->fid.vnode, key); 527 dentry, dentry, vnode->fid.vid, vnode->fid.vnode);
528
529 if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
530 goto out;
484 531
485 if (ret != -ENOENT || 532 ret = afs_probe_cell_name(dentry);
486 !test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) 533 if (ret < 0)
487 goto out; 534 goto out;
488 535
489 inode = afs_iget_autocell(dir, devname, strlen(devname), key); 536 inode = afs_iget_pseudo_dir(dir->i_sb, false);
490 if (IS_ERR(inode)) { 537 if (IS_ERR(inode)) {
491 ret = PTR_ERR(inode); 538 ret = PTR_ERR(inode);
492 goto out; 539 goto out;
@@ -545,13 +592,16 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
545 592
546 ret = afs_do_lookup(dir, dentry, &fid, key); 593 ret = afs_do_lookup(dir, dentry, &fid, key);
547 if (ret < 0) { 594 if (ret < 0) {
548 inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid); 595 if (ret == -ENOENT) {
549 if (!IS_ERR(inode)) { 596 inode = afs_try_auto_mntpt(dentry, dir, &fid);
550 key_put(key); 597 if (!IS_ERR(inode)) {
551 goto success; 598 key_put(key);
599 goto success;
600 }
601
602 ret = PTR_ERR(inode);
552 } 603 }
553 604
554 ret = PTR_ERR(inode);
555 key_put(key); 605 key_put(key);
556 if (ret == -ENOENT) { 606 if (ret == -ENOENT) {
557 d_add(dentry, NULL); 607 d_add(dentry, NULL);
@@ -583,12 +633,53 @@ success:
583} 633}
584 634
585/* 635/*
636 * Look up an entry in a dynroot directory.
637 */
638static 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
675/*
586 * check that a dentry lookup hit has found a valid entry 676 * check that a dentry lookup hit has found a valid entry
587 * - NOTE! the hit can be a negative hit too, so we can't assume we have an 677 * - NOTE! the hit can be a negative hit too, so we can't assume we have an
588 * inode 678 * inode
589 */ 679 */
590static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) 680static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
591{ 681{
682 struct afs_super_info *as = dentry->d_sb->s_fs_info;
592 struct afs_vnode *vnode, *dir; 683 struct afs_vnode *vnode, *dir;
593 struct afs_fid uninitialized_var(fid); 684 struct afs_fid uninitialized_var(fid);
594 struct dentry *parent; 685 struct dentry *parent;
@@ -600,6 +691,9 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
600 if (flags & LOOKUP_RCU) 691 if (flags & LOOKUP_RCU)
601 return -ECHILD; 692 return -ECHILD;
602 693
694 if (as->dyn_root)
695 return 1;
696
603 if (d_really_is_positive(dentry)) { 697 if (d_really_is_positive(dentry)) {
604 vnode = AFS_FS_I(d_inode(dentry)); 698 vnode = AFS_FS_I(d_inode(dentry));
605 _enter("{v={%x:%u} n=%pd fl=%lx},", 699 _enter("{v={%x:%u} n=%pd fl=%lx},",
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index c7f17c44c7ce..6b39d0255b72 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -147,7 +147,7 @@ int afs_iget5_test(struct inode *inode, void *opaque)
147 * 147 *
148 * These pseudo inodes don't match anything. 148 * These pseudo inodes don't match anything.
149 */ 149 */
150static int afs_iget5_autocell_test(struct inode *inode, void *opaque) 150static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque)
151{ 151{
152 return 0; 152 return 0;
153} 153}
@@ -169,31 +169,34 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
169} 169}
170 170
171/* 171/*
172 * inode retrieval for autocell 172 * Create an inode for a dynamic root directory or an autocell dynamic
173 * automount dir.
173 */ 174 */
174struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name, 175struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root)
175 int namesz, struct key *key)
176{ 176{
177 struct afs_iget_data data; 177 struct afs_iget_data data;
178 struct afs_super_info *as; 178 struct afs_super_info *as;
179 struct afs_vnode *vnode; 179 struct afs_vnode *vnode;
180 struct super_block *sb;
181 struct inode *inode; 180 struct inode *inode;
182 static atomic_t afs_autocell_ino; 181 static atomic_t afs_autocell_ino;
183 182
184 _enter("{%x:%u},%*.*s,", 183 _enter("");
185 AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode,
186 namesz, namesz, dev_name ?: "");
187 184
188 sb = dir->i_sb;
189 as = sb->s_fs_info; 185 as = sb->s_fs_info;
190 data.volume = as->volume; 186 if (as->volume) {
191 data.fid.vid = as->volume->vid; 187 data.volume = as->volume;
192 data.fid.unique = 0; 188 data.fid.vid = as->volume->vid;
193 data.fid.vnode = 0; 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 }
194 197
195 inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino), 198 inode = iget5_locked(sb, data.fid.vnode,
196 afs_iget5_autocell_test, afs_iget5_set, 199 afs_iget5_pseudo_dir_test, afs_iget5_set,
197 &data); 200 &data);
198 if (!inode) { 201 if (!inode) {
199 _leave(" = -ENOMEM"); 202 _leave(" = -ENOMEM");
@@ -211,7 +214,12 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
211 214
212 inode->i_size = 0; 215 inode->i_size = 0;
213 inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 216 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 }
215 set_nlink(inode, 2); 223 set_nlink(inode, 2);
216 inode->i_uid = GLOBAL_ROOT_UID; 224 inode->i_uid = GLOBAL_ROOT_UID;
217 inode->i_gid = GLOBAL_ROOT_GID; 225 inode->i_gid = GLOBAL_ROOT_GID;
@@ -223,8 +231,12 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
223 inode->i_generation = 0; 231 inode->i_generation = 0;
224 232
225 set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); 233 set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
226 set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); 234 if (!root) {
227 inode->i_flags |= S_AUTOMOUNT | S_NOATIME; 235 set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
236 inode->i_flags |= S_AUTOMOUNT;
237 }
238
239 inode->i_flags |= S_NOATIME;
228 unlock_new_inode(inode); 240 unlock_new_inode(inode);
229 _leave(" = %p", inode); 241 _leave(" = %p", inode);
230 return inode; 242 return inode;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 804d1f905622..f38d6a561a84 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -36,6 +36,7 @@ struct afs_mount_params {
36 bool rwpath; /* T if the parent should be considered R/W */ 36 bool rwpath; /* T if the parent should be considered R/W */
37 bool force; /* T to force cell type */ 37 bool force; /* T to force cell type */
38 bool autocell; /* T if set auto mount operation */ 38 bool autocell; /* T if set auto mount operation */
39 bool dyn_root; /* T if dynamic root */
39 afs_voltype_t type; /* type of volume requested */ 40 afs_voltype_t type; /* type of volume requested */
40 int volnamesz; /* size of volume name */ 41 int volnamesz; /* size of volume name */
41 const char *volname; /* name of volume to mount */ 42 const char *volname; /* name of volume to mount */
@@ -186,6 +187,7 @@ struct afs_super_info {
186 struct afs_net *net; /* Network namespace */ 187 struct afs_net *net; /* Network namespace */
187 struct afs_cell *cell; /* The cell in which the volume resides */ 188 struct afs_cell *cell; /* The cell in which the volume resides */
188 struct afs_volume *volume; /* volume record */ 189 struct afs_volume *volume; /* volume record */
190 bool dyn_root; /* True if dynamic root */
189}; 191};
190 192
191static inline struct afs_super_info *AFS_FS_S(struct super_block *sb) 193static 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 *);
634/* 636/*
635 * dir.c 637 * dir.c
636 */ 638 */
637extern bool afs_dir_check_page(struct inode *, struct page *); 639extern const struct file_operations afs_dir_file_operations;
638extern const struct inode_operations afs_dir_inode_operations; 640extern const struct inode_operations afs_dir_inode_operations;
641extern const struct file_operations afs_dynroot_file_operations;
642extern const struct inode_operations afs_dynroot_inode_operations;
639extern const struct dentry_operations afs_fs_dentry_operations; 643extern const struct dentry_operations afs_fs_dentry_operations;
640extern const struct file_operations afs_dir_file_operations; 644
645extern bool afs_dir_check_page(struct inode *, struct page *);
641 646
642/* 647/*
643 * file.c 648 * file.c
@@ -695,8 +700,7 @@ extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *,
695 */ 700 */
696extern int afs_fetch_status(struct afs_vnode *, struct key *); 701extern int afs_fetch_status(struct afs_vnode *, struct key *);
697extern int afs_iget5_test(struct inode *, void *); 702extern int afs_iget5_test(struct inode *, void *);
698extern struct inode *afs_iget_autocell(struct inode *, const char *, int, 703extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool);
699 struct key *);
700extern struct inode *afs_iget(struct super_block *, struct key *, 704extern struct inode *afs_iget(struct super_block *, struct key *,
701 struct afs_fid *, struct afs_file_status *, 705 struct afs_fid *, struct afs_file_status *,
702 struct afs_callback *, 706 struct afs_callback *,
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 690fea9d84c3..99fd13500a97 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -72,7 +72,7 @@ static int afs_mntpt_open(struct inode *inode, struct file *file)
72 */ 72 */
73static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) 73static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
74{ 74{
75 struct afs_super_info *super; 75 struct afs_super_info *as;
76 struct vfsmount *mnt; 76 struct vfsmount *mnt;
77 struct afs_vnode *vnode; 77 struct afs_vnode *vnode;
78 struct page *page; 78 struct page *page;
@@ -104,13 +104,13 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
104 goto error_no_page; 104 goto error_no_page;
105 105
106 if (mntpt->d_name.name[0] == '.') { 106 if (mntpt->d_name.name[0] == '.') {
107 devname[0] = '#'; 107 devname[0] = '%';
108 memcpy(devname + 1, mntpt->d_name.name, size - 1); 108 memcpy(devname + 1, mntpt->d_name.name + 1, size - 1);
109 memcpy(devname + size, afs_root_cell, 109 memcpy(devname + size, afs_root_cell,
110 sizeof(afs_root_cell)); 110 sizeof(afs_root_cell));
111 rwpath = true; 111 rwpath = true;
112 } else { 112 } else {
113 devname[0] = '%'; 113 devname[0] = '#';
114 memcpy(devname + 1, mntpt->d_name.name, size); 114 memcpy(devname + 1, mntpt->d_name.name, size);
115 memcpy(devname + size + 1, afs_root_cell, 115 memcpy(devname + size + 1, afs_root_cell,
116 sizeof(afs_root_cell)); 116 sizeof(afs_root_cell));
@@ -142,11 +142,13 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
142 } 142 }
143 143
144 /* work out what options we want */ 144 /* work out what options we want */
145 super = AFS_FS_S(mntpt->d_sb); 145 as = AFS_FS_S(mntpt->d_sb);
146 memcpy(options, "cell=", 5); 146 if (as->cell) {
147 strcpy(options + 5, super->volume->cell->name); 147 memcpy(options, "cell=", 5);
148 if (super->volume->type == AFSVL_RWVOL || rwpath) 148 strcpy(options + 5, as->cell->name);
149 strcat(options, ",rwpath"); 149 if ((as->volume && as->volume->type == AFSVL_RWVOL) || rwpath)
150 strcat(options, ",rwpath");
151 }
150 152
151 /* try and do the mount */ 153 /* try and do the mount */
152 _debug("--- attempting mount %s -o %s ---", devname, options); 154 _debug("--- attempting mount %s -o %s ---", devname, options);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 1037dd41a622..3623c952b6ff 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -64,6 +64,7 @@ static atomic_t afs_count_active_inodes;
64enum { 64enum {
65 afs_no_opt, 65 afs_no_opt,
66 afs_opt_cell, 66 afs_opt_cell,
67 afs_opt_dyn,
67 afs_opt_rwpath, 68 afs_opt_rwpath,
68 afs_opt_vol, 69 afs_opt_vol,
69 afs_opt_autocell, 70 afs_opt_autocell,
@@ -71,6 +72,7 @@ enum {
71 72
72static const match_table_t afs_options_list = { 73static const match_table_t afs_options_list = {
73 { afs_opt_cell, "cell=%s" }, 74 { afs_opt_cell, "cell=%s" },
75 { afs_opt_dyn, "dyn" },
74 { afs_opt_rwpath, "rwpath" }, 76 { afs_opt_rwpath, "rwpath" },
75 { afs_opt_vol, "vol=%s" }, 77 { afs_opt_vol, "vol=%s" },
76 { afs_opt_autocell, "autocell" }, 78 { afs_opt_autocell, "autocell" },
@@ -148,6 +150,11 @@ static int afs_show_devname(struct seq_file *m, struct dentry *root)
148 const char *suf = ""; 150 const char *suf = "";
149 char pref = '%'; 151 char pref = '%';
150 152
153 if (as->dyn_root) {
154 seq_puts(m, "none");
155 return 0;
156 }
157
151 switch (volume->type) { 158 switch (volume->type) {
152 case AFSVL_RWVOL: 159 case AFSVL_RWVOL:
153 break; 160 break;
@@ -171,8 +178,12 @@ static int afs_show_devname(struct seq_file *m, struct dentry *root)
171 */ 178 */
172static int afs_show_options(struct seq_file *m, struct dentry *root) 179static int afs_show_options(struct seq_file *m, struct dentry *root)
173{ 180{
181 struct afs_super_info *as = AFS_FS_S(root->d_sb);
182
183 if (as->dyn_root)
184 seq_puts(m, ",dyn");
174 if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) 185 if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags))
175 seq_puts(m, "autocell"); 186 seq_puts(m, ",autocell");
176 return 0; 187 return 0;
177} 188}
178 189
@@ -212,7 +223,7 @@ static int afs_parse_options(struct afs_mount_params *params,
212 break; 223 break;
213 224
214 case afs_opt_rwpath: 225 case afs_opt_rwpath:
215 params->rwpath = 1; 226 params->rwpath = true;
216 break; 227 break;
217 228
218 case afs_opt_vol: 229 case afs_opt_vol:
@@ -220,7 +231,11 @@ static int afs_parse_options(struct afs_mount_params *params,
220 break; 231 break;
221 232
222 case afs_opt_autocell: 233 case afs_opt_autocell:
223 params->autocell = 1; 234 params->autocell = true;
235 break;
236
237 case afs_opt_dyn:
238 params->dyn_root = true;
224 break; 239 break;
225 240
226 default: 241 default:
@@ -254,7 +269,7 @@ static int afs_parse_device_name(struct afs_mount_params *params,
254 int cellnamesz; 269 int cellnamesz;
255 270
256 _enter(",%s", name); 271 _enter(",%s", name);
257 272
258 if (!name) { 273 if (!name) {
259 printk(KERN_ERR "kAFS: no volume name specified\n"); 274 printk(KERN_ERR "kAFS: no volume name specified\n");
260 return -EINVAL; 275 return -EINVAL;
@@ -336,7 +351,14 @@ static int afs_test_super(struct super_block *sb, void *data)
336 struct afs_super_info *as1 = data; 351 struct afs_super_info *as1 = data;
337 struct afs_super_info *as = AFS_FS_S(sb); 352 struct afs_super_info *as = AFS_FS_S(sb);
338 353
339 return as->net == as1->net && as->volume->vid == as1->volume->vid; 354 return (as->net == as1->net &&
355 as->volume &&
356 as->volume->vid == as1->volume->vid);
357}
358
359static int afs_dynroot_test_super(struct super_block *sb, void *data)
360{
361 return false;
340} 362}
341 363
342static int afs_set_super(struct super_block *sb, void *data) 364static int afs_set_super(struct super_block *sb, void *data)
@@ -365,24 +387,30 @@ static int afs_fill_super(struct super_block *sb,
365 sb->s_blocksize_bits = PAGE_SHIFT; 387 sb->s_blocksize_bits = PAGE_SHIFT;
366 sb->s_magic = AFS_FS_MAGIC; 388 sb->s_magic = AFS_FS_MAGIC;
367 sb->s_op = &afs_super_ops; 389 sb->s_op = &afs_super_ops;
368 sb->s_xattr = afs_xattr_handlers; 390 if (!as->dyn_root)
391 sb->s_xattr = afs_xattr_handlers;
369 ret = super_setup_bdi(sb); 392 ret = super_setup_bdi(sb);
370 if (ret) 393 if (ret)
371 return ret; 394 return ret;
372 sb->s_bdi->ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_SIZE; 395 sb->s_bdi->ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_SIZE;
373 sprintf(sb->s_id, "%u", as->volume->vid);
374
375 afs_activate_volume(as->volume);
376 396
377 /* allocate the root inode and dentry */ 397 /* allocate the root inode and dentry */
378 fid.vid = as->volume->vid; 398 if (as->dyn_root) {
379 fid.vnode = 1; 399 inode = afs_iget_pseudo_dir(sb, true);
380 fid.unique = 1; 400 sb->s_flags |= SB_RDONLY;
381 inode = afs_iget(sb, params->key, &fid, NULL, NULL, NULL); 401 } else {
402 sprintf(sb->s_id, "%u", as->volume->vid);
403 afs_activate_volume(as->volume);
404 fid.vid = as->volume->vid;
405 fid.vnode = 1;
406 fid.unique = 1;
407 inode = afs_iget(sb, params->key, &fid, NULL, NULL, NULL);
408 }
409
382 if (IS_ERR(inode)) 410 if (IS_ERR(inode))
383 return PTR_ERR(inode); 411 return PTR_ERR(inode);
384 412
385 if (params->autocell) 413 if (params->autocell || params->dyn_root)
386 set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); 414 set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);
387 415
388 ret = -ENOMEM; 416 ret = -ENOMEM;
@@ -407,7 +435,10 @@ static struct afs_super_info *afs_alloc_sbi(struct afs_mount_params *params)
407 as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); 435 as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL);
408 if (as) { 436 if (as) {
409 as->net = afs_get_net(params->net); 437 as->net = afs_get_net(params->net);
410 as->cell = afs_get_cell(params->cell); 438 if (params->dyn_root)
439 as->dyn_root = true;
440 else
441 as->cell = afs_get_cell(params->cell);
411 } 442 }
412 return as; 443 return as;
413} 444}
@@ -451,18 +482,20 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
451 goto error; 482 goto error;
452 } 483 }
453 484
454 ret = afs_parse_device_name(&params, dev_name); 485 if (!params.dyn_root) {
455 if (ret < 0) 486 ret = afs_parse_device_name(&params, dev_name);
456 goto error; 487 if (ret < 0)
488 goto error;
457 489
458 /* try and do the mount securely */ 490 /* try and do the mount securely */
459 key = afs_request_key(params.cell); 491 key = afs_request_key(params.cell);
460 if (IS_ERR(key)) { 492 if (IS_ERR(key)) {
461 _leave(" = %ld [key]", PTR_ERR(key)); 493 _leave(" = %ld [key]", PTR_ERR(key));
462 ret = PTR_ERR(key); 494 ret = PTR_ERR(key);
463 goto error; 495 goto error;
496 }
497 params.key = key;
464 } 498 }
465 params.key = key;
466 499
467 /* allocate a superblock info record */ 500 /* allocate a superblock info record */
468 ret = -ENOMEM; 501 ret = -ENOMEM;
@@ -470,20 +503,25 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
470 if (!as) 503 if (!as)
471 goto error_key; 504 goto error_key;
472 505
473 /* Assume we're going to need a volume record; at the very least we can 506 if (!params.dyn_root) {
474 * use it to update the volume record if we have one already. This 507 /* Assume we're going to need a volume record; at the very
475 * checks that the volume exists within the cell. 508 * least we can use it to update the volume record if we have
476 */ 509 * one already. This checks that the volume exists within the
477 candidate = afs_create_volume(&params); 510 * cell.
478 if (IS_ERR(candidate)) { 511 */
479 ret = PTR_ERR(candidate); 512 candidate = afs_create_volume(&params);
480 goto error_as; 513 if (IS_ERR(candidate)) {
481 } 514 ret = PTR_ERR(candidate);
515 goto error_as;
516 }
482 517
483 as->volume = candidate; 518 as->volume = candidate;
519 }
484 520
485 /* allocate a deviceless superblock */ 521 /* allocate a deviceless superblock */
486 sb = sget(fs_type, afs_test_super, afs_set_super, flags, as); 522 sb = sget(fs_type,
523 as->dyn_root ? afs_dynroot_test_super : afs_test_super,
524 afs_set_super, flags, as);
487 if (IS_ERR(sb)) { 525 if (IS_ERR(sb)) {
488 ret = PTR_ERR(sb); 526 ret = PTR_ERR(sb);
489 goto error_as; 527 goto error_as;
@@ -529,9 +567,11 @@ static void afs_kill_super(struct super_block *sb)
529 /* Clear the callback interests (which will do ilookup5) before 567 /* Clear the callback interests (which will do ilookup5) before
530 * deactivating the superblock. 568 * deactivating the superblock.
531 */ 569 */
532 afs_clear_callback_interests(as->net, as->volume->servers); 570 if (as->volume)
571 afs_clear_callback_interests(as->net, as->volume->servers);
533 kill_anon_super(sb); 572 kill_anon_super(sb);
534 afs_deactivate_volume(as->volume); 573 if (as->volume)
574 afs_deactivate_volume(as->volume);
535 afs_destroy_sbi(as); 575 afs_destroy_sbi(as);
536} 576}
537 577
@@ -619,12 +659,24 @@ static void afs_destroy_inode(struct inode *inode)
619 */ 659 */
620static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) 660static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
621{ 661{
662 struct afs_super_info *as = AFS_FS_S(dentry->d_sb);
622 struct afs_fs_cursor fc; 663 struct afs_fs_cursor fc;
623 struct afs_volume_status vs; 664 struct afs_volume_status vs;
624 struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 665 struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
625 struct key *key; 666 struct key *key;
626 int ret; 667 int ret;
627 668
669 buf->f_type = dentry->d_sb->s_magic;
670 buf->f_bsize = AFS_BLOCK_SIZE;
671 buf->f_namelen = AFSNAMEMAX - 1;
672
673 if (as->dyn_root) {
674 buf->f_blocks = 1;
675 buf->f_bavail = 0;
676 buf->f_bfree = 0;
677 return 0;
678 }
679
628 key = afs_request_key(vnode->volume->cell); 680 key = afs_request_key(vnode->volume->cell);
629 if (IS_ERR(key)) 681 if (IS_ERR(key))
630 return PTR_ERR(key); 682 return PTR_ERR(key);
@@ -645,10 +697,6 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
645 key_put(key); 697 key_put(key);
646 698
647 if (ret == 0) { 699 if (ret == 0) {
648 buf->f_type = dentry->d_sb->s_magic;
649 buf->f_bsize = AFS_BLOCK_SIZE;
650 buf->f_namelen = AFSNAMEMAX - 1;
651
652 if (vs.max_quota == 0) 700 if (vs.max_quota == 0)
653 buf->f_blocks = vs.part_max_blocks; 701 buf->f_blocks = vs.part_max_blocks;
654 else 702 else
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c
index af781010753b..49da67034f29 100644
--- a/net/dns_resolver/dns_query.c
+++ b/net/dns_resolver/dns_query.c
@@ -52,11 +52,11 @@
52 * @name: Name to look up 52 * @name: Name to look up
53 * @namelen: Length of name 53 * @namelen: Length of name
54 * @options: Request options (or NULL if no options) 54 * @options: Request options (or NULL if no options)
55 * @_result: Where to place the returned data. 55 * @_result: Where to place the returned data (or NULL)
56 * @_expiry: Where to store the result expiry time (or NULL) 56 * @_expiry: Where to store the result expiry time (or NULL)
57 * 57 *
58 * The data will be returned in the pointer at *result, and the caller is 58 * The data will be returned in the pointer at *result, if provided, and the
59 * responsible for freeing it. 59 * caller is responsible for freeing it.
60 * 60 *
61 * The description should be of the form "[<query_type>:]<domain_name>", and 61 * The description should be of the form "[<query_type>:]<domain_name>", and
62 * the options need to be appropriate for the query type requested. If no 62 * the options need to be appropriate for the query type requested. If no
@@ -81,7 +81,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
81 kenter("%s,%*.*s,%zu,%s", 81 kenter("%s,%*.*s,%zu,%s",
82 type, (int)namelen, (int)namelen, name, namelen, options); 82 type, (int)namelen, (int)namelen, name, namelen, options);
83 83
84 if (!name || namelen == 0 || !_result) 84 if (!name || namelen == 0)
85 return -EINVAL; 85 return -EINVAL;
86 86
87 /* construct the query key description as "[<type>:]<name>" */ 87 /* construct the query key description as "[<type>:]<name>" */
@@ -146,13 +146,15 @@ int dns_query(const char *type, const char *name, size_t namelen,
146 upayload = user_key_payload_locked(rkey); 146 upayload = user_key_payload_locked(rkey);
147 len = upayload->datalen; 147 len = upayload->datalen;
148 148
149 ret = -ENOMEM; 149 if (_result) {
150 *_result = kmalloc(len + 1, GFP_KERNEL); 150 ret = -ENOMEM;
151 if (!*_result) 151 *_result = kmalloc(len + 1, GFP_KERNEL);
152 goto put; 152 if (!*_result)
153 goto put;
153 154
154 memcpy(*_result, upayload->data, len); 155 memcpy(*_result, upayload->data, len);
155 (*_result)[len] = '\0'; 156 (*_result)[len] = '\0';
157 }
156 158
157 if (_expiry) 159 if (_expiry)
158 *_expiry = rkey->expiry; 160 *_expiry = rkey->expiry;