Skip to content

Commit

Permalink
afs: Implement @sys substitution handling
Browse files Browse the repository at this point in the history
Implement the AFS feature by which @sys at the end of a pathname component
may be substituted for one of a list of values, typically naming the
operating system.  Up to 16 alternatives may be specified and these are
tried in turn until one works.  Each network namespace has[*] a separate
independent list.

Upon creation of a new network namespace, the list of values is
initialised[*] to a single OpenAFS-compatible string representing arch type
plus "_linux26".  For example, on x86_64, the sysname is "amd64_linux26".

[*] Or will, once network namespace support is finalised in kAFS.

The list may be set by:

	# for i in foo bar linux-x86_64; do echo $i; done >/proc/fs/afs/sysname

for which separate writes to the same fd are amalgamated and applied on
close.  The LF character may be used as a separator to specify multiple
items in the same write() call.

The list may be cleared by:

	# echo >/proc/fs/afs/sysname

and read by:

	# cat /proc/fs/afs/sysname
	foo
	bar
	linux-x86_64

Signed-off-by: David Howells <[email protected]>
  • Loading branch information
dhowells committed Apr 9, 2018
1 parent 5cf9dd5 commit 6f8880d
Show file tree
Hide file tree
Showing 5 changed files with 380 additions and 2 deletions.
28 changes: 27 additions & 1 deletion Documentation/filesystems/afs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Contents:
- Proc filesystem.
- The cell database.
- Security.
- Examples.
- The @sys substitution.


========
Expand Down Expand Up @@ -230,3 +230,29 @@ If a file is opened with a particular key and then the file descriptor is
passed to a process that doesn't have that key (perhaps over an AF_UNIX
socket), then the operations on the file will be made with key that was used to
open the file.


=====================
THE @SYS SUBSTITUTION
=====================

The list of up to 16 @sys substitutions for the current network namespace can
be configured by writing a list to /proc/fs/afs/sysname:

[root@andromeda ~]# echo foo amd64_linux_26 >/proc/fs/afs/sysname

or cleared entirely by writing an empty list:

[root@andromeda ~]# echo >/proc/fs/afs/sysname

The current list for current network namespace can be retrieved by:

[root@andromeda ~]# cat /proc/fs/afs/sysname
foo
amd64_linux_26

When @sys is being substituted for, each element of the list is tried in the
order given.

By default, the list will contain one item that conforms to the pattern
"<arch>_linux_26", amd64 being the name for x86_64.
63 changes: 63 additions & 0 deletions fs/afs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,62 @@ static struct inode *afs_try_auto_mntpt(struct dentry *dentry, struct inode *dir
return ERR_PTR(ret);
}

/*
* Look up an entry in a directory with @sys substitution.
*/
static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry,
struct key *key)
{
struct afs_sysnames *subs;
struct afs_net *net = afs_i2net(dir);
struct dentry *ret;
char *buf, *p, *name;
int len, i;

_enter("");

ret = ERR_PTR(-ENOMEM);
p = buf = kmalloc(AFSNAMEMAX, GFP_KERNEL);
if (!buf)
goto out_p;
if (dentry->d_name.len > 4) {
memcpy(p, dentry->d_name.name, dentry->d_name.len - 4);
p += dentry->d_name.len - 4;
}

/* There is an ordered list of substitutes that we have to try. */
read_lock(&net->sysnames_lock);
subs = net->sysnames;
refcount_inc(&subs->usage);
read_unlock(&net->sysnames_lock);

for (i = 0; i < subs->nr; i++) {
name = subs->subs[i];
len = dentry->d_name.len - 4 + strlen(name);
if (len >= AFSNAMEMAX) {
ret = ERR_PTR(-ENAMETOOLONG);
goto out_s;
}

strcpy(p, name);
ret = lookup_one_len(buf, dentry->d_parent, len);
if (IS_ERR(ret) || d_is_positive(ret))
goto out_s;
dput(ret);
}

/* We don't want to d_add() the @sys dentry here as we don't want to
* the cached dentry to hide changes to the sysnames list.
*/
ret = NULL;
out_s:
afs_put_sysnames(subs);
kfree(buf);
out_p:
key_put(key);
return ret;
}

/*
* look up an entry in a directory
*/
Expand Down Expand Up @@ -805,6 +861,13 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(ret);
}

if (dentry->d_name.len >= 4 &&
dentry->d_name.name[dentry->d_name.len - 4] == '@' &&
dentry->d_name.name[dentry->d_name.len - 3] == 's' &&
dentry->d_name.name[dentry->d_name.len - 2] == 'y' &&
dentry->d_name.name[dentry->d_name.len - 1] == 's')
return afs_lookup_atsys(dir, dentry, key);

inode = afs_do_lookup(dir, dentry, key);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
Expand Down
16 changes: 16 additions & 0 deletions fs/afs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,18 @@ static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)

extern struct file_system_type afs_fs_type;

/*
* Set of substitutes for @sys.
*/
struct afs_sysnames {
#define AFS_NR_SYSNAME 16
char *subs[AFS_NR_SYSNAME];
refcount_t usage;
unsigned short nr;
short error;
char blank[1];
};

/*
* AFS network namespace record.
*/
Expand Down Expand Up @@ -246,8 +258,11 @@ struct afs_net {

/* Misc */
struct proc_dir_entry *proc_afs; /* /proc/net/afs directory */
struct afs_sysnames *sysnames;
rwlock_t sysnames_lock;
};

extern const char afs_init_sysname[];
extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns

enum afs_cell_state {
Expand Down Expand Up @@ -789,6 +804,7 @@ extern int __net_init afs_proc_init(struct afs_net *);
extern void __net_exit afs_proc_cleanup(struct afs_net *);
extern int afs_proc_cell_setup(struct afs_net *, struct afs_cell *);
extern void afs_proc_cell_remove(struct afs_net *, struct afs_cell *);
extern void afs_put_sysnames(struct afs_sysnames *);

/*
* rotate.c
Expand Down
44 changes: 44 additions & 0 deletions fs/afs/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,42 @@ MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");
struct workqueue_struct *afs_wq;
struct afs_net __afs_net;

#if defined(CONFIG_ALPHA)
const char afs_init_sysname[] = "alpha_linux26";
#elif defined(CONFIG_X86_64)
const char afs_init_sysname[] = "amd64_linux26";
#elif defined(CONFIG_ARM)
const char afs_init_sysname[] = "arm_linux26";
#elif defined(CONFIG_ARM64)
const char afs_init_sysname[] = "aarch64_linux26";
#elif defined(CONFIG_X86_32)
const char afs_init_sysname[] = "i386_linux26";
#elif defined(CONFIG_IA64)
const char afs_init_sysname[] = "ia64_linux26";
#elif defined(CONFIG_PPC64)
const char afs_init_sysname[] = "ppc64_linux26";
#elif defined(CONFIG_PPC32)
const char afs_init_sysname[] = "ppc_linux26";
#elif defined(CONFIG_S390)
#ifdef CONFIG_64BIT
const char afs_init_sysname[] = "s390x_linux26";
#else
const char afs_init_sysname[] = "s390_linux26";
#endif
#elif defined(CONFIG_SPARC64)
const char afs_init_sysname[] = "sparc64_linux26";
#elif defined(CONFIG_SPARC32)
const char afs_init_sysname[] = "sparc_linux26";
#else
const char afs_init_sysname[] = "unknown_linux26";
#endif

/*
* Initialise an AFS network namespace record.
*/
static int __net_init afs_net_init(struct afs_net *net)
{
struct afs_sysnames *sysnames;
int ret;

net->live = true;
Expand Down Expand Up @@ -67,6 +98,16 @@ static int __net_init afs_net_init(struct afs_net *net)
INIT_WORK(&net->fs_manager, afs_manage_servers);
timer_setup(&net->fs_timer, afs_servers_timer, 0);

ret = -ENOMEM;
sysnames = kzalloc(sizeof(*sysnames), GFP_KERNEL);
if (!sysnames)
goto error_sysnames;
sysnames->subs[0] = (char *)&afs_init_sysname;
sysnames->nr = 1;
refcount_set(&sysnames->usage, 1);
net->sysnames = sysnames;
rwlock_init(&net->sysnames_lock);

/* Register the /proc stuff */
ret = afs_proc_init(net);
if (ret < 0)
Expand All @@ -92,6 +133,8 @@ static int __net_init afs_net_init(struct afs_net *net)
net->live = false;
afs_proc_cleanup(net);
error_proc:
afs_put_sysnames(net->sysnames);
error_sysnames:
net->live = false;
return ret;
}
Expand All @@ -106,6 +149,7 @@ static void __net_exit afs_net_exit(struct afs_net *net)
afs_purge_servers(net);
afs_close_socket(net);
afs_proc_cleanup(net);
afs_put_sysnames(net->sysnames);
}

/*
Expand Down
Loading

0 comments on commit 6f8880d

Please sign in to comment.