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

aufs: enter/leave flag per task



In freeing aufs iinfo objects, it acquires the internal rw_sem (see
another commit in detail). Since iinfo can be freed anytime, a deadlock
may happen due to the rw_sem. To prevent this problem, this commit
introduces a flag per task.
This is another (very) ugly approach which I don't like.
Signed-off-by: default avatarJ. R. Okajima <hooanon05g@gmail.com>
parent c7ae8357
...@@ -160,12 +160,26 @@ void au_iinfo_fin(struct inode *inode) ...@@ -160,12 +160,26 @@ void au_iinfo_fin(struct inode *inode)
{ {
struct au_iinfo *iinfo; struct au_iinfo *iinfo;
struct au_hinode *hi; struct au_hinode *hi;
struct super_block *sb;
aufs_bindex_t bindex, bbot; aufs_bindex_t bindex, bbot;
const unsigned char unlinked = !inode->i_nlink; const unsigned char unlinked = !inode->i_nlink;
AuDebugOn(au_is_bad_inode(inode)); AuDebugOn(au_is_bad_inode(inode));
au_xino_delete_inode(inode, unlinked); 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();
}
iinfo = au_ii(inode); iinfo = au_ii(inode);
bindex = iinfo->ii_btop; bindex = iinfo->ii_btop;
......
...@@ -17,6 +17,7 @@ void au_si_free(struct kobject *kobj) ...@@ -17,6 +17,7 @@ void au_si_free(struct kobject *kobj)
{ {
int i; int i;
struct au_sbinfo *sbinfo; struct au_sbinfo *sbinfo;
char *locked __maybe_unused; /* debug only */
sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
for (i = 0; i < AuPlink_NHASH; i++) for (i = 0; i < AuPlink_NHASH; i++)
...@@ -75,6 +76,7 @@ int au_si_alloc(struct super_block *sb) ...@@ -75,6 +76,7 @@ int au_si_alloc(struct super_block *sb)
/* leave other members for sysaufs and si_mnt. */ /* leave other members for sysaufs and si_mnt. */
sbinfo->si_sb = sb; sbinfo->si_sb = sb;
sb->s_fs_info = sbinfo; sb->s_fs_info = sbinfo;
si_pid_set(sb);
return 0; /* success */ return 0; /* success */
out_br: out_br:
......
...@@ -156,6 +156,33 @@ AuStubVoid(au_sbilist_del, struct super_block *sb) ...@@ -156,6 +156,33 @@ AuStubVoid(au_sbilist_del, struct super_block *sb)
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* current->atomic_flags */
/* this value should never corrupt the ones defined in linux/sched.h */
#define PFA_AUFS 7
TASK_PFA_TEST(AUFS, test_aufs) /* task_test_aufs */
TASK_PFA_SET(AUFS, aufs) /* task_set_aufs */
TASK_PFA_CLEAR(AUFS, aufs) /* task_clear_aufs */
static inline int si_pid_test(struct super_block *sb)
{
return !!task_test_aufs(current);
}
static inline void si_pid_clr(struct super_block *sb)
{
AuDebugOn(!task_test_aufs(current));
task_clear_aufs(current);
}
static inline void si_pid_set(struct super_block *sb)
{
AuDebugOn(task_test_aufs(current));
task_set_aufs(current);
}
/* ---------------------------------------------------------------------- */
/* lock superblock. mainly for entry point functions */ /* lock superblock. mainly for entry point functions */
#define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem) #define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem)
#define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem) #define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem)
...@@ -179,23 +206,33 @@ AuStubVoid(au_sbilist_del, struct super_block *sb) ...@@ -179,23 +206,33 @@ AuStubVoid(au_sbilist_del, struct super_block *sb)
static inline void si_noflush_read_lock(struct super_block *sb) static inline void si_noflush_read_lock(struct super_block *sb)
{ {
__si_read_lock(sb); __si_read_lock(sb);
/* re-commit later */ si_pid_set(sb);
} }
static inline int si_noflush_read_trylock(struct super_block *sb) static inline int si_noflush_read_trylock(struct super_block *sb)
{ {
return __si_read_trylock(sb); /* re-commit later */ int locked;
locked = __si_read_trylock(sb);
if (locked)
si_pid_set(sb);
return locked;
} }
static inline void si_noflush_write_lock(struct super_block *sb) static inline void si_noflush_write_lock(struct super_block *sb)
{ {
__si_write_lock(sb); __si_write_lock(sb);
/* re-commit later */ si_pid_set(sb);
} }
static inline int si_noflush_write_trylock(struct super_block *sb) static inline int si_noflush_write_trylock(struct super_block *sb)
{ {
return __si_write_trylock(sb); /* re-commit later */ int locked;
locked = __si_write_trylock(sb);
if (locked)
si_pid_set(sb);
return locked;
} }
#if 0 /* reserved */ #if 0 /* reserved */
...@@ -209,7 +246,7 @@ static inline int si_read_trylock(struct super_block *sb, int flags) ...@@ -209,7 +246,7 @@ static inline int si_read_trylock(struct super_block *sb, int flags)
static inline void si_read_unlock(struct super_block *sb) static inline void si_read_unlock(struct super_block *sb)
{ {
/* re-commit later */ si_pid_clr(sb);
__si_read_unlock(sb); __si_read_unlock(sb);
} }
...@@ -224,7 +261,7 @@ static inline int si_write_trylock(struct super_block *sb, int flags) ...@@ -224,7 +261,7 @@ static inline int si_write_trylock(struct super_block *sb, int flags)
static inline void si_write_unlock(struct super_block *sb) static inline void si_write_unlock(struct super_block *sb)
{ {
/* re-commit later */ si_pid_clr(sb);
__si_write_unlock(sb); __si_write_unlock(sb);
} }
......
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