lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 11 Jul 2013 19:07:20 +0800
From:	Li Zhong <zhong@...ux.vnet.ibm.com>
To:	viro@...IV.linux.org.uk
Cc:	linuxram@...ibm.com, linux-fsdevel@...r.kernel.org,
	linux-kernel@...r.kernel.org, Li Zhong <zhong@...ux.vnet.ibm.com>
Subject: [PATCH 1/2] vfs: partial revoke implementation suggested by Al Viro

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@...ux.vnet.ibm.com>
---
 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-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ