mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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: David 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: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
3e914febd7
commit
30bca65bbb
2 changed files with 131 additions and 48 deletions
177
fs/afs/dynroot.c
177
fs/afs/dynroot.c
|
@ -185,50 +185,6 @@ out:
|
|||
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)
|
||||
|
|
|
@ -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") \
|
||||
|
|
Loading…
Add table
Reference in a new issue