fuse: return -ECONNABORTED on /dev/fuse read after abort
Subsystems (2)
PATCH 1/1 fuse: return -ECONNABORTED on /dev/fuse read after abort
Currently the userspace has no way of knowing whether the fuse connection ended because of umount or abort via sysfs. It makes it hard for filesystems to free the mountpoint after abort without worrying about removing some new mount.
The patch fixes it by returning different errors when userspace reads from /dev/fuse (-ENODEV for umount and -ECONNABORTED for abort).
--- fs/fuse/control.c | 2 +- fs/fuse/dev.c | 13 ++++++++----- fs/fuse/fuse_i.h | 8 +++++++- fs/fuse/inode.c | 4 ++-- 4 files changed, 18 insertions(+), 9 deletions(-)
fs/fuse/control.c +1 -1
@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, {struct fuse_conn *fc =fuse_ctl_file_conn_get (file);if (fc) { -fuse_abort_conn (fc); +fuse_abort_conn (fc,1 );fuse_conn_put (fc); }return count;
fs/fuse/dev.c +8 -5
@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,if (err) goto err_unlock; - err = -ENODEV ; -if (!fiq->connected) +if (!fiq->connected) { + err = fiq->aborted ? -ECONNABORTED : -ENODEV ; goto err_unlock; + }if (!list_empty (&fiq->interrupts)) { req = list_entry(fiq->interrupts.next, struct fuse_req,
@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,spin_lock (&fpq->lock);clear_bit (FR_LOCKED , &req->flags);if (!fpq->connected) { - err = -ENODEV ; + err = fpq->aborted ? -ECONNABORTED : -ENODEV ; goto out_end; }if (err) {
@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)* is OK, the request will in that case be removed from the list before we touch * it. */ -void fuse_abort_conn (struct fuse_conn *fc) +void fuse_abort_conn (struct fuse_conn *fc,int is_abort) {struct fuse_iqueue *fiq = &fc->iq;
@@ -2095,6 +2096,7 @@ void fuse_abort_conn(struct fuse_conn *fc)spin_lock (&fpq->lock); fpq->connected =0 ; + fpq->aborted = is_abort;list_for_each_entry_safe (req, next, &fpq->io, list) { req->out.h.error = -ECONNABORTED ;spin_lock (&req->waitq.lock);
@@ -2113,6 +2115,7 @@ void fuse_abort_conn(struct fuse_conn *fc)spin_lock (&fiq->waitq.lock); fiq->connected =0 ; + fiq->aborted = is_abort;list_splice_init (&fiq->pending, &to_end2);list_for_each_entry (req, &to_end2, list)clear_bit (FR_PENDING , &req->flags);
@@ -2151,7 +2154,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)/* Are we the last open device? */ if (atomic_dec_and_test (&fc->dev_count)) {WARN_ON (fc->iq.fasync !=NULL ); -fuse_abort_conn (fc); +fuse_abort_conn (fc,0 ); }fuse_dev_free (fud); }
fs/fuse/fuse_i.h +7 -1
@@ -387,6 +387,9 @@ struct fuse_iqueue {/** Connection established */ unsigned connected; +/** Connection aborted via sysfs */ +int aborted; +/** Readers of the connection are waiting on this */ wait_queue_head_t waitq;
@@ -414,6 +417,9 @@ struct fuse_pqueue {/** Connection established */ unsigned connected; +/** Connection aborted via sysfs */ +int aborted; +/** Lock protecting accessess to members of this structure */ spinlock_t lock;
@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req);/* Abort all requests */ -void fuse_abort_conn (struct fuse_conn *fc); +void fuse_abort_conn (struct fuse_conn *fc,int is_abort);/** * Invalidate inode attributes
fs/fuse/inode.c +2 -2
@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)static void fuse_umount_begin (struct super_block *sb) { -fuse_abort_conn (get_fuse_conn_super (sb)); +fuse_abort_conn (get_fuse_conn_super (sb),0 ); }static void fuse_send_destroy (struct fuse_conn *fc)
@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)fuse_send_destroy (fc); -fuse_abort_conn (fc); +fuse_abort_conn (fc,0 );mutex_lock (&fuse_mutex);list_del (&fc->entry);fuse_ctl_remove_conn (fc);
Signature · 1 line
2.14.3
PATCH v2 1/1 fuse: return -ECONNABORTED on /dev/fuse read after abort
Return -ECONNABORTED when userspace tries to read from /dev/fuse after the fuse connection was aborted via sysfs.
The patch increases FUSE_KERNEL_MINOR_VERSION. However -ECONNABORTED is always returned, regardless of the minor version sent by userspace in FUSE_INIT.
Info why this patch might be useful:
https://github.com/libfuse/libfuse/issues/122
--- fs/fuse/control.c | 2 +- fs/fuse/dev.c | 13 ++++++++----- fs/fuse/fuse_i.h | 8 +++++++- fs/fuse/inode.c | 4 ++-- include/uapi/linux/fuse.h | 5 ++++- 5 files changed, 22 insertions(+), 10 deletions(-)
fs/fuse/control.c +1 -1
@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, {struct fuse_conn *fc =fuse_ctl_file_conn_get (file);if (fc) { -fuse_abort_conn (fc); +fuse_abort_conn (fc,1 );fuse_conn_put (fc); }return count;
fs/fuse/dev.c +8 -5
@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,if (err) goto err_unlock; - err = -ENODEV ; -if (!fiq->connected) +if (!fiq->connected) { + err = fiq->aborted ? -ECONNABORTED : -ENODEV ; goto err_unlock; + }if (!list_empty (&fiq->interrupts)) { req = list_entry(fiq->interrupts.next, struct fuse_req,
@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,spin_lock (&fpq->lock);clear_bit (FR_LOCKED , &req->flags);if (!fpq->connected) { - err = -ENODEV ; + err = fpq->aborted ? -ECONNABORTED : -ENODEV ; goto out_end; }if (err) {
@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)* is OK, the request will in that case be removed from the list before we touch * it. */ -void fuse_abort_conn (struct fuse_conn *fc) +void fuse_abort_conn (struct fuse_conn *fc,int is_abort) {struct fuse_iqueue *fiq = &fc->iq;
@@ -2095,6 +2096,7 @@ void fuse_abort_conn(struct fuse_conn *fc)spin_lock (&fpq->lock); fpq->connected =0 ; + fpq->aborted = is_abort;list_for_each_entry_safe (req, next, &fpq->io, list) { req->out.h.error = -ECONNABORTED ;spin_lock (&req->waitq.lock);
@@ -2113,6 +2115,7 @@ void fuse_abort_conn(struct fuse_conn *fc)spin_lock (&fiq->waitq.lock); fiq->connected =0 ; + fiq->aborted = is_abort;list_splice_init (&fiq->pending, &to_end2);list_for_each_entry (req, &to_end2, list)clear_bit (FR_PENDING , &req->flags);
@@ -2151,7 +2154,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)/* Are we the last open device? */ if (atomic_dec_and_test (&fc->dev_count)) {WARN_ON (fc->iq.fasync !=NULL ); -fuse_abort_conn (fc); +fuse_abort_conn (fc,0 ); }fuse_dev_free (fud); }
fs/fuse/fuse_i.h +7 -1
@@ -387,6 +387,9 @@ struct fuse_iqueue {/** Connection established */ unsigned connected; +/** Connection aborted via sysfs */ +int aborted; +/** Readers of the connection are waiting on this */ wait_queue_head_t waitq;
@@ -414,6 +417,9 @@ struct fuse_pqueue {/** Connection established */ unsigned connected; +/** Connection aborted via sysfs */ +int aborted; +/** Lock protecting accessess to members of this structure */ spinlock_t lock;
@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req);/* Abort all requests */ -void fuse_abort_conn (struct fuse_conn *fc); +void fuse_abort_conn (struct fuse_conn *fc,int is_abort);/** * Invalidate inode attributes
fs/fuse/inode.c +2 -2
@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)static void fuse_umount_begin (struct super_block *sb) { -fuse_abort_conn (get_fuse_conn_super (sb)); +fuse_abort_conn (get_fuse_conn_super (sb),0 ); }static void fuse_send_destroy (struct fuse_conn *fc)
@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)fuse_send_destroy (fc); -fuse_abort_conn (fc); +fuse_abort_conn (fc,0 );mutex_lock (&fuse_mutex);list_del (&fc->entry);fuse_ctl_remove_conn (fc);
include/uapi/linux/fuse.h +4 -1
@@ -112,6 +112,9 @@* 7.26 * - add FUSE_HANDLE_KILLPRIV * - add FUSE_POSIX_ACL +* +* 7.27 +* - reading from /dev/fuse after sysfs abort returns -ECONNABORTED */ #ifndef _LINUX_FUSE_H
@@ -147,7 +150,7 @@#define FUSE_KERNEL_VERSION 7/** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 26 +#define FUSE_KERNEL_MINOR_VERSION 27/** The node ID of the root inode */ #define FUSE_ROOT_ID 1
Signature · 1 line
2.15.0
Miklos Szeredi
maintainerQuoted 5 lines · Szymon Lukasz
Return
-ECONNABORTEDwhen userspace tries to read from/dev/fuseafter the fuse connection was aborted via sysfs.
The patch increasesFUSE_KERNEL_MINOR_VERSION. However-ECONNABORTEDis always returned, regardless of the minor version sent by userspace inFUSE_INIT.
I worry about that.
I'd rather have this enabled with a capability flag negotiated in INIT.
Quoted 91 lines
Info why this patch might be useful:
https://github.com/libfuse/libfuse/issues/122Signed-off-by Szymon Lukasz <[email protected]>--- fs/fuse/control.c | 2 +- fs/fuse/dev.c | 13 ++++++++----- fs/fuse/fuse_i.h | 8 +++++++- fs/fuse/inode.c | 4 ++-- include/uapi/linux/fuse.h | 5 ++++- 5 files changed, 22 insertions(+), 10 deletions(-)fs/fuse/control.c +1
-1@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, {struct fuse_conn *fc =fuse_ctl_file_conn_get (file);if (fc) { -fuse_abort_conn (fc); +fuse_abort_conn (fc,1 );fuse_conn_put (fc); }return count;fs/fuse/dev.c +8
-5@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,if (err) goto err_unlock; - err = -ENODEV ; -if (!fiq->connected) +if (!fiq->connected) { + err = fiq->aborted ? -ECONNABORTED : -ENODEV ; goto err_unlock; + }if (!list_empty (&fiq->interrupts)) { req = list_entry(fiq->interrupts.next, struct fuse_req,@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,spin_lock (&fpq->lock);clear_bit (FR_LOCKED , &req->flags);if (!fpq->connected) { - err = -ENODEV ; + err = fpq->aborted ? -ECONNABORTED : -ENODEV ; goto out_end; }if (err) {@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)* is OK, the request will in that case be removed from the list before we touch * it. */ -void fuse_abort_conn (struct fuse_conn *fc) +void fuse_abort_conn (struct fuse_conn *fc,int is_abort) {struct fuse_iqueue *fiq = &fc->iq;@@ -2095,6 +2096,7 @@ void fuse_abort_conn(struct fuse_conn *fc)spin_lock (&fpq->lock); fpq->connected =0 ; + fpq->aborted = is_abort;list_for_each_entry_safe (req, next, &fpq->io, list) { req->out.h.error = -ECONNABORTED ;spin_lock (&req->waitq.lock);@@ -2113,6 +2115,7 @@ void fuse_abort_conn(struct fuse_conn *fc)spin_lock (&fiq->waitq.lock); fiq->connected =0 ; + fiq->aborted = is_abort;list_splice_init (&fiq->pending, &to_end2);list_for_each_entry (req, &to_end2, list)clear_bit (FR_PENDING , &req->flags);@@ -2151,7 +2154,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)/* Are we the last open device? */ if (atomic_dec_and_test (&fc->dev_count)) {WARN_ON (fc->iq.fasync !=NULL ); -fuse_abort_conn (fc); +fuse_abort_conn (fc,0 ); }fuse_dev_free (fud); }fs/fuse/fuse_i.h +0
-0
fs/fuse/fuse_i.h struct fuse_iqueue { · line 392
Quoted 6 lines
fs/fuse/fuse_i.h +3
-0@@ -387,6 +387,9 @@ struct fuse_iqueue {/** Connection established */ unsigned connected; +/** Connection aborted via sysfs */ +int aborted; +
Does it need to be a per-queue granularity? Isn't a single bool infuse_conn sufficient?
Thanks,
Miklos
Quoted 70 lines
fs/fuse/fuse_i.h +4
-1/** Readers of the connection are waiting on this */ wait_queue_head_t waitq;@@ -414,6 +417,9 @@ struct fuse_pqueue {/** Connection established */ unsigned connected; +/** Connection aborted via sysfs */ +int aborted; +/** Lock protecting accessess to members of this structure */ spinlock_t lock;@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req);/* Abort all requests */ -void fuse_abort_conn (struct fuse_conn *fc); +void fuse_abort_conn (struct fuse_conn *fc,int is_abort);/** * Invalidate inode attributes fs/fuse/inode.c +2
-2@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)static void fuse_umount_begin (struct super_block *sb) { -fuse_abort_conn (get_fuse_conn_super (sb)); +fuse_abort_conn (get_fuse_conn_super (sb),0 ); }static void fuse_send_destroy (struct fuse_conn *fc)@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)fuse_send_destroy (fc); -fuse_abort_conn (fc); +fuse_abort_conn (fc,0 );mutex_lock (&fuse_mutex);list_del (&fc->entry);fuse_ctl_remove_conn (fc);include/uapi/linux/fuse.h +4
-2@@ -112,6 +112,9 @@* 7.26 * - add FUSE_HANDLE_KILLPRIV * - add FUSE_POSIX_ACL +* +* 7.27 +* - reading from /dev/fuse after sysfs abort returns -ECONNABORTED */ #ifndef _LINUX_FUSE_H@@ -147,7 +150,7 @@#define FUSE_KERNEL_VERSION 7/** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 26 +#define FUSE_KERNEL_MINOR_VERSION 27/** The node ID of the root inode */ #define FUSE_ROOT_ID 1 --2.15.0
PATCH v3 1/1 fuse: return -ECONNABORTED on /dev/fuse read after abort
Adds a new capability flag FUSE_ABORT_ERROR. If set and the connection is gone because of sysfs abort, reading from the device will return -ECONNABORTED.
--- fs/fuse/control.c | 2 +- fs/fuse/dev.c | 12 +++++++----- fs/fuse/fuse_i.h | 8 +++++++- fs/fuse/inode.c | 9 ++++++--- include/uapi/linux/fuse.h | 7 ++++++- 5 files changed, 27 insertions(+), 11 deletions(-)
fs/fuse/control.c +1 -1
@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, {struct fuse_conn *fc =fuse_ctl_file_conn_get (file);if (fc) { -fuse_abort_conn (fc); +fuse_abort_conn (fc, true);fuse_conn_put (fc); }return count;
fs/fuse/dev.c +7 -5
@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,if (err) goto err_unlock; - err = -ENODEV ; -if (!fiq->connected) +if (!fiq->connected) { + err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV ; goto err_unlock; + }if (!list_empty (&fiq->interrupts)) { req = list_entry(fiq->interrupts.next, struct fuse_req,
@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,spin_lock (&fpq->lock);clear_bit (FR_LOCKED , &req->flags);if (!fpq->connected) { - err = -ENODEV ; + err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV ; goto out_end; }if (err) {
@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)* is OK, the request will in that case be removed from the list before we touch * it. */ -void fuse_abort_conn (struct fuse_conn *fc) +void fuse_abort_conn (struct fuse_conn *fc,bool is_abort) {struct fuse_iqueue *fiq = &fc->iq;
@@ -2089,6 +2090,7 @@ void fuse_abort_conn(struct fuse_conn *fc) fc->connected =0 ; fc->blocked =0 ; + fc->aborted = is_abort;fuse_set_initialized (fc);list_for_each_entry (fud, &fc->devices, entry) {struct fuse_pqueue *fpq = &fud->pq;
@@ -2151,7 +2153,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)/* Are we the last open device? */ if (atomic_dec_and_test (&fc->dev_count)) {WARN_ON (fc->iq.fasync !=NULL ); -fuse_abort_conn (fc); +fuse_abort_conn (fc, false); }fuse_dev_free (fud); }
fs/fuse/fuse_i.h +7 -1
@@ -515,6 +515,9 @@ struct fuse_conn {abort and device release */ unsigned connected; +/** Connection aborted via sysfs */ +bool aborted; +/** Connection failed (version mismatch). Cannot race with setting other bitfields since it is only set once in INIT reply, before any other request, and never cleared */
@@ -526,6 +529,9 @@ struct fuse_conn {/** Do readpages asynchronously? Only set in INIT */ unsigned async_read:1; +/** Return an unique read error after abort. Only set in INIT */ + unsigned abort_err:1; +/** Do not send separate SETATTR request before open(O_TRUNC) */ unsigned atomic_o_trunc:1;
@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req);/* Abort all requests */ -void fuse_abort_conn (struct fuse_conn *fc); +void fuse_abort_conn (struct fuse_conn *fc,bool is_abort);/** * Invalidate inode attributes
fs/fuse/inode.c +6 -3
@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)static void fuse_umount_begin (struct super_block *sb) { -fuse_abort_conn (get_fuse_conn_super (sb)); +fuse_abort_conn (get_fuse_conn_super (sb), false); }static void fuse_send_destroy (struct fuse_conn *fc)
@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)fuse_send_destroy (fc); -fuse_abort_conn (fc); +fuse_abort_conn (fc, false);mutex_lock (&fuse_mutex);list_del (&fc->entry);fuse_ctl_remove_conn (fc);
@@ -918,6 +918,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->posix_acl =1 ; fc->sb->s_xattr = fuse_acl_xattr_handlers; } +if (arg->flags &FUSE_ABORT_ERROR ) + fc->abort_err =1 ; }else { ra_pages = fc->max_read /PAGE_SIZE ; fc->no_lock =1 ;
@@ -948,7 +950,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)FUSE_FLOCK_LOCKS |FUSE_HAS_IOCTL_DIR |FUSE_AUTO_INVAL_DATA |FUSE_DO_READDIRPLUS |FUSE_READDIRPLUS_AUTO |FUSE_ASYNC_DIO |FUSE_WRITEBACK_CACHE |FUSE_NO_OPEN_SUPPORT | -FUSE_PARALLEL_DIROPS |FUSE_HANDLE_KILLPRIV |FUSE_POSIX_ACL ; +FUSE_PARALLEL_DIROPS |FUSE_HANDLE_KILLPRIV |FUSE_POSIX_ACL | +FUSE_ABORT_ERROR ; req->in.h.opcode =FUSE_INIT ; req->in.numargs =1 ; req->in.args[0 ].size =sizeof (*arg);
include/uapi/linux/fuse.h +6 -1
@@ -112,6 +112,9 @@* 7.26 * - add FUSE_HANDLE_KILLPRIV * - add FUSE_POSIX_ACL +* +* 7.27 +* - add FUSE_ABORT_ERROR */ #ifndef _LINUX_FUSE_H
@@ -147,7 +150,7 @@#define FUSE_KERNEL_VERSION 7/** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 26 +#define FUSE_KERNEL_MINOR_VERSION 27/** The node ID of the root inode */ #define FUSE_ROOT_ID 1
@@ -244,6 +247,7 @@ struct fuse_file_lock {* FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc * FUSE_POSIX_ACL: filesystem supports posix acls +* FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED */ #define FUSE_ASYNC_READ (1 << 0)#define FUSE_POSIX_LOCKS (1 << 1)
@@ -266,6 +270,7 @@ struct fuse_file_lock {#define FUSE_PARALLEL_DIROPS (1 << 18)#define FUSE_HANDLE_KILLPRIV (1 << 19)#define FUSE_POSIX_ACL (1 << 20) +#define FUSE_ABORT_ERROR (1 << 21)/** * CUSE INIT request/reply flags
Signature · 1 line
2.15.0
kbuild test robot
build botThank you for the patch! Yet something to improve:
Hi Szymon,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on fuse/for-next]
[also build test ERROR on v4.14-rc8 next-20171109]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Szymon-Lukasz/fuse-return-ECONNABORTED-on-dev-fuse-read-after-abort/20171110-013308 base: https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next config: blackfin-allyesconfig (attached as .config) compiler: bfin-uclinux-gcc (GCC) 6.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=blackfin
All errors (new ones prefixed by >>):
fs//fuse/cuse.c: In function 'cuse_process_init_reply':
>> fs//fuse/cuse.c:409:2: error: too few arguments to function 'fuse_abort_conn'
fuse_abort_conn(fc);
^~~~~~~~~~~~~~~
In file included from fs//fuse/cuse.c:52:0:
fs//fuse/fuse_i.h:860:6: note: declared here
void fuse_abort_conn(struct fuse_conn *fc, bool is_abort);
^~~~~~~~~~~~~~~
fs//fuse/cuse.c: In function 'cuse_class_abort_store':
fs//fuse/cuse.c:584:2: error: too few arguments to function 'fuse_abort_conn'
fuse_abort_conn(&cc->fc);
^~~~~~~~~~~~~~~
In file included from fs//fuse/cuse.c:52:0:
fs//fuse/fuse_i.h:860:6: note: declared here
void fuse_abort_conn(struct fuse_conn *fc, bool is_abort);
^~~~~~~~~~~~~~~vim +/fuse_abort_conn +409 fs//fuse/cuse.c
151060ac1 Tejun Heo 2009-04-14 299
151060ac1 Tejun Heo 2009-04-14 300 /**
151060ac1 Tejun Heo 2009-04-14 301 * cuse_process_init_reply - finish initializing CUSE channel
151060ac1 Tejun Heo 2009-04-14 302 *
151060ac1 Tejun Heo 2009-04-14 303 * This function creates the character device and sets up all the
151060ac1 Tejun Heo 2009-04-14 304 * required data structures for it. Please read the comment at the
151060ac1 Tejun Heo 2009-04-14 305 * top of this file for high level overview.
151060ac1 Tejun Heo 2009-04-14 306 */
151060ac1 Tejun Heo 2009-04-14 307 static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
151060ac1 Tejun Heo 2009-04-14 308 {
30783587b David Herrmann 2012-11-17 309 struct cuse_conn *cc = fc_to_cc(fc), *pos;
07d5f69b4 Miklos Szeredi 2011-03-21 310 struct cuse_init_out *arg = req->out.args[0].value;
151060ac1 Tejun Heo 2009-04-14 311 struct page *page = req->pages[0];
151060ac1 Tejun Heo 2009-04-14 312 struct cuse_devinfo devinfo = { };
151060ac1 Tejun Heo 2009-04-14 313 struct device *dev;
151060ac1 Tejun Heo 2009-04-14 314 struct cdev *cdev;
151060ac1 Tejun Heo 2009-04-14 315 dev_t devt;
30783587b David Herrmann 2012-11-17 316 int rc, i;
151060ac1 Tejun Heo 2009-04-14 317
151060ac1 Tejun Heo 2009-04-14 318 if (req->out.h.error ||
151060ac1 Tejun Heo 2009-04-14 319 arg->major != FUSE_KERNEL_VERSION || arg->minor < 11) {
151060ac1 Tejun Heo 2009-04-14 320 goto err;
151060ac1 Tejun Heo 2009-04-14 321 }
151060ac1 Tejun Heo 2009-04-14 322
151060ac1 Tejun Heo 2009-04-14 323 fc->minor = arg->minor;
151060ac1 Tejun Heo 2009-04-14 324 fc->max_read = max_t(unsigned, arg->max_read, 4096);
151060ac1 Tejun Heo 2009-04-14 325 fc->max_write = max_t(unsigned, arg->max_write, 4096);
151060ac1 Tejun Heo 2009-04-14 326
151060ac1 Tejun Heo 2009-04-14 327 /* parse init reply */
151060ac1 Tejun Heo 2009-04-14 328 cc->unrestricted_ioctl = arg->flags & CUSE_UNRESTRICTED_IOCTL;
151060ac1 Tejun Heo 2009-04-14 329
151060ac1 Tejun Heo 2009-04-14 330 rc = cuse_parse_devinfo(page_address(page), req->out.args[1].size,
151060ac1 Tejun Heo 2009-04-14 331 &devinfo);
151060ac1 Tejun Heo 2009-04-14 332 if (rc)
151060ac1 Tejun Heo 2009-04-14 333 goto err;
151060ac1 Tejun Heo 2009-04-14 334
151060ac1 Tejun Heo 2009-04-14 335 /* determine and reserve devt */
151060ac1 Tejun Heo 2009-04-14 336 devt = MKDEV(arg->dev_major, arg->dev_minor);
151060ac1 Tejun Heo 2009-04-14 337 if (!MAJOR(devt))
151060ac1 Tejun Heo 2009-04-14 338 rc = alloc_chrdev_region(&devt, MINOR(devt), 1, devinfo.name);
151060ac1 Tejun Heo 2009-04-14 339 else
151060ac1 Tejun Heo 2009-04-14 340 rc = register_chrdev_region(devt, 1, devinfo.name);
151060ac1 Tejun Heo 2009-04-14 341 if (rc) {
151060ac1 Tejun Heo 2009-04-14 342 printk(KERN_ERR "CUSE: failed to register chrdev region\n");
151060ac1 Tejun Heo 2009-04-14 343 goto err;
151060ac1 Tejun Heo 2009-04-14 344 }
151060ac1 Tejun Heo 2009-04-14 345
151060ac1 Tejun Heo 2009-04-14 346 /* devt determined, create device */
151060ac1 Tejun Heo 2009-04-14 347 rc = -ENOMEM;
151060ac1 Tejun Heo 2009-04-14 348 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
151060ac1 Tejun Heo 2009-04-14 349 if (!dev)
151060ac1 Tejun Heo 2009-04-14 350 goto err_region;
151060ac1 Tejun Heo 2009-04-14 351
151060ac1 Tejun Heo 2009-04-14 352 device_initialize(dev);
151060ac1 Tejun Heo 2009-04-14 353 dev_set_uevent_suppress(dev, 1);
151060ac1 Tejun Heo 2009-04-14 354 dev->class = cuse_class;
151060ac1 Tejun Heo 2009-04-14 355 dev->devt = devt;
151060ac1 Tejun Heo 2009-04-14 356 dev->release = cuse_gendev_release;
151060ac1 Tejun Heo 2009-04-14 357 dev_set_drvdata(dev, cc);
151060ac1 Tejun Heo 2009-04-14 358 dev_set_name(dev, "%s", devinfo.name);
151060ac1 Tejun Heo 2009-04-14 359
30783587b David Herrmann 2012-11-17 360 mutex_lock(&cuse_lock);
30783587b David Herrmann 2012-11-17 361
30783587b David Herrmann 2012-11-17 362 /* make sure the device-name is unique */
30783587b David Herrmann 2012-11-17 363 for (i = 0; i < CUSE_CONNTBL_LEN; ++i) {
30783587b David Herrmann 2012-11-17 364 list_for_each_entry(pos, &cuse_conntbl[i], list)
30783587b David Herrmann 2012-11-17 365 if (!strcmp(dev_name(pos->dev), dev_name(dev)))
30783587b David Herrmann 2012-11-17 366 goto err_unlock;
30783587b David Herrmann 2012-11-17 367 }
30783587b David Herrmann 2012-11-17 368
151060ac1 Tejun Heo 2009-04-14 369 rc = device_add(dev);
151060ac1 Tejun Heo 2009-04-14 370 if (rc)
30783587b David Herrmann 2012-11-17 371 goto err_unlock;
151060ac1 Tejun Heo 2009-04-14 372
151060ac1 Tejun Heo 2009-04-14 373 /* register cdev */
151060ac1 Tejun Heo 2009-04-14 374 rc = -ENOMEM;
151060ac1 Tejun Heo 2009-04-14 375 cdev = cdev_alloc();
151060ac1 Tejun Heo 2009-04-14 376 if (!cdev)
30783587b David Herrmann 2012-11-17 377 goto err_unlock;
151060ac1 Tejun Heo 2009-04-14 378
151060ac1 Tejun Heo 2009-04-14 379 cdev->owner = THIS_MODULE;
151060ac1 Tejun Heo 2009-04-14 380 cdev->ops = &cuse_frontend_fops;
151060ac1 Tejun Heo 2009-04-14 381
151060ac1 Tejun Heo 2009-04-14 382 rc = cdev_add(cdev, devt, 1);
151060ac1 Tejun Heo 2009-04-14 383 if (rc)
151060ac1 Tejun Heo 2009-04-14 384 goto err_cdev;
151060ac1 Tejun Heo 2009-04-14 385
151060ac1 Tejun Heo 2009-04-14 386 cc->dev = dev;
151060ac1 Tejun Heo 2009-04-14 387 cc->cdev = cdev;
151060ac1 Tejun Heo 2009-04-14 388
151060ac1 Tejun Heo 2009-04-14 389 /* make the device available */
151060ac1 Tejun Heo 2009-04-14 390 list_add(&cc->list, cuse_conntbl_head(devt));
8ce03fd76 David Herrmann 2012-11-17 391 mutex_unlock(&cuse_lock);
151060ac1 Tejun Heo 2009-04-14 392
151060ac1 Tejun Heo 2009-04-14 393 /* announce device availability */
151060ac1 Tejun Heo 2009-04-14 394 dev_set_uevent_suppress(dev, 0);
151060ac1 Tejun Heo 2009-04-14 395 kobject_uevent(&dev->kobj, KOBJ_ADD);
151060ac1 Tejun Heo 2009-04-14 396 out:
07d5f69b4 Miklos Szeredi 2011-03-21 397 kfree(arg);
151060ac1 Tejun Heo 2009-04-14 398 __free_page(page);
151060ac1 Tejun Heo 2009-04-14 399 return;
151060ac1 Tejun Heo 2009-04-14 400
151060ac1 Tejun Heo 2009-04-14 401 err_cdev:
151060ac1 Tejun Heo 2009-04-14 402 cdev_del(cdev);
30783587b David Herrmann 2012-11-17 403 err_unlock:
30783587b David Herrmann 2012-11-17 404 mutex_unlock(&cuse_lock);
151060ac1 Tejun Heo 2009-04-14 405 put_device(dev);
151060ac1 Tejun Heo 2009-04-14 406 err_region:
151060ac1 Tejun Heo 2009-04-14 407 unregister_chrdev_region(devt, 1);
151060ac1 Tejun Heo 2009-04-14 408 err:
580640ba5 Miklos Szeredi 2014-12-12 @409 fuse_abort_conn(fc);
151060ac1 Tejun Heo 2009-04-14 410 goto out;
151060ac1 Tejun Heo 2009-04-14 411 }151060ac1 Tejun Heo 2009-04-14 412
:::::: The code at line 409 was first introduced by commit
:::::: 580640ba5d331eb5631a5de46941c98f5ed90886 fuse: flush requests on umount
:::::: TO: Miklos Szeredi <[email protected]> :::::: CC: Miklos Szeredi <[email protected]>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
kbuild test robot
build botThank you for the patch! Perhaps something to improve:
Hi Szymon,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on fuse/for-next]
[also build test WARNING on v4.14-rc8 next-20171109]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Szymon-Lukasz/fuse-return-ECONNABORTED-on-dev-fuse-read-after-abort/20171110-013308 base: https://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next reproduce: # apt-get install sparse make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
vim +409 fs/fuse/cuse.c
151060ac1 Tejun Heo 2009-04-14 299
151060ac1 Tejun Heo 2009-04-14 300 /**
151060ac1 Tejun Heo 2009-04-14 301 * cuse_process_init_reply - finish initializing CUSE channel
151060ac1 Tejun Heo 2009-04-14 302 *
151060ac1 Tejun Heo 2009-04-14 303 * This function creates the character device and sets up all the
151060ac1 Tejun Heo 2009-04-14 304 * required data structures for it. Please read the comment at the
151060ac1 Tejun Heo 2009-04-14 305 * top of this file for high level overview.
151060ac1 Tejun Heo 2009-04-14 306 */
151060ac1 Tejun Heo 2009-04-14 307 static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
151060ac1 Tejun Heo 2009-04-14 308 {
30783587b David Herrmann 2012-11-17 309 struct cuse_conn *cc = fc_to_cc(fc), *pos;
07d5f69b4 Miklos Szeredi 2011-03-21 310 struct cuse_init_out *arg = req->out.args[0].value;
151060ac1 Tejun Heo 2009-04-14 311 struct page *page = req->pages[0];
151060ac1 Tejun Heo 2009-04-14 312 struct cuse_devinfo devinfo = { };
151060ac1 Tejun Heo 2009-04-14 313 struct device *dev;
151060ac1 Tejun Heo 2009-04-14 314 struct cdev *cdev;
151060ac1 Tejun Heo 2009-04-14 315 dev_t devt;
30783587b David Herrmann 2012-11-17 316 int rc, i;
151060ac1 Tejun Heo 2009-04-14 317
151060ac1 Tejun Heo 2009-04-14 318 if (req->out.h.error ||
151060ac1 Tejun Heo 2009-04-14 319 arg->major != FUSE_KERNEL_VERSION || arg->minor < 11) {
151060ac1 Tejun Heo 2009-04-14 320 goto err;
151060ac1 Tejun Heo 2009-04-14 321 }
151060ac1 Tejun Heo 2009-04-14 322
151060ac1 Tejun Heo 2009-04-14 323 fc->minor = arg->minor;
151060ac1 Tejun Heo 2009-04-14 324 fc->max_read = max_t(unsigned, arg->max_read, 4096);
151060ac1 Tejun Heo 2009-04-14 325 fc->max_write = max_t(unsigned, arg->max_write, 4096);
151060ac1 Tejun Heo 2009-04-14 326
151060ac1 Tejun Heo 2009-04-14 327 /* parse init reply */
151060ac1 Tejun Heo 2009-04-14 328 cc->unrestricted_ioctl = arg->flags & CUSE_UNRESTRICTED_IOCTL;
151060ac1 Tejun Heo 2009-04-14 329
151060ac1 Tejun Heo 2009-04-14 330 rc = cuse_parse_devinfo(page_address(page), req->out.args[1].size,
151060ac1 Tejun Heo 2009-04-14 331 &devinfo);
151060ac1 Tejun Heo 2009-04-14 332 if (rc)
151060ac1 Tejun Heo 2009-04-14 333 goto err;
151060ac1 Tejun Heo 2009-04-14 334
151060ac1 Tejun Heo 2009-04-14 335 /* determine and reserve devt */
151060ac1 Tejun Heo 2009-04-14 336 devt = MKDEV(arg->dev_major, arg->dev_minor);
151060ac1 Tejun Heo 2009-04-14 337 if (!MAJOR(devt))
151060ac1 Tejun Heo 2009-04-14 338 rc = alloc_chrdev_region(&devt, MINOR(devt), 1, devinfo.name);
151060ac1 Tejun Heo 2009-04-14 339 else
151060ac1 Tejun Heo 2009-04-14 340 rc = register_chrdev_region(devt, 1, devinfo.name);
151060ac1 Tejun Heo 2009-04-14 341 if (rc) {
151060ac1 Tejun Heo 2009-04-14 342 printk(KERN_ERR "CUSE: failed to register chrdev region\n");
151060ac1 Tejun Heo 2009-04-14 343 goto err;
151060ac1 Tejun Heo 2009-04-14 344 }
151060ac1 Tejun Heo 2009-04-14 345
151060ac1 Tejun Heo 2009-04-14 346 /* devt determined, create device */
151060ac1 Tejun Heo 2009-04-14 347 rc = -ENOMEM;
151060ac1 Tejun Heo 2009-04-14 348 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
151060ac1 Tejun Heo 2009-04-14 349 if (!dev)
151060ac1 Tejun Heo 2009-04-14 350 goto err_region;
151060ac1 Tejun Heo 2009-04-14 351
151060ac1 Tejun Heo 2009-04-14 352 device_initialize(dev);
151060ac1 Tejun Heo 2009-04-14 353 dev_set_uevent_suppress(dev, 1);
151060ac1 Tejun Heo 2009-04-14 354 dev->class = cuse_class;
151060ac1 Tejun Heo 2009-04-14 355 dev->devt = devt;
151060ac1 Tejun Heo 2009-04-14 356 dev->release = cuse_gendev_release;
151060ac1 Tejun Heo 2009-04-14 357 dev_set_drvdata(dev, cc);
151060ac1 Tejun Heo 2009-04-14 358 dev_set_name(dev, "%s", devinfo.name);
151060ac1 Tejun Heo 2009-04-14 359
30783587b David Herrmann 2012-11-17 360 mutex_lock(&cuse_lock);
30783587b David Herrmann 2012-11-17 361
30783587b David Herrmann 2012-11-17 362 /* make sure the device-name is unique */
30783587b David Herrmann 2012-11-17 363 for (i = 0; i < CUSE_CONNTBL_LEN; ++i) {
30783587b David Herrmann 2012-11-17 364 list_for_each_entry(pos, &cuse_conntbl[i], list)
30783587b David Herrmann 2012-11-17 365 if (!strcmp(dev_name(pos->dev), dev_name(dev)))
30783587b David Herrmann 2012-11-17 366 goto err_unlock;
30783587b David Herrmann 2012-11-17 367 }
30783587b David Herrmann 2012-11-17 368
151060ac1 Tejun Heo 2009-04-14 369 rc = device_add(dev);
151060ac1 Tejun Heo 2009-04-14 370 if (rc)
30783587b David Herrmann 2012-11-17 371 goto err_unlock;
151060ac1 Tejun Heo 2009-04-14 372
151060ac1 Tejun Heo 2009-04-14 373 /* register cdev */
151060ac1 Tejun Heo 2009-04-14 374 rc = -ENOMEM;
151060ac1 Tejun Heo 2009-04-14 375 cdev = cdev_alloc();
151060ac1 Tejun Heo 2009-04-14 376 if (!cdev)
30783587b David Herrmann 2012-11-17 377 goto err_unlock;
151060ac1 Tejun Heo 2009-04-14 378
151060ac1 Tejun Heo 2009-04-14 379 cdev->owner = THIS_MODULE;
151060ac1 Tejun Heo 2009-04-14 380 cdev->ops = &cuse_frontend_fops;
151060ac1 Tejun Heo 2009-04-14 381
151060ac1 Tejun Heo 2009-04-14 382 rc = cdev_add(cdev, devt, 1);
151060ac1 Tejun Heo 2009-04-14 383 if (rc)
151060ac1 Tejun Heo 2009-04-14 384 goto err_cdev;
151060ac1 Tejun Heo 2009-04-14 385
151060ac1 Tejun Heo 2009-04-14 386 cc->dev = dev;
151060ac1 Tejun Heo 2009-04-14 387 cc->cdev = cdev;
151060ac1 Tejun Heo 2009-04-14 388
151060ac1 Tejun Heo 2009-04-14 389 /* make the device available */
151060ac1 Tejun Heo 2009-04-14 390 list_add(&cc->list, cuse_conntbl_head(devt));
8ce03fd76 David Herrmann 2012-11-17 391 mutex_unlock(&cuse_lock);
151060ac1 Tejun Heo 2009-04-14 392
151060ac1 Tejun Heo 2009-04-14 393 /* announce device availability */
151060ac1 Tejun Heo 2009-04-14 394 dev_set_uevent_suppress(dev, 0);
151060ac1 Tejun Heo 2009-04-14 395 kobject_uevent(&dev->kobj, KOBJ_ADD);
151060ac1 Tejun Heo 2009-04-14 396 out:
07d5f69b4 Miklos Szeredi 2011-03-21 397 kfree(arg);
151060ac1 Tejun Heo 2009-04-14 398 __free_page(page);
151060ac1 Tejun Heo 2009-04-14 399 return;
151060ac1 Tejun Heo 2009-04-14 400
151060ac1 Tejun Heo 2009-04-14 401 err_cdev:
151060ac1 Tejun Heo 2009-04-14 402 cdev_del(cdev);
30783587b David Herrmann 2012-11-17 403 err_unlock:
30783587b David Herrmann 2012-11-17 404 mutex_unlock(&cuse_lock);
151060ac1 Tejun Heo 2009-04-14 405 put_device(dev);
151060ac1 Tejun Heo 2009-04-14 406 err_region:
151060ac1 Tejun Heo 2009-04-14 407 unregister_chrdev_region(devt, 1);
151060ac1 Tejun Heo 2009-04-14 408 err:
580640ba5 Miklos Szeredi 2014-12-12 @409 fuse_abort_conn(fc);
151060ac1 Tejun Heo 2009-04-14 410 goto out;
151060ac1 Tejun Heo 2009-04-14 411 }151060ac1 Tejun Heo 2009-04-14 412
:::::: The code at line 409 was first introduced by commit
:::::: 580640ba5d331eb5631a5de46941c98f5ed90886 fuse: flush requests on umount
:::::: TO: Miklos Szeredi <[email protected]>
:::::: CC: Miklos Szeredi <[email protected]>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
PATCH v4 1/1 fuse: return -ECONNABORTED on /dev/fuse read after abort
In reply to Szymon LukaszAdds a new capability flag FUSE_ABORT_ERROR. If set and the connection is gone because of sysfs abort, reading from the device will return -ECONNABORTED.
--- fs/fuse/control.c | 2 +- fs/fuse/cuse.c | 4 ++-- fs/fuse/dev.c | 12 +++++++----- fs/fuse/fuse_i.h | 8 +++++++- fs/fuse/inode.c | 9 ++++++--- include/uapi/linux/fuse.h | 7 ++++++- 6 files changed, 29 insertions(+), 13 deletions(-)
fs/fuse/control.c +1 -1
@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, {struct fuse_conn *fc =fuse_ctl_file_conn_get (file);if (fc) { -fuse_abort_conn (fc); +fuse_abort_conn (fc, true);fuse_conn_put (fc); }return count;
fs/fuse/cuse.c +2 -2
@@ -406,7 +406,7 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req) err_region:unregister_chrdev_region (devt,1 ); err: -fuse_abort_conn (fc); +fuse_abort_conn (fc, false); goto out; }
@@ -581,7 +581,7 @@ static ssize_t cuse_class_abort_store(struct device *dev, {struct cuse_conn *cc =dev_get_drvdata (dev); -fuse_abort_conn (&cc->fc); +fuse_abort_conn (&cc->fc, false);return count; } static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);
fs/fuse/dev.c +7 -5
@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,if (err) goto err_unlock; - err = -ENODEV ; -if (!fiq->connected) +if (!fiq->connected) { + err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV ; goto err_unlock; + }if (!list_empty (&fiq->interrupts)) { req = list_entry(fiq->interrupts.next, struct fuse_req,
@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,spin_lock (&fpq->lock);clear_bit (FR_LOCKED , &req->flags);if (!fpq->connected) { - err = -ENODEV ; + err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV ; goto out_end; }if (err) {
@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)* is OK, the request will in that case be removed from the list before we touch * it. */ -void fuse_abort_conn (struct fuse_conn *fc) +void fuse_abort_conn (struct fuse_conn *fc,bool is_abort) {struct fuse_iqueue *fiq = &fc->iq;
@@ -2089,6 +2090,7 @@ void fuse_abort_conn(struct fuse_conn *fc) fc->connected =0 ; fc->blocked =0 ; + fc->aborted = is_abort;fuse_set_initialized (fc);list_for_each_entry (fud, &fc->devices, entry) {struct fuse_pqueue *fpq = &fud->pq;
@@ -2151,7 +2153,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)/* Are we the last open device? */ if (atomic_dec_and_test (&fc->dev_count)) {WARN_ON (fc->iq.fasync !=NULL ); -fuse_abort_conn (fc); +fuse_abort_conn (fc, false); }fuse_dev_free (fud); }
fs/fuse/fuse_i.h +7 -1
@@ -515,6 +515,9 @@ struct fuse_conn {abort and device release */ unsigned connected; +/** Connection aborted via sysfs */ +bool aborted; +/** Connection failed (version mismatch). Cannot race with setting other bitfields since it is only set once in INIT reply, before any other request, and never cleared */
@@ -526,6 +529,9 @@ struct fuse_conn {/** Do readpages asynchronously? Only set in INIT */ unsigned async_read:1; +/** Return an unique read error after abort. Only set in INIT */ + unsigned abort_err:1; +/** Do not send separate SETATTR request before open(O_TRUNC) */ unsigned atomic_o_trunc:1;
@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req);/* Abort all requests */ -void fuse_abort_conn (struct fuse_conn *fc); +void fuse_abort_conn (struct fuse_conn *fc,bool is_abort);/** * Invalidate inode attributes
fs/fuse/inode.c +6 -3
@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)static void fuse_umount_begin (struct super_block *sb) { -fuse_abort_conn (get_fuse_conn_super (sb)); +fuse_abort_conn (get_fuse_conn_super (sb), false); }static void fuse_send_destroy (struct fuse_conn *fc)
@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)fuse_send_destroy (fc); -fuse_abort_conn (fc); +fuse_abort_conn (fc, false);mutex_lock (&fuse_mutex);list_del (&fc->entry);fuse_ctl_remove_conn (fc);
@@ -918,6 +918,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->posix_acl =1 ; fc->sb->s_xattr = fuse_acl_xattr_handlers; } +if (arg->flags &FUSE_ABORT_ERROR ) + fc->abort_err =1 ; }else { ra_pages = fc->max_read /PAGE_SIZE ; fc->no_lock =1 ;
@@ -948,7 +950,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)FUSE_FLOCK_LOCKS |FUSE_HAS_IOCTL_DIR |FUSE_AUTO_INVAL_DATA |FUSE_DO_READDIRPLUS |FUSE_READDIRPLUS_AUTO |FUSE_ASYNC_DIO |FUSE_WRITEBACK_CACHE |FUSE_NO_OPEN_SUPPORT | -FUSE_PARALLEL_DIROPS |FUSE_HANDLE_KILLPRIV |FUSE_POSIX_ACL ; +FUSE_PARALLEL_DIROPS |FUSE_HANDLE_KILLPRIV |FUSE_POSIX_ACL | +FUSE_ABORT_ERROR ; req->in.h.opcode =FUSE_INIT ; req->in.numargs =1 ; req->in.args[0 ].size =sizeof (*arg);
include/uapi/linux/fuse.h +6 -1
@@ -112,6 +112,9 @@* 7.26 * - add FUSE_HANDLE_KILLPRIV * - add FUSE_POSIX_ACL +* +* 7.27 +* - add FUSE_ABORT_ERROR */ #ifndef _LINUX_FUSE_H
@@ -147,7 +150,7 @@#define FUSE_KERNEL_VERSION 7/** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 26 +#define FUSE_KERNEL_MINOR_VERSION 27/** The node ID of the root inode */ #define FUSE_ROOT_ID 1
@@ -244,6 +247,7 @@ struct fuse_file_lock {* FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc * FUSE_POSIX_ACL: filesystem supports posix acls +* FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED */ #define FUSE_ASYNC_READ (1 << 0)#define FUSE_POSIX_LOCKS (1 << 1)
@@ -266,6 +270,7 @@ struct fuse_file_lock {#define FUSE_PARALLEL_DIROPS (1 << 18)#define FUSE_HANDLE_KILLPRIV (1 << 19)#define FUSE_POSIX_ACL (1 << 20) +#define FUSE_ABORT_ERROR (1 << 21)/** * CUSE INIT request/reply flags
Signature · 1 line
2.15.0
A message that is not in the archive (sent off-list or not yet received): 20171109202335.19797-1-noh4hss-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
Bump
Quoted 232 lines · Szymon Lukasz
Adds a new capability flag
FUSE_ABORT_ERROR. If set and the connection is gone because of sysfs abort, reading from the device will return-ECONNABORTED.Signed-off-by Szymon Lukasz <[email protected]>--- fs/fuse/control.c | 2 +- fs/fuse/cuse.c | 4 ++-- fs/fuse/dev.c | 12 +++++++----- fs/fuse/fuse_i.h | 8 +++++++- fs/fuse/inode.c | 9 ++++++--- include/uapi/linux/fuse.h | 7 ++++++- 6 files changed, 29 insertions(+), 13 deletions(-)fs/fuse/control.c +1
-1@@ -35,7 +35,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, {struct fuse_conn *fc =fuse_ctl_file_conn_get (file);if (fc) { -fuse_abort_conn (fc); +fuse_abort_conn (fc, true);fuse_conn_put (fc); }return count;fs/fuse/cuse.c +2
-2@@ -406,7 +406,7 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req) err_region:unregister_chrdev_region (devt,1 ); err: -fuse_abort_conn (fc); +fuse_abort_conn (fc, false); goto out; }@@ -581,7 +581,7 @@ static ssize_t cuse_class_abort_store(struct device *dev, {struct cuse_conn *cc =dev_get_drvdata (dev); -fuse_abort_conn (&cc->fc); +fuse_abort_conn (&cc->fc, false);return count; }static
DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);fs/fuse/dev.c +4
-5@@ -1234,9 +1234,10 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, if (err) goto err_unlock; - err = -ENODEV ; -if (!fiq->connected) +if (!fiq->connected) { + err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV ; goto err_unlock; + }if (!list_empty (&fiq->interrupts)) { req = list_entry(fiq->interrupts.next, struct fuse_req,@@ -1287,7 +1288,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,spin_lock (&fpq->lock);clear_bit (FR_LOCKED , &req->flags);if (!fpq->connected) { - err = -ENODEV ; + err = (fc->aborted && fc->abort_err) ? -ECONNABORTED : -ENODEV ; goto out_end; }if (err) {@@ -2076,7 +2077,7 @@ static void end_polls(struct fuse_conn *fc)* is OK, the request will in that case be removed from the list before we touch
* it.
*/fs/fuse/dev.c +3
-2-void fuse_abort_conn (struct fuse_conn *fc) +void fuse_abort_conn (struct fuse_conn *fc,bool is_abort) {struct fuse_iqueue *fiq = &fc->iq;@@ -2089,6 +2090,7 @@ void fuse_abort_conn(struct fuse_conn *fc) fc->connected =0 ; fc->blocked =0 ; + fc->aborted = is_abort;fuse_set_initialized (fc);list_for_each_entry (fud, &fc->devices, entry) {struct fuse_pqueue *fpq = &fud->pq;@@ -2151,7 +2153,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)/* Are we the last open device? */ if (atomic_dec_and_test (&fc->dev_count)) {WARN_ON (fc->iq.fasync !=NULL ); -fuse_abort_conn (fc); +fuse_abort_conn (fc, false); }fuse_dev_free (fud);}fs/fuse/fuse_i.h +7
-1@@ -515,6 +515,9 @@ struct fuse_conn {abort and device release */ unsigned connected; +/** Connection aborted via sysfs */ +bool aborted; +/** Connection failed (version mismatch). Cannot race with setting other bitfields since it is only set once in INIT reply, before any other request, and never cleared */ @@ -526,6 +529,9 @@ struct fuse_conn {/** Do readpages asynchronously? Only set in INIT */ unsigned async_read:1; +/** Return an unique read error after abort. Only set in INIT */ + unsigned abort_err:1; +/** Do not send separate SETATTR request before open(O_TRUNC) */ unsigned atomic_o_trunc:1;@@ -851,7 +857,7 @@ void fuse_request_send_background_locked(structfuse_conn *fc, struct fuse_req *req);/* Abort all requests */ -void fuse_abort_conn (struct fuse_conn *fc); +void fuse_abort_conn (struct fuse_conn *fc,bool is_abort);/** * Invalidate inode attributes
fs/fuse/inode.c +4
-2@@ -371,7 +371,7 @@ void fuse_unlock_inode(struct inode *inode)static void fuse_umount_begin (struct super_block *sb) { -fuse_abort_conn (get_fuse_conn_super (sb)); +fuse_abort_conn (get_fuse_conn_super (sb), false); }static void fuse_send_destroy (struct fuse_conn *fc)@@ -393,7 +393,7 @@ static void fuse_put_super(struct super_block *sb)fuse_send_destroy (fc); -fuse_abort_conn (fc); +fuse_abort_conn (fc, false);mutex_lock (&fuse_mutex);list_del (&fc->entry);fuse_ctl_remove_conn (fc);@@ -918,6 +918,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->posix_acl = 1; fc->sb->s_xattr = fuse_acl_xattr_handlers; } +if (arg->flags &FUSE_ABORT_ERROR ) + fc->abort_err =1 ; }else { ra_pages = fc->max_read /PAGE_SIZE ;fc->no_lock = 1;fs/fuse/inode.c +0
-0@@ -948,7 +950,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) FUSE_FLOCK_LOCKS | FUSE_HAS_IOCTL_DIR |
FUSE_AUTO_INVAL_DATA|
FUSE_DO_READDIRPLUS|FUSE_READDIRPLUS_AUTO|FUSE_ASYNC_DIO|FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT | - FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV |
FUSE_POSIX_ACL;
+FUSE_PARALLEL_DIROPS|FUSE_HANDLE_KILLPRIV|FUSE_POSIX_ACL|fs/fuse/inode.c +1
-0+FUSE_ABORT_ERROR ; req->in.h.opcode =FUSE_INIT ; req->in.numargs =1 ; req->in.args[0 ].size =sizeof (*arg);include/uapi/linux/fuse.h +4
-1@@ -112,6 +112,9 @@* 7.26 * - add FUSE_HANDLE_KILLPRIV * - add FUSE_POSIX_ACL +* +* 7.27 +* - add FUSE_ABORT_ERROR */ #ifndef _LINUX_FUSE_H@@ -147,7 +150,7 @@#define FUSE_KERNEL_VERSION 7/** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 26 +#define FUSE_KERNEL_MINOR_VERSION 27/** The node ID of the root inode */ #define FUSE_ROOT_ID 1@@ -244,6 +247,7 @@ struct fuse_file_lock {* FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc
*FUSE_POSIX_ACL: filesystem supports posix acls
+ *FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED */
#defineFUSE_ASYNC_READ(1 << 0)
#defineFUSE_POSIX_LOCKS(1 << 1)include/uapi/linux/fuse.h +1
-1@@ -266,6 +270,7 @@ struct fuse_file_lock {#define FUSE_PARALLEL_DIROPS (1 << 18)#define FUSE_HANDLE_KILLPRIV (1 << 19)#define FUSE_POSIX_ACL (1 << 20) +#define FUSE_ABORT_ERROR (1 << 21)/** * CUSE INIT request/reply flags --
Quoted 3 lines
2.15.0
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot
Signature · 2 lines
fuse-devel mailing list To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
Bump
Miklos Szeredi
maintainerQuoted 3 lines · Szymon Lukasz
Adds a new capability flag
FUSE_ABORT_ERROR. If set and the connection is gone because of sysfs abort, reading from the device will return-ECONNABORTED.
Thanks, pushed to:
git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse.git for-next
Thanks,
Miklos