URL: http://git.c3sl.ufpr.br/pub/scm/aufs/aufs2-standalone.git
-COMMIT: b37c575759dc4535ccc03241c584ad5fe69e3b25
+COMMIT: a9be01e5e9688018ebe9ef46ec5414bb356bc556
-EXTRA_CFLAGS += -I$(src)/include
+EXTRA_CFLAGS += -I$(src)/include
include ${src}/magic.mk
ifeq (${CONFIG_AUFS_FS},m)
else
break;
+ /* some filesystems acquire extra lock */
+ /* lockdep_off(); */
mntput(br->br_mnt);
+ /* lockdep_on(); */
+
kfree(wbr);
kfree(br);
}
* test if the branch is deletable or not.
*/
static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex,
- unsigned int sigen, const unsigned int verbose)
+ unsigned int sigen)
{
int err, i, j, ndentry;
aufs_bindex_t bstart, bend;
+ unsigned char verbose;
struct au_dcsub_pages dpages;
struct au_dpage *dpage;
struct dentry *d;
if (unlikely(err))
goto out_dpages;
+ verbose = !!au_opt_test(au_mntflags(root->d_sb), VERBOSE);
for (i = 0; !err && i < dpages.ndpage; i++) {
dpage = dpages.dpages + i;
ndentry = dpage->ndentry;
}
static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex,
- unsigned int sigen, const unsigned int verbose)
+ unsigned int sigen)
{
int err;
struct inode *i;
aufs_bindex_t bstart, bend;
+ unsigned char verbose;
err = 0;
+ verbose = !!au_opt_test(au_mntflags(sb), VERBOSE);
list_for_each_entry(i, &sb->s_inodes, i_sb_list) {
AuDebugOn(!atomic_read(&i->i_count));
if (!list_empty(&i->i_dentry))
return err;
}
-static int test_children_busy(struct dentry *root, aufs_bindex_t bindex,
- const unsigned int verbose)
+static int test_children_busy(struct dentry *root, aufs_bindex_t bindex)
{
int err;
unsigned int sigen;
DiMustNoWaiters(root);
IiMustNoWaiters(root->d_inode);
di_write_unlock(root);
- err = test_dentry_busy(root, bindex, sigen, verbose);
+ err = test_dentry_busy(root, bindex, sigen);
if (!err)
- err = test_inode_busy(root->d_sb, bindex, sigen, verbose);
+ err = test_inode_busy(root->d_sb, bindex, sigen);
di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */
return err;
}
}
- err = test_children_busy(sb->s_root, bindex, verbose);
+ err = test_children_busy(sb->s_root, bindex);
if (unlikely(err)) {
if (do_wh)
goto out_wh;
struct file *au_xino_create2(struct file *base_file, struct file *copy_src);
struct file *au_xino_create(struct super_block *sb, char *fname, int silent);
ino_t au_xino_new_ino(struct super_block *sb);
-void au_xino_delete_inode(struct inode *inode, const int unlinked);
+int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
+ ino_t ino);
int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
ino_t ino);
int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
{
int err, symlen;
mm_segment_t old_fs;
- union {
- char *k;
- char __user *u;
- } sym;
+ char *sym;
err = -ENOSYS;
if (unlikely(!h_src->d_inode->i_op->readlink))
goto out;
err = -ENOMEM;
- sym.k = __getname_gfp(GFP_NOFS);
- if (unlikely(!sym.k))
+ sym = __getname_gfp(GFP_NOFS);
+ if (unlikely(!sym))
goto out;
old_fs = get_fs();
set_fs(KERNEL_DS);
- symlen = h_src->d_inode->i_op->readlink(h_src, sym.u, PATH_MAX);
+ symlen = h_src->d_inode->i_op->readlink(h_src, (char __user *)sym,
+ PATH_MAX);
err = symlen;
set_fs(old_fs);
if (symlen > 0) {
- sym.k[symlen] = 0;
- err = vfsub_symlink(h_dir, h_path, sym.k);
+ sym[symlen] = 0;
+ err = vfsub_symlink(h_dir, h_path, sym);
}
- __putname(sym.k);
+ __putname(sym);
out:
return err;
}
dpri("i%d: i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu,"
- " ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n",
+ " ct %lld, np %lu, st 0x%lx, f 0x%x, g %x%s%.*s\n",
bindex,
inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??",
atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode,
i_size_read(inode), (unsigned long long)inode->i_blocks,
(long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff,
inode->i_mapping ? inode->i_mapping->nrpages : 0,
- inode->i_state, inode->i_flags, inode->i_version,
- inode->i_generation,
+ inode->i_state, inode->i_flags, inode->i_generation,
l ? ", wh " : "", l, n);
return 0;
}
&& au_fi(file))
snprintf(a, sizeof(a), ", mmapped %d",
!!au_fi(file)->fi_hvmop);
- dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n",
+ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, pos %llu%s\n",
bindex, file->f_mode, file->f_flags, (long)file_count(file),
- file->f_version, file->f_pos, a);
+ file->f_pos, a);
if (file->f_dentry)
do_pri_dentry(bindex, file->f_dentry);
return 0;
* due to whiteout and branch permission.
*/
h_nd->flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE
- | LOOKUP_FOLLOW | LOOKUP_EXCL);
+ | LOOKUP_FOLLOW);
/* unnecessary? */
h_nd->intent.open.file = NULL;
} else
/* ---------------------------------------------------------------------- */
+#if 0
static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync)
{
int err;
err = filemap_fdatawrite(h_inode->i_mapping);
AuDebugOn(!h_inode->i_fop);
if (!err && h_inode->i_fop->fsync)
- err = h_inode->i_fop->fsync(NULL, datasync);
+ err = h_inode->i_fop->fsync(NULL, h_path.dentry,
+ datasync);
if (!err)
err = filemap_fdatawrite(h_inode->i_mapping);
if (!err)
return err;
}
+#endif
static int au_do_fsync_dir(struct file *file, int datasync)
{
static int aufs_fsync_dir(struct file *file, int datasync)
{
int err;
- struct dentry *dentry;
struct super_block *sb;
+ struct dentry *dentry;
+ if (!file) {
+ WARN_ON(1);
+ return -ENOTSUPP;
+ }
dentry = file->f_dentry;
+
IMustLock(dentry->d_inode);
err = 0;
si_noflush_read_lock(sb);
if (file)
err = au_do_fsync_dir(file, datasync);
+/*
else {
di_write_lock_child(dentry);
err = au_do_fsync_dir_no_file(dentry, datasync);
}
+*/
au_cpup_attr_timesizes(dentry->d_inode);
di_write_unlock(dentry);
if (file)
di_read_unlock(dentry, AuLock_IR);
si_read_unlock(sb);
+ /* lockdep_off(); */
err = au_vdir_fill_de(file, dirent, filldir);
+ /* lockdep_on(); */
fsstack_copy_attr_atime(inode, h_inode);
fi_write_unlock(file);
.read = generic_read_dir,
.readdir = aufs_readdir,
.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,
#ifdef CONFIG_AUFS_RDU
/* rdu.c */
long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-long au_rdu_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg);
-#endif
#else
static inline long au_rdu_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
return -EINVAL;
}
-#ifdef CONFIG_COMPAT
-static inline long au_rdu_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- return -EINVAL;
-}
-#endif
#endif
#endif /* __KERNEL__ */
/* ---------------------------------------------------------------------- */
/* inode generation external table */
-void au_xigen_inc(struct inode *inode)
+int au_xigen_inc(struct inode *inode)
{
+ int err;
loff_t pos;
ssize_t sz;
__u32 igen;
struct super_block *sb;
struct au_sbinfo *sbinfo;
+ err = 0;
sb = inode->i_sb;
- AuDebugOn(!au_opt_test(au_mntflags(sb), XINO));
-
sbinfo = au_sbi(sb);
+ /*
+ * temporary workaround for escaping from SiMustAnyLock() in
+ * au_mntflags(), since this function is called from au_iinfo_fin().
+ */
+ if (unlikely(!au_opt_test(sbinfo->si_mntflags, XINO)))
+ goto out;
+
pos = inode->i_ino;
pos *= sizeof(igen);
igen = inode->i_generation + 1;
sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen,
sizeof(igen), &pos);
if (sz == sizeof(igen))
- return; /* success */
+ goto out; /* success */
- if (unlikely(sz >= 0))
+ err = sz;
+ if (unlikely(sz >= 0)) {
+ err = -EIO;
AuIOErr("xigen error (%zd)\n", sz);
+ }
+
+ out:
+ return err;
}
int au_xigen_new(struct inode *inode)
.errp = &err
};
- wkq_err = au_wkq_wait_pre(au_call_mmap_pre, &args);
+ wkq_err = au_wkq_wait(au_call_mmap_pre, &args);
if (unlikely(wkq_err))
err = wkq_err;
if (unlikely(err))
{
int err;
struct au_pin pin;
- struct dentry *dentry;
struct inode *inode;
struct file *h_file;
struct super_block *sb;
+ struct dentry *dentry = file->f_dentry;
- dentry = file->f_dentry;
inode = dentry->d_inode;
IMustLock(file->f_mapping->host);
if (inode != file->f_mapping->host) {
err = -EINVAL;
h_file = au_hf_top(file);
if (h_file->f_op && h_file->f_op->fsync) {
+ struct dentry *h_d;
struct mutex *h_mtx;
/*
* no filemap_fdatawrite() since aufs file has no its own
* mapping, but dir.
*/
- h_mtx = &h_file->f_dentry->d_inode->i_mutex;
+ h_d = h_file->f_dentry;
+ h_mtx = &h_d->d_inode->i_mutex;
mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
err = h_file->f_op->fsync(h_file, datasync);
if (!err)
.poll = aufs_poll,
#endif
.unlocked_ioctl = aufs_ioctl_nondir,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = aufs_ioctl_nondir, /* same */
-#endif
.mmap = aufs_mmap,
.open = aufs_open_nondir,
.flush = aufs_flush_nondir,
inode = dentry->d_inode;
si_noflush_read_lock(sb);
fi_read_lock(file);
- ii_read_lock_child(inode);
+ di_read_lock_child(dentry, AuLock_IW);
err = flush(file, id);
au_cpup_attr_timesizes(inode);
- ii_read_unlock(inode);
+ di_read_unlock(dentry, AuLock_IW);
fi_read_unlock(file);
si_read_unlock(sb);
return err;
/* 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);
-#endif
/* ---------------------------------------------------------------------- */
err = -ENOMEM;
/* iput() and kfree() will be called in au_hnotify() */
+ /*
+ * inotify_mutex is already acquired and kmalloc/prune_icache may lock
+ * iprune_mutex. strange.
+ */
+ /* lockdep_off(); */
args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS);
+ /* lockdep_on(); */
if (unlikely(!args)) {
AuErr1("no memory\n");
iput(dir);
p[len] = 0;
}
+ /* lockdep_off(); */
err = au_wkq_nowait(au_hn_bh, args, dir->i_sb);
+ /* lockdep_on(); */
if (unlikely(err)) {
pr_err("wkq %d\n", err);
iput(args->h_child_inode);
struct nameidata *nd)
{
struct dentry *ret, *parent;
- struct inode *inode;
+ struct inode *inode, *h_inode;
+ struct mutex *mtx;
struct super_block *sb;
int err, npositive;
+ aufs_bindex_t bstart;
IMustLock(dir);
inode = NULL;
if (npositive) {
- inode = au_new_inode(dentry, /*must_new*/0);
+ bstart = au_dbstart(dentry);
+ h_inode = au_h_dptr(dentry, bstart)->d_inode;
+ if (!S_ISDIR(h_inode->i_mode)) {
+ /*
+ * stop 'race'-ing between hardlinks under different
+ * parents.
+ */
+ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx;
+ mutex_lock(mtx);
+ inode = au_new_inode(dentry, /*must_new*/0);
+ mutex_unlock(mtx);
+ } else
+ inode = au_new_inode(dentry, /*must_new*/0);
ret = (void *)inode;
}
if (IS_ERR(inode))
if (ia->ia_size < i_size_read(inode)) {
/* unmap only */
- err = simple_setsize(inode, ia->ia_size);
+ err = vmtruncate(inode, ia->ia_size);
if (unlikely(err))
goto out_unlock;
}
static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
int err;
+ char *buf;
mm_segment_t old_fs;
- union {
- char *k;
- char __user *u;
- } buf;
err = -ENOMEM;
- buf.k = __getname_gfp(GFP_NOFS);
- if (unlikely(!buf.k))
+ buf = __getname_gfp(GFP_NOFS);
+ if (unlikely(!buf))
goto out;
aufs_read_lock(dentry, AuLock_IR);
old_fs = get_fs();
set_fs(KERNEL_DS);
- err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX);
+ err = h_readlink(dentry, au_dbstart(dentry), (char __user *)buf,
+ PATH_MAX);
set_fs(old_fs);
aufs_read_unlock(dentry, AuLock_IR);
if (err >= 0) {
- buf.k[err] = 0;
+ buf[err] = 0;
/* will be freed by put_link */
- nd_set_link(nd, buf.k);
+ nd_set_link(nd, buf);
return NULL; /* success */
}
- __putname(buf.k);
+ __putname(buf);
out:
path_put(&nd->path);
return err;
}
+static int au_iinfo_write0(struct super_block *sb, struct au_hinode *hinode,
+ ino_t ino)
+{
+ int err;
+ aufs_bindex_t bindex;
+ unsigned char locked;
+
+ err = 0;
+ locked = !!si_noflush_read_trylock(sb);
+ bindex = au_br_index(sb, hinode->hi_id);
+ if (bindex >= 0)
+ err = au_xino_write0(sb, bindex, hinode->hi_inode->i_ino, ino);
+ /* error action? */
+ if (locked)
+ si_read_unlock(sb);
+ return err;
+}
+
void au_iinfo_fin(struct inode *inode)
{
+ ino_t ino;
+ aufs_bindex_t bend;
+ unsigned char unlinked = !inode->i_nlink;
struct au_iinfo *iinfo;
struct au_hinode *hi;
struct super_block *sb;
- aufs_bindex_t bindex, bend;
- const unsigned char unlinked = !inode->i_nlink;
+
+ if (unlinked) {
+ int err = au_xigen_inc(inode);
+ if (unlikely(err))
+ AuWarn1("failed resetting i_generation, %d\n", err);
+ }
iinfo = au_ii(inode);
/* bad_inode case */
if (!iinfo)
return;
- sb = inode->i_sb;
- if (si_pid_test(sb))
- au_xino_delete_inode(inode, unlinked);
- else {
- /*
- * it is safe to hide the dependency between sbinfo and
- * sb->s_umount.
- */
- lockdep_off();
- si_noflush_read_lock(sb);
- au_xino_delete_inode(inode, unlinked);
- si_read_unlock(sb);
- lockdep_on();
- }
-
if (iinfo->ii_vdir)
au_vdir_free(iinfo->ii_vdir);
- bindex = iinfo->ii_bstart;
- if (bindex >= 0) {
- hi = iinfo->ii_hinode + bindex;
+ if (iinfo->ii_bstart >= 0) {
+ sb = inode->i_sb;
+ ino = 0;
+ if (unlinked)
+ ino = inode->i_ino;
+ hi = iinfo->ii_hinode + iinfo->ii_bstart;
bend = iinfo->ii_bend;
- while (bindex++ <= bend) {
- if (hi->hi_inode)
+ while (iinfo->ii_bstart++ <= bend) {
+ if (hi->hi_inode) {
+ if (unlinked || !hi->hi_inode->i_nlink) {
+ au_iinfo_write0(sb, hi, ino);
+ /* ignore this error */
+ ino = 0;
+ }
au_hiput(hi);
+ }
hi++;
}
}
+
kfree(iinfo->ii_hinode);
AuRwDestroy(&iinfo->ii_rwsem);
}
#include <linux/limits.h>
#include <linux/types.h>
-#define AUFS_VERSION "2-standalone.tree-35-rcN-20100705"
+#define AUFS_VERSION "2-standalone.tree-35-rcN-20100531"
/* todo? move this to linux-2.6.19/include/magic.h */
#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's')
#define AUFS_RDBLK_DEF 512 /* bytes */
#define AUFS_RDHASH_DEF 32
#define AUFS_WKQ_NAME AUFS_NAME "d"
-#define AUFS_WKQ_PRE_NAME AUFS_WKQ_NAME "_pre"
#define AUFS_MFS_SECOND_DEF 30 /* seconds */
#define AUFS_PLINK_WARN 100 /* number of plinks */
union au_rdu_ent_ul {
struct au_rdu_ent __user *e;
- __u64 ul;
+ unsigned long ul;
};
enum {
AufsCtlRduV_SZ,
+ AufsCtlRduV_SZ_PTR,
AufsCtlRduV_End
};
{
int err;
struct mutex *mtx;
+ const int isdir = (d_type == DT_DIR);
- /* prevent hardlinked inode number from race condition */
+ /* prevent hardlinks from race condition */
mtx = NULL;
- if (d_type != DT_DIR) {
+ if (!isdir) {
mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx;
mutex_lock(mtx);
}
}
out:
- if (mtx)
+ if (!isdir)
mutex_unlock(mtx);
return err;
}
/* todo: return with unlocked? */
struct inode *au_new_inode(struct dentry *dentry, int must_new)
{
- struct inode *inode, *h_inode;
+ struct inode *inode;
struct dentry *h_dentry;
struct super_block *sb;
- struct mutex *mtx;
ino_t h_ino, ino;
int err, match;
aufs_bindex_t bstart;
sb = dentry->d_sb;
bstart = au_dbstart(dentry);
h_dentry = au_h_dptr(dentry, bstart);
- h_inode = h_dentry->d_inode;
- h_ino = h_inode->i_ino;
-
- /*
- * stop 'race'-ing between hardlinks under different
- * parents.
- */
- mtx = NULL;
- if (!S_ISDIR(h_inode->i_mode))
- mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx;
-
- new_ino:
- if (mtx)
- mutex_lock(mtx);
+ h_ino = h_dentry->d_inode->i_ino;
err = au_xino_read(sb, bstart, h_ino, &ino);
inode = ERR_PTR(err);
if (unlikely(err))
goto out;
-
+ new_ino:
if (!ino) {
ino = au_xino_new_ino(sb);
if (unlikely(!ino)) {
iget_failed(inode);
goto out_err;
} else if (!must_new) {
- /*
- * horrible race condition between lookup, readdir and copyup
- * (or something).
- */
- if (mtx)
- mutex_unlock(mtx);
err = reval_inode(inode, dentry, &match);
- if (!err) {
- mtx = NULL;
+ if (!err)
goto out; /* success */
- } else if (match) {
- mtx = NULL;
+ else if (match)
goto out_iput;
- } else if (mtx)
- mutex_lock(mtx);
}
if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode)))
err = au_xino_write(sb, bstart, h_ino, /*ino*/0);
if (!err) {
iput(inode);
- if (mtx)
- mutex_unlock(mtx);
goto new_ino;
}
out_err:
inode = ERR_PTR(err);
out:
- if (mtx)
- mutex_unlock(mtx);
return inode;
}
AuTraceErr(err);
return err;
}
-
-#ifdef CONFIG_COMPAT
-long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- long err;
-
- switch (cmd) {
- case AUFS_CTL_RDU:
- case AUFS_CTL_RDU_INO:
- err = au_rdu_compat_ioctl(file, cmd, arg);
- break;
-
- default:
- err = aufs_ioctl_dir(file, cmd, arg);
- }
-
- AuTraceErr(err);
- return err;
-}
-
-#if 0 /* unused yet */
-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
-#endif
/* true if a kernel thread named 'loop[0-9].*' accesses a file */
int au_test_loopback_kthread(void)
{
- int ret;
+ const char c = current->comm[4];
- ret = 0;
- if (current->flags & PF_KTHREAD) {
- const char c = current->comm[4];
- ret = ('0' <= c && c <= '9'
- && !strncmp(current->comm, "loop", 4));
- }
-
- return ret;
+ return current->mm == NULL
+ && '0' <= c && c <= '9'
+ && strncmp(current->comm, "loop", 4) == 0;
}
{
long err;
struct super_block *sb;
+ struct au_sbinfo *sbinfo;
err = -EACCES;
if (!capable(CAP_SYS_ADMIN))
err = 0;
sb = file->f_dentry->d_sb;
+ sbinfo = au_sbi(sb);
switch (cmd) {
case AUFS_CTL_PLINK_MAINT:
/*
break;
case AUFS_CTL_PLINK_CLEAN:
aufs_write_lock(sb->s_root);
- if (au_opt_test(au_mntflags(sb), PLINK))
+ if (au_opt_test(sbinfo->si_mntflags, PLINK))
au_plink_put(sb);
aufs_write_unlock(sb->s_root);
break;
* readdir in userspace.
*/
-#include <linux/compat.h>
#include <linux/fs_stack.h>
#include <linux/security.h>
#include <linux/uaccess.h>
static int au_rdu_verify(struct aufs_rdu *rdu)
{
- AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | "
+ AuDbg("rdu{%llu, %p, (%u, %u) | %u | %llu, %u, %u | "
"%llu, b%d, 0x%x, g%u}\n",
- rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ],
+ rdu->sz, rdu->ent.e, rdu->verify[0], rdu->verify[1],
rdu->blk,
rdu->rent, rdu->shwh, rdu->full,
rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
rdu->cookie.generation);
- if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu))
+ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)
+ && rdu->verify[AufsCtlRduV_SZ_PTR] == sizeof(rdu))
return 0;
- AuDbg("%u:%u\n",
- rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu));
+ AuDbg("%u:%u, %u:%u\n",
+ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu),
+ rdu->verify[AufsCtlRduV_SZ_PTR], (unsigned int)sizeof(rdu));
return -EINVAL;
}
AuTraceErr(err);
return err;
}
-
-#ifdef CONFIG_COMPAT
-long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- long err, e;
- struct aufs_rdu rdu;
- void __user *p = compat_ptr(arg);
-
- /* todo: get_user()? */
- err = copy_from_user(&rdu, p, sizeof(rdu));
- if (unlikely(err)) {
- err = -EFAULT;
- AuTraceErr(err);
- goto out;
- }
- rdu.ent.e = compat_ptr(rdu.ent.ul);
- err = au_rdu_verify(&rdu);
- if (unlikely(err))
- goto out;
-
- switch (cmd) {
- case AUFS_CTL_RDU:
- err = au_rdu(file, &rdu);
- if (unlikely(err))
- break;
-
- rdu.ent.ul = ptr_to_compat(rdu.ent.e);
- rdu.tail.ul = ptr_to_compat(rdu.tail.e);
- e = copy_to_user(p, &rdu, sizeof(rdu));
- if (unlikely(e)) {
- err = -EFAULT;
- AuTraceErr(err);
- }
- break;
- case AUFS_CTL_RDU_INO:
- err = au_rdu_ino(file, &rdu);
- break;
-
- default:
- /* err = -ENOTTY; */
- err = -EINVAL;
- }
-
- out:
- AuTraceErr(err);
- return err;
-}
-#endif
{
struct au_sbinfo *sbinfo;
struct super_block *sb;
- char *locked __maybe_unused; /* debug only */
sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
AuDebugOn(!list_empty(&sbinfo->si_plink.head));
si_write_lock(sb);
au_xino_clr(sb);
au_br_free(sbinfo);
- si_write_unlock(sb);
-
- AuDebugOn(radix_tree_gang_lookup
- (&sbinfo->au_si_pid.tree, (void **)&locked,
- /*first_index*/PID_MAX_DEFAULT - 1,
- /*max_items*/sizeof(locked)/sizeof(*locked)));
-
kfree(sbinfo->si_branch);
- kfree(sbinfo->au_si_pid.bitmap);
mutex_destroy(&sbinfo->si_xib_mtx);
+ si_write_unlock(sb);
AuRwDestroy(&sbinfo->si_rwsem);
kfree(sbinfo);
if (unlikely(!sbinfo))
goto out;
- BUILD_BUG_ON(sizeof(unsigned long) !=
- sizeof(*sbinfo->au_si_pid.bitmap));
- sbinfo->au_si_pid.bitmap = kcalloc(BITS_TO_LONGS(PID_MAX_DEFAULT),
- sizeof(*sbinfo->au_si_pid.bitmap),
- GFP_NOFS);
- if (unlikely(!sbinfo->au_si_pid.bitmap))
- goto out_sbinfo;
-
/* will be reallocated separately */
sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS);
if (unlikely(!sbinfo->si_branch))
- goto out_pidmap;
+ goto out_sbinfo;
err = sysaufs_si_init(sbinfo);
if (unlikely(err))
au_nwt_init(&sbinfo->si_nowait);
au_rw_init_wlock(&sbinfo->si_rwsem);
- spin_lock_init(&sbinfo->au_si_pid.tree_lock);
- INIT_RADIX_TREE(&sbinfo->au_si_pid.tree, GFP_ATOMIC | __GFP_NOFAIL);
-
sbinfo->si_bend = -1;
sbinfo->si_wbr_copyup = AuWbrCopyup_Def;
/* leave other members for sysaufs and si_mnt. */
sbinfo->si_sb = sb;
sb->s_fs_info = sbinfo;
- si_pid_set(sb);
au_debug_sbinfo_init(sbinfo);
return 0; /* success */
out_br:
kfree(sbinfo->si_branch);
- out_pidmap:
- kfree(sbinfo->au_si_pid.bitmap);
out_sbinfo:
kfree(sbinfo);
out:
di_write_unlock2(d1, d2);
si_read_unlock(d1->d_sb);
}
-
-/* ---------------------------------------------------------------------- */
-
-int si_pid_test_slow(struct super_block *sb)
-{
- void *p;
-
- rcu_read_lock();
- p = radix_tree_lookup(&au_sbi(sb)->au_si_pid.tree, current->pid);
- rcu_read_unlock();
-
- return (long)p;
-}
-
-void si_pid_set_slow(struct super_block *sb)
-{
- int err;
- struct au_sbinfo *sbinfo;
-
- AuDebugOn(si_pid_test_slow(sb));
-
- sbinfo = au_sbi(sb);
- err = radix_tree_preload(GFP_NOFS | __GFP_NOFAIL);
- AuDebugOn(err);
- spin_lock(&sbinfo->au_si_pid.tree_lock);
- err = radix_tree_insert(&sbinfo->au_si_pid.tree, current->pid,
- (void *)1);
- spin_unlock(&sbinfo->au_si_pid.tree_lock);
- AuDebugOn(err);
- radix_tree_preload_end();
-}
-
-void si_pid_clr_slow(struct super_block *sb)
-{
- void *p;
- struct au_sbinfo *sbinfo;
-
- AuDebugOn(!si_pid_test_slow(sb));
-
- sbinfo = au_sbi(sb);
- spin_lock(&sbinfo->au_si_pid.tree_lock);
- p = radix_tree_delete(&sbinfo->au_si_pid.tree, current->pid);
- spin_unlock(&sbinfo->au_si_pid.tree_lock);
- AuDebugOn(1 != (long)p);
-}
static const struct super_operations aufs_sop = {
.alloc_inode = aufs_alloc_inode,
.destroy_inode = aufs_destroy_inode,
- /* always deleting, no clearing */
.drop_inode = generic_delete_inode,
.show_options = aufs_show_options,
.statfs = aufs_statfs,
/* nowait tasks in the system-wide workqueue */
struct au_nowait_tasks si_nowait;
- /*
- * tried sb->s_umount, but failed due to the dependecy between i_mutex.
- * rwsem for au_sbinfo is necessary.
- */
struct au_rwsem si_rwsem;
- /* prevent recursive locking in deleting inode */
- struct {
- unsigned long *bitmap;
- spinlock_t tree_lock;
- struct radix_tree_root tree;
- } au_si_pid;
-
/* branch management */
unsigned int si_generation;
void aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int isdir);
void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2);
-int si_pid_test_slow(struct super_block *sb);
-void si_pid_set_slow(struct super_block *sb);
-void si_pid_clr_slow(struct super_block *sb);
-
/* wbr_policy.c */
extern struct au_wbr_copyup_operations au_wbr_copyup_ops[];
extern struct au_wbr_create_operations au_wbr_create_ops[];
static inline int au_test_nfsd(struct task_struct *tsk)
{
- return (current->flags & PF_KTHREAD)
- && !strcmp(tsk->comm, "nfsd");
+ return !tsk->mm && !strcmp(tsk->comm, "nfsd");
}
-void au_xigen_inc(struct inode *inode);
+int au_xigen_inc(struct inode *inode);
int au_xigen_new(struct inode *inode);
int au_xigen_set(struct super_block *sb, struct file *base);
void au_xigen_clr(struct super_block *sb);
#else
AuStubVoid(au_export_init, struct super_block *sb)
AuStubInt0(au_test_nfsd, struct task_struct *tsk)
-AuStubVoid(au_xigen_inc, struct inode *inode)
+AuStubInt0(au_xigen_inc, struct inode *inode)
AuStubInt0(au_xigen_new, struct inode *inode)
AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base)
AuStubVoid(au_xigen_clr, struct super_block *sb)
/* ---------------------------------------------------------------------- */
-static inline pid_t si_pid_bit(void)
-{
- /* the origin of pid is 1, but the bitmap's is 0 */
- return current->pid - 1;
-}
-
-static inline int si_pid_test(struct super_block *sb)
-{
- pid_t bit = si_pid_bit();
- if (bit < PID_MAX_DEFAULT)
- return test_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
- else
- return si_pid_test_slow(sb);
-}
-
-static inline void si_pid_set(struct super_block *sb)
-{
- pid_t bit = si_pid_bit();
- if (bit < PID_MAX_DEFAULT) {
- AuDebugOn(test_bit(bit, au_sbi(sb)->au_si_pid.bitmap));
- set_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
- /* smp_mb(); */
- } else
- si_pid_set_slow(sb);
-}
-
-static inline void si_pid_clr(struct super_block *sb)
-{
- pid_t bit = si_pid_bit();
- if (bit < PID_MAX_DEFAULT) {
- AuDebugOn(!test_bit(bit, au_sbi(sb)->au_si_pid.bitmap));
- clear_bit(bit, au_sbi(sb)->au_si_pid.bitmap);
- /* smp_mb(); */
- } else
- si_pid_clr_slow(sb);
-}
-
-/* ---------------------------------------------------------------------- */
-
/* lock superblock. mainly for entry point functions */
/*
- * __si_read_lock, __si_write_lock,
- * __si_read_unlock, __si_write_unlock, __si_downgrade_lock
+ * si_noflush_read_lock, si_noflush_write_lock,
+ * si_read_unlock, si_write_unlock, si_downgrade_lock
*/
-AuSimpleRwsemFuncs(__si, struct super_block *sb, &au_sbi(sb)->si_rwsem);
+AuSimpleLockRwsemFuncs(si_noflush, struct super_block *sb,
+ &au_sbi(sb)->si_rwsem);
+AuSimpleUnlockRwsemFuncs(si, struct super_block *sb, &au_sbi(sb)->si_rwsem);
#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem)
#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem)
#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem)
-static inline void si_noflush_read_lock(struct super_block *sb)
-{
- __si_read_lock(sb);
- si_pid_set(sb);
-}
-
-static inline int si_noflush_read_trylock(struct super_block *sb)
-{
- int locked = __si_read_trylock(sb);
- if (locked)
- si_pid_set(sb);
- return locked;
-}
-
-static inline void si_noflush_write_lock(struct super_block *sb)
-{
- __si_write_lock(sb);
- si_pid_set(sb);
-}
-
-static inline int si_noflush_write_trylock(struct super_block *sb)
-{
- int locked = __si_write_trylock(sb);
- if (locked)
- si_pid_set(sb);
- return locked;
-}
-
static inline void si_read_lock(struct super_block *sb, int flags)
{
if (au_ftest_lock(flags, FLUSH))
si_noflush_read_lock(sb);
}
-static inline int si_read_trylock(struct super_block *sb, int flags)
-{
- if (au_ftest_lock(flags, FLUSH))
- au_nwt_flush(&au_sbi(sb)->si_nowait);
- return si_noflush_read_trylock(sb);
-}
-
-static inline void si_read_unlock(struct super_block *sb)
-{
- si_pid_clr(sb);
- __si_read_unlock(sb);
-}
-
static inline void si_write_lock(struct super_block *sb)
{
au_nwt_flush(&au_sbi(sb)->si_nowait);
si_noflush_write_lock(sb);
}
-#if 0 /* unused */
-static inline int si_write_trylock(struct super_block *sb, int flags)
+static inline int si_read_trylock(struct super_block *sb, int flags)
{
if (au_ftest_lock(flags, FLUSH))
au_nwt_flush(&au_sbi(sb)->si_nowait);
- return si_noflush_write_trylock(sb);
-}
-#endif
-
-static inline void si_write_unlock(struct super_block *sb)
-{
- si_pid_clr(sb);
- __si_write_unlock(sb);
+ return si_noflush_read_trylock(sb);
}
-#if 0 /* unused */
-static inline void si_downgrade_lock(struct super_block *sb)
+static inline int si_write_trylock(struct super_block *sb, int flags)
{
- __si_downgrade_lock(sb);
+ if (au_ftest_lock(flags, FLUSH))
+ au_nwt_flush(&au_sbi(sb)->si_nowait);
+ return si_noflush_write_trylock(sb);
}
-#endif
/* ---------------------------------------------------------------------- */
{
struct file *file;
+ /* lockdep_off(); */
file = filp_open(path, oflags, mode);
+ /* lockdep_on(); */
if (IS_ERR(file))
goto out;
vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
{
int err;
+ /* lockdep_off(); */
err = kern_path(name, flags, path);
+ /* lockdep_on(); */
if (!err && path->dentry->d_inode)
vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/
return err;
{
struct dentry *d;
+ lockdep_off();
d = lock_rename(d1, d2);
+ lockdep_on();
au_hn_suspend(hdir1);
if (hdir1 != hdir2)
au_hn_suspend(hdir2);
au_hn_resume(hdir1);
if (hdir1 != hdir2)
au_hn_resume(hdir2);
+ lockdep_off();
unlock_rename(d1, d2);
+ lockdep_on();
}
/* ---------------------------------------------------------------------- */
d = path->dentry;
path->dentry = d->d_parent;
- err = security_path_mknod(path, d, mode, 0);
+ err = security_path_mknod(path, path->dentry, mode, 0);
path->dentry = d;
if (unlikely(err))
goto out;
d = path->dentry;
path->dentry = d->d_parent;
- err = security_path_symlink(path, d, symname);
+ err = security_path_symlink(path, path->dentry, symname);
path->dentry = d;
if (unlikely(err))
goto out;
d = path->dentry;
path->dentry = d->d_parent;
- err = security_path_mknod(path, d, mode, dev);
+ err = security_path_mknod(path, path->dentry, mode, dev);
path->dentry = d;
if (unlikely(err))
goto out;
d = path->dentry;
path->dentry = d->d_parent;
- err = security_path_link(src_dentry, path, d);
+ err = security_path_link(src_dentry, path, path->dentry);
path->dentry = d;
if (unlikely(err))
goto out;
+ /* lockdep_off(); */
err = vfs_link(src_dentry, dir, path->dentry);
+ /* lockdep_on(); */
if (!err) {
struct path tmp = *path;
int did;
d = path->dentry;
path->dentry = d->d_parent;
tmp.dentry = src_dentry->d_parent;
- err = security_path_rename(&tmp, src_dentry, path, d);
+ err = security_path_rename(&tmp, src_dentry, path, path->dentry);
path->dentry = d;
if (unlikely(err))
goto out;
+ /* lockdep_off(); */
err = vfs_rename(src_dir, src_dentry, dir, path->dentry);
+ /* lockdep_on(); */
if (!err) {
int did;
d = path->dentry;
path->dentry = d->d_parent;
- err = security_path_mkdir(path, d, mode);
+ err = security_path_mkdir(path, path->dentry, mode);
path->dentry = d;
if (unlikely(err))
goto out;
d = path->dentry;
path->dentry = d->d_parent;
- err = security_path_rmdir(path, d);
+ err = security_path_rmdir(path, path->dentry);
path->dentry = d;
if (unlikely(err))
goto out;
+ /* lockdep_off(); */
err = vfs_rmdir(dir, path->dentry);
+ /* lockdep_on(); */
if (!err) {
struct path tmp = {
.dentry = path->dentry->d_parent,
{
ssize_t err;
mm_segment_t oldfs;
- union {
- void *k;
- char __user *u;
- } buf;
- buf.k = kbuf;
oldfs = get_fs();
set_fs(KERNEL_DS);
- err = vfsub_read_u(file, buf.u, count, ppos);
+ err = vfsub_read_u(file, (char __user *)kbuf, count, ppos);
set_fs(oldfs);
return err;
}
{
ssize_t err;
+ /* lockdep_off(); */
err = vfs_write(file, ubuf, count, ppos);
+ /* lockdep_on(); */
if (err >= 0)
vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
return err;
{
ssize_t err;
mm_segment_t oldfs;
- union {
- void *k;
- const char __user *u;
- } buf;
- buf.k = kbuf;
oldfs = get_fs();
set_fs(KERNEL_DS);
- err = vfsub_write_u(file, buf.u, count, ppos);
+ err = vfsub_write_u(file, (const char __user *)kbuf, count, ppos);
set_fs(oldfs);
return err;
}
{
int err;
+ /* lockdep_off(); */
err = vfs_readdir(file, filldir, arg);
+ /* lockdep_on(); */
if (err >= 0)
vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/
return err;
{
long err;
+ /* lockdep_off(); */
err = do_splice_to(in, ppos, pipe, len, flags);
+ /* lockdep_on(); */
file_accessed(in);
if (err >= 0)
vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/
{
long err;
+ /* lockdep_off(); */
err = do_splice_from(pipe, out, ppos, len, flags);
+ /* lockdep_on(); */
if (err >= 0)
vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/
return err;
err = locks_verify_truncate(h_inode, h_file, length);
if (!err)
err = security_path_truncate(h_path, length, attr);
- if (!err)
+ if (!err) {
+ /* lockdep_off(); */
err = do_truncate(h_path->dentry, length, attr, h_file);
+ /* lockdep_on(); */
+ }
out_inode:
if (!h_file)
*a->errp = -EPERM;
if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) {
+ /* lockdep_off(); */
*a->errp = notify_change(a->path->dentry, a->ia);
+ /* lockdep_on(); */
if (!*a->errp)
vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/
}
if (h_inode)
atomic_inc(&h_inode->i_count);
+ /* lockdep_off(); */
*a->errp = vfs_unlink(a->dir, d);
+ /* lockdep_on(); */
if (!*a->errp) {
struct path tmp = {
.dentry = d->d_parent,
{
loff_t err;
+ /* lockdep_off(); */
err = vfs_llseek(file, offset, origin);
+ /* lockdep_on(); */
return err;
}
#include <linux/module.h>
#include "aufs.h"
-/* internal workqueue named AUFS_WKQ_NAME and AUFS_WKQ_PRE_NAME */
-enum {
- AuWkq_INORMAL,
- AuWkq_IPRE
-};
-
-static struct {
- char *name;
- struct workqueue_struct *wkq;
-} au_wkq[] = {
- [AuWkq_INORMAL] = {
- .name = AUFS_WKQ_NAME
- },
- [AuWkq_IPRE] = {
- .name = AUFS_WKQ_PRE_NAME
- }
-};
+/* internal workqueue named AUFS_WKQ_NAME */
+static struct workqueue_struct *au_wkq;
struct au_wkinfo {
struct work_struct wk;
}
#endif /* 4KSTACKS */
-static void au_wkq_run(struct au_wkinfo *wkinfo, unsigned int flags)
+static void au_wkq_run(struct au_wkinfo *wkinfo, int do_wait)
{
- struct workqueue_struct *wkq;
-
au_dbg_verify_kthread();
- if (flags & AuWkq_WAIT) {
+ if (do_wait) {
INIT_WORK_ON_STACK(&wkinfo->wk, wkq_func);
- wkq = au_wkq[AuWkq_INORMAL].wkq;
- if (flags & AuWkq_PRE)
- wkq = au_wkq[AuWkq_IPRE].wkq;
- queue_work(wkq, &wkinfo->wk);
+ queue_work(au_wkq, &wkinfo->wk);
} else {
INIT_WORK(&wkinfo->wk, wkq_func);
schedule_work(&wkinfo->wk);
}
}
-int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args)
+int au_wkq_wait(au_wkq_func_t func, void *args)
{
int err;
AuWkqCompDeclare(comp);
struct au_wkinfo wkinfo = {
- .flags = flags,
+ .flags = AuWkq_WAIT,
.func = func,
.args = args
};
err = au_wkq_comp_alloc(&wkinfo, &comp);
if (!err) {
- au_wkq_run(&wkinfo, flags);
+ au_wkq_run(&wkinfo, AuWkq_WAIT);
/* no timeout, no interrupt */
wait_for_completion(wkinfo.comp);
au_wkq_comp_free(comp);
void au_wkq_fin(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(au_wkq); i++)
- if (au_wkq[i].wkq)
- destroy_workqueue(au_wkq[i].wkq);
+ destroy_workqueue(au_wkq);
}
int __init au_wkq_init(void)
{
- int err, i;
-
- err = 0;
- for (i = 0; !err && i < ARRAY_SIZE(au_wkq); i++) {
- au_wkq[i].wkq = create_workqueue(au_wkq[i].name);
- if (IS_ERR(au_wkq[i].wkq))
- err = PTR_ERR(au_wkq[i].wkq);
- else if (!au_wkq[i].wkq)
- err = -ENOMEM;
- if (unlikely(err))
- au_wkq[i].wkq = NULL;
- }
- if (unlikely(err))
- au_wkq_fin();
-
- return err;
+ au_wkq = create_workqueue(AUFS_WKQ_NAME);
+ return 0;
}
/* wkq flags */
#define AuWkq_WAIT 1
-#define AuWkq_PRE (1 << 1)
#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name)
#define au_fset_wkq(flags, name) { (flags) |= AuWkq_##name; }
#define au_fclr_wkq(flags, name) { (flags) &= ~AuWkq_##name; }
/* wkq.c */
-int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args);
+int au_wkq_wait(au_wkq_func_t func, void *args);
int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb);
void au_nwt_init(struct au_nowait_tasks *nwt);
int __init au_wkq_init(void);
/* ---------------------------------------------------------------------- */
-static inline int au_wkq_wait_pre(au_wkq_func_t func, void *args)
-{
- return au_wkq_do_wait(AuWkq_WAIT | AuWkq_PRE, func, args);
-}
-
-static inline int au_wkq_wait(au_wkq_func_t func, void *args)
-{
- return au_wkq_do_wait(AuWkq_WAIT, func, args);
-}
-
static inline int au_test_wkq(struct task_struct *tsk)
{
- return (current->flags & PF_KTHREAD)
+ return !tsk->mm
&& !strncmp(tsk->comm, AUFS_WKQ_NAME "/",
sizeof(AUFS_WKQ_NAME));
}
#include <linux/uaccess.h>
#include "aufs.h"
-ssize_t xino_fread(au_readf_t func, struct file *file, void *kbuf, size_t size,
+ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size,
loff_t *pos)
{
ssize_t err;
mm_segment_t oldfs;
- union {
- void *k;
- char __user *u;
- } buf;
- buf.k = kbuf;
oldfs = get_fs();
set_fs(KERNEL_DS);
do {
/* todo: signal_pending? */
- err = func(file, buf.u, size, pos);
+ err = func(file, (char __user *)buf, size, pos);
} while (err == -EAGAIN || err == -EINTR);
set_fs(oldfs);
/* ---------------------------------------------------------------------- */
-static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *kbuf,
+static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *buf,
size_t size, loff_t *pos)
{
ssize_t err;
mm_segment_t oldfs;
- union {
- void *k;
- const char __user *u;
- } buf;
- buf.k = kbuf;
oldfs = get_fs();
set_fs(KERNEL_DS);
+ /* lockdep_off(); */
do {
/* todo: signal_pending? */
- err = func(file, buf.u, size, pos);
+ err = func(file, (const char __user *)buf, size, pos);
} while (err == -EAGAIN || err == -EINTR);
+ /* lockdep_on(); */
set_fs(oldfs);
#if 0 /* reserved for future use */
/* ---------------------------------------------------------------------- */
-static void au_xib_clear_bit(struct inode *inode)
+int au_xino_write0(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino,
+ ino_t ino)
{
int err, bit;
unsigned long pindex;
- struct super_block *sb;
struct au_sbinfo *sbinfo;
- AuDebugOn(inode->i_nlink);
-
- sb = inode->i_sb;
- xib_calc_bit(inode->i_ino, &pindex, &bit);
- AuDebugOn(page_bits <= bit);
- sbinfo = au_sbi(sb);
- mutex_lock(&sbinfo->si_xib_mtx);
- err = xib_pindex(sb, pindex);
- if (!err) {
- clear_bit(bit, sbinfo->si_xib_buf);
- sbinfo->si_xib_next_bit = bit;
- }
- mutex_unlock(&sbinfo->si_xib_mtx);
-}
-
-/* for s_op->delete_inode() */
-void au_xino_delete_inode(struct inode *inode, const int unlinked)
-{
- int err;
- unsigned int mnt_flags;
- aufs_bindex_t bindex, bend, bi;
- unsigned char try_trunc;
- struct au_iinfo *iinfo;
- struct super_block *sb;
- struct au_hinode *hi;
- struct inode *h_inode;
- struct au_branch *br;
- au_writef_t xwrite;
-
- sb = inode->i_sb;
- mnt_flags = au_mntflags(sb);
- if (!au_opt_test(mnt_flags, XINO)
- || inode->i_ino == AUFS_ROOT_INO)
- return;
+ if (!au_opt_test(au_mntflags(sb), XINO))
+ return 0;
- if (unlinked) {
- au_xigen_inc(inode);
- au_xib_clear_bit(inode);
+ err = 0;
+ if (ino) {
+ sbinfo = au_sbi(sb);
+ xib_calc_bit(ino, &pindex, &bit);
+ AuDebugOn(page_bits <= bit);
+ mutex_lock(&sbinfo->si_xib_mtx);
+ err = xib_pindex(sb, pindex);
+ if (!err) {
+ clear_bit(bit, sbinfo->si_xib_buf);
+ sbinfo->si_xib_next_bit = bit;
+ }
+ mutex_unlock(&sbinfo->si_xib_mtx);
}
- iinfo = au_ii(inode);
- if (!iinfo)
- return;
-
- bindex = iinfo->ii_bstart;
- if (bindex < 0)
- return;
-
- xwrite = au_sbi(sb)->si_xwrite;
- try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO);
- hi = iinfo->ii_hinode + bindex;
- bend = iinfo->ii_bend;
- for (; bindex <= bend; bindex++, hi++) {
- h_inode = hi->hi_inode;
- if (!h_inode
- || (!unlinked && h_inode->i_nlink))
- continue;
-
- /* inode may not be revalidated */
- bi = au_br_index(sb, hi->hi_id);
- if (bi < 0)
- continue;
-
- br = au_sbr(sb, bi);
- err = au_xino_do_write(xwrite, br->br_xino.xi_file,
- h_inode->i_ino, /*ino*/0);
- if (!err && try_trunc
- && au_test_fs_trunc_xino(br->br_mnt->mnt_sb))
- xino_try_trunc(sb, br);
- }
+ if (!err)
+ err = au_xino_write(sb, bindex, h_ino, 0);
+ return err;
}
/* get an unused inode number from bitmap */