mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02: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 @@ 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) | ||||
|  |  | |||
|  | @ -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…
	
		Reference in a new issue
	
	 David Howells
						David Howells