diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/localalloc.c | 8 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.c | 147 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.h | 2 |
4 files changed, 145 insertions, 13 deletions
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 0d1973ea32b0..1f17a4d08287 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c | |||
@@ -840,6 +840,12 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, | |||
840 | 840 | ||
841 | mlog(0, "Allocating %u clusters for a new window.\n", | 841 | mlog(0, "Allocating %u clusters for a new window.\n", |
842 | ocfs2_local_alloc_window_bits(osb)); | 842 | ocfs2_local_alloc_window_bits(osb)); |
843 | |||
844 | /* Instruct the allocation code to try the most recently used | ||
845 | * cluster group. We'll re-record the group used this pass | ||
846 | * below. */ | ||
847 | ac->ac_last_group = osb->la_last_gd; | ||
848 | |||
843 | /* we used the generic suballoc reserve function, but we set | 849 | /* we used the generic suballoc reserve function, but we set |
844 | * everything up nicely, so there's no reason why we can't use | 850 | * everything up nicely, so there's no reason why we can't use |
845 | * the more specific cluster api to claim bits. */ | 851 | * the more specific cluster api to claim bits. */ |
@@ -852,6 +858,8 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, | |||
852 | goto bail; | 858 | goto bail; |
853 | } | 859 | } |
854 | 860 | ||
861 | osb->la_last_gd = ac->ac_last_group; | ||
862 | |||
855 | la->la_bm_off = cpu_to_le32(cluster_off); | 863 | la->la_bm_off = cpu_to_le32(cluster_off); |
856 | alloc->id1.bitmap1.i_total = cpu_to_le32(cluster_count); | 864 | alloc->id1.bitmap1.i_total = cpu_to_le32(cluster_count); |
857 | /* just in case... In the future when we find space ourselves, | 865 | /* just in case... In the future when we find space ourselves, |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index d52100d49b6c..0462a7f4e21b 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -236,6 +236,7 @@ struct ocfs2_super | |||
236 | 236 | ||
237 | enum ocfs2_local_alloc_state local_alloc_state; | 237 | enum ocfs2_local_alloc_state local_alloc_state; |
238 | struct buffer_head *local_alloc_bh; | 238 | struct buffer_head *local_alloc_bh; |
239 | u64 la_last_gd; | ||
239 | 240 | ||
240 | /* Next two fields are for local node slot recovery during | 241 | /* Next two fields are for local node slot recovery during |
241 | * mount. */ | 242 | * mount. */ |
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 7ac68cac041d..9d91e66f51a9 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -70,12 +70,6 @@ static int ocfs2_block_group_search(struct inode *inode, | |||
70 | struct buffer_head *group_bh, | 70 | struct buffer_head *group_bh, |
71 | u32 bits_wanted, u32 min_bits, | 71 | u32 bits_wanted, u32 min_bits, |
72 | u16 *bit_off, u16 *bits_found); | 72 | u16 *bit_off, u16 *bits_found); |
73 | static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | ||
74 | u32 bits_wanted, | ||
75 | u32 min_bits, | ||
76 | u16 *bit_off, | ||
77 | unsigned int *num_bits, | ||
78 | u64 *bg_blkno); | ||
79 | static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, | 73 | static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, |
80 | struct ocfs2_alloc_context *ac, | 74 | struct ocfs2_alloc_context *ac, |
81 | u32 bits_wanted, | 75 | u32 bits_wanted, |
@@ -1030,12 +1024,103 @@ static int ocfs2_block_group_search(struct inode *inode, | |||
1030 | return ret; | 1024 | return ret; |
1031 | } | 1025 | } |
1032 | 1026 | ||
1027 | static int ocfs2_alloc_dinode_update_counts(struct inode *inode, | ||
1028 | struct ocfs2_journal_handle *handle, | ||
1029 | struct buffer_head *di_bh, | ||
1030 | u32 num_bits, | ||
1031 | u16 chain) | ||
1032 | { | ||
1033 | int ret; | ||
1034 | u32 tmp_used; | ||
1035 | struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data; | ||
1036 | struct ocfs2_chain_list *cl = (struct ocfs2_chain_list *) &di->id2.i_chain; | ||
1037 | |||
1038 | ret = ocfs2_journal_access(handle, inode, di_bh, | ||
1039 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1040 | if (ret < 0) { | ||
1041 | mlog_errno(ret); | ||
1042 | goto out; | ||
1043 | } | ||
1044 | |||
1045 | tmp_used = le32_to_cpu(di->id1.bitmap1.i_used); | ||
1046 | di->id1.bitmap1.i_used = cpu_to_le32(num_bits + tmp_used); | ||
1047 | le32_add_cpu(&cl->cl_recs[chain].c_free, -num_bits); | ||
1048 | |||
1049 | ret = ocfs2_journal_dirty(handle, di_bh); | ||
1050 | if (ret < 0) | ||
1051 | mlog_errno(ret); | ||
1052 | |||
1053 | out: | ||
1054 | return ret; | ||
1055 | } | ||
1056 | |||
1057 | static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac, | ||
1058 | u32 bits_wanted, | ||
1059 | u32 min_bits, | ||
1060 | u16 *bit_off, | ||
1061 | unsigned int *num_bits, | ||
1062 | u64 gd_blkno, | ||
1063 | u16 *bits_left) | ||
1064 | { | ||
1065 | int ret; | ||
1066 | u16 found; | ||
1067 | struct buffer_head *group_bh = NULL; | ||
1068 | struct ocfs2_group_desc *gd; | ||
1069 | struct inode *alloc_inode = ac->ac_inode; | ||
1070 | struct ocfs2_journal_handle *handle = ac->ac_handle; | ||
1071 | |||
1072 | ret = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), gd_blkno, | ||
1073 | &group_bh, OCFS2_BH_CACHED, alloc_inode); | ||
1074 | if (ret < 0) { | ||
1075 | mlog_errno(ret); | ||
1076 | return ret; | ||
1077 | } | ||
1078 | |||
1079 | gd = (struct ocfs2_group_desc *) group_bh->b_data; | ||
1080 | if (!OCFS2_IS_VALID_GROUP_DESC(gd)) { | ||
1081 | OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, gd); | ||
1082 | ret = -EIO; | ||
1083 | goto out; | ||
1084 | } | ||
1085 | |||
1086 | ret = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, min_bits, | ||
1087 | bit_off, &found); | ||
1088 | if (ret < 0) { | ||
1089 | if (ret != -ENOSPC) | ||
1090 | mlog_errno(ret); | ||
1091 | goto out; | ||
1092 | } | ||
1093 | |||
1094 | *num_bits = found; | ||
1095 | |||
1096 | ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh, | ||
1097 | *num_bits, | ||
1098 | le16_to_cpu(gd->bg_chain)); | ||
1099 | if (ret < 0) { | ||
1100 | mlog_errno(ret); | ||
1101 | goto out; | ||
1102 | } | ||
1103 | |||
1104 | ret = ocfs2_block_group_set_bits(handle, alloc_inode, gd, group_bh, | ||
1105 | *bit_off, *num_bits); | ||
1106 | if (ret < 0) | ||
1107 | mlog_errno(ret); | ||
1108 | |||
1109 | *bits_left = le16_to_cpu(gd->bg_free_bits_count); | ||
1110 | |||
1111 | out: | ||
1112 | brelse(group_bh); | ||
1113 | |||
1114 | return ret; | ||
1115 | } | ||
1116 | |||
1033 | static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | 1117 | static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, |
1034 | u32 bits_wanted, | 1118 | u32 bits_wanted, |
1035 | u32 min_bits, | 1119 | u32 min_bits, |
1036 | u16 *bit_off, | 1120 | u16 *bit_off, |
1037 | unsigned int *num_bits, | 1121 | unsigned int *num_bits, |
1038 | u64 *bg_blkno) | 1122 | u64 *bg_blkno, |
1123 | u16 *bits_left) | ||
1039 | { | 1124 | { |
1040 | int status; | 1125 | int status; |
1041 | u16 chain, tmp_bits; | 1126 | u16 chain, tmp_bits; |
@@ -1173,6 +1258,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, | |||
1173 | (unsigned long long)fe->i_blkno); | 1258 | (unsigned long long)fe->i_blkno); |
1174 | 1259 | ||
1175 | *bg_blkno = le64_to_cpu(bg->bg_blkno); | 1260 | *bg_blkno = le64_to_cpu(bg->bg_blkno); |
1261 | *bits_left = le16_to_cpu(bg->bg_free_bits_count); | ||
1176 | bail: | 1262 | bail: |
1177 | if (group_bh) | 1263 | if (group_bh) |
1178 | brelse(group_bh); | 1264 | brelse(group_bh); |
@@ -1194,6 +1280,8 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, | |||
1194 | { | 1280 | { |
1195 | int status; | 1281 | int status; |
1196 | u16 victim, i; | 1282 | u16 victim, i; |
1283 | u16 bits_left = 0; | ||
1284 | u64 hint_blkno = ac->ac_last_group; | ||
1197 | struct ocfs2_chain_list *cl; | 1285 | struct ocfs2_chain_list *cl; |
1198 | struct ocfs2_dinode *fe; | 1286 | struct ocfs2_dinode *fe; |
1199 | 1287 | ||
@@ -1220,6 +1308,28 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, | |||
1220 | goto bail; | 1308 | goto bail; |
1221 | } | 1309 | } |
1222 | 1310 | ||
1311 | if (hint_blkno) { | ||
1312 | /* Attempt to short-circuit the usual search mechanism | ||
1313 | * by jumping straight to the most recently used | ||
1314 | * allocation group. This helps us mantain some | ||
1315 | * contiguousness across allocations. */ | ||
1316 | status = ocfs2_search_one_group(ac, bits_wanted, min_bits, | ||
1317 | bit_off, num_bits, | ||
1318 | hint_blkno, &bits_left); | ||
1319 | if (!status) { | ||
1320 | /* Be careful to update *bg_blkno here as the | ||
1321 | * caller is expecting it to be filled in, and | ||
1322 | * ocfs2_search_one_group() won't do that for | ||
1323 | * us. */ | ||
1324 | *bg_blkno = hint_blkno; | ||
1325 | goto set_hint; | ||
1326 | } | ||
1327 | if (status < 0 && status != -ENOSPC) { | ||
1328 | mlog_errno(status); | ||
1329 | goto bail; | ||
1330 | } | ||
1331 | } | ||
1332 | |||
1223 | cl = (struct ocfs2_chain_list *) &fe->id2.i_chain; | 1333 | cl = (struct ocfs2_chain_list *) &fe->id2.i_chain; |
1224 | 1334 | ||
1225 | victim = ocfs2_find_victim_chain(cl); | 1335 | victim = ocfs2_find_victim_chain(cl); |
@@ -1227,9 +1337,9 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, | |||
1227 | ac->ac_allow_chain_relink = 1; | 1337 | ac->ac_allow_chain_relink = 1; |
1228 | 1338 | ||
1229 | status = ocfs2_search_chain(ac, bits_wanted, min_bits, bit_off, | 1339 | status = ocfs2_search_chain(ac, bits_wanted, min_bits, bit_off, |
1230 | num_bits, bg_blkno); | 1340 | num_bits, bg_blkno, &bits_left); |
1231 | if (!status) | 1341 | if (!status) |
1232 | goto bail; | 1342 | goto set_hint; |
1233 | if (status < 0 && status != -ENOSPC) { | 1343 | if (status < 0 && status != -ENOSPC) { |
1234 | mlog_errno(status); | 1344 | mlog_errno(status); |
1235 | goto bail; | 1345 | goto bail; |
@@ -1251,8 +1361,8 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, | |||
1251 | 1361 | ||
1252 | ac->ac_chain = i; | 1362 | ac->ac_chain = i; |
1253 | status = ocfs2_search_chain(ac, bits_wanted, min_bits, | 1363 | status = ocfs2_search_chain(ac, bits_wanted, min_bits, |
1254 | bit_off, num_bits, | 1364 | bit_off, num_bits, bg_blkno, |
1255 | bg_blkno); | 1365 | &bits_left); |
1256 | if (!status) | 1366 | if (!status) |
1257 | break; | 1367 | break; |
1258 | if (status < 0 && status != -ENOSPC) { | 1368 | if (status < 0 && status != -ENOSPC) { |
@@ -1260,8 +1370,19 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, | |||
1260 | goto bail; | 1370 | goto bail; |
1261 | } | 1371 | } |
1262 | } | 1372 | } |
1263 | bail: | ||
1264 | 1373 | ||
1374 | set_hint: | ||
1375 | if (status != -ENOSPC) { | ||
1376 | /* If the next search of this group is not likely to | ||
1377 | * yield a suitable extent, then we reset the last | ||
1378 | * group hint so as to not waste a disk read */ | ||
1379 | if (bits_left < min_bits) | ||
1380 | ac->ac_last_group = 0; | ||
1381 | else | ||
1382 | ac->ac_last_group = *bg_blkno; | ||
1383 | } | ||
1384 | |||
1385 | bail: | ||
1265 | mlog_exit(status); | 1386 | mlog_exit(status); |
1266 | return status; | 1387 | return status; |
1267 | } | 1388 | } |
@@ -1415,7 +1536,7 @@ int ocfs2_claim_clusters(struct ocfs2_super *osb, | |||
1415 | { | 1536 | { |
1416 | int status; | 1537 | int status; |
1417 | unsigned int bits_wanted = ac->ac_bits_wanted - ac->ac_bits_given; | 1538 | unsigned int bits_wanted = ac->ac_bits_wanted - ac->ac_bits_given; |
1418 | u64 bg_blkno; | 1539 | u64 bg_blkno = 0; |
1419 | u16 bg_bit_off; | 1540 | u16 bg_bit_off; |
1420 | 1541 | ||
1421 | mlog_entry_void(); | 1542 | mlog_entry_void(); |
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index a76c82a7ceac..c787838d1052 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h | |||
@@ -49,6 +49,8 @@ struct ocfs2_alloc_context { | |||
49 | u16 ac_chain; | 49 | u16 ac_chain; |
50 | int ac_allow_chain_relink; | 50 | int ac_allow_chain_relink; |
51 | group_search_t *ac_group_search; | 51 | group_search_t *ac_group_search; |
52 | |||
53 | u64 ac_last_group; | ||
52 | }; | 54 | }; |
53 | 55 | ||
54 | void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac); | 56 | void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac); |