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

aufs: remount 3/5, refresh the opened files



As a part of branch-management, aufs maintains all cached inodes,
dentries, and opened files in remounting.
This commits handles the opened files by counting the number of them,
generating an array of their pointers. I don't like such array
approach, but I don't have another idea.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent 3d06348e
...@@ -84,6 +84,250 @@ out: ...@@ -84,6 +84,250 @@ out:
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
static int au_file_refresh_by_inode(struct file *file, int *need_reopen)
{
int err;
struct au_pin pin;
struct au_finfo *finfo;
struct dentry *parent;
struct inode *inode;
struct super_block *sb;
struct au_cp_generic cpg = {
.dentry = file->f_path.dentry,
.bdst = -1,
.bsrc = -1,
.len = -1,
.pin = &pin,
.flags = AuCpup_DTIME
};
FiMustWriteLock(file);
err = 0;
finfo = au_fi(file);
sb = cpg.dentry->d_sb;
inode = d_inode(cpg.dentry);
cpg.bdst = au_ibtop(inode);
if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry))
goto out;
parent = dget_parent(cpg.dentry);
if (au_test_ro(sb, cpg.bdst, inode)) {
di_read_lock_parent(parent, !AuLock_IR);
err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
cpg.bdst = err;
di_read_unlock(parent, !AuLock_IR);
if (unlikely(err < 0))
goto out_parent;
err = 0;
}
di_read_lock_parent(parent, AuLock_IR);
if (!S_ISDIR(inode->i_mode)
&& au_opt_test(au_mntflags(sb), PLINK)
&& au_plink_test(inode)
&& !d_unhashed(cpg.dentry)
&& cpg.bdst < au_dbtop(cpg.dentry)) {
err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst);
if (unlikely(err))
goto out_unlock;
/* always superio. */
err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
AuPin_DI_LOCKED | AuPin_MNT_WRITE);
if (!err) {
err = au_sio_cpup_simple(&cpg);
au_unpin(&pin);
}
}
out_unlock:
di_read_unlock(parent, AuLock_IR);
out_parent:
dput(parent);
out:
return err;
}
static void au_do_refresh_dir(struct file *file)
{
aufs_bindex_t bindex, bbot, new_bindex, brid;
struct au_hfile *p, tmp, *q;
struct au_finfo *finfo;
struct super_block *sb;
struct au_fidir *fidir;
FiMustWriteLock(file);
sb = file->f_path.dentry->d_sb;
finfo = au_fi(file);
fidir = finfo->fi_hdir;
AuDebugOn(!fidir);
p = fidir->fd_hfile + finfo->fi_btop;
brid = p->hf_br->br_id;
bbot = fidir->fd_bbot;
for (bindex = finfo->fi_btop; bindex <= bbot; bindex++, p++) {
if (!p->hf_file)
continue;
new_bindex = au_br_index(sb, p->hf_br->br_id);
if (new_bindex == bindex)
continue;
if (new_bindex < 0) {
au_set_h_fptr(file, bindex, NULL);
continue;
}
/* swap two lower inode, and loop again */
q = fidir->fd_hfile + new_bindex;
tmp = *q;
*q = *p;
*p = tmp;
if (tmp.hf_file) {
bindex--;
p--;
}
}
p = fidir->fd_hfile;
if (!d_unlinked(file->f_path.dentry)) {
bbot = au_sbbot(sb);
for (finfo->fi_btop = 0; finfo->fi_btop <= bbot;
finfo->fi_btop++, p++)
if (p->hf_file) {
if (file_inode(p->hf_file))
break;
au_hfput(p, /*execed*/0);
}
} else {
bbot = au_br_index(sb, brid);
for (finfo->fi_btop = 0; finfo->fi_btop < bbot;
finfo->fi_btop++, p++)
if (p->hf_file)
au_hfput(p, /*execed*/0);
bbot = au_sbbot(sb);
}
p = fidir->fd_hfile + bbot;
for (fidir->fd_bbot = bbot; fidir->fd_bbot >= finfo->fi_btop;
fidir->fd_bbot--, p--)
if (p->hf_file) {
if (file_inode(p->hf_file))
break;
au_hfput(p, /*execed*/0);
}
AuDebugOn(fidir->fd_bbot < finfo->fi_btop);
}
/*
* after branch manipulating, refresh the file.
*/
static int refresh_file(struct file *file, int (*reopen)(struct file *file))
{
int err, need_reopen, nbr;
aufs_bindex_t bbot, bindex;
struct dentry *dentry;
struct super_block *sb;
struct au_finfo *finfo;
struct au_hfile *hfile;
dentry = file->f_path.dentry;
sb = dentry->d_sb;
nbr = au_sbbot(sb) + 1;
finfo = au_fi(file);
if (!finfo->fi_hdir) {
hfile = &finfo->fi_htop;
AuDebugOn(!hfile->hf_file);
bindex = au_br_index(sb, hfile->hf_br->br_id);
AuDebugOn(bindex < 0);
if (bindex != finfo->fi_btop)
au_set_fbtop(file, bindex);
} else {
err = au_fidir_realloc(finfo, nbr, /*may_shrink*/0);
if (unlikely(err))
goto out;
au_do_refresh_dir(file);
}
err = 0;
need_reopen = 1;
err = au_file_refresh_by_inode(file, &need_reopen);
if (finfo->fi_hdir)
/* harmless if err */
au_fidir_realloc(finfo, nbr, /*may_shrink*/1);
if (!err && need_reopen && !d_unlinked(dentry))
err = reopen(file);
if (!err) {
au_update_figen(file);
goto out; /* success */
}
/* error, close all lower files */
if (finfo->fi_hdir) {
bbot = au_fbbot_dir(file);
for (bindex = au_fbtop(file); bindex <= bbot; bindex++)
au_set_h_fptr(file, bindex, NULL);
}
out:
return err;
}
/* common function to regular file and dir */
int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
int wlock, unsigned int fi_lsc)
{
int err;
unsigned int sigen, figen;
aufs_bindex_t btop;
unsigned char pseudo_link;
struct dentry *dentry;
struct inode *inode;
err = 0;
dentry = file->f_path.dentry;
inode = d_inode(dentry);
sigen = au_sigen(dentry->d_sb);
fi_write_lock_nested(file, fi_lsc);
figen = au_figen(file);
if (!fi_lsc)
di_write_lock_child(dentry);
else
di_write_lock_child2(dentry);
btop = au_dbtop(dentry);
pseudo_link = (btop != au_ibtop(inode));
if (sigen == figen && !pseudo_link && au_fbtop(file) == btop) {
if (!wlock) {
di_downgrade_lock(dentry, AuLock_IR);
fi_downgrade_lock(file);
}
goto out; /* success */
}
AuDbg("sigen %d, figen %d\n", sigen, figen);
if (au_digen_test(dentry, sigen)) {
err = au_reval_dpath(dentry, sigen);
AuDebugOn(!err && au_digen_test(dentry, sigen));
}
if (!err)
err = refresh_file(file, reopen);
if (!err) {
if (!wlock) {
di_downgrade_lock(dentry, AuLock_IR);
fi_downgrade_lock(file);
}
} else {
di_write_unlock(dentry);
fi_write_unlock(file);
}
out:
return err;
}
/* ---------------------------------------------------------------------- */
/* cf. aufs_nopage() */ /* cf. aufs_nopage() */
/* for madvise(2) */ /* for madvise(2) */
static int aufs_readpage(struct file *file __maybe_unused, struct page *page) static int aufs_readpage(struct file *file __maybe_unused, struct page *page)
......
...@@ -55,6 +55,8 @@ extern const struct address_space_operations aufs_aop; ...@@ -55,6 +55,8 @@ extern const struct address_space_operations aufs_aop;
unsigned int au_file_roflags(unsigned int flags); unsigned int au_file_roflags(unsigned int flags);
struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
struct file *file); struct file *file);
int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
int wlock, unsigned int fi_lsc);
/* finfo.c */ /* finfo.c */
void au_hfput(struct au_hfile *hf, int execed); void au_hfput(struct au_hfile *hf, int execed);
...@@ -93,6 +95,45 @@ static inline struct au_finfo *au_fi(struct file *file) ...@@ -93,6 +95,45 @@ static inline struct au_finfo *au_fi(struct file *file)
#define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) #define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem)
#define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) #define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem)
/* lock subclass for finfo */
enum {
AuLsc_FI_1,
AuLsc_FI_2
};
static inline void fi_read_lock_nested(struct file *f, unsigned int lsc)
{
au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc);
}
static inline void fi_write_lock_nested(struct file *f, unsigned int lsc)
{
au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc);
}
/*
* fi_read_lock_1, fi_write_lock_1,
* fi_read_lock_2, fi_write_lock_2
*/
#define AuReadLockFunc(name) \
static inline void fi_read_lock_##name(struct file *f) \
{ fi_read_lock_nested(f, AuLsc_FI_##name); }
#define AuWriteLockFunc(name) \
static inline void fi_write_lock_##name(struct file *f) \
{ fi_write_lock_nested(f, AuLsc_FI_##name); }
#define AuRWLockFuncs(name) \
AuReadLockFunc(name) \
AuWriteLockFunc(name)
AuRWLockFuncs(1);
AuRWLockFuncs(2);
#undef AuReadLockFunc
#undef AuWriteLockFunc
#undef AuRWLockFuncs
#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) #define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem)
#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) #define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem)
#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) #define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem)
......
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