aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2009-03-30 14:02:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-03-30 15:16:38 -0400
commit0ab2621ebd9a28bf7a524ecd50d492a10579dfcc (patch)
tree62dda6de2fed116aff363190f95a58d56c690e3e /fs
parent48b32a3553a54740d236b79a90f20147a25875e3 (diff)
reiserfs: journaled xattrs
Deadlocks are possible in the xattr code between the journal lock and the xattr sems. This patch implements journalling for xattr operations. The benefit is twofold: * It gets rid of the deadlock possibility by always ensuring that xattr write operations are initiated inside a transaction. * It corrects the problem where xattr backing files aren't considered any differently than normal files, despite the fact they are metadata. I discussed the added journal load with Chris Mason, and we decided that since xattrs (versus other journal activity) is fairly rare, the introduction of larger transactions to support journaled xattrs wouldn't be too big a deal. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/reiserfs/inode.c3
-rw-r--r--fs/reiserfs/namei.c14
-rw-r--r--fs/reiserfs/xattr.c39
-rw-r--r--fs/reiserfs/xattr_acl.c105
4 files changed, 115 insertions, 46 deletions
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 50a73e7afdc8..995f6975cae1 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1914,9 +1914,8 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
1914 goto out_inserted_sd; 1914 goto out_inserted_sd;
1915 } 1915 }
1916 1916
1917 /* XXX CHECK THIS */
1918 if (reiserfs_posixacl(inode->i_sb)) { 1917 if (reiserfs_posixacl(inode->i_sb)) {
1919 retval = reiserfs_inherit_default_acl(dir, dentry, inode); 1918 retval = reiserfs_inherit_default_acl(th, dir, dentry, inode);
1920 if (retval) { 1919 if (retval) {
1921 err = retval; 1920 err = retval;
1922 reiserfs_check_path(&path_to_key); 1921 reiserfs_check_path(&path_to_key);
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index ddf1bcd41c87..d9c1c8bd2950 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -598,15 +598,13 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
598 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + 598 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
599 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); 599 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
600 struct reiserfs_transaction_handle th; 600 struct reiserfs_transaction_handle th;
601 int locked;
602 601
603 if (!(inode = new_inode(dir->i_sb))) { 602 if (!(inode = new_inode(dir->i_sb))) {
604 return -ENOMEM; 603 return -ENOMEM;
605 } 604 }
606 new_inode_init(inode, dir, mode); 605 new_inode_init(inode, dir, mode);
607 606
608 locked = reiserfs_cache_default_acl(dir); 607 jbegin_count += reiserfs_cache_default_acl(dir);
609
610 reiserfs_write_lock(dir->i_sb); 608 reiserfs_write_lock(dir->i_sb);
611 609
612 retval = journal_begin(&th, dir->i_sb, jbegin_count); 610 retval = journal_begin(&th, dir->i_sb, jbegin_count);
@@ -662,7 +660,6 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
662 JOURNAL_PER_BALANCE_CNT * 3 + 660 JOURNAL_PER_BALANCE_CNT * 3 +
663 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + 661 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
664 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); 662 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
665 int locked;
666 663
667 if (!new_valid_dev(rdev)) 664 if (!new_valid_dev(rdev))
668 return -EINVAL; 665 return -EINVAL;
@@ -672,8 +669,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
672 } 669 }
673 new_inode_init(inode, dir, mode); 670 new_inode_init(inode, dir, mode);
674 671
675 locked = reiserfs_cache_default_acl(dir); 672 jbegin_count += reiserfs_cache_default_acl(dir);
676
677 reiserfs_write_lock(dir->i_sb); 673 reiserfs_write_lock(dir->i_sb);
678 674
679 retval = journal_begin(&th, dir->i_sb, jbegin_count); 675 retval = journal_begin(&th, dir->i_sb, jbegin_count);
@@ -732,7 +728,6 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
732 JOURNAL_PER_BALANCE_CNT * 3 + 728 JOURNAL_PER_BALANCE_CNT * 3 +
733 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + 729 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
734 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); 730 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
735 int locked;
736 731
737#ifdef DISPLACE_NEW_PACKING_LOCALITIES 732#ifdef DISPLACE_NEW_PACKING_LOCALITIES
738 /* set flag that new packing locality created and new blocks for the content * of that directory are not displaced yet */ 733 /* set flag that new packing locality created and new blocks for the content * of that directory are not displaced yet */
@@ -744,8 +739,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
744 } 739 }
745 new_inode_init(inode, dir, mode); 740 new_inode_init(inode, dir, mode);
746 741
747 locked = reiserfs_cache_default_acl(dir); 742 jbegin_count += reiserfs_cache_default_acl(dir);
748
749 reiserfs_write_lock(dir->i_sb); 743 reiserfs_write_lock(dir->i_sb);
750 744
751 retval = journal_begin(&th, dir->i_sb, jbegin_count); 745 retval = journal_begin(&th, dir->i_sb, jbegin_count);
@@ -1034,8 +1028,6 @@ static int reiserfs_symlink(struct inode *parent_dir,
1034 memcpy(name, symname, strlen(symname)); 1028 memcpy(name, symname, strlen(symname));
1035 padd_item(name, item_len, strlen(symname)); 1029 padd_item(name, item_len, strlen(symname));
1036 1030
1037 /* We would inherit the default ACL here, but symlinks don't get ACLs */
1038
1039 retval = journal_begin(&th, parent_dir->i_sb, jbegin_count); 1031 retval = journal_begin(&th, parent_dir->i_sb, jbegin_count);
1040 if (retval) { 1032 if (retval) {
1041 drop_new_inode(inode); 1033 drop_new_inode(inode);
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index d3ce27436605..c2e3a92aaf2b 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -632,8 +632,9 @@ out_dput:
632 * inode->i_mutex: down 632 * inode->i_mutex: down
633 */ 633 */
634int 634int
635__reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, 635reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
636 size_t buffer_size, int flags) 636 struct inode *inode, const char *name,
637 const void *buffer, size_t buffer_size, int flags)
637{ 638{
638 int err = 0; 639 int err = 0;
639 struct dentry *dentry; 640 struct dentry *dentry;
@@ -723,14 +724,34 @@ out_unlock:
723 return err; 724 return err;
724} 725}
725 726
726int 727/* We need to start a transaction to maintain lock ordering */
727reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, 728int reiserfs_xattr_set(struct inode *inode, const char *name,
728 size_t buffer_size, int flags) 729 const void *buffer, size_t buffer_size, int flags)
729{ 730{
730 int err = __reiserfs_xattr_set(inode, name, buffer, buffer_size, flags); 731
731 if (err == -ENODATA) 732 struct reiserfs_transaction_handle th;
732 err = 0; 733 int error, error2;
733 return err; 734 size_t jbegin_count = reiserfs_xattr_nblocks(inode, buffer_size);
735
736 if (!(flags & XATTR_REPLACE))
737 jbegin_count += reiserfs_xattr_jcreate_nblocks(inode);
738
739 reiserfs_write_lock(inode->i_sb);
740 error = journal_begin(&th, inode->i_sb, jbegin_count);
741 if (error) {
742 reiserfs_write_unlock(inode->i_sb);
743 return error;
744 }
745
746 error = reiserfs_xattr_set_handle(&th, inode, name,
747 buffer, buffer_size, flags);
748
749 error2 = journal_end(&th, inode->i_sb, jbegin_count);
750 if (error == 0)
751 error = error2;
752 reiserfs_write_unlock(inode->i_sb);
753
754 return error;
734} 755}
735 756
736/* 757/*
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index bfecf7553002..d423416d93d1 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -10,15 +10,17 @@
10#include <linux/reiserfs_acl.h> 10#include <linux/reiserfs_acl.h>
11#include <asm/uaccess.h> 11#include <asm/uaccess.h>
12 12
13static int reiserfs_set_acl(struct inode *inode, int type, 13static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
14 struct inode *inode, int type,
14 struct posix_acl *acl); 15 struct posix_acl *acl);
15 16
16static int 17static int
17xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) 18xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
18{ 19{
19 struct posix_acl *acl; 20 struct posix_acl *acl;
20 int error; 21 int error, error2;
21 22 struct reiserfs_transaction_handle th;
23 size_t jcreate_blocks;
22 if (!reiserfs_posixacl(inode->i_sb)) 24 if (!reiserfs_posixacl(inode->i_sb))
23 return -EOPNOTSUPP; 25 return -EOPNOTSUPP;
24 if (!is_owner_or_cap(inode)) 26 if (!is_owner_or_cap(inode))
@@ -36,7 +38,21 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
36 } else 38 } else
37 acl = NULL; 39 acl = NULL;
38 40
39 error = reiserfs_set_acl(inode, type, acl); 41 /* Pessimism: We can't assume that anything from the xattr root up
42 * has been created. */
43
44 jcreate_blocks = reiserfs_xattr_jcreate_nblocks(inode) +
45 reiserfs_xattr_nblocks(inode, size) * 2;
46
47 reiserfs_write_lock(inode->i_sb);
48 error = journal_begin(&th, inode->i_sb, jcreate_blocks);
49 if (error == 0) {
50 error = reiserfs_set_acl(&th, inode, type, acl);
51 error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
52 if (error2)
53 error = error2;
54 }
55 reiserfs_write_unlock(inode->i_sb);
40 56
41 release_and_out: 57 release_and_out:
42 posix_acl_release(acl); 58 posix_acl_release(acl);
@@ -266,7 +282,8 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
266 * BKL held [before 2.5.x] 282 * BKL held [before 2.5.x]
267 */ 283 */
268static int 284static int
269reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) 285reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
286 int type, struct posix_acl *acl)
270{ 287{
271 char *name; 288 char *name;
272 void *value = NULL; 289 void *value = NULL;
@@ -310,7 +327,7 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
310 return (int)PTR_ERR(value); 327 return (int)PTR_ERR(value);
311 } 328 }
312 329
313 error = __reiserfs_xattr_set(inode, name, value, size, 0); 330 error = reiserfs_xattr_set_handle(th, inode, name, value, size, 0);
314 331
315 /* 332 /*
316 * Ensure that the inode gets dirtied if we're only using 333 * Ensure that the inode gets dirtied if we're only using
@@ -337,7 +354,8 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
337/* dir->i_mutex: locked, 354/* dir->i_mutex: locked,
338 * inode is new and not released into the wild yet */ 355 * inode is new and not released into the wild yet */
339int 356int
340reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry, 357reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
358 struct inode *dir, struct dentry *dentry,
341 struct inode *inode) 359 struct inode *inode)
342{ 360{
343 struct posix_acl *acl; 361 struct posix_acl *acl;
@@ -374,7 +392,8 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
374 392
375 /* Copy the default ACL to the default ACL of a new directory */ 393 /* Copy the default ACL to the default ACL of a new directory */
376 if (S_ISDIR(inode->i_mode)) { 394 if (S_ISDIR(inode->i_mode)) {
377 err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl); 395 err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
396 acl);
378 if (err) 397 if (err)
379 goto cleanup; 398 goto cleanup;
380 } 399 }
@@ -395,9 +414,9 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
395 414
396 /* If we need an ACL.. */ 415 /* If we need an ACL.. */
397 if (need_acl > 0) { 416 if (need_acl > 0) {
398 err = 417 err = reiserfs_set_acl(th, inode,
399 reiserfs_set_acl(inode, ACL_TYPE_ACCESS, 418 ACL_TYPE_ACCESS,
400 acl_copy); 419 acl_copy);
401 if (err) 420 if (err)
402 goto cleanup_copy; 421 goto cleanup_copy;
403 } 422 }
@@ -415,21 +434,45 @@ reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
415 return err; 434 return err;
416} 435}
417 436
418/* Looks up and caches the result of the default ACL. 437/* This is used to cache the default acl before a new object is created.
419 * We do this so that we don't need to carry the xattr_sem into 438 * The biggest reason for this is to get an idea of how many blocks will
420 * reiserfs_new_inode if we don't need to */ 439 * actually be required for the create operation if we must inherit an ACL.
440 * An ACL write can add up to 3 object creations and an additional file write
441 * so we'd prefer not to reserve that many blocks in the journal if we can.
442 * It also has the advantage of not loading the ACL with a transaction open,
443 * this may seem silly, but if the owner of the directory is doing the
444 * creation, the ACL may not be loaded since the permissions wouldn't require
445 * it.
446 * We return the number of blocks required for the transaction.
447 */
421int reiserfs_cache_default_acl(struct inode *inode) 448int reiserfs_cache_default_acl(struct inode *inode)
422{ 449{
423 int ret = 0; 450 struct posix_acl *acl;
424 if (reiserfs_posixacl(inode->i_sb) && !IS_PRIVATE(inode)) { 451 int nblocks = 0;
425 struct posix_acl *acl; 452
426 acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT); 453 if (IS_PRIVATE(inode))
427 ret = (acl && !IS_ERR(acl)); 454 return 0;
428 if (ret) 455
429 posix_acl_release(acl); 456 acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
457
458 if (acl && !IS_ERR(acl)) {
459 int size = reiserfs_acl_size(acl->a_count);
460
461 /* Other xattrs can be created during inode creation. We don't
462 * want to claim too many blocks, so we check to see if we
463 * we need to create the tree to the xattrs, and then we
464 * just want two files. */
465 nblocks = reiserfs_xattr_jcreate_nblocks(inode);
466 nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb);
467
468 REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
469
470 /* We need to account for writes + bitmaps for two files */
471 nblocks += reiserfs_xattr_nblocks(inode, size) * 4;
472 posix_acl_release(acl);
430 } 473 }
431 474
432 return ret; 475 return nblocks;
433} 476}
434 477
435int reiserfs_acl_chmod(struct inode *inode) 478int reiserfs_acl_chmod(struct inode *inode)
@@ -455,8 +498,22 @@ int reiserfs_acl_chmod(struct inode *inode)
455 if (!clone) 498 if (!clone)
456 return -ENOMEM; 499 return -ENOMEM;
457 error = posix_acl_chmod_masq(clone, inode->i_mode); 500 error = posix_acl_chmod_masq(clone, inode->i_mode);
458 if (!error) 501 if (!error) {
459 error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone); 502 struct reiserfs_transaction_handle th;
503 size_t size = reiserfs_xattr_nblocks(inode,
504 reiserfs_acl_size(clone->a_count));
505 reiserfs_write_lock(inode->i_sb);
506 error = journal_begin(&th, inode->i_sb, size * 2);
507 if (!error) {
508 int error2;
509 error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS,
510 clone);
511 error2 = journal_end(&th, inode->i_sb, size * 2);
512 if (error2)
513 error = error2;
514 }
515 reiserfs_write_unlock(inode->i_sb);
516 }
460 posix_acl_release(clone); 517 posix_acl_release(clone);
461 return error; 518 return error;
462} 519}