Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: fix truncate after open
fuse: fix hang of single threaded fuseblk filesystem

+56 -11
+5 -2
fs/fuse/dir.c
··· 1283 1283 if (err) 1284 1284 return err; 1285 1285 1286 - if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc) 1287 - return 0; 1286 + if (attr->ia_valid & ATTR_OPEN) { 1287 + if (fc->atomic_o_trunc) 1288 + return 0; 1289 + file = NULL; 1290 + } 1288 1291 1289 1292 if (attr->ia_valid & ATTR_SIZE) 1290 1293 is_truncate = true;
+46 -8
fs/fuse/file.c
··· 86 86 return ff; 87 87 } 88 88 89 - static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) 89 + static void fuse_release_async(struct work_struct *work) 90 90 { 91 - path_put(&req->misc.release.path); 91 + struct fuse_req *req; 92 + struct fuse_conn *fc; 93 + struct path path; 94 + 95 + req = container_of(work, struct fuse_req, misc.release.work); 96 + path = req->misc.release.path; 97 + fc = get_fuse_conn(path.dentry->d_inode); 98 + 99 + fuse_put_request(fc, req); 100 + path_put(&path); 92 101 } 93 102 94 - static void fuse_file_put(struct fuse_file *ff) 103 + static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) 104 + { 105 + if (fc->destroy_req) { 106 + /* 107 + * If this is a fuseblk mount, then it's possible that 108 + * releasing the path will result in releasing the 109 + * super block and sending the DESTROY request. If 110 + * the server is single threaded, this would hang. 111 + * For this reason do the path_put() in a separate 112 + * thread. 113 + */ 114 + atomic_inc(&req->count); 115 + INIT_WORK(&req->misc.release.work, fuse_release_async); 116 + schedule_work(&req->misc.release.work); 117 + } else { 118 + path_put(&req->misc.release.path); 119 + } 120 + } 121 + 122 + static void fuse_file_put(struct fuse_file *ff, bool sync) 95 123 { 96 124 if (atomic_dec_and_test(&ff->count)) { 97 125 struct fuse_req *req = ff->reserved_req; 98 126 99 - req->end = fuse_release_end; 100 - fuse_request_send_background(ff->fc, req); 127 + if (sync) { 128 + fuse_request_send(ff->fc, req); 129 + path_put(&req->misc.release.path); 130 + fuse_put_request(ff->fc, req); 131 + } else { 132 + req->end = fuse_release_end; 133 + fuse_request_send_background(ff->fc, req); 134 + } 101 135 kfree(ff); 102 136 } 103 137 } ··· 253 219 * Normally this will send the RELEASE request, however if 254 220 * some asynchronous READ or WRITE requests are outstanding, 255 221 * the sending will be delayed. 222 + * 223 + * Make the release synchronous if this is a fuseblk mount, 224 + * synchronous RELEASE is allowed (and desirable) in this case 225 + * because the server can be trusted not to screw up. 256 226 */ 257 - fuse_file_put(ff); 227 + fuse_file_put(ff, ff->fc->destroy_req != NULL); 258 228 } 259 229 260 230 static int fuse_open(struct inode *inode, struct file *file) ··· 596 558 page_cache_release(page); 597 559 } 598 560 if (req->ff) 599 - fuse_file_put(req->ff); 561 + fuse_file_put(req->ff, false); 600 562 } 601 563 602 564 static void fuse_send_readpages(struct fuse_req *req, struct file *file) ··· 1175 1137 static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req) 1176 1138 { 1177 1139 __free_page(req->pages[0]); 1178 - fuse_file_put(req->ff); 1140 + fuse_file_put(req->ff, false); 1179 1141 } 1180 1142 1181 1143 static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
+5 -1
fs/fuse/fuse_i.h
··· 21 21 #include <linux/rwsem.h> 22 22 #include <linux/rbtree.h> 23 23 #include <linux/poll.h> 24 + #include <linux/workqueue.h> 24 25 25 26 /** Max number of pages that can be used in a single read request */ 26 27 #define FUSE_MAX_PAGES_PER_REQ 32 ··· 263 262 /** Data for asynchronous requests */ 264 263 union { 265 264 struct { 266 - struct fuse_release_in in; 265 + union { 266 + struct fuse_release_in in; 267 + struct work_struct work; 268 + }; 267 269 struct path path; 268 270 } release; 269 271 struct fuse_init_in init_in;