diff options
Diffstat (limited to 'fs/ocfs2/journal.c')
-rw-r--r-- | fs/ocfs2/journal.c | 118 |
1 files changed, 44 insertions, 74 deletions
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 8bbfc80e5c5c..f9d01e25298d 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -1213,17 +1213,49 @@ bail: | |||
1213 | return status; | 1213 | return status; |
1214 | } | 1214 | } |
1215 | 1215 | ||
1216 | struct ocfs2_orphan_filldir_priv { | ||
1217 | struct inode *head; | ||
1218 | struct ocfs2_super *osb; | ||
1219 | }; | ||
1220 | |||
1221 | static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len, | ||
1222 | loff_t pos, u64 ino, unsigned type) | ||
1223 | { | ||
1224 | struct ocfs2_orphan_filldir_priv *p = priv; | ||
1225 | struct inode *iter; | ||
1226 | |||
1227 | if (name_len == 1 && !strncmp(".", name, 1)) | ||
1228 | return 0; | ||
1229 | if (name_len == 2 && !strncmp("..", name, 2)) | ||
1230 | return 0; | ||
1231 | |||
1232 | /* Skip bad inodes so that recovery can continue */ | ||
1233 | iter = ocfs2_iget(p->osb, ino, | ||
1234 | OCFS2_FI_FLAG_ORPHAN_RECOVERY); | ||
1235 | if (IS_ERR(iter)) | ||
1236 | return 0; | ||
1237 | |||
1238 | mlog(0, "queue orphan %llu\n", | ||
1239 | (unsigned long long)OCFS2_I(iter)->ip_blkno); | ||
1240 | /* No locking is required for the next_orphan queue as there | ||
1241 | * is only ever a single process doing orphan recovery. */ | ||
1242 | OCFS2_I(iter)->ip_next_orphan = p->head; | ||
1243 | p->head = iter; | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1216 | static int ocfs2_queue_orphans(struct ocfs2_super *osb, | 1248 | static int ocfs2_queue_orphans(struct ocfs2_super *osb, |
1217 | int slot, | 1249 | int slot, |
1218 | struct inode **head) | 1250 | struct inode **head) |
1219 | { | 1251 | { |
1220 | int status; | 1252 | int status; |
1221 | struct inode *orphan_dir_inode = NULL; | 1253 | struct inode *orphan_dir_inode = NULL; |
1222 | struct inode *iter; | 1254 | struct ocfs2_orphan_filldir_priv priv; |
1223 | unsigned long offset, blk, local; | 1255 | loff_t pos = 0; |
1224 | struct buffer_head *bh = NULL; | 1256 | |
1225 | struct ocfs2_dir_entry *de; | 1257 | priv.osb = osb; |
1226 | struct super_block *sb = osb->sb; | 1258 | priv.head = *head; |
1227 | 1259 | ||
1228 | orphan_dir_inode = ocfs2_get_system_file_inode(osb, | 1260 | orphan_dir_inode = ocfs2_get_system_file_inode(osb, |
1229 | ORPHAN_DIR_SYSTEM_INODE, | 1261 | ORPHAN_DIR_SYSTEM_INODE, |
@@ -1241,77 +1273,15 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb, | |||
1241 | goto out; | 1273 | goto out; |
1242 | } | 1274 | } |
1243 | 1275 | ||
1244 | offset = 0; | 1276 | status = ocfs2_dir_foreach(orphan_dir_inode, &pos, &priv, |
1245 | iter = NULL; | 1277 | ocfs2_orphan_filldir); |
1246 | while(offset < i_size_read(orphan_dir_inode)) { | 1278 | if (status) { |
1247 | blk = offset >> sb->s_blocksize_bits; | 1279 | mlog_errno(status); |
1248 | 1280 | goto out; | |
1249 | bh = ocfs2_bread(orphan_dir_inode, blk, &status, 0); | ||
1250 | if (!bh) | ||
1251 | status = -EINVAL; | ||
1252 | if (status < 0) { | ||
1253 | if (bh) | ||
1254 | brelse(bh); | ||
1255 | mlog_errno(status); | ||
1256 | goto out_unlock; | ||
1257 | } | ||
1258 | |||
1259 | local = 0; | ||
1260 | while(offset < i_size_read(orphan_dir_inode) | ||
1261 | && local < sb->s_blocksize) { | ||
1262 | de = (struct ocfs2_dir_entry *) (bh->b_data + local); | ||
1263 | |||
1264 | if (!ocfs2_check_dir_entry(orphan_dir_inode, | ||
1265 | de, bh, local)) { | ||
1266 | status = -EINVAL; | ||
1267 | mlog_errno(status); | ||
1268 | brelse(bh); | ||
1269 | goto out_unlock; | ||
1270 | } | ||
1271 | |||
1272 | local += le16_to_cpu(de->rec_len); | ||
1273 | offset += le16_to_cpu(de->rec_len); | ||
1274 | |||
1275 | /* I guess we silently fail on no inode? */ | ||
1276 | if (!le64_to_cpu(de->inode)) | ||
1277 | continue; | ||
1278 | if (de->file_type > OCFS2_FT_MAX) { | ||
1279 | mlog(ML_ERROR, | ||
1280 | "block %llu contains invalid de: " | ||
1281 | "inode = %llu, rec_len = %u, " | ||
1282 | "name_len = %u, file_type = %u, " | ||
1283 | "name='%.*s'\n", | ||
1284 | (unsigned long long)bh->b_blocknr, | ||
1285 | (unsigned long long)le64_to_cpu(de->inode), | ||
1286 | le16_to_cpu(de->rec_len), | ||
1287 | de->name_len, | ||
1288 | de->file_type, | ||
1289 | de->name_len, | ||
1290 | de->name); | ||
1291 | continue; | ||
1292 | } | ||
1293 | if (de->name_len == 1 && !strncmp(".", de->name, 1)) | ||
1294 | continue; | ||
1295 | if (de->name_len == 2 && !strncmp("..", de->name, 2)) | ||
1296 | continue; | ||
1297 | |||
1298 | iter = ocfs2_iget(osb, le64_to_cpu(de->inode), | ||
1299 | OCFS2_FI_FLAG_ORPHAN_RECOVERY); | ||
1300 | if (IS_ERR(iter)) | ||
1301 | continue; | ||
1302 | |||
1303 | mlog(0, "queue orphan %llu\n", | ||
1304 | (unsigned long long)OCFS2_I(iter)->ip_blkno); | ||
1305 | /* No locking is required for the next_orphan | ||
1306 | * queue as there is only ever a single | ||
1307 | * process doing orphan recovery. */ | ||
1308 | OCFS2_I(iter)->ip_next_orphan = *head; | ||
1309 | *head = iter; | ||
1310 | } | ||
1311 | brelse(bh); | ||
1312 | } | 1281 | } |
1313 | 1282 | ||
1314 | out_unlock: | 1283 | *head = priv.head; |
1284 | |||
1315 | ocfs2_meta_unlock(orphan_dir_inode, 0); | 1285 | ocfs2_meta_unlock(orphan_dir_inode, 0); |
1316 | out: | 1286 | out: |
1317 | mutex_unlock(&orphan_dir_inode->i_mutex); | 1287 | mutex_unlock(&orphan_dir_inode->i_mutex); |