Fix AFFS race condition.
Subsystems (2)
PATCH v2 1/1 Fix AFFS race condition.
AFFS code preallocates several blocks as an optimisation. Unfortunately it's not protected by lock so the same blocks may end up allocated twice. Here is a fix.
fs/affs/affs.h +2 -0
@@ -66,6 +66,8 @@ struct affs_inode_info {u32 i_protect;/* unused attribute bits */ u32 i_lastalloc;/* last allocated block */ int i_pa_cnt;/* number of preallocated blocks */ +spinlock_t i_alloc;/* Protects last 2 fields. */ +struct inode vfs_inode; };
fs/affs/bitmap.c +23 -11
@@ -151,12 +151,18 @@ affs_alloc_block(struct inode *inode, u32 goal)pr_debug ("AFFS: balloc(inode=%lu,goal=%u): " , inode->i_ino, goal); +spin_lock (&AFFS_I (inode)->i_alloc); +if (AFFS_I (inode)->i_pa_cnt) { -pr_debug ("%d\n" ,AFFS_I (inode)->i_lastalloc+1 ); +u32 ret;AFFS_I (inode)->i_pa_cnt--; -return ++AFFS_I (inode)->i_lastalloc; + ret = ++AFFS_I (inode)->i_lastalloc; +spin_unlock (&AFFS_I (inode)->i_alloc); +return ret; } +spin_unlock (&AFFS_I (inode)->i_alloc); +if (!goal || goal > sbi->s_partition_size) {if (goal)affs_warning (sb,"affs_balloc" ,"invalid goal %d" , goal);
@@ -230,16 +236,22 @@ find_bit: bit =ffs (tmp & mask) -1 ; blk += bit + sbi->s_reserved; mask2 = mask =1 << (bit &31 ); -AFFS_I (inode)->i_lastalloc = blk; - -/* prealloc as much as possible within this word */ -while ((mask2 <<=1 )) { -if (!(tmp & mask2)) -break ; -AFFS_I (inode)->i_pa_cnt++; - mask |= mask2; + +spin_lock (&AFFS_I (inode)->i_alloc); +if (!AFFS_I (inode)->i_pa_cnt) { +AFFS_I (inode)->i_lastalloc = blk; + +/* prealloc as much as possible within this word */ +while ((mask2 <<=1 )) { +if (!(tmp & mask2)) +break ; +AFFS_I (inode)->i_pa_cnt++; + mask |= mask2; + } + bm->bm_free -=AFFS_I (inode)->i_pa_cnt +1 ; } - bm->bm_free -=AFFS_I (inode)->i_pa_cnt +1 ; + +spin_unlock (&AFFS_I (inode)->i_alloc); *data =cpu_to_be32 (tmp & ~mask);
fs/affs/file.c +12 -3
@@ -795,12 +795,21 @@ void affs_free_prealloc(struct inode *inode) {struct super_block *sb = inode->i_sb; +u32 first, cnt;pr_debug ("AFFS: free_prealloc(ino=%lu)\n" , inode->i_ino); -while (AFFS_I (inode)->i_pa_cnt) { -AFFS_I (inode)->i_pa_cnt--; -affs_free_block (sb, ++AFFS_I (inode)->i_lastalloc); +spin_lock (&AFFS_I (inode)->i_alloc); + first =AFFS_I (inode)->i_lastalloc; + cnt =AFFS_I (inode)->i_pa_cnt; +AFFS_I (inode)->i_lastalloc += cnt; +AFFS_I (inode)->i_pa_cnt =0 ; + +spin_unlock (&AFFS_I (inode)->i_alloc); + +while (cnt) { + cnt--; +affs_free_block (sb, ++first); } }
fs/affs/super.c +1 -0
@@ -91,6 +91,7 @@ static struct inode *affs_alloc_inode(struct super_block *sb) i->i_lc =NULL ; i->i_ext_bh =NULL ; i->i_pa_cnt =0 ; +spin_lock_init (&i->i_alloc);return &i->vfs_inode; }
Quoted 5 lines · Vladimir 'φ-coder/phcoder' Serbinenko
AFFS code preallocates several blocks as an optimisation. Unfortunately it's not protected by lock so the same blocks may end up allocated twice. Here is a fix.
Signed-off-by Vladimir Serbinenko <[email protected]>
The patch looks good to me now. Thanks! You can add:
Al, will you merge this patch through your tree? AFFS does not seem to
have a maintainer so you are a default fallback...
Honza
Quoted 112 lines
fs/affs/affs.h +2
-0@@ -66,6 +66,8 @@ struct affs_inode_info {u32 i_protect;/* unused attribute bits */ u32 i_lastalloc;/* last allocated block */ int i_pa_cnt;/* number of preallocated blocks */ +spinlock_t i_alloc;/* Protects last 2 fields. */ +struct inode vfs_inode; };fs/affs/bitmap.c +23
-11@@ -151,12 +151,18 @@ affs_alloc_block(struct inode *inode, u32 goal)pr_debug ("AFFS: balloc(inode=%lu,goal=%u): " , inode->i_ino, goal); +spin_lock (&AFFS_I (inode)->i_alloc); +if (AFFS_I (inode)->i_pa_cnt) { -pr_debug ("%d\n" ,AFFS_I (inode)->i_lastalloc+1 ); +u32 ret;AFFS_I (inode)->i_pa_cnt--; -return ++AFFS_I (inode)->i_lastalloc; + ret = ++AFFS_I (inode)->i_lastalloc; +spin_unlock (&AFFS_I (inode)->i_alloc); +return ret; } +spin_unlock (&AFFS_I (inode)->i_alloc); +if (!goal || goal > sbi->s_partition_size) {if (goal)affs_warning (sb,"affs_balloc" ,"invalid goal %d" , goal);@@ -230,16 +236,22 @@ find_bit: bit =ffs (tmp & mask) -1 ; blk += bit + sbi->s_reserved; mask2 = mask =1 << (bit &31 ); -AFFS_I (inode)->i_lastalloc = blk; - -/* prealloc as much as possible within this word */ -while ((mask2 <<=1 )) { -if (!(tmp & mask2)) -break ; -AFFS_I (inode)->i_pa_cnt++; - mask |= mask2; + +spin_lock (&AFFS_I (inode)->i_alloc); +if (!AFFS_I (inode)->i_pa_cnt) { +AFFS_I (inode)->i_lastalloc = blk; + +/* prealloc as much as possible within this word */ +while ((mask2 <<=1 )) { +if (!(tmp & mask2)) +break ; +AFFS_I (inode)->i_pa_cnt++; + mask |= mask2; + } + bm->bm_free -=AFFS_I (inode)->i_pa_cnt +1 ; } - bm->bm_free -=AFFS_I (inode)->i_pa_cnt +1 ; + +spin_unlock (&AFFS_I (inode)->i_alloc); *data =cpu_to_be32 (tmp & ~mask);fs/affs/file.c +12
-3@@ -795,12 +795,21 @@ void affs_free_prealloc(struct inode *inode) {struct super_block *sb = inode->i_sb; +u32 first, cnt;pr_debug ("AFFS: free_prealloc(ino=%lu)\n" , inode->i_ino); -while (AFFS_I (inode)->i_pa_cnt) { -AFFS_I (inode)->i_pa_cnt--; -affs_free_block (sb, ++AFFS_I (inode)->i_lastalloc); +spin_lock (&AFFS_I (inode)->i_alloc); + first =AFFS_I (inode)->i_lastalloc; + cnt =AFFS_I (inode)->i_pa_cnt; +AFFS_I (inode)->i_lastalloc += cnt; +AFFS_I (inode)->i_pa_cnt =0 ; + +spin_unlock (&AFFS_I (inode)->i_alloc); + +while (cnt) { + cnt--; +affs_free_block (sb, ++first); } }fs/affs/super.c +1
-0@@ -91,6 +91,7 @@ static struct inode *affs_alloc_inode(struct super_block *sb) i->i_lc =NULL ; i->i_ext_bh =NULL ; i->i_pa_cnt =0 ; +spin_lock_init (&i->i_alloc);return &i->vfs_inode; }
Signature · 2 lines
Jan Kara <[email protected]> SUSE Labs, CR
2012/5/14 Jan Kara <[email protected]>:
Quoted 5 lines · Vladimir 'φ-coder/phcoder' Serbinenko
Quoted 4 lines
AFFS code preallocates several blocks as an optimisation. Unfortunately it's not protected by lock so the same blocks may end up allocated twice. Here is a fix.
Quoted 9 lines
Quoted 1 line
Signed-off-by Vladimir Serbinenko <[email protected]>The patch looks good to me now. Thanks! You can add:
Reviewed-by Jan Kara <[email protected]>Al, will you merge this patch through your tree? AFFS does not seem to have a maintainer so you are a default fallback...
Honza
I don't know the AFFS code, so only a question. Instead to use a spin lock, I think we can use a simple mutex. Or is the spin lock mandatory?
Marco
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Jan Kara
reviewerQuoted 13 lines · Marco Stornelli
2012/5/14 Jan Kara <[email protected]>:
Quoted 12 lines · Vladimir 'φ-coder/phcoder' Serbinenko
Quoted 5 lines
AFFS code preallocates several blocks as an optimisation. Unfortunately it's not protected by lock so the same blocks may end up allocated twice. Here is a fix.
Signed-off-by Vladimir Serbinenko <[email protected]>The patch looks good to me now. Thanks! You can add:
Reviewed-by Jan Kara <[email protected]>Al, will you merge this patch through your tree? AFFS does not seem to have a maintainer so you are a default fallback...
Quoted 6 lines
Quoted 2 lines
Honza
I don't know the AFFS code, so only a question. Instead to use a spin lock, I think we can use a simple mutex. Or is the spin lock mandatory?
So what would be an advantage of a mutex? Spinlock *is* the simple locking
variant...
Honza
Signature · 6 lines
Jan Kara <[email protected]> SUSE Labs, CR -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 13 lines · Marco Stornelli
2012/5/14 Jan Kara <[email protected]>:
Quoted 12 lines · Vladimir 'φ-coder/phcoder' Serbinenko
Quoted 5 lines
AFFS code preallocates several blocks as an optimisation. Unfortunately it's not protected by lock so the same blocks may end up allocated twice. Here is a fix.
Signed-off-by Vladimir Serbinenko <[email protected]>The patch looks good to me now. Thanks! You can add:
Reviewed-by Jan Kara <[email protected]>Al, will you merge this patch through your tree? AFFS does not seem to
have a maintainer so you are a default fallback...
Quoted 6 lines
Quoted 2 lines
Honza
I don't know the AFFS code, so only a question. Instead to use a spin lock, I think we can use a simple mutex. Or is the spin lock mandatory?
My first version used mutex. But then Jan suggested that since the critical section is very short and doesn't contain any instructions which might sleep, it's better for performance to use a spin lock.
Signature · 2 lines
Regards Vladimir 'φ-coder/phcoder' Serbinenko
2012/5/14 Jan Kara <[email protected]>:
Quoted 17 lines · Marco Stornelli
Quoted 16 lines
2012/5/14 Jan Kara <[email protected]>:
Quoted 14 lines · Vladimir 'φ-coder/phcoder' Serbinenko
Quoted 5 lines
AFFS code preallocates several blocks as an optimisation. Unfortunately it's not protected by lock so the same blocks may end up allocated twice. Here is a fix.
Signed-off-by Vladimir Serbinenko <[email protected]>The patch looks good to me now. Thanks! You can add:
Reviewed-by Jan Kara <[email protected]>Al, will you merge this patch through your tree? AFFS does not seem to have a maintainer so you are a default fallback...
Honza
Quoted 8 lines
Quoted 3 lines
I don't know the AFFS code, so only a question. Instead to use a spin lock, I think we can use a simple mutex. Or is the spin lock mandatory?
So what would be an advantage of a mutex? Spinlock *is* the simple locking variant...
Honza --
None actually, only style, but if there are performance consideration already done, ok it was only a question. :)
Marco
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html