linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests
@ 2006-01-14  0:39 Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 01/17] add /sys/fs Miklos Szeredi
                   ` (16 more replies)
  0 siblings, 17 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

This series contains recent fixes and cleanups to FUSE.  The bigger
part is the support for asynchronous reads.  This will be a big
performance improvement of filesystems in certain situations due to
the readahead logic being able to work to it's full capability.  

I'd prefer to have this in 2.6.16.  The merge window is still open,
isn't it?

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 01/17] add /sys/fs
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-17 12:47   ` Christoph Hellwig
  2006-01-14  0:39 ` [PATCH 02/17] fuse: fuse_copy_finish() order fix Miklos Szeredi
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: sys_fs.patch --]
[-- Type: text/plain, Size: 1353 bytes --]

This patch adds an empty /sys/fs, which filesystems can use.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/include/linux/fs.h
===================================================================
--- linux.orig/include/linux/fs.h	2006-01-13 21:52:18.000000000 +0100
+++ linux/include/linux/fs.h	2006-01-13 22:51:37.000000000 +0100
@@ -1297,6 +1297,9 @@ extern void mnt_set_mountpoint(struct vf
 
 extern int vfs_statfs(struct super_block *, struct kstatfs *);
 
+/* /sys/fs */
+extern struct subsystem fs_subsys;
+
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
 
Index: linux/fs/namespace.c
===================================================================
--- linux.orig/fs/namespace.c	2006-01-13 21:52:16.000000000 +0100
+++ linux/fs/namespace.c	2006-01-13 22:51:37.000000000 +0100
@@ -48,6 +48,10 @@ static int hash_mask __read_mostly, hash
 static kmem_cache_t *mnt_cache;
 static struct rw_semaphore namespace_sem;
 
+/* /sys/fs */
+decl_subsys(fs, NULL, NULL);
+EXPORT_SYMBOL(fs_subsys);
+
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
 	unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
@@ -1725,6 +1729,7 @@ void __init mnt_init(unsigned long mempa
 		i--;
 	} while (i);
 	sysfs_init();
+	subsystem_register(&fs_subsys);
 	init_rootfs();
 	init_mount_tree();
 }

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 02/17] fuse: fuse_copy_finish() order fix
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 01/17] add /sys/fs Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 03/17] fuse: fix request_end() Miklos Szeredi
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_fix_copy_finish.patch --]
[-- Type: text/plain, Size: 781 bytes --]

fuse_copy_finish() must be called before request_end(), since the
later might sleep, and no sleeping is allowed between fuse_copy_one()
and fuse_copy_finish() because of kmap_atomic()/kunmap_atomic() used
in them.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-13 21:52:16.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-13 22:51:43.000000000 +0100
@@ -773,8 +773,10 @@ static ssize_t fuse_dev_writev(struct fi
 
 	list_del_init(&req->list);
 	if (req->interrupted) {
-		request_end(fc, req);
+		spin_unlock(&fuse_lock);
 		fuse_copy_finish(&cs);
+		spin_lock(&fuse_lock);
+		request_end(fc, req);
 		return -ENOENT;
 	}
 	req->out.h = oh;

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 03/17] fuse: fix request_end()
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 01/17] add /sys/fs Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 02/17] fuse: fuse_copy_finish() order fix Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 04/17] fuse: handle error INIT reply Miklos Szeredi
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_fix_request_end.patch --]
[-- Type: text/plain, Size: 2027 bytes --]

This function used the request object after decrementing it's
reference count and releasing the lock.  This could in theory lead to
all sorts of problems.

Fix and simplify at the same time.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-13 22:51:43.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-13 22:51:48.000000000 +0100
@@ -171,19 +171,17 @@ static void process_init_reply(struct fu
 /*
  * This function is called when a request is finished.  Either a reply
  * has arrived or it was interrupted (and not yet sent) or some error
- * occurred during communication with userspace, or the device file was
- * closed.  It decreases the reference count for the request.  In case
- * of a background request the reference to the stored objects are
- * released.  The requester thread is woken up (if still waiting), and
- * finally the request is either freed or put on the unused_list
+ * occurred during communication with userspace, or the device file
+ * was closed.  In case of a background request the reference to the
+ * stored objects are released.  The requester thread is woken up (if
+ * still waiting), and finally the reference to the request is
+ * released
  *
  * Called with fuse_lock, unlocks it
  */
 static void request_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-	int putback;
 	req->finished = 1;
-	putback = atomic_dec_and_test(&req->count);
 	spin_unlock(&fuse_lock);
 	if (req->background) {
 		down_read(&fc->sbput_sem);
@@ -197,13 +195,11 @@ static void request_end(struct fuse_conn
 	else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) {
 		/* Special case for failed iget in CREATE */
 		u64 nodeid = req->in.h.nodeid;
-		__fuse_get_request(req);
 		fuse_reset_request(req);
 		fuse_send_forget(fc, req, nodeid, 1);
-		putback = 0;
+		return;
 	}
-	if (putback)
-		fuse_putback_request(fc, req);
+	fuse_put_request(fc, req);
 }
 
 /*

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 04/17] fuse: handle error INIT reply
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (2 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 03/17] fuse: fix request_end() Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 05/17] fuse: uninline some functions Miklos Szeredi
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_init_reply_error.patch --]
[-- Type: text/plain, Size: 625 bytes --]

Handle the case when the INIT request is answered with an error.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-13 22:51:48.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-13 22:51:53.000000000 +0100
@@ -153,7 +153,7 @@ static void process_init_reply(struct fu
 	int i;
 	struct fuse_init_out *arg = &req->misc.init_out;
 
-	if (arg->major != FUSE_KERNEL_VERSION)
+	if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
 		fc->conn_error = 1;
 	else {
 		fc->minor = arg->minor;

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 05/17] fuse: uninline some functions
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (3 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 04/17] fuse: handle error INIT reply Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 06/17] fuse: miscellaneous cleanup Miklos Szeredi
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_uninline.patch --]
[-- Type: text/plain, Size: 5268 bytes --]

Inline keyword is unnecessary in most cases.  Clean them up.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-13 23:40:08.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-13 23:40:09.000000000 +0100
@@ -21,7 +21,7 @@ MODULE_ALIAS_MISCDEV(FUSE_MINOR);
 
 static kmem_cache_t *fuse_req_cachep;
 
-static inline struct fuse_conn *fuse_get_conn(struct file *file)
+static struct fuse_conn *fuse_get_conn(struct file *file)
 {
 	struct fuse_conn *fc;
 	spin_lock(&fuse_lock);
@@ -32,7 +32,7 @@ static inline struct fuse_conn *fuse_get
 	return fc;
 }
 
-static inline void fuse_request_init(struct fuse_req *req)
+static void fuse_request_init(struct fuse_req *req)
 {
 	memset(req, 0, sizeof(*req));
 	INIT_LIST_HEAD(&req->list);
@@ -53,7 +53,7 @@ void fuse_request_free(struct fuse_req *
 	kmem_cache_free(fuse_req_cachep, req);
 }
 
-static inline void block_sigs(sigset_t *oldset)
+static void block_sigs(sigset_t *oldset)
 {
 	sigset_t mask;
 
@@ -61,7 +61,7 @@ static inline void block_sigs(sigset_t *
 	sigprocmask(SIG_BLOCK, &mask, oldset);
 }
 
-static inline void restore_sigs(sigset_t *oldset)
+static void restore_sigs(sigset_t *oldset)
 {
 	sigprocmask(SIG_SETMASK, oldset, NULL);
 }
@@ -385,7 +385,7 @@ void fuse_send_init(struct fuse_conn *fc
  * anything that could cause a page-fault.  If the request was already
  * interrupted bail out.
  */
-static inline int lock_request(struct fuse_req *req)
+static int lock_request(struct fuse_req *req)
 {
 	int err = 0;
 	if (req) {
@@ -404,7 +404,7 @@ static inline int lock_request(struct fu
  * requester thread is currently waiting for it to be unlocked, so
  * wake it up.
  */
-static inline void unlock_request(struct fuse_req *req)
+static void unlock_request(struct fuse_req *req)
 {
 	if (req) {
 		spin_lock(&fuse_lock);
@@ -440,7 +440,7 @@ static void fuse_copy_init(struct fuse_c
 }
 
 /* Unmap and put previous page of userspace buffer */
-static inline void fuse_copy_finish(struct fuse_copy_state *cs)
+static void fuse_copy_finish(struct fuse_copy_state *cs)
 {
 	if (cs->mapaddr) {
 		kunmap_atomic(cs->mapaddr, KM_USER0);
@@ -489,8 +489,7 @@ static int fuse_copy_fill(struct fuse_co
 }
 
 /* Do as much copy to/from userspace buffer as we can */
-static inline int fuse_copy_do(struct fuse_copy_state *cs, void **val,
-			       unsigned *size)
+static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size)
 {
 	unsigned ncpy = min(*size, cs->len);
 	if (val) {
@@ -510,8 +509,8 @@ static inline int fuse_copy_do(struct fu
  * Copy a page in the request to/from the userspace buffer.  Must be
  * done atomically
  */
-static inline int fuse_copy_page(struct fuse_copy_state *cs, struct page *page,
-				 unsigned offset, unsigned count, int zeroing)
+static int fuse_copy_page(struct fuse_copy_state *cs, struct page *page,
+			  unsigned offset, unsigned count, int zeroing)
 {
 	if (page && zeroing && count < PAGE_SIZE) {
 		void *mapaddr = kmap_atomic(page, KM_USER1);
Index: linux/fs/fuse/dir.c
===================================================================
--- linux.orig/fs/fuse/dir.c	2006-01-13 23:40:08.000000000 +0100
+++ linux/fs/fuse/dir.c	2006-01-13 23:40:09.000000000 +0100
@@ -23,8 +23,7 @@
 /*
  * Calculate the time in jiffies until a dentry/attributes are valid
  */
-static inline unsigned long time_to_jiffies(unsigned long sec,
-					    unsigned long nsec)
+static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec)
 {
 	struct timespec ts = {sec, nsec};
 	return jiffies + timespec_to_jiffies(&ts);
@@ -157,7 +156,7 @@ static int dir_alias(struct inode *inode
 	return 0;
 }
 
-static inline int invalid_nodeid(u64 nodeid)
+static int invalid_nodeid(u64 nodeid)
 {
 	return !nodeid || nodeid == FUSE_ROOT_ID;
 }
@@ -166,7 +165,7 @@ static struct dentry_operations fuse_den
 	.d_revalidate	= fuse_dentry_revalidate,
 };
 
-static inline int valid_mode(int m)
+static int valid_mode(int m)
 {
 	return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
 		S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
@@ -763,9 +762,8 @@ static int parse_dirfile(char *buf, size
 	return 0;
 }
 
-static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
-				       struct inode *inode, loff_t pos,
-				       size_t count)
+static size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
+				struct inode *inode, loff_t pos, size_t count)
 {
 	return fuse_send_read_common(req, file, inode, pos, count, 1);
 }
Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c	2006-01-13 23:40:08.000000000 +0100
+++ linux/fs/fuse/file.c	2006-01-13 23:40:09.000000000 +0100
@@ -267,9 +267,8 @@ size_t fuse_send_read_common(struct fuse
 	return req->out.args[0].size;
 }
 
-static inline size_t fuse_send_read(struct fuse_req *req, struct file *file,
-				    struct inode *inode, loff_t pos,
-				    size_t count)
+static size_t fuse_send_read(struct fuse_req *req, struct file *file,
+			     struct inode *inode, loff_t pos, size_t count)
 {
 	return fuse_send_read_common(req, file, inode, pos, count, 0);
 }

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 06/17] fuse: miscellaneous cleanup
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (4 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 05/17] fuse: uninline some functions Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 07/17] fuse: introduce unified request state Miklos Szeredi
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_cleanup.patch --]
[-- Type: text/plain, Size: 2984 bytes --]

 - remove some unneeded assignments

 - use kzalloc instead of kmalloc + memset

 - simplify setting sb->s_fs_info

 - in fuse_send_init() use fuse_get_request() instead of
   do_get_request() helper

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2006-01-13 23:12:58.000000000 +0100
+++ linux/fs/fuse/inode.c	2006-01-13 23:40:48.000000000 +0100
@@ -200,9 +200,6 @@ static void fuse_put_super(struct super_
 
 	spin_lock(&fuse_lock);
 	fc->mounted = 0;
-	fc->user_id = 0;
-	fc->group_id = 0;
-	fc->flags = 0;
 	/* Flush all readers on this fs */
 	wake_up_all(&fc->waitq);
 	up_write(&fc->sbput_sem);
@@ -379,16 +376,15 @@ static struct fuse_conn *new_conn(void)
 {
 	struct fuse_conn *fc;
 
-	fc = kmalloc(sizeof(*fc), GFP_KERNEL);
+	fc = kzalloc(sizeof(*fc), GFP_KERNEL);
 	if (fc != NULL) {
 		int i;
-		memset(fc, 0, sizeof(*fc));
 		init_waitqueue_head(&fc->waitq);
 		INIT_LIST_HEAD(&fc->pending);
 		INIT_LIST_HEAD(&fc->processing);
 		INIT_LIST_HEAD(&fc->unused_list);
 		INIT_LIST_HEAD(&fc->background);
-		sema_init(&fc->outstanding_sem, 0);
+		sema_init(&fc->outstanding_sem, 1); /* One for INIT */
 		init_rwsem(&fc->sbput_sem);
 		for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
 			struct fuse_req *req = fuse_request_alloc();
@@ -420,7 +416,7 @@ static struct fuse_conn *get_conn(struct
 		fc = ERR_PTR(-EINVAL);
 	} else {
 		file->private_data = fc;
-		*get_fuse_conn_super_p(sb) = fc;
+		sb->s_fs_info = fc;
 		fc->mounted = 1;
 		fc->connected = 1;
 		fc->count = 2;
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-13 23:12:57.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-13 23:40:18.000000000 +0100
@@ -280,14 +280,9 @@ struct fuse_conn {
 	struct backing_dev_info bdi;
 };
 
-static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb)
-{
-	return (struct fuse_conn **) &sb->s_fs_info;
-}
-
 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
 {
-	return *get_fuse_conn_super_p(sb);
+	return (struct fuse_conn *) sb->s_fs_info;
 }
 
 static inline struct fuse_conn *get_fuse_conn(struct inode *inode)
Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-13 23:40:09.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-13 23:40:18.000000000 +0100
@@ -361,8 +361,8 @@ void request_send_background(struct fuse
 void fuse_send_init(struct fuse_conn *fc)
 {
 	/* This is called from fuse_read_super() so there's guaranteed
-	   to be a request available */
-	struct fuse_req *req = do_get_request(fc);
+	   to be exactly one request available */
+	struct fuse_req *req = fuse_get_request(fc);
 	struct fuse_init_in *arg = &req->misc.init_in;
 	arg->major = FUSE_KERNEL_VERSION;
 	arg->minor = FUSE_KERNEL_MINOR_VERSION;

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 07/17] fuse: introduce unified request state
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (5 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 06/17] fuse: miscellaneous cleanup Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 08/17] fuse: introduce list for requests under I/O Miklos Szeredi
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_request_state.patch --]
[-- Type: text/plain, Size: 3007 bytes --]

The state of request was made up of 2 bitfields (->sent and
->finished) and of the fact that the request was on a list or not.

Unify this into a single state field.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-13 22:52:03.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-13 22:52:06.000000000 +0100
@@ -181,7 +181,7 @@ static void process_init_reply(struct fu
  */
 static void request_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-	req->finished = 1;
+	req->state = FUSE_REQ_FINISHED;
 	spin_unlock(&fuse_lock);
 	if (req->background) {
 		down_read(&fc->sbput_sem);
@@ -250,10 +250,10 @@ static void request_wait_answer(struct f
 
 	spin_unlock(&fuse_lock);
 	block_sigs(&oldset);
-	wait_event_interruptible(req->waitq, req->finished);
+	wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
 	restore_sigs(&oldset);
 	spin_lock(&fuse_lock);
-	if (req->finished)
+	if (req->state == FUSE_REQ_FINISHED)
 		return;
 
 	req->out.h.error = -EINTR;
@@ -268,10 +268,10 @@ static void request_wait_answer(struct f
 		wait_event(req->waitq, !req->locked);
 		spin_lock(&fuse_lock);
 	}
-	if (!req->sent && !list_empty(&req->list)) {
+	if (req->state == FUSE_REQ_PENDING) {
 		list_del(&req->list);
 		__fuse_put_request(req);
-	} else if (!req->finished && req->sent)
+	} else if (req->state == FUSE_REQ_SENT)
 		background_request(fc, req);
 }
 
@@ -306,6 +306,7 @@ static void queue_request(struct fuse_co
 			fc->outstanding_debt++;
 	}
 	list_add_tail(&req->list, &fc->pending);
+	req->state = FUSE_REQ_PENDING;
 	wake_up(&fc->waitq);
 }
 
@@ -639,6 +640,7 @@ static ssize_t fuse_dev_readv(struct fil
 		goto err_unlock;
 
 	req = list_entry(fc->pending.next, struct fuse_req, list);
+	req->state = FUSE_REQ_READING;
 	list_del_init(&req->list);
 
 	in = &req->in;
@@ -672,7 +674,7 @@ static ssize_t fuse_dev_readv(struct fil
 	if (!req->isreply)
 		request_end(fc, req);
 	else {
-		req->sent = 1;
+		req->state = FUSE_REQ_SENT;
 		list_add_tail(&req->list, &fc->processing);
 		spin_unlock(&fuse_lock);
 	}
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-13 22:52:03.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-13 22:52:06.000000000 +0100
@@ -111,6 +111,15 @@ struct fuse_out {
 	struct fuse_arg args[3];
 };
 
+/** The request state */
+enum fuse_req_state {
+	FUSE_REQ_INIT = 0,
+	FUSE_REQ_PENDING,
+	FUSE_REQ_READING,
+	FUSE_REQ_SENT,
+	FUSE_REQ_FINISHED
+};
+
 /**
  * A request to the client
  */
@@ -140,11 +149,8 @@ struct fuse_req {
 	/** Data is being copied to/from the request */
 	unsigned locked:1;
 
-	/** Request has been sent to userspace */
-	unsigned sent:1;
-
-	/** The request is finished */
-	unsigned finished:1;
+	/** State of the request */
+	enum fuse_req_state state;
 
 	/** The request input */
 	struct fuse_in in;

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 08/17] fuse: introduce list for requests under I/O
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (6 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 07/17] fuse: introduce unified request state Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 09/17] fuse: extend semantics of connected flag Miklos Szeredi
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_io_list.patch --]
[-- Type: text/plain, Size: 3344 bytes --]

Create a new list for requests in the process of being transfered
to/from userspace.  This will be needed to be able to abort all
requests even those currently under I/O

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-13 22:52:06.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-13 22:52:09.000000000 +0100
@@ -181,6 +181,7 @@ static void process_init_reply(struct fu
  */
 static void request_end(struct fuse_conn *fc, struct fuse_req *req)
 {
+	list_del(&req->list);
 	req->state = FUSE_REQ_FINISHED;
 	spin_unlock(&fuse_lock);
 	if (req->background) {
@@ -641,7 +642,7 @@ static ssize_t fuse_dev_readv(struct fil
 
 	req = list_entry(fc->pending.next, struct fuse_req, list);
 	req->state = FUSE_REQ_READING;
-	list_del_init(&req->list);
+	list_move(&req->list, &fc->io);
 
 	in = &req->in;
 	reqsize = in->h.len;
@@ -675,7 +676,7 @@ static ssize_t fuse_dev_readv(struct fil
 		request_end(fc, req);
 	else {
 		req->state = FUSE_REQ_SENT;
-		list_add_tail(&req->list, &fc->processing);
+		list_move_tail(&req->list, &fc->processing);
 		spin_unlock(&fuse_lock);
 	}
 	return reqsize;
@@ -768,7 +769,6 @@ static ssize_t fuse_dev_writev(struct fi
 	if (!req)
 		goto err_unlock;
 
-	list_del_init(&req->list);
 	if (req->interrupted) {
 		spin_unlock(&fuse_lock);
 		fuse_copy_finish(&cs);
@@ -776,6 +776,7 @@ static ssize_t fuse_dev_writev(struct fi
 		request_end(fc, req);
 		return -ENOENT;
 	}
+	list_move(&req->list, &fc->io);
 	req->out.h = oh;
 	req->locked = 1;
 	cs.req = req;
@@ -835,7 +836,6 @@ static void end_requests(struct fuse_con
 	while (!list_empty(head)) {
 		struct fuse_req *req;
 		req = list_entry(head->next, struct fuse_req, list);
-		list_del_init(&req->list);
 		req->out.h.error = -ECONNABORTED;
 		request_end(fc, req);
 		spin_lock(&fuse_lock);
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-13 22:52:06.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-13 22:52:09.000000000 +0100
@@ -124,8 +124,8 @@ enum fuse_req_state {
  * A request to the client
  */
 struct fuse_req {
-	/** This can be on either unused_list, pending or processing
-	    lists in fuse_conn */
+	/** This can be on either unused_list, pending processing or
+	    io lists in fuse_conn */
 	struct list_head list;
 
 	/** Entry on the background list */
@@ -223,6 +223,9 @@ struct fuse_conn {
 	/** The list of requests being processed */
 	struct list_head processing;
 
+	/** The list of requests under I/O */
+	struct list_head io;
+
 	/** Requests put in the background (RELEASE or any other
 	    interrupted request) */
 	struct list_head background;
Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2006-01-13 22:52:03.000000000 +0100
+++ linux/fs/fuse/inode.c	2006-01-13 22:52:09.000000000 +0100
@@ -382,6 +382,7 @@ static struct fuse_conn *new_conn(void)
 		init_waitqueue_head(&fc->waitq);
 		INIT_LIST_HEAD(&fc->pending);
 		INIT_LIST_HEAD(&fc->processing);
+		INIT_LIST_HEAD(&fc->io);
 		INIT_LIST_HEAD(&fc->unused_list);
 		INIT_LIST_HEAD(&fc->background);
 		sema_init(&fc->outstanding_sem, 1); /* One for INIT */

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 09/17] fuse: extend semantics of connected flag
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (7 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 08/17] fuse: introduce list for requests under I/O Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 10/17] fuse: make fuse connection a kobject Miklos Szeredi
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_connected.patch --]
[-- Type: text/plain, Size: 2396 bytes --]

The ->connected flag for a fuse_conn object previously only indicated
whether the device file for this connection is currently open or not.

Change it's meaning so that it indicates whether the connection is
active or not: now either umount or device release will clear the
flag.

The separate ->mounted flag is still needed for handling background
requests.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-13 23:52:20.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-14 00:12:49.000000000 +0100
@@ -26,7 +26,7 @@ static struct fuse_conn *fuse_get_conn(s
 	struct fuse_conn *fc;
 	spin_lock(&fuse_lock);
 	fc = file->private_data;
-	if (fc && !fc->mounted)
+	if (fc && !fc->connected)
 		fc = NULL;
 	spin_unlock(&fuse_lock);
 	return fc;
@@ -594,7 +594,7 @@ static void request_wait(struct fuse_con
 	DECLARE_WAITQUEUE(wait, current);
 
 	add_wait_queue_exclusive(&fc->waitq, &wait);
-	while (fc->mounted && list_empty(&fc->pending)) {
+	while (fc->connected && list_empty(&fc->pending)) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (signal_pending(current))
 			break;
@@ -634,7 +634,7 @@ static ssize_t fuse_dev_readv(struct fil
 		goto err_unlock;
 	request_wait(fc);
 	err = -ENODEV;
-	if (!fc->mounted)
+	if (!fc->connected)
 		goto err_unlock;
 	err = -ERESTARTSYS;
 	if (list_empty(&fc->pending))
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-13 23:52:20.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-14 00:13:21.000000000 +0100
@@ -249,7 +249,8 @@ struct fuse_conn {
 	/** Mount is active */
 	unsigned mounted : 1;
 
-	/** Connection established */
+	/** Connection established, cleared on umount and device
+	    release */
 	unsigned connected : 1;
 
 	/** Connection failed (version mismatch) */
Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2006-01-13 23:52:20.000000000 +0100
+++ linux/fs/fuse/inode.c	2006-01-14 00:12:49.000000000 +0100
@@ -200,6 +200,7 @@ static void fuse_put_super(struct super_
 
 	spin_lock(&fuse_lock);
 	fc->mounted = 0;
+	fc->connected = 0;
 	/* Flush all readers on this fs */
 	wake_up_all(&fc->waitq);
 	up_write(&fc->sbput_sem);

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 10/17] fuse: make fuse connection a kobject
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (8 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 09/17] fuse: extend semantics of connected flag Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  0:39 ` [PATCH 11/17] fuse: add number of waiting requests attribute Miklos Szeredi
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_sys.patch --]
[-- Type: text/plain, Size: 9334 bytes --]

Kobjectify fuse_conn, and make it visible under
/sys/fs/fuse/connections.  Lacking any natural naming, connections are
numbered.

This patch doesn't add any attributes, just the infrastructure.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-14 00:04:52.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-14 00:09:47.000000000 +0100
@@ -852,9 +852,11 @@ static int fuse_dev_release(struct inode
 		fc->connected = 0;
 		end_requests(fc, &fc->pending);
 		end_requests(fc, &fc->processing);
-		fuse_release_conn(fc);
 	}
 	spin_unlock(&fuse_lock);
+	if (fc)
+		kobject_put(&fc->kobj);
+
 	return 0;
 }
 
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-14 00:04:52.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-14 00:09:47.000000000 +0100
@@ -196,9 +196,6 @@ struct fuse_req {
  * unmounted.
  */
 struct fuse_conn {
-	/** Reference count */
-	int count;
-
 	/** The user id for this mount */
 	uid_t user_id;
 
@@ -288,6 +285,9 @@ struct fuse_conn {
 
 	/** Backing dev info */
 	struct backing_dev_info bdi;
+
+	/** kobject */
+	struct kobject kobj;
 };
 
 static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
@@ -300,6 +300,11 @@ static inline struct fuse_conn *get_fuse
 	return get_fuse_conn_super(inode->i_sb);
 }
 
+static inline struct fuse_conn *get_fuse_conn_kobj(struct kobject *obj)
+{
+	return container_of(obj, struct fuse_conn, kobj);
+}
+
 static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
 {
 	return container_of(inode, struct fuse_inode, inode);
@@ -400,12 +405,6 @@ void fuse_init_symlink(struct inode *ino
 void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr);
 
 /**
- * Check if the connection can be released, and if yes, then free the
- * connection structure
- */
-void fuse_release_conn(struct fuse_conn *fc);
-
-/**
  * Initialize the client device
  */
 int fuse_dev_init(void);
Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2006-01-14 00:04:52.000000000 +0100
+++ linux/fs/fuse/inode.c	2006-01-14 00:09:47.000000000 +0100
@@ -24,6 +24,13 @@ MODULE_LICENSE("GPL");
 
 spinlock_t fuse_lock;
 static kmem_cache_t *fuse_inode_cachep;
+static struct subsystem connections_subsys;
+
+struct fuse_conn_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct fuse_conn *, char *);
+	ssize_t (*store)(struct fuse_conn *, const char *, size_t);
+};
 
 #define FUSE_SUPER_MAGIC 0x65735546
 
@@ -201,11 +208,12 @@ static void fuse_put_super(struct super_
 	spin_lock(&fuse_lock);
 	fc->mounted = 0;
 	fc->connected = 0;
+	spin_unlock(&fuse_lock);
+	up_write(&fc->sbput_sem);
 	/* Flush all readers on this fs */
 	wake_up_all(&fc->waitq);
-	up_write(&fc->sbput_sem);
-	fuse_release_conn(fc);
-	spin_unlock(&fuse_lock);
+	kobject_del(&fc->kobj);
+	kobject_put(&fc->kobj);
 }
 
 static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
@@ -354,8 +362,10 @@ static int fuse_show_options(struct seq_
 	return 0;
 }
 
-static void free_conn(struct fuse_conn *fc)
+static void fuse_conn_release(struct kobject *kobj)
 {
+	struct fuse_conn *fc = get_fuse_conn_kobj(kobj);
+
 	while (!list_empty(&fc->unused_list)) {
 		struct fuse_req *req;
 		req = list_entry(fc->unused_list.next, struct fuse_req, list);
@@ -365,20 +375,12 @@ static void free_conn(struct fuse_conn *
 	kfree(fc);
 }
 
-/* Must be called with the fuse lock held */
-void fuse_release_conn(struct fuse_conn *fc)
-{
-	fc->count--;
-	if (!fc->count)
-		free_conn(fc);
-}
-
 static struct fuse_conn *new_conn(void)
 {
 	struct fuse_conn *fc;
 
 	fc = kzalloc(sizeof(*fc), GFP_KERNEL);
-	if (fc != NULL) {
+	if (fc) {
 		int i;
 		init_waitqueue_head(&fc->waitq);
 		INIT_LIST_HEAD(&fc->pending);
@@ -388,10 +390,12 @@ static struct fuse_conn *new_conn(void)
 		INIT_LIST_HEAD(&fc->background);
 		sema_init(&fc->outstanding_sem, 1); /* One for INIT */
 		init_rwsem(&fc->sbput_sem);
+		kobj_set_kset_s(fc, connections_subsys);
+		kobject_init(&fc->kobj);
 		for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
 			struct fuse_req *req = fuse_request_alloc();
 			if (!req) {
-				free_conn(fc);
+				kobject_put(&fc->kobj);
 				return NULL;
 			}
 			list_add(&req->list, &fc->unused_list);
@@ -406,25 +410,32 @@ static struct fuse_conn *new_conn(void)
 static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
 {
 	struct fuse_conn *fc;
+	int err;
 
+	err = -EINVAL;
 	if (file->f_op != &fuse_dev_operations)
-		return ERR_PTR(-EINVAL);
+		goto out_err;
+
+	err = -ENOMEM;
 	fc = new_conn();
-	if (fc == NULL)
-		return ERR_PTR(-ENOMEM);
+	if (!fc)
+		goto out_err;
+
 	spin_lock(&fuse_lock);
-	if (file->private_data) {
-		free_conn(fc);
-		fc = ERR_PTR(-EINVAL);
-	} else {
-		file->private_data = fc;
-		sb->s_fs_info = fc;
-		fc->mounted = 1;
-		fc->connected = 1;
-		fc->count = 2;
-	}
+	err = -EINVAL;
+	if (file->private_data)
+		goto out_unlock;
+
+	kobject_get(&fc->kobj);
+	file->private_data = fc;
 	spin_unlock(&fuse_lock);
 	return fc;
+
+ out_unlock:
+	spin_unlock(&fuse_lock);
+	kobject_put(&fc->kobj);
+ out_err:
+	return ERR_PTR(err);
 }
 
 static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
@@ -447,12 +458,23 @@ static struct super_operations fuse_supe
 	.show_options	= fuse_show_options,
 };
 
+static unsigned long long conn_id(void)
+{
+	static unsigned long long ctr = 1;
+	unsigned long long val;
+	spin_lock(&fuse_lock);
+	val = ctr++;
+	spin_unlock(&fuse_lock);
+	return val;
+}
+
 static int fuse_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct fuse_conn *fc;
 	struct inode *root;
 	struct fuse_mount_data d;
 	struct file *file;
+	struct dentry *root_dentry;
 	int err;
 
 	if (!parse_fuse_opt((char *) data, &d))
@@ -480,23 +502,42 @@ static int fuse_fill_super(struct super_
 	if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
 		fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;
 
+	/* Used by get_root_inode() */
+	sb->s_fs_info = fc;
+
 	err = -ENOMEM;
 	root = get_root_inode(sb, d.rootmode);
-	if (root == NULL)
+	if (!root)
 		goto err;
 
-	sb->s_root = d_alloc_root(root);
-	if (!sb->s_root) {
+	root_dentry = d_alloc_root(root);
+	if (!root_dentry) {
 		iput(root);
 		goto err;
 	}
+
+	err = kobject_set_name(&fc->kobj, "%llu", conn_id());
+	if (err)
+		goto err_put_root;
+
+	err = kobject_add(&fc->kobj);
+	if (err)
+		goto err_put_root;
+
+	sb->s_root = root_dentry;
+	spin_lock(&fuse_lock);
+	fc->mounted = 1;
+	fc->connected = 1;
+	spin_unlock(&fuse_lock);
+
 	fuse_send_init(fc);
+
 	return 0;
 
+ err_put_root:
+	dput(root_dentry);
  err:
-	spin_lock(&fuse_lock);
-	fuse_release_conn(fc);
-	spin_unlock(&fuse_lock);
+	kobject_put(&fc->kobj);
 	return err;
 }
 
@@ -514,6 +555,50 @@ static struct file_system_type fuse_fs_t
 	.kill_sb	= kill_anon_super,
 };
 
+static struct attribute *fuse_conn_attrs[] = {
+	NULL,
+};
+
+static ssize_t fuse_conn_attr_show(struct kobject *kobj,
+				   struct attribute *attr,
+				   char *page)
+{
+	struct fuse_conn_attr *fca =
+		container_of(attr, struct fuse_conn_attr, attr);
+
+	if (fca->show)
+		return fca->show(get_fuse_conn_kobj(kobj), page);
+	else
+		return -EACCES;
+}
+
+static ssize_t fuse_conn_attr_store(struct kobject *kobj,
+				    struct attribute *attr,
+				    const char *page, size_t count)
+{
+	struct fuse_conn_attr *fca =
+		container_of(attr, struct fuse_conn_attr, attr);
+
+	if (fca->store)
+		return fca->store(get_fuse_conn_kobj(kobj), page, count);
+	else
+		return -EACCES;
+}
+
+static struct sysfs_ops fuse_conn_sysfs_ops = {
+	.show	= &fuse_conn_attr_show,
+	.store	= &fuse_conn_attr_store,
+};
+
+static struct kobj_type ktype_fuse_conn = {
+	.release	= fuse_conn_release,
+	.sysfs_ops	= &fuse_conn_sysfs_ops,
+	.default_attrs	= fuse_conn_attrs,
+};
+
+static decl_subsys(fuse, NULL, NULL);
+static decl_subsys(connections, &ktype_fuse_conn, NULL);
+
 static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
 				 unsigned long flags)
 {
@@ -551,6 +636,34 @@ static void fuse_fs_cleanup(void)
 	kmem_cache_destroy(fuse_inode_cachep);
 }
 
+static int fuse_sysfs_init(void)
+{
+	int err;
+
+	kset_set_kset_s(&fuse_subsys, fs_subsys);
+	err = subsystem_register(&fuse_subsys);
+	if (err)
+		goto out_err;
+
+	kset_set_kset_s(&connections_subsys, fuse_subsys);
+	err = subsystem_register(&connections_subsys);
+	if (err)
+		goto out_fuse_unregister;
+
+	return 0;
+
+ out_fuse_unregister:
+	subsystem_unregister(&fuse_subsys);
+ out_err:
+	return err;
+}
+
+static void fuse_sysfs_cleanup(void)
+{
+	subsystem_unregister(&connections_subsys);
+	subsystem_unregister(&fuse_subsys);
+}
+
 static int __init fuse_init(void)
 {
 	int res;
@@ -567,8 +680,14 @@ static int __init fuse_init(void)
 	if (res)
 		goto err_fs_cleanup;
 
+	res = fuse_sysfs_init();
+	if (res)
+		goto err_dev_cleanup;
+
 	return 0;
 
+ err_dev_cleanup:
+	fuse_dev_cleanup();
  err_fs_cleanup:
 	fuse_fs_cleanup();
  err:
@@ -579,6 +698,7 @@ static void __exit fuse_exit(void)
 {
 	printk(KERN_DEBUG "fuse exit\n");
 
+	fuse_sysfs_cleanup();
 	fuse_fs_cleanup();
 	fuse_dev_cleanup();
 }

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 11/17] fuse: add number of waiting requests attribute
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (9 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 10/17] fuse: make fuse connection a kobject Miklos Szeredi
@ 2006-01-14  0:39 ` Miklos Szeredi
  2006-01-14  1:28   ` Andrew Morton
  2006-01-14  0:40 ` [PATCH 12/17] fuse: add connection aborting Miklos Szeredi
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:39 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_num_waiting.patch --]
[-- Type: text/plain, Size: 2327 bytes --]

This patch adds the 'waiting' attribute which indicates how many
filesystem requests are currently waiting to be completed.  A non-zero
value without any filesystem activity indicates a hung or deadlocked
filesystem.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2006-01-14 00:22:44.000000000 +0100
+++ linux/fs/fuse/inode.c	2006-01-14 00:33:16.000000000 +0100
@@ -555,7 +555,16 @@ static struct file_system_type fuse_fs_t
 	.kill_sb	= kill_anon_super,
 };
 
+static ssize_t fuse_conn_waiting_show(struct fuse_conn *fc, char *page)
+{
+	return sprintf(page, "%i\n", atomic_read(&fc->num_waiting));
+}
+
+static struct fuse_conn_attr fuse_conn_waiting =
+	__ATTR(waiting, 0400, fuse_conn_waiting_show, NULL);
+
 static struct attribute *fuse_conn_attrs[] = {
+	&fuse_conn_waiting.attr,
 	NULL,
 };
 
Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-14 00:22:44.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-14 00:23:16.000000000 +0100
@@ -109,18 +109,24 @@ struct fuse_req *fuse_get_request(struct
 	int intr;
 	sigset_t oldset;
 
+	atomic_inc(&fc->num_waiting);
 	block_sigs(&oldset);
 	intr = down_interruptible(&fc->outstanding_sem);
 	restore_sigs(&oldset);
-	return intr ? NULL : do_get_request(fc);
+	if (intr) {
+		atomic_dec(&fc->num_waiting);
+		return NULL;
+	} 
+	return do_get_request(fc);
 }
 
 static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
 {
 	spin_lock(&fuse_lock);
-	if (req->preallocated)
+	if (req->preallocated) {
+		atomic_dec(&fc->num_waiting);
 		list_add(&req->list, &fc->unused_list);
-	else
+	} else
 		fuse_request_free(req);
 
 	/* If we are in debt decrease that first */
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-14 00:22:44.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-14 00:23:16.000000000 +0100
@@ -280,6 +280,9 @@ struct fuse_conn {
 	/** Is create not implemented by fs? */
 	unsigned no_create : 1;
 
+	/** The number of requests waiting for completion */
+	atomic_t num_waiting;
+
 	/** Negotiated minor version */
 	unsigned minor;
 

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 12/17] fuse: add connection aborting
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (10 preceding siblings ...)
  2006-01-14  0:39 ` [PATCH 11/17] fuse: add number of waiting requests attribute Miklos Szeredi
@ 2006-01-14  0:40 ` Miklos Szeredi
  2006-01-14  1:31   ` Andrew Morton
  2006-01-14  0:40 ` [PATCH 13/17] fuse: add asynchronous request support Miklos Szeredi
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:40 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_abort_conn.patch --]
[-- Type: text/plain, Size: 6095 bytes --]

Add ability to abort a filesystem connection.

With the introduction of asynchronous reads, the ability to interrupt
any request is not enough to dissolve deadlocks, since now waiting for
the request completion (page unlocked) is independent of the actual
request, so in a deadlock all threads will be uninterruptible.

The solution is to make it possible to abort all requests, even those
currently undergoing I/O to/from userspace.  The natural interface for
this is 'mount -f mountpoint', but that only works as long as the
filesystem is attached.  So also add an 'abort' attribute to the sysfs
view of the connection.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-14 00:23:16.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-14 00:33:20.000000000 +0100
@@ -260,11 +260,13 @@ static void request_wait_answer(struct f
 	wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED);
 	restore_sigs(&oldset);
 	spin_lock(&fuse_lock);
-	if (req->state == FUSE_REQ_FINISHED)
+	if (req->state == FUSE_REQ_FINISHED && !req->interrupted)
 		return;
 
-	req->out.h.error = -EINTR;
-	req->interrupted = 1;
+	if (!req->interrupted) {
+		req->out.h.error = -EINTR;
+		req->interrupted = 1;
+	}
 	if (req->locked) {
 		/* This is uninterruptible sleep, because data is
 		   being copied to/from the buffers of req.  During
@@ -770,6 +772,10 @@ static ssize_t fuse_dev_writev(struct fi
 		goto err_finish;
 
 	spin_lock(&fuse_lock);
+	err = -ENOENT;
+	if (!fc->connected)
+		goto err_unlock;
+
 	req = request_find(fc, oh.unique);
 	err = -EINVAL;
 	if (!req)
@@ -836,7 +842,11 @@ static unsigned fuse_dev_poll(struct fil
 	return mask;
 }
 
-/* Abort all requests on the given list (pending or processing) */
+/*
+ * Abort all requests on the given list (pending or processing)
+ *
+ * This function releases and reacquires fuse_lock
+ */
 static void end_requests(struct fuse_conn *fc, struct list_head *head)
 {
 	while (!list_empty(head)) {
@@ -848,6 +858,59 @@ static void end_requests(struct fuse_con
 	}
 }
 
+/*
+ * Abort requests under I/O
+ *
+ * The requests are set to interrupted and finished, and the request
+ * waiter is woken up.  This will make request_wait_answer() wait
+ * until the request is unlocked and then return.
+ */
+static void end_io_requests(struct fuse_conn *fc)
+{
+	while (!list_empty(&fc->io)) {
+		struct fuse_req *req;
+		req = list_entry(fc->io.next, struct fuse_req, list);
+		req->interrupted = 1;
+		req->out.h.error = -ECONNABORTED;
+		req->state = FUSE_REQ_FINISHED;
+		list_del_init(&req->list);
+		wake_up(&req->waitq);
+	}
+}
+
+/*
+ * Abort all requests.
+ *
+ * Emergency exit in case of a malicious or accidental deadlock, or
+ * just a hung filesystem.
+ *
+ * The same effect is usually achievable through killing the
+ * filesystem daemon and all users of the filesystem.  The exception
+ * is the combination of an asynchronous request and the tricky
+ * deadlock (see Documentation/filesystems/fuse.txt).
+ *
+ * During the aborting, progression of requests from the pending and
+ * processing lists onto the io list, and progression of new requests
+ * onto the pending list is prevented by req->connected being false.
+ *
+ * Progression of requests under I/O to the processing list is
+ * prevented by the req->interrupted flag being true for these
+ * requests.  For this reason requests on the io list must be aborted
+ * first.
+ */
+void fuse_abort_conn(struct fuse_conn *fc)
+{
+	spin_lock(&fuse_lock);
+	if (fc->connected) {
+		fc->connected = 0;
+		end_io_requests(fc);
+		end_requests(fc, &fc->pending);
+		end_requests(fc, &fc->processing);
+		wake_up_all(&fc->waitq);
+	}
+	spin_unlock(&fuse_lock);
+}
+
 static int fuse_dev_release(struct inode *inode, struct file *file)
 {
 	struct fuse_conn *fc;
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-14 00:23:16.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-14 00:33:20.000000000 +0100
@@ -246,8 +246,8 @@ struct fuse_conn {
 	/** Mount is active */
 	unsigned mounted : 1;
 
-	/** Connection established, cleared on umount and device
-	    release */
+	/** Connection established, cleared on umount, connection
+	    abort and device release */
 	unsigned connected : 1;
 
 	/** Connection failed (version mismatch) */
@@ -463,6 +463,9 @@ void request_send_background(struct fuse
  */
 void fuse_release_background(struct fuse_req *req);
 
+/* Abort all requests */
+void fuse_abort_conn(struct fuse_conn *fc);
+
 /**
  * Get the attributes of a file
  */
Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2006-01-14 00:33:16.000000000 +0100
+++ linux/fs/fuse/inode.c	2006-01-14 00:33:20.000000000 +0100
@@ -196,6 +196,11 @@ struct inode *fuse_iget(struct super_blo
 	return inode;
 }
 
+static void fuse_umount_begin(struct super_block *sb)
+{
+	fuse_abort_conn(get_fuse_conn_super(sb));
+}
+
 static void fuse_put_super(struct super_block *sb)
 {
 	struct fuse_conn *fc = get_fuse_conn_super(sb);
@@ -454,6 +459,7 @@ static struct super_operations fuse_supe
 	.read_inode	= fuse_read_inode,
 	.clear_inode	= fuse_clear_inode,
 	.put_super	= fuse_put_super,
+	.umount_begin	= fuse_umount_begin,
 	.statfs		= fuse_statfs,
 	.show_options	= fuse_show_options,
 };
@@ -560,11 +566,21 @@ static ssize_t fuse_conn_waiting_show(st
 	return sprintf(page, "%i\n", atomic_read(&fc->num_waiting));
 }
 
+static ssize_t fuse_conn_abort_store(struct fuse_conn *fc, const char *page,
+				     size_t count)
+{
+	fuse_abort_conn(fc);
+	return count;
+}
+
 static struct fuse_conn_attr fuse_conn_waiting =
 	__ATTR(waiting, 0400, fuse_conn_waiting_show, NULL);
+static struct fuse_conn_attr fuse_conn_abort =
+	__ATTR(abort, 0600, NULL, fuse_conn_abort_store);
 
 static struct attribute *fuse_conn_attrs[] = {
 	&fuse_conn_waiting.attr,
+	&fuse_conn_abort.attr,
 	NULL,
 };
 

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 13/17] fuse: add asynchronous request support
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (11 preceding siblings ...)
  2006-01-14  0:40 ` [PATCH 12/17] fuse: add connection aborting Miklos Szeredi
@ 2006-01-14  0:40 ` Miklos Szeredi
  2006-01-14  0:40 ` [PATCH 14/17] fuse: move INIT handling to inode.c Miklos Szeredi
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:40 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_async_req.patch --]
[-- Type: text/plain, Size: 4811 bytes --]

Add possibility for requests to run asynchronously and call an 'end'
callback when finished.

With this, the special handling of the INIT and RELEASE requests can
be cleaned up too.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-14 00:41:33.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-14 00:43:41.000000000 +0100
@@ -172,6 +172,8 @@ static void process_init_reply(struct fu
 	   fuse_putback_request() */
 	for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
 		up(&fc->outstanding_sem);
+
+	fuse_put_request(fc, req);
 }
 
 /*
@@ -180,13 +182,15 @@ static void process_init_reply(struct fu
  * occurred during communication with userspace, or the device file
  * was closed.  In case of a background request the reference to the
  * stored objects are released.  The requester thread is woken up (if
- * still waiting), and finally the reference to the request is
- * released
+ * still waiting), the 'end' callback is called if given, else the
+ * reference to the request is released
  *
  * Called with fuse_lock, unlocks it
  */
 static void request_end(struct fuse_conn *fc, struct fuse_req *req)
 {
+	void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
+	req->end = NULL;
 	list_del(&req->list);
 	req->state = FUSE_REQ_FINISHED;
 	spin_unlock(&fuse_lock);
@@ -197,16 +201,10 @@ static void request_end(struct fuse_conn
 		up_read(&fc->sbput_sem);
 	}
 	wake_up(&req->waitq);
-	if (req->in.h.opcode == FUSE_INIT)
-		process_init_reply(fc, req);
-	else if (req->in.h.opcode == FUSE_RELEASE && req->inode == NULL) {
-		/* Special case for failed iget in CREATE */
-		u64 nodeid = req->in.h.nodeid;
-		fuse_reset_request(req);
-		fuse_send_forget(fc, req, nodeid, 1);
-		return;
-	}
-	fuse_put_request(fc, req);
+	if (end)
+		end(fc, req);
+	else
+		fuse_put_request(fc, req);
 }
 
 /*
@@ -387,6 +385,7 @@ void fuse_send_init(struct fuse_conn *fc
 	req->out.argvar = 1;
 	req->out.args[0].size = sizeof(struct fuse_init_out);
 	req->out.args[0].value = &req->misc.init_out;
+	req->end = process_init_reply;
 	request_send_background(fc, req);
 }
 
@@ -864,17 +863,32 @@ static void end_requests(struct fuse_con
  * The requests are set to interrupted and finished, and the request
  * waiter is woken up.  This will make request_wait_answer() wait
  * until the request is unlocked and then return.
+ *
+ * If the request is asynchronous, then the end function needs to be
+ * called after waiting for the request to be unlocked (if it was
+ * locked).
  */
 static void end_io_requests(struct fuse_conn *fc)
 {
 	while (!list_empty(&fc->io)) {
-		struct fuse_req *req;
-		req = list_entry(fc->io.next, struct fuse_req, list);
+		struct fuse_req *req =
+			list_entry(fc->io.next, struct fuse_req, list);
+		void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
+
 		req->interrupted = 1;
 		req->out.h.error = -ECONNABORTED;
 		req->state = FUSE_REQ_FINISHED;
 		list_del_init(&req->list);
 		wake_up(&req->waitq);
+		if (end) {
+			req->end = NULL;
+			/* The end function will consume this reference */
+			__fuse_get_request(req);
+			spin_unlock(&fuse_lock);
+			wait_event(req->waitq, !req->locked);
+			end(fc, req);
+			spin_lock(&fuse_lock);
+		}
 	}
 }
 
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-14 00:41:33.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-14 00:43:41.000000000 +0100
@@ -120,6 +120,8 @@ enum fuse_req_state {
 	FUSE_REQ_FINISHED
 };
 
+struct fuse_conn;
+
 /**
  * A request to the client
  */
@@ -186,6 +188,9 @@ struct fuse_req {
 
 	/** File used in the request (or NULL) */
 	struct file *file;
+
+	/** Request completion callback */
+	void (*end)(struct fuse_conn *, struct fuse_req *);
 };
 
 /**
Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c	2006-01-13 23:40:09.000000000 +0100
+++ linux/fs/fuse/file.c	2006-01-14 00:43:41.000000000 +0100
@@ -113,6 +113,14 @@ int fuse_open_common(struct inode *inode
 	return err;
 }
 
+/* Special case for failed iget in CREATE */
+static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+	u64 nodeid = req->in.h.nodeid;
+	fuse_reset_request(req);
+	fuse_send_forget(fc, req, nodeid, 1);
+}
+
 void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
 		       u64 nodeid, struct inode *inode, int flags, int isdir)
 {
@@ -128,6 +136,8 @@ void fuse_send_release(struct fuse_conn 
 	req->in.args[0].size = sizeof(struct fuse_release_in);
 	req->in.args[0].value = inarg;
 	request_send_background(fc, req);
+	if (!inode)
+		req->end = fuse_release_end;
 	kfree(ff);
 }
 

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 14/17] fuse: move INIT handling to inode.c
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (12 preceding siblings ...)
  2006-01-14  0:40 ` [PATCH 13/17] fuse: add asynchronous request support Miklos Szeredi
@ 2006-01-14  0:40 ` Miklos Szeredi
  2006-01-14  0:40 ` [PATCH 15/17] fuse: READ request initialization Miklos Szeredi
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:40 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_send_init_cleanup.patch --]
[-- Type: text/plain, Size: 4767 bytes --]

Now the INIT requests can be completely handled in inode.c and the
fuse_send_init() function need not be global any more.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dev.c
===================================================================
--- linux.orig/fs/fuse/dev.c	2006-01-14 00:43:41.000000000 +0100
+++ linux/fs/fuse/dev.c	2006-01-14 00:45:13.000000000 +0100
@@ -154,28 +154,6 @@ void fuse_release_background(struct fuse
 	spin_unlock(&fuse_lock);
 }
 
-static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
-{
-	int i;
-	struct fuse_init_out *arg = &req->misc.init_out;
-
-	if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
-		fc->conn_error = 1;
-	else {
-		fc->minor = arg->minor;
-		fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
-	}
-
-	/* After INIT reply is received other requests can go
-	   out.  So do (FUSE_MAX_OUTSTANDING - 1) number of
-	   up()s on outstanding_sem.  The last up() is done in
-	   fuse_putback_request() */
-	for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
-		up(&fc->outstanding_sem);
-
-	fuse_put_request(fc, req);
-}
-
 /*
  * This function is called when a request is finished.  Either a reply
  * has arrived or it was interrupted (and not yet sent) or some error
@@ -366,29 +344,6 @@ void request_send_background(struct fuse
 	request_send_nowait(fc, req);
 }
 
-void fuse_send_init(struct fuse_conn *fc)
-{
-	/* This is called from fuse_read_super() so there's guaranteed
-	   to be exactly one request available */
-	struct fuse_req *req = fuse_get_request(fc);
-	struct fuse_init_in *arg = &req->misc.init_in;
-	arg->major = FUSE_KERNEL_VERSION;
-	arg->minor = FUSE_KERNEL_MINOR_VERSION;
-	req->in.h.opcode = FUSE_INIT;
-	req->in.numargs = 1;
-	req->in.args[0].size = sizeof(*arg);
-	req->in.args[0].value = arg;
-	req->out.numargs = 1;
-	/* Variable length arguement used for backward compatibility
-	   with interface version < 7.5.  Rest of init_out is zeroed
-	   by do_get_request(), so a short reply is not a problem */
-	req->out.argvar = 1;
-	req->out.args[0].size = sizeof(struct fuse_init_out);
-	req->out.args[0].value = &req->misc.init_out;
-	req->end = process_init_reply;
-	request_send_background(fc, req);
-}
-
 /*
  * Lock the request.  Up to the next unlock_request() there mustn't be
  * anything that could cause a page-fault.  If the request was already
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-14 00:43:41.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-14 00:45:13.000000000 +0100
@@ -480,8 +480,3 @@ int fuse_do_getattr(struct inode *inode)
  * Invalidate inode attributes
  */
 void fuse_invalidate_attr(struct inode *inode);
-
-/**
- * Send the INIT message
- */
-void fuse_send_init(struct fuse_conn *fc);
Index: linux/fs/fuse/inode.c
===================================================================
--- linux.orig/fs/fuse/inode.c	2006-01-14 00:41:33.000000000 +0100
+++ linux/fs/fuse/inode.c	2006-01-14 00:45:13.000000000 +0100
@@ -464,6 +464,51 @@ static struct super_operations fuse_supe
 	.show_options	= fuse_show_options,
 };
 
+static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
+{
+	int i;
+	struct fuse_init_out *arg = &req->misc.init_out;
+
+	if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION)
+		fc->conn_error = 1;
+	else {
+		fc->minor = arg->minor;
+		fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
+	}
+
+	/* After INIT reply is received other requests can go
+	   out.  So do (FUSE_MAX_OUTSTANDING - 1) number of
+	   up()s on outstanding_sem.  The last up() is done in
+	   fuse_putback_request() */
+	for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
+		up(&fc->outstanding_sem);
+
+	fuse_put_request(fc, req);
+}
+
+static void fuse_send_init(struct fuse_conn *fc)
+{
+	/* This is called from fuse_read_super() so there's guaranteed
+	   to be exactly one request available */
+	struct fuse_req *req = fuse_get_request(fc);
+	struct fuse_init_in *arg = &req->misc.init_in;
+	arg->major = FUSE_KERNEL_VERSION;
+	arg->minor = FUSE_KERNEL_MINOR_VERSION;
+	req->in.h.opcode = FUSE_INIT;
+	req->in.numargs = 1;
+	req->in.args[0].size = sizeof(*arg);
+	req->in.args[0].value = arg;
+	req->out.numargs = 1;
+	/* Variable length arguement used for backward compatibility
+	   with interface version < 7.5.  Rest of init_out is zeroed
+	   by do_get_request(), so a short reply is not a problem */
+	req->out.argvar = 1;
+	req->out.args[0].size = sizeof(struct fuse_init_out);
+	req->out.args[0].value = &req->misc.init_out;
+	req->end = process_init_reply;
+	request_send_background(fc, req);
+}
+
 static unsigned long long conn_id(void)
 {
 	static unsigned long long ctr = 1;

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 15/17] fuse: READ request initialization
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (13 preceding siblings ...)
  2006-01-14  0:40 ` [PATCH 14/17] fuse: move INIT handling to inode.c Miklos Szeredi
@ 2006-01-14  0:40 ` Miklos Szeredi
  2006-01-14  0:40 ` [PATCH 16/17] fuse: use asynchronous READ requests for readpages Miklos Szeredi
  2006-01-14  0:40 ` [PATCH 17/17] fuse: update documentation for sysfs Miklos Szeredi
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:40 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_read_fill.patch --]
[-- Type: text/plain, Size: 3898 bytes --]

Add a separate function for filling in the READ request.  This will
make it possible to send asynchronous READ requests as well as
synchronous ones.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/dir.c
===================================================================
--- linux.orig/fs/fuse/dir.c	2006-01-13 23:40:09.000000000 +0100
+++ linux/fs/fuse/dir.c	2006-01-14 00:48:17.000000000 +0100
@@ -762,12 +762,6 @@ static int parse_dirfile(char *buf, size
 	return 0;
 }
 
-static size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
-				struct inode *inode, loff_t pos, size_t count)
-{
-	return fuse_send_read_common(req, file, inode, pos, count, 1);
-}
-
 static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
 {
 	int err;
@@ -791,7 +785,9 @@ static int fuse_readdir(struct file *fil
 	}
 	req->num_pages = 1;
 	req->pages[0] = page;
-	nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
+	fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
+	request_send(fc, req);
+	nbytes = req->out.args[0].size;
 	err = req->out.h.error;
 	fuse_put_request(fc, req);
 	if (!err)
Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c	2006-01-14 00:43:41.000000000 +0100
+++ linux/fs/fuse/file.c	2006-01-14 00:48:17.000000000 +0100
@@ -250,19 +250,16 @@ static int fuse_fsync(struct file *file,
 	return fuse_fsync_common(file, de, datasync, 0);
 }
 
-size_t fuse_send_read_common(struct fuse_req *req, struct file *file,
-			     struct inode *inode, loff_t pos, size_t count,
-			     int isdir)
+void fuse_read_fill(struct fuse_req *req, struct file *file,
+		    struct inode *inode, loff_t pos, size_t count, int opcode)
 {
-	struct fuse_conn *fc = get_fuse_conn(inode);
 	struct fuse_file *ff = file->private_data;
-	struct fuse_read_in inarg;
+	struct fuse_read_in *inarg = &req->misc.read_in;
 
-	memset(&inarg, 0, sizeof(struct fuse_read_in));
-	inarg.fh = ff->fh;
-	inarg.offset = pos;
-	inarg.size = count;
-	req->in.h.opcode = isdir ? FUSE_READDIR : FUSE_READ;
+	inarg->fh = ff->fh;
+	inarg->offset = pos;
+	inarg->size = count;
+	req->in.h.opcode = opcode;
 	req->in.h.nodeid = get_node_id(inode);
 	req->inode = inode;
 	req->file = file;
@@ -273,14 +270,15 @@ size_t fuse_send_read_common(struct fuse
 	req->out.argvar = 1;
 	req->out.numargs = 1;
 	req->out.args[0].size = count;
-	request_send(fc, req);
-	return req->out.args[0].size;
 }
 
 static size_t fuse_send_read(struct fuse_req *req, struct file *file,
 			     struct inode *inode, loff_t pos, size_t count)
 {
-	return fuse_send_read_common(req, file, inode, pos, count, 0);
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
+	request_send(fc, req);
+	return req->out.args[0].size;
 }
 
 static int fuse_readpage(struct file *file, struct page *page)
Index: linux/fs/fuse/fuse_i.h
===================================================================
--- linux.orig/fs/fuse/fuse_i.h	2006-01-14 00:45:13.000000000 +0100
+++ linux/fs/fuse/fuse_i.h	2006-01-14 00:48:17.000000000 +0100
@@ -169,6 +169,7 @@ struct fuse_req {
 		struct fuse_release_in release_in;
 		struct fuse_init_in init_in;
 		struct fuse_init_out init_out;
+		struct fuse_read_in read_in;
 	} misc;
 
 	/** page vector */
@@ -354,11 +355,10 @@ void fuse_send_forget(struct fuse_conn *
 		      unsigned long nodeid, u64 nlookup);
 
 /**
- * Send READ or READDIR request
+ * Initialize READ or READDIR request
  */
-size_t fuse_send_read_common(struct fuse_req *req, struct file *file,
-			     struct inode *inode, loff_t pos, size_t count,
-			     int isdir);
+void fuse_read_fill(struct fuse_req *req, struct file *file,
+		    struct inode *inode, loff_t pos, size_t count, int opcode);
 
 /**
  * Send OPEN or OPENDIR request

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 16/17] fuse: use asynchronous READ requests for readpages
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (14 preceding siblings ...)
  2006-01-14  0:40 ` [PATCH 15/17] fuse: READ request initialization Miklos Szeredi
@ 2006-01-14  0:40 ` Miklos Szeredi
  2006-01-14  0:40 ` [PATCH 17/17] fuse: update documentation for sysfs Miklos Szeredi
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:40 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_async_read.patch --]
[-- Type: text/plain, Size: 3019 bytes --]

This patch changes fuse_readpages() to send READ requests
asynchronously.  This makes it possible for userspace filesystems to
utilize the kernel readahead logic instead of having to implement
their own (resulting in double caching).

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/fs/fuse/file.c
===================================================================
--- linux.orig/fs/fuse/file.c	2006-01-14 00:48:17.000000000 +0100
+++ linux/fs/fuse/file.c	2006-01-14 00:53:07.000000000 +0100
@@ -265,7 +265,7 @@ void fuse_read_fill(struct fuse_req *req
 	req->file = file;
 	req->in.numargs = 1;
 	req->in.args[0].size = sizeof(struct fuse_read_in);
-	req->in.args[0].value = &inarg;
+	req->in.args[0].value = inarg;
 	req->out.argpages = 1;
 	req->out.argvar = 1;
 	req->out.numargs = 1;
@@ -311,21 +311,33 @@ static int fuse_readpage(struct file *fi
 	return err;
 }
 
-static int fuse_send_readpages(struct fuse_req *req, struct file *file,
-			       struct inode *inode)
+static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
 {
-	loff_t pos = page_offset(req->pages[0]);
-	size_t count = req->num_pages << PAGE_CACHE_SHIFT;
-	unsigned i;
-	req->out.page_zeroing = 1;
-	fuse_send_read(req, file, inode, pos, count);
+	int i;
+
+	fuse_invalidate_attr(req->pages[0]->mapping->host); /* atime changed */
+
 	for (i = 0; i < req->num_pages; i++) {
 		struct page *page = req->pages[i];
 		if (!req->out.h.error)
 			SetPageUptodate(page);
+		else
+			SetPageError(page);
 		unlock_page(page);
 	}
-	return req->out.h.error;
+	fuse_put_request(fc, req);
+}
+
+static void fuse_send_readpages(struct fuse_req *req, struct file *file,
+				struct inode *inode)
+{
+	struct fuse_conn *fc = get_fuse_conn(inode);
+	loff_t pos = page_offset(req->pages[0]);
+	size_t count = req->num_pages << PAGE_CACHE_SHIFT;
+	req->out.page_zeroing = 1;
+	req->end = fuse_readpages_end;
+	fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
+	request_send_background(fc, req);
 }
 
 struct fuse_readpages_data {
@@ -345,12 +357,12 @@ static int fuse_readpages_fill(void *_da
 	    (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
 	     (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
 	     req->pages[req->num_pages - 1]->index + 1 != page->index)) {
-		int err = fuse_send_readpages(req, data->file, inode);
-		if (err) {
+		fuse_send_readpages(req, data->file, inode);
+		data->req = req = fuse_get_request(fc);
+		if (!req) {
 			unlock_page(page);
-			return err;
+			return -EINTR;
 		}
-		fuse_reset_request(req);
 	}
 	req->pages[req->num_pages] = page;
 	req->num_pages ++;
@@ -375,10 +387,8 @@ static int fuse_readpages(struct file *f
 		return -EINTR;
 
 	err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
-	if (!err && data.req->num_pages)
-		err = fuse_send_readpages(data.req, file, inode);
-	fuse_put_request(fc, data.req);
-	fuse_invalidate_attr(inode); /* atime changed */
+	if (!err)
+		fuse_send_readpages(data.req, file, inode);
 	return err;
 }
 

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 17/17] fuse: update documentation for sysfs
  2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
                   ` (15 preceding siblings ...)
  2006-01-14  0:40 ` [PATCH 16/17] fuse: use asynchronous READ requests for readpages Miklos Szeredi
@ 2006-01-14  0:40 ` Miklos Szeredi
  16 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  0:40 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

[-- Attachment #1: fuse_update_doc.patch --]
[-- Type: text/plain, Size: 2874 bytes --]

Add documentation for new attributes in sysfs.  Also describe the
different ways a connection may be aborted to a hung or deadlocked
filesystem.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>

Index: linux/Documentation/filesystems/fuse.txt
===================================================================
--- linux.orig/Documentation/filesystems/fuse.txt	2006-01-03 04:21:10.000000000 +0100
+++ linux/Documentation/filesystems/fuse.txt	2006-01-14 01:31:13.000000000 +0100
@@ -86,6 +86,62 @@ Mount options
   The default is infinite.  Note that the size of read requests is
   limited anyway to 32 pages (which is 128kbyte on i386).
 
+Sysfs
+~~~~~
+
+FUSE sets up the following hierarchy in sysfs:
+
+  /sys/fs/fuse/connections/N/
+
+where N is an increasing number allocated to each new connection.
+
+For each connection the following attributes are defined:
+
+ 'waiting'
+
+  The number of requests which are waiting to be transfered to
+  userspace or being processed by the filesystem daemon.  If there is
+  no filesystem activity and 'waiting' is non-zero, then the
+  filesystem is hung or deadlocked.
+
+ 'abort'
+
+  Writing anything into this file will abort the filesystem
+  connection.  This means that all waiting requests will be aborted an
+  error returned for all aborted and new requests.
+
+Only a privileged user may read or write these attributes.
+
+Aborting a filesystem connection
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is possible to get into certain situations where the filesystem is
+not responding.  Reasons for this may be:
+
+  a) Broken userspace filesystem implementation
+
+  b) Network connection down
+
+  c) Accidental deadlock
+
+  d) Malicious deadlock
+
+(For more on c) and d) see later sections)
+
+In either of these cases it may be useful to abort the connection to
+the filesystem.  There are several ways to do this:
+
+  - Kill the filesystem daemon.  Works in case of a) and b)
+
+  - Kill the filesystem daemon and all users of the filesystem.  Works
+    in all cases except some malicious deadlocks
+
+  - Use forced umount (umount -f).  Works in all cases but only if
+    filesystem is still attached (it hasn't been lazy unmounted)
+
+  - Abort filesystem through the sysfs interface.  Most powerful
+    method, always works.
+
 How do non-privileged mounts work?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -313,3 +369,10 @@ faulted with get_user_pages().  The 'req
 when the copy is taking place, and interruption is delayed until
 this flag is unset.
 
+Scenario 3 - Tricky deadlock with asynchronous read
+---------------------------------------------------
+
+The same situation as above, except thread-1 will wait on page lock
+and hence it will be uninterruptible as well.  The solution is to
+abort the connection with forced umount (if mount is attached) or
+through the abort attribute in sysfs.

--

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 11/17] fuse: add number of waiting requests attribute
  2006-01-14  0:39 ` [PATCH 11/17] fuse: add number of waiting requests attribute Miklos Szeredi
@ 2006-01-14  1:28   ` Andrew Morton
  2006-01-14  9:44     ` Miklos Szeredi
  2006-01-18  5:56     ` Eric Dumazet
  0 siblings, 2 replies; 26+ messages in thread
From: Andrew Morton @ 2006-01-14  1:28 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-kernel

Miklos Szeredi <miklos@szeredi.hu> wrote:
>
> +	/** The number of requests waiting for completion */
> +	atomic_t num_waiting;

This doesn't get initialised anywhere.

Presumably you're relying on a memset somewhere.  That might work on all
architectures, AFAIK.  But in theory it's wrong.  If, for example, the
architecture implements atomic_t via a spinlock-plus-integer, and that
spinlock's unlocked state is not all-bits-zero, we're dead.

So we should initialise it with

	foo->num_waiting = ATOMIC_INIT(0);



nb: it is not correct to initialise an atomic_t with

	atomic_set(a, 0);

because in the above theoretical case case where the arch uses a spinlock
in the atomic_t, that spinlock doesn't get initialised.  I bet we've got code
in there which does this.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 12/17] fuse: add connection aborting
  2006-01-14  0:40 ` [PATCH 12/17] fuse: add connection aborting Miklos Szeredi
@ 2006-01-14  1:31   ` Andrew Morton
  2006-01-14  9:50     ` Miklos Szeredi
  0 siblings, 1 reply; 26+ messages in thread
From: Andrew Morton @ 2006-01-14  1:31 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-kernel

Miklos Szeredi <miklos@szeredi.hu> wrote:
>
>  	unsigned mounted : 1;
>  	unsigned connected : 1;

Do these bitfields have locking?

On some architectures, it might be that

	foo->mounted = 1;

will race with another CPU doing

	bar->connected = 1;

if the CPU+compiler implements bitfield modification via non-atomic
read/modify/write.

I don't know whether that's happening in real life, but it's a subtle risk.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 11/17] fuse: add number of waiting requests attribute
  2006-01-14  1:28   ` Andrew Morton
@ 2006-01-14  9:44     ` Miklos Szeredi
  2006-01-14  9:53       ` Andrew Morton
  2006-01-18  5:56     ` Eric Dumazet
  1 sibling, 1 reply; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  9:44 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

> This doesn't get initialised anywhere.
> 
> Presumably you're relying on a memset somewhere.  That might work on all
> architectures, AFAIK.  But in theory it's wrong.  If, for example, the
> architecture implements atomic_t via a spinlock-plus-integer, and that
> spinlock's unlocked state is not all-bits-zero, we're dead.
> 
> So we should initialise it with
> 
> 	foo->num_waiting = ATOMIC_INIT(0);
> 

Is it correct to use a structure initializer this way?

> nb: it is not correct to initialise an atomic_t with
> 
> 	atomic_set(a, 0);
> 
> because in the above theoretical case case where the arch uses a spinlock
> in the atomic_t, that spinlock doesn't get initialised.  I bet we've got code
> in there which does this.

According to Documentation/atomic_ops.txt, this is the correct usage
of atomic_set():

|           The first operations to implement for atomic_t's are the
|   initializers and plain reads.
|   
|           #define ATOMIC_INIT(i)          { (i) }
|           #define atomic_set(v, i)        ((v)->counter = (i))
|   
|   The first macro is used in definitions, such as:
|   
|   static atomic_t my_counter = ATOMIC_INIT(1);
|   
|   The second interface can be used at runtime, as in:
|   
|           struct foo { atomic_t counter; };
|           ...
|   
|           struct foo *k;
|   
|           k = kmalloc(sizeof(*k), GFP_KERNEL);
|           if (!k)
|                   return -ENOMEM;
|           atomic_set(&k->counter, 0);

So in fact atomic_set() is an initializer, and should be named
atomic_init() accordingly.  Is atomic_set() ever used as an atomic
operation rather than an initializer?

Miklos

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 12/17] fuse: add connection aborting
  2006-01-14  1:31   ` Andrew Morton
@ 2006-01-14  9:50     ` Miklos Szeredi
  0 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-14  9:50 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel

> >
> >  	unsigned mounted : 1;
> >  	unsigned connected : 1;
> 
> Do these bitfields have locking?

Yes, these ones do have locking, but the others that follow don't,
which would cause similar problems.  I'll revise this part of the
code.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 11/17] fuse: add number of waiting requests attribute
  2006-01-14  9:44     ` Miklos Szeredi
@ 2006-01-14  9:53       ` Andrew Morton
  0 siblings, 0 replies; 26+ messages in thread
From: Andrew Morton @ 2006-01-14  9:53 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: linux-kernel

Miklos Szeredi <miklos@szeredi.hu> wrote:
>
> > This doesn't get initialised anywhere.
> > 
> > Presumably you're relying on a memset somewhere.  That might work on all
> > architectures, AFAIK.  But in theory it's wrong.  If, for example, the
> > architecture implements atomic_t via a spinlock-plus-integer, and that
> > spinlock's unlocked state is not all-bits-zero, we're dead.
> > 
> > So we should initialise it with
> > 
> > 	foo->num_waiting = ATOMIC_INIT(0);
> > 
> 
> Is it correct to use a structure initializer this way?

Yes, if it's typecast to the right type.

ATOMIC_INIT is not.  I had a brainfart.

> > nb: it is not correct to initialise an atomic_t with
> > 
> > 	atomic_set(a, 0);
> > 
> > because in the above theoretical case case where the arch uses a spinlock
> > in the atomic_t, that spinlock doesn't get initialised.  I bet we've got code
> > in there which does this.
> 
> According to Documentation/atomic_ops.txt, this is the correct usage
> of atomic_set():
> 
> |           The first operations to implement for atomic_t's are the
> |   initializers and plain reads.
> |   
> |           #define ATOMIC_INIT(i)          { (i) }
> |           #define atomic_set(v, i)        ((v)->counter = (i))
> |   
> |   The first macro is used in definitions, such as:
> |   
> |   static atomic_t my_counter = ATOMIC_INIT(1);
> |   
> |   The second interface can be used at runtime, as in:
> |   
> |           struct foo { atomic_t counter; };
> |           ...
> |   
> |           struct foo *k;
> |   
> |           k = kmalloc(sizeof(*k), GFP_KERNEL);
> |           if (!k)
> |                   return -ENOMEM;
> |           atomic_set(&k->counter, 0);
> 
> So in fact atomic_set() is an initializer, and should be named
> atomic_init() accordingly.

Yes, we're screwed.  I don't think it's possible to implement atomic_t as
spinlock+int due to this.

>  Is atomic_set() ever used as an atomic
> operation rather than an initializer?
> 

Sure, lots of places.  Lots of places where you _don't_ want your
atomic_t's spinlock to be reinitialised.

hmm.

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 01/17] add /sys/fs
  2006-01-14  0:39 ` [PATCH 01/17] add /sys/fs Miklos Szeredi
@ 2006-01-17 12:47   ` Christoph Hellwig
  2006-01-17 12:52     ` Miklos Szeredi
  0 siblings, 1 reply; 26+ messages in thread
From: Christoph Hellwig @ 2006-01-17 12:47 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: akpm, linux-kernel, viro

On Sat, Jan 14, 2006 at 01:39:49AM +0100, Miklos Szeredi wrote:
> This patch adds an empty /sys/fs, which filesystems can use.

How does this address all the comments on the last submission
(as part of the reiser4 core changes)?


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 01/17] add /sys/fs
  2006-01-17 12:47   ` Christoph Hellwig
@ 2006-01-17 12:52     ` Miklos Szeredi
  0 siblings, 0 replies; 26+ messages in thread
From: Miklos Szeredi @ 2006-01-17 12:52 UTC (permalink / raw)
  To: hch; +Cc: akpm, linux-kernel, viro

> > This patch adds an empty /sys/fs, which filesystems can use.
> 
> How does this address all the comments on the last submission
> (as part of the reiser4 core changes)?

It's a different patch.

This just adds /sys/fs without any content.  Fuse needs this to add
some stuff, and other fs can use it as needed.

Miklos


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 11/17] fuse: add number of waiting requests attribute
  2006-01-14  1:28   ` Andrew Morton
  2006-01-14  9:44     ` Miklos Szeredi
@ 2006-01-18  5:56     ` Eric Dumazet
  1 sibling, 0 replies; 26+ messages in thread
From: Eric Dumazet @ 2006-01-18  5:56 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Miklos Szeredi, linux-kernel, jeffrey.t.kirsher

Andrew Morton a écrit :
> Miklos Szeredi <miklos@szeredi.hu> wrote:
>> +	/** The number of requests waiting for completion */
>> +	atomic_t num_waiting;
> 
> This doesn't get initialised anywhere.
> 
> Presumably you're relying on a memset somewhere.  That might work on all
> architectures, AFAIK.  But in theory it's wrong.  If, for example, the
> architecture implements atomic_t via a spinlock-plus-integer, and that
> spinlock's unlocked state is not all-bits-zero, we're dead.
> 
> So we should initialise it with
> 
> 	foo->num_waiting = ATOMIC_INIT(0);
> 
> 
> 
> nb: it is not correct to initialise an atomic_t with
> 
> 	atomic_set(a, 0);
> 
> because in the above theoretical case case where the arch uses a spinlock
> in the atomic_t, that spinlock doesn't get initialised.  I bet we've got code
> in there which does this.

Hum... I tracked one missing atomic_set() or ATOMIC_INIT in e1000 driver then.

e1000_alloc_queues() does :

#ifdef CONFIG_E1000_NAPI
         size = sizeof(struct net_device) * adapter->num_queues;
         adapter->polling_netdev = kmalloc(size, GFP_KERNEL);
         if (!adapter->polling_netdev) {
                 kfree(adapter->tx_ring);
                 kfree(adapter->rx_ring);
                 return -ENOMEM;
         }
         memset(adapter->polling_netdev, 0, size);
#endif

So this driver clearly assumes a memset(... 0 ...) also initialize atomic_t to 
  0   ((struct net_device *)->refcnt for example)

Eric

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2006-01-18  5:56 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-14  0:39 [PATCH 00/17] fuse: fixes, cleanups and asynchronous read requests Miklos Szeredi
2006-01-14  0:39 ` [PATCH 01/17] add /sys/fs Miklos Szeredi
2006-01-17 12:47   ` Christoph Hellwig
2006-01-17 12:52     ` Miklos Szeredi
2006-01-14  0:39 ` [PATCH 02/17] fuse: fuse_copy_finish() order fix Miklos Szeredi
2006-01-14  0:39 ` [PATCH 03/17] fuse: fix request_end() Miklos Szeredi
2006-01-14  0:39 ` [PATCH 04/17] fuse: handle error INIT reply Miklos Szeredi
2006-01-14  0:39 ` [PATCH 05/17] fuse: uninline some functions Miklos Szeredi
2006-01-14  0:39 ` [PATCH 06/17] fuse: miscellaneous cleanup Miklos Szeredi
2006-01-14  0:39 ` [PATCH 07/17] fuse: introduce unified request state Miklos Szeredi
2006-01-14  0:39 ` [PATCH 08/17] fuse: introduce list for requests under I/O Miklos Szeredi
2006-01-14  0:39 ` [PATCH 09/17] fuse: extend semantics of connected flag Miklos Szeredi
2006-01-14  0:39 ` [PATCH 10/17] fuse: make fuse connection a kobject Miklos Szeredi
2006-01-14  0:39 ` [PATCH 11/17] fuse: add number of waiting requests attribute Miklos Szeredi
2006-01-14  1:28   ` Andrew Morton
2006-01-14  9:44     ` Miklos Szeredi
2006-01-14  9:53       ` Andrew Morton
2006-01-18  5:56     ` Eric Dumazet
2006-01-14  0:40 ` [PATCH 12/17] fuse: add connection aborting Miklos Szeredi
2006-01-14  1:31   ` Andrew Morton
2006-01-14  9:50     ` Miklos Szeredi
2006-01-14  0:40 ` [PATCH 13/17] fuse: add asynchronous request support Miklos Szeredi
2006-01-14  0:40 ` [PATCH 14/17] fuse: move INIT handling to inode.c Miklos Szeredi
2006-01-14  0:40 ` [PATCH 15/17] fuse: READ request initialization Miklos Szeredi
2006-01-14  0:40 ` [PATCH 16/17] fuse: use asynchronous READ requests for readpages Miklos Szeredi
2006-01-14  0:40 ` [PATCH 17/17] fuse: update documentation for sysfs Miklos Szeredi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).