[PATCH 1/2] vfs: partial revoke implementation suggested by Al Viro

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch tries to partially implement what Al Viro suggested in
https://lkml.org/lkml/2013/4/5/15

Code also mostly copied from the above link

Signed-off-by: Li Zhong <zhong@xxxxxxxxxxxxxxxxxx>
---
 fs/Makefile            |    2 +-
 fs/revoke.c            |  133 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h     |    2 +
 include/linux/revoke.h |   50 ++++++++++++++++++
 4 files changed, 186 insertions(+), 1 deletion(-)
 create mode 100644 fs/revoke.c
 create mode 100644 include/linux/revoke.h

diff --git a/fs/Makefile b/fs/Makefile
index 4fe6df3..af0a622 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -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 revoke.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=	buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
diff --git a/fs/revoke.c b/fs/revoke.c
new file mode 100644
index 0000000..bcda9ba
--- /dev/null
+++ b/fs/revoke.c
@@ -0,0 +1,133 @@
+#include <linux/revoke.h>
+#include <linux/rcupdate.h>
+#include <linux/slab.h>
+
+bool __start_using(struct revoke *revoke)
+{
+	struct revokable *r;
+	rcu_read_lock();
+	r = rcu_dereference(revoke->revokable);
+	if (unlikely(!r)) {
+		rcu_read_unlock();
+		return false;	/* revoked */
+	}
+
+	if (likely(atomic_inc_unless_negative(&r->in_use))) {
+		rcu_read_unlock();
+		return true;	/* we are using it now */
+	}
+
+	rcu_read_unlock();
+	return false;		/* it's being revoked right now */
+}
+
+#define BIAS (-1U<<31)
+
+void __stop_using(struct revoke *revoke)
+{
+	struct revokable *r;
+	r = rcu_dereference_protected(revoke->revokable, 1);
+	BUG_ON(!r);
+	if (atomic_dec_return(&r->in_use) == BIAS)
+		complete(r->c);
+}
+
+/* called with r->lock held by caller, unlocks it */
+static void __release_revoke(struct revokable *r, struct revoke *revoke)
+{
+	if (revoke->closing) {
+		DECLARE_COMPLETION_ONSTACK(c);
+		revoke->c = &c;
+		spin_unlock(&r->lock);
+		wait_for_completion(&c);
+	} else {
+		struct file *file;
+		revoke->closing = 1;
+		spin_unlock(&r->lock);
+		file = revoke->file;
+		if (file->f_op->release)
+			file->f_op->release(file_inode(file), file);
+		spin_lock(&r->lock);
+		hlist_del_init(&revoke->node);
+		rcu_assign_pointer(revoke->revokable, NULL);
+		rcu_read_lock();	/* prevent freeing of r */
+		if (revoke->c)
+			complete(revoke->c);
+		spin_unlock(&r->lock);
+		rcu_read_unlock();
+	}
+}
+
+void release_revoke(struct revoke *revoke)
+{
+	struct revokable *r;
+	rcu_read_lock();
+	r = rcu_dereference(revoke->revokable);
+	if (!r) {
+		/* already closed by revokation */
+		rcu_read_unlock();
+		goto out;
+	}
+
+	spin_lock(&r->lock);
+	if (unlikely(hlist_unhashed(&revoke->node))) {
+		/* just been revoked */
+		spin_unlock(&r->lock);
+		rcu_read_unlock();
+		goto out;
+	}
+
+	/*
+	 * Ok, revoke_it() couldn't have been finished yet
+	 * it'll have to get r->lock before it's through, so
+	 * we can drop rcu_read_lock
+	 */
+	rcu_read_unlock();
+	__release_revoke(r, revoke);
+out:
+	kfree(revoke);
+}
+
+void revoke_it(struct revokable *r)
+{
+	DECLARE_COMPLETION_ONSTACK(c);
+	r->c = &c;
+	if (atomic_add_return(BIAS, &r->in_use) != BIAS) {
+		if (r->kick)
+			r->kick(r);
+		wait_for_completion(&c);
+	}
+
+	while (1) {
+		struct hlist_node *p;
+		spin_lock(&r->lock);
+		p = r->list.first;
+		if (!p)
+			break;
+		__release_revoke(r, hlist_entry(p, struct revoke, node));
+	}
+	spin_unlock(&r->lock);
+}
+
+int make_revokable(struct file *f, struct revokable *r)
+{
+	struct revoke *revoke = kzalloc(sizeof(struct revoke), GFP_KERNEL);
+	if (!revoke)
+		return -ENOMEM;
+
+	if (!atomic_inc_unless_negative(&r->in_use)) {
+		kfree(revoke);
+		return -ENOENT;
+	}
+
+	revoke->file = f;
+	revoke->revokable = r;
+	f->f_revoke = revoke;
+
+	spin_lock(&r->lock);
+	hlist_add_head(&revoke->node, &r->list);
+	spin_unlock(&r->lock);
+
+	__stop_using(revoke);
+	return 0;
+}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 99be011..4ec9437 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -45,6 +45,7 @@ struct vfsmount;
 struct cred;
 struct swap_info_struct;
 struct seq_file;
+struct revoke;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
@@ -807,6 +808,7 @@ struct file {
 #ifdef CONFIG_DEBUG_WRITECOUNT
 	unsigned long f_mnt_write_state;
 #endif
+	struct revoke *f_revoke;
 };
 
 struct file_handle {
diff --git a/include/linux/revoke.h b/include/linux/revoke.h
new file mode 100644
index 0000000..263569b
--- /dev/null
+++ b/include/linux/revoke.h
@@ -0,0 +1,50 @@
+#ifndef _LINUX_REVOKE_H
+#define _LINUX_REVOKE_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/completion.h>
+#include <linux/fs.h>
+
+struct revokable {
+	atomic_t in_use;	/* number of threads in methods,*/
+				/* negative => going away */
+	spinlock_t lock;
+	struct hlist_head list;	/* protected by ->lock, goes through */
+				/* struct revoke->node */
+	struct completion *c;
+	void (*kick)(struct revokable *);
+};
+
+struct revoke {
+	struct file *file;
+	struct revokable *revokable;
+	struct hlist_node node;
+	bool closing;
+	struct completion *c;
+};
+
+bool __start_using(struct revoke *revoke);
+void __stop_using(struct revoke *revoke);
+
+static inline bool start_using(struct file *f)
+{
+	struct revoke *revoke = f->f_revoke;
+	if (likely(!revoke))
+		return true;	/* non-revokable file */
+	return __start_using(revoke);
+}
+
+static inline void stop_using(struct file *f)
+{
+	struct revoke *revoke = f->f_revoke;
+	if (unlikely(revoke))
+		__stop_using(revoke);
+}
+
+void release_revoke(struct revoke *revoke);
+void revoke_it(struct revokable *r);
+int make_revokable(struct file *f, struct revokable *r);
+
+#endif /* __LINUX_REVOKE_H */
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux