aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/xattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/xattr.c')
-rw-r--r--fs/ext4/xattr.c110
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
315static int 310int
316ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, 311ext4_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
584struct ext4_xattr_info {
585 int name_index;
586 const char *name;
587 const void *value;
588 size_t value_len;
589};
590
591struct 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
599static int 579static int
600ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) 580ext4_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
953struct ext4_xattr_ibody_find { 942int 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
958static int
959ext4_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
988static int 971int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
989ext4_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
1009static 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
1148retry: 1169retry:
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 {