Unverified Commit 30bca65b authored by David Howells's avatar David Howells Committed by Christian Brauner
Browse files

afs: Make /afs/@cell and /afs/.@cell symlinks



Make /afs/@cell a symlink in the /afs dynamic root to match what other AFS
clients do rather than doing a substitution in the dentry name.  This has
the bonus of being tab-expandable also.

Further, provide a /afs/.@cell symlink to point to the dotted cell share.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20250107183454.608451-4-dhowells@redhat.com


cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 3e914feb
Loading
Loading
Loading
Loading
+129 −48
Original line number Diff line number Diff line
@@ -185,50 +185,6 @@ struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
	return ret == -ENOENT ? NULL : ERR_PTR(ret);
}

/*
 * Look up @cell in a dynroot directory.  This is a substitution for the
 * local cell name for the net namespace.
 */
static struct dentry *afs_lookup_atcell(struct dentry *dentry)
{
	struct afs_cell *cell;
	struct afs_net *net = afs_d2net(dentry);
	struct dentry *ret;
	char *name;
	int len;

	if (!net->ws_cell)
		return ERR_PTR(-ENOENT);

	ret = ERR_PTR(-ENOMEM);
	name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
	if (!name)
		goto out_p;

	down_read(&net->cells_lock);
	cell = net->ws_cell;
	if (cell) {
		len = cell->name_len;
		memcpy(name, cell->name, len + 1);
	}
	up_read(&net->cells_lock);

	ret = ERR_PTR(-ENOENT);
	if (!cell)
		goto out_n;

	ret = lookup_one_len(name, dentry->d_parent, len);

	/* We don't want to d_add() the @cell dentry here as we don't want to
	 * the cached dentry to hide changes to the local cell name.
	 */

out_n:
	kfree(name);
out_p:
	return ret;
}

/*
 * Look up an entry in a dynroot directory.
 */
@@ -247,10 +203,6 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr
		return ERR_PTR(-ENAMETOOLONG);
	}

	if (dentry->d_name.len == 5 &&
	    memcmp(dentry->d_name.name, "@cell", 5) == 0)
		return afs_lookup_atcell(dentry);

	return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry);
}

@@ -343,6 +295,131 @@ void afs_dynroot_rmdir(struct afs_net *net, struct afs_cell *cell)
	_leave("");
}

static void afs_atcell_delayed_put_cell(void *arg)
{
	struct afs_cell *cell = arg;

	afs_put_cell(cell, afs_cell_trace_put_atcell);
}

/*
 * Read @cell or .@cell symlinks.
 */
static const char *afs_atcell_get_link(struct dentry *dentry, struct inode *inode,
				       struct delayed_call *done)
{
	struct afs_vnode *vnode = AFS_FS_I(inode);
	struct afs_cell *cell;
	struct afs_net *net = afs_i2net(inode);
	const char *name;
	bool dotted = vnode->fid.vnode == 3;

	if (!net->ws_cell)
		return ERR_PTR(-ENOENT);

	down_read(&net->cells_lock);

	cell = net->ws_cell;
	if (dotted)
		name = cell->name - 1;
	else
		name = cell->name;
	afs_get_cell(cell, afs_cell_trace_get_atcell);
	set_delayed_call(done, afs_atcell_delayed_put_cell, cell);

	up_read(&net->cells_lock);
	return name;
}

static const struct inode_operations afs_atcell_inode_operations = {
	.get_link	= afs_atcell_get_link,
};

/*
 * Look up @cell or .@cell in a dynroot directory.  This is a substitution for
 * the local cell name for the net namespace.
 */
static struct dentry *afs_dynroot_create_symlink(struct dentry *root, const char *name)
{
	struct afs_vnode *vnode;
	struct afs_fid fid = { .vnode = 2, .unique = 1, };
	struct dentry *dentry;
	struct inode *inode;

	if (name[0] == '.')
		fid.vnode = 3;

	dentry = d_alloc_name(root, name);
	if (!dentry)
		return ERR_PTR(-ENOMEM);

	inode = iget5_locked(dentry->d_sb, fid.vnode,
			     afs_iget5_pseudo_test, afs_iget5_pseudo_set, &fid);
	if (!inode) {
		dput(dentry);
		return ERR_PTR(-ENOMEM);
	}

	vnode = AFS_FS_I(inode);

	/* there shouldn't be an existing inode */
	if (WARN_ON_ONCE(!(inode->i_state & I_NEW))) {
		iput(inode);
		dput(dentry);
		return ERR_PTR(-EIO);
	}

	netfs_inode_init(&vnode->netfs, NULL, false);
	simple_inode_init_ts(inode);
	set_nlink(inode, 1);
	inode->i_size		= 0;
	inode->i_mode		= S_IFLNK | 0555;
	inode->i_op		= &afs_atcell_inode_operations;
	inode->i_uid		= GLOBAL_ROOT_UID;
	inode->i_gid		= GLOBAL_ROOT_GID;
	inode->i_blocks		= 0;
	inode->i_generation	= 0;
	inode->i_flags		|= S_NOATIME;

	unlock_new_inode(inode);
	d_splice_alias(inode, dentry);
	return dentry;
}

/*
 * Create @cell and .@cell symlinks.
 */
static int afs_dynroot_symlink(struct afs_net *net)
{
	struct super_block *sb = net->dynroot_sb;
	struct dentry *root, *symlink, *dsymlink;
	int ret;

	/* Let the ->lookup op do the creation */
	root = sb->s_root;
	inode_lock(root->d_inode);
	symlink = afs_dynroot_create_symlink(root, "@cell");
	if (IS_ERR(symlink)) {
		ret = PTR_ERR(symlink);
		goto unlock;
	}

	dsymlink = afs_dynroot_create_symlink(root, ".@cell");
	if (IS_ERR(dsymlink)) {
		ret = PTR_ERR(dsymlink);
		dput(symlink);
		goto unlock;
	}

	/* Note that we're retaining extra refs on the dentries. */
	symlink->d_fsdata = (void *)1UL;
	dsymlink->d_fsdata = (void *)1UL;
	ret = 0;
unlock:
	inode_unlock(root->d_inode);
	return ret;
}

/*
 * Populate a newly created dynamic root with cell names.
 */
@@ -355,6 +432,10 @@ int afs_dynroot_populate(struct super_block *sb)
	mutex_lock(&net->proc_cells_lock);

	net->dynroot_sb = sb;
	ret = afs_dynroot_symlink(net);
	if (ret < 0)
		goto error;

	hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
		ret = afs_dynroot_mkdir(net, cell);
		if (ret < 0)
+2 −0
Original line number Diff line number Diff line
@@ -168,12 +168,14 @@ enum yfs_cm_operation {
#define afs_cell_traces \
	EM(afs_cell_trace_alloc,		"ALLOC     ") \
	EM(afs_cell_trace_free,			"FREE      ") \
	EM(afs_cell_trace_get_atcell,		"GET atcell") \
	EM(afs_cell_trace_get_queue_dns,	"GET q-dns ") \
	EM(afs_cell_trace_get_queue_manage,	"GET q-mng ") \
	EM(afs_cell_trace_get_queue_new,	"GET q-new ") \
	EM(afs_cell_trace_get_vol,		"GET vol   ") \
	EM(afs_cell_trace_insert,		"INSERT    ") \
	EM(afs_cell_trace_manage,		"MANAGE    ") \
	EM(afs_cell_trace_put_atcell,		"PUT atcell") \
	EM(afs_cell_trace_put_candidate,	"PUT candid") \
	EM(afs_cell_trace_put_destroy,		"PUT destry") \
	EM(afs_cell_trace_put_queue_work,	"PUT q-work") \