diff options
author | Jeff Mahoney <jeffm@suse.com> | 2009-03-30 14:02:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-30 15:16:38 -0400 |
commit | 8b6dd72a441a683cef7ace93de0a57ced4367f00 (patch) | |
tree | 6bdeebd3a35d71db2c7ea3e48e3f617b5efbd81a /fs/reiserfs/xattr.c | |
parent | d984561b326cd0fe0d1183d11b9b4fa1d011d21d (diff) |
reiserfs: make per-inode xattr locking more fine grained
The per-inode locking can be made more fine-grained to surround just the
interaction with the filesystem itself. This really only applies to
protecting reads during a write, since concurrent writes are barred with
inode->i_mutex at the vfs level.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/reiserfs/xattr.c')
-rw-r--r-- | fs/reiserfs/xattr.c | 114 |
1 files changed, 53 insertions, 61 deletions
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 62c98829c545..ccb8e4d4c032 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
@@ -29,10 +29,8 @@ | |||
29 | * to the inode so that unnecessary lookups are avoided. | 29 | * to the inode so that unnecessary lookups are avoided. |
30 | * | 30 | * |
31 | * Locking works like so: | 31 | * Locking works like so: |
32 | * The xattr root (/.reiserfs_priv/xattrs) is protected by its i_mutex. | 32 | * Directory components (xattr root, xattr dir) are protectd by their i_mutex. |
33 | * The xattr dir (/.reiserfs_priv/xattrs/<oid>.<gen>) is protected by | 33 | * The xattrs themselves are protected by the xattr_sem. |
34 | * inode->xattr_sem. | ||
35 | * The xattrs themselves are likewise protected by the xattr_sem. | ||
36 | */ | 34 | */ |
37 | 35 | ||
38 | #include <linux/reiserfs_fs.h> | 36 | #include <linux/reiserfs_fs.h> |
@@ -55,6 +53,8 @@ | |||
55 | #define PRIVROOT_NAME ".reiserfs_priv" | 53 | #define PRIVROOT_NAME ".reiserfs_priv" |
56 | #define XAROOT_NAME "xattrs" | 54 | #define XAROOT_NAME "xattrs" |
57 | 55 | ||
56 | static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char *); | ||
57 | |||
58 | /* Helpers for inode ops. We do this so that we don't have all the VFS | 58 | /* Helpers for inode ops. We do this so that we don't have all the VFS |
59 | * overhead and also for proper i_mutex annotation. | 59 | * overhead and also for proper i_mutex annotation. |
60 | * dir->i_mutex must be held for all of them. */ | 60 | * dir->i_mutex must be held for all of them. */ |
@@ -339,12 +339,14 @@ int xattr_readdir(struct inode *inode, filldir_t filler, void *buf) | |||
339 | return res; | 339 | return res; |
340 | } | 340 | } |
341 | 341 | ||
342 | /* expects xadir->d_inode->i_mutex to be locked */ | ||
342 | static int | 343 | static int |
343 | __reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) | 344 | __reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) |
344 | { | 345 | { |
345 | struct dentry *dentry; | 346 | struct dentry *dentry; |
346 | struct inode *dir = xadir->d_inode; | 347 | struct inode *dir = xadir->d_inode; |
347 | int err = 0; | 348 | int err = 0; |
349 | struct reiserfs_xattr_handler *xah; | ||
348 | 350 | ||
349 | dentry = lookup_one_len(name, xadir, namelen); | 351 | dentry = lookup_one_len(name, xadir, namelen); |
350 | if (IS_ERR(dentry)) { | 352 | if (IS_ERR(dentry)) { |
@@ -372,6 +374,14 @@ __reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen) | |||
372 | return -EIO; | 374 | return -EIO; |
373 | } | 375 | } |
374 | 376 | ||
377 | /* Deletion pre-operation */ | ||
378 | xah = find_xattr_handler_prefix(name); | ||
379 | if (xah && xah->del) { | ||
380 | err = xah->del(dentry->d_inode, name); | ||
381 | if (err) | ||
382 | goto out; | ||
383 | } | ||
384 | |||
375 | err = xattr_unlink(dir, dentry); | 385 | err = xattr_unlink(dir, dentry); |
376 | 386 | ||
377 | out_file: | 387 | out_file: |
@@ -398,7 +408,7 @@ reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, | |||
398 | /* This is called w/ inode->i_mutex downed */ | 408 | /* This is called w/ inode->i_mutex downed */ |
399 | int reiserfs_delete_xattrs(struct inode *inode) | 409 | int reiserfs_delete_xattrs(struct inode *inode) |
400 | { | 410 | { |
401 | int err = 0; | 411 | int err = -ENODATA; |
402 | struct dentry *dir, *root; | 412 | struct dentry *dir, *root; |
403 | struct reiserfs_transaction_handle th; | 413 | struct reiserfs_transaction_handle th; |
404 | int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + | 414 | int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + |
@@ -414,14 +424,19 @@ int reiserfs_delete_xattrs(struct inode *inode) | |||
414 | goto out; | 424 | goto out; |
415 | } else if (!dir->d_inode) { | 425 | } else if (!dir->d_inode) { |
416 | dput(dir); | 426 | dput(dir); |
417 | return 0; | 427 | goto out; |
418 | } | 428 | } |
419 | 429 | ||
420 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); | 430 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); |
421 | err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); | 431 | err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); |
422 | mutex_unlock(&dir->d_inode->i_mutex); | 432 | mutex_unlock(&dir->d_inode->i_mutex); |
423 | if (err) | 433 | if (err) { |
424 | goto out_dir; | 434 | dput(dir); |
435 | goto out; | ||
436 | } | ||
437 | |||
438 | root = dget(dir->d_parent); | ||
439 | dput(dir); | ||
425 | 440 | ||
426 | /* We start a transaction here to avoid a ABBA situation | 441 | /* We start a transaction here to avoid a ABBA situation |
427 | * between the xattr root's i_mutex and the journal lock. | 442 | * between the xattr root's i_mutex and the journal lock. |
@@ -435,19 +450,14 @@ int reiserfs_delete_xattrs(struct inode *inode) | |||
435 | err = journal_begin(&th, inode->i_sb, blocks); | 450 | err = journal_begin(&th, inode->i_sb, blocks); |
436 | if (!err) { | 451 | if (!err) { |
437 | int jerror; | 452 | int jerror; |
438 | root = dget(dir->d_parent); | ||
439 | mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR); | 453 | mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR); |
440 | err = xattr_rmdir(root->d_inode, dir); | 454 | err = xattr_rmdir(root->d_inode, dir); |
441 | jerror = journal_end(&th, inode->i_sb, blocks); | 455 | jerror = journal_end(&th, inode->i_sb, blocks); |
442 | mutex_unlock(&root->d_inode->i_mutex); | 456 | mutex_unlock(&root->d_inode->i_mutex); |
443 | dput(root); | ||
444 | |||
445 | err = jerror ?: err; | 457 | err = jerror ?: err; |
446 | } | 458 | } |
447 | 459 | ||
448 | out_dir: | 460 | dput(root); |
449 | dput(dir); | ||
450 | |||
451 | out: | 461 | out: |
452 | if (!err) | 462 | if (!err) |
453 | REISERFS_I(inode)->i_flags = | 463 | REISERFS_I(inode)->i_flags = |
@@ -484,7 +494,7 @@ reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, | |||
484 | 494 | ||
485 | if (!S_ISDIR(xafile->d_inode->i_mode)) { | 495 | if (!S_ISDIR(xafile->d_inode->i_mode)) { |
486 | mutex_lock_nested(&xafile->d_inode->i_mutex, I_MUTEX_CHILD); | 496 | mutex_lock_nested(&xafile->d_inode->i_mutex, I_MUTEX_CHILD); |
487 | err = notify_change(xafile, attrs); | 497 | err = reiserfs_setattr(xafile, attrs); |
488 | mutex_unlock(&xafile->d_inode->i_mutex); | 498 | mutex_unlock(&xafile->d_inode->i_mutex); |
489 | } | 499 | } |
490 | dput(xafile); | 500 | dput(xafile); |
@@ -520,13 +530,16 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) | |||
520 | err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); | 530 | err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); |
521 | 531 | ||
522 | if (!err) | 532 | if (!err) |
523 | err = notify_change(dir, attrs); | 533 | err = reiserfs_setattr(dir, attrs); |
524 | mutex_unlock(&dir->d_inode->i_mutex); | 534 | mutex_unlock(&dir->d_inode->i_mutex); |
525 | 535 | ||
526 | attrs->ia_valid = ia_valid; | 536 | attrs->ia_valid = ia_valid; |
527 | out_dir: | 537 | out_dir: |
528 | dput(dir); | 538 | dput(dir); |
529 | out: | 539 | out: |
540 | if (err) | ||
541 | reiserfs_warning(inode->i_sb, "jdm-20007", | ||
542 | "Couldn't chown all xattrs (%d)\n", err); | ||
530 | return err; | 543 | return err; |
531 | } | 544 | } |
532 | 545 | ||
@@ -635,9 +648,8 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, | |||
635 | if (get_inode_sd_version(inode) == STAT_DATA_V1) | 648 | if (get_inode_sd_version(inode) == STAT_DATA_V1) |
636 | return -EOPNOTSUPP; | 649 | return -EOPNOTSUPP; |
637 | 650 | ||
638 | /* Empty xattrs are ok, they're just empty files, no hash */ | 651 | if (!buffer) |
639 | if (buffer && buffer_size) | 652 | return reiserfs_xattr_del(inode, name); |
640 | xahash = xattr_hash(buffer, buffer_size); | ||
641 | 653 | ||
642 | dentry = get_xa_file_dentry(inode, name, flags); | 654 | dentry = get_xa_file_dentry(inode, name, flags); |
643 | if (IS_ERR(dentry)) { | 655 | if (IS_ERR(dentry)) { |
@@ -645,13 +657,19 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, | |||
645 | goto out; | 657 | goto out; |
646 | } | 658 | } |
647 | 659 | ||
660 | down_write(&REISERFS_I(inode)->i_xattr_sem); | ||
661 | |||
662 | xahash = xattr_hash(buffer, buffer_size); | ||
648 | REISERFS_I(inode)->i_flags |= i_has_xattr_dir; | 663 | REISERFS_I(inode)->i_flags |= i_has_xattr_dir; |
649 | 664 | ||
650 | /* Resize it so we're ok to write there */ | 665 | /* Resize it so we're ok to write there */ |
651 | newattrs.ia_size = buffer_size; | 666 | newattrs.ia_size = buffer_size; |
667 | newattrs.ia_ctime = current_fs_time(inode->i_sb); | ||
652 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | 668 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; |
653 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); | 669 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); |
654 | err = notify_change(dentry, &newattrs); | 670 | down_write(&dentry->d_inode->i_alloc_sem); |
671 | err = reiserfs_setattr(dentry, &newattrs); | ||
672 | up_write(&dentry->d_inode->i_alloc_sem); | ||
655 | mutex_unlock(&dentry->d_inode->i_mutex); | 673 | mutex_unlock(&dentry->d_inode->i_mutex); |
656 | if (err) | 674 | if (err) |
657 | goto out_filp; | 675 | goto out_filp; |
@@ -712,6 +730,7 @@ reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer, | |||
712 | } | 730 | } |
713 | 731 | ||
714 | out_filp: | 732 | out_filp: |
733 | up_write(&REISERFS_I(inode)->i_xattr_sem); | ||
715 | dput(dentry); | 734 | dput(dentry); |
716 | 735 | ||
717 | out: | 736 | out: |
@@ -747,10 +766,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, | |||
747 | goto out; | 766 | goto out; |
748 | } | 767 | } |
749 | 768 | ||
750 | /* protect against concurrent access. xattrs are backed by | 769 | down_read(&REISERFS_I(inode)->i_xattr_sem); |
751 | * regular files, but they're not regular files. The updates | ||
752 | * must be atomic from the perspective of the user. */ | ||
753 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_XATTR); | ||
754 | 770 | ||
755 | isize = i_size_read(dentry->d_inode); | 771 | isize = i_size_read(dentry->d_inode); |
756 | REISERFS_I(inode)->i_flags |= i_has_xattr_dir; | 772 | REISERFS_I(inode)->i_flags |= i_has_xattr_dir; |
@@ -758,12 +774,12 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, | |||
758 | /* Just return the size needed */ | 774 | /* Just return the size needed */ |
759 | if (buffer == NULL) { | 775 | if (buffer == NULL) { |
760 | err = isize - sizeof(struct reiserfs_xattr_header); | 776 | err = isize - sizeof(struct reiserfs_xattr_header); |
761 | goto out_dput; | 777 | goto out_unlock; |
762 | } | 778 | } |
763 | 779 | ||
764 | if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) { | 780 | if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) { |
765 | err = -ERANGE; | 781 | err = -ERANGE; |
766 | goto out_dput; | 782 | goto out_unlock; |
767 | } | 783 | } |
768 | 784 | ||
769 | while (file_pos < isize) { | 785 | while (file_pos < isize) { |
@@ -778,7 +794,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, | |||
778 | page = reiserfs_get_page(dentry->d_inode, file_pos); | 794 | page = reiserfs_get_page(dentry->d_inode, file_pos); |
779 | if (IS_ERR(page)) { | 795 | if (IS_ERR(page)) { |
780 | err = PTR_ERR(page); | 796 | err = PTR_ERR(page); |
781 | goto out_dput; | 797 | goto out_unlock; |
782 | } | 798 | } |
783 | 799 | ||
784 | lock_page(page); | 800 | lock_page(page); |
@@ -797,7 +813,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, | |||
797 | "associated with %k", name, | 813 | "associated with %k", name, |
798 | INODE_PKEY(inode)); | 814 | INODE_PKEY(inode)); |
799 | err = -EIO; | 815 | err = -EIO; |
800 | goto out_dput; | 816 | goto out_unlock; |
801 | } | 817 | } |
802 | hash = le32_to_cpu(rxh->h_hash); | 818 | hash = le32_to_cpu(rxh->h_hash); |
803 | } | 819 | } |
@@ -818,8 +834,8 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, | |||
818 | err = -EIO; | 834 | err = -EIO; |
819 | } | 835 | } |
820 | 836 | ||
821 | out_dput: | 837 | out_unlock: |
822 | mutex_unlock(&dentry->d_inode->i_mutex); | 838 | up_read(&REISERFS_I(inode)->i_xattr_sem); |
823 | dput(dentry); | 839 | dput(dentry); |
824 | 840 | ||
825 | out: | 841 | out: |
@@ -852,8 +868,6 @@ int reiserfs_xattr_del(struct inode *inode, const char *name) | |||
852 | } | 868 | } |
853 | 869 | ||
854 | /* Actual operations that are exported to VFS-land */ | 870 | /* Actual operations that are exported to VFS-land */ |
855 | |||
856 | static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char *); | ||
857 | /* | 871 | /* |
858 | * Inode operation getxattr() | 872 | * Inode operation getxattr() |
859 | */ | 873 | */ |
@@ -868,9 +882,7 @@ reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, | |||
868 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 882 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) |
869 | return -EOPNOTSUPP; | 883 | return -EOPNOTSUPP; |
870 | 884 | ||
871 | reiserfs_read_lock_xattr_i(dentry->d_inode); | ||
872 | err = xah->get(dentry->d_inode, name, buffer, size); | 885 | err = xah->get(dentry->d_inode, name, buffer, size); |
873 | reiserfs_read_unlock_xattr_i(dentry->d_inode); | ||
874 | return err; | 886 | return err; |
875 | } | 887 | } |
876 | 888 | ||
@@ -890,9 +902,7 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
890 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 902 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) |
891 | return -EOPNOTSUPP; | 903 | return -EOPNOTSUPP; |
892 | 904 | ||
893 | reiserfs_write_lock_xattr_i(dentry->d_inode); | ||
894 | err = xah->set(dentry->d_inode, name, value, size, flags); | 905 | err = xah->set(dentry->d_inode, name, value, size, flags); |
895 | reiserfs_write_unlock_xattr_i(dentry->d_inode); | ||
896 | return err; | 906 | return err; |
897 | } | 907 | } |
898 | 908 | ||
@@ -910,21 +920,11 @@ int reiserfs_removexattr(struct dentry *dentry, const char *name) | |||
910 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 920 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) |
911 | return -EOPNOTSUPP; | 921 | return -EOPNOTSUPP; |
912 | 922 | ||
913 | reiserfs_write_lock_xattr_i(dentry->d_inode); | ||
914 | /* Deletion pre-operation */ | ||
915 | if (xah->del) { | ||
916 | err = xah->del(dentry->d_inode, name); | ||
917 | if (err) | ||
918 | goto out; | ||
919 | } | ||
920 | |||
921 | err = reiserfs_xattr_del(dentry->d_inode, name); | 923 | err = reiserfs_xattr_del(dentry->d_inode, name); |
922 | 924 | ||
923 | dentry->d_inode->i_ctime = CURRENT_TIME_SEC; | 925 | dentry->d_inode->i_ctime = CURRENT_TIME_SEC; |
924 | mark_inode_dirty(dentry->d_inode); | 926 | mark_inode_dirty(dentry->d_inode); |
925 | 927 | ||
926 | out: | ||
927 | reiserfs_write_unlock_xattr_i(dentry->d_inode); | ||
928 | return err; | 928 | return err; |
929 | } | 929 | } |
930 | 930 | ||
@@ -986,7 +986,6 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) | |||
986 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 986 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) |
987 | return -EOPNOTSUPP; | 987 | return -EOPNOTSUPP; |
988 | 988 | ||
989 | reiserfs_read_lock_xattr_i(dentry->d_inode); | ||
990 | dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE); | 989 | dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE); |
991 | if (IS_ERR(dir)) { | 990 | if (IS_ERR(dir)) { |
992 | err = PTR_ERR(dir); | 991 | err = PTR_ERR(dir); |
@@ -1005,19 +1004,16 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) | |||
1005 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); | 1004 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); |
1006 | err = xattr_readdir(dir->d_inode, reiserfs_listxattr_filler, &buf); | 1005 | err = xattr_readdir(dir->d_inode, reiserfs_listxattr_filler, &buf); |
1007 | mutex_unlock(&dir->d_inode->i_mutex); | 1006 | mutex_unlock(&dir->d_inode->i_mutex); |
1008 | if (err) | ||
1009 | goto out_dir; | ||
1010 | 1007 | ||
1011 | if (buf.r_pos > buf.r_size && buffer != NULL) | 1008 | if (!err) { |
1012 | err = -ERANGE; | 1009 | if (buf.r_pos > buf.r_size && buffer != NULL) |
1013 | else | 1010 | err = -ERANGE; |
1014 | err = buf.r_pos; | 1011 | else |
1012 | err = buf.r_pos; | ||
1013 | } | ||
1015 | 1014 | ||
1016 | out_dir: | ||
1017 | dput(dir); | 1015 | dput(dir); |
1018 | 1016 | out: | |
1019 | out: | ||
1020 | reiserfs_read_unlock_xattr_i(dentry->d_inode); | ||
1021 | return err; | 1017 | return err; |
1022 | } | 1018 | } |
1023 | 1019 | ||
@@ -1115,12 +1111,8 @@ static int reiserfs_check_acl(struct inode *inode, int mask) | |||
1115 | struct posix_acl *acl; | 1111 | struct posix_acl *acl; |
1116 | int error = -EAGAIN; /* do regular unix permission checks by default */ | 1112 | int error = -EAGAIN; /* do regular unix permission checks by default */ |
1117 | 1113 | ||
1118 | reiserfs_read_lock_xattr_i(inode); | ||
1119 | |||
1120 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); | 1114 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); |
1121 | 1115 | ||
1122 | reiserfs_read_unlock_xattr_i(inode); | ||
1123 | |||
1124 | if (acl) { | 1116 | if (acl) { |
1125 | if (!IS_ERR(acl)) { | 1117 | if (!IS_ERR(acl)) { |
1126 | error = posix_acl_permission(inode, acl, mask); | 1118 | error = posix_acl_permission(inode, acl, mask); |