Some filesystem system calls, such as mkdirat(), take a 'directory fd' to specify the pathwalk origin. This takes either AT_FDCWD or a file descriptor that refers to an open directory. Make it possible to supply a container fd, as obtained from container_create(), instead thereby specifying the container's root as the origin. This performs the filesystem operation into the container's mount namespace. For example: int cfd = container_create("fred", CONTAINER_NEW_MNT_NS, 0); mkdirat(cfd, "/fred", 0755); A better way to do this might be to temporarily override current->fs and current->nsproxy, but this requires splitting those fields so that procfs doesn't see the override. A sequence number and lock are available to protect the root pointer in case container_chroot() and/or container_pivot_root() are implemented. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> --- fs/namei.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 0d35760fee00..2f0310a39e60 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2208,23 +2208,47 @@ static const char *path_init(struct nameidata *nd, unsigned flags) if (!f.file) return ERR_PTR(-EBADF); - dentry = f.file->f_path.dentry; + if (is_container_file(f.file)) { + struct container *c = f.file->private_data; + unsigned seq; - if (*s) { - if (!d_can_lookup(dentry)) { - fdput(f); - return ERR_PTR(-ENOTDIR); + if (!*s) + return ERR_PTR(-EINVAL); + + if (flags & LOOKUP_RCU) { + rcu_read_lock(); + do { + seq = read_seqcount_begin(&c->seq); + nd->path = c->root; + nd->inode = nd->path.dentry->d_inode; + nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); + } while (read_seqcount_retry(&c->seq, seq)); + } else { + spin_lock(&c->lock); + nd->path = c->root; + path_get(&nd->path); + spin_unlock(&c->lock); + nd->inode = nd->path.dentry->d_inode; } - } - - nd->path = f.file->f_path; - if (flags & LOOKUP_RCU) { - rcu_read_lock(); - nd->inode = nd->path.dentry->d_inode; - nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); } else { - path_get(&nd->path); - nd->inode = nd->path.dentry->d_inode; + dentry = f.file->f_path.dentry; + + if (*s) { + if (!d_can_lookup(dentry)) { + fdput(f); + return ERR_PTR(-ENOTDIR); + } + } + + nd->path = f.file->f_path; + if (flags & LOOKUP_RCU) { + rcu_read_lock(); + nd->inode = nd->path.dentry->d_inode; + nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); + } else { + path_get(&nd->path); + nd->inode = nd->path.dentry->d_inode; + } } fdput(f); return s;