diff options
author | Tigran Aivazian <aivazian.tigran@gmail.com> | 2019-01-03 18:28:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-04 16:13:47 -0500 |
commit | d1877155891020cb26ad4fba45bfee52d8da9951 (patch) | |
tree | 1be2ddb904a730b47d1f21ce9b512a2bfa7c0013 /fs/bfs/inode.c | |
parent | 655c16a8ce9c15842547f40ce23fd148aeccc074 (diff) |
bfs: extra sanity checking and static inode bitmap
Strengthen validation of BFS superblock against corruption. Make
in-core inode bitmap static part of superblock info structure. Print a
warning when mounting a BFS filesystem created with "-N 512" option as
only 510 files can be created in the root directory. Make the kernel
messages more uniform. Update the 'prefix' passed to bfs_dump_imap() to
match the current naming of operations. White space and comments
cleanup.
Link: http://lkml.kernel.org/r/CAK+_RLkFZMduoQF36wZFd3zLi-6ZutWKsydjeHFNdtRvZZEb4w@mail.gmail.com
Signed-off-by: Tigran Aivazian <aivazian.tigran@gmail.com>
Reported-by: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/bfs/inode.c')
-rw-r--r-- | fs/bfs/inode.c | 65 |
1 files changed, 28 insertions, 37 deletions
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index d81c148682e7..d136b2aaafb3 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c | |||
@@ -1,10 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * fs/bfs/inode.c | 2 | * fs/bfs/inode.c |
3 | * BFS superblock and inode operations. | 3 | * BFS superblock and inode operations. |
4 | * Copyright (C) 1999-2006 Tigran Aivazian <aivazian.tigran@gmail.com> | 4 | * Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com> |
5 | * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds. | 5 | * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds. |
6 | * | 6 | * Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005. |
7 | * Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005. | ||
8 | */ | 7 | */ |
9 | 8 | ||
10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
@@ -118,12 +117,12 @@ static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
118 | { | 117 | { |
119 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); | 118 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); |
120 | unsigned int ino = (u16)inode->i_ino; | 119 | unsigned int ino = (u16)inode->i_ino; |
121 | unsigned long i_sblock; | 120 | unsigned long i_sblock; |
122 | struct bfs_inode *di; | 121 | struct bfs_inode *di; |
123 | struct buffer_head *bh; | 122 | struct buffer_head *bh; |
124 | int err = 0; | 123 | int err = 0; |
125 | 124 | ||
126 | dprintf("ino=%08x\n", ino); | 125 | dprintf("ino=%08x\n", ino); |
127 | 126 | ||
128 | di = find_inode(inode->i_sb, ino, &bh); | 127 | di = find_inode(inode->i_sb, ino, &bh); |
129 | if (IS_ERR(di)) | 128 | if (IS_ERR(di)) |
@@ -144,7 +143,7 @@ static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
144 | di->i_atime = cpu_to_le32(inode->i_atime.tv_sec); | 143 | di->i_atime = cpu_to_le32(inode->i_atime.tv_sec); |
145 | di->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); | 144 | di->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); |
146 | di->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); | 145 | di->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); |
147 | i_sblock = BFS_I(inode)->i_sblock; | 146 | i_sblock = BFS_I(inode)->i_sblock; |
148 | di->i_sblock = cpu_to_le32(i_sblock); | 147 | di->i_sblock = cpu_to_le32(i_sblock); |
149 | di->i_eblock = cpu_to_le32(BFS_I(inode)->i_eblock); | 148 | di->i_eblock = cpu_to_le32(BFS_I(inode)->i_eblock); |
150 | di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1); | 149 | di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1); |
@@ -188,13 +187,13 @@ static void bfs_evict_inode(struct inode *inode) | |||
188 | mark_buffer_dirty(bh); | 187 | mark_buffer_dirty(bh); |
189 | brelse(bh); | 188 | brelse(bh); |
190 | 189 | ||
191 | if (bi->i_dsk_ino) { | 190 | if (bi->i_dsk_ino) { |
192 | if (bi->i_sblock) | 191 | if (bi->i_sblock) |
193 | info->si_freeb += bi->i_eblock + 1 - bi->i_sblock; | 192 | info->si_freeb += bi->i_eblock + 1 - bi->i_sblock; |
194 | info->si_freei++; | 193 | info->si_freei++; |
195 | clear_bit(ino, info->si_imap); | 194 | clear_bit(ino, info->si_imap); |
196 | bfs_dump_imap("delete_inode", s); | 195 | bfs_dump_imap("evict_inode", s); |
197 | } | 196 | } |
198 | 197 | ||
199 | /* | 198 | /* |
200 | * If this was the last file, make the previous block | 199 | * If this was the last file, make the previous block |
@@ -214,7 +213,6 @@ static void bfs_put_super(struct super_block *s) | |||
214 | return; | 213 | return; |
215 | 214 | ||
216 | mutex_destroy(&info->bfs_lock); | 215 | mutex_destroy(&info->bfs_lock); |
217 | kfree(info->si_imap); | ||
218 | kfree(info); | 216 | kfree(info); |
219 | s->s_fs_info = NULL; | 217 | s->s_fs_info = NULL; |
220 | } | 218 | } |
@@ -311,8 +309,7 @@ void bfs_dump_imap(const char *prefix, struct super_block *s) | |||
311 | else | 309 | else |
312 | strcat(tmpbuf, "0"); | 310 | strcat(tmpbuf, "0"); |
313 | } | 311 | } |
314 | printf("BFS-fs: %s: lasti=%08lx <%s>\n", | 312 | printf("%s: lasti=%08lx <%s>\n", prefix, BFS_SB(s)->si_lasti, tmpbuf); |
315 | prefix, BFS_SB(s)->si_lasti, tmpbuf); | ||
316 | free_page((unsigned long)tmpbuf); | 313 | free_page((unsigned long)tmpbuf); |
317 | #endif | 314 | #endif |
318 | } | 315 | } |
@@ -322,7 +319,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
322 | struct buffer_head *bh, *sbh; | 319 | struct buffer_head *bh, *sbh; |
323 | struct bfs_super_block *bfs_sb; | 320 | struct bfs_super_block *bfs_sb; |
324 | struct inode *inode; | 321 | struct inode *inode; |
325 | unsigned i, imap_len; | 322 | unsigned i; |
326 | struct bfs_sb_info *info; | 323 | struct bfs_sb_info *info; |
327 | int ret = -EINVAL; | 324 | int ret = -EINVAL; |
328 | unsigned long i_sblock, i_eblock, i_eoff, s_size; | 325 | unsigned long i_sblock, i_eblock, i_eoff, s_size; |
@@ -341,8 +338,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
341 | bfs_sb = (struct bfs_super_block *)sbh->b_data; | 338 | bfs_sb = (struct bfs_super_block *)sbh->b_data; |
342 | if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) { | 339 | if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) { |
343 | if (!silent) | 340 | if (!silent) |
344 | printf("No BFS filesystem on %s (magic=%08x)\n", | 341 | printf("No BFS filesystem on %s (magic=%08x)\n", s->s_id, le32_to_cpu(bfs_sb->s_magic)); |
345 | s->s_id, le32_to_cpu(bfs_sb->s_magic)); | ||
346 | goto out1; | 342 | goto out1; |
347 | } | 343 | } |
348 | if (BFS_UNCLEAN(bfs_sb, s) && !silent) | 344 | if (BFS_UNCLEAN(bfs_sb, s) && !silent) |
@@ -351,18 +347,16 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
351 | s->s_magic = BFS_MAGIC; | 347 | s->s_magic = BFS_MAGIC; |
352 | 348 | ||
353 | if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) || | 349 | if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) || |
354 | le32_to_cpu(bfs_sb->s_start) < BFS_BSIZE) { | 350 | le32_to_cpu(bfs_sb->s_start) < sizeof(struct bfs_super_block) + sizeof(struct bfs_dirent)) { |
355 | printf("Superblock is corrupted\n"); | 351 | printf("Superblock is corrupted on %s\n", s->s_id); |
356 | goto out1; | 352 | goto out1; |
357 | } | 353 | } |
358 | 354 | ||
359 | info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / | 355 | info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / sizeof(struct bfs_inode) + BFS_ROOT_INO - 1; |
360 | sizeof(struct bfs_inode) | 356 | if (info->si_lasti == BFS_MAX_LASTI) |
361 | + BFS_ROOT_INO - 1; | 357 | printf("WARNING: filesystem %s was created with 512 inodes, the real maximum is 511, mounting anyway\n", s->s_id); |
362 | imap_len = (info->si_lasti / 8) + 1; | 358 | else if (info->si_lasti > BFS_MAX_LASTI) { |
363 | info->si_imap = kzalloc(imap_len, GFP_KERNEL | __GFP_NOWARN); | 359 | printf("Impossible last inode number %lu > %d on %s\n", info->si_lasti, BFS_MAX_LASTI, s->s_id); |
364 | if (!info->si_imap) { | ||
365 | printf("Cannot allocate %u bytes\n", imap_len); | ||
366 | goto out1; | 360 | goto out1; |
367 | } | 361 | } |
368 | for (i = 0; i < BFS_ROOT_INO; i++) | 362 | for (i = 0; i < BFS_ROOT_INO; i++) |
@@ -372,26 +366,25 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
372 | inode = bfs_iget(s, BFS_ROOT_INO); | 366 | inode = bfs_iget(s, BFS_ROOT_INO); |
373 | if (IS_ERR(inode)) { | 367 | if (IS_ERR(inode)) { |
374 | ret = PTR_ERR(inode); | 368 | ret = PTR_ERR(inode); |
375 | goto out2; | 369 | goto out1; |
376 | } | 370 | } |
377 | s->s_root = d_make_root(inode); | 371 | s->s_root = d_make_root(inode); |
378 | if (!s->s_root) { | 372 | if (!s->s_root) { |
379 | ret = -ENOMEM; | 373 | ret = -ENOMEM; |
380 | goto out2; | 374 | goto out1; |
381 | } | 375 | } |
382 | 376 | ||
383 | info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1) >> BFS_BSIZE_BITS; | 377 | info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1) >> BFS_BSIZE_BITS; |
384 | info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1 | 378 | info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1 - le32_to_cpu(bfs_sb->s_start)) >> BFS_BSIZE_BITS; |
385 | - le32_to_cpu(bfs_sb->s_start)) >> BFS_BSIZE_BITS; | ||
386 | info->si_freei = 0; | 379 | info->si_freei = 0; |
387 | info->si_lf_eblk = 0; | 380 | info->si_lf_eblk = 0; |
388 | 381 | ||
389 | /* can we read the last block? */ | 382 | /* can we read the last block? */ |
390 | bh = sb_bread(s, info->si_blocks - 1); | 383 | bh = sb_bread(s, info->si_blocks - 1); |
391 | if (!bh) { | 384 | if (!bh) { |
392 | printf("Last block not available: %lu\n", info->si_blocks - 1); | 385 | printf("Last block not available on %s: %lu\n", s->s_id, info->si_blocks - 1); |
393 | ret = -EIO; | 386 | ret = -EIO; |
394 | goto out3; | 387 | goto out2; |
395 | } | 388 | } |
396 | brelse(bh); | 389 | brelse(bh); |
397 | 390 | ||
@@ -425,11 +418,11 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
425 | (i_eoff != le32_to_cpu(-1) && i_eoff > s_size) || | 418 | (i_eoff != le32_to_cpu(-1) && i_eoff > s_size) || |
426 | i_sblock * BFS_BSIZE > i_eoff) { | 419 | i_sblock * BFS_BSIZE > i_eoff) { |
427 | 420 | ||
428 | printf("Inode 0x%08x corrupted\n", i); | 421 | printf("Inode 0x%08x corrupted on %s\n", i, s->s_id); |
429 | 422 | ||
430 | brelse(bh); | 423 | brelse(bh); |
431 | ret = -EIO; | 424 | ret = -EIO; |
432 | goto out3; | 425 | goto out2; |
433 | } | 426 | } |
434 | 427 | ||
435 | if (!di->i_ino) { | 428 | if (!di->i_ino) { |
@@ -445,14 +438,12 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
445 | } | 438 | } |
446 | brelse(bh); | 439 | brelse(bh); |
447 | brelse(sbh); | 440 | brelse(sbh); |
448 | bfs_dump_imap("read_super", s); | 441 | bfs_dump_imap("fill_super", s); |
449 | return 0; | 442 | return 0; |
450 | 443 | ||
451 | out3: | 444 | out2: |
452 | dput(s->s_root); | 445 | dput(s->s_root); |
453 | s->s_root = NULL; | 446 | s->s_root = NULL; |
454 | out2: | ||
455 | kfree(info->si_imap); | ||
456 | out1: | 447 | out1: |
457 | brelse(sbh); | 448 | brelse(sbh); |
458 | out: | 449 | out: |
@@ -482,7 +473,7 @@ static int __init init_bfs_fs(void) | |||
482 | int err = init_inodecache(); | 473 | int err = init_inodecache(); |
483 | if (err) | 474 | if (err) |
484 | goto out1; | 475 | goto out1; |
485 | err = register_filesystem(&bfs_fs_type); | 476 | err = register_filesystem(&bfs_fs_type); |
486 | if (err) | 477 | if (err) |
487 | goto out; | 478 | goto out; |
488 | return 0; | 479 | return 0; |