diff options
Diffstat (limited to 'fs/ext4/xattr.c')
-rw-r--r-- | fs/ext4/xattr.c | 110 |
1 files changed, 69 insertions, 41 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 2cdb98d62980..3a91ebc2b66f 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -61,11 +61,6 @@ | |||
61 | #include "xattr.h" | 61 | #include "xattr.h" |
62 | #include "acl.h" | 62 | #include "acl.h" |
63 | 63 | ||
64 | #define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data)) | ||
65 | #define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr)) | ||
66 | #define BFIRST(bh) ENTRY(BHDR(bh)+1) | ||
67 | #define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) | ||
68 | |||
69 | #ifdef EXT4_XATTR_DEBUG | 64 | #ifdef EXT4_XATTR_DEBUG |
70 | # define ea_idebug(inode, f...) do { \ | 65 | # define ea_idebug(inode, f...) do { \ |
71 | printk(KERN_DEBUG "inode %s:%lu: ", \ | 66 | printk(KERN_DEBUG "inode %s:%lu: ", \ |
@@ -312,7 +307,7 @@ cleanup: | |||
312 | return error; | 307 | return error; |
313 | } | 308 | } |
314 | 309 | ||
315 | static int | 310 | int |
316 | ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, | 311 | ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, |
317 | void *buffer, size_t buffer_size) | 312 | void *buffer, size_t buffer_size) |
318 | { | 313 | { |
@@ -581,21 +576,6 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last, | |||
581 | return (*min_offs - ((void *)last - base) - sizeof(__u32)); | 576 | return (*min_offs - ((void *)last - base) - sizeof(__u32)); |
582 | } | 577 | } |
583 | 578 | ||
584 | struct ext4_xattr_info { | ||
585 | int name_index; | ||
586 | const char *name; | ||
587 | const void *value; | ||
588 | size_t value_len; | ||
589 | }; | ||
590 | |||
591 | struct ext4_xattr_search { | ||
592 | struct ext4_xattr_entry *first; | ||
593 | void *base; | ||
594 | void *end; | ||
595 | struct ext4_xattr_entry *here; | ||
596 | int not_found; | ||
597 | }; | ||
598 | |||
599 | static int | 579 | static int |
600 | ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | 580 | ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) |
601 | { | 581 | { |
@@ -648,9 +628,14 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | |||
648 | size. Just replace. */ | 628 | size. Just replace. */ |
649 | s->here->e_value_size = | 629 | s->here->e_value_size = |
650 | cpu_to_le32(i->value_len); | 630 | cpu_to_le32(i->value_len); |
651 | memset(val + size - EXT4_XATTR_PAD, 0, | 631 | if (i->value == EXT4_ZERO_XATTR_VALUE) { |
652 | EXT4_XATTR_PAD); /* Clear pad bytes. */ | 632 | memset(val, 0, size); |
653 | memcpy(val, i->value, i->value_len); | 633 | } else { |
634 | /* Clear pad bytes first. */ | ||
635 | memset(val + size - EXT4_XATTR_PAD, 0, | ||
636 | EXT4_XATTR_PAD); | ||
637 | memcpy(val, i->value, i->value_len); | ||
638 | } | ||
654 | return 0; | 639 | return 0; |
655 | } | 640 | } |
656 | 641 | ||
@@ -689,9 +674,14 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | |||
689 | size_t size = EXT4_XATTR_SIZE(i->value_len); | 674 | size_t size = EXT4_XATTR_SIZE(i->value_len); |
690 | void *val = s->base + min_offs - size; | 675 | void *val = s->base + min_offs - size; |
691 | s->here->e_value_offs = cpu_to_le16(min_offs - size); | 676 | s->here->e_value_offs = cpu_to_le16(min_offs - size); |
692 | memset(val + size - EXT4_XATTR_PAD, 0, | 677 | if (i->value == EXT4_ZERO_XATTR_VALUE) { |
693 | EXT4_XATTR_PAD); /* Clear the pad bytes. */ | 678 | memset(val, 0, size); |
694 | memcpy(val, i->value, i->value_len); | 679 | } else { |
680 | /* Clear the pad bytes first. */ | ||
681 | memset(val + size - EXT4_XATTR_PAD, 0, | ||
682 | EXT4_XATTR_PAD); | ||
683 | memcpy(val, i->value, i->value_len); | ||
684 | } | ||
695 | } | 685 | } |
696 | } | 686 | } |
697 | return 0; | 687 | return 0; |
@@ -794,7 +784,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
794 | int offset = (char *)s->here - bs->bh->b_data; | 784 | int offset = (char *)s->here - bs->bh->b_data; |
795 | 785 | ||
796 | unlock_buffer(bs->bh); | 786 | unlock_buffer(bs->bh); |
797 | ext4_handle_release_buffer(handle, bs->bh); | ||
798 | if (ce) { | 787 | if (ce) { |
799 | mb_cache_entry_release(ce); | 788 | mb_cache_entry_release(ce); |
800 | ce = NULL; | 789 | ce = NULL; |
@@ -950,14 +939,8 @@ bad_block: | |||
950 | #undef header | 939 | #undef header |
951 | } | 940 | } |
952 | 941 | ||
953 | struct ext4_xattr_ibody_find { | 942 | int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, |
954 | struct ext4_xattr_search s; | 943 | struct ext4_xattr_ibody_find *is) |
955 | struct ext4_iloc iloc; | ||
956 | }; | ||
957 | |||
958 | static int | ||
959 | ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, | ||
960 | struct ext4_xattr_ibody_find *is) | ||
961 | { | 944 | { |
962 | struct ext4_xattr_ibody_header *header; | 945 | struct ext4_xattr_ibody_header *header; |
963 | struct ext4_inode *raw_inode; | 946 | struct ext4_inode *raw_inode; |
@@ -985,10 +968,47 @@ ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, | |||
985 | return 0; | 968 | return 0; |
986 | } | 969 | } |
987 | 970 | ||
988 | static int | 971 | int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, |
989 | ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, | 972 | struct ext4_xattr_info *i, |
990 | struct ext4_xattr_info *i, | 973 | struct ext4_xattr_ibody_find *is) |
991 | struct ext4_xattr_ibody_find *is) | 974 | { |
975 | struct ext4_xattr_ibody_header *header; | ||
976 | struct ext4_xattr_search *s = &is->s; | ||
977 | int error; | ||
978 | |||
979 | if (EXT4_I(inode)->i_extra_isize == 0) | ||
980 | return -ENOSPC; | ||
981 | error = ext4_xattr_set_entry(i, s); | ||
982 | if (error) { | ||
983 | if (error == -ENOSPC && | ||
984 | ext4_has_inline_data(inode)) { | ||
985 | error = ext4_try_to_evict_inline_data(handle, inode, | ||
986 | EXT4_XATTR_LEN(strlen(i->name) + | ||
987 | EXT4_XATTR_SIZE(i->value_len))); | ||
988 | if (error) | ||
989 | return error; | ||
990 | error = ext4_xattr_ibody_find(inode, i, is); | ||
991 | if (error) | ||
992 | return error; | ||
993 | error = ext4_xattr_set_entry(i, s); | ||
994 | } | ||
995 | if (error) | ||
996 | return error; | ||
997 | } | ||
998 | header = IHDR(inode, ext4_raw_inode(&is->iloc)); | ||
999 | if (!IS_LAST_ENTRY(s->first)) { | ||
1000 | header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); | ||
1001 | ext4_set_inode_state(inode, EXT4_STATE_XATTR); | ||
1002 | } else { | ||
1003 | header->h_magic = cpu_to_le32(0); | ||
1004 | ext4_clear_inode_state(inode, EXT4_STATE_XATTR); | ||
1005 | } | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, | ||
1010 | struct ext4_xattr_info *i, | ||
1011 | struct ext4_xattr_ibody_find *is) | ||
992 | { | 1012 | { |
993 | struct ext4_xattr_ibody_header *header; | 1013 | struct ext4_xattr_ibody_header *header; |
994 | struct ext4_xattr_search *s = &is->s; | 1014 | struct ext4_xattr_search *s = &is->s; |
@@ -1144,9 +1164,17 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name, | |||
1144 | { | 1164 | { |
1145 | handle_t *handle; | 1165 | handle_t *handle; |
1146 | int error, retries = 0; | 1166 | int error, retries = 0; |
1167 | int credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb); | ||
1147 | 1168 | ||
1148 | retry: | 1169 | retry: |
1149 | handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); | 1170 | /* |
1171 | * In case of inline data, we may push out the data to a block, | ||
1172 | * So reserve the journal space first. | ||
1173 | */ | ||
1174 | if (ext4_has_inline_data(inode)) | ||
1175 | credits += ext4_writepage_trans_blocks(inode) + 1; | ||
1176 | |||
1177 | handle = ext4_journal_start(inode, credits); | ||
1150 | if (IS_ERR(handle)) { | 1178 | if (IS_ERR(handle)) { |
1151 | error = PTR_ERR(handle); | 1179 | error = PTR_ERR(handle); |
1152 | } else { | 1180 | } else { |