Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81153336 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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()
parents ef9417e8 4d673da1
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ Contents:
 - Overview.
 - Usage.
 - Mountpoints.
 - Dynamic root.
 - Proc filesystem.
 - The cell database.
 - Security.
@@ -127,6 +128,22 @@ mounted on /afs in one go by doing:
	umount /afs


============
DYNAMIC ROOT
============

A mount option is available to create a serverless mount that is only usable
for dynamic lookup.  Creating such a mount can be done by, for example:

	mount -t afs none /afs -o dyn

This creates a mount that just has an empty directory at the root.  Attempting
to look up a name in this directory will cause a mountpoint to be created that
looks up a cell of the same name, for example:

	ls /afs/grand.central.org/


===============
PROC FILESYSTEM
===============
+10 −3
Original line number Diff line number Diff line
@@ -332,11 +332,18 @@ bool afs_iterate_addresses(struct afs_addr_cursor *ac)
 */
int afs_end_cursor(struct afs_addr_cursor *ac)
{
	struct afs_addr_list *alist;

	alist = ac->alist;
	if (alist) {
		if (ac->responded && ac->index != ac->start)
		WRITE_ONCE(ac->alist->index, ac->index);
			WRITE_ONCE(alist->index, ac->index);
		afs_put_addrlist(alist);
	}

	afs_put_addrlist(ac->alist);
	ac->addr = NULL;
	ac->alist = NULL;
	ac->begun = false;
	return ac->error;
}

+108 −14
Original line number Diff line number Diff line
@@ -17,10 +17,13 @@
#include <linux/pagemap.h>
#include <linux/ctype.h>
#include <linux/sched.h>
#include <linux/dns_resolver.h>
#include "internal.h"

static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
				 unsigned int flags);
static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
					 unsigned int flags);
static int afs_dir_open(struct inode *inode, struct file *file);
static int afs_readdir(struct file *file, struct dir_context *ctx);
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
@@ -64,6 +67,17 @@ const struct inode_operations afs_dir_inode_operations = {
	.listxattr	= afs_listxattr,
};

const struct file_operations afs_dynroot_file_operations = {
	.open		= dcache_dir_open,
	.release	= dcache_dir_close,
	.iterate_shared	= dcache_readdir,
	.llseek		= dcache_dir_lseek,
};

const struct inode_operations afs_dynroot_inode_operations = {
	.lookup		= afs_dynroot_lookup,
};

const struct dentry_operations afs_fs_dentry_operations = {
	.d_revalidate	= afs_d_revalidate,
	.d_delete	= afs_d_delete,
@@ -467,26 +481,59 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
	return 0;
}

/*
 * Probe to see if a cell may exist.  This prevents positive dentries from
 * being created unnecessarily.
 */
static int afs_probe_cell_name(struct dentry *dentry)
{
	struct afs_cell *cell;
	const char *name = dentry->d_name.name;
	size_t len = dentry->d_name.len;
	int ret;

	/* Names prefixed with a dot are R/W mounts. */
	if (name[0] == '.') {
		if (len == 1)
			return -EINVAL;
		name++;
		len--;
	}

	cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
	if (!IS_ERR(cell)) {
		afs_put_cell(afs_d2net(dentry), cell);
		return 0;
	}

	ret = dns_query("afsdb", name, len, "ipv4", NULL, NULL);
	if (ret == -ENODATA)
		ret = -EDESTADDRREQ;
	return ret;
}

/*
 * Try to auto mount the mountpoint with pseudo directory, if the autocell
 * operation is setted.
 */
static struct inode *afs_try_auto_mntpt(
	int ret, struct dentry *dentry, struct inode *dir, struct key *key,
	struct afs_fid *fid)
static struct inode *afs_try_auto_mntpt(struct dentry *dentry,
					struct inode *dir, struct afs_fid *fid)
{
	const char *devname = dentry->d_name.name;
	struct afs_vnode *vnode = AFS_FS_I(dir);
	struct inode *inode;
	int ret = -ENOENT;

	_enter("%p{%pd}, {%x:%u}",
	       dentry, dentry, vnode->fid.vid, vnode->fid.vnode);

	_enter("%d, %p{%pd}, {%x:%u}, %p",
	       ret, dentry, dentry, vnode->fid.vid, vnode->fid.vnode, key);
	if (!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
		goto out;

	if (ret != -ENOENT ||
	    !test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
	ret = afs_probe_cell_name(dentry);
	if (ret < 0)
		goto out;

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

	ret = afs_do_lookup(dir, dentry, &fid, key);
	if (ret < 0) {
		inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid);
		if (ret == -ENOENT) {
			inode = afs_try_auto_mntpt(dentry, dir, &fid);
			if (!IS_ERR(inode)) {
				key_put(key);
				goto success;
			}

			ret = PTR_ERR(inode);
		}

		key_put(key);
		if (ret == -ENOENT) {
			d_add(dentry, NULL);
@@ -582,6 +632,46 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
	return NULL;
}

/*
 * Look up an entry in a dynroot directory.
 */
static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentry,
					 unsigned int flags)
{
	struct afs_vnode *vnode;
	struct afs_fid fid;
	struct inode *inode;
	int ret;

	vnode = AFS_FS_I(dir);

	_enter("%pd", dentry);

	ASSERTCMP(d_inode(dentry), ==, NULL);

	if (dentry->d_name.len >= AFSNAMEMAX) {
		_leave(" = -ENAMETOOLONG");
		return ERR_PTR(-ENAMETOOLONG);
	}

	inode = afs_try_auto_mntpt(dentry, dir, &fid);
	if (IS_ERR(inode)) {
		ret = PTR_ERR(inode);
		if (ret == -ENOENT) {
			d_add(dentry, NULL);
			_leave(" = NULL [negative]");
			return NULL;
		}
		_leave(" = %d [do]", ret);
		return ERR_PTR(ret);
	}

	d_add(dentry, inode);
	_leave(" = 0 { ino=%lu v=%u }",
	       d_inode(dentry)->i_ino, d_inode(dentry)->i_generation);
	return NULL;
}

/*
 * check that a dentry lookup hit has found a valid entry
 * - NOTE! the hit can be a negative hit too, so we can't assume we have an
@@ -589,6 +679,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
 */
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
{
	struct afs_super_info *as = dentry->d_sb->s_fs_info;
	struct afs_vnode *vnode, *dir;
	struct afs_fid uninitialized_var(fid);
	struct dentry *parent;
@@ -600,6 +691,9 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
	if (flags & LOOKUP_RCU)
		return -ECHILD;

	if (as->dyn_root)
		return 1;

	if (d_really_is_positive(dentry)) {
		vnode = AFS_FS_I(d_inode(dentry));
		_enter("{v={%x:%u} n=%pd fl=%lx},",
+30 −18
Original line number Diff line number Diff line
@@ -147,7 +147,7 @@ int afs_iget5_test(struct inode *inode, void *opaque)
 *
 * These pseudo inodes don't match anything.
 */
static int afs_iget5_autocell_test(struct inode *inode, void *opaque)
static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque)
{
	return 0;
}
@@ -169,31 +169,34 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
}

/*
 * inode retrieval for autocell
 * Create an inode for a dynamic root directory or an autocell dynamic
 * automount dir.
 */
struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
				int namesz, struct key *key)
struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root)
{
	struct afs_iget_data data;
	struct afs_super_info *as;
	struct afs_vnode *vnode;
	struct super_block *sb;
	struct inode *inode;
	static atomic_t afs_autocell_ino;

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

	sb = dir->i_sb;
	as = sb->s_fs_info;
	if (as->volume) {
		data.volume = as->volume;
		data.fid.vid = as->volume->vid;
	}
	if (root) {
		data.fid.vnode = 1;
		data.fid.unique = 1;
	} else {
		data.fid.vnode = atomic_inc_return(&afs_autocell_ino);
		data.fid.unique = 0;
	data.fid.vnode = 0;
	}

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

	inode->i_size		= 0;
	inode->i_mode		= S_IFDIR | S_IRUGO | S_IXUGO;
	if (root) {
		inode->i_op	= &afs_dynroot_inode_operations;
		inode->i_fop	= &afs_dynroot_file_operations;
	} else {
		inode->i_op	= &afs_autocell_inode_operations;
	}
	set_nlink(inode, 2);
	inode->i_uid		= GLOBAL_ROOT_UID;
	inode->i_gid		= GLOBAL_ROOT_GID;
@@ -223,8 +231,12 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
	inode->i_generation	= 0;

	set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
	if (!root) {
		set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
	inode->i_flags |= S_AUTOMOUNT | S_NOATIME;
		inode->i_flags |= S_AUTOMOUNT;
	}

	inode->i_flags |= S_NOATIME;
	unlock_new_inode(inode);
	_leave(" = %p", inode);
	return inode;
+8 −4
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct afs_mount_params {
	bool			rwpath;		/* T if the parent should be considered R/W */
	bool			force;		/* T to force cell type */
	bool			autocell;	/* T if set auto mount operation */
	bool			dyn_root;	/* T if dynamic root */
	afs_voltype_t		type;		/* type of volume requested */
	int			volnamesz;	/* size of volume name */
	const char		*volname;	/* name of volume to mount */
@@ -186,6 +187,7 @@ struct afs_super_info {
	struct afs_net		*net;		/* Network namespace */
	struct afs_cell		*cell;		/* The cell in which the volume resides */
	struct afs_volume	*volume;	/* volume record */
	bool			dyn_root;	/* True if dynamic root */
};

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 *);
/*
 * dir.c
 */
extern bool afs_dir_check_page(struct inode *, struct page *);
extern const struct file_operations afs_dir_file_operations;
extern const struct inode_operations afs_dir_inode_operations;
extern const struct file_operations afs_dynroot_file_operations;
extern const struct inode_operations afs_dynroot_inode_operations;
extern const struct dentry_operations afs_fs_dentry_operations;
extern const struct file_operations afs_dir_file_operations;

extern bool afs_dir_check_page(struct inode *, struct page *);

/*
 * file.c
@@ -695,8 +700,7 @@ extern int afs_fs_get_capabilities(struct afs_net *, struct afs_server *,
 */
extern int afs_fetch_status(struct afs_vnode *, struct key *);
extern int afs_iget5_test(struct inode *, void *);
extern struct inode *afs_iget_autocell(struct inode *, const char *, int,
				       struct key *);
extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool);
extern struct inode *afs_iget(struct super_block *, struct key *,
			      struct afs_fid *, struct afs_file_status *,
			      struct afs_callback *,
Loading