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

aufs: mount/unmount



Now aufs becomes mountable with very few features.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent f8ec4890
......@@ -79,6 +79,7 @@ aufs_bindex_t au_dbtaildir(struct dentry *dentry);
void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
struct dentry *h_dentry);
int au_digen_test(struct dentry *dentry, unsigned int sigen);
int au_dbrange_test(struct dentry *dentry);
void au_update_digen(struct dentry *dentry);
void au_update_dbtop(struct dentry *dentry);
void au_update_dbbot(struct dentry *dentry);
......
......@@ -285,6 +285,24 @@ void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
}
}
int au_dbrange_test(struct dentry *dentry)
{
int err;
aufs_bindex_t btop, bbot;
err = 0;
btop = au_dbtop(dentry);
bbot = au_dbbot(dentry);
if (btop >= 0)
AuDebugOn(bbot < 0 && btop > bbot);
else {
err = -EIO;
AuDebugOn(bbot >= 0);
}
return err;
}
int au_digen_test(struct dentry *dentry, unsigned int sigen)
{
int err;
......
......@@ -60,8 +60,7 @@ static void au_do_dir_ts(void *arg)
if (d_really_is_negative(a->dentry))
goto out;
/* no dir->i_mutex lock */
si_read_lock(sb, /*flags*/0); /* noflush */
di_write_lock(a->dentry, AuLsc_DI_CHILD);
aufs_read_lock(a->dentry, AuLock_DW); /* noflush */
dir = d_inode(a->dentry);
btop = au_ibtop(dir);
......@@ -97,8 +96,7 @@ static void au_do_dir_ts(void *arg)
au_cpup_attr_timesizes(dir);
out_unlock:
di_write_unlock(a->dentry);
si_read_unlock(sb);
aufs_read_unlock(a->dentry, AuLock_DW);
out:
dput(a->dentry);
au_nwt_done(&au_sbi(sb)->si_nowait);
......
......@@ -185,10 +185,16 @@ static int __init aufs_init(void)
if (unlikely(err))
goto out_hin;
err = register_filesystem(&aufs_fs_type);
if (unlikely(err))
goto out_cache;
/* since we define pr_fmt, call printk directly */
printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n");
goto out; /* success */
out_cache:
au_cache_fin();
out_hin:
au_hnotify_fin();
out_wkq:
......
......@@ -612,8 +612,7 @@ au_opts_parse_xino_itrunc_path(struct super_block *sb,
xino_itrunc->bindex = -1;
root = sb->s_root;
si_read_lock(sb, AuLock_FLUSH);
di_read_lock_child(root, /*flags*/0);
aufs_read_lock(root, AuLock_FLUSH);
bbot = au_sbbot(sb);
for (bindex = 0; bindex <= bbot; bindex++) {
if (au_h_dptr(root, bindex) == path.dentry) {
......@@ -621,8 +620,7 @@ au_opts_parse_xino_itrunc_path(struct super_block *sb,
break;
}
}
di_read_unlock(root, /*flags*/0);
si_read_unlock(sb);
aufs_read_unlock(root, !AuLock_IR);
path_put(&path);
if (unlikely(xino_itrunc->bindex < 0)) {
......@@ -714,16 +712,13 @@ int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts)
break;
}
u.xino_itrunc->bindex = n;
si_read_lock(sb, AuLock_FLUSH);
di_read_lock_child(root, !AuLock_IR);
aufs_read_lock(root, AuLock_FLUSH);
if (n < 0 || au_sbbot(sb) < n) {
pr_err("out of bounds, %d\n", n);
di_read_unlock(root, !AuLock_IR);
si_read_unlock(sb);
aufs_read_unlock(root, !AuLock_IR);
break;
}
di_read_unlock(root, !AuLock_IR);
si_read_unlock(sb);
aufs_read_unlock(root, !AuLock_IR);
err = 0;
opt->type = token;
break;
......
......@@ -431,8 +431,11 @@ void au_plink_put(struct super_block *sb, int verbose)
void au_plink_clean(struct super_block *sb, int verbose)
{
si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); /* replaced later */
struct dentry *root;
root = sb->s_root;
aufs_write_lock(root);
if (au_opt_test(au_mntflags(sb), PLINK))
au_plink_put(sb, verbose);
si_write_unlock(sb);
aufs_write_unlock(root);
}
......@@ -182,3 +182,54 @@ int si_write_lock(struct super_block *sb, int flags)
return err;
}
/* dentry and super_block lock. call at entry point */
int aufs_read_lock(struct dentry *dentry, int flags)
{
int err;
struct super_block *sb;
sb = dentry->d_sb;
err = si_read_lock(sb, flags);
if (unlikely(err))
goto out;
if (au_ftest_lock(flags, DW))
di_write_lock_child(dentry);
else
di_read_lock_child(dentry, flags);
if (au_ftest_lock(flags, GEN)) {
err = au_digen_test(dentry, au_sigen(sb));
if (!au_opt_test(au_mntflags(sb), UDBA_NONE))
AuDebugOn(!err && au_dbrange_test(dentry));
else if (!err)
err = au_dbrange_test(dentry);
if (unlikely(err))
aufs_read_unlock(dentry, flags);
}
out:
return err;
}
void aufs_read_unlock(struct dentry *dentry, int flags)
{
if (au_ftest_lock(flags, DW))
di_write_unlock(dentry);
else
di_read_unlock(dentry, flags);
si_read_unlock(dentry->d_sb);
}
void aufs_write_lock(struct dentry *dentry)
{
si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW);
di_write_lock_child(dentry);
}
void aufs_write_unlock(struct dentry *dentry)
{
di_write_unlock(dentry);
si_write_unlock(dentry->d_sb);
}
......@@ -222,6 +222,21 @@ static void aufs_put_super(struct super_block *sb)
/* ---------------------------------------------------------------------- */
/* stop extra interpretation of errno in mount(8), and strange error messages */
static int cvt_err(int err)
{
AuTraceErr(err);
switch (err) {
case -ENOENT:
case -ENOTDIR:
case -EEXIST:
case -EIO:
err = -EINVAL;
}
return err;
}
static const struct super_operations aufs_sop = {
.alloc_inode = aufs_alloc_inode,
.destroy_inode = aufs_destroy_inode,
......@@ -229,3 +244,170 @@ static const struct super_operations aufs_sop = {
.drop_inode = generic_delete_inode,
.put_super = aufs_put_super
};
/* ---------------------------------------------------------------------- */
static int alloc_root(struct super_block *sb)
{
int err;
struct inode *inode;
struct dentry *root;
err = -ENOMEM;
inode = au_iget_locked(sb, AUFS_ROOT_INO);
err = PTR_ERR(inode);
if (IS_ERR(inode))
goto out;
inode->i_op = &simple_dir_inode_operations; /* replace later */
inode->i_fop = &simple_dir_operations; /* replace later */
inode->i_mode = S_IFDIR;
set_nlink(inode, 2);
unlock_new_inode(inode);
root = d_make_root(inode);
if (unlikely(!root))
goto out;
err = PTR_ERR(root);
if (IS_ERR(root))
goto out;
err = au_di_init(root);
if (!err) {
sb->s_root = root;
return 0; /* success */
}
dput(root);
out:
return err;
}
static int aufs_fill_super(struct super_block *sb, void *raw_data,
int silent __maybe_unused)
{
int err;
struct au_opts opts = {
.opt = NULL
};
struct dentry *root;
struct inode *inode;
char *arg = raw_data;
if (unlikely(!arg || !*arg)) {
err = -EINVAL;
pr_err("no arg\n");
goto out;
}
err = -ENOMEM;
opts.opt = (void *)__get_free_page(GFP_NOFS);
if (unlikely(!opts.opt))
goto out;
opts.max_opt = PAGE_SIZE / sizeof(*opts.opt);
opts.sb_flags = sb->s_flags;
err = au_si_alloc(sb);
if (unlikely(err))
goto out_opts;
/* all timestamps always follow the ones on the branch */
sb->s_flags |= SB_NOATIME | SB_NODIRATIME;
sb->s_flags |= SB_I_VERSION; /* do we really need this? */
sb->s_op = &aufs_sop;
sb->s_d_op = &simple_dentry_operations; /* replace later */
sb->s_magic = AUFS_SUPER_MAGIC;
sb->s_maxbytes = 0;
sb->s_stack_depth = 1;
err = alloc_root(sb);
if (unlikely(err)) {
si_write_unlock(sb);
goto out_info;
}
root = sb->s_root;
inode = d_inode(root);
/*
* actually we can parse options regardless aufs lock here.
* but at remount time, parsing must be done before aufs lock.
* so we follow the same rule.
*/
ii_write_lock_parent(inode);
aufs_write_unlock(root);
err = au_opts_parse(sb, arg, &opts);
if (unlikely(err))
goto out_root;
/* lock vfs_inode first, then aufs. */
inode_lock(inode);
aufs_write_lock(root);
err = au_opts_mount(sb, &opts);
au_opts_free(&opts);
aufs_write_unlock(root);
inode_unlock(inode);
if (!err)
goto out_opts; /* success */
out_root:
dput(root);
sb->s_root = NULL;
out_info:
kobject_put(&au_sbi(sb)->si_kobj);
sb->s_fs_info = NULL;
out_opts:
free_page((unsigned long)opts.opt);
out:
AuTraceErr(err);
err = cvt_err(err);
AuTraceErr(err);
return err;
}
/* ---------------------------------------------------------------------- */
static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags,
const char *dev_name __maybe_unused,
void *raw_data)
{
struct dentry *root;
/* all timestamps always follow the ones on the branch */
/* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */
root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super);
if (IS_ERR(root))
goto out;
au_sbilist_add(root->d_sb);
out:
return root;
}
static void aufs_kill_sb(struct super_block *sb)
{
struct au_sbinfo *sbinfo;
sbinfo = au_sbi(sb);
if (sbinfo) {
au_sbilist_del(sb);
aufs_write_lock(sb->s_root);
if (sbinfo->si_wbr_create_ops->fin)
sbinfo->si_wbr_create_ops->fin(sb);
if (au_opt_test(sbinfo->si_mntflags, PLINK))
au_plink_put(sb, /*verbose*/1);
au_xino_clr(sb);
sbinfo->si_sb = NULL;
aufs_write_unlock(sb->s_root);
au_nwt_flush(&sbinfo->si_nowait);
}
kill_anon_super(sb);
}
struct file_system_type aufs_fs_type = {
.name = AUFS_FSTYPE,
.mount = aufs_mount,
.kill_sb = aufs_kill_sb,
/* no need to __module_get() and module_put(). */
.owner = THIS_MODULE,
};
......@@ -149,6 +149,7 @@ struct au_sbinfo {
#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */
#define AuLock_NOPLM (1 << 5) /* return err in plm mode */
#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */
#define AuLock_GEN (1 << 7) /* test digen/iigen */
#define au_ftest_lock(flags, name) ((flags) & AuLock_##name)
#define au_fset_lock(flags, name) \
do { (flags) |= AuLock_##name; } while (0)
......@@ -158,6 +159,7 @@ struct au_sbinfo {
/* ---------------------------------------------------------------------- */
/* super.c */
extern struct file_system_type aufs_fs_type;
struct inode *au_iget_locked(struct super_block *sb, ino_t ino);
/* sbinfo.c */
......@@ -170,6 +172,10 @@ aufs_bindex_t au_new_br_id(struct super_block *sb);
int si_read_lock(struct super_block *sb, int flags);
int si_write_lock(struct super_block *sb, int flags);
int aufs_read_lock(struct dentry *dentry, int flags);
void aufs_read_unlock(struct dentry *dentry, int flags);
void aufs_write_lock(struct dentry *dentry);
void aufs_write_unlock(struct dentry *dentry);
/* wbr_policy.c */
extern struct au_wbr_copyup_operations au_wbr_copyup_ops[];
......
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