diff options
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r-- | fs/gfs2/rgrp.c | 87 |
1 files changed, 70 insertions, 17 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 027f6ec5b0d9..fd3fd9074779 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "ops_file.h" | 28 | #include "ops_file.h" |
29 | #include "util.h" | 29 | #include "util.h" |
30 | #include "log.h" | 30 | #include "log.h" |
31 | #include "inode.h" | ||
31 | 32 | ||
32 | #define BFITNOENT ((u32)~0) | 33 | #define BFITNOENT ((u32)~0) |
33 | 34 | ||
@@ -50,6 +51,9 @@ static const char valid_change[16] = { | |||
50 | 1, 0, 0, 0 | 51 | 1, 0, 0, 0 |
51 | }; | 52 | }; |
52 | 53 | ||
54 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, | ||
55 | unsigned char old_state, unsigned char new_state); | ||
56 | |||
53 | /** | 57 | /** |
54 | * gfs2_setbit - Set a bit in the bitmaps | 58 | * gfs2_setbit - Set a bit in the bitmaps |
55 | * @buffer: the buffer that holds the bitmaps | 59 | * @buffer: the buffer that holds the bitmaps |
@@ -531,6 +535,7 @@ static int read_rindex_entry(struct gfs2_inode *ip, | |||
531 | 535 | ||
532 | rgd->rd_gl->gl_object = rgd; | 536 | rgd->rd_gl->gl_object = rgd; |
533 | rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; | 537 | rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1; |
538 | rgd->rd_flags |= GFS2_RDF_CHECK; | ||
534 | return error; | 539 | return error; |
535 | } | 540 | } |
536 | 541 | ||
@@ -846,6 +851,37 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) | |||
846 | } | 851 | } |
847 | 852 | ||
848 | /** | 853 | /** |
854 | * try_rgrp_unlink - Look for any unlinked, allocated, but unused inodes | ||
855 | * @rgd: The rgrp | ||
856 | * | ||
857 | * Returns: The inode, if one has been found | ||
858 | */ | ||
859 | |||
860 | static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) | ||
861 | { | ||
862 | struct inode *inode; | ||
863 | u32 goal = 0; | ||
864 | u64 ino; | ||
865 | |||
866 | for(;;) { | ||
867 | goal = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, | ||
868 | GFS2_BLKST_UNLINKED); | ||
869 | if (goal == 0) | ||
870 | return 0; | ||
871 | ino = goal + rgd->rd_data0; | ||
872 | if (ino <= *last_unlinked) | ||
873 | continue; | ||
874 | *last_unlinked = ino; | ||
875 | inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, ino, DT_UNKNOWN); | ||
876 | if (!IS_ERR(inode)) | ||
877 | return inode; | ||
878 | } | ||
879 | |||
880 | rgd->rd_flags &= ~GFS2_RDF_CHECK; | ||
881 | return NULL; | ||
882 | } | ||
883 | |||
884 | /** | ||
849 | * recent_rgrp_first - get first RG from "recent" list | 885 | * recent_rgrp_first - get first RG from "recent" list |
850 | * @sdp: The GFS2 superblock | 886 | * @sdp: The GFS2 superblock |
851 | * @rglast: address of the rgrp used last | 887 | * @rglast: address of the rgrp used last |
@@ -1006,8 +1042,9 @@ static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd) | |||
1006 | * Returns: errno | 1042 | * Returns: errno |
1007 | */ | 1043 | */ |
1008 | 1044 | ||
1009 | static int get_local_rgrp(struct gfs2_inode *ip) | 1045 | static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) |
1010 | { | 1046 | { |
1047 | struct inode *inode = NULL; | ||
1011 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1048 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1012 | struct gfs2_rgrpd *rgd, *begin = NULL; | 1049 | struct gfs2_rgrpd *rgd, *begin = NULL; |
1013 | struct gfs2_alloc *al = &ip->i_alloc; | 1050 | struct gfs2_alloc *al = &ip->i_alloc; |
@@ -1027,7 +1064,11 @@ static int get_local_rgrp(struct gfs2_inode *ip) | |||
1027 | case 0: | 1064 | case 0: |
1028 | if (try_rgrp_fit(rgd, al)) | 1065 | if (try_rgrp_fit(rgd, al)) |
1029 | goto out; | 1066 | goto out; |
1067 | if (rgd->rd_flags & GFS2_RDF_CHECK) | ||
1068 | inode = try_rgrp_unlink(rgd, last_unlinked); | ||
1030 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1069 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1070 | if (inode) | ||
1071 | return inode; | ||
1031 | rgd = recent_rgrp_next(rgd, 1); | 1072 | rgd = recent_rgrp_next(rgd, 1); |
1032 | break; | 1073 | break; |
1033 | 1074 | ||
@@ -1036,7 +1077,7 @@ static int get_local_rgrp(struct gfs2_inode *ip) | |||
1036 | break; | 1077 | break; |
1037 | 1078 | ||
1038 | default: | 1079 | default: |
1039 | return error; | 1080 | return ERR_PTR(error); |
1040 | } | 1081 | } |
1041 | } | 1082 | } |
1042 | 1083 | ||
@@ -1051,7 +1092,11 @@ static int get_local_rgrp(struct gfs2_inode *ip) | |||
1051 | case 0: | 1092 | case 0: |
1052 | if (try_rgrp_fit(rgd, al)) | 1093 | if (try_rgrp_fit(rgd, al)) |
1053 | goto out; | 1094 | goto out; |
1095 | if (rgd->rd_flags & GFS2_RDF_CHECK) | ||
1096 | inode = try_rgrp_unlink(rgd, last_unlinked); | ||
1054 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1097 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1098 | if (inode) | ||
1099 | return inode; | ||
1055 | break; | 1100 | break; |
1056 | 1101 | ||
1057 | case GLR_TRYFAILED: | 1102 | case GLR_TRYFAILED: |
@@ -1059,7 +1104,7 @@ static int get_local_rgrp(struct gfs2_inode *ip) | |||
1059 | break; | 1104 | break; |
1060 | 1105 | ||
1061 | default: | 1106 | default: |
1062 | return error; | 1107 | return ERR_PTR(error); |
1063 | } | 1108 | } |
1064 | 1109 | ||
1065 | rgd = gfs2_rgrpd_get_next(rgd); | 1110 | rgd = gfs2_rgrpd_get_next(rgd); |
@@ -1068,7 +1113,7 @@ static int get_local_rgrp(struct gfs2_inode *ip) | |||
1068 | 1113 | ||
1069 | if (rgd == begin) { | 1114 | if (rgd == begin) { |
1070 | if (++loops >= 3) | 1115 | if (++loops >= 3) |
1071 | return -ENOSPC; | 1116 | return ERR_PTR(-ENOSPC); |
1072 | if (!skipped) | 1117 | if (!skipped) |
1073 | loops++; | 1118 | loops++; |
1074 | flags = 0; | 1119 | flags = 0; |
@@ -1088,7 +1133,7 @@ out: | |||
1088 | forward_rgrp_set(sdp, rgd); | 1133 | forward_rgrp_set(sdp, rgd); |
1089 | } | 1134 | } |
1090 | 1135 | ||
1091 | return 0; | 1136 | return NULL; |
1092 | } | 1137 | } |
1093 | 1138 | ||
1094 | /** | 1139 | /** |
@@ -1102,11 +1147,14 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) | |||
1102 | { | 1147 | { |
1103 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1148 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1104 | struct gfs2_alloc *al = &ip->i_alloc; | 1149 | struct gfs2_alloc *al = &ip->i_alloc; |
1150 | struct inode *inode; | ||
1105 | int error = 0; | 1151 | int error = 0; |
1152 | u64 last_unlinked = 0; | ||
1106 | 1153 | ||
1107 | if (gfs2_assert_warn(sdp, al->al_requested)) | 1154 | if (gfs2_assert_warn(sdp, al->al_requested)) |
1108 | return -EINVAL; | 1155 | return -EINVAL; |
1109 | 1156 | ||
1157 | try_again: | ||
1110 | /* We need to hold the rindex unless the inode we're using is | 1158 | /* We need to hold the rindex unless the inode we're using is |
1111 | the rindex itself, in which case it's already held. */ | 1159 | the rindex itself, in which case it's already held. */ |
1112 | if (ip != GFS2_I(sdp->sd_rindex)) | 1160 | if (ip != GFS2_I(sdp->sd_rindex)) |
@@ -1117,11 +1165,15 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line) | |||
1117 | if (error) | 1165 | if (error) |
1118 | return error; | 1166 | return error; |
1119 | 1167 | ||
1120 | error = get_local_rgrp(ip); | 1168 | inode = get_local_rgrp(ip, &last_unlinked); |
1121 | if (error) { | 1169 | if (inode) { |
1122 | if (ip != GFS2_I(sdp->sd_rindex)) | 1170 | if (ip != GFS2_I(sdp->sd_rindex)) |
1123 | gfs2_glock_dq_uninit(&al->al_ri_gh); | 1171 | gfs2_glock_dq_uninit(&al->al_ri_gh); |
1124 | return error; | 1172 | if (IS_ERR(inode)) |
1173 | return PTR_ERR(inode); | ||
1174 | iput(inode); | ||
1175 | gfs2_log_flush(sdp, NULL); | ||
1176 | goto try_again; | ||
1125 | } | 1177 | } |
1126 | 1178 | ||
1127 | al->al_file = file; | 1179 | al->al_file = file; |
@@ -1209,7 +1261,7 @@ unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block) | |||
1209 | */ | 1261 | */ |
1210 | 1262 | ||
1211 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, | 1263 | static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, |
1212 | unsigned char old_state, unsigned char new_state) | 1264 | unsigned char old_state, unsigned char new_state) |
1213 | { | 1265 | { |
1214 | struct gfs2_bitmap *bi = NULL; | 1266 | struct gfs2_bitmap *bi = NULL; |
1215 | u32 length = rgd->rd_length; | 1267 | u32 length = rgd->rd_length; |
@@ -1250,17 +1302,18 @@ static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, | |||
1250 | goal = 0; | 1302 | goal = 0; |
1251 | } | 1303 | } |
1252 | 1304 | ||
1253 | if (gfs2_assert_withdraw(rgd->rd_sbd, x <= length)) | 1305 | if (old_state != new_state) { |
1254 | blk = 0; | 1306 | gfs2_assert_withdraw(rgd->rd_sbd, blk != BFITNOENT); |
1255 | 1307 | ||
1256 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); | 1308 | gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1); |
1257 | gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, | 1309 | gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset, |
1258 | bi->bi_len, blk, new_state); | ||
1259 | if (bi->bi_clone) | ||
1260 | gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset, | ||
1261 | bi->bi_len, blk, new_state); | 1310 | bi->bi_len, blk, new_state); |
1311 | if (bi->bi_clone) | ||
1312 | gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset, | ||
1313 | bi->bi_len, blk, new_state); | ||
1314 | } | ||
1262 | 1315 | ||
1263 | return bi->bi_start * GFS2_NBBY + blk; | 1316 | return (blk == BFITNOENT) ? 0 : (bi->bi_start * GFS2_NBBY) + blk; |
1264 | } | 1317 | } |
1265 | 1318 | ||
1266 | /** | 1319 | /** |