Commit de0ee5c9 authored by J. R. Okajima's avatar J. R. Okajima
Browse files

aufs: ioctl, wbr_fd



Provide a file descriptor corresponding the specified writable branch.
The file descriptor will be used from user-space such as FHSM and
libau.so. For details, see aufs-util.git.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent b41567b1
......@@ -17,7 +17,8 @@ aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \
dynop.o \
finfo.o file.o f_op.o \
dir.o vdir.o \
iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o
iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \
ioctl.o
# all are boolean
aufs-$(CONFIG_PROC_FS) += procfs.o plink.o
......
......@@ -736,6 +736,10 @@ const struct file_operations aufs_dir_fop = {
.llseek = default_llseek,
.read = generic_read_dir,
.iterate_shared = aufs_iterate_shared,
.unlocked_ioctl = aufs_ioctl_dir,
#ifdef CONFIG_COMPAT
.compat_ioctl = aufs_compat_ioctl_dir,
#endif
.open = aufs_open_dir,
.release = aufs_release_dir,
.flush = aufs_flush_dir,
......
......@@ -98,5 +98,8 @@ void au_vdir_free(struct au_vdir *vdir);
int au_vdir_init(struct file *file);
int au_vdir_fill_de(struct file *file, struct dir_context *ctx);
/* ioctl.c */
long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg);
#endif /* __KERNEL__ */
#endif /* __AUFS_DIR_H__ */
......@@ -757,6 +757,10 @@ const struct file_operations aufs_file_fop = {
.read_iter = aufs_read_iter,
.write_iter = aufs_write_iter,
.unlocked_ioctl = aufs_ioctl_nondir,
#ifdef CONFIG_COMPAT
.compat_ioctl = aufs_compat_ioctl_nondir,
#endif
.mmap = aufs_mmap,
.open = aufs_open_nondir,
.flush = aufs_flush_nondir,
......
......@@ -97,6 +97,15 @@ void au_fi_init_once(void *_fi);
void au_finfo_fin(struct file *file);
int au_finfo_init(struct file *file, struct au_fidir *fidir);
/* ioctl.c */
long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_COMPAT
long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
unsigned long arg);
long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
unsigned long arg);
#endif
/* ---------------------------------------------------------------------- */
static inline struct au_finfo *au_fi(struct file *file)
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2005-2019 Junjiro R. Okajima
*/
/*
* ioctl
* plink-management and readdir in userspace.
* assist the pathconf(3) wrapper library.
* move-down
* File-based Hierarchical Storage Management.
*/
#include <linux/compat.h>
#include <linux/file.h>
#include "aufs.h"
static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg)
{
int err, fd;
aufs_bindex_t wbi, bindex, bbot;
struct file *h_file;
struct super_block *sb;
struct dentry *root;
struct au_branch *br;
struct aufs_wbr_fd wbrfd = {
.oflags = au_dir_roflags,
.brid = -1
};
const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY
| O_NOATIME | O_CLOEXEC;
AuDebugOn(wbrfd.oflags & ~valid);
if (arg) {
err = copy_from_user(&wbrfd, arg, sizeof(wbrfd));
if (unlikely(err)) {
err = -EFAULT;
goto out;
}
err = -EINVAL;
AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid);
wbrfd.oflags |= au_dir_roflags;
AuDbg("0%o\n", wbrfd.oflags);
if (unlikely(wbrfd.oflags & ~valid))
goto out;
}
fd = get_unused_fd_flags(0);
err = fd;
if (unlikely(fd < 0))
goto out;
h_file = ERR_PTR(-EINVAL);
wbi = 0;
br = NULL;
sb = path->dentry->d_sb;
root = sb->s_root;
aufs_read_lock(root, AuLock_IR);
bbot = au_sbbot(sb);
if (wbrfd.brid >= 0) {
wbi = au_br_index(sb, wbrfd.brid);
if (unlikely(wbi < 0 || wbi > bbot))
goto out_unlock;
}
h_file = ERR_PTR(-ENOENT);
br = au_sbr(sb, wbi);
if (!au_br_writable(br->br_perm)) {
if (arg)
goto out_unlock;
bindex = wbi + 1;
wbi = -1;
for (; bindex <= bbot; bindex++) {
br = au_sbr(sb, bindex);
if (au_br_writable(br->br_perm)) {
wbi = bindex;
br = au_sbr(sb, wbi);
break;
}
}
}
AuDbg("wbi %d\n", wbi);
if (wbi >= 0)
h_file = au_h_open(root, wbi, wbrfd.oflags, NULL);
out_unlock:
aufs_read_unlock(root, AuLock_IR);
err = PTR_ERR(h_file);
if (IS_ERR(h_file))
goto out_fd;
au_lcnt_dec(&br->br_nfiles); /* cf. au_h_open() */
fd_install(fd, h_file);
err = fd;
goto out; /* success */
out_fd:
put_unused_fd(fd);
out:
AuTraceErr(err);
return err;
}
/* ---------------------------------------------------------------------- */
long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
{
long err;
switch (cmd) {
case AUFS_CTL_WBR_FD:
err = au_wbr_fd(&file->f_path, (void __user *)arg);
break;
default:
/* do not call the lower */
AuDbg("0x%x\n", cmd);
err = -ENOTTY;
}
AuTraceErr(err);
return err;
}
long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg)
{
long err;
switch (cmd) {
case AUFS_CTL_WBR_FD:
err = au_wbr_fd(&file->f_path, (void __user *)arg);
break;
default:
/* do not call the lower */
AuDbg("0x%x\n", cmd);
err = -ENOTTY;
}
AuTraceErr(err);
return err;
}
#ifdef CONFIG_COMPAT
long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
unsigned long arg)
{
long err;
err = aufs_ioctl_dir(file, cmd, arg);
AuTraceErr(err);
return err;
}
long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd,
unsigned long arg)
{
return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg));
}
#endif
......@@ -191,6 +191,30 @@ static inline int au_br_wh_linkable(int brperm)
/* ---------------------------------------------------------------------- */
/* ioctl */
enum {
AuCtl_WBR_FD /* pathconf wrapper */
};
/* borrowed from linux/include/linux/kernel.h */
#ifndef ALIGN
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
#endif
/* borrowed from linux/include/linux/compiler-gcc3.h */
#ifndef __aligned
#define __aligned(x) __attribute__((aligned(x)))
#endif
#ifdef __KERNEL__
#ifndef __packed
#define __packed __attribute__((packed))
#endif
#endif
/* ---------------------------------------------------------------------- */
/* dirren. the branch is identified by the filename who contains this */
struct au_drinfo {
uint64_t ino;
......@@ -210,4 +234,17 @@ struct au_drinfo_fdata {
/* future */
#define AUFS_DRINFO_MAGIC_V2 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x02)
/* ---------------------------------------------------------------------- */
struct aufs_wbr_fd {
uint32_t oflags;
int16_t brid;
} __aligned(8);
/* ---------------------------------------------------------------------- */
#define AuCtlType 'A'
#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \
struct aufs_wbr_fd)
#endif /* __AUFS_TYPE_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment