diff options
Diffstat (limited to 'fs/reiserfs/xattr.c')
-rw-r--r-- | fs/reiserfs/xattr.c | 70 |
1 files changed, 35 insertions, 35 deletions
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 57920a4df7a4..62c98829c545 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
@@ -27,6 +27,12 @@ | |||
27 | * these are special cases for filesystem ACLs, they are interpreted by the | 27 | * these are special cases for filesystem ACLs, they are interpreted by the |
28 | * kernel, in addition, they are negatively and positively cached and attached | 28 | * kernel, in addition, they are negatively and positively cached and attached |
29 | * to the inode so that unnecessary lookups are avoided. | 29 | * to the inode so that unnecessary lookups are avoided. |
30 | * | ||
31 | * Locking works like so: | ||
32 | * The xattr root (/.reiserfs_priv/xattrs) is protected by its i_mutex. | ||
33 | * The xattr dir (/.reiserfs_priv/xattrs/<oid>.<gen>) is protected by | ||
34 | * inode->xattr_sem. | ||
35 | * The xattrs themselves are likewise protected by the xattr_sem. | ||
30 | */ | 36 | */ |
31 | 37 | ||
32 | #include <linux/reiserfs_fs.h> | 38 | #include <linux/reiserfs_fs.h> |
@@ -392,16 +398,17 @@ reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, | |||
392 | /* This is called w/ inode->i_mutex downed */ | 398 | /* This is called w/ inode->i_mutex downed */ |
393 | int reiserfs_delete_xattrs(struct inode *inode) | 399 | int reiserfs_delete_xattrs(struct inode *inode) |
394 | { | 400 | { |
395 | struct dentry *dir, *root; | ||
396 | int err = 0; | 401 | int err = 0; |
402 | struct dentry *dir, *root; | ||
403 | struct reiserfs_transaction_handle th; | ||
404 | int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + | ||
405 | 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); | ||
397 | 406 | ||
398 | /* Skip out, an xattr has no xattrs associated with it */ | 407 | /* Skip out, an xattr has no xattrs associated with it */ |
399 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) | 408 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) |
400 | return 0; | 409 | return 0; |
401 | 410 | ||
402 | reiserfs_read_lock_xattrs(inode->i_sb); | ||
403 | dir = open_xa_dir(inode, XATTR_REPLACE); | 411 | dir = open_xa_dir(inode, XATTR_REPLACE); |
404 | reiserfs_read_unlock_xattrs(inode->i_sb); | ||
405 | if (IS_ERR(dir)) { | 412 | if (IS_ERR(dir)) { |
406 | err = PTR_ERR(dir); | 413 | err = PTR_ERR(dir); |
407 | goto out; | 414 | goto out; |
@@ -416,18 +423,26 @@ int reiserfs_delete_xattrs(struct inode *inode) | |||
416 | if (err) | 423 | if (err) |
417 | goto out_dir; | 424 | goto out_dir; |
418 | 425 | ||
419 | /* Leftovers besides . and .. -- that's not good. */ | 426 | /* We start a transaction here to avoid a ABBA situation |
420 | if (dir->d_inode->i_nlink <= 2) { | 427 | * between the xattr root's i_mutex and the journal lock. |
421 | root = open_xa_root(inode->i_sb, XATTR_REPLACE); | 428 | * Inode creation will inherit an ACL, which requires a |
422 | reiserfs_write_lock_xattrs(inode->i_sb); | 429 | * lookup. The lookup locks the xattr root i_mutex with a |
430 | * transaction open. Inode deletion takes teh xattr root | ||
431 | * i_mutex to delete the directory and then starts a | ||
432 | * transaction inside it. Boom. This doesn't incur much | ||
433 | * additional overhead since the reiserfs_rmdir transaction | ||
434 | * will just nest inside the outer transaction. */ | ||
435 | err = journal_begin(&th, inode->i_sb, blocks); | ||
436 | if (!err) { | ||
437 | int jerror; | ||
438 | root = dget(dir->d_parent); | ||
423 | mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR); | 439 | mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR); |
424 | err = xattr_rmdir(root->d_inode, dir); | 440 | err = xattr_rmdir(root->d_inode, dir); |
441 | jerror = journal_end(&th, inode->i_sb, blocks); | ||
425 | mutex_unlock(&root->d_inode->i_mutex); | 442 | mutex_unlock(&root->d_inode->i_mutex); |
426 | reiserfs_write_unlock_xattrs(inode->i_sb); | ||
427 | dput(root); | 443 | dput(root); |
428 | } else { | 444 | |
429 | reiserfs_warning(inode->i_sb, "jdm-20006", | 445 | err = jerror ?: err; |
430 | "Couldn't remove all entries in directory"); | ||
431 | } | 446 | } |
432 | 447 | ||
433 | out_dir: | 448 | out_dir: |
@@ -437,6 +452,9 @@ out: | |||
437 | if (!err) | 452 | if (!err) |
438 | REISERFS_I(inode)->i_flags = | 453 | REISERFS_I(inode)->i_flags = |
439 | REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; | 454 | REISERFS_I(inode)->i_flags & ~i_has_xattr_dir; |
455 | else | ||
456 | reiserfs_warning(inode->i_sb, "jdm-20004", | ||
457 | "Couldn't remove all xattrs (%d)\n", err); | ||
440 | return err; | 458 | return err; |
441 | } | 459 | } |
442 | 460 | ||
@@ -485,9 +503,7 @@ int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) | |||
485 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) | 503 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) |
486 | return 0; | 504 | return 0; |
487 | 505 | ||
488 | reiserfs_read_lock_xattrs(inode->i_sb); | ||
489 | dir = open_xa_dir(inode, XATTR_REPLACE); | 506 | dir = open_xa_dir(inode, XATTR_REPLACE); |
490 | reiserfs_read_unlock_xattrs(inode->i_sb); | ||
491 | if (IS_ERR(dir)) { | 507 | if (IS_ERR(dir)) { |
492 | if (PTR_ERR(dir) != -ENODATA) | 508 | if (PTR_ERR(dir) != -ENODATA) |
493 | err = PTR_ERR(dir); | 509 | err = PTR_ERR(dir); |
@@ -731,6 +747,11 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, | |||
731 | goto out; | 747 | goto out; |
732 | } | 748 | } |
733 | 749 | ||
750 | /* protect against concurrent access. xattrs are backed by | ||
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 | |||
734 | isize = i_size_read(dentry->d_inode); | 755 | isize = i_size_read(dentry->d_inode); |
735 | REISERFS_I(inode)->i_flags |= i_has_xattr_dir; | 756 | REISERFS_I(inode)->i_flags |= i_has_xattr_dir; |
736 | 757 | ||
@@ -798,6 +819,7 @@ reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer, | |||
798 | } | 819 | } |
799 | 820 | ||
800 | out_dput: | 821 | out_dput: |
822 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
801 | dput(dentry); | 823 | dput(dentry); |
802 | 824 | ||
803 | out: | 825 | out: |
@@ -834,7 +856,6 @@ int reiserfs_xattr_del(struct inode *inode, const char *name) | |||
834 | static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char *); | 856 | static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char *); |
835 | /* | 857 | /* |
836 | * Inode operation getxattr() | 858 | * Inode operation getxattr() |
837 | * Preliminary locking: we down dentry->d_inode->i_mutex | ||
838 | */ | 859 | */ |
839 | ssize_t | 860 | ssize_t |
840 | reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, | 861 | reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, |
@@ -848,9 +869,7 @@ reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer, | |||
848 | return -EOPNOTSUPP; | 869 | return -EOPNOTSUPP; |
849 | 870 | ||
850 | reiserfs_read_lock_xattr_i(dentry->d_inode); | 871 | reiserfs_read_lock_xattr_i(dentry->d_inode); |
851 | reiserfs_read_lock_xattrs(dentry->d_sb); | ||
852 | err = xah->get(dentry->d_inode, name, buffer, size); | 872 | err = xah->get(dentry->d_inode, name, buffer, size); |
853 | reiserfs_read_unlock_xattrs(dentry->d_sb); | ||
854 | reiserfs_read_unlock_xattr_i(dentry->d_inode); | 873 | reiserfs_read_unlock_xattr_i(dentry->d_inode); |
855 | return err; | 874 | return err; |
856 | } | 875 | } |
@@ -866,23 +885,13 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
866 | { | 885 | { |
867 | struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); | 886 | struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name); |
868 | int err; | 887 | int err; |
869 | int lock; | ||
870 | 888 | ||
871 | if (!xah || !reiserfs_xattrs(dentry->d_sb) || | 889 | if (!xah || !reiserfs_xattrs(dentry->d_sb) || |
872 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) | 890 | get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1) |
873 | return -EOPNOTSUPP; | 891 | return -EOPNOTSUPP; |
874 | 892 | ||
875 | reiserfs_write_lock_xattr_i(dentry->d_inode); | 893 | reiserfs_write_lock_xattr_i(dentry->d_inode); |
876 | lock = !has_xattr_dir(dentry->d_inode); | ||
877 | if (lock) | ||
878 | reiserfs_write_lock_xattrs(dentry->d_sb); | ||
879 | else | ||
880 | reiserfs_read_lock_xattrs(dentry->d_sb); | ||
881 | err = xah->set(dentry->d_inode, name, value, size, flags); | 894 | err = xah->set(dentry->d_inode, name, value, size, flags); |
882 | if (lock) | ||
883 | reiserfs_write_unlock_xattrs(dentry->d_sb); | ||
884 | else | ||
885 | reiserfs_read_unlock_xattrs(dentry->d_sb); | ||
886 | reiserfs_write_unlock_xattr_i(dentry->d_inode); | 895 | reiserfs_write_unlock_xattr_i(dentry->d_inode); |
887 | return err; | 896 | return err; |
888 | } | 897 | } |
@@ -902,8 +911,6 @@ int reiserfs_removexattr(struct dentry *dentry, const char *name) | |||
902 | return -EOPNOTSUPP; | 911 | return -EOPNOTSUPP; |
903 | 912 | ||
904 | reiserfs_write_lock_xattr_i(dentry->d_inode); | 913 | reiserfs_write_lock_xattr_i(dentry->d_inode); |
905 | reiserfs_read_lock_xattrs(dentry->d_sb); | ||
906 | |||
907 | /* Deletion pre-operation */ | 914 | /* Deletion pre-operation */ |
908 | if (xah->del) { | 915 | if (xah->del) { |
909 | err = xah->del(dentry->d_inode, name); | 916 | err = xah->del(dentry->d_inode, name); |
@@ -917,7 +924,6 @@ int reiserfs_removexattr(struct dentry *dentry, const char *name) | |||
917 | mark_inode_dirty(dentry->d_inode); | 924 | mark_inode_dirty(dentry->d_inode); |
918 | 925 | ||
919 | out: | 926 | out: |
920 | reiserfs_read_unlock_xattrs(dentry->d_sb); | ||
921 | reiserfs_write_unlock_xattr_i(dentry->d_inode); | 927 | reiserfs_write_unlock_xattr_i(dentry->d_inode); |
922 | return err; | 928 | return err; |
923 | } | 929 | } |
@@ -966,8 +972,6 @@ reiserfs_listxattr_filler(void *buf, const char *name, int namelen, | |||
966 | 972 | ||
967 | /* | 973 | /* |
968 | * Inode operation listxattr() | 974 | * Inode operation listxattr() |
969 | * | ||
970 | * Preliminary locking: we down dentry->d_inode->i_mutex | ||
971 | */ | 975 | */ |
972 | ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) | 976 | ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) |
973 | { | 977 | { |
@@ -983,9 +987,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) | |||
983 | return -EOPNOTSUPP; | 987 | return -EOPNOTSUPP; |
984 | 988 | ||
985 | reiserfs_read_lock_xattr_i(dentry->d_inode); | 989 | reiserfs_read_lock_xattr_i(dentry->d_inode); |
986 | reiserfs_read_lock_xattrs(dentry->d_sb); | ||
987 | dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE); | 990 | dir = open_xa_dir(dentry->d_inode, XATTR_REPLACE); |
988 | reiserfs_read_unlock_xattrs(dentry->d_sb); | ||
989 | if (IS_ERR(dir)) { | 991 | if (IS_ERR(dir)) { |
990 | err = PTR_ERR(dir); | 992 | err = PTR_ERR(dir); |
991 | if (err == -ENODATA) | 993 | if (err == -ENODATA) |
@@ -1114,11 +1116,9 @@ static int reiserfs_check_acl(struct inode *inode, int mask) | |||
1114 | int error = -EAGAIN; /* do regular unix permission checks by default */ | 1116 | int error = -EAGAIN; /* do regular unix permission checks by default */ |
1115 | 1117 | ||
1116 | reiserfs_read_lock_xattr_i(inode); | 1118 | reiserfs_read_lock_xattr_i(inode); |
1117 | reiserfs_read_lock_xattrs(inode->i_sb); | ||
1118 | 1119 | ||
1119 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); | 1120 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); |
1120 | 1121 | ||
1121 | reiserfs_read_unlock_xattrs(inode->i_sb); | ||
1122 | reiserfs_read_unlock_xattr_i(inode); | 1122 | reiserfs_read_unlock_xattr_i(inode); |
1123 | 1123 | ||
1124 | if (acl) { | 1124 | if (acl) { |