Commit 5672cdfb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs

Pull JFFS2, UBI and UBIFS updates from Richard Weinberger:
 "JFFS2:
   - Fix for a deadlock in jffs2_write_begin()

  UBI:
   - Fixes in comments

  UBIFS:
   - Expose error counters in sysfs
   - Many bugfixes found by Hulk Robot and others"

* tag 'for-linus-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs:
  jffs2: GC deadlock reading a page that is used in jffs2_write_begin()
  ubifs: read-only if LEB may always be taken in ubifs_garbage_collect
  ubifs: fix double return leb in ubifs_garbage_collect
  ubifs: fix slab-out-of-bounds in ubifs_change_lp
  ubifs: fix snprintf() length check
  ubifs: Document sysfs nodes
  ubifs: Export filesystem error counters
  ubifs: Error path in ubifs_remount_rw() seems to wrongly free write buffers
  ubifs: Make use of the helper macro kthread_run()
  ubi: Fix a mistake in comment
  ubifs: Fix spelling mistakes
parents 3f67eaed aa39cc67
What: /sys/fs/ubifsX_Y/error_magic
Date: October 2021
KernelVersion: 5.16
Contact: linux-mtd@lists.infradead.org
Description:
Exposes magic errors: every node starts with a magic number.
This counter keeps track of the number of accesses of nodes
with a corrupted magic number.
The counter is reset to 0 with a remount.
What: /sys/fs/ubifsX_Y/error_node
Date: October 2021
KernelVersion: 5.16
Contact: linux-mtd@lists.infradead.org
Description:
Exposes node errors. Every node embeds its type.
This counter keeps track of the number of accesses of nodes
with a corrupted node type.
The counter is reset to 0 with a remount.
What: /sys/fs/ubifsX_Y/error_crc
Date: October 2021
KernelVersion: 5.16
Contact: linux-mtd@lists.infradead.org
Description:
Exposes crc errors: every node embeds a crc checksum.
This counter keeps track of the number of accesses of nodes
with a bad crc checksum.
The counter is reset to 0 with a remount.
...@@ -19603,6 +19603,7 @@ S: Supported ...@@ -19603,6 +19603,7 @@ S: Supported
W: http://www.linux-mtd.infradead.org/doc/ubifs.html W: http://www.linux-mtd.infradead.org/doc/ubifs.html
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git next T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git next
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git fixes T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git fixes
F: Documentation/ABI/testing/sysfs-fs-ubifs
F: Documentation/filesystems/ubifs-authentication.rst F: Documentation/filesystems/ubifs-authentication.rst
F: Documentation/filesystems/ubifs.rst F: Documentation/filesystems/ubifs.rst
F: fs/ubifs/ F: fs/ubifs/
......
...@@ -562,7 +562,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi) ...@@ -562,7 +562,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
} }
/** /**
* dbg_debug_exit_dev - free all debugfs files corresponding to device @ubi * ubi_debugfs_exit_dev - free all debugfs files corresponding to device @ubi
* @ubi: UBI device description object * @ubi: UBI device description object
*/ */
void ubi_debugfs_exit_dev(struct ubi_device *ubi) void ubi_debugfs_exit_dev(struct ubi_device *ubi)
......
...@@ -136,20 +136,15 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, ...@@ -136,20 +136,15 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
struct page *pg; struct page *pg;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 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; pgoff_t index = pos >> PAGE_SHIFT;
uint32_t pageofs = index << PAGE_SHIFT; uint32_t pageofs = index << PAGE_SHIFT;
int ret = 0; int ret = 0;
pg = grab_cache_page_write_begin(mapping, index, flags);
if (!pg)
return -ENOMEM;
*pagep = pg;
jffs2_dbg(1, "%s()\n", __func__); jffs2_dbg(1, "%s()\n", __func__);
if (pageofs > inode->i_size) { if (pageofs > inode->i_size) {
/* Make new hole frag from old EOF to new page */ /* Make new hole frag from old EOF to new page */
struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
struct jffs2_raw_inode ri; struct jffs2_raw_inode ri;
struct jffs2_full_dnode *fn; struct jffs2_full_dnode *fn;
uint32_t alloc_len; uint32_t alloc_len;
...@@ -160,7 +155,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, ...@@ -160,7 +155,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
if (ret) if (ret)
goto out_page; goto out_err;
mutex_lock(&f->sem); mutex_lock(&f->sem);
memset(&ri, 0, sizeof(ri)); memset(&ri, 0, sizeof(ri));
...@@ -190,7 +185,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, ...@@ -190,7 +185,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
ret = PTR_ERR(fn); ret = PTR_ERR(fn);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
mutex_unlock(&f->sem); mutex_unlock(&f->sem);
goto out_page; goto out_err;
} }
ret = jffs2_add_full_dnode_to_inode(c, f, fn); ret = jffs2_add_full_dnode_to_inode(c, f, fn);
if (f->metadata) { if (f->metadata) {
...@@ -205,13 +200,26 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, ...@@ -205,13 +200,26 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
jffs2_free_full_dnode(fn); jffs2_free_full_dnode(fn);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
mutex_unlock(&f->sem); mutex_unlock(&f->sem);
goto out_page; goto out_err;
} }
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
inode->i_size = pageofs; inode->i_size = pageofs;
mutex_unlock(&f->sem); mutex_unlock(&f->sem);
} }
/*
* While getting a page and reading data in, lock c->alloc_sem until
* the page is Uptodate. Otherwise GC task may attempt to read the same
* page in read_cache_page(), which causes a deadlock.
*/
mutex_lock(&c->alloc_sem);
pg = grab_cache_page_write_begin(mapping, index, flags);
if (!pg) {
ret = -ENOMEM;
goto release_sem;
}
*pagep = pg;
/* /*
* Read in the page if it wasn't already present. Cannot optimize away * Read in the page if it wasn't already present. Cannot optimize away
* the whole page write case until jffs2_write_end can handle the * the whole page write case until jffs2_write_end can handle the
...@@ -221,15 +229,17 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, ...@@ -221,15 +229,17 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
mutex_lock(&f->sem); mutex_lock(&f->sem);
ret = jffs2_do_readpage_nolock(inode, pg); ret = jffs2_do_readpage_nolock(inode, pg);
mutex_unlock(&f->sem); mutex_unlock(&f->sem);
if (ret) if (ret) {
goto out_page; unlock_page(pg);
put_page(pg);
goto release_sem;
}
} }
jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags);
return ret;
out_page: release_sem:
unlock_page(pg); mutex_unlock(&c->alloc_sem);
put_page(pg); out_err:
return ret; return ret;
} }
......
...@@ -5,7 +5,7 @@ ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o ...@@ -5,7 +5,7 @@ ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o
ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o debug.o ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o debug.o
ubifs-y += misc.o ubifs-y += misc.o sysfs.o
ubifs-$(CONFIG_FS_ENCRYPTION) += crypto.o ubifs-$(CONFIG_FS_ENCRYPTION) += crypto.o
ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o
ubifs-$(CONFIG_UBIFS_FS_AUTHENTICATION) += auth.o ubifs-$(CONFIG_UBIFS_FS_AUTHENTICATION) += auth.o
...@@ -1207,7 +1207,7 @@ static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -1207,7 +1207,7 @@ static int ubifs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
* @inode1: first inode * @inode1: first inode
* @inode2: second inode * @inode2: second inode
* @inode3: third inode * @inode3: third inode
* @inode4: fouth inode * @inode4: fourth inode
* *
* This function is used for 'ubifs_rename()' and @inode1 may be the same as * This function is used for 'ubifs_rename()' and @inode1 may be the same as
* @inode2 whereas @inode3 and @inode4 may be %NULL. * @inode2 whereas @inode3 and @inode4 may be %NULL.
...@@ -1233,7 +1233,7 @@ static void lock_4_inodes(struct inode *inode1, struct inode *inode2, ...@@ -1233,7 +1233,7 @@ static void lock_4_inodes(struct inode *inode1, struct inode *inode2,
* @inode1: first inode * @inode1: first inode
* @inode2: second inode * @inode2: second inode
* @inode3: third inode * @inode3: third inode
* @inode4: fouth inode * @inode4: fourth inode
*/ */
static void unlock_4_inodes(struct inode *inode1, struct inode *inode2, static void unlock_4_inodes(struct inode *inode1, struct inode *inode2,
struct inode *inode3, struct inode *inode4) struct inode *inode3, struct inode *inode4)
......
...@@ -692,6 +692,9 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway) ...@@ -692,6 +692,9 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
for (i = 0; ; i++) { for (i = 0; ; i++) {
int space_before, space_after; int space_before, space_after;
/* Maybe continue after find and break before find */
lp.lnum = -1;
cond_resched(); cond_resched();
/* Give the commit an opportunity to run */ /* Give the commit an opportunity to run */
...@@ -753,8 +756,19 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway) ...@@ -753,8 +756,19 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
* caller instead of the original '-EAGAIN'. * caller instead of the original '-EAGAIN'.
*/ */
err = ubifs_return_leb(c, lp.lnum); err = ubifs_return_leb(c, lp.lnum);
if (err) if (err) {
ret = err; ret = err;
/*
* An LEB may always be "taken",
* so setting ubifs to read-only,
* and then executing sync wbuf will
* return -EROFS and enter the "out"
* error branch.
*/
ubifs_ro_mode(c, ret);
}
/* Maybe double return LEB if goto out */
lp.lnum = -1;
break; break;
} }
goto out; goto out;
...@@ -843,6 +857,7 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway) ...@@ -843,6 +857,7 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
ubifs_wbuf_sync_nolock(wbuf); ubifs_wbuf_sync_nolock(wbuf);
ubifs_ro_mode(c, ret); ubifs_ro_mode(c, ret);
mutex_unlock(&wbuf->io_mutex); mutex_unlock(&wbuf->io_mutex);
if (lp.lnum != -1)
ubifs_return_leb(c, lp.lnum); ubifs_return_leb(c, lp.lnum);
return ret; return ret;
} }
......
...@@ -194,6 +194,24 @@ int ubifs_is_mapped(const struct ubifs_info *c, int lnum) ...@@ -194,6 +194,24 @@ int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
return err; return err;
} }
static void record_magic_error(struct ubifs_stats_info *stats)
{
if (stats)
stats->magic_errors++;
}
static void record_node_error(struct ubifs_stats_info *stats)
{
if (stats)
stats->node_errors++;
}
static void record_crc_error(struct ubifs_stats_info *stats)
{
if (stats)
stats->crc_errors++;
}
/** /**
* ubifs_check_node - check node. * ubifs_check_node - check node.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -238,6 +256,7 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len, ...@@ -238,6 +256,7 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len,
if (!quiet) if (!quiet)
ubifs_err(c, "bad magic %#08x, expected %#08x", ubifs_err(c, "bad magic %#08x, expected %#08x",
magic, UBIFS_NODE_MAGIC); magic, UBIFS_NODE_MAGIC);
record_magic_error(c->stats);
err = -EUCLEAN; err = -EUCLEAN;
goto out; goto out;
} }
...@@ -246,6 +265,7 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len, ...@@ -246,6 +265,7 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len,
if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) { if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) {
if (!quiet) if (!quiet)
ubifs_err(c, "bad node type %d", type); ubifs_err(c, "bad node type %d", type);
record_node_error(c->stats);
goto out; goto out;
} }
...@@ -270,6 +290,7 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len, ...@@ -270,6 +290,7 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int len,
if (!quiet) if (!quiet)
ubifs_err(c, "bad CRC: calculated %#08x, read %#08x", ubifs_err(c, "bad CRC: calculated %#08x, read %#08x",
crc, node_crc); crc, node_crc);
record_crc_error(c->stats);
err = -EUCLEAN; err = -EUCLEAN;
goto out; goto out;
} }
......
...@@ -106,7 +106,7 @@ static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b) ...@@ -106,7 +106,7 @@ static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
* property values should be @lp->free == @c->leb_size and * property values should be @lp->free == @c->leb_size and
* @lp->dirty == 0, but that is not the case. The reason is that * @lp->dirty == 0, but that is not the case. The reason is that
* the LEB had been garbage collected before it became the bud, * the LEB had been garbage collected before it became the bud,
* and there was not commit inbetween. The garbage collector * and there was no commit in between. The garbage collector
* resets the free and dirty space without recording it * resets the free and dirty space without recording it
* anywhere except lprops, so if there was no commit then * anywhere except lprops, so if there was no commit then
* lprops does not have that information. * lprops does not have that information.
......
...@@ -1264,6 +1264,10 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1264,6 +1264,10 @@ static int mount_ubifs(struct ubifs_info *c)
if (err) if (err)
return err; return err;
err = ubifs_sysfs_register(c);
if (err)
goto out_debugging;
err = check_volume_empty(c); err = check_volume_empty(c);
if (err) if (err)
goto out_free; goto out_free;
...@@ -1367,7 +1371,7 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1367,7 +1371,7 @@ static int mount_ubifs(struct ubifs_info *c)
sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
if (!c->ro_mount) { if (!c->ro_mount) {
/* Create background thread */ /* Create background thread */
c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); c->bgt = kthread_run(ubifs_bg_thread, c, "%s", c->bgt_name);
if (IS_ERR(c->bgt)) { if (IS_ERR(c->bgt)) {
err = PTR_ERR(c->bgt); err = PTR_ERR(c->bgt);
c->bgt = NULL; c->bgt = NULL;
...@@ -1375,7 +1379,6 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1375,7 +1379,6 @@ static int mount_ubifs(struct ubifs_info *c)
c->bgt_name, err); c->bgt_name, err);
goto out_wbufs; goto out_wbufs;
} }
wake_up_process(c->bgt);
} }
err = ubifs_read_master(c); err = ubifs_read_master(c);
...@@ -1641,6 +1644,8 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1641,6 +1644,8 @@ static int mount_ubifs(struct ubifs_info *c)
vfree(c->sbuf); vfree(c->sbuf);
kfree(c->bottom_up_buf); kfree(c->bottom_up_buf);
kfree(c->sup_node); kfree(c->sup_node);
ubifs_sysfs_unregister(c);
out_debugging:
ubifs_debugging_exit(c); ubifs_debugging_exit(c);
return err; return err;
} }
...@@ -1684,6 +1689,7 @@ static void ubifs_umount(struct ubifs_info *c) ...@@ -1684,6 +1689,7 @@ static void ubifs_umount(struct ubifs_info *c)
kfree(c->bottom_up_buf); kfree(c->bottom_up_buf);
kfree(c->sup_node); kfree(c->sup_node);
ubifs_debugging_exit(c); ubifs_debugging_exit(c);
ubifs_sysfs_unregister(c);
} }
/** /**
...@@ -1780,7 +1786,7 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1780,7 +1786,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
goto out; goto out;
/* Create background thread */ /* Create background thread */
c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); c->bgt = kthread_run(ubifs_bg_thread, c, "%s", c->bgt_name);
if (IS_ERR(c->bgt)) { if (IS_ERR(c->bgt)) {
err = PTR_ERR(c->bgt); err = PTR_ERR(c->bgt);
c->bgt = NULL; c->bgt = NULL;
...@@ -1788,7 +1794,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1788,7 +1794,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
c->bgt_name, err); c->bgt_name, err);
goto out; goto out;
} }
wake_up_process(c->bgt);
c->orph_buf = vmalloc(c->leb_size); c->orph_buf = vmalloc(c->leb_size);
if (!c->orph_buf) { if (!c->orph_buf) {
...@@ -1853,7 +1858,6 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1853,7 +1858,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
kthread_stop(c->bgt); kthread_stop(c->bgt);
c->bgt = NULL; c->bgt = NULL;
} }
free_wbufs(c);
kfree(c->write_reserve_buf); kfree(c->write_reserve_buf);
c->write_reserve_buf = NULL; c->write_reserve_buf = NULL;
vfree(c->ileb_buf); vfree(c->ileb_buf);
...@@ -2436,14 +2440,20 @@ static int __init ubifs_init(void) ...@@ -2436,14 +2440,20 @@ static int __init ubifs_init(void)
dbg_debugfs_init(); dbg_debugfs_init();
err = ubifs_sysfs_init();
if (err)
goto out_dbg;
err = register_filesystem(&ubifs_fs_type); err = register_filesystem(&ubifs_fs_type);
if (err) { if (err) {
pr_err("UBIFS error (pid %d): cannot register file system, error %d", pr_err("UBIFS error (pid %d): cannot register file system, error %d",
current->pid, err); current->pid, err);
goto out_dbg; goto out_sysfs;
} }
return 0; return 0;
out_sysfs:
ubifs_sysfs_exit();
out_dbg: out_dbg:
dbg_debugfs_exit(); dbg_debugfs_exit();
ubifs_compressors_exit(); ubifs_compressors_exit();
...@@ -2462,6 +2472,7 @@ static void __exit ubifs_exit(void) ...@@ -2462,6 +2472,7 @@ static void __exit ubifs_exit(void)
WARN_ON(atomic_long_read(&ubifs_clean_zn_cnt) != 0); WARN_ON(atomic_long_read(&ubifs_clean_zn_cnt) != 0);
dbg_debugfs_exit(); dbg_debugfs_exit();
ubifs_sysfs_exit();
ubifs_compressors_exit(); ubifs_compressors_exit();
unregister_shrinker(&ubifs_shrinker_info); unregister_shrinker(&ubifs_shrinker_info);
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* This file is part of UBIFS.
*
* Copyright (C) 2021 Cisco Systems
*
* Author: Stefan Schaeckeler
*/
#include <linux/fs.h>
#include "ubifs.h"
enum attr_id_t {
attr_errors_magic,
attr_errors_node,
attr_errors_crc,
};
struct ubifs_attr {
struct attribute attr;
enum attr_id_t attr_id;
};
#define UBIFS_ATTR(_name, _mode, _id) \
static struct ubifs_attr ubifs_attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.attr_id = attr_##_id, \
}
#define UBIFS_ATTR_FUNC(_name, _mode) UBIFS_ATTR(_name, _mode, _name)
UBIFS_ATTR_FUNC(errors_magic, 0444);
UBIFS_ATTR_FUNC(errors_crc, 0444);
UBIFS_ATTR_FUNC(errors_node, 0444);
#define ATTR_LIST(name) (&ubifs_attr_##name.attr)
static struct attribute *ubifs_attrs[] = {
ATTR_LIST(errors_magic),
ATTR_LIST(errors_node),
ATTR_LIST(errors_crc),
NULL,
};
static ssize_t ubifs_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct ubifs_info *sbi = container_of(kobj, struct ubifs_info,
kobj);
struct ubifs_attr *a = container_of(attr, struct ubifs_attr, attr);
switch (a->attr_id) {
case attr_errors_magic:
return sysfs_emit(buf, "%u\n", sbi->stats->magic_errors);
case attr_errors_node:
return sysfs_emit(buf, "%u\n", sbi->stats->node_errors);
case attr_errors_crc:
return sysfs_emit(buf, "%u\n", sbi->stats->crc_errors);
}
return 0;
};
static void ubifs_sb_release(struct kobject *kobj)
{
struct ubifs_info *c = container_of(kobj, struct ubifs_info, kobj);
complete(&c->kobj_unregister);
}
static const struct sysfs_ops ubifs_attr_ops = {
.show = ubifs_attr_show,
};
static struct kobj_type ubifs_sb_ktype = {
.default_attrs = ubifs_attrs,
.sysfs_ops = &ubifs_attr_ops,
.release = ubifs_sb_release,
};
static struct kobj_type ubifs_ktype = {
.sysfs_ops = &ubifs_attr_ops,
};
static struct kset ubifs_kset = {
.kobj = {.ktype = &ubifs_ktype},
};
int ubifs_sysfs_register(struct ubifs_info *c)
{
int ret, n;
char dfs_dir_name[UBIFS_DFS_DIR_LEN+1];
c->stats = kzalloc(sizeof(struct ubifs_stats_info), GFP_KERNEL);
if (!c->stats) {
ret = -ENOMEM;
goto out_last;
}
n = snprintf(dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
c->vi.ubi_num, c->vi.vol_id);
if (n > UBIFS_DFS_DIR_LEN) {
/* The array size is too small */
ret = -EINVAL;
goto out_free;
}
c->kobj.kset = &ubifs_kset;
init_completion(&c->kobj_unregister);
ret = kobject_init_and_add(&c->kobj, &ubifs_sb_ktype, NULL,
"%s", dfs_dir_name);
if (ret)
goto out_put;
return 0;
out_put:
kobject_put(&c->kobj);
wait_for_completion(&c->kobj_unregister);
out_free:
kfree(c->stats);
out_last:
ubifs_err(c, "cannot create sysfs entry for ubifs%d_%d, error %d\n",
c->vi.ubi_num, c->vi.vol_id, ret);
return ret;
}
void ubifs_sysfs_unregister(struct ubifs_info *c)
{
kobject_del(&c->kobj);
kobject_put(&c->kobj);
wait_for_completion(&c->kobj_unregister);
kfree(c->stats);
}
int __init ubifs_sysfs_init(void)
{
int ret;
kobject_set_name(&ubifs_kset.kobj, "ubifs");
ubifs_kset.kobj.parent = fs_kobj;
ret = kset_register(&ubifs_kset);
return ret;
}
void ubifs_sysfs_exit(void)
{
kset_unregister(&ubifs_kset);
}
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include <linux/security.h> #include <linux/security.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/sysfs.h>
#include <linux/completion.h>
#include <crypto/hash_info.h> #include <crypto/hash_info.h>
#include <crypto/hash.h> #include <crypto/hash.h>
#include <crypto/algapi.h> #include <crypto/algapi.h>
...@@ -155,6 +157,13 @@ ...@@ -155,6 +157,13 @@
#define UBIFS_HMAC_ARR_SZ 0 #define UBIFS_HMAC_ARR_SZ 0
#endif #endif
/*
* The UBIFS sysfs directory name pattern and maximum name length (3 for "ubi"
* + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
*/
#define UBIFS_DFS_DIR_NAME "ubi%d_%d"
#define UBIFS_DFS_DIR_LEN (3 + 1 + 2*2 + 1)
/* /*
* Lockdep classes for UBIFS inode @ui_mutex. * Lockdep classes for UBIFS inode @ui_mutex.
*/ */
...@@ -990,6 +999,18 @@ struct ubifs_budg_info { ...@@ -990,6 +999,18 @@ struct ubifs_budg_info {
int dent_budget; int dent_budget;
}; };
/**
* ubifs_stats_info - per-FS statistics information.
* @magic_errors: number of bad magic numbers (will be reset with a new mount).
* @node_errors: number of bad nodes (will be reset with a new mount).
* @crc_errors: number of bad crcs (will be reset with a new mount).
*/
struct ubifs_stats_info {
unsigned int magic_errors;
unsigned int node_errors;
unsigned int crc_errors;
};
struct ubifs_debug_info; struct ubifs_debug_info;
/** /**
...@@ -1251,6 +1272,10 @@ struct ubifs_debug_info; ...@@ -1251,6 +1272,10 @@ struct ubifs_debug_info;
* @mount_opts: UBIFS-specific mount options * @mount_opts: UBIFS-specific mount options
* *
* @dbg: debugging-related information * @dbg: debugging-related information
* @stats: statistics exported over sysfs
*
* @kobj: kobject for /sys/fs/ubifs/
* @kobj_unregister: completion to unregister sysfs kobject
*/ */
struct ubifs_info { struct ubifs_info {
struct super_block *vfs_sb; struct super_block *vfs_sb;
...@@ -1286,6 +1311,9 @@ struct ubifs_info { ...@@ -1286,6 +1311,9 @@ struct ubifs_info {
spinlock_t cs_lock; spinlock_t cs_lock;
wait_queue_head_t cmt_wq; wait_queue_head_t cmt_wq;
struct kobject kobj;
struct completion kobj_unregister;
unsigned int big_lpt:1; unsigned int big_lpt:1;
unsigned int space_fixup:1; unsigned int space_fixup:1;
unsigned int double_hash:1; unsigned int double_hash:1;
...@@ -1493,6 +1521,7 @@ struct ubifs_info { ...@@ -1493,6 +1521,7 @@ struct ubifs_info {
struct ubifs_mount_opts mount_opts; struct ubifs_mount_opts mount_opts;
struct ubifs_debug_info *dbg; struct ubifs_debug_info *dbg;
struct ubifs_stats_info *stats;
}; };
extern struct list_head ubifs_infos; extern struct list_head ubifs_infos;
...@@ -2072,6 +2101,12 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf, int in_len, ...@@ -2072,6 +2101,12 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf, int in_len,
int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len, int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
void *out, int *out_len, int compr_type); void *out, int *out_len, int compr_type);
/* sysfs.c */
int ubifs_sysfs_init(void);
void ubifs_sysfs_exit(void);
int ubifs_sysfs_register(struct ubifs_info *c);
void ubifs_sysfs_unregister(struct ubifs_info *c);
#include "debug.h" #include "debug.h"
#include "misc.h" #include "misc.h"
#include "key.h" #include "key.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment