aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2/rgrp.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2007-06-08 05:05:33 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2007-07-09 03:23:26 -0400
commitc8cdf479377462315d6b4f56379f8ac989b0ef29 (patch)
tree3eee98ca4af8bba92a6df096f6fd2de615a71fa5 /fs/gfs2/rgrp.c
parentb35997d4482ed24b43a5951c5b021d224b24293c (diff)
[GFS2] Recovery for lost unlinked inodes
Under certain circumstances its possible (though rather unlikely) that inodes which were unlinked by one node while still open on another might get "lost" in the sense that they don't get deallocated if the node which held the inode open crashed before it was unlinked. This patch adds the recovery code which allows automatic deallocation of the inode if its found during block allocation (the sensible time to look for such inodes since we are scanning the rgrp's bitmaps anyway at this time, so it adds no overhead to do this). Since the inode will have had its i_nlink set to zero, all we need to trigger recovery is a lookup and an iput(), and the normal deallocation code takes care of the rest. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r--fs/gfs2/rgrp.c87
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
54static 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
860static 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
1009static int get_local_rgrp(struct gfs2_inode *ip) 1045static 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
1157try_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
1211static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, 1263static 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/**