Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 209641
b: refs/heads/master
c: 6416ccb
h: refs/heads/master
i:
  209639: 2c99217
v: v3
  • Loading branch information
Nick Piggin authored and Al Viro committed Aug 18, 2010
1 parent 04d857b commit e32bb75
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2dc91abe03d8ce6dd7f9251faffafca5f6b9e85d
refs/heads/master: 6416ccb7899960868f5016751fb81bf25213d24f
108 changes: 90 additions & 18 deletions trunk/fs/file_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
#include <linux/cdev.h>
#include <linux/fsnotify.h>
#include <linux/sysctl.h>
#include <linux/lglock.h>
#include <linux/percpu_counter.h>
#include <linux/percpu.h>
#include <linux/ima.h>

#include <asm/atomic.h>
Expand All @@ -32,7 +34,8 @@ struct files_stat_struct files_stat = {
.max_files = NR_FILE
};

static __cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock);
DECLARE_LGLOCK(files_lglock);
DEFINE_LGLOCK(files_lglock);

/* SLAB cache for file structures */
static struct kmem_cache *filp_cachep __read_mostly;
Expand Down Expand Up @@ -336,30 +339,98 @@ void put_filp(struct file *file)
}
}

static inline int file_list_cpu(struct file *file)
{
#ifdef CONFIG_SMP
return file->f_sb_list_cpu;
#else
return smp_processor_id();
#endif
}

/* helper for file_sb_list_add to reduce ifdefs */
static inline void __file_sb_list_add(struct file *file, struct super_block *sb)
{
struct list_head *list;
#ifdef CONFIG_SMP
int cpu;
cpu = smp_processor_id();
file->f_sb_list_cpu = cpu;
list = per_cpu_ptr(sb->s_files, cpu);
#else
list = &sb->s_files;
#endif
list_add(&file->f_u.fu_list, list);
}

/**
* file_sb_list_add - add a file to the sb's file list
* @file: file to add
* @sb: sb to add it to
*
* Use this function to associate a file with the superblock of the inode it
* refers to.
*/
void file_sb_list_add(struct file *file, struct super_block *sb)
{
spin_lock(&files_lock);
BUG_ON(!list_empty(&file->f_u.fu_list));
list_add(&file->f_u.fu_list, &sb->s_files);
spin_unlock(&files_lock);
lg_local_lock(files_lglock);
__file_sb_list_add(file, sb);
lg_local_unlock(files_lglock);
}

/**
* file_sb_list_del - remove a file from the sb's file list
* @file: file to remove
* @sb: sb to remove it from
*
* Use this function to remove a file from its superblock.
*/
void file_sb_list_del(struct file *file)
{
if (!list_empty(&file->f_u.fu_list)) {
spin_lock(&files_lock);
lg_local_lock_cpu(files_lglock, file_list_cpu(file));
list_del_init(&file->f_u.fu_list);
spin_unlock(&files_lock);
lg_local_unlock_cpu(files_lglock, file_list_cpu(file));
}
}

#ifdef CONFIG_SMP

/*
* These macros iterate all files on all CPUs for a given superblock.
* files_lglock must be held globally.
*/
#define do_file_list_for_each_entry(__sb, __file) \
{ \
int i; \
for_each_possible_cpu(i) { \
struct list_head *list; \
list = per_cpu_ptr((__sb)->s_files, i); \
list_for_each_entry((__file), list, f_u.fu_list)

#define while_file_list_for_each_entry \
} \
}

#else

#define do_file_list_for_each_entry(__sb, __file) \
{ \
struct list_head *list; \
list = &(sb)->s_files; \
list_for_each_entry((__file), list, f_u.fu_list)

#define while_file_list_for_each_entry \
}

#endif

int fs_may_remount_ro(struct super_block *sb)
{
struct file *file;

/* Check that no files are currently opened for writing. */
spin_lock(&files_lock);
list_for_each_entry(file, &sb->s_files, f_u.fu_list) {
lg_global_lock(files_lglock);
do_file_list_for_each_entry(sb, file) {
struct inode *inode = file->f_path.dentry->d_inode;

/* File with pending delete? */
Expand All @@ -369,11 +440,11 @@ int fs_may_remount_ro(struct super_block *sb)
/* Writeable file? */
if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
goto too_bad;
}
spin_unlock(&files_lock);
} while_file_list_for_each_entry;
lg_global_unlock(files_lglock);
return 1; /* Tis' cool bro. */
too_bad:
spin_unlock(&files_lock);
lg_global_unlock(files_lglock);
return 0;
}

Expand All @@ -389,8 +460,8 @@ void mark_files_ro(struct super_block *sb)
struct file *f;

retry:
spin_lock(&files_lock);
list_for_each_entry(f, &sb->s_files, f_u.fu_list) {
lg_global_lock(files_lglock);
do_file_list_for_each_entry(sb, f) {
struct vfsmount *mnt;
if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
continue;
Expand All @@ -406,12 +477,12 @@ void mark_files_ro(struct super_block *sb)
file_release_write(f);
mnt = mntget(f->f_path.mnt);
/* This can sleep, so we can't hold the spinlock. */
spin_unlock(&files_lock);
lg_global_unlock(files_lglock);
mnt_drop_write(mnt);
mntput(mnt);
goto retry;
}
spin_unlock(&files_lock);
} while_file_list_for_each_entry;
lg_global_unlock(files_lglock);
}

void __init files_init(unsigned long mempages)
Expand All @@ -431,5 +502,6 @@ void __init files_init(unsigned long mempages)
if (files_stat.max_files < NR_FILE)
files_stat.max_files = NR_FILE;
files_defer_init();
lg_lock_init(files_lglock);
percpu_counter_init(&nr_files, 0);
}
18 changes: 18 additions & 0 deletions trunk/fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,22 @@ static struct super_block *alloc_super(struct file_system_type *type)
s = NULL;
goto out;
}
#ifdef CONFIG_SMP
s->s_files = alloc_percpu(struct list_head);
if (!s->s_files) {
security_sb_free(s);
kfree(s);
s = NULL;
goto out;
} else {
int i;

for_each_possible_cpu(i)
INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i));
}
#else
INIT_LIST_HEAD(&s->s_files);
#endif
INIT_LIST_HEAD(&s->s_instances);
INIT_HLIST_HEAD(&s->s_anon);
INIT_LIST_HEAD(&s->s_inodes);
Expand Down Expand Up @@ -108,6 +123,9 @@ static struct super_block *alloc_super(struct file_system_type *type)
*/
static inline void destroy_super(struct super_block *s)
{
#ifdef CONFIG_SMP
free_percpu(s->s_files);
#endif
security_sb_free(s);
kfree(s->s_subtype);
kfree(s->s_options);
Expand Down
7 changes: 7 additions & 0 deletions trunk/include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,9 @@ struct file {
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */
#ifdef CONFIG_SMP
int f_sb_list_cpu;
#endif
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
Expand Down Expand Up @@ -1334,7 +1337,11 @@ struct super_block {

struct list_head s_inodes; /* all inodes */
struct hlist_head s_anon; /* anonymous dentries for (nfs) exporting */
#ifdef CONFIG_SMP
struct list_head __percpu *s_files;
#else
struct list_head s_files;
#endif
/* s_dentry_lru and s_nr_dentry_unused are protected by dcache_lock */
struct list_head s_dentry_lru; /* unused dentry lru */
int s_nr_dentry_unused; /* # of dentry on lru */
Expand Down

0 comments on commit e32bb75

Please sign in to comment.