aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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
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')
-rw-r--r--fs/gfs2/incore.h2
-rw-r--r--fs/gfs2/inode.c50
-rw-r--r--fs/gfs2/rgrp.c87
3 files changed, 107 insertions, 32 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index e5069b912d5e..c7c6ec0f17c7 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -95,6 +95,8 @@ struct gfs2_rgrpd {
95 u32 rd_last_alloc_data; 95 u32 rd_last_alloc_data;
96 u32 rd_last_alloc_meta; 96 u32 rd_last_alloc_meta;
97 struct gfs2_sbd *rd_sbd; 97 struct gfs2_sbd *rd_sbd;
98 unsigned long rd_flags;
99#define GFS2_RDF_CHECK 0x0001 /* Need to check for unlinked inodes */
98}; 100};
99 101
100enum gfs2_state_bits { 102enum gfs2_state_bits {
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 87505f7eb745..cacdb0dfe577 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -98,22 +98,8 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, u64 no_addr, unsigned in
98 98
99 if (inode->i_state & I_NEW) { 99 if (inode->i_state & I_NEW) {
100 struct gfs2_sbd *sdp = GFS2_SB(inode); 100 struct gfs2_sbd *sdp = GFS2_SB(inode);
101 umode_t mode = DT2IF(type); 101 umode_t mode;
102 inode->i_private = ip; 102 inode->i_private = ip;
103 inode->i_mode = mode;
104
105 if (S_ISREG(mode)) {
106 inode->i_op = &gfs2_file_iops;
107 inode->i_fop = &gfs2_file_fops;
108 inode->i_mapping->a_ops = &gfs2_file_aops;
109 } else if (S_ISDIR(mode)) {
110 inode->i_op = &gfs2_dir_iops;
111 inode->i_fop = &gfs2_dir_fops;
112 } else if (S_ISLNK(mode)) {
113 inode->i_op = &gfs2_symlink_iops;
114 } else {
115 inode->i_op = &gfs2_dev_iops;
116 }
117 103
118 error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl); 104 error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
119 if (unlikely(error)) 105 if (unlikely(error))
@@ -130,10 +116,44 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, u64 no_addr, unsigned in
130 goto fail_iopen; 116 goto fail_iopen;
131 117
132 gfs2_glock_put(io_gl); 118 gfs2_glock_put(io_gl);
119
120 /*
121 * We must read the inode in order to work out its type in
122 * this case. Note that this doesn't happen often as we normally
123 * know the type beforehand. This code path only occurs during
124 * unlinked inode recovery (where it is safe to do this glock,
125 * which is not true in the general case).
126 */
127 inode->i_mode = mode = DT2IF(type);
128 if (type == DT_UNKNOWN) {
129 struct gfs2_holder gh;
130 error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
131 if (unlikely(error))
132 goto fail_glock;
133 /* Inode is now uptodate */
134 mode = inode->i_mode;
135 gfs2_glock_dq_uninit(&gh);
136 }
137
138 if (S_ISREG(mode)) {
139 inode->i_op = &gfs2_file_iops;
140 inode->i_fop = &gfs2_file_fops;
141 inode->i_mapping->a_ops = &gfs2_file_aops;
142 } else if (S_ISDIR(mode)) {
143 inode->i_op = &gfs2_dir_iops;
144 inode->i_fop = &gfs2_dir_fops;
145 } else if (S_ISLNK(mode)) {
146 inode->i_op = &gfs2_symlink_iops;
147 } else {
148 inode->i_op = &gfs2_dev_iops;
149 }
150
133 unlock_new_inode(inode); 151 unlock_new_inode(inode);
134 } 152 }
135 153
136 return inode; 154 return inode;
155fail_glock:
156 gfs2_glock_dq(&ip->i_iopen_gh);
137fail_iopen: 157fail_iopen:
138 gfs2_glock_put(io_gl); 158 gfs2_glock_put(io_gl);
139fail_put: 159fail_put:
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/**