From 23892d383bee15b64f5463bd7195615734bb2415 Mon Sep 17 00:00:00 2001 From: Yifei Liu Date: Wed, 3 Aug 2022 15:53:12 +0000 Subject: [PATCH 01/36] jffs2: correct logic when creating a hole in jffs2_write_begin Bug description and fix: 1. Write data to a file, say all 1s from offset 0 to 16. 2. Truncate the file to a smaller size, say 8 bytes. 3. Write new bytes (say 2s) from an offset past the original size of the file, say at offset 20, for 4 bytes. This is supposed to create a "hole" in the file, meaning that the bytes from offset 8 (where it was truncated above) up to the new write at offset 20, should all be 0s (zeros). 4. Flush all caches using "echo 3 > /proc/sys/vm/drop_caches" (or unmount and remount) the f/s. 5. Check the content of the file. It is wrong. The 1s that used to be between bytes 9 and 16, before the truncation, have REAPPEARED (they should be 0s). We wrote a script and helper C program to reproduce the bug (reproduce_jffs2_write_begin_issue.sh, write_file.c, and Makefile). We can make them available to anyone. The above example is shown when writing a small file within the same first page. But the bug happens for larger files, as long as steps 1, 2, and 3 above all happen within the same page. The problem was traced to the jffs2_write_begin code, where it goes into an 'if' statement intended to handle writes past the current EOF (i.e., writes that may create a hole). The code computes a 'pageofs' that is the floor of the write position (pos), aligned to the page size boundary. In other words, 'pageofs' will never be larger than 'pos'. The code then sets the internal jffs2_raw_inode->isize to the size of max(current inode size, pageofs) but that is wrong: the new file size should be the 'pos', which is larger than both the current inode size and pageofs. Similarly, the code incorrectly sets the internal jffs2_raw_inode->dsize to the difference between the pageofs minus current inode size; instead it should be the current pos minus the current inode size. Finally, inode->i_size was also set incorrectly. The patch below fixes this bug. The bug was discovered using a new tool for finding f/s bugs using model checking, called MCFS (Model Checking File Systems). Signed-off-by: Yifei Liu Signed-off-by: Erez Zadok Signed-off-by: Manish Adkar Signed-off-by: Richard Weinberger --- fs/jffs2/file.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 3cf71befa475..96b0275ce957 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -137,19 +137,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); pgoff_t index = pos >> PAGE_SHIFT; - uint32_t pageofs = index << PAGE_SHIFT; int ret = 0; jffs2_dbg(1, "%s()\n", __func__); - if (pageofs > inode->i_size) { - /* Make new hole frag from old EOF to new page */ + if (pos > inode->i_size) { + /* Make new hole frag from old EOF to new position */ struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; uint32_t alloc_len; - jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", - (unsigned int)inode->i_size, pageofs); + jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new position\n", + (unsigned int)inode->i_size, (uint32_t)pos); ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); @@ -169,10 +168,10 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, ri.mode = cpu_to_jemode(inode->i_mode); ri.uid = cpu_to_je16(i_uid_read(inode)); ri.gid = cpu_to_je16(i_gid_read(inode)); - ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); + ri.isize = cpu_to_je32((uint32_t)pos); ri.atime = ri.ctime = ri.mtime = cpu_to_je32(JFFS2_NOW()); ri.offset = cpu_to_je32(inode->i_size); - ri.dsize = cpu_to_je32(pageofs - inode->i_size); + ri.dsize = cpu_to_je32((uint32_t)pos - inode->i_size); ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); @@ -202,7 +201,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, goto out_err; } jffs2_complete_reservation(c); - inode->i_size = pageofs; + inode->i_size = pos; mutex_unlock(&f->sem); } From 1b42b1a36fc946f0d7088425b90d491b4257ca3e Mon Sep 17 00:00:00 2001 From: George Kennedy Date: Tue, 15 Nov 2022 10:14:44 -0500 Subject: [PATCH 02/36] ubi: ensure that VID header offset + VID header size <= alloc, size Ensure that the VID header offset + VID header size does not exceed the allocated area to avoid slab OOB. BUG: KASAN: slab-out-of-bounds in crc32_body lib/crc32.c:111 [inline] BUG: KASAN: slab-out-of-bounds in crc32_le_generic lib/crc32.c:179 [inline] BUG: KASAN: slab-out-of-bounds in crc32_le_base+0x58c/0x626 lib/crc32.c:197 Read of size 4 at addr ffff88802bb36f00 by task syz-executor136/1555 CPU: 2 PID: 1555 Comm: syz-executor136 Tainted: G W 6.0.0-1868 #1 Hardware name: Red Hat KVM, BIOS 1.13.0-2.module+el8.3.0+7860+a7792d29 04/01/2014 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0x85/0xad lib/dump_stack.c:106 print_address_description mm/kasan/report.c:317 [inline] print_report.cold.13+0xb6/0x6bb mm/kasan/report.c:433 kasan_report+0xa7/0x11b mm/kasan/report.c:495 crc32_body lib/crc32.c:111 [inline] crc32_le_generic lib/crc32.c:179 [inline] crc32_le_base+0x58c/0x626 lib/crc32.c:197 ubi_io_write_vid_hdr+0x1b7/0x472 drivers/mtd/ubi/io.c:1067 create_vtbl+0x4d5/0x9c4 drivers/mtd/ubi/vtbl.c:317 create_empty_lvol drivers/mtd/ubi/vtbl.c:500 [inline] ubi_read_volume_table+0x67b/0x288a drivers/mtd/ubi/vtbl.c:812 ubi_attach+0xf34/0x1603 drivers/mtd/ubi/attach.c:1601 ubi_attach_mtd_dev+0x6f3/0x185e drivers/mtd/ubi/build.c:965 ctrl_cdev_ioctl+0x2db/0x347 drivers/mtd/ubi/cdev.c:1043 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x193/0x213 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3e/0x86 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0x0 RIP: 0033:0x7f96d5cf753d Code: RSP: 002b:00007fffd72206f8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f96d5cf753d RDX: 0000000020000080 RSI: 0000000040186f40 RDI: 0000000000000003 RBP: 0000000000400cd0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000400be0 R13: 00007fffd72207e0 R14: 0000000000000000 R15: 0000000000000000 Allocated by task 1555: kasan_save_stack+0x20/0x3d mm/kasan/common.c:38 kasan_set_track mm/kasan/common.c:45 [inline] set_alloc_info mm/kasan/common.c:437 [inline] ____kasan_kmalloc mm/kasan/common.c:516 [inline] __kasan_kmalloc+0x88/0xa3 mm/kasan/common.c:525 kasan_kmalloc include/linux/kasan.h:234 [inline] __kmalloc+0x138/0x257 mm/slub.c:4429 kmalloc include/linux/slab.h:605 [inline] ubi_alloc_vid_buf drivers/mtd/ubi/ubi.h:1093 [inline] create_vtbl+0xcc/0x9c4 drivers/mtd/ubi/vtbl.c:295 create_empty_lvol drivers/mtd/ubi/vtbl.c:500 [inline] ubi_read_volume_table+0x67b/0x288a drivers/mtd/ubi/vtbl.c:812 ubi_attach+0xf34/0x1603 drivers/mtd/ubi/attach.c:1601 ubi_attach_mtd_dev+0x6f3/0x185e drivers/mtd/ubi/build.c:965 ctrl_cdev_ioctl+0x2db/0x347 drivers/mtd/ubi/cdev.c:1043 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:870 [inline] __se_sys_ioctl fs/ioctl.c:856 [inline] __x64_sys_ioctl+0x193/0x213 fs/ioctl.c:856 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x3e/0x86 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0x0 The buggy address belongs to the object at ffff88802bb36e00 which belongs to the cache kmalloc-256 of size 256 The buggy address is located 0 bytes to the right of 256-byte region [ffff88802bb36e00, ffff88802bb36f00) The buggy address belongs to the physical page: page:00000000ea4d1263 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x2bb36 head:00000000ea4d1263 order:1 compound_mapcount:0 compound_pincount:0 flags: 0xfffffc0010200(slab|head|node=0|zone=1|lastcpupid=0x1fffff) raw: 000fffffc0010200 ffffea000066c300 dead000000000003 ffff888100042b40 raw: 0000000000000000 0000000000100010 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88802bb36e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff88802bb36e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffff88802bb36f00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ^ ffff88802bb36f80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff88802bb37000: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ================================================================== Fixes: 801c135ce73d ("UBI: Unsorted Block Images") Reported-by: syzkaller Signed-off-by: George Kennedy Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/build.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index a901f8edfa41..2178eb4115b3 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -663,6 +663,12 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024) ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size); ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size); + if (ubi->vid_hdr_offset && ((ubi->vid_hdr_offset + UBI_VID_HDR_SIZE) > + ubi->vid_hdr_alsize)) { + ubi_err(ubi, "VID header offset %d too large.", ubi->vid_hdr_offset); + return -EINVAL; + } + dbg_gen("min_io_size %d", ubi->min_io_size); dbg_gen("max_write_size %d", ubi->max_write_size); dbg_gen("hdrs_min_io_size %d", ubi->hdrs_min_io_size); From aa6d148e6d6270274e3d5a529b71c54cd329d17f Mon Sep 17 00:00:00 2001 From: Li Hua Date: Mon, 21 Nov 2022 19:18:47 +0800 Subject: [PATCH 03/36] ubifs: Fix build errors as symbol undefined With CONFIG_UBIFS_FS_AUTHENTICATION not set, the compiler can assume that ubifs_node_check_hash() is never true and drops the call to ubifs_bad_hash(). Is CONFIG_CC_OPTIMIZE_FOR_SIZE enabled this optimization does not happen anymore. So When CONFIG_UBIFS_FS and CONFIG_CC_OPTIMIZE_FOR_SIZE is enabled but CONFIG_UBIFS_FS_AUTHENTICATION is not set, the build errors is as followd: ERROR: modpost: "ubifs_bad_hash" [fs/ubifs/ubifs.ko] undefined! Fix it by add no-op ubifs_bad_hash() for the CONFIG_UBIFS_FS_AUTHENTICATION=n case. Fixes: 16a26b20d2af ("ubifs: authentication: Add hashes to index nodes") Signed-off-by: Li Hua Reviewed-by: Sascha Hauer Signed-off-by: Richard Weinberger --- fs/ubifs/ubifs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 478bbbb5382f..2f1f31581094 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1623,8 +1623,13 @@ static inline int ubifs_check_hmac(const struct ubifs_info *c, return crypto_memneq(expected, got, c->hmac_desc_len); } +#ifdef CONFIG_UBIFS_FS_AUTHENTICATION void ubifs_bad_hash(const struct ubifs_info *c, const void *node, const u8 *hash, int lnum, int offs); +#else +static inline void ubifs_bad_hash(const struct ubifs_info *c, const void *node, + const u8 *hash, int lnum, int offs) {}; +#endif int __ubifs_node_check_hash(const struct ubifs_info *c, const void *buf, const u8 *expected); From 203a55f04f66eea1a1ca7e5a302a7f5c99c62327 Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Thu, 20 Oct 2022 12:30:31 +0800 Subject: [PATCH 04/36] ubifs: Fix memory leak in ubifs_sysfs_init() When insmod ubifs.ko, a kmemleak reported as below: unreferenced object 0xffff88817fb1a780 (size 8): comm "insmod", pid 25265, jiffies 4295239702 (age 100.130s) hex dump (first 8 bytes): 75 62 69 66 73 00 ff ff ubifs... backtrace: [] slab_post_alloc_hook+0x9c/0x3c0 [] __kmalloc_track_caller+0x183/0x410 [] kstrdup+0x3a/0x80 [] kstrdup_const+0x66/0x80 [] kvasprintf_const+0x155/0x190 [] kobject_set_name_vargs+0x5b/0x150 [] kobject_set_name+0xbb/0xf0 [] do_one_initcall+0x14c/0x5a0 [] do_init_module+0x1f0/0x660 [] load_module+0x6d7e/0x7590 [] __do_sys_finit_module+0x19f/0x230 [] __x64_sys_finit_module+0x73/0xb0 [] do_syscall_64+0x35/0x80 [] entry_SYSCALL_64_after_hwframe+0x63/0xcd When kset_register() failed, we should call kset_put to cleanup it. Fixes: 2e3cbf425804 ("ubifs: Export filesystem error counters") Signed-off-by: Liu Shixin Signed-off-by: Richard Weinberger --- fs/ubifs/sysfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ubifs/sysfs.c b/fs/ubifs/sysfs.c index 06ad8fa1fcfb..54270ad36321 100644 --- a/fs/ubifs/sysfs.c +++ b/fs/ubifs/sysfs.c @@ -144,6 +144,8 @@ int __init ubifs_sysfs_init(void) kobject_set_name(&ubifs_kset.kobj, "ubifs"); ubifs_kset.kobj.parent = fs_kobj; ret = kset_register(&ubifs_kset); + if (ret) + kset_put(&ubifs_kset); return ret; } From 6addbe91fcccd446036d5acc8e54a9b4395ac4bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Lindahl?= Date: Thu, 13 Oct 2022 14:02:49 +0200 Subject: [PATCH 05/36] ubi: block: Reduce warning print to info for static volumes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If volume size is not multiple of the sector size 512 a warning is printed saying that the last non-sector aligned bytes will be ignored. This should be valid for resizable volumes, but when creating static volumes which are read only this will always be printed even if the unaligned data is deliberate. The message is still valid but the severity should be lowered for static volumes. Signed-off-by: Mårten Lindahl Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/block.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 75eaecc8639f..d725215ae66e 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -354,9 +354,12 @@ static int calc_disk_capacity(struct ubi_volume_info *vi, u64 *disk_capacity) u64 size = vi->used_bytes >> 9; if (vi->used_bytes % 512) { - pr_warn("UBI: block: volume size is not a multiple of 512, " - "last %llu bytes are ignored!\n", - vi->used_bytes - (size << 9)); + if (vi->vol_type == UBI_DYNAMIC_VOLUME) + pr_warn("UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored!\n", + vi->used_bytes - (size << 9)); + else + pr_info("UBI: block: volume size is not a multiple of 512, last %llu bytes are ignored!\n", + vi->used_bytes - (size << 9)); } if ((sector_t)size != size) From c2c36cc6ca23e614f9e4238d0ecf48549ee9002a Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:27 +0800 Subject: [PATCH 06/36] ubifs: Rectify space budget for ubifs_symlink() if symlink is encrypted Fix bad space budget when symlink file is encrypted. Bad space budget may let make_reservation() return with -ENOSPC, which could turn ubifs to read-only mode in do_writepage() process. Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216490 Fixes: ca7f85be8d6cf9 ("ubifs: Add support for encrypted symlinks") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 0f29cf201136..aaff3f3f0aa3 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1151,7 +1151,6 @@ static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir, int err, sz_change, len = strlen(symname); struct fscrypt_str disk_link; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, - .new_ino_d = ALIGN(len, 8), .dirtied_ino = 1 }; struct fscrypt_name nm; @@ -1167,6 +1166,7 @@ static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir, * Budget request settings: new inode, new direntry and changing parent * directory inode. */ + req.new_ino_d = ALIGN(disk_link.len - 1, 8); err = ubifs_budget_space(c, &req); if (err) return err; From 1b2ba09060e41adb356b9ae58ef94a7390928004 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:28 +0800 Subject: [PATCH 07/36] ubifs: Rectify space budget for ubifs_xrename() There is no space budget for ubifs_xrename(). It may let make_reservation() return with -ENOSPC, which could turn ubifs to read-only mode in do_writepage() process. Fix it by adding space budget for ubifs_xrename(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216569 Fixes: 9ec64962afb170 ("ubifs: Implement RENAME_EXCHANGE") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index aaff3f3f0aa3..94634b872e38 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1576,6 +1576,10 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, return err; } + err = ubifs_budget_space(c, &req); + if (err) + goto out; + lock_4_inodes(old_dir, new_dir, NULL, NULL); time = current_time(old_dir); @@ -1601,6 +1605,7 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, unlock_4_inodes(old_dir, new_dir, NULL, NULL); ubifs_release_budget(c, &req); +out: fscrypt_free_filename(&fst_nm); fscrypt_free_filename(&snd_nm); return err; From c04cc68da856eac2b59e2a421c3f81a2afc560db Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:29 +0800 Subject: [PATCH 08/36] ubifs: Add comments and debug info for ubifs_xrename() Just like other operations (eg. ubifs_create, do_rename), add comments and debug information for ubifs_xrename(). Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 94634b872e38..7a1dcd14e387 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1566,6 +1566,15 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, ubifs_assert(c, fst_inode && snd_inode); + /* + * Budget request settings: changing two direntries, changing the two + * parent directory inodes. + */ + + dbg_gen("dent '%pd' ino %lu in dir ino %lu exchange dent '%pd' ino %lu in dir ino %lu", + old_dentry, fst_inode->i_ino, old_dir->i_ino, + new_dentry, snd_inode->i_ino, new_dir->i_ino); + err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm); if (err) return err; From b248eaf049d9cdc5eb76b59399e4d3de233f02ac Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:30 +0800 Subject: [PATCH 09/36] ubifs: Fix wrong dirty space budget for dirty inode Each dirty inode should reserve 'c->bi.inode_budget' bytes in space budget calculation. Currently, space budget for dirty inode reports more space than what UBIFS actually needs to write. Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/budget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index e8b9b756f0ac..986e6e4081c7 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c @@ -400,7 +400,7 @@ static int calc_dd_growth(const struct ubifs_info *c, dd_growth = req->dirtied_page ? c->bi.page_budget : 0; if (req->dirtied_ino) - dd_growth += c->bi.inode_budget << (req->dirtied_ino - 1); + dd_growth += c->bi.inode_budget * req->dirtied_ino; if (req->mod_dent) dd_growth += c->bi.dent_budget; dd_growth += req->dirtied_ino_d; From 25fce616a61fc2f1821e4a9ce212d0e064707093 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:31 +0800 Subject: [PATCH 10/36] ubifs: do_rename: Fix wrong space budget when target inode's nlink > 1 If target inode is a special file (eg. block/char device) with nlink count greater than 1, the inode with ui->data will be re-written on disk. However, UBIFS losts target inode's data_len while doing space budget. Bad space budget may let make_reservation() return with -ENOSPC, which could turn ubifs to read-only mode in do_writepage() process. Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216494 Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/dir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 7a1dcd14e387..4509d9fa9e6e 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -1324,6 +1324,8 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, if (unlink) { ubifs_assert(c, inode_is_locked(new_inode)); + /* Budget for old inode's data when its nlink > 1. */ + req.dirtied_ino_d = ALIGN(ubifs_inode(new_inode)->data_len, 8); err = ubifs_purge_xattrs(new_inode); if (err) return err; From e874dcde1cbf82c786c0e7f2899811c02630cc52 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 11 Oct 2022 11:47:32 +0800 Subject: [PATCH 11/36] ubifs: Reserve one leb for each journal head while doing budget UBIFS calculates available space by c->main_bytes - c->lst.total_used (which means non-index lebs' free and dirty space is accounted into total available), then index lebs and four lebs (one for gc_lnum, one for deletions, two for journal heads) are deducted. In following situation, ubifs may get -ENOSPC from make_reservation(): LEB 84: DATAHD free 122880 used 1920 dirty 2176 dark 6144 LEB 110:DELETION free 126976 used 0 dirty 0 dark 6144 (empty) LEB 201:gc_lnum free 126976 used 0 dirty 0 dark 6144 LEB 272:GCHD free 77824 used 47672 dirty 1480 dark 6144 LEB 356:BASEHD free 0 used 39776 dirty 87200 dark 6144 OTHERS: index lebs, zero-available non-index lebs UBIFS calculates the available bytes is 6888 (How to calculate it: 126976 * 5[remain main bytes] - 1920[used] - 47672[used] - 39776[used] - 126976 * 1[deletions] - 126976 * 1[gc_lnum] - 126976 * 2[journal heads] - 6144 * 5[dark] = 6888) after doing budget, however UBIFS cannot use BASEHD's dirty space(87200), because UBIFS cannot find next BASEHD to reclaim current BASEHD. (c->bi.min_idx_lebs equals to c->lst.idx_lebs, the empty leb won't be found by ubifs_find_free_space(), and dirty index lebs won't be picked as gced lebs. All non-index lebs has dirty space less then c->dead_wm, non-index lebs won't be picked as gced lebs either. So new free lebs won't be produced.). See more details in Link. To fix it, reserve one leb for each journal head while doing budget. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216562 Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/budget.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index 986e6e4081c7..d76eb7b39f56 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c @@ -209,11 +209,10 @@ long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs) subtract_lebs += 1; /* - * The GC journal head LEB is not really accessible. And since - * different write types go to different heads, we may count only on - * one head's space. + * Since different write types go to different heads, we should + * reserve one leb for each head. */ - subtract_lebs += c->jhead_cnt - 1; + subtract_lebs += c->jhead_cnt; /* We also reserve one LEB for deletions, which bypass budgeting */ subtract_lebs += 1; From 9af31d6ec1a4be4caab2550096c6bd2ba8fba472 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Fri, 21 Oct 2022 18:21:56 +0800 Subject: [PATCH 12/36] ubi: Fix use-after-free when volume resizing failed There is an use-after-free problem reported by KASAN: ================================================================== BUG: KASAN: use-after-free in ubi_eba_copy_table+0x11f/0x1c0 [ubi] Read of size 8 at addr ffff888101eec008 by task ubirsvol/4735 CPU: 2 PID: 4735 Comm: ubirsvol Not tainted 6.1.0-rc1-00003-g84fa3304a7fc-dirty #14 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014 Call Trace: dump_stack_lvl+0x34/0x44 print_report+0x171/0x472 kasan_report+0xad/0x130 ubi_eba_copy_table+0x11f/0x1c0 [ubi] ubi_resize_volume+0x4f9/0xbc0 [ubi] ubi_cdev_ioctl+0x701/0x1850 [ubi] __x64_sys_ioctl+0x11d/0x170 do_syscall_64+0x35/0x80 entry_SYSCALL_64_after_hwframe+0x46/0xb0 When ubi_change_vtbl_record() returns an error in ubi_resize_volume(), "new_eba_tbl" will be freed on error handing path, but it is holded by "vol->eba_tbl" in ubi_eba_replace_table(). It means that the liftcycle of "vol->eba_tbl" and "vol" are different, so when resizing volume in next time, it causing an use-after-free fault. Fix it by not freeing "new_eba_tbl" after it replaced in ubi_eba_replace_table(), while will be freed in next volume resizing. Fixes: 801c135ce73d ("UBI: Unsorted Block Images") Signed-off-by: Li Zetao Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/vmt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 8fcc0bdf0635..74637575346e 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -464,7 +464,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) for (i = 0; i < -pebs; i++) { err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); if (err) - goto out_acc; + goto out_free; } spin_lock(&ubi->volumes_lock); ubi->rsvd_pebs += pebs; @@ -512,6 +512,8 @@ out_acc: ubi->avail_pebs += pebs; spin_unlock(&ubi->volumes_lock); } + return err; + out_free: kfree(new_eba_tbl); return err; From 1e591ea072df7211f64542a09482b5f81cb3ad27 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Fri, 21 Oct 2022 18:21:57 +0800 Subject: [PATCH 13/36] ubi: Fix unreferenced object reported by kmemleak in ubi_resize_volume() There is a memory leaks problem reported by kmemleak: unreferenced object 0xffff888102007a00 (size 128): comm "ubirsvol", pid 32090, jiffies 4298464136 (age 2361.231s) hex dump (first 32 bytes): ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ................ backtrace: [] __kmalloc+0x4d/0x150 [] ubi_eba_create_table+0x76/0x170 [ubi] [] ubi_resize_volume+0x1be/0xbc0 [ubi] [] ubi_cdev_ioctl+0x701/0x1850 [ubi] [] __x64_sys_ioctl+0x11d/0x170 [] do_syscall_64+0x35/0x80 [] entry_SYSCALL_64_after_hwframe+0x46/0xb0 This is due to a mismatch between create and destroy interfaces, and in detail that "new_eba_tbl" created by ubi_eba_create_table() but destroyed by kfree(), while will causing "new_eba_tbl->entries" not freed. Fix it by replacing kfree(new_eba_tbl) with ubi_eba_destroy_table(new_eba_tbl) Fixes: 799dca34ac54 ("UBI: hide EBA internals") Signed-off-by: Li Zetao Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/vmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 74637575346e..9fbc64b997ce 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -515,7 +515,7 @@ out_acc: return err; out_free: - kfree(new_eba_tbl); + ubi_eba_destroy_table(new_eba_tbl); return err; } From 4a1ff3c5d04b9079b4f768d9a71b51c4af578dd2 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Sat, 22 Oct 2022 19:52:11 +0800 Subject: [PATCH 14/36] ubifs: Fix memory leak in alloc_wbufs() kmemleak reported a sequence of memory leaks, and show them as following: unreferenced object 0xffff8881575f8400 (size 1024): comm "mount", pid 19625, jiffies 4297119604 (age 20.383s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] __kmalloc+0x4d/0x150 [] ubifs_mount+0x307b/0x7170 [ubifs] [] legacy_get_tree+0xed/0x1d0 [] vfs_get_tree+0x7d/0x230 [] path_mount+0xdd4/0x17b0 [] __x64_sys_mount+0x1fa/0x270 [] do_syscall_64+0x35/0x80 [] entry_SYSCALL_64_after_hwframe+0x46/0xb0 unreferenced object 0xffff8881798a6e00 (size 512): comm "mount", pid 19677, jiffies 4297121912 (age 37.816s) hex dump (first 32 bytes): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk backtrace: [] __kmalloc+0x4d/0x150 [] ubifs_wbuf_init+0x52/0x480 [ubifs] [] ubifs_mount+0x31f5/0x7170 [ubifs] [] legacy_get_tree+0xed/0x1d0 [] vfs_get_tree+0x7d/0x230 [] path_mount+0xdd4/0x17b0 [] __x64_sys_mount+0x1fa/0x270 [] do_syscall_64+0x35/0x80 [] entry_SYSCALL_64_after_hwframe+0x46/0xb0 The problem is that the ubifs_wbuf_init() returns an error in the loop which in the alloc_wbufs(), then the wbuf->buf and wbuf->inodes that were successfully alloced before are not freed. Fix it by adding error hanging path in alloc_wbufs() which frees the memory alloced before when ubifs_wbuf_init() returns an error. Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Li Zetao Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/super.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index d0c9a09988bc..32cb14759796 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -833,7 +833,7 @@ static int alloc_wbufs(struct ubifs_info *c) INIT_LIST_HEAD(&c->jheads[i].buds_list); err = ubifs_wbuf_init(c, &c->jheads[i].wbuf); if (err) - return err; + goto out_wbuf; c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback; c->jheads[i].wbuf.jhead = i; @@ -841,7 +841,7 @@ static int alloc_wbufs(struct ubifs_info *c) c->jheads[i].log_hash = ubifs_hash_get_desc(c); if (IS_ERR(c->jheads[i].log_hash)) { err = PTR_ERR(c->jheads[i].log_hash); - goto out; + goto out_log_hash; } } @@ -854,9 +854,18 @@ static int alloc_wbufs(struct ubifs_info *c) return 0; -out: - while (i--) +out_log_hash: + kfree(c->jheads[i].wbuf.buf); + kfree(c->jheads[i].wbuf.inodes); + +out_wbuf: + while (i--) { + kfree(c->jheads[i].wbuf.buf); + kfree(c->jheads[i].wbuf.inodes); kfree(c->jheads[i].log_hash); + } + kfree(c->jheads); + c->jheads = NULL; return err; } From 7af73882dd1cea5d32ac0cc9eda263635295de50 Mon Sep 17 00:00:00 2001 From: ZhaoLong Wang Date: Tue, 25 Oct 2022 16:52:49 +0800 Subject: [PATCH 15/36] ubi: fastmap: Add fastmap control support for module parameter The UBI driver can use the IOCTL to disable the fastmap after the mainline 669d204469c4 ("ubi: fastmap: Add fastmap control support for 'UBI_IOCATT' ioctl"). To destroy the fastmap on a old image, we need to reattach the device in user space. However, if the UBI driver build in kernel and the UBI volume is the root partition, the UBI device cannot be reattached in user space. To disable fastmap in this case, the UBI must provide the kernel cmdline parameters to disable fastmap during attach. This patch add 'enable_fm' as 5th module init parameter of mtd=xx to control fastmap enable or not. When the value is 0, fastmap will not create and existed fastmap will destroyed for the given ubi device. Default value is 0. To enable or disable fastmap during module loading, fm_autoconvert must be set to non-zero. +-----------------+---------------+---------------------------+ | \ | enable_fm=0 | enable_fm=1 | +-----------------+---------------+---------------------------+ |fm_autoconvert=Y | disable fm | enable fm | +---------------------------------+---------------------------+ |fm_autoconvert=N | disable fm | Enable fastmap if fastmap | | | | exists on the old image | +-------------------------------------------------------------+ Example: # - Attach mtd1 to ubi1, disable fastmap, mtd2 to ubi2, enable fastmap. # modprobe ubi mtd=1,0,0,1,0 mtd=2,0,0,2,1 fm_autoconvert=1 # - If 5th parameter is not specified, the value is 0, fastmap is disable # modprobe ubi mtd=1 fm_autoconvert=1 Link: https://bugzilla.kernel.org/show_bug.cgi?id=216623 Signed-off-by: ZhaoLong Wang Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/build.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 2178eb4115b3..eaf3c0c86b2b 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -35,7 +35,7 @@ #define MTD_PARAM_LEN_MAX 64 /* Maximum number of comma-separated items in the 'mtd=' parameter */ -#define MTD_PARAM_MAX_COUNT 4 +#define MTD_PARAM_MAX_COUNT 5 /* Maximum value for the number of bad PEBs per 1024 PEBs */ #define MAX_MTD_UBI_BEB_LIMIT 768 @@ -53,12 +53,14 @@ * @ubi_num: UBI number * @vid_hdr_offs: VID header offset * @max_beb_per1024: maximum expected number of bad PEBs per 1024 PEBs + * @enable_fm: enable fastmap when value is non-zero */ struct mtd_dev_param { char name[MTD_PARAM_LEN_MAX]; int ubi_num; int vid_hdr_offs; int max_beb_per1024; + int enable_fm; }; /* Numbers of elements set in the @mtd_dev_param array */ @@ -1254,7 +1256,7 @@ static int __init ubi_init(void) mutex_lock(&ubi_devices_mutex); err = ubi_attach_mtd_dev(mtd, p->ubi_num, p->vid_hdr_offs, p->max_beb_per1024, - false); + p->enable_fm == 0 ? true : false); mutex_unlock(&ubi_devices_mutex); if (err < 0) { pr_err("UBI error: cannot attach mtd%d\n", @@ -1433,7 +1435,7 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) int err = kstrtoint(token, 10, &p->max_beb_per1024); if (err) { - pr_err("UBI error: bad value for max_beb_per1024 parameter: %s", + pr_err("UBI error: bad value for max_beb_per1024 parameter: %s\n", token); return -EINVAL; } @@ -1444,13 +1446,25 @@ static int ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) int err = kstrtoint(token, 10, &p->ubi_num); if (err) { - pr_err("UBI error: bad value for ubi_num parameter: %s", + pr_err("UBI error: bad value for ubi_num parameter: %s\n", token); return -EINVAL; } } else p->ubi_num = UBI_DEV_NUM_AUTO; + token = tokens[4]; + if (token) { + int err = kstrtoint(token, 10, &p->enable_fm); + + if (err) { + pr_err("UBI error: bad value for enable_fm parameter: %s\n", + token); + return -EINVAL; + } + } else + p->enable_fm = 0; + mtd_devs += 1; return 0; } @@ -1463,11 +1477,13 @@ MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: mtd= Date: Mon, 14 Nov 2022 18:26:24 +0800 Subject: [PATCH 16/36] ubi: Fix possible null-ptr-deref in ubi_free_volume() It willl cause null-ptr-deref in the following case: uif_init() ubi_add_volume() cdev_add() -> if it fails, call kill_volumes() device_register() kill_volumes() -> if ubi_add_volume() fails call this function ubi_free_volume() cdev_del() device_unregister() -> trying to delete a not added device, it causes null-ptr-deref So in ubi_free_volume(), it delete devices whether they are added or not, it will causes null-ptr-deref. Handle the error case whlie calling ubi_add_volume() to fix this problem. If add volume fails, set the corresponding vol to null, so it can not be accessed in kill_volumes() and release the resource in ubi_add_volume() error path. Fixes: 801c135ce73d ("UBI: Unsorted Block Images") Suggested-by: Zhihao Cheng Signed-off-by: Yang Yingliang Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/build.c | 1 + drivers/mtd/ubi/vmt.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index eaf3c0c86b2b..5e90a4423b69 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -470,6 +470,7 @@ static int uif_init(struct ubi_device *ubi) err = ubi_add_volume(ubi, ubi->volumes[i]); if (err) { ubi_err(ubi, "cannot add volume %d", i); + ubi->volumes[i] = NULL; goto out_volumes; } } diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 9fbc64b997ce..2c867d16f89f 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -582,6 +582,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) if (err) { ubi_err(ubi, "cannot add character device for volume %d, error %d", vol_id, err); + vol_release(&vol->dev); return err; } @@ -592,15 +593,14 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) vol->dev.groups = volume_dev_groups; dev_set_name(&vol->dev, "%s_%d", ubi->ubi_name, vol->vol_id); err = device_register(&vol->dev); - if (err) - goto out_cdev; + if (err) { + cdev_del(&vol->cdev); + put_device(&vol->dev); + return err; + } self_check_volumes(ubi); return err; - -out_cdev: - cdev_del(&vol->cdev); - return err; } /** From 2de203d8ab51657664a60f2d4cd89cb7d75b7eac Mon Sep 17 00:00:00 2001 From: ZhaoLong Wang Date: Mon, 14 Nov 2022 22:46:46 +0800 Subject: [PATCH 17/36] ubi: Fix permission display of the debugfs files Some interface files in debugfs support the read method dfs_file_read(), but their rwx permissions is shown as unreadable. In the user mode, the following problem can be clearly seen: # ls -l /sys/kernel/debug/ubi/ubi0/ total 0 --w------- 1 root root 0 Oct 22 16:26 chk_fastmap --w------- 1 root root 0 Oct 22 16:26 chk_gen --w------- 1 root root 0 Oct 22 16:26 chk_io -r-------- 1 root root 0 Oct 22 16:26 detailed_erase_block_info --w------- 1 root root 0 Oct 22 16:26 tst_disable_bgt --w------- 1 root root 0 Oct 22 16:26 tst_emulate_bitflips --w------- 1 root root 0 Oct 22 16:26 tst_emulate_io_failures --w------- 1 root root 0 Oct 22 16:26 tst_emulate_power_cut --w------- 1 root root 0 Oct 22 16:26 tst_emulate_power_cut_max --w------- 1 root root 0 Oct 22 16:26 tst_emulate_power_cut_min It shows that these files do not have read permission 'r', but we can actually read their contents. # echo 1 > /sys/kernel/debug/ubi/ubi0/chk_io # cat /sys/kernel/debug/ubi/ubi0/chk_io 1 User's permission access is determined by capabilities. Of course, the root user is not restricted from reading these files. When reading a debugfs file, the process is as follows: ksys_read() vfs_read() if (file->f_op->read) file->f_op->read() full_proxy_open() real_fops->read() dfs_file_read() -- Read method of debugfs file. else if (file->f_op->read_iter) new_sync_read() else ret = -EINVAL -- Return -EINVAL if no read method. This indicates that the debugfs file can be read as long as the read method of the debugfs file is registered. This patch adds the read permission display for file that support the read method. Signed-off-by: ZhaoLong Wang Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/debug.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c index fcca6942dbdd..27168f511d6d 100644 --- a/drivers/mtd/ubi/debug.c +++ b/drivers/mtd/ubi/debug.c @@ -504,6 +504,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) { unsigned long ubi_num = ubi->ubi_num; struct ubi_debug_info *d = &ubi->dbg; + umode_t mode = S_IRUSR | S_IWUSR; int n; if (!IS_ENABLED(CONFIG_DEBUG_FS)) @@ -518,41 +519,41 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) d->dfs_dir = debugfs_create_dir(d->dfs_dir_name, dfs_rootdir); - d->dfs_chk_gen = debugfs_create_file("chk_gen", S_IWUSR, d->dfs_dir, + d->dfs_chk_gen = debugfs_create_file("chk_gen", mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); - d->dfs_chk_io = debugfs_create_file("chk_io", S_IWUSR, d->dfs_dir, + d->dfs_chk_io = debugfs_create_file("chk_io", mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); - d->dfs_chk_fastmap = debugfs_create_file("chk_fastmap", S_IWUSR, + d->dfs_chk_fastmap = debugfs_create_file("chk_fastmap", mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); - d->dfs_disable_bgt = debugfs_create_file("tst_disable_bgt", S_IWUSR, + d->dfs_disable_bgt = debugfs_create_file("tst_disable_bgt", mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); d->dfs_emulate_bitflips = debugfs_create_file("tst_emulate_bitflips", - S_IWUSR, d->dfs_dir, + mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); d->dfs_emulate_io_failures = debugfs_create_file("tst_emulate_io_failures", - S_IWUSR, d->dfs_dir, + mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); d->dfs_emulate_power_cut = debugfs_create_file("tst_emulate_power_cut", - S_IWUSR, d->dfs_dir, + mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); d->dfs_power_cut_min = debugfs_create_file("tst_emulate_power_cut_min", - S_IWUSR, d->dfs_dir, + mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); d->dfs_power_cut_max = debugfs_create_file("tst_emulate_power_cut_max", - S_IWUSR, d->dfs_dir, + mode, d->dfs_dir, (void *)ubi_num, &dfs_fops); debugfs_create_file("detailed_erase_block_info", S_IRUSR, d->dfs_dir, From 944e096aa24071d3fe22822f6249d3ae309e39ea Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Fri, 18 Nov 2022 17:02:35 +0800 Subject: [PATCH 18/36] ubifs: Re-statistic cleaned znode count if commit failed Dirty znodes will be written on flash in committing process with following states: process A | znode state ------------------------------------------------------ do_commit | DIRTY_ZNODE ubifs_tnc_start_commit | DIRTY_ZNODE get_znodes_to_commit | DIRTY_ZNODE | COW_ZNODE layout_commit | DIRTY_ZNODE | COW_ZNODE fill_gap | 0 write master | 0 or OBSOLETE_ZNODE process B | znode state ------------------------------------------------------ do_commit | DIRTY_ZNODE[1] ubifs_tnc_start_commit | DIRTY_ZNODE get_znodes_to_commit | DIRTY_ZNODE | COW_ZNODE ubifs_tnc_end_commit | DIRTY_ZNODE | COW_ZNODE write_index | 0 write master | 0 or OBSOLETE_ZNODE[2] or | DIRTY_ZNODE[3] [1] znode is dirtied without concurrent committing process [2] znode is copied up (re-dirtied by other process) before cleaned up in committing process [3] znode is re-dirtied after cleaned up in committing process Currently, the clean znode count is updated in free_obsolete_znodes(), which is called only in normal path. If do_commit failed, clean znode count won't be updated, which triggers a failure ubifs assertion[4] in ubifs_tnc_close(): ubifs_assert_failed [ubifs]: UBIFS assert failed: freed == n [4] Commit 380347e9ca7682 ("UBIFS: Add an assertion for clean_zn_cnt"). Fix it by re-statisticing cleaned znode count in tnc_destroy_cnext(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216704 Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/tnc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 488f3da7a6c6..2df56bbc6865 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -3053,6 +3053,21 @@ static void tnc_destroy_cnext(struct ubifs_info *c) cnext = cnext->cnext; if (ubifs_zn_obsolete(znode)) kfree(znode); + else if (!ubifs_zn_cow(znode)) { + /* + * Don't forget to update clean znode count after + * committing failed, because ubifs will check this + * count while closing tnc. Non-obsolete znode could + * be re-dirtied during committing process, so dirty + * flag is untrustable. The flag 'COW_ZNODE' is set + * for each dirty znode before committing, and it is + * cleared as long as the znode become clean, so we + * can statistic clean znode count according to this + * flag. + */ + atomic_long_inc(&c->clean_zn_cnt); + atomic_long_inc(&ubifs_clean_zn_cnt); + } } while (cnext && cnext != c->cnext); } From 122deabfe1428bffe95e2bf364ff8a5059bdf089 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Fri, 18 Nov 2022 17:02:36 +0800 Subject: [PATCH 19/36] ubifs: dirty_cow_znode: Fix memleak in error handling path Following process will cause a memleak for copied up znode: dirty_cow_znode zn = copy_znode(c, znode); err = insert_old_idx(c, zbr->lnum, zbr->offs); if (unlikely(err)) return ERR_PTR(err); // No one refers to zn. Fix it by adding copied znode back to tnc, then it will be freed by ubifs_destroy_tnc_subtree() while closing tnc. Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216705 Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/tnc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 2df56bbc6865..2469f72eeaab 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -267,11 +267,18 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c, if (zbr->len) { err = insert_old_idx(c, zbr->lnum, zbr->offs); if (unlikely(err)) - return ERR_PTR(err); + /* + * Obsolete znodes will be freed by tnc_destroy_cnext() + * or free_obsolete_znodes(), copied up znodes should + * be added back to tnc and freed by + * ubifs_destroy_tnc_subtree(). + */ + goto out; err = add_idx_dirt(c, zbr->lnum, zbr->len); } else err = 0; +out: zbr->znode = zn; zbr->lnum = 0; zbr->offs = 0; From fb8bc4c74ae4526d9489362ab2793a936d072b84 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Wed, 1 Jun 2022 10:59:59 +0800 Subject: [PATCH 20/36] ubifs: ubifs_writepage: Mark page dirty after writing inode failed There are two states for ubifs writing pages: 1. Dirty, Private 2. Not Dirty, Not Private There is a third possibility which maybe related to [1] that page is private but not dirty caused by following process: PA lock(page) ubifs_write_end attach_page_private // set Private __set_page_dirty_nobuffers // set Dirty unlock(page) write_cache_pages lock(page) clear_page_dirty_for_io(page) // clear Dirty ubifs_writepage write_inode // fail, goto out, following codes are not executed // do_writepage // set_page_writeback // set Writeback // detach_page_private // clear Private // end_page_writeback // clear Writeback out: unlock(page) // Private, Not Dirty PB ksys_fadvise64_64 generic_fadvise invalidate_inode_page // page is neither Dirty nor Writeback invalidate_complete_page // page_has_private is true try_to_release_page ubifs_releasepage ubifs_assert(c, 0) !!! Then we may get following assertion failed: UBIFS error (ubi0:0 pid 1492): ubifs_assert_failed [ubifs]: UBIFS assert failed: 0, in fs/ubifs/file.c:1499 UBIFS warning (ubi0:0 pid 1492): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22 CPU: 2 PID: 1492 Comm: aa Not tainted 5.16.0-rc2-00012-g7bb767dee0ba-dirty Call Trace: dump_stack+0x13/0x1b ubifs_ro_mode+0x54/0x60 [ubifs] ubifs_assert_failed+0x4b/0x80 [ubifs] ubifs_releasepage+0x7e/0x1e0 [ubifs] try_to_release_page+0x57/0xe0 invalidate_inode_page+0xfb/0x130 invalidate_mapping_pagevec+0x12/0x20 generic_fadvise+0x303/0x3c0 vfs_fadvise+0x35/0x40 ksys_fadvise64_64+0x4c/0xb0 Jump [2] to find a reproducer. [1] https://linux-mtd.infradead.narkive.com/NQoBeT1u/patch-rfc-ubifs-fix-assert-failed-in-ubifs-set-page-dirty [2] https://bugzilla.kernel.org/show_bug.cgi?id=215357 Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/file.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index f2353dd676ef..1f429260a85f 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1032,7 +1032,7 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc) if (page->index >= synced_i_size >> PAGE_SHIFT) { err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) - goto out_unlock; + goto out_redirty; /* * The inode has been written, but the write-buffer has * not been synchronized, so in case of an unclean @@ -1060,11 +1060,17 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc) if (i_size > synced_i_size) { err = inode->i_sb->s_op->write_inode(inode, NULL); if (err) - goto out_unlock; + goto out_redirty; } return do_writepage(page, len); - +out_redirty: + /* + * redirty_page_for_writepage() won't call ubifs_dirty_inode() because + * it passes I_DIRTY_PAGES flag while calling __mark_inode_dirty(), so + * there is no need to do space budget for dirty inode. + */ + redirty_page_for_writepage(wbc, page); out_unlock: unlock_page(page); return err; From 66f4742e93523ab2f062d9d9828b3e590bc61536 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Wed, 1 Jun 2022 11:00:00 +0800 Subject: [PATCH 21/36] ubifs: ubifs_releasepage: Remove ubifs_assert(0) to valid this process There are two states for ubifs writing pages: 1. Dirty, Private 2. Not Dirty, Not Private The normal process cannot go to ubifs_releasepage() which means there exists pages being private but not dirty. Reproducer[1] shows that it could occur (which maybe related to [2]) with following process: PA PB PC lock(page)[PA] ubifs_write_end attach_page_private // set Private __set_page_dirty_nobuffers // set Dirty unlock(page) write_cache_pages[PA] lock(page) clear_page_dirty_for_io(page) // clear Dirty ubifs_writepage do_truncation[PB] truncate_setsize i_size_write(inode, newsize) // newsize = 0 i_size = i_size_read(inode) // i_size = 0 end_index = i_size >> PAGE_SHIFT if (page->index > end_index) goto out // jump out: unlock(page) // Private, Not Dirty generic_fadvise[PC] lock(page) invalidate_inode_page try_to_release_page ubifs_releasepage ubifs_assert(c, 0) // bad assertion! unlock(page) truncate_pagecache[PB] Then we may get following assertion failed: UBIFS error (ubi0:0 pid 1683): ubifs_assert_failed [ubifs]: UBIFS assert failed: 0, in fs/ubifs/file.c:1513 UBIFS warning (ubi0:0 pid 1683): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22 CPU: 2 PID: 1683 Comm: aa Not tainted 5.16.0-rc5-00184-g0bca5994cacc-dirty #308 Call Trace: dump_stack+0x13/0x1b ubifs_ro_mode+0x54/0x60 [ubifs] ubifs_assert_failed+0x4b/0x80 [ubifs] ubifs_releasepage+0x67/0x1d0 [ubifs] try_to_release_page+0x57/0xe0 invalidate_inode_page+0xfb/0x130 __invalidate_mapping_pages+0xb9/0x280 invalidate_mapping_pagevec+0x12/0x20 generic_fadvise+0x303/0x3c0 ksys_fadvise64_64+0x4c/0xb0 [1] https://bugzilla.kernel.org/show_bug.cgi?id=215373 [2] https://linux-mtd.infradead.narkive.com/NQoBeT1u/patch-rfc-ubifs-fix-assert-failed-in-ubifs-set-page-dirty Fixes: 1e51764a3c2ac0 ("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/file.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 1f429260a85f..10c1779af9c5 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1472,14 +1472,23 @@ static bool ubifs_release_folio(struct folio *folio, gfp_t unused_gfp_flags) struct inode *inode = folio->mapping->host; struct ubifs_info *c = inode->i_sb->s_fs_info; - /* - * An attempt to release a dirty page without budgeting for it - should - * not happen. - */ if (folio_test_writeback(folio)) return false; + + /* + * Page is private but not dirty, weird? There is one condition + * making it happened. ubifs_writepage skipped the page because + * page index beyonds isize (for example. truncated by other + * process named A), then the page is invalidated by fadvise64 + * syscall before being truncated by process A. + */ ubifs_assert(c, folio_test_private(folio)); - ubifs_assert(c, 0); + if (folio_test_checked(folio)) + release_new_page_budget(c); + else + release_existing_page_budget(c); + + atomic_long_dec(&c->dirty_pg_cnt); folio_detach_private(folio); folio_clear_checked(folio); return true; From 76f9476ece445a07aeb72df9d896cd563fb5b50f Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Tue, 9 Aug 2022 15:06:19 +0800 Subject: [PATCH 22/36] ubi: fastmap: Fix missed fm_anchor PEB in wear-leveling after disabling fastmap After disabling fastmap(ubi->fm_disabled = 1), fastmap won't be updated, fm_anchor PEB is missed being scheduled for erasing. Besides, fm_anchor PEB may have smallest erase count, it doesn't participate wear-leveling. The difference of erase count between fm_anchor PEB and other PEBs will be larger and larger later on. In which situation fastmap can be disabled? Initially, we have an UBI image with fastmap. Then the image will be atttached without module parameter 'fm_autoconvert', ubi turns to full scanning mode in one random attaching process(eg. bad fastmap caused by powercut), ubi fastmap is disabled since then. Fix it by not getting fm_anchor if fastmap is disabled in ubi_refill_pools(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216341 Fixes: 4b68bf9a69d22d ("ubi: Select fastmap anchor PEBs considering ...") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/fastmap-wl.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 0ee452275578..863f571f1adb 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -146,13 +146,15 @@ void ubi_refill_pools(struct ubi_device *ubi) if (ubi->fm_anchor) { wl_tree_add(ubi->fm_anchor, &ubi->free); ubi->free_count++; + ubi->fm_anchor = NULL; } - /* - * All available PEBs are in ubi->free, now is the time to get - * the best anchor PEBs. - */ - ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1); + if (!ubi->fm_disabled) + /* + * All available PEBs are in ubi->free, now is the time to get + * the best anchor PEBs. + */ + ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1); for (;;) { enough = 0; From a240bc5c43130c6aa50831d7caaa02a1d84e1bce Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Sat, 30 Jul 2022 19:28:37 +0800 Subject: [PATCH 23/36] ubi: Fix UAF wear-leveling entry in eraseblk_count_seq_show() Wear-leveling entry could be freed in error path, which may be accessed again in eraseblk_count_seq_show(), for example: __erase_worker eraseblk_count_seq_show wl = ubi->lookuptbl[*block_number] if (wl) wl_entry_destroy ubi->lookuptbl[e->pnum] = NULL kmem_cache_free(ubi_wl_entry_slab, e) erase_count = wl->ec // UAF! Wear-leveling entry updating/accessing in ubi->lookuptbl should be protected by ubi->wl_lock, fix it by adding ubi->wl_lock to serialize wl entry accessing between wl_entry_destroy() and eraseblk_count_seq_show(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216305 Fixes: 7bccd12d27b7e3 ("ubi: Add debugfs file for tracking PEB state") Fixes: 801c135ce73d5d ("UBI: Unsorted Block Images") Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 68eb0f21b3fe..f45df3b77373 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -890,8 +890,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, err = do_sync_erase(ubi, e1, vol_id, lnum, 0); if (err) { - if (e2) + if (e2) { + spin_lock(&ubi->wl_lock); wl_entry_destroy(ubi, e2); + spin_unlock(&ubi->wl_lock); + } goto out_ro; } @@ -1130,14 +1133,18 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk) /* Re-schedule the LEB for erasure */ err1 = schedule_erase(ubi, e, vol_id, lnum, 0, false); if (err1) { + spin_lock(&ubi->wl_lock); wl_entry_destroy(ubi, e); + spin_unlock(&ubi->wl_lock); err = err1; goto out_ro; } return err; } + spin_lock(&ubi->wl_lock); wl_entry_destroy(ubi, e); + spin_unlock(&ubi->wl_lock); if (err != -EIO) /* * If this is not %-EIO, we have no idea what to do. Scheduling From 4d57a7333e26040f2b583983e1970d9d460e56b0 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Mon, 13 Jun 2022 14:59:04 +0800 Subject: [PATCH 24/36] ubi: ubi_wl_put_peb: Fix infinite loop when wear-leveling work failed Following process will trigger an infinite loop in ubi_wl_put_peb(): ubifs_bgt ubi_bgt ubifs_leb_unmap ubi_leb_unmap ubi_eba_unmap_leb ubi_wl_put_peb wear_leveling_worker e1 = rb_entry(rb_first(&ubi->used) e2 = get_peb_for_wl(ubi) ubi_io_read_vid_hdr // return err (flash fault) out_error: ubi->move_from = ubi->move_to = NULL wl_entry_destroy(ubi, e1) ubi->lookuptbl[e->pnum] = NULL retry: e = ubi->lookuptbl[pnum]; // return NULL if (e == ubi->move_from) { // NULL == NULL gets true goto retry; // infinite loop !!! $ top PID USER PR NI VIRT RES SHR S %CPU %MEM COMMAND 7676 root 20 0 0 0 0 R 100.0 0.0 ubifs_bgt0_0 Fix it by: 1) Letting ubi_wl_put_peb() returns directly if wearl leveling entry has been removed from 'ubi->lookuptbl'. 2) Using 'ubi->wl_lock' protecting wl entry deletion to preventing an use-after-free problem for wl entry in ubi_wl_put_peb(). Fetch a reproducer in [Link]. Fixes: 43f9b25a9cdd7b1 ("UBI: bugfix: protect from volume removal") Fixes: ee59ba8b064f692 ("UBI: Fix stale pointers in ubi->lookuptbl") Link: https://bugzilla.kernel.org/show_bug.cgi?id=216111 Signed-off-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/wl.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index f45df3b77373..9e14319225c9 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -976,11 +976,11 @@ out_error: spin_lock(&ubi->wl_lock); ubi->move_from = ubi->move_to = NULL; ubi->move_to_put = ubi->wl_scheduled = 0; + wl_entry_destroy(ubi, e1); + wl_entry_destroy(ubi, e2); spin_unlock(&ubi->wl_lock); ubi_free_vid_buf(vidb); - wl_entry_destroy(ubi, e1); - wl_entry_destroy(ubi, e2); out_ro: ubi_ro_mode(ubi); @@ -1260,6 +1260,18 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum, retry: spin_lock(&ubi->wl_lock); e = ubi->lookuptbl[pnum]; + if (!e) { + /* + * This wl entry has been removed for some errors by other + * process (eg. wear leveling worker), corresponding process + * (except __erase_worker, which cannot concurrent with + * ubi_wl_put_peb) will set ubi ro_mode at the same time, + * just ignore this wl entry. + */ + spin_unlock(&ubi->wl_lock); + up_read(&ubi->fm_protect); + return 0; + } if (e == ubi->move_from) { /* * User is putting the physical eraseblock which was selected to From b5dd034f8f4a8405713842fb0a6f35e5062d95b7 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Tue, 27 Sep 2022 11:57:58 +0800 Subject: [PATCH 25/36] UBI: Fastmap: Fix kernel-doc drivers/mtd/ubi/fastmap.c:104: warning: expecting prototype for new_fm_vhdr(). Prototype was for new_fm_vbuf() instead. Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=2289 Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/fastmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index ca2d9efe62c3..28c8151a0725 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -93,7 +93,7 @@ size_t ubi_calc_fm_size(struct ubi_device *ubi) /** - * new_fm_vhdr - allocate a new volume header for fastmap usage. + * new_fm_vbuf() - allocate a new volume header for fastmap usage. * @ubi: UBI device description object * @vol_id: the VID of the new header * From 415c94532ebb2838dc9e2e5a5e609a6140caa5c5 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 2 Jun 2022 14:55:56 +0800 Subject: [PATCH 26/36] ubifs: Fix some kernel-doc comments Remove warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. fs/ubifs/journal.c:1221: warning: Function parameter or member 'old_inode' not described in 'ubifs_jnl_rename' fs/ubifs/journal.c:1221: warning: Function parameter or member 'old_nm' not described in 'ubifs_jnl_rename' fs/ubifs/journal.c:1221: warning: Function parameter or member 'new_inode' not described in 'ubifs_jnl_rename' fs/ubifs/journal.c:1221: warning: Function parameter or member 'new_nm' not described in 'ubifs_jnl_rename' fs/ubifs/journal.c:1221: warning: Function parameter or member 'whiteout' not described in 'ubifs_jnl_rename' fs/ubifs/journal.c:1221: warning: Excess function parameter 'old_dentry' description in 'ubifs_jnl_rename' fs/ubifs/journal.c:1221: warning: Excess function parameter 'new_dentry' description in 'ubifs_jnl_rename' Reported-by: Abaci Robot Signed-off-by: Yang Li Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/journal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index d02509920baf..dc52ac0f4a34 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -1201,9 +1201,13 @@ out_free: * ubifs_jnl_rename - rename a directory entry. * @c: UBIFS file-system description object * @old_dir: parent inode of directory entry to rename - * @old_dentry: directory entry to rename + * @old_inode: directory entry's inode to rename + * @old_nm: name of the old directory entry to rename * @new_dir: parent inode of directory entry to rename - * @new_dentry: new directory entry (or directory entry to replace) + * @new_inode: new directory entry's inode (or directory entry's inode to + * replace) + * @new_nm: new name of the new directory entry + * @whiteout: whiteout inode * @sync: non-zero if the write-buffer has to be synchronized * * This function implements the re-name operation which may involve writing up From 422125232f6200f0490b7d7fb97722723eb8876d Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 17 Nov 2021 15:03:04 +0800 Subject: [PATCH 27/36] ubifs: Fix kernel-doc Fix function name in fs/ubifs/io.c kernel-doc comment to remove some warnings found by clang(make W=1 LLVM=1). fs/ubifs/io.c:497: warning: expecting prototype for wbuf_timer_callback(). Prototype was for wbuf_timer_callback_nolock() instead fs/ubifs/io.c:513: warning: expecting prototype for new_wbuf_timer(). Prototype was for new_wbuf_timer_nolock() instead fs/ubifs/io.c:538: warning: expecting prototype for cancel_wbuf_timer(). Prototype was for cancel_wbuf_timer_nolock() instead Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: Richard Weinberger --- fs/ubifs/io.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 1607a3c76681..01d8eb170382 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c @@ -488,7 +488,7 @@ void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last) } /** - * wbuf_timer_callback - write-buffer timer callback function. + * wbuf_timer_callback_nolock - write-buffer timer callback function. * @timer: timer data (write-buffer descriptor) * * This function is called when the write-buffer timer expires. @@ -505,7 +505,7 @@ static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer) } /** - * new_wbuf_timer - start new write-buffer timer. + * new_wbuf_timer_nolock - start new write-buffer timer. * @c: UBIFS file-system description object * @wbuf: write-buffer descriptor */ @@ -531,7 +531,7 @@ static void new_wbuf_timer_nolock(struct ubifs_info *c, struct ubifs_wbuf *wbuf) } /** - * cancel_wbuf_timer - cancel write-buffer timer. + * cancel_wbuf_timer_nolock - cancel write-buffer timer. * @wbuf: write-buffer descriptor */ static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) From 7198c9c00338287fe364d76bba35b3b10feec3c5 Mon Sep 17 00:00:00 2001 From: Yu Zhe Date: Fri, 18 Nov 2022 16:51:04 +0800 Subject: [PATCH 28/36] jffs2: fix spelling mistake "neccecary"->"necessary" There is a spelling mistake in comment. Fix it. Signed-off-by: Yu Zhe Signed-off-by: Richard Weinberger --- fs/jffs2/fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 66af51c41619..e952b0bd548b 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -403,7 +403,7 @@ int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc) /* We stop if it was running, then restart if it needs to. This also catches the case where it was stopped and this is just a remount to restart it. - Flush the writebuffer, if neccecary, else we loose it */ + Flush the writebuffer, if necessary, else we loose it */ if (!sb_rdonly(sb)) { jffs2_stop_garbage_collect_thread(c); mutex_lock(&c->alloc_sem); From d5711ae52d5a548d16e5c177c92c15338ec63624 Mon Sep 17 00:00:00 2001 From: Zhang Xiaoxu Date: Thu, 27 Oct 2022 20:49:05 +0800 Subject: [PATCH 29/36] jffs2: Use function instead of macro when initialize compressors The initialized compressors should be released if one of them initialize fail, this is the pre-patch for fix the problem, use function instead of the macro in jffs2_compressors_init() to simplify the codes, no functional change intended. Signed-off-by: Zhang Xiaoxu Signed-off-by: Richard Weinberger --- fs/jffs2/compr.c | 17 +---------------- fs/jffs2/compr.h | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 4849a4c9a0e2..afe74c65f1e4 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -365,19 +365,12 @@ void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) int __init jffs2_compressors_init(void) { /* Registering compressors */ -#ifdef CONFIG_JFFS2_ZLIB jffs2_zlib_init(); -#endif -#ifdef CONFIG_JFFS2_RTIME jffs2_rtime_init(); -#endif -#ifdef CONFIG_JFFS2_RUBIN jffs2_rubinmips_init(); jffs2_dynrubin_init(); -#endif -#ifdef CONFIG_JFFS2_LZO jffs2_lzo_init(); -#endif + /* Setting default compression mode */ #ifdef CONFIG_JFFS2_CMODE_NONE jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; @@ -401,18 +394,10 @@ int __init jffs2_compressors_init(void) int jffs2_compressors_exit(void) { /* Unregistering compressors */ -#ifdef CONFIG_JFFS2_LZO jffs2_lzo_exit(); -#endif -#ifdef CONFIG_JFFS2_RUBIN jffs2_dynrubin_exit(); jffs2_rubinmips_exit(); -#endif -#ifdef CONFIG_JFFS2_RTIME jffs2_rtime_exit(); -#endif -#ifdef CONFIG_JFFS2_ZLIB jffs2_zlib_exit(); -#endif return 0; } diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 5e91d578f4ed..3716b6b7924c 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -88,18 +88,32 @@ int jffs2_rubinmips_init(void); void jffs2_rubinmips_exit(void); int jffs2_dynrubin_init(void); void jffs2_dynrubin_exit(void); +#else +static inline int jffs2_rubinmips_init(void) { return 0; } +static inline void jffs2_rubinmips_exit(void) {} +static inline int jffs2_dynrubin_init(void) { return 0; } +static inline void jffs2_dynrubin_exit(void) {} #endif #ifdef CONFIG_JFFS2_RTIME -int jffs2_rtime_init(void); -void jffs2_rtime_exit(void); +extern int jffs2_rtime_init(void); +extern void jffs2_rtime_exit(void); +#else +static inline int jffs2_rtime_init(void) { return 0; } +static inline void jffs2_rtime_exit(void) {} #endif #ifdef CONFIG_JFFS2_ZLIB -int jffs2_zlib_init(void); -void jffs2_zlib_exit(void); +extern int jffs2_zlib_init(void); +extern void jffs2_zlib_exit(void); +#else +static inline int jffs2_zlib_init(void) { return 0; } +static inline void jffs2_zlib_exit(void) {} #endif #ifdef CONFIG_JFFS2_LZO -int jffs2_lzo_init(void); -void jffs2_lzo_exit(void); +extern int jffs2_lzo_init(void); +extern void jffs2_lzo_exit(void); +#else +static inline int jffs2_lzo_init(void) { return 0; } +static inline void jffs2_lzo_exit(void) {} #endif #endif /* __JFFS2_COMPR_H__ */ From 3432e57493c278c1cb48abc2d69c6c055a19723e Mon Sep 17 00:00:00 2001 From: Zhang Xiaoxu Date: Thu, 27 Oct 2022 20:49:06 +0800 Subject: [PATCH 30/36] jffs2: Fix list_del corruption if compressors initialized failed There is a list_del corruption when remove the jffs2 module: list_del corruption, ffffffffa0623e60->next is NULL WARNING: CPU: 6 PID: 6332 at lib/list_debug.c:49 __list_del_entry_valid+0x98/0x130 Modules linked in: jffs2(-) ] CPU: 6 PID: 6332 Comm: rmmod Tainted: G W 6.1.0-rc2+ #5 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014 RIP: 0010:__list_del_entry_valid+0x98/0x130 ... Call Trace: jffs2_unregister_compressor+0x3e/0xe0 [jffs2] jffs2_zlib_exit+0x11/0x30 [jffs2] jffs2_compressors_exit+0x1e/0x30 [jffs2] exit_jffs2_fs+0x16/0x44f [jffs2] __do_sys_delete_module.constprop.0+0x244/0x370 do_syscall_64+0x35/0x80 entry_SYSCALL_64_after_hwframe+0x46/0xb0 If one of the compressor initialize failed, the module always insert success since jffs2_compressors_init() always return success, then something bad may happen during remove the module. For this scenario, let's insmod failed. Signed-off-by: Zhang Xiaoxu Signed-off-by: Richard Weinberger --- fs/jffs2/compr.c | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index afe74c65f1e4..764f19dec3f0 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -364,12 +364,24 @@ void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) int __init jffs2_compressors_init(void) { + int ret = 0; /* Registering compressors */ - jffs2_zlib_init(); - jffs2_rtime_init(); - jffs2_rubinmips_init(); - jffs2_dynrubin_init(); - jffs2_lzo_init(); + ret = jffs2_zlib_init(); + if (ret) + goto exit; + ret = jffs2_rtime_init(); + if (ret) + goto exit_zlib; + ret = jffs2_rubinmips_init(); + if (ret) + goto exit_rtime; + ret = jffs2_dynrubin_init(); + if (ret) + goto exit_runinmips; + ret = jffs2_lzo_init(); + if (ret) + goto exit_dynrubin; + /* Setting default compression mode */ #ifdef CONFIG_JFFS2_CMODE_NONE @@ -389,6 +401,17 @@ int __init jffs2_compressors_init(void) #endif #endif return 0; + +exit_dynrubin: + jffs2_dynrubin_exit(); +exit_runinmips: + jffs2_rubinmips_exit(); +exit_rtime: + jffs2_rtime_exit(); +exit_zlib: + jffs2_zlib_exit(); +exit: + return ret; } int jffs2_compressors_exit(void) From 91cc8fbcc8c705310fc6e39899e6e6685531935b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 12 Jan 2023 17:15:40 +0100 Subject: [PATCH 31/36] ubi: block: set BLK_MQ_F_BLOCKING Set BLK_MQ_F_BLOCKING so that the block layer always calls ->queue_rq from process context and drop the driver internal workqueue. Signed-off-by: Christoph Hellwig Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/block.c | 99 ++++++++++++----------------------------- 1 file changed, 29 insertions(+), 70 deletions(-) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index d725215ae66e..f5d036203fe7 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -62,7 +61,6 @@ struct ubiblock_param { }; struct ubiblock_pdu { - struct work_struct work; struct ubi_sgl usgl; }; @@ -82,8 +80,6 @@ struct ubiblock { struct gendisk *gd; struct request_queue *rq; - struct workqueue_struct *wq; - struct mutex dev_mutex; struct list_head list; struct blk_mq_tag_set tag_set; @@ -181,20 +177,29 @@ static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id) return NULL; } -static int ubiblock_read(struct ubiblock_pdu *pdu) +static blk_status_t ubiblock_read(struct request *req) { - int ret, leb, offset, bytes_left, to_read; - u64 pos; - struct request *req = blk_mq_rq_from_pdu(pdu); + struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req); struct ubiblock *dev = req->q->queuedata; - - to_read = blk_rq_bytes(req); - pos = blk_rq_pos(req) << 9; - + u64 pos = blk_rq_pos(req) << 9; + int to_read = blk_rq_bytes(req); + int bytes_left = to_read; /* Get LEB:offset address to read from */ - offset = do_div(pos, dev->leb_size); - leb = pos; - bytes_left = to_read; + int offset = do_div(pos, dev->leb_size); + int leb = pos; + struct req_iterator iter; + struct bio_vec bvec; + int ret; + + blk_mq_start_request(req); + + /* + * It is safe to ignore the return value of blk_rq_map_sg() because + * the number of sg entries is limited to UBI_MAX_SG_COUNT + * and ubi_read_sg() will check that limit. + */ + ubi_sgl_init(&pdu->usgl); + blk_rq_map_sg(req->q, req, pdu->usgl.sg); while (bytes_left) { /* @@ -206,14 +211,17 @@ static int ubiblock_read(struct ubiblock_pdu *pdu) ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read); if (ret < 0) - return ret; + break; bytes_left -= to_read; to_read = bytes_left; leb += 1; offset = 0; } - return 0; + + rq_for_each_segment(bvec, req, iter) + flush_dcache_page(bvec.bv_page); + return errno_to_blk_status(ret); } static int ubiblock_open(struct block_device *bdev, fmode_t mode) @@ -289,47 +297,15 @@ static const struct block_device_operations ubiblock_ops = { .getgeo = ubiblock_getgeo, }; -static void ubiblock_do_work(struct work_struct *work) -{ - int ret; - struct ubiblock_pdu *pdu = container_of(work, struct ubiblock_pdu, work); - struct request *req = blk_mq_rq_from_pdu(pdu); - struct req_iterator iter; - struct bio_vec bvec; - - blk_mq_start_request(req); - - /* - * It is safe to ignore the return value of blk_rq_map_sg() because - * the number of sg entries is limited to UBI_MAX_SG_COUNT - * and ubi_read_sg() will check that limit. - */ - blk_rq_map_sg(req->q, req, pdu->usgl.sg); - - ret = ubiblock_read(pdu); - - rq_for_each_segment(bvec, req, iter) - flush_dcache_page(bvec.bv_page); - - blk_mq_end_request(req, errno_to_blk_status(ret)); -} - static blk_status_t ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd) { - struct request *req = bd->rq; - struct ubiblock *dev = hctx->queue->queuedata; - struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req); - - switch (req_op(req)) { + switch (req_op(bd->rq)) { case REQ_OP_READ: - ubi_sgl_init(&pdu->usgl); - queue_work(dev->wq, &pdu->work); - return BLK_STS_OK; + return ubiblock_read(bd->rq); default: return BLK_STS_IOERR; } - } static int ubiblock_init_request(struct blk_mq_tag_set *set, @@ -339,8 +315,6 @@ static int ubiblock_init_request(struct blk_mq_tag_set *set, struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req); sg_init_table(pdu->usgl.sg, UBI_MAX_SG_COUNT); - INIT_WORK(&pdu->work, ubiblock_do_work); - return 0; } @@ -404,7 +378,7 @@ int ubiblock_create(struct ubi_volume_info *vi) dev->tag_set.ops = &ubiblock_mq_ops; dev->tag_set.queue_depth = 64; dev->tag_set.numa_node = NUMA_NO_NODE; - dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING; dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu); dev->tag_set.driver_data = dev; dev->tag_set.nr_hw_queues = 1; @@ -442,31 +416,18 @@ int ubiblock_create(struct ubi_volume_info *vi) dev->rq = gd->queue; blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT); - /* - * Create one workqueue per volume (per registered block device). - * Remember workqueues are cheap, they're not threads. - */ - dev->wq = alloc_workqueue("%s", 0, 0, gd->disk_name); - if (!dev->wq) { - ret = -ENOMEM; - goto out_remove_minor; - } - list_add_tail(&dev->list, &ubiblock_devices); /* Must be the last step: anyone can call file ops from now on */ ret = add_disk(dev->gd); if (ret) - goto out_destroy_wq; + goto out_remove_minor; dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", dev->ubi_num, dev->vol_id, vi->name); mutex_unlock(&devices_mutex); return 0; -out_destroy_wq: - list_del(&dev->list); - destroy_workqueue(dev->wq); out_remove_minor: idr_remove(&ubiblock_minor_idr, gd->first_minor); out_cleanup_disk: @@ -485,8 +446,6 @@ static void ubiblock_cleanup(struct ubiblock *dev) { /* Stop new requests to arrive */ del_gendisk(dev->gd); - /* Flush pending work */ - destroy_workqueue(dev->wq); /* Finally destroy the blk queue */ dev_info(disk_to_dev(dev->gd), "released"); put_disk(dev->gd); From 0b3bc49c936c1e6f399fcd2028ce24c3de9e7e59 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Jan 2023 22:40:12 -0800 Subject: [PATCH 32/36] ubi: use correct names in function kernel-doc comments Fix kernel-doc warnings by using the correct function names in their kernel-doc notation: drivers/mtd/ubi/eba.c:72: warning: expecting prototype for next_sqnum(). Prototype was for ubi_next_sqnum() instead drivers/mtd/ubi/wl.c:176: warning: expecting prototype for wl_tree_destroy(). Prototype was for wl_entry_destroy() instead drivers/mtd/ubi/misc.c:24: warning: expecting prototype for calc_data_len(). Prototype was for ubi_calc_data_len() instead Signed-off-by: Randy Dunlap Cc: Richard Weinberger Cc: Miquel Raynal Cc: Vignesh Raghavendra Cc: linux-mtd@lists.infradead.org Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/eba.c | 2 +- drivers/mtd/ubi/misc.c | 2 +- drivers/mtd/ubi/wl.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 09c408c45a62..403b79d6efd5 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -61,7 +61,7 @@ struct ubi_eba_table { }; /** - * next_sqnum - get next sequence number. + * ubi_next_sqnum - get next sequence number. * @ubi: UBI device description object * * This function returns next sequence number to use, which is just the current diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index 7b30c8ee3e82..1794d66b6eb7 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -10,7 +10,7 @@ #include "ubi.h" /** - * calc_data_len - calculate how much real data is stored in a buffer. + * ubi_calc_data_len - calculate how much real data is stored in a buffer. * @ubi: UBI device description object * @buf: a buffer with the contents of the physical eraseblock * @length: the buffer length diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 9e14319225c9..40f39e5d6dfc 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -165,7 +165,7 @@ static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root) } /** - * wl_tree_destroy - destroy a wear-leveling entry. + * wl_entry_destroy - destroy a wear-leveling entry. * @ubi: UBI device description object * @e: the wear-leveling entry to add * From 1ecf9e390452e73a362ea7fbde8f3f0db83de856 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 22 Dec 2022 19:33:04 +0000 Subject: [PATCH 33/36] mtd: ubi: wire-up parent MTD device Wire up the device parent pointer of UBI devices to their lower MTD device, typically an MTD partition or whole-chip device. The most noticeable change is that in sysfs, previously ubi devices would be could in /sys/devices/virtual/ubi while after this change they would be correctly attached to their parent MTD device, e.g. /sys/devices/platform/1100d000.spi/spi_master/spi1/spi1.0/mtd/mtd2/ubi0. Locating UBI devices using /sys/class/ubi/ of course still works as well. Signed-off-by: Daniel Golle Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/build.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 5e90a4423b69..0904eb40c95f 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -915,6 +915,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, ubi->dev.release = dev_release; ubi->dev.class = &ubi_class; ubi->dev.groups = ubi_dev_groups; + ubi->dev.parent = &mtd->dev; ubi->mtd = mtd; ubi->ubi_num = ubi_num; From 05b8773ca33253ea562be145cf3145b05ef19f86 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Thu, 22 Dec 2022 19:33:31 +0000 Subject: [PATCH 34/36] mtd: ubi: block: wire-up device parent ubiblock devices were previously only identifyable by their name, but not connected to their parent UBI volume device e.g. in sysfs. Properly parent ubiblock device as descendant of a UBI volume device to reflect device model hierachy. Signed-off-by: Daniel Golle Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/block.c | 2 +- drivers/mtd/ubi/kapi.c | 1 + include/linux/mtd/ubi.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index f5d036203fe7..6a9eb2c860b5 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -419,7 +419,7 @@ int ubiblock_create(struct ubi_volume_info *vi) list_add_tail(&dev->list, &ubiblock_devices); /* Must be the last step: anyone can call file ops from now on */ - ret = add_disk(dev->gd); + ret = device_add_disk(vi->dev, dev->gd, NULL); if (ret) goto out_remove_minor; diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 0fce99ff29b5..5db653eacbd4 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -79,6 +79,7 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol, vi->name_len = vol->name_len; vi->name = vol->name; vi->cdev = vol->cdev.dev; + vi->dev = &vol->dev; } /** diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h index 7d48ea368c5e..a529347fd75b 100644 --- a/include/linux/mtd/ubi.h +++ b/include/linux/mtd/ubi.h @@ -110,6 +110,7 @@ struct ubi_volume_info { int name_len; const char *name; dev_t cdev; + struct device *dev; }; /** From 22d74bc26bbfde150f602b2a6e93fb11df30ce0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 10 Feb 2023 02:16:13 +0000 Subject: [PATCH 35/36] ubifs: make kobj_type structures constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ee6d3dd4ed48 ("driver core: make kobj_type constant.") the driver core allows the usage of const struct kobj_type. Take advantage of this to constify the structure definitions to prevent modification at runtime. Signed-off-by: Thomas Weißschuh Reviewed-by: Zhihao Cheng Signed-off-by: Richard Weinberger --- fs/ubifs/sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ubifs/sysfs.c b/fs/ubifs/sysfs.c index 54270ad36321..1c958148bb87 100644 --- a/fs/ubifs/sysfs.c +++ b/fs/ubifs/sysfs.c @@ -74,13 +74,13 @@ static const struct sysfs_ops ubifs_attr_ops = { .show = ubifs_attr_show, }; -static struct kobj_type ubifs_sb_ktype = { +static const struct kobj_type ubifs_sb_ktype = { .default_groups = ubifs_groups, .sysfs_ops = &ubifs_attr_ops, .release = ubifs_sb_release, }; -static struct kobj_type ubifs_ktype = { +static const struct kobj_type ubifs_ktype = { .sysfs_ops = &ubifs_attr_ops, }; From 8fcf2d012c8641c18adcd139dba6a1e556338d36 Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Tue, 14 Feb 2023 01:38:01 -0800 Subject: [PATCH 36/36] ubi: block: Fix a possible use-after-free bug in ubiblock_create() Smatch warns: drivers/mtd/ubi/block.c:438 ubiblock_create() warn: '&dev->list' not removed from list 'dev' is freed in 'out_free_dev:, but it is still on the list. To fix this, delete the list item before freeing. Fixes: 91cc8fbcc8c7 ("ubi: block: set BLK_MQ_F_BLOCKING") Signed-off-by: Harshit Mogalapalli Reviewed-by: Christoph Hellwig Signed-off-by: Richard Weinberger --- drivers/mtd/ubi/block.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 6a9eb2c860b5..1de87062c67b 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -429,6 +429,7 @@ int ubiblock_create(struct ubi_volume_info *vi) return 0; out_remove_minor: + list_del(&dev->list); idr_remove(&ubiblock_minor_idr, gd->first_minor); out_cleanup_disk: put_disk(dev->gd);