diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/dir.c | 28 | ||||
-rw-r--r-- | fs/ocfs2/dir.h | 7 | ||||
-rw-r--r-- | fs/ocfs2/journal.c | 118 |
3 files changed, 70 insertions, 83 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index dbfa6f66291a..a75c340fc689 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -81,10 +81,10 @@ static int ocfs2_do_extend_dir(struct super_block *sb, | |||
81 | struct ocfs2_alloc_context *meta_ac, | 81 | struct ocfs2_alloc_context *meta_ac, |
82 | struct buffer_head **new_bh); | 82 | struct buffer_head **new_bh); |
83 | 83 | ||
84 | int ocfs2_check_dir_entry(struct inode * dir, | 84 | static int ocfs2_check_dir_entry(struct inode * dir, |
85 | struct ocfs2_dir_entry * de, | 85 | struct ocfs2_dir_entry * de, |
86 | struct buffer_head * bh, | 86 | struct buffer_head * bh, |
87 | unsigned long offset) | 87 | unsigned long offset) |
88 | { | 88 | { |
89 | const char *error_msg = NULL; | 89 | const char *error_msg = NULL; |
90 | const int rlen = le16_to_cpu(de->rec_len); | 90 | const int rlen = le16_to_cpu(de->rec_len); |
@@ -532,6 +532,26 @@ out: | |||
532 | } | 532 | } |
533 | 533 | ||
534 | /* | 534 | /* |
535 | * This is intended to be called from inside other kernel functions, | ||
536 | * so we fake some arguments. | ||
537 | */ | ||
538 | int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, | ||
539 | filldir_t filldir) | ||
540 | { | ||
541 | int ret = 0; | ||
542 | unsigned long version = inode->i_version; | ||
543 | |||
544 | while (*f_pos < i_size_read(inode)) { | ||
545 | ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv, | ||
546 | filldir); | ||
547 | if (ret) | ||
548 | break; | ||
549 | } | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | /* | ||
535 | * ocfs2_readdir() | 555 | * ocfs2_readdir() |
536 | * | 556 | * |
537 | */ | 557 | */ |
diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index 7bf9c0a01cdf..075d0e9fd459 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h | |||
@@ -62,6 +62,8 @@ int ocfs2_find_files_on_disk(const char *name, | |||
62 | struct buffer_head **dirent_bh, | 62 | struct buffer_head **dirent_bh, |
63 | struct ocfs2_dir_entry **dirent); | 63 | struct ocfs2_dir_entry **dirent); |
64 | int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir); | 64 | int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir); |
65 | int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, | ||
66 | filldir_t filldir); | ||
65 | int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, | 67 | int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb, |
66 | struct inode *dir, | 68 | struct inode *dir, |
67 | struct buffer_head *parent_fe_bh, | 69 | struct buffer_head *parent_fe_bh, |
@@ -76,9 +78,4 @@ int ocfs2_fill_new_dir(struct ocfs2_super *osb, | |||
76 | struct buffer_head *fe_bh, | 78 | struct buffer_head *fe_bh, |
77 | struct ocfs2_alloc_context *data_ac); | 79 | struct ocfs2_alloc_context *data_ac); |
78 | 80 | ||
79 | int ocfs2_check_dir_entry(struct inode *dir, | ||
80 | struct ocfs2_dir_entry *de, | ||
81 | struct buffer_head *bh, | ||
82 | unsigned long offset); | ||
83 | |||
84 | #endif /* OCFS2_DIR_H */ | 81 | #endif /* OCFS2_DIR_H */ |
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); |