Skip to content

Commit

Permalink
Take sb_lock once per cycle, preventing filesystems being added/removed.
Browse files Browse the repository at this point in the history
Signed-off-by: Nigel Cunningham <[email protected]>
  • Loading branch information
NigelCunningham committed Feb 3, 2016
1 parent 313c1b3 commit dc8248c
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 1 deletion.
4 changes: 3 additions & 1 deletion fs/drop_caches.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
/* A global variable is a bit ugly, but it keeps the code simple */
int sysctl_drop_caches;

extern void iterate_supers_no_sb_lock(void (*f)(struct super_block *, void *), void *arg);

static void drop_pagecache_sb(struct super_block *sb, void *unused)
{
struct inode *inode, *toput_inode = NULL;
Expand Down Expand Up @@ -43,7 +45,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
/* For TuxOnIce */
void drop_pagecache(void)
{
iterate_supers(drop_pagecache_sb, NULL);
iterate_supers_no_sb_lock(drop_pagecache_sb, NULL);
}

int drop_caches_sysctl_handler(struct ctl_table *table, int write,
Expand Down
47 changes: 47 additions & 0 deletions fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1373,3 +1373,50 @@ int thaw_super(struct super_block *sb)
return 0;
}
EXPORT_SYMBOL(thaw_super);

/**
* lock_supers -- Stop other processes from modifying the list of super blocks.
*/
void take_super_lock() {
spin_lock(&sb_lock);
}

/**
* unlock_supers -- Allow other processes to again modify the list of super blocks.
*/
void release_super_lock() {
spin_unlock(&sb_lock);
}

/**
* iterate_supers_no_sb_lock - call function for all active superblocks without using sb_lock
*
* Note that the callback must work with sb_lock taken and not unlock it.
*
* @f: function to call
* @arg: argument to pass to it
*
* Scans the superblock list and calls given function, passing it
* locked superblock and given argument.
*/
void iterate_supers_no_sb_lock(void (*f)(struct super_block *, void *), void *arg)
{
struct super_block *sb, *p = NULL;

list_for_each_entry(sb, &super_blocks, s_list) {
if (hlist_unhashed(&sb->s_instances))
continue;
sb->s_count++;

down_read(&sb->s_umount);
if (sb->s_root && (sb->s_flags & MS_BORN))
f(sb, arg);
up_read(&sb->s_umount);

if (p)
__put_super(p);
p = sb;
}
if (p)
__put_super(p);
}
3 changes: 3 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -3037,4 +3037,7 @@ static inline bool dir_relax(struct inode *inode)

extern bool path_noexec(const struct path *path);

extern void take_super_lock(void);
extern void release_super_lock(void);

#endif /* _LINUX_FS_H */
3 changes: 3 additions & 0 deletions kernel/power/tuxonice_highlevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ void toi_finish_anything(int hibernate_or_resume)
toi_alloc_print_debug_stats();
atomic_inc(&snapshot_device_available);
unlock_system_sleep();
release_super_lock();
}

set_fs(oldfs);
Expand All @@ -185,6 +186,7 @@ int toi_start_anything(int hibernate_or_resume)
toi_trace_index = 0;

if (hibernate_or_resume) {
take_super_lock();
lock_system_sleep();

if (!atomic_add_unless(&snapshot_device_available, -1, 0))
Expand Down Expand Up @@ -230,6 +232,7 @@ int toi_start_anything(int hibernate_or_resume)
snapshotdevice_unavailable:
if (hibernate_or_resume)
mutex_unlock(&pm_mutex);
release_super_lock();
set_fs(oldfs);
mutex_unlock(&tuxonice_in_use);
return -EBUSY;
Expand Down

0 comments on commit dc8248c

Please sign in to comment.