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

[PATCH] FUSE: don't allow restarting of system calls

This patch removes ability to interrupt and restart operations while there
hasn't been any side-effect.

The reason: applications. There are some apps it seems that generate
signals at a fast rate. This means, that if the operation cannot make
enough progress between two signals, it will be restarted for ever. This
bug actually manifested itself with 'krusader' trying to open a file for
writing under sshfs. Thanks to Eduard Czimbalmos for the report.

The problem can be solved just by making open() uninterruptible, because in
this case it was the truncate operation that slowed down the progress. But
it's better to solve this by simply not allowing interrupts at all (except
SIGKILL), because applications don't expect file operations to be
interruptible anyway. As an added bonus the code is simplified somewhat.

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Miklos Szeredi and committed by
Linus Torvalds
7c352bdf 82547981

+45 -111
+13 -60
fs/fuse/dev.c
··· 103 103 return req; 104 104 } 105 105 106 + /* This can return NULL, but only in case it's interrupted by a SIGKILL */ 106 107 struct fuse_req *fuse_get_request(struct fuse_conn *fc) 107 - { 108 - if (down_interruptible(&fc->outstanding_sem)) 109 - return NULL; 110 - return do_get_request(fc); 111 - } 112 - 113 - /* 114 - * Non-interruptible version of the above function is for operations 115 - * which can't legally return -ERESTART{SYS,NOINTR}. This can still 116 - * return NULL, but only in case the signal is SIGKILL. 117 - */ 118 - struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc) 119 108 { 120 109 int intr; 121 110 sigset_t oldset; ··· 230 241 get_file(req->file); 231 242 } 232 243 233 - static int request_wait_answer_nonint(struct fuse_req *req) 234 - { 235 - int err; 236 - sigset_t oldset; 237 - block_sigs(&oldset); 238 - err = wait_event_interruptible(req->waitq, req->finished); 239 - restore_sigs(&oldset); 240 - return err; 241 - } 242 - 243 244 /* Called with fuse_lock held. Releases, and then reacquires it. */ 244 - static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req, 245 - int interruptible) 245 + static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) 246 246 { 247 - int intr; 247 + sigset_t oldset; 248 248 249 249 spin_unlock(&fuse_lock); 250 - if (interruptible) 251 - intr = wait_event_interruptible(req->waitq, req->finished); 252 - else 253 - intr = request_wait_answer_nonint(req); 250 + block_sigs(&oldset); 251 + wait_event_interruptible(req->waitq, req->finished); 252 + restore_sigs(&oldset); 254 253 spin_lock(&fuse_lock); 255 - if (intr && interruptible && req->sent) { 256 - /* If request is already in userspace, only allow KILL 257 - signal to interrupt */ 258 - spin_unlock(&fuse_lock); 259 - intr = request_wait_answer_nonint(req); 260 - spin_lock(&fuse_lock); 261 - } 262 - if (!intr) 254 + if (req->finished) 263 255 return; 264 256 265 - if (!interruptible || req->sent) 266 - req->out.h.error = -EINTR; 267 - else 268 - req->out.h.error = -ERESTARTNOINTR; 269 - 257 + req->out.h.error = -EINTR; 270 258 req->interrupted = 1; 271 259 if (req->locked) { 272 260 /* This is uninterruptible sleep, because data is ··· 296 330 wake_up(&fc->waitq); 297 331 } 298 332 299 - static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req, 300 - int interruptible) 333 + /* 334 + * This can only be interrupted by a SIGKILL 335 + */ 336 + void request_send(struct fuse_conn *fc, struct fuse_req *req) 301 337 { 302 338 req->isreply = 1; 303 339 spin_lock(&fuse_lock); ··· 313 345 after request_end() */ 314 346 __fuse_get_request(req); 315 347 316 - request_wait_answer(fc, req, interruptible); 348 + request_wait_answer(fc, req); 317 349 } 318 350 spin_unlock(&fuse_lock); 319 - } 320 - 321 - void request_send(struct fuse_conn *fc, struct fuse_req *req) 322 - { 323 - request_send_wait(fc, req, 1); 324 - } 325 - 326 - /* 327 - * Non-interruptible version of the above function is for operations 328 - * which can't legally return -ERESTART{SYS,NOINTR}. This can still 329 - * be interrupted but only with SIGKILL. 330 - */ 331 - void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req) 332 - { 333 - request_send_wait(fc, req, 0); 334 351 } 335 352 336 353 static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
+18 -18
fs/fuse/dir.c
··· 46 46 struct inode *inode = entry->d_inode; 47 47 struct fuse_inode *fi = get_fuse_inode(inode); 48 48 struct fuse_conn *fc = get_fuse_conn(inode); 49 - struct fuse_req *req = fuse_get_request_nonint(fc); 49 + struct fuse_req *req = fuse_get_request(fc); 50 50 if (!req) 51 51 return 0; 52 52 53 53 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); 54 - request_send_nonint(fc, req); 54 + request_send(fc, req); 55 55 err = req->out.h.error; 56 56 if (!err) { 57 57 if (outarg.nodeid != get_node_id(inode)) { ··· 91 91 92 92 req = fuse_get_request(fc); 93 93 if (!req) 94 - return -ERESTARTNOINTR; 94 + return -EINTR; 95 95 96 96 fuse_lookup_init(req, dir, entry, &outarg); 97 97 request_send(fc, req); ··· 185 185 struct fuse_conn *fc = get_fuse_conn(dir); 186 186 struct fuse_req *req = fuse_get_request(fc); 187 187 if (!req) 188 - return -ERESTARTNOINTR; 188 + return -EINTR; 189 189 190 190 memset(&inarg, 0, sizeof(inarg)); 191 191 inarg.mode = mode; ··· 211 211 struct fuse_conn *fc = get_fuse_conn(dir); 212 212 struct fuse_req *req = fuse_get_request(fc); 213 213 if (!req) 214 - return -ERESTARTNOINTR; 214 + return -EINTR; 215 215 216 216 memset(&inarg, 0, sizeof(inarg)); 217 217 inarg.mode = mode; ··· 236 236 237 237 req = fuse_get_request(fc); 238 238 if (!req) 239 - return -ERESTARTNOINTR; 239 + return -EINTR; 240 240 241 241 req->in.h.opcode = FUSE_SYMLINK; 242 242 req->in.numargs = 2; ··· 253 253 struct fuse_conn *fc = get_fuse_conn(dir); 254 254 struct fuse_req *req = fuse_get_request(fc); 255 255 if (!req) 256 - return -ERESTARTNOINTR; 256 + return -EINTR; 257 257 258 258 req->in.h.opcode = FUSE_UNLINK; 259 259 req->in.h.nodeid = get_node_id(dir); ··· 284 284 struct fuse_conn *fc = get_fuse_conn(dir); 285 285 struct fuse_req *req = fuse_get_request(fc); 286 286 if (!req) 287 - return -ERESTARTNOINTR; 287 + return -EINTR; 288 288 289 289 req->in.h.opcode = FUSE_RMDIR; 290 290 req->in.h.nodeid = get_node_id(dir); ··· 311 311 struct fuse_conn *fc = get_fuse_conn(olddir); 312 312 struct fuse_req *req = fuse_get_request(fc); 313 313 if (!req) 314 - return -ERESTARTNOINTR; 314 + return -EINTR; 315 315 316 316 memset(&inarg, 0, sizeof(inarg)); 317 317 inarg.newdir = get_node_id(newdir); ··· 356 356 struct fuse_conn *fc = get_fuse_conn(inode); 357 357 struct fuse_req *req = fuse_get_request(fc); 358 358 if (!req) 359 - return -ERESTARTNOINTR; 359 + return -EINTR; 360 360 361 361 memset(&inarg, 0, sizeof(inarg)); 362 362 inarg.oldnodeid = get_node_id(inode); ··· 386 386 struct fuse_conn *fc = get_fuse_conn(inode); 387 387 struct fuse_req *req = fuse_get_request(fc); 388 388 if (!req) 389 - return -ERESTARTNOINTR; 389 + return -EINTR; 390 390 391 391 req->in.h.opcode = FUSE_GETATTR; 392 392 req->in.h.nodeid = get_node_id(inode); ··· 533 533 struct page *page; 534 534 struct inode *inode = file->f_dentry->d_inode; 535 535 struct fuse_conn *fc = get_fuse_conn(inode); 536 - struct fuse_req *req = fuse_get_request_nonint(fc); 536 + struct fuse_req *req = fuse_get_request(fc); 537 537 if (!req) 538 538 return -EINTR; 539 539 ··· 564 564 char *link; 565 565 566 566 if (!req) 567 - return ERR_PTR(-ERESTARTNOINTR); 567 + return ERR_PTR(-EINTR); 568 568 569 569 link = (char *) __get_free_page(GFP_KERNEL); 570 570 if (!link) { ··· 677 677 678 678 req = fuse_get_request(fc); 679 679 if (!req) 680 - return -ERESTARTNOINTR; 680 + return -EINTR; 681 681 682 682 memset(&inarg, 0, sizeof(inarg)); 683 683 inarg.valid = iattr_to_fattr(attr, &inarg.attr); ··· 761 761 762 762 req = fuse_get_request(fc); 763 763 if (!req) 764 - return -ERESTARTNOINTR; 764 + return -EINTR; 765 765 766 766 memset(&inarg, 0, sizeof(inarg)); 767 767 inarg.size = size; ··· 801 801 802 802 req = fuse_get_request(fc); 803 803 if (!req) 804 - return -ERESTARTNOINTR; 804 + return -EINTR; 805 805 806 806 memset(&inarg, 0, sizeof(inarg)); 807 807 inarg.size = size; ··· 851 851 852 852 req = fuse_get_request(fc); 853 853 if (!req) 854 - return -ERESTARTNOINTR; 854 + return -EINTR; 855 855 856 856 memset(&inarg, 0, sizeof(inarg)); 857 857 inarg.size = size; ··· 897 897 898 898 req = fuse_get_request(fc); 899 899 if (!req) 900 - return -ERESTARTNOINTR; 900 + return -EINTR; 901 901 902 902 req->in.h.opcode = FUSE_REMOVEXATTR; 903 903 req->in.h.nodeid = get_node_id(inode);
+12 -21
fs/fuse/file.c
··· 22 22 struct fuse_open_out outarg; 23 23 struct fuse_file *ff; 24 24 int err; 25 - /* Restarting the syscall is not allowed if O_CREAT and O_EXCL 26 - are both set, because creation will fail on the restart */ 27 - int excl = (file->f_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL); 28 25 29 26 err = generic_file_open(inode, file); 30 27 if (err) ··· 35 38 return err; 36 39 } 37 40 38 - if (excl) 39 - req = fuse_get_request_nonint(fc); 40 - else 41 - req = fuse_get_request(fc); 41 + req = fuse_get_request(fc); 42 42 if (!req) 43 - return excl ? -EINTR : -ERESTARTSYS; 43 + return -EINTR; 44 44 45 45 err = -ENOMEM; 46 46 ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL); ··· 61 67 req->out.numargs = 1; 62 68 req->out.args[0].size = sizeof(outarg); 63 69 req->out.args[0].value = &outarg; 64 - if (excl) 65 - request_send_nonint(fc, req); 66 - else 67 - request_send(fc, req); 70 + request_send(fc, req); 68 71 err = req->out.h.error; 69 72 if (err) { 70 73 fuse_request_free(ff->release_req); ··· 124 133 if (fc->no_flush) 125 134 return 0; 126 135 127 - req = fuse_get_request_nonint(fc); 136 + req = fuse_get_request(fc); 128 137 if (!req) 129 138 return -EINTR; 130 139 ··· 137 146 req->in.numargs = 1; 138 147 req->in.args[0].size = sizeof(inarg); 139 148 req->in.args[0].value = &inarg; 140 - request_send_nonint(fc, req); 149 + request_send(fc, req); 141 150 err = req->out.h.error; 142 151 fuse_put_request(fc, req); 143 152 if (err == -ENOSYS) { ··· 162 171 163 172 req = fuse_get_request(fc); 164 173 if (!req) 165 - return -ERESTARTSYS; 174 + return -EINTR; 166 175 167 176 memset(&inarg, 0, sizeof(inarg)); 168 177 inarg.fh = ff->fh; ··· 215 224 req->out.argvar = 1; 216 225 req->out.numargs = 1; 217 226 req->out.args[0].size = count; 218 - request_send_nonint(fc, req); 227 + request_send(fc, req); 219 228 return req->out.args[0].size; 220 229 } 221 230 ··· 231 240 struct inode *inode = page->mapping->host; 232 241 struct fuse_conn *fc = get_fuse_conn(inode); 233 242 loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT; 234 - struct fuse_req *req = fuse_get_request_nonint(fc); 243 + struct fuse_req *req = fuse_get_request(fc); 235 244 int err = -EINTR; 236 245 if (!req) 237 246 goto out; ··· 305 314 int err; 306 315 data.file = file; 307 316 data.inode = inode; 308 - data.req = fuse_get_request_nonint(fc); 317 + data.req = fuse_get_request(fc); 309 318 if (!data.req) 310 319 return -EINTR; 311 320 ··· 341 350 req->out.numargs = 1; 342 351 req->out.args[0].size = sizeof(struct fuse_write_out); 343 352 req->out.args[0].value = &outarg; 344 - request_send_nonint(fc, req); 353 + request_send(fc, req); 345 354 return outarg.size; 346 355 } 347 356 ··· 361 370 struct inode *inode = page->mapping->host; 362 371 struct fuse_conn *fc = get_fuse_conn(inode); 363 372 loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset; 364 - struct fuse_req *req = fuse_get_request_nonint(fc); 373 + struct fuse_req *req = fuse_get_request(fc); 365 374 if (!req) 366 375 return -EINTR; 367 376 ··· 435 444 ssize_t res = 0; 436 445 struct fuse_req *req = fuse_get_request(fc); 437 446 if (!req) 438 - return -ERESTARTSYS; 447 + return -EINTR; 439 448 440 449 while (count) { 441 450 size_t tmp;
+1 -11
fs/fuse/fuse_i.h
··· 410 410 struct fuse_req *fuse_get_request(struct fuse_conn *fc); 411 411 412 412 /** 413 - * Reserve a preallocated request, only interruptible by SIGKILL 414 - */ 415 - struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc); 416 - 417 - /** 418 413 * Decrement reference count of a request. If count goes to zero put 419 414 * on unused list (preallocated) or free reqest (not preallocated). 420 415 */ 421 416 void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); 422 417 423 418 /** 424 - * Send a request (synchronous, interruptible) 419 + * Send a request (synchronous) 425 420 */ 426 421 void request_send(struct fuse_conn *fc, struct fuse_req *req); 427 - 428 - /** 429 - * Send a request (synchronous, non-interruptible except by SIGKILL) 430 - */ 431 - void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req); 432 422 433 423 /** 434 424 * Send a request with no reply
+1 -1
fs/fuse/inode.c
··· 236 236 237 237 req = fuse_get_request(fc); 238 238 if (!req) 239 - return -ERESTARTSYS; 239 + return -EINTR; 240 240 241 241 req->in.numargs = 0; 242 242 req->in.h.opcode = FUSE_STATFS;