acct: get rid of acct_list
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 7 Aug 2014 10:23:41 +0000 (06:23 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 7 Aug 2014 18:40:08 +0000 (14:40 -0400)
Put these suckers on per-vfsmount and per-superblock lists instead.
Note: right now it's still acct_lock for everything, but that's
going to change.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/mount.h
fs/namespace.c
fs/super.c
include/linux/acct.h
include/linux/fs.h
kernel/acct.c

index d55297f2fa058c18512d0136b8a5437b29bc481c..0a2d1458681fb0e9dfd74cc8415d77a4caa52209 100644 (file)
@@ -56,6 +56,7 @@ struct mount {
        int mnt_group_id;               /* peer group identifier */
        int mnt_expiry_mark;            /* true if marked for expiry */
        int mnt_pinned;
+       struct hlist_head mnt_pins;
        struct path mnt_ex_mountpoint;
 };
 
index 182bc41cd88711d593c4d997171c6ad483a87577..22e530addfaf2cfd29074e3a3d75d20b3e122a46 100644 (file)
@@ -956,7 +956,7 @@ put_again:
                mnt->mnt_pinned = 0;
                rcu_read_unlock();
                unlock_mount_hash();
-               acct_auto_close_mnt(&mnt->mnt);
+               acct_auto_close_mnt(&mnt->mnt_pins);
                goto put_again;
        }
        if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) {
index d20d5b11dedf80a7d6c2f39872e6a892b21d7206..52ed93eb63df6fceb78ce317e2de54384bcb8a2b 100644 (file)
@@ -703,7 +703,7 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 #endif
 
        if (flags & MS_RDONLY)
-               acct_auto_close(sb);
+               acct_auto_close(&sb->s_pins);
        shrink_dcache_sb(sb);
 
        remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY);
index 4a5b7cb56079121152b780d7a75e54f43de4f344..65a4f889182e4ff7dfb4d275ccf9321c327295a8 100644 (file)
@@ -24,14 +24,14 @@ struct super_block;
 struct pacct_struct;
 struct pid_namespace;
 extern int acct_parm[]; /* for sysctl */
-extern void acct_auto_close_mnt(struct vfsmount *m);
-extern void acct_auto_close(struct super_block *sb);
+extern void acct_auto_close(struct hlist_head *);
+extern void acct_auto_close_mnt(struct hlist_head *);
 extern void acct_collect(long exitcode, int group_dead);
 extern void acct_process(void);
 extern void acct_exit_ns(struct pid_namespace *);
 #else
-#define acct_auto_close_mnt(x) do { } while (0)
 #define acct_auto_close(x)     do { } while (0)
+#define acct_auto_close_mnt(x) do { } while (0)
 #define acct_collect(x,y)      do { } while (0)
 #define acct_process()         do { } while (0)
 #define acct_exit_ns(ns)       do { } while (0)
index 4b7d57cf786394feba6b7d873b1f0440a6652b0d..17f70872a4a5d726c5e0a71ecbc622ee2e7a9a77 100644 (file)
@@ -1250,6 +1250,7 @@ struct super_block {
 
        /* AIO completions deferred from interrupt context */
        struct workqueue_struct *s_dio_done_wq;
+       struct hlist_head s_pins;
 
        /*
         * Keep the lru lists last in the structure so they always sit on their
index 019f012a3c6fd1f9e4a6d3d564a44b1ca1d4baf7..21fbb3c27c2adf858cb84d00258b17f4e1494a71 100644 (file)
@@ -59,6 +59,7 @@
 #include <asm/div64.h>
 #include <linux/blkdev.h> /* sector_div */
 #include <linux/pid_namespace.h>
+#include <../fs/mount.h>       /* will go away when we refactor */
 
 /*
  * These constants control the amount of freespace that suspend and
@@ -79,16 +80,16 @@ static void do_acct_process(struct bsd_acct_struct *acct);
 
 struct bsd_acct_struct {
        long                    count;
+       struct hlist_node       s_list;
+       struct hlist_node       m_list;
        struct mutex            lock;
        int                     active;
        unsigned long           needcheck;
        struct file             *file;
        struct pid_namespace    *ns;
-       struct list_head        list;
 };
 
 static DEFINE_SPINLOCK(acct_lock);
-static LIST_HEAD(acct_list);
 
 /*
  * Check the amount of free space and suspend/resume accordingly.
@@ -133,25 +134,33 @@ static void acct_put(struct bsd_acct_struct *p)
        spin_unlock(&acct_lock);
 }
 
-static struct bsd_acct_struct *acct_get(struct bsd_acct_struct **p)
+static struct bsd_acct_struct *__acct_get(struct bsd_acct_struct *res)
+{
+       res->count++;
+       spin_unlock(&acct_lock);
+       mutex_lock(&res->lock);
+       if (!res->ns) {
+               mutex_unlock(&res->lock);
+               spin_lock(&acct_lock);
+               if (!--res->count)
+                       kfree(res);
+               return NULL;
+       }
+       return res;
+}
+
+static struct bsd_acct_struct *acct_get(struct pid_namespace *ns)
 {
        struct bsd_acct_struct *res;
        spin_lock(&acct_lock);
 again:
-       res = *p;
-       if (res)
-               res->count++;
-       spin_unlock(&acct_lock);
-       if (res) {
-               mutex_lock(&res->lock);
-               if (!res->ns) {
-                       mutex_unlock(&res->lock);
-                       spin_lock(&acct_lock);
-                       if (!--res->count)
-                               kfree(res);
-                       goto again;
-               }
+       if (!ns->bacct) {
+               spin_unlock(&acct_lock);
+               return NULL;
        }
+       res = __acct_get(ns->bacct);
+       if (!res)
+               goto again;
        return res;
 }
 
@@ -162,7 +171,8 @@ static void acct_kill(struct bsd_acct_struct *acct,
                struct file *file = acct->file;
                struct pid_namespace *ns = acct->ns;
                spin_lock(&acct_lock);
-               list_del(&acct->list);
+               hlist_del(&acct->m_list);
+               hlist_del(&acct->s_list);
                mnt_unpin(file->f_path.mnt);
                spin_unlock(&acct_lock);
                do_acct_process(acct);
@@ -170,8 +180,10 @@ static void acct_kill(struct bsd_acct_struct *acct,
                spin_lock(&acct_lock);
                ns->bacct = new;
                if (new) {
-                       mnt_pin(new->file->f_path.mnt);
-                       list_add(&new->list, &acct_list);
+                       struct vfsmount *m = new->file->f_path.mnt;
+                       mnt_pin(m);
+                       hlist_add_head(&new->s_list, &m->mnt_sb->s_pins);
+                       hlist_add_head(&new->m_list, &real_mount(m)->mnt_pins);
                }
                acct->ns = NULL;
                mutex_unlock(&acct->lock);
@@ -218,14 +230,15 @@ static int acct_on(struct filename *pathname)
        mutex_init(&acct->lock);
        mnt = file->f_path.mnt;
 
-       old = acct_get(&ns->bacct);
+       old = acct_get(ns);
        if (old) {
                acct_kill(old, acct);
        } else {
                spin_lock(&acct_lock);
                ns->bacct = acct;
                mnt_pin(mnt);
-               list_add(&acct->list, &acct_list);
+               hlist_add_head(&acct->s_list, &mnt->mnt_sb->s_pins);
+               hlist_add_head(&acct->m_list, &real_mount(mnt)->mnt_pins);
                spin_unlock(&acct_lock);
        }
        mntput(mnt); /* it's pinned, now give up active reference */
@@ -261,79 +274,41 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
                mutex_unlock(&acct_on_mutex);
                putname(tmp);
        } else {
-               acct_kill(acct_get(&task_active_pid_ns(current)->bacct), NULL);
+               acct_kill(acct_get(task_active_pid_ns(current)), NULL);
        }
 
        return error;
 }
 
-/**
- * acct_auto_close - turn off a filesystem's accounting if it is on
- * @m: vfsmount being shut down
- *
- * If the accounting is turned on for a file in the subtree pointed to
- * to by m, turn accounting off.  Done when m is about to die.
- */
-void acct_auto_close_mnt(struct vfsmount *m)
+void acct_auto_close_mnt(struct hlist_head *list)
 {
-       struct bsd_acct_struct *acct;
-
-       spin_lock(&acct_lock);
-restart:
-       list_for_each_entry(acct, &acct_list, list)
-               if (acct->file->f_path.mnt == m) {
-                       acct->count++;
-                       spin_unlock(&acct_lock);
-                       mutex_lock(&acct->lock);
-                       if (!acct->ns) {
-                               mutex_unlock(&acct->lock);
-                               spin_lock(&acct_lock);
-                               if (!--acct->count)
-                                       kfree(acct);
-                               goto restart;
-                       }
-                       acct_kill(acct, NULL);
-                       spin_lock(&acct_lock);
-                       goto restart;
-               }
+       while (1) {
+               spin_lock(&acct_lock);
+               if (!list->first)
+                       break;
+               acct_kill(__acct_get(hlist_entry(list->first,
+                                                struct bsd_acct_struct,
+                                                m_list)), NULL);
+       }
        spin_unlock(&acct_lock);
 }
 
-/**
- * acct_auto_close - turn off a filesystem's accounting if it is on
- * @sb: super block for the filesystem
- *
- * If the accounting is turned on for a file in the filesystem pointed
- * to by sb, turn accounting off.
- */
-void acct_auto_close(struct super_block *sb)
+void acct_auto_close(struct hlist_head *list)
 {
-       struct bsd_acct_struct *acct;
-
-       spin_lock(&acct_lock);
-restart:
-       list_for_each_entry(acct, &acct_list, list)
-               if (acct->file->f_path.dentry->d_sb == sb) {
-                       acct->count++;
-                       spin_unlock(&acct_lock);
-                       mutex_lock(&acct->lock);
-                       if (!acct->ns) {
-                               mutex_unlock(&acct->lock);
-                               spin_lock(&acct_lock);
-                               if (!--acct->count)
-                                       kfree(acct);
-                               goto restart;
-                       }
-                       acct_kill(acct, NULL);
-                       spin_lock(&acct_lock);
-                       goto restart;
-               }
+       while (1) {
+               spin_lock(&acct_lock);
+               if (!list->first)
+                       break;
+               acct_kill(__acct_get(hlist_entry(list->first,
+                                                struct bsd_acct_struct,
+                                                s_list)), NULL);
+       }
        spin_unlock(&acct_lock);
 }
 
 void acct_exit_ns(struct pid_namespace *ns)
 {
-       acct_kill(acct_get(&ns->bacct), NULL);
+       acct_kill(acct_get(ns), NULL);
 }
 
 /*
@@ -602,7 +577,7 @@ void acct_collect(long exitcode, int group_dead)
 static void slow_acct_process(struct pid_namespace *ns)
 {
        for ( ; ns; ns = ns->parent) {
-               struct bsd_acct_struct *acct = acct_get(&ns->bacct);
+               struct bsd_acct_struct *acct = acct_get(ns);
                if (acct) {
                        do_acct_process(acct);
                        mutex_unlock(&acct->lock);