Skip to content

Commit 30bca65

Browse files
dhowellsbrauner
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] cc: Marc Dionne <[email protected]> cc: [email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 3e914fe commit 30bca65

File tree

2 files changed

+131
-48
lines changed

2 files changed

+131
-48
lines changed

fs/afs/dynroot.c

Lines changed: 129 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -185,50 +185,6 @@ struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir)
185185
return ret == -ENOENT ? NULL : ERR_PTR(ret);
186186
}
187187

188-
/*
189-
* Look up @cell in a dynroot directory. This is a substitution for the
190-
* local cell name for the net namespace.
191-
*/
192-
static struct dentry *afs_lookup_atcell(struct dentry *dentry)
193-
{
194-
struct afs_cell *cell;
195-
struct afs_net *net = afs_d2net(dentry);
196-
struct dentry *ret;
197-
char *name;
198-
int len;
199-
200-
if (!net->ws_cell)
201-
return ERR_PTR(-ENOENT);
202-
203-
ret = ERR_PTR(-ENOMEM);
204-
name = kmalloc(AFS_MAXCELLNAME + 1, GFP_KERNEL);
205-
if (!name)
206-
goto out_p;
207-
208-
down_read(&net->cells_lock);
209-
cell = net->ws_cell;
210-
if (cell) {
211-
len = cell->name_len;
212-
memcpy(name, cell->name, len + 1);
213-
}
214-
up_read(&net->cells_lock);
215-
216-
ret = ERR_PTR(-ENOENT);
217-
if (!cell)
218-
goto out_n;
219-
220-
ret = lookup_one_len(name, dentry->d_parent, len);
221-
222-
/* We don't want to d_add() the @cell dentry here as we don't want to
223-
* the cached dentry to hide changes to the local cell name.
224-
*/
225-
226-
out_n:
227-
kfree(name);
228-
out_p:
229-
return ret;
230-
}
231-
232188
/*
233189
* Look up an entry in a dynroot directory.
234190
*/
@@ -247,10 +203,6 @@ static struct dentry *afs_dynroot_lookup(struct inode *dir, struct dentry *dentr
247203
return ERR_PTR(-ENAMETOOLONG);
248204
}
249205

250-
if (dentry->d_name.len == 5 &&
251-
memcmp(dentry->d_name.name, "@cell", 5) == 0)
252-
return afs_lookup_atcell(dentry);
253-
254206
return d_splice_alias(afs_try_auto_mntpt(dentry, dir), dentry);
255207
}
256208

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

298+
static void afs_atcell_delayed_put_cell(void *arg)
299+
{
300+
struct afs_cell *cell = arg;
301+
302+
afs_put_cell(cell, afs_cell_trace_put_atcell);
303+
}
304+
305+
/*
306+
* Read @cell or .@cell symlinks.
307+
*/
308+
static const char *afs_atcell_get_link(struct dentry *dentry, struct inode *inode,
309+
struct delayed_call *done)
310+
{
311+
struct afs_vnode *vnode = AFS_FS_I(inode);
312+
struct afs_cell *cell;
313+
struct afs_net *net = afs_i2net(inode);
314+
const char *name;
315+
bool dotted = vnode->fid.vnode == 3;
316+
317+
if (!net->ws_cell)
318+
return ERR_PTR(-ENOENT);
319+
320+
down_read(&net->cells_lock);
321+
322+
cell = net->ws_cell;
323+
if (dotted)
324+
name = cell->name - 1;
325+
else
326+
name = cell->name;
327+
afs_get_cell(cell, afs_cell_trace_get_atcell);
328+
set_delayed_call(done, afs_atcell_delayed_put_cell, cell);
329+
330+
up_read(&net->cells_lock);
331+
return name;
332+
}
333+
334+
static const struct inode_operations afs_atcell_inode_operations = {
335+
.get_link = afs_atcell_get_link,
336+
};
337+
338+
/*
339+
* Look up @cell or .@cell in a dynroot directory. This is a substitution for
340+
* the local cell name for the net namespace.
341+
*/
342+
static struct dentry *afs_dynroot_create_symlink(struct dentry *root, const char *name)
343+
{
344+
struct afs_vnode *vnode;
345+
struct afs_fid fid = { .vnode = 2, .unique = 1, };
346+
struct dentry *dentry;
347+
struct inode *inode;
348+
349+
if (name[0] == '.')
350+
fid.vnode = 3;
351+
352+
dentry = d_alloc_name(root, name);
353+
if (!dentry)
354+
return ERR_PTR(-ENOMEM);
355+
356+
inode = iget5_locked(dentry->d_sb, fid.vnode,
357+
afs_iget5_pseudo_test, afs_iget5_pseudo_set, &fid);
358+
if (!inode) {
359+
dput(dentry);
360+
return ERR_PTR(-ENOMEM);
361+
}
362+
363+
vnode = AFS_FS_I(inode);
364+
365+
/* there shouldn't be an existing inode */
366+
if (WARN_ON_ONCE(!(inode->i_state & I_NEW))) {
367+
iput(inode);
368+
dput(dentry);
369+
return ERR_PTR(-EIO);
370+
}
371+
372+
netfs_inode_init(&vnode->netfs, NULL, false);
373+
simple_inode_init_ts(inode);
374+
set_nlink(inode, 1);
375+
inode->i_size = 0;
376+
inode->i_mode = S_IFLNK | 0555;
377+
inode->i_op = &afs_atcell_inode_operations;
378+
inode->i_uid = GLOBAL_ROOT_UID;
379+
inode->i_gid = GLOBAL_ROOT_GID;
380+
inode->i_blocks = 0;
381+
inode->i_generation = 0;
382+
inode->i_flags |= S_NOATIME;
383+
384+
unlock_new_inode(inode);
385+
d_splice_alias(inode, dentry);
386+
return dentry;
387+
}
388+
389+
/*
390+
* Create @cell and .@cell symlinks.
391+
*/
392+
static int afs_dynroot_symlink(struct afs_net *net)
393+
{
394+
struct super_block *sb = net->dynroot_sb;
395+
struct dentry *root, *symlink, *dsymlink;
396+
int ret;
397+
398+
/* Let the ->lookup op do the creation */
399+
root = sb->s_root;
400+
inode_lock(root->d_inode);
401+
symlink = afs_dynroot_create_symlink(root, "@cell");
402+
if (IS_ERR(symlink)) {
403+
ret = PTR_ERR(symlink);
404+
goto unlock;
405+
}
406+
407+
dsymlink = afs_dynroot_create_symlink(root, ".@cell");
408+
if (IS_ERR(dsymlink)) {
409+
ret = PTR_ERR(dsymlink);
410+
dput(symlink);
411+
goto unlock;
412+
}
413+
414+
/* Note that we're retaining extra refs on the dentries. */
415+
symlink->d_fsdata = (void *)1UL;
416+
dsymlink->d_fsdata = (void *)1UL;
417+
ret = 0;
418+
unlock:
419+
inode_unlock(root->d_inode);
420+
return ret;
421+
}
422+
346423
/*
347424
* Populate a newly created dynamic root with cell names.
348425
*/
@@ -355,6 +432,10 @@ int afs_dynroot_populate(struct super_block *sb)
355432
mutex_lock(&net->proc_cells_lock);
356433

357434
net->dynroot_sb = sb;
435+
ret = afs_dynroot_symlink(net);
436+
if (ret < 0)
437+
goto error;
438+
358439
hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
359440
ret = afs_dynroot_mkdir(net, cell);
360441
if (ret < 0)

include/trace/events/afs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,14 @@ enum yfs_cm_operation {
168168
#define afs_cell_traces \
169169
EM(afs_cell_trace_alloc, "ALLOC ") \
170170
EM(afs_cell_trace_free, "FREE ") \
171+
EM(afs_cell_trace_get_atcell, "GET atcell") \
171172
EM(afs_cell_trace_get_queue_dns, "GET q-dns ") \
172173
EM(afs_cell_trace_get_queue_manage, "GET q-mng ") \
173174
EM(afs_cell_trace_get_queue_new, "GET q-new ") \
174175
EM(afs_cell_trace_get_vol, "GET vol ") \
175176
EM(afs_cell_trace_insert, "INSERT ") \
176177
EM(afs_cell_trace_manage, "MANAGE ") \
178+
EM(afs_cell_trace_put_atcell, "PUT atcell") \
177179
EM(afs_cell_trace_put_candidate, "PUT candid") \
178180
EM(afs_cell_trace_put_destroy, "PUT destry") \
179181
EM(afs_cell_trace_put_queue_work, "PUT q-work") \

0 commit comments

Comments
 (0)