take fs_pin stuff to fs/*
Add a new field to fs_pin - kill(pin). That's what umount and r/o remount will be calling for all pins attached to vfsmount and superblock resp. Called after bumping the refcount, so it won't go away under us. Dropping the refcount is responsibility of the instance. All generic stuff moved to fs/fs_pin.c; the next step will rip all the knowledge of kernel/acct.c from fs/super.c and fs/namespace.c. After that - death to mnt_pin(); it was intended to be usable as generic mechanism for code that wants to attach objects to vfsmount, so that they would not make the sucker busy and would get killed on umount. Never got it right; it remained acct.c-specific all along. Now it's very close to being killable. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
1629d0eb3e
commit
efb170c228
5 changed files with 129 additions and 100 deletions
|
@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \
|
|||
attr.o bad_inode.o file.o filesystems.o namespace.o \
|
||||
seq_file.o xattr.o libfs.o fs-writeback.o \
|
||||
pnode.o splice.o sync.o utimes.o \
|
||||
stack.o fs_struct.o statfs.o
|
||||
stack.o fs_struct.o statfs.o fs_pin.o
|
||||
|
||||
ifeq ($(CONFIG_BLOCK),y)
|
||||
obj-y += buffer.o block_dev.o direct-io.o mpage.o
|
||||
|
|
77
fs/fs_pin.c
Normal file
77
fs/fs_pin.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs_pin.h>
|
||||
#include "mount.h"
|
||||
|
||||
static void pin_free_rcu(struct rcu_head *head)
|
||||
{
|
||||
kfree(container_of(head, struct fs_pin, rcu));
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(pin_lock);
|
||||
|
||||
void pin_put(struct fs_pin *p)
|
||||
{
|
||||
if (atomic_long_dec_and_test(&p->count))
|
||||
call_rcu(&p->rcu, pin_free_rcu);
|
||||
}
|
||||
|
||||
void pin_remove(struct fs_pin *pin)
|
||||
{
|
||||
spin_lock(&pin_lock);
|
||||
hlist_del(&pin->m_list);
|
||||
hlist_del(&pin->s_list);
|
||||
spin_unlock(&pin_lock);
|
||||
}
|
||||
|
||||
void pin_insert(struct fs_pin *pin, struct vfsmount *m)
|
||||
{
|
||||
spin_lock(&pin_lock);
|
||||
hlist_add_head(&pin->s_list, &m->mnt_sb->s_pins);
|
||||
hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins);
|
||||
spin_unlock(&pin_lock);
|
||||
}
|
||||
|
||||
void acct_auto_close_mnt(struct hlist_head *list)
|
||||
{
|
||||
while (1) {
|
||||
struct hlist_node *p;
|
||||
struct fs_pin *pin;
|
||||
rcu_read_lock();
|
||||
p = ACCESS_ONCE(list->first);
|
||||
if (!p) {
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
}
|
||||
pin = hlist_entry(p, struct fs_pin, m_list);
|
||||
if (!atomic_long_inc_not_zero(&pin->count)) {
|
||||
rcu_read_unlock();
|
||||
cpu_relax();
|
||||
continue;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
pin->kill(pin);
|
||||
}
|
||||
}
|
||||
|
||||
void acct_auto_close(struct hlist_head *list)
|
||||
{
|
||||
while (1) {
|
||||
struct hlist_node *p;
|
||||
struct fs_pin *pin;
|
||||
rcu_read_lock();
|
||||
p = ACCESS_ONCE(list->first);
|
||||
if (!p) {
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
}
|
||||
pin = hlist_entry(p, struct fs_pin, s_list);
|
||||
if (!atomic_long_inc_not_zero(&pin->count)) {
|
||||
rcu_read_unlock();
|
||||
cpu_relax();
|
||||
continue;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
pin->kill(pin);
|
||||
}
|
||||
}
|
|
@ -24,18 +24,16 @@ struct super_block;
|
|||
struct pacct_struct;
|
||||
struct pid_namespace;
|
||||
extern int acct_parm[]; /* for sysctl */
|
||||
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(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)
|
||||
#endif
|
||||
extern void acct_auto_close(struct hlist_head *);
|
||||
extern void acct_auto_close_mnt(struct hlist_head *);
|
||||
|
||||
/*
|
||||
* ACCT_VERSION numbers as yet defined:
|
||||
|
|
17
include/linux/fs_pin.h
Normal file
17
include/linux/fs_pin.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include <linux/fs.h>
|
||||
|
||||
struct fs_pin {
|
||||
atomic_long_t count;
|
||||
union {
|
||||
struct {
|
||||
struct hlist_node s_list;
|
||||
struct hlist_node m_list;
|
||||
};
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
void (*kill)(struct fs_pin *);
|
||||
};
|
||||
|
||||
void pin_put(struct fs_pin *);
|
||||
void pin_remove(struct fs_pin *);
|
||||
void pin_insert(struct fs_pin *, struct vfsmount *);
|
127
kernel/acct.c
127
kernel/acct.c
|
@ -59,7 +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 */
|
||||
#include <linux/fs_pin.h>
|
||||
|
||||
/*
|
||||
* These constants control the amount of freespace that suspend and
|
||||
|
@ -78,17 +78,6 @@ int acct_parm[3] = {4, 2, 30};
|
|||
*/
|
||||
static void do_acct_process(struct bsd_acct_struct *acct);
|
||||
|
||||
struct fs_pin {
|
||||
atomic_long_t count;
|
||||
union {
|
||||
struct {
|
||||
struct hlist_node s_list;
|
||||
struct hlist_node m_list;
|
||||
};
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
};
|
||||
|
||||
struct bsd_acct_struct {
|
||||
struct fs_pin pin;
|
||||
struct mutex lock;
|
||||
|
@ -100,13 +89,6 @@ struct bsd_acct_struct {
|
|||
struct completion done;
|
||||
};
|
||||
|
||||
static void pin_free_rcu(struct rcu_head *head)
|
||||
{
|
||||
kfree(container_of(head, struct fs_pin, rcu));
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(acct_lock);
|
||||
|
||||
/*
|
||||
* Check the amount of free space and suspend/resume accordingly.
|
||||
*/
|
||||
|
@ -142,29 +124,6 @@ static int check_free_space(struct bsd_acct_struct *acct)
|
|||
return acct->active;
|
||||
}
|
||||
|
||||
static void pin_put(struct fs_pin *p)
|
||||
{
|
||||
if (atomic_long_dec_and_test(&p->count))
|
||||
call_rcu(&p->rcu, pin_free_rcu);
|
||||
}
|
||||
|
||||
static struct bsd_acct_struct *__acct_get(struct bsd_acct_struct *res)
|
||||
{
|
||||
if (!atomic_long_inc_not_zero(&res->pin.count)) {
|
||||
rcu_read_unlock();
|
||||
cpu_relax();
|
||||
return NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
mutex_lock(&res->lock);
|
||||
if (!res->ns) {
|
||||
mutex_unlock(&res->lock);
|
||||
pin_put(&res->pin);
|
||||
return NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct bsd_acct_struct *acct_get(struct pid_namespace *ns)
|
||||
{
|
||||
struct bsd_acct_struct *res;
|
||||
|
@ -176,9 +135,18 @@ static struct bsd_acct_struct *acct_get(struct pid_namespace *ns)
|
|||
rcu_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
res = __acct_get(res);
|
||||
if (!res)
|
||||
if (!atomic_long_inc_not_zero(&res->pin.count)) {
|
||||
rcu_read_unlock();
|
||||
cpu_relax();
|
||||
goto again;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
mutex_lock(&res->lock);
|
||||
if (!res->ns) {
|
||||
mutex_unlock(&res->lock);
|
||||
pin_put(&res->pin);
|
||||
goto again;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -203,19 +171,8 @@ static void acct_kill(struct bsd_acct_struct *acct,
|
|||
init_completion(&acct->done);
|
||||
schedule_work(&acct->work);
|
||||
wait_for_completion(&acct->done);
|
||||
spin_lock(&acct_lock);
|
||||
hlist_del(&acct->pin.m_list);
|
||||
hlist_del(&acct->pin.s_list);
|
||||
spin_unlock(&acct_lock);
|
||||
pin_remove(&acct->pin);
|
||||
ns->bacct = new;
|
||||
if (new) {
|
||||
struct vfsmount *m = new->file->f_path.mnt;
|
||||
spin_lock(&acct_lock);
|
||||
hlist_add_head(&new->pin.s_list, &m->mnt_sb->s_pins);
|
||||
hlist_add_head(&new->pin.m_list, &real_mount(m)->mnt_pins);
|
||||
spin_unlock(&acct_lock);
|
||||
mutex_unlock(&new->lock);
|
||||
}
|
||||
acct->ns = NULL;
|
||||
atomic_long_dec(&acct->pin.count);
|
||||
mutex_unlock(&acct->lock);
|
||||
|
@ -223,6 +180,19 @@ static void acct_kill(struct bsd_acct_struct *acct,
|
|||
}
|
||||
}
|
||||
|
||||
static void acct_pin_kill(struct fs_pin *pin)
|
||||
{
|
||||
struct bsd_acct_struct *acct;
|
||||
acct = container_of(pin, struct bsd_acct_struct, pin);
|
||||
mutex_lock(&acct->lock);
|
||||
if (!acct->ns) {
|
||||
mutex_unlock(&acct->lock);
|
||||
pin_put(pin);
|
||||
acct = NULL;
|
||||
}
|
||||
acct_kill(acct, NULL);
|
||||
}
|
||||
|
||||
static int acct_on(struct filename *pathname)
|
||||
{
|
||||
struct file *file;
|
||||
|
@ -254,25 +224,22 @@ static int acct_on(struct filename *pathname)
|
|||
}
|
||||
|
||||
atomic_long_set(&acct->pin.count, 1);
|
||||
acct->pin.kill = acct_pin_kill;
|
||||
acct->file = file;
|
||||
acct->needcheck = jiffies;
|
||||
acct->ns = ns;
|
||||
mutex_init(&acct->lock);
|
||||
mnt = file->f_path.mnt;
|
||||
mnt_pin(mnt);
|
||||
mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */
|
||||
pin_insert(&acct->pin, mnt);
|
||||
|
||||
old = acct_get(ns);
|
||||
mutex_lock_nested(&acct->lock, 1); /* nobody has seen it yet */
|
||||
if (old) {
|
||||
if (old)
|
||||
acct_kill(old, acct);
|
||||
} else {
|
||||
else
|
||||
ns->bacct = acct;
|
||||
spin_lock(&acct_lock);
|
||||
hlist_add_head(&acct->pin.s_list, &mnt->mnt_sb->s_pins);
|
||||
hlist_add_head(&acct->pin.m_list, &real_mount(mnt)->mnt_pins);
|
||||
spin_unlock(&acct_lock);
|
||||
mutex_unlock(&acct->lock);
|
||||
}
|
||||
mutex_unlock(&acct->lock);
|
||||
mntput(mnt); /* it's pinned, now give up active reference */
|
||||
return 0;
|
||||
}
|
||||
|
@ -312,36 +279,6 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
|
|||
return error;
|
||||
}
|
||||
|
||||
void acct_auto_close_mnt(struct hlist_head *list)
|
||||
{
|
||||
rcu_read_lock();
|
||||
while (1) {
|
||||
struct hlist_node *p = ACCESS_ONCE(list->first);
|
||||
if (!p)
|
||||
break;
|
||||
acct_kill(__acct_get(hlist_entry(p,
|
||||
struct bsd_acct_struct,
|
||||
pin.m_list)), NULL);
|
||||
rcu_read_lock();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void acct_auto_close(struct hlist_head *list)
|
||||
{
|
||||
rcu_read_lock();
|
||||
while (1) {
|
||||
struct hlist_node *p = ACCESS_ONCE(list->first);
|
||||
if (!p)
|
||||
break;
|
||||
acct_kill(__acct_get(hlist_entry(p,
|
||||
struct bsd_acct_struct,
|
||||
pin.s_list)), NULL);
|
||||
rcu_read_lock();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void acct_exit_ns(struct pid_namespace *ns)
|
||||
{
|
||||
acct_kill(acct_get(ns), NULL);
|
||||
|
|
Loading…
Reference in a new issue