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

aufs: branch management, delete 1/3, file list



Implement an internal list of opened files to allow deleting a branch
which has an opened dir. Obviously I don't like such list.

There was such list in linux as sb->s_files, but in linux-3.12 s_files
became containing just a part of the opened files, and in linux-3.13 it
was totally gone.
Aufs still needs the file list, particularly for re-setting the branch
attribute from RW to RO.
After resetting to RO, aufs should return EROFS for write. In order to
support such case, aufs keeps the late s_files and mark_files_ro()
approach.

See also the document in this commit.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent a8203e4e
......@@ -27,3 +27,23 @@ o Check the owner/group/mode of the directory
and the infected file will be valid in aufs.
I am afraid it can be a security issue, but aufs can do nothing except
producing a warning.
Delete a Branch
----------------------------------------------------------------------
o Confirm the deleting branch is not busy
To be general, there is one merit to adopt "remount" interface to
manipulate branches. It is to discard caches. At deleting a branch,
aufs checks the still cached (and connected) dentries and inodes. If
there are any, then they are all in-use. An inode without its
corresponding dentry can be alive alone (for example, inotify/fsnotify case).
For the cached one, aufs checks whether the same named entry exists on
other branches.
If the cached one is a directory, because aufs provides a merged view
to users, as long as one dir is left on any branch aufs can show the
dir to users. In this case, the branch can be removed from aufs.
Otherwise aufs rejects deleting the branch.
If any file on the deleting branch is opened by aufs, then aufs
rejects deleting.
......@@ -315,6 +315,8 @@ static int aufs_release_dir(struct inode *inode __maybe_unused,
finfo = au_fi(file);
fidir = finfo->fi_hdir;
if (fidir) {
au_hbl_del(&finfo->fi_hlist,
&au_sbi(file->f_path.dentry->d_sb)->si_files);
vdir_cache = fidir->fd_vdir_cache; /* lock-free */
if (vdir_cache)
au_vdir_free(vdir_cache);
......
......@@ -79,6 +79,8 @@ int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file)
aufs_bindex_t bindex;
finfo = au_fi(file);
au_hbl_del(&finfo->fi_hlist,
&au_sbi(file->f_path.dentry->d_sb)->si_files);
bindex = finfo->fi_btop;
if (bindex >= 0)
au_set_h_fptr(file, bindex, NULL);
......
......@@ -112,6 +112,11 @@ int au_do_open(struct file *file, struct au_do_open_args *args)
di_read_unlock(dentry, AuLock_IR);
finfo = au_fi(file);
if (!err) {
finfo->fi_file = file;
au_hbl_add(&finfo->fi_hlist,
&au_sbi(file->f_path.dentry->d_sb)->si_files);
}
if (!aopen)
fi_write_unlock(file);
else {
......
......@@ -49,6 +49,9 @@ struct au_finfo {
atomic_t fi_mmapped;
};
struct au_fidir *fi_hdir; /* for dir only */
struct hlist_bl_node fi_hlist;
struct file *fi_file; /* very ugly */
struct rcu_head rcu;
} ____cacheline_aligned_in_smp;
......
......@@ -94,6 +94,8 @@ void au_finfo_fin(struct file *file)
{
struct au_finfo *finfo;
au_lcnt_dec(&au_sbi(file->f_path.dentry->d_sb)->si_nfiles);
finfo = au_fi(file);
AuDebugOn(finfo->fi_hdir);
AuRwDestroy(&finfo->fi_rwsem);
......@@ -120,6 +122,7 @@ int au_finfo_init(struct file *file, struct au_fidir *fidir)
goto out;
err = 0;
au_lcnt_inc(&au_sbi(dentry->d_sb)->si_nfiles);
au_rw_write_lock(&finfo->fi_rwsem);
finfo->fi_btop = -1;
finfo->fi_hdir = fidir;
......
......@@ -26,6 +26,8 @@ void au_si_free(struct kobject *kobj)
AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0));
au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0);
AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0));
au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0);
au_rw_write_lock(&sbinfo->si_rwsem);
au_br_free(sbinfo);
......@@ -36,6 +38,7 @@ void au_si_free(struct kobject *kobj)
AuRwDestroy(&sbinfo->si_rwsem);
au_lcnt_wait_for_fin(&sbinfo->si_ninodes);
/* si_nfiles is waited too */
au_kfree_rcu(sbinfo);
}
......@@ -62,6 +65,7 @@ int au_si_alloc(struct super_block *sb)
au_rw_init_wlock(&sbinfo->si_rwsem);
au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL);
au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL);
sbinfo->si_bbot = -1;
sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2;
......@@ -90,6 +94,8 @@ int au_si_alloc(struct super_block *sb)
init_waitqueue_head(&sbinfo->si_plink_wq);
spin_lock_init(&sbinfo->si_plink_maint_lock);
INIT_HLIST_BL_HEAD(&sbinfo->si_files);
/* with getattr by default */
sbinfo->si_iop_array = aufs_iop;
......
......@@ -65,10 +65,10 @@ struct au_sbinfo {
struct au_rwsem si_rwsem;
/*
* dirty approach to protect sb->sb_inodes from
* dirty approach to protect sb->sb_inodes and ->s_files (gone) from
* remount.
*/
au_lcnt_t si_ninodes;
au_lcnt_t si_ninodes, si_nfiles;
/* branch management */
unsigned int si_generation;
......@@ -136,6 +136,9 @@ struct au_sbinfo {
spinlock_t si_plink_maint_lock;
pid_t si_plink_maint_pid;
/* file list */
struct hlist_bl_head si_files;
/* with/without getattr, brother of sb->s_d_op */
struct inode_operations *si_iop_array;
......
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