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

aufs: ioctl, ibusy



Because of some inode is in use, the deletion of a branch can fail.
For those who wants to test the inode is busy or not, aufs provides an
ioctl, and a utility 'aubusy' in aufs-util.git.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent 681a21c3
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* branch management * branch management
*/ */
#include <linux/compat.h>
#include <linux/statfs.h> #include <linux/statfs.h>
#include "aufs.h" #include "aufs.h"
...@@ -1088,6 +1089,78 @@ out: ...@@ -1088,6 +1089,78 @@ out:
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg)
{
int err;
aufs_bindex_t btop, bbot;
struct aufs_ibusy ibusy;
struct inode *inode, *h_inode;
err = -EPERM;
if (unlikely(!capable(CAP_SYS_ADMIN)))
goto out;
err = copy_from_user(&ibusy, arg, sizeof(ibusy));
if (!err)
/* VERIFY_WRITE */
err = !access_ok(&arg->h_ino, sizeof(arg->h_ino));
if (unlikely(err)) {
err = -EFAULT;
AuTraceErr(err);
goto out;
}
err = -EINVAL;
si_read_lock(sb, AuLock_FLUSH);
if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbbot(sb)))
goto out_unlock;
err = 0;
ibusy.h_ino = 0; /* invalid */
inode = ilookup(sb, ibusy.ino);
if (!inode
|| inode->i_ino == AUFS_ROOT_INO
|| au_is_bad_inode(inode))
goto out_unlock;
ii_read_lock_child(inode);
btop = au_ibtop(inode);
bbot = au_ibbot(inode);
if (btop <= ibusy.bindex && ibusy.bindex <= bbot) {
h_inode = au_h_iptr(inode, ibusy.bindex);
if (h_inode && au_test_ibusy(inode, btop, bbot))
ibusy.h_ino = h_inode->i_ino;
}
ii_read_unlock(inode);
iput(inode);
out_unlock:
si_read_unlock(sb);
if (!err) {
err = __put_user(ibusy.h_ino, &arg->h_ino);
if (unlikely(err)) {
err = -EFAULT;
AuTraceErr(err);
}
}
out:
return err;
}
long au_ibusy_ioctl(struct file *file, unsigned long arg)
{
return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg);
}
#ifdef CONFIG_COMPAT
long au_ibusy_compat_ioctl(struct file *file, unsigned long arg)
{
return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg));
}
#endif
/* ---------------------------------------------------------------------- */
/* /*
* change a branch permission * change a branch permission
*/ */
......
...@@ -187,6 +187,10 @@ struct au_opt_add; ...@@ -187,6 +187,10 @@ struct au_opt_add;
int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount);
struct au_opt_del; struct au_opt_del;
int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount);
long au_ibusy_ioctl(struct file *file, unsigned long arg);
#ifdef CONFIG_COMPAT
long au_ibusy_compat_ioctl(struct file *file, unsigned long arg);
#endif
struct au_opt_mod; struct au_opt_mod;
int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount,
int *do_refresh); int *do_refresh);
......
...@@ -120,6 +120,10 @@ long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -120,6 +120,10 @@ long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg)
err = au_wbr_fd(&file->f_path, (void __user *)arg); err = au_wbr_fd(&file->f_path, (void __user *)arg);
break; break;
case AUFS_CTL_IBUSY:
err = au_ibusy_ioctl(file, arg);
break;
case AUFS_CTL_BRINFO: case AUFS_CTL_BRINFO:
err = au_brinfo_ioctl(file, arg); err = au_brinfo_ioctl(file, arg);
break; break;
...@@ -165,6 +169,10 @@ long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ...@@ -165,6 +169,10 @@ long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
err = au_rdu_compat_ioctl(file, cmd, arg); err = au_rdu_compat_ioctl(file, cmd, arg);
break; break;
case AUFS_CTL_IBUSY:
err = au_ibusy_compat_ioctl(file, arg);
break;
case AUFS_CTL_BRINFO: case AUFS_CTL_BRINFO:
err = au_brinfo_compat_ioctl(file, arg); err = au_brinfo_compat_ioctl(file, arg);
break; break;
......
...@@ -198,6 +198,7 @@ enum { ...@@ -198,6 +198,7 @@ enum {
AuCtl_RDU_INO, AuCtl_RDU_INO,
AuCtl_WBR_FD, /* pathconf wrapper */ AuCtl_WBR_FD, /* pathconf wrapper */
AuCtl_IBUSY, /* busy inode */
AuCtl_BR /* info about branches */ AuCtl_BR /* info about branches */
}; };
...@@ -304,6 +305,13 @@ struct aufs_wbr_fd { ...@@ -304,6 +305,13 @@ struct aufs_wbr_fd {
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
struct aufs_ibusy {
uint64_t ino, h_ino;
int16_t bindex;
} __aligned(8);
/* ---------------------------------------------------------------------- */
union aufs_brinfo { union aufs_brinfo {
/* PATH_MAX may differ between kernel-space and user-space */ /* PATH_MAX may differ between kernel-space and user-space */
char _spacer[4096]; char _spacer[4096];
...@@ -321,6 +329,7 @@ union aufs_brinfo { ...@@ -321,6 +329,7 @@ union aufs_brinfo {
#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) #define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu)
#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ #define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \
struct aufs_wbr_fd) struct aufs_wbr_fd)
#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy)
#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) #define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo)
#endif /* __AUFS_TYPE_H__ */ #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