diff options
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r-- | fs/gfs2/rgrp.c | 104 |
1 files changed, 60 insertions, 44 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 708c287e1d0e..3552110b2e5f 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -25,10 +25,10 @@ | |||
25 | #include "rgrp.h" | 25 | #include "rgrp.h" |
26 | #include "super.h" | 26 | #include "super.h" |
27 | #include "trans.h" | 27 | #include "trans.h" |
28 | #include "ops_file.h" | ||
29 | #include "util.h" | 28 | #include "util.h" |
30 | #include "log.h" | 29 | #include "log.h" |
31 | #include "inode.h" | 30 | #include "inode.h" |
31 | #include "ops_address.h" | ||
32 | 32 | ||
33 | #define BFITNOENT ((u32)~0) | 33 | #define BFITNOENT ((u32)~0) |
34 | #define NO_BLOCK ((u64)~0) | 34 | #define NO_BLOCK ((u64)~0) |
@@ -126,41 +126,43 @@ static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer, | |||
126 | * Return: the block number (bitmap buffer scope) that was found | 126 | * Return: the block number (bitmap buffer scope) that was found |
127 | */ | 127 | */ |
128 | 128 | ||
129 | static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer, | 129 | static u32 gfs2_bitfit(unsigned char *buffer, unsigned int buflen, u32 goal, |
130 | unsigned int buflen, u32 goal, | 130 | unsigned char old_state) |
131 | unsigned char old_state) | ||
132 | { | 131 | { |
133 | unsigned char *byte, *end, alloc; | 132 | unsigned char *byte; |
134 | u32 blk = goal; | 133 | u32 blk = goal; |
135 | unsigned int bit; | 134 | unsigned int bit, bitlong; |
135 | unsigned long *plong, plong55; | ||
136 | 136 | ||
137 | byte = buffer + (goal / GFS2_NBBY); | 137 | byte = buffer + (goal / GFS2_NBBY); |
138 | plong = (unsigned long *)(buffer + (goal / GFS2_NBBY)); | ||
138 | bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; | 139 | bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE; |
139 | end = buffer + buflen; | 140 | bitlong = bit; |
140 | alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0; | 141 | #if BITS_PER_LONG == 32 |
141 | 142 | plong55 = 0x55555555; | |
142 | while (byte < end) { | 143 | #else |
143 | /* If we're looking for a free block we can eliminate all | 144 | plong55 = 0x5555555555555555; |
144 | bitmap settings with 0x55, which represents four data | 145 | #endif |
145 | blocks in a row. If we're looking for a data block, we can | 146 | while (byte < buffer + buflen) { |
146 | eliminate 0x00 which corresponds to four free blocks. */ | 147 | |
147 | if ((*byte & 0x55) == alloc) { | 148 | if (bitlong == 0 && old_state == 0 && *plong == plong55) { |
148 | blk += (8 - bit) >> 1; | 149 | plong++; |
149 | 150 | byte += sizeof(unsigned long); | |
150 | bit = 0; | 151 | blk += sizeof(unsigned long) * GFS2_NBBY; |
151 | byte++; | ||
152 | |||
153 | continue; | 152 | continue; |
154 | } | 153 | } |
155 | |||
156 | if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) | 154 | if (((*byte >> bit) & GFS2_BIT_MASK) == old_state) |
157 | return blk; | 155 | return blk; |
158 | |||
159 | bit += GFS2_BIT_SIZE; | 156 | bit += GFS2_BIT_SIZE; |
160 | if (bit >= 8) { | 157 | if (bit >= 8) { |
161 | bit = 0; | 158 | bit = 0; |
162 | byte++; | 159 | byte++; |
163 | } | 160 | } |
161 | bitlong += GFS2_BIT_SIZE; | ||
162 | if (bitlong >= sizeof(unsigned long) * 8) { | ||
163 | bitlong = 0; | ||
164 | plong++; | ||
165 | } | ||
164 | 166 | ||
165 | blk++; | 167 | blk++; |
166 | } | 168 | } |
@@ -817,11 +819,9 @@ void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd) | |||
817 | 819 | ||
818 | struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip) | 820 | struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip) |
819 | { | 821 | { |
820 | struct gfs2_alloc *al = &ip->i_alloc; | 822 | BUG_ON(ip->i_alloc != NULL); |
821 | 823 | ip->i_alloc = kzalloc(sizeof(struct gfs2_alloc), GFP_KERNEL); | |
822 | /* FIXME: Should assert that the correct locks are held here... */ | 824 | return ip->i_alloc; |
823 | memset(al, 0, sizeof(*al)); | ||
824 | return al; | ||
825 | } | 825 | } |
826 | 826 | ||
827 | /** | 827 | /** |
@@ -1059,26 +1059,34 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1059 | struct inode *inode = NULL; | 1059 | struct inode *inode = NULL; |
1060 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1060 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1061 | struct gfs2_rgrpd *rgd, *begin = NULL; | 1061 | struct gfs2_rgrpd *rgd, *begin = NULL; |
1062 | struct gfs2_alloc *al = &ip->i_alloc; | 1062 | struct gfs2_alloc *al = ip->i_alloc; |
1063 | int flags = LM_FLAG_TRY; | 1063 | int flags = LM_FLAG_TRY; |
1064 | int skipped = 0; | 1064 | int skipped = 0; |
1065 | int loops = 0; | 1065 | int loops = 0; |
1066 | int error; | 1066 | int error, rg_locked; |
1067 | 1067 | ||
1068 | /* Try recently successful rgrps */ | 1068 | /* Try recently successful rgrps */ |
1069 | 1069 | ||
1070 | rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); | 1070 | rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc); |
1071 | 1071 | ||
1072 | while (rgd) { | 1072 | while (rgd) { |
1073 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, | 1073 | rg_locked = 0; |
1074 | LM_FLAG_TRY, &al->al_rgd_gh); | 1074 | |
1075 | if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) { | ||
1076 | rg_locked = 1; | ||
1077 | error = 0; | ||
1078 | } else { | ||
1079 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, | ||
1080 | LM_FLAG_TRY, &al->al_rgd_gh); | ||
1081 | } | ||
1075 | switch (error) { | 1082 | switch (error) { |
1076 | case 0: | 1083 | case 0: |
1077 | if (try_rgrp_fit(rgd, al)) | 1084 | if (try_rgrp_fit(rgd, al)) |
1078 | goto out; | 1085 | goto out; |
1079 | if (rgd->rd_flags & GFS2_RDF_CHECK) | 1086 | if (rgd->rd_flags & GFS2_RDF_CHECK) |
1080 | inode = try_rgrp_unlink(rgd, last_unlinked); | 1087 | inode = try_rgrp_unlink(rgd, last_unlinked); |
1081 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1088 | if (!rg_locked) |
1089 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | ||
1082 | if (inode) | 1090 | if (inode) |
1083 | return inode; | 1091 | return inode; |
1084 | rgd = recent_rgrp_next(rgd, 1); | 1092 | rgd = recent_rgrp_next(rgd, 1); |
@@ -1098,15 +1106,23 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1098 | begin = rgd = forward_rgrp_get(sdp); | 1106 | begin = rgd = forward_rgrp_get(sdp); |
1099 | 1107 | ||
1100 | for (;;) { | 1108 | for (;;) { |
1101 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags, | 1109 | rg_locked = 0; |
1102 | &al->al_rgd_gh); | 1110 | |
1111 | if (gfs2_glock_is_locked_by_me(rgd->rd_gl)) { | ||
1112 | rg_locked = 1; | ||
1113 | error = 0; | ||
1114 | } else { | ||
1115 | error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags, | ||
1116 | &al->al_rgd_gh); | ||
1117 | } | ||
1103 | switch (error) { | 1118 | switch (error) { |
1104 | case 0: | 1119 | case 0: |
1105 | if (try_rgrp_fit(rgd, al)) | 1120 | if (try_rgrp_fit(rgd, al)) |
1106 | goto out; | 1121 | goto out; |
1107 | if (rgd->rd_flags & GFS2_RDF_CHECK) | 1122 | if (rgd->rd_flags & GFS2_RDF_CHECK) |
1108 | inode = try_rgrp_unlink(rgd, last_unlinked); | 1123 | inode = try_rgrp_unlink(rgd, last_unlinked); |
1109 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1124 | if (!rg_locked) |
1125 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | ||
1110 | if (inode) | 1126 | if (inode) |
1111 | return inode; | 1127 | return inode; |
1112 | break; | 1128 | break; |
@@ -1158,7 +1174,7 @@ out: | |||
1158 | int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) | 1174 | int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) |
1159 | { | 1175 | { |
1160 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1176 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1161 | struct gfs2_alloc *al = &ip->i_alloc; | 1177 | struct gfs2_alloc *al = ip->i_alloc; |
1162 | struct inode *inode; | 1178 | struct inode *inode; |
1163 | int error = 0; | 1179 | int error = 0; |
1164 | u64 last_unlinked = NO_BLOCK; | 1180 | u64 last_unlinked = NO_BLOCK; |
@@ -1204,7 +1220,7 @@ try_again: | |||
1204 | void gfs2_inplace_release(struct gfs2_inode *ip) | 1220 | void gfs2_inplace_release(struct gfs2_inode *ip) |
1205 | { | 1221 | { |
1206 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1222 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1207 | struct gfs2_alloc *al = &ip->i_alloc; | 1223 | struct gfs2_alloc *al = ip->i_alloc; |
1208 | 1224 | ||
1209 | if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1) | 1225 | if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1) |
1210 | fs_warn(sdp, "al_alloced = %u, al_requested = %u " | 1226 | fs_warn(sdp, "al_alloced = %u, al_requested = %u " |
@@ -1213,7 +1229,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip) | |||
1213 | al->al_line); | 1229 | al->al_line); |
1214 | 1230 | ||
1215 | al->al_rgd = NULL; | 1231 | al->al_rgd = NULL; |
1216 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1232 | if (al->al_rgd_gh.gh_gl) |
1233 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | ||
1217 | if (ip != GFS2_I(sdp->sd_rindex)) | 1234 | if (ip != GFS2_I(sdp->sd_rindex)) |
1218 | gfs2_glock_dq_uninit(&al->al_ri_gh); | 1235 | gfs2_glock_dq_uninit(&al->al_ri_gh); |
1219 | } | 1236 | } |
@@ -1301,11 +1318,10 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, | |||
1301 | /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone | 1318 | /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone |
1302 | bitmaps, so we must search the originals for that. */ | 1319 | bitmaps, so we must search the originals for that. */ |
1303 | if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) | 1320 | if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone) |
1304 | blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset, | 1321 | blk = gfs2_bitfit(bi->bi_clone + bi->bi_offset, |
1305 | bi->bi_len, goal, old_state); | 1322 | bi->bi_len, goal, old_state); |
1306 | else | 1323 | else |
1307 | blk = gfs2_bitfit(rgd, | 1324 | blk = gfs2_bitfit(bi->bi_bh->b_data + bi->bi_offset, |
1308 | bi->bi_bh->b_data + bi->bi_offset, | ||
1309 | bi->bi_len, goal, old_state); | 1325 | bi->bi_len, goal, old_state); |
1310 | if (blk != BFITNOENT) | 1326 | if (blk != BFITNOENT) |
1311 | break; | 1327 | break; |
@@ -1394,7 +1410,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, | |||
1394 | u64 gfs2_alloc_data(struct gfs2_inode *ip) | 1410 | u64 gfs2_alloc_data(struct gfs2_inode *ip) |
1395 | { | 1411 | { |
1396 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1412 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1397 | struct gfs2_alloc *al = &ip->i_alloc; | 1413 | struct gfs2_alloc *al = ip->i_alloc; |
1398 | struct gfs2_rgrpd *rgd = al->al_rgd; | 1414 | struct gfs2_rgrpd *rgd = al->al_rgd; |
1399 | u32 goal, blk; | 1415 | u32 goal, blk; |
1400 | u64 block; | 1416 | u64 block; |
@@ -1439,7 +1455,7 @@ u64 gfs2_alloc_data(struct gfs2_inode *ip) | |||
1439 | u64 gfs2_alloc_meta(struct gfs2_inode *ip) | 1455 | u64 gfs2_alloc_meta(struct gfs2_inode *ip) |
1440 | { | 1456 | { |
1441 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1457 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1442 | struct gfs2_alloc *al = &ip->i_alloc; | 1458 | struct gfs2_alloc *al = ip->i_alloc; |
1443 | struct gfs2_rgrpd *rgd = al->al_rgd; | 1459 | struct gfs2_rgrpd *rgd = al->al_rgd; |
1444 | u32 goal, blk; | 1460 | u32 goal, blk; |
1445 | u64 block; | 1461 | u64 block; |
@@ -1485,7 +1501,7 @@ u64 gfs2_alloc_meta(struct gfs2_inode *ip) | |||
1485 | u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) | 1501 | u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation) |
1486 | { | 1502 | { |
1487 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); | 1503 | struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); |
1488 | struct gfs2_alloc *al = &dip->i_alloc; | 1504 | struct gfs2_alloc *al = dip->i_alloc; |
1489 | struct gfs2_rgrpd *rgd = al->al_rgd; | 1505 | struct gfs2_rgrpd *rgd = al->al_rgd; |
1490 | u32 blk; | 1506 | u32 blk; |
1491 | u64 block; | 1507 | u64 block; |