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:
parent
389b8be6ef
commit
b20bd1a5e7
|
@ -110,14 +110,10 @@ EXPORT_SYMBOL_GPL(get_inotify_watch);
|
||||||
int pin_inotify_watch(struct inotify_watch *watch)
|
int pin_inotify_watch(struct inotify_watch *watch)
|
||||||
{
|
{
|
||||||
struct super_block *sb = watch->inode->i_sb;
|
struct super_block *sb = watch->inode->i_sb;
|
||||||
spin_lock(&sb_lock);
|
if (atomic_inc_not_zero(&sb->s_active)) {
|
||||||
if (sb->s_count >= S_BIAS) {
|
|
||||||
atomic_inc(&sb->s_active);
|
|
||||||
spin_unlock(&sb_lock);
|
|
||||||
atomic_inc(&watch->count);
|
atomic_inc(&watch->count);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
spin_unlock(&sb_lock);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,16 +514,16 @@ EXPORT_SYMBOL_GPL(inotify_init_watch);
|
||||||
* ->s_umount, which will almost certainly wait until the superblock is shut
|
* ->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
|
* 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
|
* 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
|
* getting to 0 (i.e. the moment when superblock is past the point of no return
|
||||||
* is past the point of no return and is heading for shutdown) and the
|
* and is heading for shutdown) and the moment when deactivate_super() acquires
|
||||||
* moment when deactivate_super() acquires ->s_umount. We could just do
|
* ->s_umount. We could just do drop_super() yield() and retry, but that's
|
||||||
* drop_super() yield() and retry, but that's rather antisocial and this
|
* rather antisocial and this stuff is luser-triggerable. OTOH, having grabbed
|
||||||
* stuff is luser-triggerable. OTOH, having grabbed ->s_umount and having
|
* ->s_umount and having found that we'd got there first (i.e. that ->s_root is
|
||||||
* found that we'd got there first (i.e. that ->s_root is non-NULL) we know
|
* non-NULL) we know that we won't race with inotify_umount_inodes(). So we
|
||||||
* that we won't race with inotify_umount_inodes(). So we could grab a
|
* could grab a reference to watch and do the rest as above, just with
|
||||||
* reference to watch and do the rest as above, just with drop_super() instead
|
* drop_super() instead of deactivate_super(), right? Wrong. We had to drop
|
||||||
* of deactivate_super(), right? Wrong. We had to drop ih->mutex before we
|
* ih->mutex before we could grab ->s_umount. So the watch could've been gone
|
||||||
* could grab ->s_umount. So the watch could've been gone already.
|
* already.
|
||||||
*
|
*
|
||||||
* That still can be dealt with - we need to save watch->wd, do idr_find()
|
* 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
|
* 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;
|
struct super_block *sb = watch->inode->i_sb;
|
||||||
s32 wd = watch->wd;
|
s32 wd = watch->wd;
|
||||||
|
|
||||||
spin_lock(&sb_lock);
|
if (atomic_inc_not_zero(&sb->s_active)) {
|
||||||
if (sb->s_count >= S_BIAS) {
|
|
||||||
atomic_inc(&sb->s_active);
|
|
||||||
spin_unlock(&sb_lock);
|
|
||||||
get_inotify_watch(watch);
|
get_inotify_watch(watch);
|
||||||
mutex_unlock(&ih->mutex);
|
mutex_unlock(&ih->mutex);
|
||||||
return 1; /* the best outcome */
|
return 1; /* the best outcome */
|
||||||
}
|
}
|
||||||
|
spin_lock(&sb_lock);
|
||||||
sb->s_count++;
|
sb->s_count++;
|
||||||
spin_unlock(&sb_lock);
|
spin_unlock(&sb_lock);
|
||||||
mutex_unlock(&ih->mutex); /* can't grab ->s_umount under it */
|
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.
|
* subclass.
|
||||||
*/
|
*/
|
||||||
down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
|
down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
|
||||||
s->s_count = S_BIAS;
|
s->s_count = 1;
|
||||||
atomic_set(&s->s_active, 1);
|
atomic_set(&s->s_active, 1);
|
||||||
mutex_init(&s->s_vfs_rename_mutex);
|
mutex_init(&s->s_vfs_rename_mutex);
|
||||||
mutex_init(&s->s_dquot.dqio_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)
|
void deactivate_super(struct super_block *s)
|
||||||
{
|
{
|
||||||
struct file_system_type *fs = s->s_type;
|
struct file_system_type *fs = s->s_type;
|
||||||
if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
|
if (atomic_dec_and_test(&s->s_active)) {
|
||||||
s->s_count -= S_BIAS-1;
|
|
||||||
spin_unlock(&sb_lock);
|
|
||||||
vfs_dq_off(s, 0);
|
vfs_dq_off(s, 0);
|
||||||
down_write(&s->s_umount);
|
down_write(&s->s_umount);
|
||||||
fs->kill_sb(s);
|
fs->kill_sb(s);
|
||||||
|
@ -216,9 +214,7 @@ EXPORT_SYMBOL(deactivate_super);
|
||||||
void deactivate_locked_super(struct super_block *s)
|
void deactivate_locked_super(struct super_block *s)
|
||||||
{
|
{
|
||||||
struct file_system_type *fs = s->s_type;
|
struct file_system_type *fs = s->s_type;
|
||||||
if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
|
if (atomic_dec_and_test(&s->s_active)) {
|
||||||
s->s_count -= S_BIAS-1;
|
|
||||||
spin_unlock(&sb_lock);
|
|
||||||
vfs_dq_off(s, 0);
|
vfs_dq_off(s, 0);
|
||||||
fs->kill_sb(s);
|
fs->kill_sb(s);
|
||||||
put_filesystem(fs);
|
put_filesystem(fs);
|
||||||
|
@ -243,21 +239,19 @@ EXPORT_SYMBOL(deactivate_locked_super);
|
||||||
*/
|
*/
|
||||||
static int grab_super(struct super_block *s) __releases(sb_lock)
|
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++;
|
s->s_count++;
|
||||||
spin_unlock(&sb_lock);
|
spin_unlock(&sb_lock);
|
||||||
|
/* usually that'll be enough for it to die... */
|
||||||
down_write(&s->s_umount);
|
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);
|
up_write(&s->s_umount);
|
||||||
put_super(s);
|
put_super(s);
|
||||||
|
/* ... but in case it wasn't, let's at least yield() */
|
||||||
yield();
|
yield();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1314,7 +1314,6 @@ extern int send_sigurg(struct fown_struct *fown);
|
||||||
extern struct list_head super_blocks;
|
extern struct list_head super_blocks;
|
||||||
extern spinlock_t sb_lock;
|
extern spinlock_t sb_lock;
|
||||||
|
|
||||||
#define S_BIAS (1<<30)
|
|
||||||
struct super_block {
|
struct super_block {
|
||||||
struct list_head s_list; /* Keep this first */
|
struct list_head s_list; /* Keep this first */
|
||||||
dev_t s_dev; /* search index; _not_ kdev_t */
|
dev_t s_dev; /* search index; _not_ kdev_t */
|
||||||
|
|
Loading…
Reference in New Issue