Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Tigran Aivazian and committed by
Linus Torvalds
d1877155 655c16a8

+41 -43
+9 -2
fs/bfs/bfs.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 3 * fs/bfs/bfs.h 4 - * Copyright (C) 1999 Tigran Aivazian <tigran@veritas.com> 4 + * Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com> 5 5 */ 6 6 #ifndef _FS_BFS_BFS_H 7 7 #define _FS_BFS_BFS_H 8 8 9 9 #include <linux/bfs_fs.h> 10 + 11 + /* In theory BFS supports up to 512 inodes, numbered from 2 (for /) up to 513 inclusive. 12 + In actual fact, attempting to create the 512th inode (i.e. inode No. 513 or file No. 511) 13 + will fail with ENOSPC in bfs_add_entry(): the root directory cannot contain so many entries, counting '..'. 14 + So, mkfs.bfs(8) should really limit its -N option to 511 and not 512. For now, we just print a warning 15 + if a filesystem is mounted with such "impossible to fill up" number of inodes */ 16 + #define BFS_MAX_LASTI 513 10 17 11 18 /* 12 19 * BFS file system in-core superblock info ··· 24 17 unsigned long si_freei; 25 18 unsigned long si_lf_eblk; 26 19 unsigned long si_lasti; 27 - unsigned long *si_imap; 20 + DECLARE_BITMAP(si_imap, BFS_MAX_LASTI+1); 28 21 struct mutex bfs_lock; 29 22 }; 30 23
+2 -2
fs/bfs/dir.c
··· 2 2 /* 3 3 * fs/bfs/dir.c 4 4 * BFS directory operations. 5 - * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 6 - * Made endianness-clean by Andrew Stribblehill <ads@wompom.org> 2005 5 + * Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com> 6 + * Made endianness-clean by Andrew Stribblehill <ads@wompom.org> 2005 7 7 */ 8 8 9 9 #include <linux/time.h>
+1 -1
fs/bfs/file.c
··· 2 2 /* 3 3 * fs/bfs/file.c 4 4 * BFS file operations. 5 - * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> 5 + * Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com> 6 6 * 7 7 * Make the file block allocation algorithm understand the size 8 8 * of the underlying block device.
+28 -37
fs/bfs/inode.c
··· 1 1 /* 2 2 * fs/bfs/inode.c 3 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 5 * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds. 6 - * 7 - * Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005. 6 + * Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005. 8 7 */ 9 8 10 9 #include <linux/module.h> ··· 117 118 { 118 119 struct bfs_sb_info *info = BFS_SB(inode->i_sb); 119 120 unsigned int ino = (u16)inode->i_ino; 120 - unsigned long i_sblock; 121 + unsigned long i_sblock; 121 122 struct bfs_inode *di; 122 123 struct buffer_head *bh; 123 124 int err = 0; 124 125 125 - dprintf("ino=%08x\n", ino); 126 + dprintf("ino=%08x\n", ino); 126 127 127 128 di = find_inode(inode->i_sb, ino, &bh); 128 129 if (IS_ERR(di)) ··· 143 144 di->i_atime = cpu_to_le32(inode->i_atime.tv_sec); 144 145 di->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); 145 146 di->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); 146 - i_sblock = BFS_I(inode)->i_sblock; 147 + i_sblock = BFS_I(inode)->i_sblock; 147 148 di->i_sblock = cpu_to_le32(i_sblock); 148 149 di->i_eblock = cpu_to_le32(BFS_I(inode)->i_eblock); 149 150 di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1); ··· 187 188 mark_buffer_dirty(bh); 188 189 brelse(bh); 189 190 190 - if (bi->i_dsk_ino) { 191 + if (bi->i_dsk_ino) { 191 192 if (bi->i_sblock) 192 193 info->si_freeb += bi->i_eblock + 1 - bi->i_sblock; 193 194 info->si_freei++; 194 195 clear_bit(ino, info->si_imap); 195 - bfs_dump_imap("delete_inode", s); 196 - } 196 + bfs_dump_imap("evict_inode", s); 197 + } 197 198 198 199 /* 199 200 * If this was the last file, make the previous block ··· 213 214 return; 214 215 215 216 mutex_destroy(&info->bfs_lock); 216 - kfree(info->si_imap); 217 217 kfree(info); 218 218 s->s_fs_info = NULL; 219 219 } ··· 309 311 else 310 312 strcat(tmpbuf, "0"); 311 313 } 312 - printf("BFS-fs: %s: lasti=%08lx <%s>\n", 313 - prefix, BFS_SB(s)->si_lasti, tmpbuf); 314 + printf("%s: lasti=%08lx <%s>\n", prefix, BFS_SB(s)->si_lasti, tmpbuf); 314 315 free_page((unsigned long)tmpbuf); 315 316 #endif 316 317 } ··· 319 322 struct buffer_head *bh, *sbh; 320 323 struct bfs_super_block *bfs_sb; 321 324 struct inode *inode; 322 - unsigned i, imap_len; 325 + unsigned i; 323 326 struct bfs_sb_info *info; 324 327 int ret = -EINVAL; 325 328 unsigned long i_sblock, i_eblock, i_eoff, s_size; ··· 338 341 bfs_sb = (struct bfs_super_block *)sbh->b_data; 339 342 if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) { 340 343 if (!silent) 341 - printf("No BFS filesystem on %s (magic=%08x)\n", 342 - s->s_id, le32_to_cpu(bfs_sb->s_magic)); 344 + printf("No BFS filesystem on %s (magic=%08x)\n", s->s_id, le32_to_cpu(bfs_sb->s_magic)); 343 345 goto out1; 344 346 } 345 347 if (BFS_UNCLEAN(bfs_sb, s) && !silent) ··· 347 351 s->s_magic = BFS_MAGIC; 348 352 349 353 if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) || 350 - le32_to_cpu(bfs_sb->s_start) < BFS_BSIZE) { 351 - printf("Superblock is corrupted\n"); 354 + le32_to_cpu(bfs_sb->s_start) < sizeof(struct bfs_super_block) + sizeof(struct bfs_dirent)) { 355 + printf("Superblock is corrupted on %s\n", s->s_id); 352 356 goto out1; 353 357 } 354 358 355 - info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / 356 - sizeof(struct bfs_inode) 357 - + BFS_ROOT_INO - 1; 358 - imap_len = (info->si_lasti / 8) + 1; 359 - info->si_imap = kzalloc(imap_len, GFP_KERNEL | __GFP_NOWARN); 360 - if (!info->si_imap) { 361 - printf("Cannot allocate %u bytes\n", imap_len); 359 + info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / sizeof(struct bfs_inode) + BFS_ROOT_INO - 1; 360 + if (info->si_lasti == BFS_MAX_LASTI) 361 + printf("WARNING: filesystem %s was created with 512 inodes, the real maximum is 511, mounting anyway\n", s->s_id); 362 + else if (info->si_lasti > BFS_MAX_LASTI) { 363 + printf("Impossible last inode number %lu > %d on %s\n", info->si_lasti, BFS_MAX_LASTI, s->s_id); 362 364 goto out1; 363 365 } 364 366 for (i = 0; i < BFS_ROOT_INO; i++) ··· 366 372 inode = bfs_iget(s, BFS_ROOT_INO); 367 373 if (IS_ERR(inode)) { 368 374 ret = PTR_ERR(inode); 369 - goto out2; 375 + goto out1; 370 376 } 371 377 s->s_root = d_make_root(inode); 372 378 if (!s->s_root) { 373 379 ret = -ENOMEM; 374 - goto out2; 380 + goto out1; 375 381 } 376 382 377 383 info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1) >> BFS_BSIZE_BITS; 378 - info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1 379 - - le32_to_cpu(bfs_sb->s_start)) >> BFS_BSIZE_BITS; 384 + info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1 - le32_to_cpu(bfs_sb->s_start)) >> BFS_BSIZE_BITS; 380 385 info->si_freei = 0; 381 386 info->si_lf_eblk = 0; 382 387 383 388 /* can we read the last block? */ 384 389 bh = sb_bread(s, info->si_blocks - 1); 385 390 if (!bh) { 386 - printf("Last block not available: %lu\n", info->si_blocks - 1); 391 + printf("Last block not available on %s: %lu\n", s->s_id, info->si_blocks - 1); 387 392 ret = -EIO; 388 - goto out3; 393 + goto out2; 389 394 } 390 395 brelse(bh); 391 396 ··· 418 425 (i_eoff != le32_to_cpu(-1) && i_eoff > s_size) || 419 426 i_sblock * BFS_BSIZE > i_eoff) { 420 427 421 - printf("Inode 0x%08x corrupted\n", i); 428 + printf("Inode 0x%08x corrupted on %s\n", i, s->s_id); 422 429 423 430 brelse(bh); 424 431 ret = -EIO; 425 - goto out3; 432 + goto out2; 426 433 } 427 434 428 435 if (!di->i_ino) { ··· 438 445 } 439 446 brelse(bh); 440 447 brelse(sbh); 441 - bfs_dump_imap("read_super", s); 448 + bfs_dump_imap("fill_super", s); 442 449 return 0; 443 450 444 - out3: 451 + out2: 445 452 dput(s->s_root); 446 453 s->s_root = NULL; 447 - out2: 448 - kfree(info->si_imap); 449 454 out1: 450 455 brelse(sbh); 451 456 out: ··· 473 482 int err = init_inodecache(); 474 483 if (err) 475 484 goto out1; 476 - err = register_filesystem(&bfs_fs_type); 485 + err = register_filesystem(&bfs_fs_type); 477 486 if (err) 478 487 goto out; 479 488 return 0;
+1 -1
include/uapi/linux/bfs_fs.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 2 /* 3 3 * include/linux/bfs_fs.h - BFS data structures on disk. 4 - * Copyright (C) 1999 Tigran Aivazian <tigran@veritas.com> 4 + * Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com> 5 5 */ 6 6 7 7 #ifndef _LINUX_BFS_FS_H