Merge tag 'for-linus-3.5-20120601' of git://git.infradead.org/linux-mtd
Pull mtd update from David Woodhouse: - More robust parsing especially of xattr data in JFFS2 - Updates to mxc_nand and gpmi drivers to support new boards and device tree - Improve consistency of information about ECC strength in NAND devices - Clean up partition handling of plat_nand - Support NAND drivers without dedicated access to OOB area - BCH hardware ECC support for OMAP - Other fixes and cleanups, and a few new device IDs Fixed trivial conflict in drivers/mtd/nand/gpmi-nand/gpmi-nand.c due to added include files next to each other. * tag 'for-linus-3.5-20120601' of git://git.infradead.org/linux-mtd: (75 commits) mtd: mxc_nand: move ecc strengh setup before nand_scan_tail mtd: block2mtd: fix recursive call of mtd_writev mtd: gpmi-nand: define ecc.strength mtd: of_parts: fix breakage in Kconfig mtd: nand: fix scan_read_raw_oob mtd: docg3 fix in-middle of blocks reads mtd: cfi_cmdset_0002: Slight cleanup of fixup messages mtd: add fixup for S29NS512P NOR flash. jffs2: allow to complete xattr integrity check on first GC scan jffs2: allow to discriminate between recoverable and non-recoverable errors mtd: nand: omap: add support for hardware BCH ecc ARM: OMAP3: gpmc: add BCH ecc api and modes mtd: nand: check the return code of 'read_oob/read_oob_raw' mtd: nand: remove 'sndcmd' parameter of 'read_oob/read_oob_raw' mtd: m25p80: Add support for Winbond W25Q80BW jffs2: get rid of jffs2_sync_super jffs2: remove unnecessary GC pass on sync jffs2: remove unnecessary GC pass on umount jffs2: remove lock_super mtd: gpmi: add gpmi support for mx6q ...
Esse commit está contido em:
@@ -32,6 +32,13 @@ struct jffs2_inodirty;
|
||||
struct jffs2_mount_opts {
|
||||
bool override_compr;
|
||||
unsigned int compr;
|
||||
|
||||
/* The size of the reserved pool. The reserved pool is the JFFS2 flash
|
||||
* space which may only be used by root cannot be used by the other
|
||||
* users. This is implemented simply by means of not allowing the
|
||||
* latter users to write to the file system if the amount if the
|
||||
* available space is less then 'rp_size'. */
|
||||
unsigned int rp_size;
|
||||
};
|
||||
|
||||
/* A struct for the overall file system control. Pointers to
|
||||
|
@@ -18,6 +18,37 @@
|
||||
#include "nodelist.h"
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
* Check whether the user is allowed to write.
|
||||
*/
|
||||
static int jffs2_rp_can_write(struct jffs2_sb_info *c)
|
||||
{
|
||||
uint32_t avail;
|
||||
struct jffs2_mount_opts *opts = &c->mount_opts;
|
||||
|
||||
avail = c->dirty_size + c->free_size + c->unchecked_size +
|
||||
c->erasing_size - c->resv_blocks_write * c->sector_size
|
||||
- c->nospc_dirty_size;
|
||||
|
||||
if (avail < 2 * opts->rp_size)
|
||||
jffs2_dbg(1, "rpsize %u, dirty_size %u, free_size %u, "
|
||||
"erasing_size %u, unchecked_size %u, "
|
||||
"nr_erasing_blocks %u, avail %u, resrv %u\n",
|
||||
opts->rp_size, c->dirty_size, c->free_size,
|
||||
c->erasing_size, c->unchecked_size,
|
||||
c->nr_erasing_blocks, avail, c->nospc_dirty_size);
|
||||
|
||||
if (avail > opts->rp_size)
|
||||
return 1;
|
||||
|
||||
/* Always allow root */
|
||||
if (capable(CAP_SYS_RESOURCE))
|
||||
return 1;
|
||||
|
||||
jffs2_dbg(1, "forbid writing\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* jffs2_reserve_space - request physical space to write nodes to flash
|
||||
* @c: superblock info
|
||||
@@ -55,6 +86,15 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
/*
|
||||
* Check if the free space is greater then size of the reserved pool.
|
||||
* If not, only allow root to proceed with writing.
|
||||
*/
|
||||
if (prio != ALLOC_DELETION && !jffs2_rp_can_write(c)) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* this needs a little more thought (true <tglx> :)) */
|
||||
while(ret == -EAGAIN) {
|
||||
while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
|
||||
@@ -158,6 +198,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
jffs2_dbg(1, "%s(): ret is %d\n", __func__, ret);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
if (!ret)
|
||||
ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1);
|
||||
|
@@ -1266,19 +1266,25 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
||||
/* Symlink's inode data is the target path. Read it and
|
||||
* keep in RAM to facilitate quick follow symlink
|
||||
* operation. */
|
||||
f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
|
||||
uint32_t csize = je32_to_cpu(latest_node->csize);
|
||||
if (csize > JFFS2_MAX_NAME_LEN) {
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
f->target = kmalloc(csize + 1, GFP_KERNEL);
|
||||
if (!f->target) {
|
||||
JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize));
|
||||
JFFS2_ERROR("can't allocate %u bytes of memory for the symlink target path cache\n", csize);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node),
|
||||
je32_to_cpu(latest_node->csize), &retlen, (char *)f->target);
|
||||
csize, &retlen, (char *)f->target);
|
||||
|
||||
if (ret || retlen != je32_to_cpu(latest_node->csize)) {
|
||||
if (retlen != je32_to_cpu(latest_node->csize))
|
||||
if (ret || retlen != csize) {
|
||||
if (retlen != csize)
|
||||
ret = -EIO;
|
||||
kfree(f->target);
|
||||
f->target = NULL;
|
||||
@@ -1287,7 +1293,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
f->target[je32_to_cpu(latest_node->csize)] = '\0';
|
||||
f->target[csize] = '\0';
|
||||
dbg_readinode("symlink's target '%s' cached\n", f->target);
|
||||
}
|
||||
|
||||
@@ -1415,6 +1421,7 @@ int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
}
|
||||
jffs2_xattr_do_crccheck_inode(c, ic);
|
||||
kfree (f);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -90,6 +90,8 @@ static int jffs2_show_options(struct seq_file *s, struct dentry *root)
|
||||
|
||||
if (opts->override_compr)
|
||||
seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
|
||||
if (opts->rp_size)
|
||||
seq_printf(s, ",rp_size=%u", opts->rp_size / 1024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -154,15 +156,18 @@ static const struct export_operations jffs2_export_ops = {
|
||||
* JFFS2 mount options.
|
||||
*
|
||||
* Opt_override_compr: override default compressor
|
||||
* Opt_rp_size: size of reserved pool in KiB
|
||||
* Opt_err: just end of array marker
|
||||
*/
|
||||
enum {
|
||||
Opt_override_compr,
|
||||
Opt_rp_size,
|
||||
Opt_err,
|
||||
};
|
||||
|
||||
static const match_table_t tokens = {
|
||||
{Opt_override_compr, "compr=%s"},
|
||||
{Opt_rp_size, "rp_size=%u"},
|
||||
{Opt_err, NULL},
|
||||
};
|
||||
|
||||
@@ -170,6 +175,7 @@ static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
|
||||
{
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
char *p, *name;
|
||||
unsigned int opt;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
@@ -207,6 +213,17 @@ static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
|
||||
kfree(name);
|
||||
c->mount_opts.override_compr = true;
|
||||
break;
|
||||
case Opt_rp_size:
|
||||
if (match_int(&args[0], &opt))
|
||||
return -EINVAL;
|
||||
opt *= 1024;
|
||||
if (opt > c->mtd->size) {
|
||||
pr_warn("Too large reserve pool specified, max "
|
||||
"is %llu KB\n", c->mtd->size / 1024);
|
||||
return -EINVAL;
|
||||
}
|
||||
c->mount_opts.rp_size = opt;
|
||||
break;
|
||||
default:
|
||||
pr_err("Error: unrecognized mount option '%s' or missing value\n",
|
||||
p);
|
||||
|
@@ -11,6 +11,8 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#define JFFS2_XATTR_IS_CORRUPTED 1
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fs.h>
|
||||
@@ -153,7 +155,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
|
||||
JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
|
||||
offset, je32_to_cpu(rx.hdr_crc), crc);
|
||||
xd->flags |= JFFS2_XFLAGS_INVALID;
|
||||
return -EIO;
|
||||
return JFFS2_XATTR_IS_CORRUPTED;
|
||||
}
|
||||
totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
|
||||
if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
|
||||
@@ -169,7 +171,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
|
||||
je32_to_cpu(rx.xid), xd->xid,
|
||||
je32_to_cpu(rx.version), xd->version);
|
||||
xd->flags |= JFFS2_XFLAGS_INVALID;
|
||||
return -EIO;
|
||||
return JFFS2_XATTR_IS_CORRUPTED;
|
||||
}
|
||||
xd->xprefix = rx.xprefix;
|
||||
xd->name_len = rx.name_len;
|
||||
@@ -227,12 +229,12 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum
|
||||
data[xd->name_len] = '\0';
|
||||
crc = crc32(0, data, length);
|
||||
if (crc != xd->data_crc) {
|
||||
JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XREF)"
|
||||
JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XATTR)"
|
||||
" at %#08x, read: 0x%08x calculated: 0x%08x\n",
|
||||
ref_offset(xd->node), xd->data_crc, crc);
|
||||
kfree(data);
|
||||
xd->flags |= JFFS2_XFLAGS_INVALID;
|
||||
return -EIO;
|
||||
return JFFS2_XATTR_IS_CORRUPTED;
|
||||
}
|
||||
|
||||
xd->flags |= JFFS2_XFLAGS_HOT;
|
||||
@@ -270,7 +272,7 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
|
||||
if (xd->xname)
|
||||
return 0;
|
||||
if (xd->flags & JFFS2_XFLAGS_INVALID)
|
||||
return -EIO;
|
||||
return JFFS2_XATTR_IS_CORRUPTED;
|
||||
if (unlikely(is_xattr_datum_unchecked(c, xd)))
|
||||
rc = do_verify_xattr_datum(c, xd);
|
||||
if (!rc)
|
||||
@@ -435,6 +437,8 @@ static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datu
|
||||
* is called to release xattr related objects when unmounting.
|
||||
* check_xattr_ref_inode(c, ic)
|
||||
* is used to confirm inode does not have duplicate xattr name/value pair.
|
||||
* jffs2_xattr_do_crccheck_inode(c, ic)
|
||||
* is used to force xattr data integrity check during the initial gc scan.
|
||||
* -------------------------------------------------- */
|
||||
static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
|
||||
{
|
||||
@@ -462,7 +466,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
|
||||
if (crc != je32_to_cpu(rr.node_crc)) {
|
||||
JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
|
||||
offset, je32_to_cpu(rr.node_crc), crc);
|
||||
return -EIO;
|
||||
return JFFS2_XATTR_IS_CORRUPTED;
|
||||
}
|
||||
if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
|
||||
|| je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF
|
||||
@@ -472,7 +476,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
|
||||
offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
|
||||
je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
|
||||
je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
|
||||
return -EIO;
|
||||
return JFFS2_XATTR_IS_CORRUPTED;
|
||||
}
|
||||
ref->ino = je32_to_cpu(rr.ino);
|
||||
ref->xid = je32_to_cpu(rr.xid);
|
||||
@@ -682,6 +686,11 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac
|
||||
return rc;
|
||||
}
|
||||
|
||||
void jffs2_xattr_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
|
||||
{
|
||||
check_xattr_ref_inode(c, ic);
|
||||
}
|
||||
|
||||
/* -------- xattr subsystem functions ---------------
|
||||
* jffs2_init_xattr_subsystem(c)
|
||||
* is used to initialize semaphore and list_head, and some variables.
|
||||
|
@@ -77,6 +77,7 @@ extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c);
|
||||
extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
|
||||
uint32_t xid, uint32_t version);
|
||||
|
||||
extern void jffs2_xattr_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
|
||||
extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
|
||||
extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
|
||||
|
||||
@@ -108,6 +109,7 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
|
||||
#define jffs2_build_xattr_subsystem(c)
|
||||
#define jffs2_clear_xattr_subsystem(c)
|
||||
|
||||
#define jffs2_xattr_do_crccheck_inode(c, ic)
|
||||
#define jffs2_xattr_delete_inode(c, ic)
|
||||
#define jffs2_xattr_free_inode(c, ic)
|
||||
#define jffs2_verify_xattr(c) (1)
|
||||
|
Referência em uma nova issue
Block a user