aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/ext4.h10
-rw-r--r--fs/ext4/inline.c377
-rw-r--r--fs/ext4/namei.c34
-rw-r--r--fs/ext4/xattr.h19
4 files changed, 430 insertions, 10 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 8e9e94cf1bca..689ce1d696b8 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1616,6 +1616,11 @@ struct ext4_dir_entry_tail {
1616 __le32 det_checksum; /* crc32c(uuid+inum+dirblock) */ 1616 __le32 det_checksum; /* crc32c(uuid+inum+dirblock) */
1617}; 1617};
1618 1618
1619#define EXT4_DIRENT_TAIL(block, blocksize) \
1620 ((struct ext4_dir_entry_tail *)(((void *)(block)) + \
1621 ((blocksize) - \
1622 sizeof(struct ext4_dir_entry_tail))))
1623
1619/* 1624/*
1620 * Ext4 directory file types. Only the low 3 bits are used. The 1625 * Ext4 directory file types. Only the low 3 bits are used. The
1621 * other bits are reserved for now. 1626 * other bits are reserved for now.
@@ -2435,6 +2440,11 @@ extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
2435 struct ext4_dir_entry_2 *de, 2440 struct ext4_dir_entry_2 *de,
2436 int blocksize, int csum_size, 2441 int blocksize, int csum_size,
2437 unsigned int parent_ino, int dotdot_real_len); 2442 unsigned int parent_ino, int dotdot_real_len);
2443extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
2444 unsigned int blocksize);
2445extern int ext4_handle_dirty_dirent_node(handle_t *handle,
2446 struct inode *inode,
2447 struct buffer_head *bh);
2438 2448
2439/* symlink.c */ 2449/* symlink.c */
2440extern const struct inode_operations ext4_symlink_inode_operations; 2450extern const struct inode_operations ext4_symlink_inode_operations;
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 65f7ffb5437f..bf7322818738 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -18,6 +18,7 @@
18 18
19#define EXT4_XATTR_SYSTEM_DATA "data" 19#define EXT4_XATTR_SYSTEM_DATA "data"
20#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS)) 20#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
21#define EXT4_INLINE_DOTDOT_SIZE 4
21 22
22int ext4_get_inline_size(struct inode *inode) 23int ext4_get_inline_size(struct inode *inode)
23{ 24{
@@ -949,6 +950,382 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
949 return copied; 950 return copied;
950} 951}
951 952
953#ifdef INLINE_DIR_DEBUG
954void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh,
955 void *inline_start, int inline_size)
956{
957 int offset;
958 unsigned short de_len;
959 struct ext4_dir_entry_2 *de = inline_start;
960 void *dlimit = inline_start + inline_size;
961
962 trace_printk("inode %lu\n", dir->i_ino);
963 offset = 0;
964 while ((void *)de < dlimit) {
965 de_len = ext4_rec_len_from_disk(de->rec_len, inline_size);
966 trace_printk("de: off %u rlen %u name %*.s nlen %u ino %u\n",
967 offset, de_len, de->name_len, de->name,
968 de->name_len, le32_to_cpu(de->inode));
969 if (ext4_check_dir_entry(dir, NULL, de, bh,
970 inline_start, inline_size, offset))
971 BUG();
972
973 offset += de_len;
974 de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
975 }
976}
977#else
978#define ext4_show_inline_dir(dir, bh, inline_start, inline_size)
979#endif
980
981/*
982 * Add a new entry into a inline dir.
983 * It will return -ENOSPC if no space is available, and -EIO
984 * and -EEXIST if directory entry already exists.
985 */
986static int ext4_add_dirent_to_inline(handle_t *handle,
987 struct dentry *dentry,
988 struct inode *inode,
989 struct ext4_iloc *iloc,
990 void *inline_start, int inline_size)
991{
992 struct inode *dir = dentry->d_parent->d_inode;
993 const char *name = dentry->d_name.name;
994 int namelen = dentry->d_name.len;
995 unsigned short reclen;
996 int err;
997 struct ext4_dir_entry_2 *de;
998
999 reclen = EXT4_DIR_REC_LEN(namelen);
1000 err = ext4_find_dest_de(dir, inode, iloc->bh,
1001 inline_start, inline_size,
1002 name, namelen, &de);
1003 if (err)
1004 return err;
1005
1006 err = ext4_journal_get_write_access(handle, iloc->bh);
1007 if (err)
1008 return err;
1009 ext4_insert_dentry(inode, de, inline_size, name, namelen);
1010
1011 ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size);
1012
1013 /*
1014 * XXX shouldn't update any times until successful
1015 * completion of syscall, but too many callers depend
1016 * on this.
1017 *
1018 * XXX similarly, too many callers depend on
1019 * ext4_new_inode() setting the times, but error
1020 * recovery deletes the inode, so the worst that can
1021 * happen is that the times are slightly out of date
1022 * and/or different from the directory change time.
1023 */
1024 dir->i_mtime = dir->i_ctime = ext4_current_time(dir);
1025 ext4_update_dx_flag(dir);
1026 dir->i_version++;
1027 ext4_mark_inode_dirty(handle, dir);
1028 return 1;
1029}
1030
1031static void *ext4_get_inline_xattr_pos(struct inode *inode,
1032 struct ext4_iloc *iloc)
1033{
1034 struct ext4_xattr_entry *entry;
1035 struct ext4_xattr_ibody_header *header;
1036
1037 BUG_ON(!EXT4_I(inode)->i_inline_off);
1038
1039 header = IHDR(inode, ext4_raw_inode(iloc));
1040 entry = (struct ext4_xattr_entry *)((void *)ext4_raw_inode(iloc) +
1041 EXT4_I(inode)->i_inline_off);
1042
1043 return (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs);
1044}
1045
1046/* Set the final de to cover the whole block. */
1047static void ext4_update_final_de(void *de_buf, int old_size, int new_size)
1048{
1049 struct ext4_dir_entry_2 *de, *prev_de;
1050 void *limit;
1051 int de_len;
1052
1053 de = (struct ext4_dir_entry_2 *)de_buf;
1054 if (old_size) {
1055 limit = de_buf + old_size;
1056 do {
1057 prev_de = de;
1058 de_len = ext4_rec_len_from_disk(de->rec_len, old_size);
1059 de_buf += de_len;
1060 de = (struct ext4_dir_entry_2 *)de_buf;
1061 } while (de_buf < limit);
1062
1063 prev_de->rec_len = ext4_rec_len_to_disk(de_len + new_size -
1064 old_size, new_size);
1065 } else {
1066 /* this is just created, so create an empty entry. */
1067 de->inode = 0;
1068 de->rec_len = ext4_rec_len_to_disk(new_size, new_size);
1069 }
1070}
1071
1072static int ext4_update_inline_dir(handle_t *handle, struct inode *dir,
1073 struct ext4_iloc *iloc)
1074{
1075 int ret;
1076 int old_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE;
1077 int new_size = get_max_inline_xattr_value_size(dir, iloc);
1078
1079 if (new_size - old_size <= EXT4_DIR_REC_LEN(1))
1080 return -ENOSPC;
1081
1082 ret = ext4_update_inline_data(handle, dir,
1083 new_size + EXT4_MIN_INLINE_DATA_SIZE);
1084 if (ret)
1085 return ret;
1086
1087 ext4_update_final_de(ext4_get_inline_xattr_pos(dir, iloc), old_size,
1088 EXT4_I(dir)->i_inline_size -
1089 EXT4_MIN_INLINE_DATA_SIZE);
1090 dir->i_size = EXT4_I(dir)->i_disksize = EXT4_I(dir)->i_inline_size;
1091 return 0;
1092}
1093
1094static void ext4_restore_inline_data(handle_t *handle, struct inode *inode,
1095 struct ext4_iloc *iloc,
1096 void *buf, int inline_size)
1097{
1098 ext4_create_inline_data(handle, inode, inline_size);
1099 ext4_write_inline_data(inode, iloc, buf, 0, inline_size);
1100 ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
1101}
1102
1103static int ext4_finish_convert_inline_dir(handle_t *handle,
1104 struct inode *inode,
1105 struct buffer_head *dir_block,
1106 void *buf,
1107 int inline_size)
1108{
1109 int err, csum_size = 0, header_size = 0;
1110 struct ext4_dir_entry_2 *de;
1111 struct ext4_dir_entry_tail *t;
1112 void *target = dir_block->b_data;
1113
1114 /*
1115 * First create "." and ".." and then copy the dir information
1116 * back to the block.
1117 */
1118 de = (struct ext4_dir_entry_2 *)target;
1119 de = ext4_init_dot_dotdot(inode, de,
1120 inode->i_sb->s_blocksize, csum_size,
1121 le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode), 1);
1122 header_size = (void *)de - target;
1123
1124 memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE,
1125 inline_size - EXT4_INLINE_DOTDOT_SIZE);
1126
1127 if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
1128 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
1129 csum_size = sizeof(struct ext4_dir_entry_tail);
1130
1131 inode->i_size = inode->i_sb->s_blocksize;
1132 i_size_write(inode, inode->i_sb->s_blocksize);
1133 EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
1134 ext4_update_final_de(dir_block->b_data,
1135 inline_size - EXT4_INLINE_DOTDOT_SIZE + header_size,
1136 inode->i_sb->s_blocksize - csum_size);
1137
1138 if (csum_size) {
1139 t = EXT4_DIRENT_TAIL(dir_block->b_data,
1140 inode->i_sb->s_blocksize);
1141 initialize_dirent_tail(t, inode->i_sb->s_blocksize);
1142 }
1143 set_buffer_uptodate(dir_block);
1144 err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
1145 if (err)
1146 goto out;
1147 set_buffer_verified(dir_block);
1148out:
1149 return err;
1150}
1151
1152static int ext4_convert_inline_data_nolock(handle_t *handle,
1153 struct inode *inode,
1154 struct ext4_iloc *iloc)
1155{
1156 int error;
1157 void *buf = NULL;
1158 struct buffer_head *data_bh = NULL;
1159 struct ext4_map_blocks map;
1160 int inline_size;
1161
1162 inline_size = ext4_get_inline_size(inode);
1163 buf = kmalloc(inline_size, GFP_NOFS);
1164 if (!buf) {
1165 error = -ENOMEM;
1166 goto out;
1167 }
1168
1169 error = ext4_read_inline_data(inode, buf, inline_size, iloc);
1170 if (error < 0)
1171 goto out;
1172
1173 error = ext4_destroy_inline_data_nolock(handle, inode);
1174 if (error)
1175 goto out;
1176
1177 map.m_lblk = 0;
1178 map.m_len = 1;
1179 map.m_flags = 0;
1180 error = ext4_map_blocks(handle, inode, &map, EXT4_GET_BLOCKS_CREATE);
1181 if (error < 0)
1182 goto out_restore;
1183 if (!(map.m_flags & EXT4_MAP_MAPPED)) {
1184 error = -EIO;
1185 goto out_restore;
1186 }
1187
1188 data_bh = sb_getblk(inode->i_sb, map.m_pblk);
1189 if (!data_bh) {
1190 error = -EIO;
1191 goto out_restore;
1192 }
1193
1194 lock_buffer(data_bh);
1195 error = ext4_journal_get_create_access(handle, data_bh);
1196 if (error) {
1197 unlock_buffer(data_bh);
1198 error = -EIO;
1199 goto out_restore;
1200 }
1201 memset(data_bh->b_data, 0, inode->i_sb->s_blocksize);
1202
1203 if (!S_ISDIR(inode->i_mode)) {
1204 memcpy(data_bh->b_data, buf, inline_size);
1205 set_buffer_uptodate(data_bh);
1206 error = ext4_handle_dirty_metadata(handle,
1207 inode, data_bh);
1208 } else {
1209 error = ext4_finish_convert_inline_dir(handle, inode, data_bh,
1210 buf, inline_size);
1211 }
1212
1213 unlock_buffer(data_bh);
1214out_restore:
1215 if (error)
1216 ext4_restore_inline_data(handle, inode, iloc, buf, inline_size);
1217
1218out:
1219 brelse(data_bh);
1220 kfree(buf);
1221 return error;
1222}
1223
1224/*
1225 * Try to add the new entry to the inline data.
1226 * If succeeds, return 0. If not, extended the inline dir and copied data to
1227 * the new created block.
1228 */
1229int ext4_try_add_inline_entry(handle_t *handle, struct dentry *dentry,
1230 struct inode *inode)
1231{
1232 int ret, inline_size;
1233 void *inline_start;
1234 struct ext4_iloc iloc;
1235 struct inode *dir = dentry->d_parent->d_inode;
1236
1237 ret = ext4_get_inode_loc(dir, &iloc);
1238 if (ret)
1239 return ret;
1240
1241 down_write(&EXT4_I(dir)->xattr_sem);
1242 if (!ext4_has_inline_data(dir))
1243 goto out;
1244
1245 inline_start = (void *)ext4_raw_inode(&iloc)->i_block +
1246 EXT4_INLINE_DOTDOT_SIZE;
1247 inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE;
1248
1249 ret = ext4_add_dirent_to_inline(handle, dentry, inode, &iloc,
1250 inline_start, inline_size);
1251 if (ret != -ENOSPC)
1252 goto out;
1253
1254 /* check whether it can be inserted to inline xattr space. */
1255 inline_size = EXT4_I(dir)->i_inline_size -
1256 EXT4_MIN_INLINE_DATA_SIZE;
1257 if (!inline_size) {
1258 /* Try to use the xattr space.*/
1259 ret = ext4_update_inline_dir(handle, dir, &iloc);
1260 if (ret && ret != -ENOSPC)
1261 goto out;
1262
1263 inline_size = EXT4_I(dir)->i_inline_size -
1264 EXT4_MIN_INLINE_DATA_SIZE;
1265 }
1266
1267 if (inline_size) {
1268 inline_start = ext4_get_inline_xattr_pos(dir, &iloc);
1269
1270 ret = ext4_add_dirent_to_inline(handle, dentry, inode, &iloc,
1271 inline_start, inline_size);
1272
1273 if (ret != -ENOSPC)
1274 goto out;
1275 }
1276
1277 /*
1278 * The inline space is filled up, so create a new block for it.
1279 * As the extent tree will be created, we have to save the inline
1280 * dir first.
1281 */
1282 ret = ext4_convert_inline_data_nolock(handle, dir, &iloc);
1283
1284out:
1285 ext4_mark_inode_dirty(handle, dir);
1286 up_write(&EXT4_I(dir)->xattr_sem);
1287 brelse(iloc.bh);
1288 return ret;
1289}
1290
1291/*
1292 * Try to create the inline data for the new dir.
1293 * If it succeeds, return 0, otherwise return the error.
1294 * In case of ENOSPC, the caller should create the normal disk layout dir.
1295 */
1296int ext4_try_create_inline_dir(handle_t *handle, struct inode *parent,
1297 struct inode *inode)
1298{
1299 int ret, inline_size = EXT4_MIN_INLINE_DATA_SIZE;
1300 struct ext4_iloc iloc;
1301 struct ext4_dir_entry_2 *de;
1302
1303 ret = ext4_get_inode_loc(inode, &iloc);
1304 if (ret)
1305 return ret;
1306
1307 ret = ext4_prepare_inline_data(handle, inode, inline_size);
1308 if (ret)
1309 goto out;
1310
1311 /*
1312 * For inline dir, we only save the inode information for the ".."
1313 * and create a fake dentry to cover the left space.
1314 */
1315 de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block;
1316 de->inode = cpu_to_le32(parent->i_ino);
1317 de = (struct ext4_dir_entry_2 *)((void *)de + EXT4_INLINE_DOTDOT_SIZE);
1318 de->inode = 0;
1319 de->rec_len = ext4_rec_len_to_disk(
1320 inline_size - EXT4_INLINE_DOTDOT_SIZE,
1321 inline_size);
1322 set_nlink(inode, 2);
1323 inode->i_size = EXT4_I(inode)->i_disksize = inline_size;
1324out:
1325 brelse(iloc.bh);
1326 return ret;
1327}
1328
952int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) 1329int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
953{ 1330{
954 int ret; 1331 int ret;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index bb9259d20b55..3cde36bd8020 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -202,13 +202,8 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
202 struct inode *inode); 202 struct inode *inode);
203 203
204/* checksumming functions */ 204/* checksumming functions */
205#define EXT4_DIRENT_TAIL(block, blocksize) \ 205void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
206 ((struct ext4_dir_entry_tail *)(((void *)(block)) + \ 206 unsigned int blocksize)
207 ((blocksize) - \
208 sizeof(struct ext4_dir_entry_tail))))
209
210static void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
211 unsigned int blocksize)
212{ 207{
213 memset(t, 0, sizeof(struct ext4_dir_entry_tail)); 208 memset(t, 0, sizeof(struct ext4_dir_entry_tail));
214 t->det_rec_len = ext4_rec_len_to_disk( 209 t->det_rec_len = ext4_rec_len_to_disk(
@@ -307,9 +302,9 @@ static void ext4_dirent_csum_set(struct inode *inode,
307 (void *)t - (void *)dirent); 302 (void *)t - (void *)dirent);
308} 303}
309 304
310static inline int ext4_handle_dirty_dirent_node(handle_t *handle, 305int ext4_handle_dirty_dirent_node(handle_t *handle,
311 struct inode *inode, 306 struct inode *inode,
312 struct buffer_head *bh) 307 struct buffer_head *bh)
313{ 308{
314 ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); 309 ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data);
315 return ext4_handle_dirty_metadata(handle, inode, bh); 310 return ext4_handle_dirty_metadata(handle, inode, bh);
@@ -1878,6 +1873,17 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
1878 blocksize = sb->s_blocksize; 1873 blocksize = sb->s_blocksize;
1879 if (!dentry->d_name.len) 1874 if (!dentry->d_name.len)
1880 return -EINVAL; 1875 return -EINVAL;
1876
1877 if (ext4_has_inline_data(dir)) {
1878 retval = ext4_try_add_inline_entry(handle, dentry, inode);
1879 if (retval < 0)
1880 return retval;
1881 if (retval == 1) {
1882 retval = 0;
1883 return retval;
1884 }
1885 }
1886
1881 if (is_dx(dir)) { 1887 if (is_dx(dir)) {
1882 retval = ext4_dx_add_entry(handle, dentry, inode); 1888 retval = ext4_dx_add_entry(handle, dentry, inode);
1883 if (!retval || (retval != ERR_BAD_DX_DIR)) 1889 if (!retval || (retval != ERR_BAD_DX_DIR))
@@ -2301,6 +2307,14 @@ static int ext4_init_new_dir(handle_t *handle, struct inode *dir,
2301 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) 2307 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
2302 csum_size = sizeof(struct ext4_dir_entry_tail); 2308 csum_size = sizeof(struct ext4_dir_entry_tail);
2303 2309
2310 if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
2311 err = ext4_try_create_inline_dir(handle, dir, inode);
2312 if (err < 0 && err != -ENOSPC)
2313 goto out;
2314 if (!err)
2315 goto out;
2316 }
2317
2304 inode->i_size = EXT4_I(inode)->i_disksize = blocksize; 2318 inode->i_size = EXT4_I(inode)->i_disksize = blocksize;
2305 dir_block = ext4_bread(handle, inode, 0, 1, &err); 2319 dir_block = ext4_bread(handle, inode, 0, 1, &err);
2306 if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) { 2320 if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) {
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 37e66f867645..397ef4bbaf1e 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -163,6 +163,11 @@ extern int ext4_da_write_inline_data_begin(struct address_space *mapping,
163extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, 163extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
164 unsigned len, unsigned copied, 164 unsigned len, unsigned copied,
165 struct page *page); 165 struct page *page);
166extern int ext4_try_add_inline_entry(handle_t *handle, struct dentry *dentry,
167 struct inode *inode);
168extern int ext4_try_create_inline_dir(handle_t *handle,
169 struct inode *parent,
170 struct inode *inode);
166# else /* CONFIG_EXT4_FS_XATTR */ 171# else /* CONFIG_EXT4_FS_XATTR */
167 172
168static inline int 173static inline int
@@ -327,6 +332,20 @@ static inline int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
327{ 332{
328 return 0; 333 return 0;
329} 334}
335
336static inline int ext4_try_add_inline_entry(handle_t *handle,
337 struct dentry *dentry,
338 struct inode *inode)
339{
340 return 0;
341}
342
343static inline int ext4_try_create_inline_dir(handle_t *handle,
344 struct inode *parent,
345 struct inode *inode)
346{
347 return 0;
348}
330# endif /* CONFIG_EXT4_FS_XATTR */ 349# endif /* CONFIG_EXT4_FS_XATTR */
331 350
332#ifdef CONFIG_EXT4_FS_SECURITY 351#ifdef CONFIG_EXT4_FS_SECURITY