diff options
author | Mark Fasheh <mfasheh@suse.com> | 2008-11-24 20:02:08 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2009-04-03 14:39:16 -0400 |
commit | 4ed8a6bb083bfcc21f1ed66a474b03c0386e4b34 (patch) | |
tree | 89cc2629bed3949e980edcae3d807e71718a9028 | |
parent | 9b7895efac906d66d19856194e1ba61f37e231a4 (diff) |
ocfs2: Store dir index records inline
Allow us to store a small number of directory index records in the
ocfs2_dx_root_block. This saves us a disk read on small to medium sized
directories (less than about 250 entries). The inline root is automatically
turned into a root block with extents if the directory size increases beyond
it's capacity.
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Acked-by: Joel Becker <joel.becker@oracle.com>
-rw-r--r-- | fs/ocfs2/dir.c | 572 | ||||
-rw-r--r-- | fs/ocfs2/dir.h | 2 | ||||
-rw-r--r-- | fs/ocfs2/journal.h | 10 | ||||
-rw-r--r-- | fs/ocfs2/namei.c | 4 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_fs.h | 28 |
5 files changed, 471 insertions, 145 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 0b8c88b47a4e..47de64988b11 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -151,6 +151,7 @@ static void ocfs2_init_dir_trailer(struct inode *inode, | |||
151 | 151 | ||
152 | void ocfs2_free_dir_lookup_result(struct ocfs2_dir_lookup_result *res) | 152 | void ocfs2_free_dir_lookup_result(struct ocfs2_dir_lookup_result *res) |
153 | { | 153 | { |
154 | brelse(res->dl_dx_root_bh); | ||
154 | brelse(res->dl_leaf_bh); | 155 | brelse(res->dl_leaf_bh); |
155 | brelse(res->dl_dx_leaf_bh); | 156 | brelse(res->dl_dx_leaf_bh); |
156 | } | 157 | } |
@@ -162,6 +163,11 @@ static int ocfs2_dir_indexed(struct inode *inode) | |||
162 | return 0; | 163 | return 0; |
163 | } | 164 | } |
164 | 165 | ||
166 | static inline int ocfs2_dx_root_inline(struct ocfs2_dx_root_block *dx_root) | ||
167 | { | ||
168 | return dx_root->dr_flags & OCFS2_DX_FLAG_INLINE; | ||
169 | } | ||
170 | |||
165 | /* | 171 | /* |
166 | * Hashing code adapted from ext3 | 172 | * Hashing code adapted from ext3 |
167 | */ | 173 | */ |
@@ -799,13 +805,18 @@ out: | |||
799 | * Returns the block index, from the start of the cluster which this | 805 | * Returns the block index, from the start of the cluster which this |
800 | * hash belongs too. | 806 | * hash belongs too. |
801 | */ | 807 | */ |
802 | static unsigned int ocfs2_dx_dir_hash_idx(struct ocfs2_super *osb, | 808 | static inline unsigned int __ocfs2_dx_dir_hash_idx(struct ocfs2_super *osb, |
803 | struct ocfs2_dx_hinfo *hinfo) | 809 | u32 minor_hash) |
804 | { | 810 | { |
805 | u32 minor_hash = hinfo->minor_hash; | ||
806 | return minor_hash & osb->osb_dx_mask; | 811 | return minor_hash & osb->osb_dx_mask; |
807 | } | 812 | } |
808 | 813 | ||
814 | static inline unsigned int ocfs2_dx_dir_hash_idx(struct ocfs2_super *osb, | ||
815 | struct ocfs2_dx_hinfo *hinfo) | ||
816 | { | ||
817 | return __ocfs2_dx_dir_hash_idx(osb, hinfo->minor_hash); | ||
818 | } | ||
819 | |||
809 | static int ocfs2_dx_dir_lookup(struct inode *inode, | 820 | static int ocfs2_dx_dir_lookup(struct inode *inode, |
810 | struct ocfs2_extent_list *el, | 821 | struct ocfs2_extent_list *el, |
811 | struct ocfs2_dx_hinfo *hinfo, | 822 | struct ocfs2_dx_hinfo *hinfo, |
@@ -855,7 +866,7 @@ out: | |||
855 | 866 | ||
856 | static int ocfs2_dx_dir_search(const char *name, int namelen, | 867 | static int ocfs2_dx_dir_search(const char *name, int namelen, |
857 | struct inode *dir, | 868 | struct inode *dir, |
858 | struct ocfs2_extent_list *dr_el, | 869 | struct ocfs2_dx_root_block *dx_root, |
859 | struct ocfs2_dir_lookup_result *res) | 870 | struct ocfs2_dir_lookup_result *res) |
860 | { | 871 | { |
861 | int ret, i, found; | 872 | int ret, i, found; |
@@ -866,9 +877,18 @@ static int ocfs2_dx_dir_search(const char *name, int namelen, | |||
866 | struct buffer_head *dir_ent_bh = NULL; | 877 | struct buffer_head *dir_ent_bh = NULL; |
867 | struct ocfs2_dir_entry *dir_ent = NULL; | 878 | struct ocfs2_dir_entry *dir_ent = NULL; |
868 | struct ocfs2_dx_hinfo *hinfo = &res->dl_hinfo; | 879 | struct ocfs2_dx_hinfo *hinfo = &res->dl_hinfo; |
880 | struct ocfs2_extent_list *dr_el; | ||
881 | struct ocfs2_dx_entry_list *entry_list; | ||
869 | 882 | ||
870 | ocfs2_dx_dir_name_hash(dir, name, namelen, &res->dl_hinfo); | 883 | ocfs2_dx_dir_name_hash(dir, name, namelen, &res->dl_hinfo); |
871 | 884 | ||
885 | if (ocfs2_dx_root_inline(dx_root)) { | ||
886 | entry_list = &dx_root->dr_entries; | ||
887 | goto search; | ||
888 | } | ||
889 | |||
890 | dr_el = &dx_root->dr_list; | ||
891 | |||
872 | ret = ocfs2_dx_dir_lookup(dir, dr_el, hinfo, NULL, &phys); | 892 | ret = ocfs2_dx_dir_lookup(dir, dr_el, hinfo, NULL, &phys); |
873 | if (ret) { | 893 | if (ret) { |
874 | mlog_errno(ret); | 894 | mlog_errno(ret); |
@@ -893,12 +913,15 @@ static int ocfs2_dx_dir_search(const char *name, int namelen, | |||
893 | le16_to_cpu(dx_leaf->dl_list.de_num_used), | 913 | le16_to_cpu(dx_leaf->dl_list.de_num_used), |
894 | le16_to_cpu(dx_leaf->dl_list.de_count)); | 914 | le16_to_cpu(dx_leaf->dl_list.de_count)); |
895 | 915 | ||
916 | entry_list = &dx_leaf->dl_list; | ||
917 | |||
918 | search: | ||
896 | /* | 919 | /* |
897 | * Empty leaf is legal, so no need to check for that. | 920 | * Empty leaf is legal, so no need to check for that. |
898 | */ | 921 | */ |
899 | found = 0; | 922 | found = 0; |
900 | for (i = 0; i < le16_to_cpu(dx_leaf->dl_list.de_num_used); i++) { | 923 | for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++) { |
901 | dx_entry = &dx_leaf->dl_list.de_entries[i]; | 924 | dx_entry = &entry_list->de_entries[i]; |
902 | 925 | ||
903 | if (hinfo->major_hash != le32_to_cpu(dx_entry->dx_major_hash) | 926 | if (hinfo->major_hash != le32_to_cpu(dx_entry->dx_major_hash) |
904 | || hinfo->minor_hash != le32_to_cpu(dx_entry->dx_minor_hash)) | 927 | || hinfo->minor_hash != le32_to_cpu(dx_entry->dx_minor_hash)) |
@@ -982,14 +1005,15 @@ static int ocfs2_find_entry_dx(const char *name, int namelen, | |||
982 | } | 1005 | } |
983 | dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data; | 1006 | dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data; |
984 | 1007 | ||
985 | ret = ocfs2_dx_dir_search(name, namelen, dir, &dx_root->dr_list, | 1008 | ret = ocfs2_dx_dir_search(name, namelen, dir, dx_root, lookup); |
986 | lookup); | ||
987 | if (ret) { | 1009 | if (ret) { |
988 | if (ret != -ENOENT) | 1010 | if (ret != -ENOENT) |
989 | mlog_errno(ret); | 1011 | mlog_errno(ret); |
990 | goto out; | 1012 | goto out; |
991 | } | 1013 | } |
992 | 1014 | ||
1015 | lookup->dl_dx_root_bh = dx_root_bh; | ||
1016 | dx_root_bh = NULL; | ||
993 | out: | 1017 | out: |
994 | brelse(di_bh); | 1018 | brelse(di_bh); |
995 | brelse(dx_root_bh); | 1019 | brelse(dx_root_bh); |
@@ -1126,64 +1150,88 @@ bail: | |||
1126 | return status; | 1150 | return status; |
1127 | } | 1151 | } |
1128 | 1152 | ||
1129 | static void ocfs2_dx_leaf_remove_entry(struct ocfs2_dx_leaf *dx_leaf, int index) | 1153 | static void ocfs2_dx_list_remove_entry(struct ocfs2_dx_entry_list *entry_list, |
1154 | int index) | ||
1130 | { | 1155 | { |
1131 | struct ocfs2_dx_entry_list *dl_list = &dx_leaf->dl_list; | 1156 | int num_used = le16_to_cpu(entry_list->de_num_used); |
1132 | int num_used = le16_to_cpu(dl_list->de_num_used); | ||
1133 | 1157 | ||
1134 | if (num_used == 1 || index == (num_used - 1)) | 1158 | if (num_used == 1 || index == (num_used - 1)) |
1135 | goto clear; | 1159 | goto clear; |
1136 | 1160 | ||
1137 | memmove(&dl_list->de_entries[index], &dl_list->de_entries[index + 1], | 1161 | memmove(&entry_list->de_entries[index], |
1162 | &entry_list->de_entries[index + 1], | ||
1138 | (num_used - index - 1)*sizeof(struct ocfs2_dx_entry)); | 1163 | (num_used - index - 1)*sizeof(struct ocfs2_dx_entry)); |
1139 | clear: | 1164 | clear: |
1140 | num_used--; | 1165 | num_used--; |
1141 | memset(&dl_list->de_entries[num_used], 0, | 1166 | memset(&entry_list->de_entries[num_used], 0, |
1142 | sizeof(struct ocfs2_dx_entry)); | 1167 | sizeof(struct ocfs2_dx_entry)); |
1143 | dl_list->de_num_used = cpu_to_le16(num_used); | 1168 | entry_list->de_num_used = cpu_to_le16(num_used); |
1144 | } | 1169 | } |
1145 | 1170 | ||
1146 | static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir, | 1171 | static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir, |
1147 | struct ocfs2_dir_lookup_result *lookup) | 1172 | struct ocfs2_dir_lookup_result *lookup) |
1148 | { | 1173 | { |
1149 | int ret, index; | 1174 | int ret, index; |
1175 | struct buffer_head *dx_root_bh = lookup->dl_dx_root_bh; | ||
1150 | struct buffer_head *leaf_bh = lookup->dl_leaf_bh; | 1176 | struct buffer_head *leaf_bh = lookup->dl_leaf_bh; |
1151 | struct ocfs2_dx_leaf *dx_leaf; | 1177 | struct ocfs2_dx_leaf *dx_leaf; |
1152 | struct ocfs2_dx_entry *dx_entry = lookup->dl_dx_entry; | 1178 | struct ocfs2_dx_entry *dx_entry = lookup->dl_dx_entry; |
1179 | struct ocfs2_dx_root_block *dx_root; | ||
1180 | struct ocfs2_dx_entry_list *entry_list; | ||
1181 | |||
1182 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | ||
1183 | if (ocfs2_dx_root_inline(dx_root)) { | ||
1184 | entry_list = &dx_root->dr_entries; | ||
1185 | } else { | ||
1186 | dx_leaf = (struct ocfs2_dx_leaf *) lookup->dl_dx_leaf_bh->b_data; | ||
1187 | entry_list = &dx_leaf->dl_list; | ||
1188 | } | ||
1153 | 1189 | ||
1154 | dx_leaf = (struct ocfs2_dx_leaf *) lookup->dl_dx_leaf_bh->b_data; | ||
1155 | /* Neither of these are a disk corruption - that should have | 1190 | /* Neither of these are a disk corruption - that should have |
1156 | * been caught by lookup, before we got here. */ | 1191 | * been caught by lookup, before we got here. */ |
1157 | BUG_ON(le16_to_cpu(dx_leaf->dl_list.de_count) <= 0); | 1192 | BUG_ON(le16_to_cpu(entry_list->de_count) <= 0); |
1158 | BUG_ON(le16_to_cpu(dx_leaf->dl_list.de_num_used) <= 0); | 1193 | BUG_ON(le16_to_cpu(entry_list->de_num_used) <= 0); |
1159 | 1194 | ||
1160 | index = (char *)dx_entry - (char *)dx_leaf->dl_list.de_entries; | 1195 | index = (char *)dx_entry - (char *)entry_list->de_entries; |
1161 | index /= sizeof(*dx_entry); | 1196 | index /= sizeof(*dx_entry); |
1162 | 1197 | ||
1163 | if (index >= le16_to_cpu(dx_leaf->dl_list.de_num_used)) { | 1198 | if (index >= le16_to_cpu(entry_list->de_num_used)) { |
1164 | mlog(ML_ERROR, "Dir %llu: Bad dx_entry ptr idx %d, (%p, %p)\n", | 1199 | mlog(ML_ERROR, "Dir %llu: Bad dx_entry ptr idx %d, (%p, %p)\n", |
1165 | (unsigned long long)OCFS2_I(dir)->ip_blkno, index, dx_leaf, | 1200 | (unsigned long long)OCFS2_I(dir)->ip_blkno, index, |
1166 | dx_entry); | 1201 | entry_list, dx_entry); |
1167 | return -EIO; | 1202 | return -EIO; |
1168 | } | 1203 | } |
1169 | 1204 | ||
1170 | mlog(0, "Dir %llu: delete entry at index: %d\n", | ||
1171 | (unsigned long long)OCFS2_I(dir)->ip_blkno, index); | ||
1172 | |||
1173 | /* | 1205 | /* |
1174 | * Add the index leaf into the journal before removing the | 1206 | * Add the block holding our index into the journal before |
1175 | * unindexed entry. If we get an error return from | 1207 | * removing the unindexed entry. If we get an error return |
1176 | * __ocfs2_delete_entry(), then it hasn't removed the entry | 1208 | * from __ocfs2_delete_entry(), then it hasn't removed the |
1177 | * yet. Likewise, successful return means we *must* remove the | 1209 | * entry yet. Likewise, successful return means we *must* |
1178 | * indexed entry. | 1210 | * remove the indexed entry. |
1211 | * | ||
1212 | * We're also careful to journal the root tree block here if | ||
1213 | * we're going to be adding to the start of the free list. | ||
1179 | */ | 1214 | */ |
1180 | ret = ocfs2_journal_access_dl(handle, dir, lookup->dl_dx_leaf_bh, | 1215 | if (ocfs2_dx_root_inline(dx_root)) { |
1181 | OCFS2_JOURNAL_ACCESS_WRITE); | 1216 | ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, |
1182 | if (ret) { | 1217 | OCFS2_JOURNAL_ACCESS_WRITE); |
1183 | mlog_errno(ret); | 1218 | if (ret) { |
1184 | goto out; | 1219 | mlog_errno(ret); |
1220 | goto out; | ||
1221 | } | ||
1222 | } else { | ||
1223 | ret = ocfs2_journal_access_dl(handle, dir, | ||
1224 | lookup->dl_dx_leaf_bh, | ||
1225 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1226 | if (ret) { | ||
1227 | mlog_errno(ret); | ||
1228 | goto out; | ||
1229 | } | ||
1185 | } | 1230 | } |
1186 | 1231 | ||
1232 | mlog(0, "Dir %llu: delete entry at index: %d\n", | ||
1233 | (unsigned long long)OCFS2_I(dir)->ip_blkno, index); | ||
1234 | |||
1187 | ret = __ocfs2_delete_entry(handle, dir, lookup->dl_entry, | 1235 | ret = __ocfs2_delete_entry(handle, dir, lookup->dl_entry, |
1188 | leaf_bh, leaf_bh->b_data, leaf_bh->b_size); | 1236 | leaf_bh, leaf_bh->b_data, leaf_bh->b_size); |
1189 | if (ret) { | 1237 | if (ret) { |
@@ -1191,9 +1239,12 @@ static int ocfs2_delete_entry_dx(handle_t *handle, struct inode *dir, | |||
1191 | goto out; | 1239 | goto out; |
1192 | } | 1240 | } |
1193 | 1241 | ||
1194 | ocfs2_dx_leaf_remove_entry(dx_leaf, index); | 1242 | ocfs2_dx_list_remove_entry(entry_list, index); |
1195 | 1243 | ||
1196 | ocfs2_journal_dirty(handle, lookup->dl_dx_leaf_bh); | 1244 | if (ocfs2_dx_root_inline(dx_root)) |
1245 | ocfs2_journal_dirty(handle, dx_root_bh); | ||
1246 | else | ||
1247 | ocfs2_journal_dirty(handle, lookup->dl_dx_leaf_bh); | ||
1197 | 1248 | ||
1198 | out: | 1249 | out: |
1199 | return ret; | 1250 | return ret; |
@@ -1290,13 +1341,30 @@ static void ocfs2_dx_dir_leaf_insert_tail(struct ocfs2_dx_leaf *dx_leaf, | |||
1290 | le16_add_cpu(&dx_leaf->dl_list.de_num_used, 1); | 1341 | le16_add_cpu(&dx_leaf->dl_list.de_num_used, 1); |
1291 | } | 1342 | } |
1292 | 1343 | ||
1344 | static void ocfs2_dx_entry_list_insert(struct ocfs2_dx_entry_list *entry_list, | ||
1345 | struct ocfs2_dx_hinfo *hinfo, | ||
1346 | u64 dirent_blk) | ||
1347 | { | ||
1348 | int i; | ||
1349 | struct ocfs2_dx_entry *dx_entry; | ||
1350 | |||
1351 | i = le16_to_cpu(entry_list->de_num_used); | ||
1352 | dx_entry = &entry_list->de_entries[i]; | ||
1353 | |||
1354 | memset(dx_entry, 0, sizeof(*dx_entry)); | ||
1355 | dx_entry->dx_major_hash = cpu_to_le32(hinfo->major_hash); | ||
1356 | dx_entry->dx_minor_hash = cpu_to_le32(hinfo->minor_hash); | ||
1357 | dx_entry->dx_dirent_blk = cpu_to_le64(dirent_blk); | ||
1358 | |||
1359 | le16_add_cpu(&entry_list->de_num_used, 1); | ||
1360 | } | ||
1361 | |||
1293 | static int __ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle, | 1362 | static int __ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle, |
1294 | struct ocfs2_dx_hinfo *hinfo, | 1363 | struct ocfs2_dx_hinfo *hinfo, |
1295 | u64 dirent_blk, | 1364 | u64 dirent_blk, |
1296 | struct buffer_head *dx_leaf_bh) | 1365 | struct buffer_head *dx_leaf_bh) |
1297 | { | 1366 | { |
1298 | int ret, i; | 1367 | int ret; |
1299 | struct ocfs2_dx_entry *dx_entry; | ||
1300 | struct ocfs2_dx_leaf *dx_leaf; | 1368 | struct ocfs2_dx_leaf *dx_leaf; |
1301 | 1369 | ||
1302 | ret = ocfs2_journal_access_dl(handle, dir, dx_leaf_bh, | 1370 | ret = ocfs2_journal_access_dl(handle, dir, dx_leaf_bh, |
@@ -1307,25 +1375,48 @@ static int __ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle, | |||
1307 | } | 1375 | } |
1308 | 1376 | ||
1309 | dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_bh->b_data; | 1377 | dx_leaf = (struct ocfs2_dx_leaf *)dx_leaf_bh->b_data; |
1310 | i = le16_to_cpu(dx_leaf->dl_list.de_num_used); | 1378 | ocfs2_dx_entry_list_insert(&dx_leaf->dl_list, hinfo, dirent_blk); |
1311 | dx_entry = &dx_leaf->dl_list.de_entries[i]; | 1379 | ocfs2_journal_dirty(handle, dx_leaf_bh); |
1312 | 1380 | ||
1313 | memset(dx_entry, 0, sizeof(*dx_entry)); | 1381 | out: |
1314 | dx_entry->dx_major_hash = cpu_to_le32(hinfo->major_hash); | 1382 | return ret; |
1315 | dx_entry->dx_minor_hash = cpu_to_le32(hinfo->minor_hash); | 1383 | } |
1316 | dx_entry->dx_dirent_blk = cpu_to_le64(dirent_blk); | ||
1317 | 1384 | ||
1318 | le16_add_cpu(&dx_leaf->dl_list.de_num_used, 1); | 1385 | static int ocfs2_dx_inline_root_insert(struct inode *dir, handle_t *handle, |
1386 | struct ocfs2_dx_hinfo *hinfo, | ||
1387 | u64 dirent_blk, | ||
1388 | struct buffer_head *dx_root_bh) | ||
1389 | { | ||
1390 | int ret; | ||
1391 | struct ocfs2_dx_root_block *dx_root; | ||
1319 | 1392 | ||
1320 | ocfs2_journal_dirty(handle, dx_leaf_bh); | 1393 | ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, |
1394 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1395 | if (ret) { | ||
1396 | mlog_errno(ret); | ||
1397 | goto out; | ||
1398 | } | ||
1399 | |||
1400 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | ||
1401 | ocfs2_dx_entry_list_insert(&dx_root->dr_entries, hinfo, dirent_blk); | ||
1402 | ocfs2_journal_dirty(handle, dx_root_bh); | ||
1321 | 1403 | ||
1322 | out: | 1404 | out: |
1323 | return ret; | 1405 | return ret; |
1324 | } | 1406 | } |
1325 | 1407 | ||
1326 | static int ocfs2_dx_dir_leaf_insert(struct inode *dir, handle_t *handle, | 1408 | static int ocfs2_dx_dir_insert(struct inode *dir, handle_t *handle, |
1327 | struct ocfs2_dir_lookup_result *lookup) | 1409 | struct ocfs2_dir_lookup_result *lookup) |
1328 | { | 1410 | { |
1411 | struct ocfs2_dx_root_block *dx_root; | ||
1412 | |||
1413 | dx_root = (struct ocfs2_dx_root_block *)lookup->dl_dx_root_bh->b_data; | ||
1414 | if (ocfs2_dx_root_inline(dx_root)) | ||
1415 | return ocfs2_dx_inline_root_insert(dir, handle, | ||
1416 | &lookup->dl_hinfo, | ||
1417 | lookup->dl_leaf_bh->b_blocknr, | ||
1418 | lookup->dl_dx_root_bh); | ||
1419 | |||
1329 | return __ocfs2_dx_dir_leaf_insert(dir, handle, &lookup->dl_hinfo, | 1420 | return __ocfs2_dx_dir_leaf_insert(dir, handle, &lookup->dl_hinfo, |
1330 | lookup->dl_leaf_bh->b_blocknr, | 1421 | lookup->dl_leaf_bh->b_blocknr, |
1331 | lookup->dl_dx_leaf_bh); | 1422 | lookup->dl_dx_leaf_bh); |
@@ -1409,11 +1500,12 @@ int __ocfs2_add_entry(handle_t *handle, | |||
1409 | else { | 1500 | else { |
1410 | status = ocfs2_journal_access_db(handle, dir, | 1501 | status = ocfs2_journal_access_db(handle, dir, |
1411 | insert_bh, | 1502 | insert_bh, |
1412 | OCFS2_JOURNAL_ACCESS_WRITE); | 1503 | OCFS2_JOURNAL_ACCESS_WRITE); |
1504 | |||
1413 | if (ocfs2_dir_indexed(dir)) { | 1505 | if (ocfs2_dir_indexed(dir)) { |
1414 | status = ocfs2_dx_dir_leaf_insert(dir, | 1506 | status = ocfs2_dx_dir_insert(dir, |
1415 | handle, | 1507 | handle, |
1416 | lookup); | 1508 | lookup); |
1417 | if (status) { | 1509 | if (status) { |
1418 | mlog_errno(status); | 1510 | mlog_errno(status); |
1419 | goto bail; | 1511 | goto bail; |
@@ -2019,6 +2111,7 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, | |||
2019 | handle_t *handle, struct inode *dir, | 2111 | handle_t *handle, struct inode *dir, |
2020 | struct buffer_head *di_bh, | 2112 | struct buffer_head *di_bh, |
2021 | struct ocfs2_alloc_context *meta_ac, | 2113 | struct ocfs2_alloc_context *meta_ac, |
2114 | int dx_inline, | ||
2022 | struct buffer_head **ret_dx_root_bh) | 2115 | struct buffer_head **ret_dx_root_bh) |
2023 | { | 2116 | { |
2024 | int ret; | 2117 | int ret; |
@@ -2062,8 +2155,15 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, | |||
2062 | dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation); | 2155 | dx_root->dr_fs_generation = cpu_to_le32(osb->fs_generation); |
2063 | dx_root->dr_blkno = cpu_to_le64(dr_blkno); | 2156 | dx_root->dr_blkno = cpu_to_le64(dr_blkno); |
2064 | dx_root->dr_dir_blkno = cpu_to_le64(OCFS2_I(dir)->ip_blkno); | 2157 | dx_root->dr_dir_blkno = cpu_to_le64(OCFS2_I(dir)->ip_blkno); |
2065 | dx_root->dr_list.l_count = | 2158 | |
2066 | cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb)); | 2159 | if (dx_inline) { |
2160 | dx_root->dr_flags |= OCFS2_DX_FLAG_INLINE; | ||
2161 | dx_root->dr_entries.de_count = | ||
2162 | cpu_to_le16(ocfs2_dx_entries_per_root(osb->sb)); | ||
2163 | } else { | ||
2164 | dx_root->dr_list.l_count = | ||
2165 | cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb)); | ||
2166 | } | ||
2067 | 2167 | ||
2068 | ret = ocfs2_journal_dirty(handle, dx_root_bh); | 2168 | ret = ocfs2_journal_dirty(handle, dx_root_bh); |
2069 | if (ret) | 2169 | if (ret) |
@@ -2236,20 +2336,12 @@ static int ocfs2_fill_new_dir_dx(struct ocfs2_super *osb, | |||
2236 | struct ocfs2_alloc_context *data_ac, | 2336 | struct ocfs2_alloc_context *data_ac, |
2237 | struct ocfs2_alloc_context *meta_ac) | 2337 | struct ocfs2_alloc_context *meta_ac) |
2238 | { | 2338 | { |
2239 | int ret, num_dx_leaves, i; | 2339 | int ret; |
2240 | struct buffer_head *leaf_bh = NULL; | 2340 | struct buffer_head *leaf_bh = NULL; |
2241 | struct buffer_head *dx_root_bh = NULL; | 2341 | struct buffer_head *dx_root_bh = NULL; |
2242 | struct buffer_head **dx_leaves = NULL; | ||
2243 | struct ocfs2_extent_tree et; | ||
2244 | struct ocfs2_dx_hinfo hinfo; | 2342 | struct ocfs2_dx_hinfo hinfo; |
2245 | u64 insert_blkno; | 2343 | struct ocfs2_dx_root_block *dx_root; |
2246 | 2344 | struct ocfs2_dx_entry_list *entry_list; | |
2247 | dx_leaves = ocfs2_dx_dir_kmalloc_leaves(osb->sb, &num_dx_leaves); | ||
2248 | if (!dx_leaves) { | ||
2249 | ret = -ENOMEM; | ||
2250 | mlog_errno(ret); | ||
2251 | goto out; | ||
2252 | } | ||
2253 | 2345 | ||
2254 | /* | 2346 | /* |
2255 | * Our strategy is to create the directory as though it were | 2347 | * Our strategy is to create the directory as though it were |
@@ -2258,7 +2350,8 @@ static int ocfs2_fill_new_dir_dx(struct ocfs2_super *osb, | |||
2258 | * very well known quantity. | 2350 | * very well known quantity. |
2259 | * | 2351 | * |
2260 | * Essentially, we have two dirents ("." and ".."), in the 1st | 2352 | * Essentially, we have two dirents ("." and ".."), in the 1st |
2261 | * block which need indexing. | 2353 | * block which need indexing. These are easily inserted into |
2354 | * the index block. | ||
2262 | */ | 2355 | */ |
2263 | 2356 | ||
2264 | ret = ocfs2_fill_new_dir_el(osb, handle, parent, inode, di_bh, | 2357 | ret = ocfs2_fill_new_dir_el(osb, handle, parent, inode, di_bh, |
@@ -2268,61 +2361,22 @@ static int ocfs2_fill_new_dir_dx(struct ocfs2_super *osb, | |||
2268 | goto out; | 2361 | goto out; |
2269 | } | 2362 | } |
2270 | 2363 | ||
2271 | /* | 2364 | ret = ocfs2_dx_dir_attach_index(osb, handle, inode, di_bh, |
2272 | * Allocate and format the index leaf first, before attaching | 2365 | meta_ac, 1, &dx_root_bh); |
2273 | * the index root. That way we're sure that the main bitmap | ||
2274 | * won't -enospc on us with a half-created dir index. | ||
2275 | * | ||
2276 | * The meta data allocation for our index block will not | ||
2277 | * -enospc on us unless there is a disk corruption. | ||
2278 | */ | ||
2279 | |||
2280 | ret = __ocfs2_dx_dir_new_cluster(inode, 0, handle, data_ac, dx_leaves, | ||
2281 | num_dx_leaves, &insert_blkno); | ||
2282 | if (ret) { | 2366 | if (ret) { |
2283 | mlog_errno(ret); | 2367 | mlog_errno(ret); |
2284 | goto out; | 2368 | goto out; |
2285 | } | 2369 | } |
2370 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | ||
2371 | entry_list = &dx_root->dr_entries; | ||
2286 | 2372 | ||
2287 | ocfs2_dx_dir_name_hash(inode, ".", 1, &hinfo); | 2373 | /* Buffer has been journaled for us by ocfs2_dx_dir_attach_index */ |
2288 | i = ocfs2_dx_dir_hash_idx(osb, &hinfo); | 2374 | ocfs2_dx_entry_list_insert(entry_list, &hinfo, leaf_bh->b_blocknr); |
2289 | ret = __ocfs2_dx_dir_leaf_insert(inode, handle, &hinfo, | ||
2290 | leaf_bh->b_blocknr, dx_leaves[i]); | ||
2291 | if (ret) { | ||
2292 | mlog_errno(ret); | ||
2293 | goto out; | ||
2294 | } | ||
2295 | 2375 | ||
2296 | ocfs2_dx_dir_name_hash(inode, "..", 2, &hinfo); | 2376 | ocfs2_dx_dir_name_hash(inode, "..", 2, &hinfo); |
2297 | i = ocfs2_dx_dir_hash_idx(osb, &hinfo); | 2377 | ocfs2_dx_entry_list_insert(entry_list, &hinfo, leaf_bh->b_blocknr); |
2298 | ret = __ocfs2_dx_dir_leaf_insert(inode, handle, &hinfo, | ||
2299 | leaf_bh->b_blocknr, dx_leaves[i]); | ||
2300 | if (ret) { | ||
2301 | mlog_errno(ret); | ||
2302 | goto out; | ||
2303 | } | ||
2304 | |||
2305 | ret = ocfs2_dx_dir_attach_index(osb, handle, inode, di_bh, meta_ac, | ||
2306 | &dx_root_bh); | ||
2307 | if (ret) { | ||
2308 | mlog_errno(ret); | ||
2309 | goto out; | ||
2310 | } | ||
2311 | |||
2312 | /* This should never fail considering we start with an empty | ||
2313 | * dx_root. */ | ||
2314 | ocfs2_init_dx_root_extent_tree(&et, inode, dx_root_bh); | ||
2315 | ret = ocfs2_insert_extent(osb, handle, inode, &et, 0, | ||
2316 | insert_blkno, 1, 0, NULL); | ||
2317 | if (ret) | ||
2318 | mlog_errno(ret); | ||
2319 | 2378 | ||
2320 | out: | 2379 | out: |
2321 | if (dx_leaves) { | ||
2322 | for (i = 0; i < num_dx_leaves; i++) | ||
2323 | brelse(dx_leaves[i]); | ||
2324 | kfree(dx_leaves); | ||
2325 | } | ||
2326 | brelse(dx_root_bh); | 2380 | brelse(dx_root_bh); |
2327 | brelse(leaf_bh); | 2381 | brelse(leaf_bh); |
2328 | return ret; | 2382 | return ret; |
@@ -2392,6 +2446,74 @@ inc: | |||
2392 | out: | 2446 | out: |
2393 | return ret; | 2447 | return ret; |
2394 | } | 2448 | } |
2449 | /* | ||
2450 | * XXX: This expects dx_root_bh to already be part of the transaction. | ||
2451 | */ | ||
2452 | static void ocfs2_dx_dir_index_root_block(struct inode *dir, | ||
2453 | struct buffer_head *dx_root_bh, | ||
2454 | struct buffer_head *dirent_bh) | ||
2455 | { | ||
2456 | char *de_buf, *limit; | ||
2457 | struct ocfs2_dx_root_block *dx_root; | ||
2458 | struct ocfs2_dir_entry *de; | ||
2459 | struct ocfs2_dx_hinfo hinfo; | ||
2460 | u64 dirent_blk = dirent_bh->b_blocknr; | ||
2461 | |||
2462 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | ||
2463 | |||
2464 | de_buf = dirent_bh->b_data; | ||
2465 | limit = de_buf + dir->i_sb->s_blocksize; | ||
2466 | |||
2467 | while (de_buf < limit) { | ||
2468 | de = (struct ocfs2_dir_entry *)de_buf; | ||
2469 | |||
2470 | if (!de->name_len || !de->inode) | ||
2471 | goto inc; | ||
2472 | |||
2473 | ocfs2_dx_dir_name_hash(dir, de->name, de->name_len, &hinfo); | ||
2474 | |||
2475 | mlog(0, | ||
2476 | "dir: %llu, major: 0x%x minor: 0x%x, index: %u, name: %.*s\n", | ||
2477 | (unsigned long long)dir->i_ino, hinfo.major_hash, | ||
2478 | hinfo.minor_hash, | ||
2479 | le16_to_cpu(dx_root->dr_entries.de_num_used), | ||
2480 | de->name_len, de->name); | ||
2481 | |||
2482 | ocfs2_dx_entry_list_insert(&dx_root->dr_entries, &hinfo, | ||
2483 | dirent_blk); | ||
2484 | inc: | ||
2485 | de_buf += le16_to_cpu(de->rec_len); | ||
2486 | } | ||
2487 | } | ||
2488 | |||
2489 | /* | ||
2490 | * Count the number of inline directory entries in di_bh and compare | ||
2491 | * them against the number of entries we can hold in an inline dx root | ||
2492 | * block. | ||
2493 | */ | ||
2494 | static int ocfs2_new_dx_should_be_inline(struct inode *dir, | ||
2495 | struct buffer_head *di_bh) | ||
2496 | { | ||
2497 | int dirent_count = 0; | ||
2498 | char *de_buf, *limit; | ||
2499 | struct ocfs2_dir_entry *de; | ||
2500 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | ||
2501 | |||
2502 | de_buf = di->id2.i_data.id_data; | ||
2503 | limit = de_buf + i_size_read(dir); | ||
2504 | |||
2505 | while (de_buf < limit) { | ||
2506 | de = (struct ocfs2_dir_entry *)de_buf; | ||
2507 | |||
2508 | if (de->name_len && de->inode) | ||
2509 | dirent_count++; | ||
2510 | |||
2511 | de_buf += le16_to_cpu(de->rec_len); | ||
2512 | } | ||
2513 | |||
2514 | /* We are careful to leave room for one extra record. */ | ||
2515 | return dirent_count < ocfs2_dx_entries_per_root(dir->i_sb); | ||
2516 | } | ||
2395 | 2517 | ||
2396 | /* | 2518 | /* |
2397 | * Expand rec_len of the rightmost dirent in a directory block so that it | 2519 | * Expand rec_len of the rightmost dirent in a directory block so that it |
@@ -2442,7 +2564,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2442 | { | 2564 | { |
2443 | u32 alloc, dx_alloc, bit_off, len; | 2565 | u32 alloc, dx_alloc, bit_off, len; |
2444 | struct super_block *sb = dir->i_sb; | 2566 | struct super_block *sb = dir->i_sb; |
2445 | int ret, i, num_dx_leaves = 0, | 2567 | int ret, i, num_dx_leaves = 0, dx_inline = 0, |
2446 | credits = ocfs2_inline_to_extents_credits(sb); | 2568 | credits = ocfs2_inline_to_extents_credits(sb); |
2447 | u64 dx_insert_blkno, blkno, | 2569 | u64 dx_insert_blkno, blkno, |
2448 | bytes = blocks_wanted << sb->s_blocksize_bits; | 2570 | bytes = blocks_wanted << sb->s_blocksize_bits; |
@@ -2465,15 +2587,19 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2465 | dx_alloc = 0; | 2587 | dx_alloc = 0; |
2466 | 2588 | ||
2467 | if (ocfs2_supports_indexed_dirs(osb)) { | 2589 | if (ocfs2_supports_indexed_dirs(osb)) { |
2468 | /* Add one more cluster for an index leaf */ | ||
2469 | dx_alloc++; | ||
2470 | credits += ocfs2_add_dir_index_credits(sb); | 2590 | credits += ocfs2_add_dir_index_credits(sb); |
2471 | 2591 | ||
2472 | dx_leaves = ocfs2_dx_dir_kmalloc_leaves(sb, &num_dx_leaves); | 2592 | dx_inline = ocfs2_new_dx_should_be_inline(dir, di_bh); |
2473 | if (!dx_leaves) { | 2593 | if (!dx_inline) { |
2474 | ret = -ENOMEM; | 2594 | /* Add one more cluster for an index leaf */ |
2475 | mlog_errno(ret); | 2595 | dx_alloc++; |
2476 | goto out; | 2596 | dx_leaves = ocfs2_dx_dir_kmalloc_leaves(sb, |
2597 | &num_dx_leaves); | ||
2598 | if (!dx_leaves) { | ||
2599 | ret = -ENOMEM; | ||
2600 | mlog_errno(ret); | ||
2601 | goto out; | ||
2602 | } | ||
2477 | } | 2603 | } |
2478 | 2604 | ||
2479 | /* This gets us the dx_root */ | 2605 | /* This gets us the dx_root */ |
@@ -2524,7 +2650,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2524 | } | 2650 | } |
2525 | did_quota = 1; | 2651 | did_quota = 1; |
2526 | 2652 | ||
2527 | if (ocfs2_supports_indexed_dirs(osb)) { | 2653 | if (ocfs2_supports_indexed_dirs(osb) && !dx_inline) { |
2528 | /* | 2654 | /* |
2529 | * Allocate our index cluster first, to maximize the | 2655 | * Allocate our index cluster first, to maximize the |
2530 | * possibility that unindexed leaves grow | 2656 | * possibility that unindexed leaves grow |
@@ -2587,7 +2713,12 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2587 | goto out_commit; | 2713 | goto out_commit; |
2588 | } | 2714 | } |
2589 | 2715 | ||
2590 | if (ocfs2_supports_indexed_dirs(osb)) { | 2716 | if (ocfs2_supports_indexed_dirs(osb) && !dx_inline) { |
2717 | /* | ||
2718 | * Dx dirs with an external cluster need to do this up | ||
2719 | * front. Inline dx root's get handled later, after | ||
2720 | * we've allocated our root block. | ||
2721 | */ | ||
2591 | ret = ocfs2_dx_dir_index_block(dir, handle, dx_leaves, | 2722 | ret = ocfs2_dx_dir_index_block(dir, handle, dx_leaves, |
2592 | num_dx_leaves, dirdata_bh); | 2723 | num_dx_leaves, dirdata_bh); |
2593 | if (ret) { | 2724 | if (ret) { |
@@ -2650,17 +2781,23 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2650 | 2781 | ||
2651 | if (ocfs2_supports_indexed_dirs(osb)) { | 2782 | if (ocfs2_supports_indexed_dirs(osb)) { |
2652 | ret = ocfs2_dx_dir_attach_index(osb, handle, dir, di_bh, | 2783 | ret = ocfs2_dx_dir_attach_index(osb, handle, dir, di_bh, |
2653 | meta_ac, &dx_root_bh); | 2784 | meta_ac, dx_inline, |
2785 | &dx_root_bh); | ||
2654 | if (ret) { | 2786 | if (ret) { |
2655 | mlog_errno(ret); | 2787 | mlog_errno(ret); |
2656 | goto out_commit; | 2788 | goto out_commit; |
2657 | } | 2789 | } |
2658 | 2790 | ||
2659 | ocfs2_init_dx_root_extent_tree(&dx_et, dir, dx_root_bh); | 2791 | if (dx_inline) { |
2660 | ret = ocfs2_insert_extent(osb, handle, dir, &dx_et, 0, | 2792 | ocfs2_dx_dir_index_root_block(dir, dx_root_bh, |
2661 | dx_insert_blkno, 1, 0, NULL); | 2793 | dirdata_bh); |
2662 | if (ret) | 2794 | } else { |
2663 | mlog_errno(ret); | 2795 | ocfs2_init_dx_root_extent_tree(&dx_et, dir, dx_root_bh); |
2796 | ret = ocfs2_insert_extent(osb, handle, dir, &dx_et, 0, | ||
2797 | dx_insert_blkno, 1, 0, NULL); | ||
2798 | if (ret) | ||
2799 | mlog_errno(ret); | ||
2800 | } | ||
2664 | } | 2801 | } |
2665 | 2802 | ||
2666 | /* | 2803 | /* |
@@ -2690,14 +2827,18 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2690 | if (ocfs2_supports_indexed_dirs(osb)) { | 2827 | if (ocfs2_supports_indexed_dirs(osb)) { |
2691 | unsigned int off; | 2828 | unsigned int off; |
2692 | 2829 | ||
2693 | /* | 2830 | if (!dx_inline) { |
2694 | * We need to return the correct block within the | 2831 | /* |
2695 | * cluster which should hold our entry. | 2832 | * We need to return the correct block within the |
2696 | */ | 2833 | * cluster which should hold our entry. |
2697 | off = ocfs2_dx_dir_hash_idx(OCFS2_SB(dir->i_sb), | 2834 | */ |
2698 | &lookup->dl_hinfo); | 2835 | off = ocfs2_dx_dir_hash_idx(OCFS2_SB(dir->i_sb), |
2699 | get_bh(dx_leaves[off]); | 2836 | &lookup->dl_hinfo); |
2700 | lookup->dl_dx_leaf_bh = dx_leaves[off]; | 2837 | get_bh(dx_leaves[off]); |
2838 | lookup->dl_dx_leaf_bh = dx_leaves[off]; | ||
2839 | } | ||
2840 | lookup->dl_dx_root_bh = dx_root_bh; | ||
2841 | dx_root_bh = NULL; | ||
2701 | } | 2842 | } |
2702 | 2843 | ||
2703 | out_commit: | 2844 | out_commit: |
@@ -3506,6 +3647,138 @@ out: | |||
3506 | return ret; | 3647 | return ret; |
3507 | } | 3648 | } |
3508 | 3649 | ||
3650 | static int ocfs2_expand_inline_dx_root(struct inode *dir, | ||
3651 | struct buffer_head *dx_root_bh) | ||
3652 | { | ||
3653 | int ret, num_dx_leaves, i, j, did_quota = 0; | ||
3654 | struct buffer_head **dx_leaves = NULL; | ||
3655 | struct ocfs2_extent_tree et; | ||
3656 | u64 insert_blkno; | ||
3657 | struct ocfs2_alloc_context *data_ac = NULL; | ||
3658 | struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); | ||
3659 | handle_t *handle = NULL; | ||
3660 | struct ocfs2_dx_root_block *dx_root; | ||
3661 | struct ocfs2_dx_entry_list *entry_list; | ||
3662 | struct ocfs2_dx_entry *dx_entry; | ||
3663 | struct ocfs2_dx_leaf *target_leaf; | ||
3664 | |||
3665 | ret = ocfs2_reserve_clusters(osb, 1, &data_ac); | ||
3666 | if (ret) { | ||
3667 | mlog_errno(ret); | ||
3668 | goto out; | ||
3669 | } | ||
3670 | |||
3671 | dx_leaves = ocfs2_dx_dir_kmalloc_leaves(osb->sb, &num_dx_leaves); | ||
3672 | if (!dx_leaves) { | ||
3673 | ret = -ENOMEM; | ||
3674 | mlog_errno(ret); | ||
3675 | goto out; | ||
3676 | } | ||
3677 | |||
3678 | handle = ocfs2_start_trans(osb, ocfs2_calc_dxi_expand_credits(osb->sb)); | ||
3679 | if (IS_ERR(handle)) { | ||
3680 | ret = PTR_ERR(handle); | ||
3681 | mlog_errno(ret); | ||
3682 | goto out; | ||
3683 | } | ||
3684 | |||
3685 | if (vfs_dq_alloc_space_nodirty(dir, | ||
3686 | ocfs2_clusters_to_bytes(osb->sb, 1))) { | ||
3687 | ret = -EDQUOT; | ||
3688 | goto out_commit; | ||
3689 | } | ||
3690 | did_quota = 1; | ||
3691 | |||
3692 | /* | ||
3693 | * We do this up front, before the allocation, so that a | ||
3694 | * failure to add the dx_root_bh to the journal won't result | ||
3695 | * us losing clusters. | ||
3696 | */ | ||
3697 | ret = ocfs2_journal_access_dr(handle, dir, dx_root_bh, | ||
3698 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
3699 | if (ret) { | ||
3700 | mlog_errno(ret); | ||
3701 | goto out_commit; | ||
3702 | } | ||
3703 | |||
3704 | ret = __ocfs2_dx_dir_new_cluster(dir, 0, handle, data_ac, dx_leaves, | ||
3705 | num_dx_leaves, &insert_blkno); | ||
3706 | if (ret) { | ||
3707 | mlog_errno(ret); | ||
3708 | goto out_commit; | ||
3709 | } | ||
3710 | |||
3711 | /* | ||
3712 | * Transfer the entries from our dx_root into the appropriate | ||
3713 | * block | ||
3714 | */ | ||
3715 | dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data; | ||
3716 | entry_list = &dx_root->dr_entries; | ||
3717 | |||
3718 | for (i = 0; i < le16_to_cpu(entry_list->de_num_used); i++) { | ||
3719 | dx_entry = &entry_list->de_entries[i]; | ||
3720 | |||
3721 | j = __ocfs2_dx_dir_hash_idx(osb, | ||
3722 | le32_to_cpu(dx_entry->dx_minor_hash)); | ||
3723 | target_leaf = (struct ocfs2_dx_leaf *)dx_leaves[j]->b_data; | ||
3724 | |||
3725 | ocfs2_dx_dir_leaf_insert_tail(target_leaf, dx_entry); | ||
3726 | |||
3727 | /* Each leaf has been passed to the journal already | ||
3728 | * via __ocfs2_dx_dir_new_cluster() */ | ||
3729 | } | ||
3730 | |||
3731 | dx_root->dr_flags &= ~OCFS2_DX_FLAG_INLINE; | ||
3732 | memset(&dx_root->dr_list, 0, osb->sb->s_blocksize - | ||
3733 | offsetof(struct ocfs2_dx_root_block, dr_list)); | ||
3734 | dx_root->dr_list.l_count = | ||
3735 | cpu_to_le16(ocfs2_extent_recs_per_dx_root(osb->sb)); | ||
3736 | |||
3737 | /* This should never fail considering we start with an empty | ||
3738 | * dx_root. */ | ||
3739 | ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh); | ||
3740 | ret = ocfs2_insert_extent(osb, handle, dir, &et, 0, | ||
3741 | insert_blkno, 1, 0, NULL); | ||
3742 | if (ret) | ||
3743 | mlog_errno(ret); | ||
3744 | did_quota = 0; | ||
3745 | |||
3746 | ocfs2_journal_dirty(handle, dx_root_bh); | ||
3747 | |||
3748 | out_commit: | ||
3749 | if (ret < 0 && did_quota) | ||
3750 | vfs_dq_free_space_nodirty(dir, | ||
3751 | ocfs2_clusters_to_bytes(dir->i_sb, 1)); | ||
3752 | |||
3753 | ocfs2_commit_trans(osb, handle); | ||
3754 | |||
3755 | out: | ||
3756 | if (data_ac) | ||
3757 | ocfs2_free_alloc_context(data_ac); | ||
3758 | |||
3759 | if (dx_leaves) { | ||
3760 | for (i = 0; i < num_dx_leaves; i++) | ||
3761 | brelse(dx_leaves[i]); | ||
3762 | kfree(dx_leaves); | ||
3763 | } | ||
3764 | return ret; | ||
3765 | } | ||
3766 | |||
3767 | static int ocfs2_inline_dx_has_space(struct buffer_head *dx_root_bh) | ||
3768 | { | ||
3769 | struct ocfs2_dx_root_block *dx_root; | ||
3770 | struct ocfs2_dx_entry_list *entry_list; | ||
3771 | |||
3772 | dx_root = (struct ocfs2_dx_root_block *) dx_root_bh->b_data; | ||
3773 | entry_list = &dx_root->dr_entries; | ||
3774 | |||
3775 | if (le16_to_cpu(entry_list->de_num_used) >= | ||
3776 | le16_to_cpu(entry_list->de_count)) | ||
3777 | return -ENOSPC; | ||
3778 | |||
3779 | return 0; | ||
3780 | } | ||
3781 | |||
3509 | static int ocfs2_find_dir_space_dx(struct ocfs2_super *osb, struct inode *dir, | 3782 | static int ocfs2_find_dir_space_dx(struct ocfs2_super *osb, struct inode *dir, |
3510 | struct buffer_head *di_bh, const char *name, | 3783 | struct buffer_head *di_bh, const char *name, |
3511 | int namelen, | 3784 | int namelen, |
@@ -3527,6 +3800,23 @@ static int ocfs2_find_dir_space_dx(struct ocfs2_super *osb, struct inode *dir, | |||
3527 | } | 3800 | } |
3528 | 3801 | ||
3529 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | 3802 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; |
3803 | if (ocfs2_dx_root_inline(dx_root)) { | ||
3804 | ret = ocfs2_inline_dx_has_space(dx_root_bh); | ||
3805 | |||
3806 | if (ret == 0) | ||
3807 | goto search_el; | ||
3808 | |||
3809 | /* | ||
3810 | * We ran out of room in the root block. Expand it to | ||
3811 | * an extent, then allow ocfs2_find_dir_space_dx to do | ||
3812 | * the rest. | ||
3813 | */ | ||
3814 | ret = ocfs2_expand_inline_dx_root(dir, dx_root_bh); | ||
3815 | if (ret) { | ||
3816 | mlog_errno(ret); | ||
3817 | goto out; | ||
3818 | } | ||
3819 | } | ||
3530 | 3820 | ||
3531 | restart_search: | 3821 | restart_search: |
3532 | ret = ocfs2_dx_dir_lookup(dir, &dx_root->dr_list, &lookup->dl_hinfo, | 3822 | ret = ocfs2_dx_dir_lookup(dir, &dx_root->dr_list, &lookup->dl_hinfo, |
@@ -3578,8 +3868,11 @@ restart_search: | |||
3578 | goto restart_search; | 3868 | goto restart_search; |
3579 | } | 3869 | } |
3580 | 3870 | ||
3871 | search_el: | ||
3581 | lookup->dl_dx_leaf_bh = dx_leaf_bh; | 3872 | lookup->dl_dx_leaf_bh = dx_leaf_bh; |
3582 | dx_leaf_bh = NULL; | 3873 | dx_leaf_bh = NULL; |
3874 | lookup->dl_dx_root_bh = dx_root_bh; | ||
3875 | dx_root_bh = NULL; | ||
3583 | 3876 | ||
3584 | out: | 3877 | out: |
3585 | brelse(dx_leaf_bh); | 3878 | brelse(dx_leaf_bh); |
@@ -3774,10 +4067,12 @@ int ocfs2_dx_dir_truncate(struct inode *dir, struct buffer_head *di_bh) | |||
3774 | mlog_errno(ret); | 4067 | mlog_errno(ret); |
3775 | goto out; | 4068 | goto out; |
3776 | } | 4069 | } |
4070 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | ||
3777 | 4071 | ||
3778 | ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh); | 4072 | if (ocfs2_dx_root_inline(dx_root)) |
4073 | goto remove_index; | ||
3779 | 4074 | ||
3780 | dx_root = (struct ocfs2_dx_root_block *)dx_root_bh->b_data; | 4075 | ocfs2_init_dx_root_extent_tree(&et, dir, dx_root_bh); |
3781 | 4076 | ||
3782 | /* XXX: What if dr_clusters is too large? */ | 4077 | /* XXX: What if dr_clusters is too large? */ |
3783 | while (le32_to_cpu(dx_root->dr_clusters)) { | 4078 | while (le32_to_cpu(dx_root->dr_clusters)) { |
@@ -3803,6 +4098,7 @@ int ocfs2_dx_dir_truncate(struct inode *dir, struct buffer_head *di_bh) | |||
3803 | major_hash = cpos - 1; | 4098 | major_hash = cpos - 1; |
3804 | } | 4099 | } |
3805 | 4100 | ||
4101 | remove_index: | ||
3806 | ret = ocfs2_dx_dir_remove_index(dir, di_bh, dx_root_bh); | 4102 | ret = ocfs2_dx_dir_remove_index(dir, di_bh, dx_root_bh); |
3807 | if (ret) { | 4103 | if (ret) { |
3808 | mlog_errno(ret); | 4104 | mlog_errno(ret); |
diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index d273aaef2ec2..07b0416cdd42 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h | |||
@@ -37,6 +37,8 @@ struct ocfs2_dir_lookup_result { | |||
37 | struct ocfs2_dir_entry *dl_entry; /* Target dirent in | 37 | struct ocfs2_dir_entry *dl_entry; /* Target dirent in |
38 | * unindexed leaf */ | 38 | * unindexed leaf */ |
39 | 39 | ||
40 | struct buffer_head *dl_dx_root_bh; /* Root of indexed | ||
41 | * tree */ | ||
40 | struct buffer_head *dl_dx_leaf_bh; /* Indexed leaf block */ | 42 | struct buffer_head *dl_dx_leaf_bh; /* Indexed leaf block */ |
41 | struct ocfs2_dx_entry *dl_dx_entry; /* Target dx_entry in | 43 | struct ocfs2_dx_entry *dl_dx_entry; /* Target dx_entry in |
42 | * indexed leaf */ | 44 | * indexed leaf */ |
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 4939c04290ca..5585dde91344 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h | |||
@@ -458,6 +458,16 @@ static inline int ocfs2_rename_credits(struct super_block *sb) | |||
458 | #define OCFS2_DX_ROOT_REMOVE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + \ | 458 | #define OCFS2_DX_ROOT_REMOVE_CREDITS (OCFS2_INODE_UPDATE_CREDITS + \ |
459 | OCFS2_SUBALLOC_FREE) | 459 | OCFS2_SUBALLOC_FREE) |
460 | 460 | ||
461 | static inline int ocfs2_calc_dxi_expand_credits(struct super_block *sb) | ||
462 | { | ||
463 | int credits = 1 + OCFS2_SUBALLOC_ALLOC; | ||
464 | |||
465 | credits += ocfs2_clusters_to_blocks(sb, 1); | ||
466 | credits += ocfs2_quota_trans_credits(sb); | ||
467 | |||
468 | return credits; | ||
469 | } | ||
470 | |||
461 | /* | 471 | /* |
462 | * Please note that the caller must make sure that root_el is the root | 472 | * Please note that the caller must make sure that root_el is the root |
463 | * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise | 473 | * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise |
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 0c5507193200..f911edc8378b 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -321,10 +321,8 @@ static int ocfs2_mknod(struct inode *dir, | |||
321 | want_clusters += 1; | 321 | want_clusters += 1; |
322 | 322 | ||
323 | /* Dir indexing requires extra space as well */ | 323 | /* Dir indexing requires extra space as well */ |
324 | if (ocfs2_supports_indexed_dirs(osb)) { | 324 | if (ocfs2_supports_indexed_dirs(osb)) |
325 | want_clusters++; | ||
326 | want_meta++; | 325 | want_meta++; |
327 | } | ||
328 | } | 326 | } |
329 | 327 | ||
330 | status = ocfs2_reserve_new_metadata_blocks(osb, want_meta, &meta_ac); | 328 | status = ocfs2_reserve_new_metadata_blocks(osb, want_meta, &meta_ac); |
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index 036eb03950a3..1d1c54ea5bc4 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
@@ -815,6 +815,8 @@ struct ocfs2_dx_entry_list { | |||
815 | * length de_num_used */ | 815 | * length de_num_used */ |
816 | }; | 816 | }; |
817 | 817 | ||
818 | #define OCFS2_DX_FLAG_INLINE 0x01 | ||
819 | |||
818 | /* | 820 | /* |
819 | * A directory indexing block. Each indexed directory has one of these, | 821 | * A directory indexing block. Each indexed directory has one of these, |
820 | * pointed to by ocfs2_dinode. | 822 | * pointed to by ocfs2_dinode. |
@@ -835,13 +837,21 @@ struct ocfs2_dx_root_block { | |||
835 | * extent block */ | 837 | * extent block */ |
836 | __le32 dr_clusters; /* Clusters allocated | 838 | __le32 dr_clusters; /* Clusters allocated |
837 | * to the indexed tree. */ | 839 | * to the indexed tree. */ |
838 | __le32 dr_reserved1; | 840 | __u8 dr_flags; /* OCFS2_DX_FLAG_* flags */ |
841 | __u8 dr_reserved0; | ||
842 | __le16 dr_reserved1; | ||
839 | __le64 dr_dir_blkno; /* Pointer to parent inode */ | 843 | __le64 dr_dir_blkno; /* Pointer to parent inode */ |
840 | __le64 dr_reserved2; | 844 | __le64 dr_reserved2; |
841 | __le64 dr_reserved3[16]; | 845 | __le64 dr_reserved3[16]; |
842 | struct ocfs2_extent_list dr_list; /* Keep this aligned to 128 | 846 | union { |
843 | * bits for maximum space | 847 | struct ocfs2_extent_list dr_list; /* Keep this aligned to 128 |
844 | * efficiency. */ | 848 | * bits for maximum space |
849 | * efficiency. */ | ||
850 | struct ocfs2_dx_entry_list dr_entries; /* In-root-block list of | ||
851 | * entries. We grow out | ||
852 | * to extents if this | ||
853 | * gets too big. */ | ||
854 | }; | ||
845 | }; | 855 | }; |
846 | 856 | ||
847 | /* | 857 | /* |
@@ -1228,6 +1238,16 @@ static inline int ocfs2_dx_entries_per_leaf(struct super_block *sb) | |||
1228 | return size / sizeof(struct ocfs2_dx_entry); | 1238 | return size / sizeof(struct ocfs2_dx_entry); |
1229 | } | 1239 | } |
1230 | 1240 | ||
1241 | static inline int ocfs2_dx_entries_per_root(struct super_block *sb) | ||
1242 | { | ||
1243 | int size; | ||
1244 | |||
1245 | size = sb->s_blocksize - | ||
1246 | offsetof(struct ocfs2_dx_root_block, dr_entries.de_entries); | ||
1247 | |||
1248 | return size / sizeof(struct ocfs2_dx_entry); | ||
1249 | } | ||
1250 | |||
1231 | static inline u16 ocfs2_local_alloc_size(struct super_block *sb) | 1251 | static inline u16 ocfs2_local_alloc_size(struct super_block *sb) |
1232 | { | 1252 | { |
1233 | u16 size; | 1253 | u16 size; |