aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikulas Patocka <mikulas@twibright.com>2016-02-25 12:17:38 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2016-02-27 19:15:51 -0500
commitb6853f78e763d42c7a158d8de3549c9827c604ab (patch)
tree163114c508c577d3c6228d80667ffc17d2a60c13
parent7ae8fd0351f912b075149a1e03a017be8b903b9a (diff)
hpfs: don't truncate the file when delete fails
The delete opration can allocate additional space on the HPFS filesystem due to btree split. The HPFS driver checks in advance if there is available space, so that it won't corrupt the btree if we run out of space during splitting. If there is not enough available space, the HPFS driver attempted to truncate the file, but this results in a deadlock since the commit 7dd29d8d865efdb00c0542a5d2c87af8c52ea6c7 ("HPFS: Introduce a global mutex and lock it on every callback from VFS"). This patch removes the code that tries to truncate the file and -ENOSPC is returned instead. If the user hits -ENOSPC on delete, he should try to delete other files (that are stored in a leaf btree node), so that the delete operation will make some space for deleting the file stored in non-leaf btree node. Reported-by: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz> Cc: stable@vger.kernel.org # 2.6.39+ Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/hpfs/namei.c31
1 files changed, 3 insertions, 28 deletions
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 506765afa1a3..bb8d67e2740a 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -376,12 +376,11 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
376 struct inode *inode = d_inode(dentry); 376 struct inode *inode = d_inode(dentry);
377 dnode_secno dno; 377 dnode_secno dno;
378 int r; 378 int r;
379 int rep = 0;
380 int err; 379 int err;
381 380
382 hpfs_lock(dir->i_sb); 381 hpfs_lock(dir->i_sb);
383 hpfs_adjust_length(name, &len); 382 hpfs_adjust_length(name, &len);
384again: 383
385 err = -ENOENT; 384 err = -ENOENT;
386 de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); 385 de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
387 if (!de) 386 if (!de)
@@ -401,33 +400,9 @@ again:
401 hpfs_error(dir->i_sb, "there was error when removing dirent"); 400 hpfs_error(dir->i_sb, "there was error when removing dirent");
402 err = -EFSERROR; 401 err = -EFSERROR;
403 break; 402 break;
404 case 2: /* no space for deleting, try to truncate file */ 403 case 2: /* no space for deleting */
405
406 err = -ENOSPC; 404 err = -ENOSPC;
407 if (rep++) 405 break;
408 break;
409
410 dentry_unhash(dentry);
411 if (!d_unhashed(dentry)) {
412 hpfs_unlock(dir->i_sb);
413 return -ENOSPC;
414 }
415 if (generic_permission(inode, MAY_WRITE) ||
416 !S_ISREG(inode->i_mode) ||
417 get_write_access(inode)) {
418 d_rehash(dentry);
419 } else {
420 struct iattr newattrs;
421 /*pr_info("truncating file before delete.\n");*/
422 newattrs.ia_size = 0;
423 newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
424 err = notify_change(dentry, &newattrs, NULL);
425 put_write_access(inode);
426 if (!err)
427 goto again;
428 }
429 hpfs_unlock(dir->i_sb);
430 return -ENOSPC;
431 default: 406 default:
432 drop_nlink(inode); 407 drop_nlink(inode);
433 err = 0; 408 err = 0;