aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/inode.c63
-rw-r--r--fs/ext4/xattr.c274
-rw-r--r--fs/ext4/xattr.h17
-rw-r--r--include/linux/ext4_fs.h1
4 files changed, 347 insertions, 8 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b83f91edebd1..f6d8528c4f55 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3106,6 +3106,39 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
3106} 3106}
3107 3107
3108/* 3108/*
3109 * Expand an inode by new_extra_isize bytes.
3110 * Returns 0 on success or negative error number on failure.
3111 */
3112int ext4_expand_extra_isize(struct inode *inode, unsigned int new_extra_isize,
3113 struct ext4_iloc iloc, handle_t *handle)
3114{
3115 struct ext4_inode *raw_inode;
3116 struct ext4_xattr_ibody_header *header;
3117 struct ext4_xattr_entry *entry;
3118
3119 if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
3120 return 0;
3121
3122 raw_inode = ext4_raw_inode(&iloc);
3123
3124 header = IHDR(inode, raw_inode);
3125 entry = IFIRST(header);
3126
3127 /* No extended attributes present */
3128 if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR) ||
3129 header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
3130 memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
3131 new_extra_isize);
3132 EXT4_I(inode)->i_extra_isize = new_extra_isize;
3133 return 0;
3134 }
3135
3136 /* try to expand with EAs present */
3137 return ext4_expand_extra_isize_ea(inode, new_extra_isize,
3138 raw_inode, handle);
3139}
3140
3141/*
3109 * What we do here is to mark the in-core inode as clean with respect to inode 3142 * What we do here is to mark the in-core inode as clean with respect to inode
3110 * dirtiness (it may still be data-dirty). 3143 * dirtiness (it may still be data-dirty).
3111 * This means that the in-core inode may be reaped by prune_icache 3144 * This means that the in-core inode may be reaped by prune_icache
@@ -3129,10 +3162,38 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
3129int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) 3162int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
3130{ 3163{
3131 struct ext4_iloc iloc; 3164 struct ext4_iloc iloc;
3132 int err; 3165 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
3166 static unsigned int mnt_count;
3167 int err, ret;
3133 3168
3134 might_sleep(); 3169 might_sleep();
3135 err = ext4_reserve_inode_write(handle, inode, &iloc); 3170 err = ext4_reserve_inode_write(handle, inode, &iloc);
3171 if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
3172 !(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) {
3173 /*
3174 * We need extra buffer credits since we may write into EA block
3175 * with this same handle. If journal_extend fails, then it will
3176 * only result in a minor loss of functionality for that inode.
3177 * If this is felt to be critical, then e2fsck should be run to
3178 * force a large enough s_min_extra_isize.
3179 */
3180 if ((jbd2_journal_extend(handle,
3181 EXT4_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {
3182 ret = ext4_expand_extra_isize(inode,
3183 sbi->s_want_extra_isize,
3184 iloc, handle);
3185 if (ret) {
3186 EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
3187 if (mnt_count != sbi->s_es->s_mnt_count) {
3188 ext4_warning(inode->i_sb, __FUNCTION__,
3189 "Unable to expand inode %lu. Delete"
3190 " some EAs or run e2fsck.",
3191 inode->i_ino);
3192 mnt_count = sbi->s_es->s_mnt_count;
3193 }
3194 }
3195 }
3196 }
3136 if (!err) 3197 if (!err)
3137 err = ext4_mark_iloc_dirty(handle, inode, &iloc); 3198 err = ext4_mark_iloc_dirty(handle, inode, &iloc);
3138 return err; 3199 return err;
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index fe16a569d06b..b10d68fffb55 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -66,13 +66,6 @@
66#define BFIRST(bh) ENTRY(BHDR(bh)+1) 66#define BFIRST(bh) ENTRY(BHDR(bh)+1)
67#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) 67#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
68 68
69#define IHDR(inode, raw_inode) \
70 ((struct ext4_xattr_ibody_header *) \
71 ((void *)raw_inode + \
72 EXT4_GOOD_OLD_INODE_SIZE + \
73 EXT4_I(inode)->i_extra_isize))
74#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
75
76#ifdef EXT4_XATTR_DEBUG 69#ifdef EXT4_XATTR_DEBUG
77# define ea_idebug(inode, f...) do { \ 70# define ea_idebug(inode, f...) do { \
78 printk(KERN_DEBUG "inode %s:%lu: ", \ 71 printk(KERN_DEBUG "inode %s:%lu: ", \
@@ -508,6 +501,24 @@ out:
508 return; 501 return;
509} 502}
510 503
504/*
505 * Find the available free space for EAs. This also returns the total number of
506 * bytes used by EA entries.
507 */
508static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
509 size_t *min_offs, void *base, int *total)
510{
511 for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
512 *total += EXT4_XATTR_LEN(last->e_name_len);
513 if (!last->e_value_block && last->e_value_size) {
514 size_t offs = le16_to_cpu(last->e_value_offs);
515 if (offs < *min_offs)
516 *min_offs = offs;
517 }
518 }
519 return (*min_offs - ((void *)last - base) - sizeof(__u32));
520}
521
511struct ext4_xattr_info { 522struct ext4_xattr_info {
512 int name_index; 523 int name_index;
513 const char *name; 524 const char *name;
@@ -1014,6 +1025,8 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
1014 if (!error) { 1025 if (!error) {
1015 ext4_xattr_update_super_block(handle, inode->i_sb); 1026 ext4_xattr_update_super_block(handle, inode->i_sb);
1016 inode->i_ctime = ext4_current_time(inode); 1027 inode->i_ctime = ext4_current_time(inode);
1028 if (!value)
1029 EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
1017 error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 1030 error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
1018 /* 1031 /*
1019 * The bh is consumed by ext4_mark_iloc_dirty, even with 1032 * The bh is consumed by ext4_mark_iloc_dirty, even with
@@ -1067,6 +1080,253 @@ retry:
1067} 1080}
1068 1081
1069/* 1082/*
1083 * Shift the EA entries in the inode to create space for the increased
1084 * i_extra_isize.
1085 */
1086static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
1087 int value_offs_shift, void *to,
1088 void *from, size_t n, int blocksize)
1089{
1090 struct ext4_xattr_entry *last = entry;
1091 int new_offs;
1092
1093 /* Adjust the value offsets of the entries */
1094 for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
1095 if (!last->e_value_block && last->e_value_size) {
1096 new_offs = le16_to_cpu(last->e_value_offs) +
1097 value_offs_shift;
1098 BUG_ON(new_offs + le32_to_cpu(last->e_value_size)
1099 > blocksize);
1100 last->e_value_offs = cpu_to_le16(new_offs);
1101 }
1102 }
1103 /* Shift the entries by n bytes */
1104 memmove(to, from, n);
1105}
1106
1107/*
1108 * Expand an inode by new_extra_isize bytes when EAs are present.
1109 * Returns 0 on success or negative error number on failure.
1110 */
1111int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
1112 struct ext4_inode *raw_inode, handle_t *handle)
1113{
1114 struct ext4_xattr_ibody_header *header;
1115 struct ext4_xattr_entry *entry, *last, *first;
1116 struct buffer_head *bh = NULL;
1117 struct ext4_xattr_ibody_find *is = NULL;
1118 struct ext4_xattr_block_find *bs = NULL;
1119 char *buffer = NULL, *b_entry_name = NULL;
1120 size_t min_offs, free;
1121 int total_ino, total_blk;
1122 void *base, *start, *end;
1123 int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
1124 int s_min_extra_isize = EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize;
1125
1126 down_write(&EXT4_I(inode)->xattr_sem);
1127retry:
1128 if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) {
1129 up_write(&EXT4_I(inode)->xattr_sem);
1130 return 0;
1131 }
1132
1133 header = IHDR(inode, raw_inode);
1134 entry = IFIRST(header);
1135
1136 /*
1137 * Check if enough free space is available in the inode to shift the
1138 * entries ahead by new_extra_isize.
1139 */
1140
1141 base = start = entry;
1142 end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
1143 min_offs = end - base;
1144 last = entry;
1145 total_ino = sizeof(struct ext4_xattr_ibody_header);
1146
1147 free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
1148 if (free >= new_extra_isize) {
1149 entry = IFIRST(header);
1150 ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize
1151 - new_extra_isize, (void *)raw_inode +
1152 EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize,
1153 (void *)header, total_ino,
1154 inode->i_sb->s_blocksize);
1155 EXT4_I(inode)->i_extra_isize = new_extra_isize;
1156 error = 0;
1157 goto cleanup;
1158 }
1159
1160 /*
1161 * Enough free space isn't available in the inode, check if
1162 * EA block can hold new_extra_isize bytes.
1163 */
1164 if (EXT4_I(inode)->i_file_acl) {
1165 bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
1166 error = -EIO;
1167 if (!bh)
1168 goto cleanup;
1169 if (ext4_xattr_check_block(bh)) {
1170 ext4_error(inode->i_sb, __FUNCTION__,
1171 "inode %lu: bad block %llu", inode->i_ino,
1172 EXT4_I(inode)->i_file_acl);
1173 error = -EIO;
1174 goto cleanup;
1175 }
1176 base = BHDR(bh);
1177 first = BFIRST(bh);
1178 end = bh->b_data + bh->b_size;
1179 min_offs = end - base;
1180 free = ext4_xattr_free_space(first, &min_offs, base,
1181 &total_blk);
1182 if (free < new_extra_isize) {
1183 if (!tried_min_extra_isize && s_min_extra_isize) {
1184 tried_min_extra_isize++;
1185 new_extra_isize = s_min_extra_isize;
1186 brelse(bh);
1187 goto retry;
1188 }
1189 error = -1;
1190 goto cleanup;
1191 }
1192 } else {
1193 free = inode->i_sb->s_blocksize;
1194 }
1195
1196 while (new_extra_isize > 0) {
1197 size_t offs, size, entry_size;
1198 struct ext4_xattr_entry *small_entry = NULL;
1199 struct ext4_xattr_info i = {
1200 .value = NULL,
1201 .value_len = 0,
1202 };
1203 unsigned int total_size; /* EA entry size + value size */
1204 unsigned int shift_bytes; /* No. of bytes to shift EAs by? */
1205 unsigned int min_total_size = ~0U;
1206
1207 is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
1208 bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
1209 if (!is || !bs) {
1210 error = -ENOMEM;
1211 goto cleanup;
1212 }
1213
1214 is->s.not_found = -ENODATA;
1215 bs->s.not_found = -ENODATA;
1216 is->iloc.bh = NULL;
1217 bs->bh = NULL;
1218
1219 last = IFIRST(header);
1220 /* Find the entry best suited to be pushed into EA block */
1221 entry = NULL;
1222 for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
1223 total_size =
1224 EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
1225 EXT4_XATTR_LEN(last->e_name_len);
1226 if (total_size <= free && total_size < min_total_size) {
1227 if (total_size < new_extra_isize) {
1228 small_entry = last;
1229 } else {
1230 entry = last;
1231 min_total_size = total_size;
1232 }
1233 }
1234 }
1235
1236 if (entry == NULL) {
1237 if (small_entry) {
1238 entry = small_entry;
1239 } else {
1240 if (!tried_min_extra_isize &&
1241 s_min_extra_isize) {
1242 tried_min_extra_isize++;
1243 new_extra_isize = s_min_extra_isize;
1244 goto retry;
1245 }
1246 error = -1;
1247 goto cleanup;
1248 }
1249 }
1250 offs = le16_to_cpu(entry->e_value_offs);
1251 size = le32_to_cpu(entry->e_value_size);
1252 entry_size = EXT4_XATTR_LEN(entry->e_name_len);
1253 i.name_index = entry->e_name_index,
1254 buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS);
1255 b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
1256 if (!buffer || !b_entry_name) {
1257 error = -ENOMEM;
1258 goto cleanup;
1259 }
1260 /* Save the entry name and the entry value */
1261 memcpy(buffer, (void *)IFIRST(header) + offs,
1262 EXT4_XATTR_SIZE(size));
1263 memcpy(b_entry_name, entry->e_name, entry->e_name_len);
1264 b_entry_name[entry->e_name_len] = '\0';
1265 i.name = b_entry_name;
1266
1267 error = ext4_get_inode_loc(inode, &is->iloc);
1268 if (error)
1269 goto cleanup;
1270
1271 error = ext4_xattr_ibody_find(inode, &i, is);
1272 if (error)
1273 goto cleanup;
1274
1275 /* Remove the chosen entry from the inode */
1276 error = ext4_xattr_ibody_set(handle, inode, &i, is);
1277
1278 entry = IFIRST(header);
1279 if (entry_size + EXT4_XATTR_SIZE(size) >= new_extra_isize)
1280 shift_bytes = new_extra_isize;
1281 else
1282 shift_bytes = entry_size + size;
1283 /* Adjust the offsets and shift the remaining entries ahead */
1284 ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize -
1285 shift_bytes, (void *)raw_inode +
1286 EXT4_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
1287 (void *)header, total_ino - entry_size,
1288 inode->i_sb->s_blocksize);
1289
1290 extra_isize += shift_bytes;
1291 new_extra_isize -= shift_bytes;
1292 EXT4_I(inode)->i_extra_isize = extra_isize;
1293
1294 i.name = b_entry_name;
1295 i.value = buffer;
1296 i.value_len = cpu_to_le32(size);
1297 error = ext4_xattr_block_find(inode, &i, bs);
1298 if (error)
1299 goto cleanup;
1300
1301 /* Add entry which was removed from the inode into the block */
1302 error = ext4_xattr_block_set(handle, inode, &i, bs);
1303 if (error)
1304 goto cleanup;
1305 kfree(b_entry_name);
1306 kfree(buffer);
1307 brelse(is->iloc.bh);
1308 kfree(is);
1309 kfree(bs);
1310 }
1311 brelse(bh);
1312 up_write(&EXT4_I(inode)->xattr_sem);
1313 return 0;
1314
1315cleanup:
1316 kfree(b_entry_name);
1317 kfree(buffer);
1318 if (is)
1319 brelse(is->iloc.bh);
1320 kfree(is);
1321 kfree(bs);
1322 brelse(bh);
1323 up_write(&EXT4_I(inode)->xattr_sem);
1324 return error;
1325}
1326
1327
1328
1329/*
1070 * ext4_xattr_delete_inode() 1330 * ext4_xattr_delete_inode()
1071 * 1331 *
1072 * Free extended attribute resources associated with this inode. This 1332 * Free extended attribute resources associated with this inode. This
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 79432b35398f..d7f5d6a12651 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -56,6 +56,13 @@ struct ext4_xattr_entry {
56#define EXT4_XATTR_SIZE(size) \ 56#define EXT4_XATTR_SIZE(size) \
57 (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND) 57 (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
58 58
59#define IHDR(inode, raw_inode) \
60 ((struct ext4_xattr_ibody_header *) \
61 ((void *)raw_inode + \
62 EXT4_GOOD_OLD_INODE_SIZE + \
63 EXT4_I(inode)->i_extra_isize))
64#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
65
59# ifdef CONFIG_EXT4DEV_FS_XATTR 66# ifdef CONFIG_EXT4DEV_FS_XATTR
60 67
61extern struct xattr_handler ext4_xattr_user_handler; 68extern struct xattr_handler ext4_xattr_user_handler;
@@ -74,6 +81,9 @@ extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *,
74extern void ext4_xattr_delete_inode(handle_t *, struct inode *); 81extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
75extern void ext4_xattr_put_super(struct super_block *); 82extern void ext4_xattr_put_super(struct super_block *);
76 83
84extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
85 struct ext4_inode *raw_inode, handle_t *handle);
86
77extern int init_ext4_xattr(void); 87extern int init_ext4_xattr(void);
78extern void exit_ext4_xattr(void); 88extern void exit_ext4_xattr(void);
79 89
@@ -129,6 +139,13 @@ exit_ext4_xattr(void)
129{ 139{
130} 140}
131 141
142static inline int
143ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
144 struct ext4_inode *raw_inode, handle_t *handle)
145{
146 return -EOPNOTSUPP;
147}
148
132#define ext4_xattr_handlers NULL 149#define ext4_xattr_handlers NULL
133 150
134# endif /* CONFIG_EXT4DEV_FS_XATTR */ 151# endif /* CONFIG_EXT4DEV_FS_XATTR */
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
index df5e38faa15f..52dcc24dd986 100644
--- a/include/linux/ext4_fs.h
+++ b/include/linux/ext4_fs.h
@@ -202,6 +202,7 @@ struct ext4_group_desc
202#define EXT4_STATE_JDATA 0x00000001 /* journaled data exists */ 202#define EXT4_STATE_JDATA 0x00000001 /* journaled data exists */
203#define EXT4_STATE_NEW 0x00000002 /* inode is newly created */ 203#define EXT4_STATE_NEW 0x00000002 /* inode is newly created */
204#define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */ 204#define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */
205#define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */
205 206
206/* Used to pass group descriptor data when online resize is done */ 207/* Used to pass group descriptor data when online resize is done */
207struct ext4_new_group_input { 208struct ext4_new_group_input {