get rid of S_BIAS
use atomic_inc_not_zero(&sb->s_active) instead of playing games with checking ->s_count > S_BIAS Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
389b8be6ef
Коммит
b20bd1a5e7
|
@ -110,14 +110,10 @@ EXPORT_SYMBOL_GPL(get_inotify_watch);
|
|||
int pin_inotify_watch(struct inotify_watch *watch)
|
||||
{
|
||||
struct super_block *sb = watch->inode->i_sb;
|
||||
spin_lock(&sb_lock);
|
||||
if (sb->s_count >= S_BIAS) {
|
||||
atomic_inc(&sb->s_active);
|
||||
spin_unlock(&sb_lock);
|
||||
if (atomic_inc_not_zero(&sb->s_active)) {
|
||||
atomic_inc(&watch->count);
|
||||
return 1;
|
||||
}
|
||||
spin_unlock(&sb_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -518,16 +514,16 @@ EXPORT_SYMBOL_GPL(inotify_init_watch);
|
|||
* ->s_umount, which will almost certainly wait until the superblock is shut
|
||||
* down and the watch in question is pining for fjords. That's fine, but
|
||||
* there is a problem - we might have hit the window between ->s_active
|
||||
* getting to 0 / ->s_count - below S_BIAS (i.e. the moment when superblock
|
||||
* is past the point of no return and is heading for shutdown) and the
|
||||
* moment when deactivate_super() acquires ->s_umount. We could just do
|
||||
* drop_super() yield() and retry, but that's rather antisocial and this
|
||||
* stuff is luser-triggerable. OTOH, having grabbed ->s_umount and having
|
||||
* found that we'd got there first (i.e. that ->s_root is non-NULL) we know
|
||||
* that we won't race with inotify_umount_inodes(). So we could grab a
|
||||
* reference to watch and do the rest as above, just with drop_super() instead
|
||||
* of deactivate_super(), right? Wrong. We had to drop ih->mutex before we
|
||||
* could grab ->s_umount. So the watch could've been gone already.
|
||||
* getting to 0 (i.e. the moment when superblock is past the point of no return
|
||||
* and is heading for shutdown) and the moment when deactivate_super() acquires
|
||||
* ->s_umount. We could just do drop_super() yield() and retry, but that's
|
||||
* rather antisocial and this stuff is luser-triggerable. OTOH, having grabbed
|
||||
* ->s_umount and having found that we'd got there first (i.e. that ->s_root is
|
||||
* non-NULL) we know that we won't race with inotify_umount_inodes(). So we
|
||||
* could grab a reference to watch and do the rest as above, just with
|
||||
* drop_super() instead of deactivate_super(), right? Wrong. We had to drop
|
||||
* ih->mutex before we could grab ->s_umount. So the watch could've been gone
|
||||
* already.
|
||||
*
|
||||
* That still can be dealt with - we need to save watch->wd, do idr_find()
|
||||
* and compare its result with our pointer. If they match, we either have
|
||||
|
@ -565,14 +561,12 @@ static int pin_to_kill(struct inotify_handle *ih, struct inotify_watch *watch)
|
|||
struct super_block *sb = watch->inode->i_sb;
|
||||
s32 wd = watch->wd;
|
||||
|
||||
spin_lock(&sb_lock);
|
||||
if (sb->s_count >= S_BIAS) {
|
||||
atomic_inc(&sb->s_active);
|
||||
spin_unlock(&sb_lock);
|
||||
if (atomic_inc_not_zero(&sb->s_active)) {
|
||||
get_inotify_watch(watch);
|
||||
mutex_unlock(&ih->mutex);
|
||||
return 1; /* the best outcome */
|
||||
}
|
||||
spin_lock(&sb_lock);
|
||||
sb->s_count++;
|
||||
spin_unlock(&sb_lock);
|
||||
mutex_unlock(&ih->mutex); /* can't grab ->s_umount under it */
|
||||
|
|
28
fs/super.c
28
fs/super.c
|
@ -93,7 +93,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
|
|||
* subclass.
|
||||
*/
|
||||
down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
|
||||
s->s_count = S_BIAS;
|
||||
s->s_count = 1;
|
||||
atomic_set(&s->s_active, 1);
|
||||
mutex_init(&s->s_vfs_rename_mutex);
|
||||
mutex_init(&s->s_dquot.dqio_mutex);
|
||||
|
@ -189,9 +189,7 @@ void put_super(struct super_block *sb)
|
|||
void deactivate_super(struct super_block *s)
|
||||
{
|
||||
struct file_system_type *fs = s->s_type;
|
||||
if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
|
||||
s->s_count -= S_BIAS-1;
|
||||
spin_unlock(&sb_lock);
|
||||
if (atomic_dec_and_test(&s->s_active)) {
|
||||
vfs_dq_off(s, 0);
|
||||
down_write(&s->s_umount);
|
||||
fs->kill_sb(s);
|
||||
|
@ -216,9 +214,7 @@ EXPORT_SYMBOL(deactivate_super);
|
|||
void deactivate_locked_super(struct super_block *s)
|
||||
{
|
||||
struct file_system_type *fs = s->s_type;
|
||||
if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
|
||||
s->s_count -= S_BIAS-1;
|
||||
spin_unlock(&sb_lock);
|
||||
if (atomic_dec_and_test(&s->s_active)) {
|
||||
vfs_dq_off(s, 0);
|
||||
fs->kill_sb(s);
|
||||
put_filesystem(fs);
|
||||
|
@ -243,21 +239,19 @@ EXPORT_SYMBOL(deactivate_locked_super);
|
|||
*/
|
||||
static int grab_super(struct super_block *s) __releases(sb_lock)
|
||||
{
|
||||
if (atomic_inc_not_zero(&s->s_active)) {
|
||||
spin_unlock(&sb_lock);
|
||||
down_write(&s->s_umount);
|
||||
return 1;
|
||||
}
|
||||
/* it's going away */
|
||||
s->s_count++;
|
||||
spin_unlock(&sb_lock);
|
||||
/* usually that'll be enough for it to die... */
|
||||
down_write(&s->s_umount);
|
||||
if (s->s_root) {
|
||||
spin_lock(&sb_lock);
|
||||
if (s->s_count > S_BIAS) {
|
||||
atomic_inc(&s->s_active);
|
||||
s->s_count--;
|
||||
spin_unlock(&sb_lock);
|
||||
return 1;
|
||||
}
|
||||
spin_unlock(&sb_lock);
|
||||
}
|
||||
up_write(&s->s_umount);
|
||||
put_super(s);
|
||||
/* ... but in case it wasn't, let's at least yield() */
|
||||
yield();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1314,7 +1314,6 @@ extern int send_sigurg(struct fown_struct *fown);
|
|||
extern struct list_head super_blocks;
|
||||
extern spinlock_t sb_lock;
|
||||
|
||||
#define S_BIAS (1<<30)
|
||||
struct super_block {
|
||||
struct list_head s_list; /* Keep this first */
|
||||
dev_t s_dev; /* search index; _not_ kdev_t */
|
||||
|
|
Загрузка…
Ссылка в новой задаче