1
0
Files
kernel-49/fs/jffs2/readinode.c
Greg Kroah-Hartman 483e66c0e0 Merge 4.9.249 into android-4.9-q
Changes in 4.9.249
	spi: bcm2835aux: Fix use-after-free on unbind
	spi: bcm2835aux: Restore err assignment in bcm2835aux_spi_probe
	iwlwifi: pcie: limit memory read spin time
	arm64: dts: rockchip: Assign a fixed index to mmc devices on rk3399 boards.
	ARC: stack unwinding: don't assume non-current task is sleeping
	platform/x86: acer-wmi: add automatic keyboard background light toggle key as KEY_LIGHTS_TOGGLE
	Input: cm109 - do not stomp on control URB
	Input: i8042 - add Acer laptops to the i8042 reset list
	pinctrl: amd: remove debounce filter setting in IRQ type setting
	scsi: be2iscsi: Revert "Fix a theoretical leak in beiscsi_create_eqs()"
	spi: Prevent adding devices below an unregistering controller
	net/mlx4_en: Avoid scheduling restart task if it is already running
	tcp: fix cwnd-limited bug for TSO deferral where we send nothing
	net: stmmac: delete the eee_ctrl_timer after napi disabled
	net: stmmac: dwmac-meson8b: fix mask definition of the m250_sel mux
	net: bridge: vlan: fix error return code in __vlan_add()
	mac80211: mesh: fix mesh_pathtbl_init() error path
	USB: dummy-hcd: Fix uninitialized array use in init()
	USB: add RESET_RESUME quirk for Snapscan 1212
	ALSA: usb-audio: Fix potential out-of-bounds shift
	ALSA: usb-audio: Fix control 'access overflow' errors from chmap
	xhci: Give USB2 ports time to enter U3 in bus suspend
	USB: sisusbvga: Make console support depend on BROKEN
	ALSA: pcm: oss: Fix potential out-of-bounds shift
	serial: 8250_omap: Avoid FIFO corruption caused by MDR1 access
	pinctrl: merrifield: Set default bias in case no particular value given
	pinctrl: baytrail: Avoid clearing debounce value when turning it off
	scsi: bnx2i: Requires MMU
	can: softing: softing_netdev_open(): fix error handling
	RDMA/cm: Fix an attempt to use non-valid pointer when cleaning timewait
	kernel/cpu: add arch override for clear_tasks_mm_cpumask() mm handling
	drm/tegra: sor: Disable clocks on error in tegra_sor_init()
	scsi: mpt3sas: Increase IOCInit request timeout to 30s
	dm table: Remove BUG_ON(in_interrupt())
	soc/tegra: fuse: Fix index bug in get_process_id
	USB: serial: option: add interface-number sanity check to flag handling
	USB: gadget: f_acm: add support for SuperSpeed Plus
	USB: gadget: f_midi: setup SuperSpeed Plus descriptors
	USB: gadget: f_rndis: fix bitrate for SuperSpeed and above
	usb: gadget: f_fs: Re-use SS descriptors for SuperSpeedPlus
	usb: chipidea: ci_hdrc_imx: Pass DISABLE_DEVICE_STREAMING flag to imx6ul
	ARM: dts: exynos: fix roles of USB 3.0 ports on Odroid XU
	ARM: dts: exynos: fix USB 3.0 VBUS control and over-current pins on Exynos5410
	ARM: dts: exynos: fix USB 3.0 pins supply being turned off on Odroid XU
	HID: i2c-hid: add Vero K147 to descriptor override
	serial_core: Check for port state when tty is in error state
	media: msi2500: assign SPI bus number dynamically
	md: fix a warning caused by a race between concurrent md_ioctl()s
	Bluetooth: Fix slab-out-of-bounds read in hci_le_direct_adv_report_evt()
	drm/gma500: fix double free of gma_connector
	RDMA/rxe: Compute PSN windows correctly
	ARM: p2v: fix handling of LPAE translation in BE mode
	crypto: talitos - Fix return type of current_desc_hdr()
	spi: img-spfi: fix reference leak in img_spfi_resume
	ASoC: pcm: DRAIN support reactivation
	arm64: dts: exynos: Correct psci compatible used on Exynos7
	Bluetooth: Fix null pointer dereference in hci_event_packet()
	spi: spi-ti-qspi: fix reference leak in ti_qspi_setup
	spi: tegra20-slink: fix reference leak in slink ops of tegra20
	spi: tegra20-sflash: fix reference leak in tegra_sflash_resume
	spi: tegra114: fix reference leak in tegra spi ops
	RDMa/mthca: Work around -Wenum-conversion warning
	MIPS: BCM47XX: fix kconfig dependency bug for BCM47XX_BCMA
	staging: greybus: codecs: Fix reference counter leak in error handling
	media: solo6x10: fix missing snd_card_free in error handling case
	drm/omap: dmm_tiler: fix return error code in omap_dmm_probe()
	Input: ads7846 - fix integer overflow on Rt calculation
	Input: ads7846 - fix unaligned access on 7845
	powerpc/feature: Fix CPU_FTRS_ALWAYS by removing CPU_FTRS_GENERIC_32
	crypto: omap-aes - Fix PM disable depth imbalance in omap_aes_probe
	soc: ti: knav_qmss: fix reference leak in knav_queue_probe
	soc: ti: Fix reference imbalance in knav_dma_probe
	drivers: soc: ti: knav_qmss_queue: Fix error return code in knav_queue_probe
	RDMA/cxgb4: Validate the number of CQEs
	memstick: fix a double-free bug in memstick_check
	ARM: dts: at91: sama5d4_xplained: add pincontrol for USB Host
	ARM: dts: at91: sama5d3_xplained: add pincontrol for USB Host
	orinoco: Move context allocation after processing the skb
	cw1200: fix missing destroy_workqueue() on error in cw1200_init_common
	media: siano: fix memory leak of debugfs members in smsdvb_hotplug
	mips: cdmm: fix use-after-free in mips_cdmm_bus_discover
	HSI: omap_ssi: Don't jump to free ID in ssi_add_controller()
	ARM: dts: at91: at91sam9rl: fix ADC triggers
	NFSv4.2: condition READDIR's mask for security label based on LSM state
	SUNRPC: xprt_load_transport() needs to support the netid "rdma6"
	lockd: don't use interval-based rebinding over TCP
	NFS: switch nfsiod to be an UNBOUND workqueue.
	vfio-pci: Use io_remap_pfn_range() for PCI IO memory
	media: saa7146: fix array overflow in vidioc_s_audio()
	clocksource/drivers/cadence_ttc: Fix memory leak in ttc_setup_clockevent()
	pinctrl: falcon: add missing put_device() call in pinctrl_falcon_probe()
	memstick: r592: Fix error return in r592_probe()
	ASoC: jz4740-i2s: add missed checks for clk_get()
	dm ioctl: fix error return code in target_message
	clocksource/drivers/arm_arch_timer: Correct fault programming of CNTKCTL_EL1.EVNTI
	cpufreq: highbank: Add missing MODULE_DEVICE_TABLE
	cpufreq: st: Add missing MODULE_DEVICE_TABLE
	cpufreq: loongson1: Add missing MODULE_ALIAS
	cpufreq: scpi: Add missing MODULE_ALIAS
	scsi: pm80xx: Fix error return in pm8001_pci_probe()
	seq_buf: Avoid type mismatch for seq_buf_init
	scsi: fnic: Fix error return code in fnic_probe()
	powerpc/pseries/hibernation: drop pseries_suspend_begin() from suspend ops
	usb: ehci-omap: Fix PM disable depth umbalance in ehci_hcd_omap_probe
	usb: oxu210hp-hcd: Fix memory leak in oxu_create
	speakup: fix uninitialized flush_lock
	nfsd: Fix message level for normal termination
	nfs_common: need lock during iterate through the list
	x86/kprobes: Restore BTF if the single-stepping is cancelled
	clk: tegra: Fix duplicated SE clock entry
	extcon: max77693: Fix modalias string
	ASoC: wm_adsp: remove "ctl" from list on error in wm_adsp_create_control()
	irqchip/alpine-msi: Fix freeing of interrupts on allocation error path
	um: chan_xterm: Fix fd leak
	nfc: s3fwrn5: Release the nfc firmware
	powerpc/ps3: use dma_mapping_error()
	checkpatch: fix unescaped left brace
	net: bcmgenet: Fix a resource leak in an error handling path in the probe functin
	net: allwinner: Fix some resources leak in the error handling path of the probe and in the remove function
	net: korina: fix return value
	watchdog: qcom: Avoid context switch in restart handler
	clk: ti: Fix memleak in ti_fapll_synth_setup
	perf record: Fix memory leak when using '--user-regs=?' to list registers
	qlcnic: Fix error code in probe
	clk: s2mps11: Fix a resource leak in error handling paths in the probe function
	cfg80211: initialize rekey_data
	Input: cros_ec_keyb - send 'scancodes' in addition to key events
	Input: goodix - add upside-down quirk for Teclast X98 Pro tablet
	media: gspca: Fix memory leak in probe
	media: sunxi-cir: ensure IR is handled when it is continuous
	media: netup_unidvb: Don't leak SPI master in probe error path
	Input: cyapa_gen6 - fix out-of-bounds stack access
	Revert "ACPI / resources: Use AE_CTRL_TERMINATE to terminate resources walks"
	ACPI: PNP: compare the string length in the matching_id()
	ALSA: pcm: oss: Fix a few more UBSAN fixes
	ALSA: usb-audio: Disable sample read check if firmware doesn't give back
	s390/dasd: prevent inconsistent LCU device data
	s390/dasd: fix list corruption of pavgroup group list
	s390/dasd: fix list corruption of lcu list
	staging: comedi: mf6x4: Fix AI end-of-conversion detection
	powerpc/perf: Exclude kernel samples while counting events in user space.
	USB: serial: mos7720: fix parallel-port state restore
	USB: serial: keyspan_pda: fix dropped unthrottle interrupts
	USB: serial: keyspan_pda: fix write deadlock
	USB: serial: keyspan_pda: fix stalled writes
	USB: serial: keyspan_pda: fix write-wakeup use-after-free
	USB: serial: keyspan_pda: fix tx-unthrottle use-after-free
	USB: serial: keyspan_pda: fix write unthrottling
	btrfs: quota: Set rescan progress to (u64)-1 if we hit last leaf
	btrfs: scrub: Don't use inode page cache in scrub_handle_errored_block()
	Btrfs: fix selftests failure due to uninitialized i_mode in test inodes
	btrfs: fix return value mixup in btrfs_get_extent
	ext4: fix a memory leak of ext4_free_data
	KVM: arm64: Introduce handling of AArch32 TTBCR2 traps
	powerpc/xmon: Change printk() to pr_cont()
	ceph: fix race in concurrent __ceph_remove_cap invocations
	jffs2: Fix GC exit abnormally
	jfs: Fix array index bounds check in dbAdjTree
	drm/dp_aux_dev: check aux_dev before use in drm_dp_aux_dev_get_by_minor()
	spi: spi-sh: Fix use-after-free on unbind
	spi: davinci: Fix use-after-free on unbind
	spi: pic32: Don't leak DMA channels in probe error path
	spi: rb4xx: Don't leak SPI master in probe error path
	spi: sc18is602: Don't leak SPI master in probe error path
	spi: st-ssc4: Fix unbalanced pm_runtime_disable() in probe error path
	soc: qcom: smp2p: Safely acquire spinlock without IRQs
	mtd: parser: cmdline: Fix parsing of part-names with colons
	iio: buffer: Fix demux update
	iio: adc: rockchip_saradc: fix missing clk_disable_unprepare() on error in rockchip_saradc_resume
	iio:pressure:mpl3115: Force alignment of buffer
	clk: mvebu: a3700: fix the XTAL MODE pin to MPP1_9
	xen-blkback: set ring->xenblkd to NULL after kthread_stop()
	PCI: Fix pci_slot_release() NULL pointer dereference
	Linux 4.9.249

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I4829a32e2ea6e76eefea716f35f42ee02b75c265
2021-01-12 18:29:40 +03:00

1448 lines
43 KiB
C

/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright © 2001-2007 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/crc32.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include <linux/compiler.h>
#include "nodelist.h"
/*
* Check the data CRC of the node.
*
* Returns: 0 if the data CRC is correct;
* 1 - if incorrect;
* error code if an error occurred.
*/
static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
{
struct jffs2_raw_node_ref *ref = tn->fn->raw;
int err = 0, pointed = 0;
struct jffs2_eraseblock *jeb;
unsigned char *buffer;
uint32_t crc, ofs, len;
size_t retlen;
BUG_ON(tn->csize == 0);
/* Calculate how many bytes were already checked */
ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
len = tn->csize;
if (jffs2_is_writebuffered(c)) {
int adj = ofs % c->wbuf_pagesize;
if (likely(adj))
adj = c->wbuf_pagesize - adj;
if (adj >= tn->csize) {
dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
ref_offset(ref), tn->csize, ofs);
goto adj_acc;
}
ofs += adj;
len -= adj;
}
dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n",
ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len);
#ifndef __ECOS
/* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
* adding and jffs2_flash_read_end() interface. */
err = mtd_point(c->mtd, ofs, len, &retlen, (void **)&buffer, NULL);
if (!err && retlen < len) {
JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
mtd_unpoint(c->mtd, ofs, retlen);
} else if (err) {
if (err != -EOPNOTSUPP)
JFFS2_WARNING("MTD point failed: error code %d.\n", err);
} else
pointed = 1; /* succefully pointed to device */
#endif
if (!pointed) {
buffer = kmalloc(len, GFP_KERNEL);
if (unlikely(!buffer))
return -ENOMEM;
/* TODO: this is very frequent pattern, make it a separate
* routine */
err = jffs2_flash_read(c, ofs, len, &retlen, buffer);
if (err) {
JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err);
goto free_out;
}
if (retlen != len) {
JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len);
err = -EIO;
goto free_out;
}
}
/* Continue calculating CRC */
crc = crc32(tn->partial_crc, buffer, len);
if(!pointed)
kfree(buffer);
#ifndef __ECOS
else
mtd_unpoint(c->mtd, ofs, len);
#endif
if (crc != tn->data_crc) {
JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
ref_offset(ref), tn->data_crc, crc);
return 1;
}
adj_acc:
jeb = &c->blocks[ref->flash_offset / c->sector_size];
len = ref_totlen(c, jeb, ref);
/* If it should be REF_NORMAL, it'll get marked as such when
we build the fragtree, shortly. No need to worry about GC
moving it while it's marked REF_PRISTINE -- GC won't happen
till we've finished checking every inode anyway. */
ref->flash_offset |= REF_PRISTINE;
/*
* Mark the node as having been checked and fix the
* accounting accordingly.
*/
spin_lock(&c->erase_completion_lock);
jeb->used_size += len;
jeb->unchecked_size -= len;
c->used_size += len;
c->unchecked_size -= len;
jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
spin_unlock(&c->erase_completion_lock);
return 0;
free_out:
if(!pointed)
kfree(buffer);
#ifndef __ECOS
else
mtd_unpoint(c->mtd, ofs, len);
#endif
return err;
}
/*
* Helper function for jffs2_add_older_frag_to_fragtree().
*
* Checks the node if we are in the checking stage.
*/
static int check_tn_node(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
{
int ret;
BUG_ON(ref_obsolete(tn->fn->raw));
/* We only check the data CRC of unchecked nodes */
if (ref_flags(tn->fn->raw) != REF_UNCHECKED)
return 0;
dbg_readinode("check node %#04x-%#04x, phys offs %#08x\n",
tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw));
ret = check_node_data(c, tn);
if (unlikely(ret < 0)) {
JFFS2_ERROR("check_node_data() returned error: %d.\n",
ret);
} else if (unlikely(ret > 0)) {
dbg_readinode("CRC error, mark it obsolete.\n");
jffs2_mark_node_obsolete(c, tn->fn->raw);
}
return ret;
}
static struct jffs2_tmp_dnode_info *jffs2_lookup_tn(struct rb_root *tn_root, uint32_t offset)
{
struct rb_node *next;
struct jffs2_tmp_dnode_info *tn = NULL;
dbg_readinode("root %p, offset %d\n", tn_root, offset);
next = tn_root->rb_node;
while (next) {
tn = rb_entry(next, struct jffs2_tmp_dnode_info, rb);
if (tn->fn->ofs < offset)
next = tn->rb.rb_right;
else if (tn->fn->ofs >= offset)
next = tn->rb.rb_left;
else
break;
}
return tn;
}
static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
{
jffs2_mark_node_obsolete(c, tn->fn->raw);
jffs2_free_full_dnode(tn->fn);
jffs2_free_tmp_dnode_info(tn);
}
/*
* This function is used when we read an inode. Data nodes arrive in
* arbitrary order -- they may be older or newer than the nodes which
* are already in the tree. Where overlaps occur, the older node can
* be discarded as long as the newer passes the CRC check. We don't
* bother to keep track of holes in this rbtree, and neither do we deal
* with frags -- we can have multiple entries starting at the same
* offset, and the one with the smallest length will come first in the
* ordering.
*
* Returns 0 if the node was handled (including marking it obsolete)
* < 0 an if error occurred
*/
static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
struct jffs2_readinode_info *rii,
struct jffs2_tmp_dnode_info *tn)
{
uint32_t fn_end = tn->fn->ofs + tn->fn->size;
struct jffs2_tmp_dnode_info *this, *ptn;
dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw));
/* If a node has zero dsize, we only have to keep it if it might be the
node with highest version -- i.e. the one which will end up as f->metadata.
Note that such nodes won't be REF_UNCHECKED since there are no data to
check anyway. */
if (!tn->fn->size) {
if (rii->mdata_tn) {
if (rii->mdata_tn->version < tn->version) {
/* We had a candidate mdata node already */
dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version);
jffs2_kill_tn(c, rii->mdata_tn);
} else {
dbg_readinode("kill new mdata with ver %d (older than existing %d\n",
tn->version, rii->mdata_tn->version);
jffs2_kill_tn(c, tn);
return 0;
}
}
rii->mdata_tn = tn;
dbg_readinode("keep new mdata with ver %d\n", tn->version);
return 0;
}
/* Find the earliest node which _may_ be relevant to this one */
this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs);
if (this) {
/* If the node is coincident with another at a lower address,
back up until the other node is found. It may be relevant */
while (this->overlapped) {
ptn = tn_prev(this);
if (!ptn) {
/*
* We killed a node which set the overlapped
* flags during the scan. Fix it up.
*/
this->overlapped = 0;
break;
}
this = ptn;
}
dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
}
while (this) {
if (this->fn->ofs > fn_end)
break;
dbg_readinode("Ponder this ver %d, 0x%x-0x%x\n",
this->version, this->fn->ofs, this->fn->size);
if (this->version == tn->version) {
/* Version number collision means REF_PRISTINE GC. Accept either of them
as long as the CRC is correct. Check the one we have already... */
if (!check_tn_node(c, this)) {
/* The one we already had was OK. Keep it and throw away the new one */
dbg_readinode("Like old node. Throw away new\n");
jffs2_kill_tn(c, tn);
return 0;
} else {
/* Who cares if the new one is good; keep it for now anyway. */
dbg_readinode("Like new node. Throw away old\n");
rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
jffs2_kill_tn(c, this);
/* Same overlapping from in front and behind */
return 0;
}
}
if (this->version < tn->version &&
this->fn->ofs >= tn->fn->ofs &&
this->fn->ofs + this->fn->size <= fn_end) {
/* New node entirely overlaps 'this' */
if (check_tn_node(c, tn)) {
dbg_readinode("new node bad CRC\n");
jffs2_kill_tn(c, tn);
return 0;
}
/* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */
while (this && this->fn->ofs + this->fn->size <= fn_end) {
struct jffs2_tmp_dnode_info *next = tn_next(this);
if (this->version < tn->version) {
tn_erase(this, &rii->tn_root);
dbg_readinode("Kill overlapped ver %d, 0x%x-0x%x\n",
this->version, this->fn->ofs,
this->fn->ofs+this->fn->size);
jffs2_kill_tn(c, this);
}
this = next;
}
dbg_readinode("Done killing overlapped nodes\n");
continue;
}
if (this->version > tn->version &&
this->fn->ofs <= tn->fn->ofs &&
this->fn->ofs+this->fn->size >= fn_end) {
/* New node entirely overlapped by 'this' */
if (!check_tn_node(c, this)) {
dbg_readinode("Good CRC on old node. Kill new\n");
jffs2_kill_tn(c, tn);
return 0;
}
/* ... but 'this' was bad. Replace it... */
dbg_readinode("Bad CRC on old overlapping node. Kill it\n");
tn_erase(this, &rii->tn_root);
jffs2_kill_tn(c, this);
break;
}
this = tn_next(this);
}
/* We neither completely obsoleted nor were completely
obsoleted by an earlier node. Insert into the tree */
{
struct rb_node *parent;
struct rb_node **link = &rii->tn_root.rb_node;
struct jffs2_tmp_dnode_info *insert_point = NULL;
while (*link) {
parent = *link;
insert_point = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
if (tn->fn->ofs > insert_point->fn->ofs)
link = &insert_point->rb.rb_right;
else if (tn->fn->ofs < insert_point->fn->ofs ||
tn->fn->size < insert_point->fn->size)
link = &insert_point->rb.rb_left;
else
link = &insert_point->rb.rb_right;
}
rb_link_node(&tn->rb, &insert_point->rb, link);
rb_insert_color(&tn->rb, &rii->tn_root);
}
/* If there's anything behind that overlaps us, note it */
this = tn_prev(tn);
if (this) {
while (1) {
if (this->fn->ofs + this->fn->size > tn->fn->ofs) {
dbg_readinode("Node is overlapped by %p (v %d, 0x%x-0x%x)\n",
this, this->version, this->fn->ofs,
this->fn->ofs+this->fn->size);
tn->overlapped = 1;
break;
}
if (!this->overlapped)
break;
ptn = tn_prev(this);
if (!ptn) {
/*
* We killed a node which set the overlapped
* flags during the scan. Fix it up.
*/
this->overlapped = 0;
break;
}
this = ptn;
}
}
/* If the new node overlaps anything ahead, note it */
this = tn_next(tn);
while (this && this->fn->ofs < fn_end) {
this->overlapped = 1;
dbg_readinode("Node ver %d, 0x%x-0x%x is overlapped\n",
this->version, this->fn->ofs,
this->fn->ofs+this->fn->size);
this = tn_next(this);
}
return 0;
}
/* Trivial function to remove the last node in the tree. Which by definition
has no right-hand child — so can be removed just by making its left-hand
child (if any) take its place under its parent. Since this is only done
when we're consuming the whole tree, there's no need to use rb_erase()
and let it worry about adjusting colours and balancing the tree. That
would just be a waste of time. */
static void eat_last(struct rb_root *root, struct rb_node *node)
{
struct rb_node *parent = rb_parent(node);
struct rb_node **link;
/* LAST! */
BUG_ON(node->rb_right);
if (!parent)
link = &root->rb_node;
else if (node == parent->rb_left)
link = &parent->rb_left;
else
link = &parent->rb_right;
*link = node->rb_left;
if (node->rb_left)
node->rb_left->__rb_parent_color = node->__rb_parent_color;
}
/* We put the version tree in reverse order, so we can use the same eat_last()
function that we use to consume the tmpnode tree (tn_root). */
static void ver_insert(struct rb_root *ver_root, struct jffs2_tmp_dnode_info *tn)
{
struct rb_node **link = &ver_root->rb_node;
struct rb_node *parent = NULL;
struct jffs2_tmp_dnode_info *this_tn;
while (*link) {
parent = *link;
this_tn = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
if (tn->version > this_tn->version)
link = &parent->rb_left;
else
link = &parent->rb_right;
}
dbg_readinode("Link new node at %p (root is %p)\n", link, ver_root);
rb_link_node(&tn->rb, parent, link);
rb_insert_color(&tn->rb, ver_root);
}
/* Build final, normal fragtree from tn tree. It doesn't matter which order
we add nodes to the real fragtree, as long as they don't overlap. And
having thrown away the majority of overlapped nodes as we went, there
really shouldn't be many sets of nodes which do overlap. If we start at
the end, we can use the overlap markers -- we can just eat nodes which
aren't overlapped, and when we encounter nodes which _do_ overlap we
sort them all into a temporary tree in version order before replaying them. */
static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
struct jffs2_inode_info *f,
struct jffs2_readinode_info *rii)
{
struct jffs2_tmp_dnode_info *pen, *last, *this;
struct rb_root ver_root = RB_ROOT;
uint32_t high_ver = 0;
if (rii->mdata_tn) {
dbg_readinode("potential mdata is ver %d at %p\n", rii->mdata_tn->version, rii->mdata_tn);
high_ver = rii->mdata_tn->version;
rii->latest_ref = rii->mdata_tn->fn->raw;
}
#ifdef JFFS2_DBG_READINODE_MESSAGES
this = tn_last(&rii->tn_root);
while (this) {
dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs,
this->fn->ofs+this->fn->size, this->overlapped);
this = tn_prev(this);
}
#endif
pen = tn_last(&rii->tn_root);
while ((last = pen)) {
pen = tn_prev(last);
eat_last(&rii->tn_root, &last->rb);
ver_insert(&ver_root, last);
if (unlikely(last->overlapped)) {
if (pen)
continue;
/*
* We killed a node which set the overlapped
* flags during the scan. Fix it up.
*/
last->overlapped = 0;
}
/* Now we have a bunch of nodes in reverse version
order, in the tree at ver_root. Most of the time,
there'll actually be only one node in the 'tree',
in fact. */
this = tn_last(&ver_root);
while (this) {
struct jffs2_tmp_dnode_info *vers_next;
int ret;
vers_next = tn_prev(this);
eat_last(&ver_root, &this->rb);
if (check_tn_node(c, this)) {
dbg_readinode("node ver %d, 0x%x-0x%x failed CRC\n",
this->version, this->fn->ofs,
this->fn->ofs+this->fn->size);
jffs2_kill_tn(c, this);
} else {
if (this->version > high_ver) {
/* Note that this is different from the other
highest_version, because this one is only
counting _valid_ nodes which could give the
latest inode metadata */
high_ver = this->version;
rii->latest_ref = this->fn->raw;
}
dbg_readinode("Add %p (v %d, 0x%x-0x%x, ov %d) to fragtree\n",
this, this->version, this->fn->ofs,
this->fn->ofs+this->fn->size, this->overlapped);
ret = jffs2_add_full_dnode_to_inode(c, f, this->fn);
if (ret) {
/* Free the nodes in vers_root; let the caller
deal with the rest */
JFFS2_ERROR("Add node to tree failed %d\n", ret);
while (1) {
vers_next = tn_prev(this);
if (check_tn_node(c, this))
jffs2_mark_node_obsolete(c, this->fn->raw);
jffs2_free_full_dnode(this->fn);
jffs2_free_tmp_dnode_info(this);
this = vers_next;
if (!this)
break;
eat_last(&ver_root, &vers_next->rb);
}
return ret;
}
jffs2_free_tmp_dnode_info(this);
}
this = vers_next;
}
}
return 0;
}
static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
{
struct jffs2_tmp_dnode_info *tn, *next;
rbtree_postorder_for_each_entry_safe(tn, next, list, rb) {
jffs2_free_full_dnode(tn->fn);
jffs2_free_tmp_dnode_info(tn);
}
*list = RB_ROOT;
}
static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
{
struct jffs2_full_dirent *next;
while (fd) {
next = fd->next;
jffs2_free_full_dirent(fd);
fd = next;
}
}
/* Returns first valid node after 'ref'. May return 'ref' */
static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref)
{
while (ref && ref->next_in_ino) {
if (!ref_obsolete(ref))
return ref;
dbg_noderef("node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref));
ref = ref->next_in_ino;
}
return NULL;
}
/*
* Helper function for jffs2_get_inode_nodes().
* It is called every time an directory entry node is found.
*
* Returns: 0 on success;
* negative error code on failure.
*/
static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
struct jffs2_raw_dirent *rd, size_t read,
struct jffs2_readinode_info *rii)
{
struct jffs2_full_dirent *fd;
uint32_t crc;
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
BUG_ON(ref_obsolete(ref));
crc = crc32(0, rd, sizeof(*rd) - 8);
if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n",
ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
jffs2_mark_node_obsolete(c, ref);
return 0;
}
/* If we've never checked the CRCs on this node, check them now */
if (ref_flags(ref) == REF_UNCHECKED) {
struct jffs2_eraseblock *jeb;
int len;
/* Sanity check */
if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
jffs2_mark_node_obsolete(c, ref);
return 0;
}
jeb = &c->blocks[ref->flash_offset / c->sector_size];
len = ref_totlen(c, jeb, ref);
spin_lock(&c->erase_completion_lock);
jeb->used_size += len;
jeb->unchecked_size -= len;
c->used_size += len;
c->unchecked_size -= len;
ref->flash_offset = ref_offset(ref) | dirent_node_state(rd);
spin_unlock(&c->erase_completion_lock);
}
fd = jffs2_alloc_full_dirent(rd->nsize + 1);
if (unlikely(!fd))
return -ENOMEM;
fd->raw = ref;
fd->version = je32_to_cpu(rd->version);
fd->ino = je32_to_cpu(rd->ino);
fd->type = rd->type;
if (fd->version > rii->highest_version)
rii->highest_version = fd->version;
/* Pick out the mctime of the latest dirent */
if(fd->version > rii->mctime_ver && je32_to_cpu(rd->mctime)) {
rii->mctime_ver = fd->version;
rii->latest_mctime = je32_to_cpu(rd->mctime);
}
/*
* Copy as much of the name as possible from the raw
* dirent we've already read from the flash.
*/
if (read > sizeof(*rd))
memcpy(&fd->name[0], &rd->name[0],
min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) ));
/* Do we need to copy any more of the name directly from the flash? */
if (rd->nsize + sizeof(*rd) > read) {
/* FIXME: point() */
int err;
int already = read - sizeof(*rd);
err = jffs2_flash_read(c, (ref_offset(ref)) + read,
rd->nsize - already, &read, &fd->name[already]);
if (unlikely(read != rd->nsize - already) && likely(!err)) {
jffs2_free_full_dirent(fd);
JFFS2_ERROR("short read: wanted %d bytes, got %zd\n",
rd->nsize - already, read);
return -EIO;
}
if (unlikely(err)) {
JFFS2_ERROR("read remainder of name: error %d\n", err);
jffs2_free_full_dirent(fd);
return -EIO;
}
#ifdef CONFIG_JFFS2_SUMMARY
/*
* we use CONFIG_JFFS2_SUMMARY because without it, we
* have checked it while mounting
*/
crc = crc32(0, fd->name, rd->nsize);
if (unlikely(crc != je32_to_cpu(rd->name_crc))) {
JFFS2_NOTICE("name CRC failed on dirent node at"
"%#08x: read %#08x,calculated %#08x\n",
ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
jffs2_mark_node_obsolete(c, ref);
jffs2_free_full_dirent(fd);
return 0;
}
#endif
}
fd->nhash = full_name_hash(NULL, fd->name, rd->nsize);
fd->next = NULL;
fd->name[rd->nsize] = '\0';
/*
* Wheee. We now have a complete jffs2_full_dirent structure, with
* the name in it and everything. Link it into the list
*/
jffs2_add_fd_to_list(c, fd, &rii->fds);
return 0;
}
/*
* Helper function for jffs2_get_inode_nodes().
* It is called every time an inode node is found.
*
* Returns: 0 on success (possibly after marking a bad node obsolete);
* negative error code on failure.
*/
static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
struct jffs2_raw_inode *rd, int rdlen,
struct jffs2_readinode_info *rii)
{
struct jffs2_tmp_dnode_info *tn;
uint32_t len, csize;
int ret = 0;
uint32_t crc;
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
BUG_ON(ref_obsolete(ref));
crc = crc32(0, rd, sizeof(*rd) - 8);
if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n",
ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
jffs2_mark_node_obsolete(c, ref);
return 0;
}
tn = jffs2_alloc_tmp_dnode_info();
if (!tn) {
JFFS2_ERROR("failed to allocate tn (%zu bytes).\n", sizeof(*tn));
return -ENOMEM;
}
tn->partial_crc = 0;
csize = je32_to_cpu(rd->csize);
/* If we've never checked the CRCs on this node, check them now */
if (ref_flags(ref) == REF_UNCHECKED) {
/* Sanity checks */
if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||
unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) {
JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref));
jffs2_dbg_dump_node(c, ref_offset(ref));
jffs2_mark_node_obsolete(c, ref);
goto free_out;
}
if (jffs2_is_writebuffered(c) && csize != 0) {
/* At this point we are supposed to check the data CRC
* of our unchecked node. But thus far, we do not
* know whether the node is valid or obsolete. To
* figure this out, we need to walk all the nodes of
* the inode and build the inode fragtree. We don't
* want to spend time checking data of nodes which may
* later be found to be obsolete. So we put off the full
* data CRC checking until we have read all the inode
* nodes and have started building the fragtree.
*
* The fragtree is being built starting with nodes
* having the highest version number, so we'll be able
* to detect whether a node is valid (i.e., it is not
* overlapped by a node with higher version) or not.
* And we'll be able to check only those nodes, which
* are not obsolete.
*
* Of course, this optimization only makes sense in case
* of NAND flashes (or other flashes with
* !jffs2_can_mark_obsolete()), since on NOR flashes
* nodes are marked obsolete physically.
*
* Since NAND flashes (or other flashes with
* jffs2_is_writebuffered(c)) are anyway read by
* fractions of c->wbuf_pagesize, and we have just read
* the node header, it is likely that the starting part
* of the node data is also read when we read the
* header. So we don't mind to check the CRC of the
* starting part of the data of the node now, and check
* the second part later (in jffs2_check_node_data()).
* Of course, we will not need to re-read and re-check
* the NAND page which we have just read. This is why we
* read the whole NAND page at jffs2_get_inode_nodes(),
* while we needed only the node header.
*/
unsigned char *buf;
/* 'buf' will point to the start of data */
buf = (unsigned char *)rd + sizeof(*rd);
/* len will be the read data length */
len = min_t(uint32_t, rdlen - sizeof(*rd), csize);
tn->partial_crc = crc32(0, buf, len);
dbg_readinode("Calculates CRC (%#08x) for %d bytes, csize %d\n", tn->partial_crc, len, csize);
/* If we actually calculated the whole data CRC
* and it is wrong, drop the node. */
if (len >= csize && unlikely(tn->partial_crc != je32_to_cpu(rd->data_crc))) {
JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
ref_offset(ref), tn->partial_crc, je32_to_cpu(rd->data_crc));
jffs2_mark_node_obsolete(c, ref);
goto free_out;
}
} else if (csize == 0) {
/*
* We checked the header CRC. If the node has no data, adjust
* the space accounting now. For other nodes this will be done
* later either when the node is marked obsolete or when its
* data is checked.
*/
struct jffs2_eraseblock *jeb;
dbg_readinode("the node has no data.\n");
jeb = &c->blocks[ref->flash_offset / c->sector_size];
len = ref_totlen(c, jeb, ref);
spin_lock(&c->erase_completion_lock);
jeb->used_size += len;
jeb->unchecked_size -= len;
c->used_size += len;
c->unchecked_size -= len;
ref->flash_offset = ref_offset(ref) | REF_NORMAL;
spin_unlock(&c->erase_completion_lock);
}
}
tn->fn = jffs2_alloc_full_dnode();
if (!tn->fn) {
JFFS2_ERROR("alloc fn failed\n");
ret = -ENOMEM;
goto free_out;
}
tn->version = je32_to_cpu(rd->version);
tn->fn->ofs = je32_to_cpu(rd->offset);
tn->data_crc = je32_to_cpu(rd->data_crc);
tn->csize = csize;
tn->fn->raw = ref;
tn->overlapped = 0;
if (tn->version > rii->highest_version)
rii->highest_version = tn->version;
/* There was a bug where we wrote hole nodes out with
csize/dsize swapped. Deal with it */
if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && csize)
tn->fn->size = csize;
else // normal case...
tn->fn->size = je32_to_cpu(rd->dsize);
dbg_readinode2("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n",
ref_offset(ref), je32_to_cpu(rd->version),
je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize);
ret = jffs2_add_tn_to_tree(c, rii, tn);
if (ret) {
jffs2_free_full_dnode(tn->fn);
free_out:
jffs2_free_tmp_dnode_info(tn);
return ret;
}
#ifdef JFFS2_DBG_READINODE2_MESSAGES
dbg_readinode2("After adding ver %d:\n", je32_to_cpu(rd->version));
tn = tn_first(&rii->tn_root);
while (tn) {
dbg_readinode2("%p: v %d r 0x%x-0x%x ov %d\n",
tn, tn->version, tn->fn->ofs,
tn->fn->ofs+tn->fn->size, tn->overlapped);
tn = tn_next(tn);
}
#endif
return 0;
}
/*
* Helper function for jffs2_get_inode_nodes().
* It is called every time an unknown node is found.
*
* Returns: 0 on success;
* negative error code on failure.
*/
static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un)
{
/* We don't mark unknown nodes as REF_UNCHECKED */
if (ref_flags(ref) == REF_UNCHECKED) {
JFFS2_ERROR("REF_UNCHECKED but unknown node at %#08x\n",
ref_offset(ref));
JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n",
je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc));
jffs2_mark_node_obsolete(c, ref);
return 0;
}
un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype));
switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) {
case JFFS2_FEATURE_INCOMPAT:
JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n",
je16_to_cpu(un->nodetype), ref_offset(ref));
/* EEP */
BUG();
break;
case JFFS2_FEATURE_ROCOMPAT:
JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n",
je16_to_cpu(un->nodetype), ref_offset(ref));
BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO));
break;
case JFFS2_FEATURE_RWCOMPAT_COPY:
JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n",
je16_to_cpu(un->nodetype), ref_offset(ref));
break;
case JFFS2_FEATURE_RWCOMPAT_DELETE:
JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",
je16_to_cpu(un->nodetype), ref_offset(ref));
jffs2_mark_node_obsolete(c, ref);
return 0;
}
return 0;
}
/*
* Helper function for jffs2_get_inode_nodes().
* The function detects whether more data should be read and reads it if yes.
*
* Returns: 0 on success;
* negative error code on failure.
*/
static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
int needed_len, int *rdlen, unsigned char *buf)
{
int err, to_read = needed_len - *rdlen;
size_t retlen;
uint32_t offs;
if (jffs2_is_writebuffered(c)) {
int rem = to_read % c->wbuf_pagesize;
if (rem)
to_read += c->wbuf_pagesize - rem;
}
/* We need to read more data */
offs = ref_offset(ref) + *rdlen;
dbg_readinode("read more %d bytes\n", to_read);
err = jffs2_flash_read(c, offs, to_read, &retlen, buf + *rdlen);
if (err) {
JFFS2_ERROR("can not read %d bytes from 0x%08x, "
"error code: %d.\n", to_read, offs, err);
return err;
}
if (retlen < to_read) {
JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n",
offs, retlen, to_read);
return -EIO;
}
*rdlen += to_read;
return 0;
}
/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
with this ino. Perform a preliminary ordering on data nodes, throwing away
those which are completely obsoleted by newer ones. The naïve approach we
use to take of just returning them _all_ in version order will cause us to
run out of memory in certain degenerate cases. */
static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
struct jffs2_readinode_info *rii)
{
struct jffs2_raw_node_ref *ref, *valid_ref;
unsigned char *buf = NULL;
union jffs2_node_union *node;
size_t retlen;
int len, err;
rii->mctime_ver = 0;
dbg_readinode("ino #%u\n", f->inocache->ino);
/* FIXME: in case of NOR and available ->point() this
* needs to be fixed. */
len = sizeof(union jffs2_node_union) + c->wbuf_pagesize;
buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
spin_lock(&c->erase_completion_lock);
valid_ref = jffs2_first_valid_node(f->inocache->nodes);
if (!valid_ref && f->inocache->ino != 1)
JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino);
while (valid_ref) {
/* We can hold a pointer to a non-obsolete node without the spinlock,
but _obsolete_ nodes may disappear at any time, if the block
they're in gets erased. So if we mark 'ref' obsolete while we're
not holding the lock, it can go away immediately. For that reason,
we find the next valid node first, before processing 'ref'.
*/
ref = valid_ref;
valid_ref = jffs2_first_valid_node(ref->next_in_ino);
spin_unlock(&c->erase_completion_lock);
cond_resched();
/*
* At this point we don't know the type of the node we're going
* to read, so we do not know the size of its header. In order
* to minimize the amount of flash IO we assume the header is
* of size = JFFS2_MIN_NODE_HEADER.
*/
len = JFFS2_MIN_NODE_HEADER;
if (jffs2_is_writebuffered(c)) {
int end, rem;
/*
* We are about to read JFFS2_MIN_NODE_HEADER bytes,
* but this flash has some minimal I/O unit. It is
* possible that we'll need to read more soon, so read
* up to the next min. I/O unit, in order not to
* re-read the same min. I/O unit twice.
*/
end = ref_offset(ref) + len;
rem = end % c->wbuf_pagesize;
if (rem)
end += c->wbuf_pagesize - rem;
len = end - ref_offset(ref);
}
dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref));
/* FIXME: point() */
err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, buf);
if (err) {
JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ref_offset(ref), err);
goto free_out;
}
if (retlen < len) {
JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n", ref_offset(ref), retlen, len);
err = -EIO;
goto free_out;
}
node = (union jffs2_node_union *)buf;
/* No need to mask in the valid bit; it shouldn't be invalid */
if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) {
JFFS2_NOTICE("Node header CRC failed at %#08x. {%04x,%04x,%08x,%08x}\n",
ref_offset(ref), je16_to_cpu(node->u.magic),
je16_to_cpu(node->u.nodetype),
je32_to_cpu(node->u.totlen),
je32_to_cpu(node->u.hdr_crc));
jffs2_dbg_dump_node(c, ref_offset(ref));
jffs2_mark_node_obsolete(c, ref);
goto cont;
}
if (je16_to_cpu(node->u.magic) != JFFS2_MAGIC_BITMASK) {
/* Not a JFFS2 node, whinge and move on */
JFFS2_NOTICE("Wrong magic bitmask 0x%04x in node header at %#08x.\n",
je16_to_cpu(node->u.magic), ref_offset(ref));
jffs2_mark_node_obsolete(c, ref);
goto cont;
}
switch (je16_to_cpu(node->u.nodetype)) {
case JFFS2_NODETYPE_DIRENT:
if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent) &&
len < sizeof(struct jffs2_raw_dirent)) {
err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf);
if (unlikely(err))
goto free_out;
}
err = read_direntry(c, ref, &node->d, retlen, rii);
if (unlikely(err))
goto free_out;
break;
case JFFS2_NODETYPE_INODE:
if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode) &&
len < sizeof(struct jffs2_raw_inode)) {
err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf);
if (unlikely(err))
goto free_out;
}
err = read_dnode(c, ref, &node->i, len, rii);
if (unlikely(err))
goto free_out;
break;
default:
if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node) &&
len < sizeof(struct jffs2_unknown_node)) {
err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf);
if (unlikely(err))
goto free_out;
}
err = read_unknown(c, ref, &node->u);
if (unlikely(err))
goto free_out;
}
cont:
spin_lock(&c->erase_completion_lock);
}
spin_unlock(&c->erase_completion_lock);
kfree(buf);
f->highest_version = rii->highest_version;
dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n",
f->inocache->ino, rii->highest_version, rii->latest_mctime,
rii->mctime_ver);
return 0;
free_out:
jffs2_free_tmp_dnode_info_list(&rii->tn_root);
jffs2_free_full_dirent_list(rii->fds);
rii->fds = NULL;
kfree(buf);
return err;
}
static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
struct jffs2_inode_info *f,
struct jffs2_raw_inode *latest_node)
{
struct jffs2_readinode_info rii;
uint32_t crc, new_size;
size_t retlen;
int ret;
dbg_readinode("ino #%u pino/nlink is %d\n", f->inocache->ino,
f->inocache->pino_nlink);
memset(&rii, 0, sizeof(rii));
/* Grab all nodes relevant to this ino */
ret = jffs2_get_inode_nodes(c, f, &rii);
if (ret) {
JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret);
if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
return ret;
}
ret = jffs2_build_inode_fragtree(c, f, &rii);
if (ret) {
JFFS2_ERROR("Failed to build final fragtree for inode #%u: error %d\n",
f->inocache->ino, ret);
if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
jffs2_free_tmp_dnode_info_list(&rii.tn_root);
/* FIXME: We could at least crc-check them all */
if (rii.mdata_tn) {
jffs2_free_full_dnode(rii.mdata_tn->fn);
jffs2_free_tmp_dnode_info(rii.mdata_tn);
rii.mdata_tn = NULL;
}
return ret;
}
if (rii.mdata_tn) {
if (rii.mdata_tn->fn->raw == rii.latest_ref) {
f->metadata = rii.mdata_tn->fn;
jffs2_free_tmp_dnode_info(rii.mdata_tn);
} else {
jffs2_kill_tn(c, rii.mdata_tn);
}
rii.mdata_tn = NULL;
}
f->dents = rii.fds;
jffs2_dbg_fragtree_paranoia_check_nolock(f);
if (unlikely(!rii.latest_ref)) {
/* No data nodes for this inode. */
if (f->inocache->ino != 1) {
JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino);
if (!rii.fds) {
if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
return -EIO;
}
JFFS2_NOTICE("but it has children so we fake some modes for it\n");
}
latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);
latest_node->version = cpu_to_je32(0);
latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0);
latest_node->isize = cpu_to_je32(0);
latest_node->gid = cpu_to_je16(0);
latest_node->uid = cpu_to_je16(0);
if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
return 0;
}
ret = jffs2_flash_read(c, ref_offset(rii.latest_ref), sizeof(*latest_node), &retlen, (void *)latest_node);
if (ret || retlen != sizeof(*latest_node)) {
JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n",
ret, retlen, sizeof(*latest_node));
/* FIXME: If this fails, there seems to be a memory leak. Find it. */
return ret ? ret : -EIO;
}
crc = crc32(0, latest_node, sizeof(*latest_node)-8);
if (crc != je32_to_cpu(latest_node->node_crc)) {
JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n",
f->inocache->ino, ref_offset(rii.latest_ref));
return -EIO;
}
switch(jemode_to_cpu(latest_node->mode) & S_IFMT) {
case S_IFDIR:
if (rii.mctime_ver > je32_to_cpu(latest_node->version)) {
/* The times in the latest_node are actually older than
mctime in the latest dirent. Cheat. */
latest_node->ctime = latest_node->mtime = cpu_to_je32(rii.latest_mctime);
}
break;
case S_IFREG:
/* If it was a regular file, truncate it to the latest node's isize */
new_size = jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize));
if (new_size != je32_to_cpu(latest_node->isize)) {
JFFS2_WARNING("Truncating ino #%u to %d bytes failed because it only had %d bytes to start with!\n",
f->inocache->ino, je32_to_cpu(latest_node->isize), new_size);
latest_node->isize = cpu_to_je32(new_size);
}
break;
case S_IFLNK:
/* Hack to work around broken isize in old symlink code.
Remove this when dwmw2 comes to his senses and stops
symlinks from being an entirely gratuitous special
case. */
if (!je32_to_cpu(latest_node->isize))
latest_node->isize = latest_node->dsize;
if (f->inocache->state != INO_STATE_CHECKING) {
/* Symlink's inode data is the target path. Read it and
* keep in RAM to facilitate quick follow symlink
* operation. */
uint32_t csize = je32_to_cpu(latest_node->csize);
if (csize > JFFS2_MAX_NAME_LEN)
return -ENAMETOOLONG;
f->target = kmalloc(csize + 1, GFP_KERNEL);
if (!f->target) {
JFFS2_ERROR("can't allocate %u bytes of memory for the symlink target path cache\n", csize);
return -ENOMEM;
}
ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node),
csize, &retlen, (char *)f->target);
if (ret || retlen != csize) {
if (retlen != csize)
ret = -EIO;
kfree(f->target);
f->target = NULL;
return ret;
}
f->target[csize] = '\0';
dbg_readinode("symlink's target '%s' cached\n", f->target);
}
/* fall through... */
case S_IFBLK:
case S_IFCHR:
/* Certain inode types should have only one data node, and it's
kept as the metadata node */
if (f->metadata) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
return -EIO;
}
if (!frag_first(&f->fragtree)) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
return -EIO;
}
/* ASSERT: f->fraglist != NULL */
if (frag_next(frag_first(&f->fragtree))) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode));
/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
return -EIO;
}
/* OK. We're happy */
f->metadata = frag_first(&f->fragtree)->node;
jffs2_free_node_frag(frag_first(&f->fragtree));
f->fragtree = RB_ROOT;
break;
}
if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
return 0;
}
/* Scan the list of all nodes present for this ino, build map of versions, etc. */
int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
uint32_t ino, struct jffs2_raw_inode *latest_node)
{
dbg_readinode("read inode #%u\n", ino);
retry_inocache:
spin_lock(&c->inocache_lock);
f->inocache = jffs2_get_ino_cache(c, ino);
if (f->inocache) {
/* Check its state. We may need to wait before we can use it */
switch(f->inocache->state) {
case INO_STATE_UNCHECKED:
case INO_STATE_CHECKEDABSENT:
f->inocache->state = INO_STATE_READING;
break;
case INO_STATE_CHECKING:
case INO_STATE_GC:
/* If it's in either of these states, we need
to wait for whoever's got it to finish and
put it back. */
dbg_readinode("waiting for ino #%u in state %d\n", ino, f->inocache->state);
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
goto retry_inocache;
case INO_STATE_READING:
case INO_STATE_PRESENT:
/* Eep. This should never happen. It can
happen if Linux calls read_inode() again
before clear_inode() has finished though. */
JFFS2_ERROR("Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state);
/* Fail. That's probably better than allowing it to succeed */
f->inocache = NULL;
break;
default:
BUG();
}
}
spin_unlock(&c->inocache_lock);
if (!f->inocache && ino == 1) {
/* Special case - no root inode on medium */
f->inocache = jffs2_alloc_inode_cache();
if (!f->inocache) {
JFFS2_ERROR("cannot allocate inocache for root inode\n");
return -ENOMEM;
}
dbg_readinode("creating inocache for root inode\n");
memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
f->inocache->ino = f->inocache->pino_nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_READING;
jffs2_add_ino_cache(c, f->inocache);
}
if (!f->inocache) {
JFFS2_ERROR("requestied to read an nonexistent ino %u\n", ino);
return -ENOENT;
}
return jffs2_do_read_inode_internal(c, f, latest_node);
}
int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
{
struct jffs2_raw_inode n;
struct jffs2_inode_info *f = kzalloc(sizeof(*f), GFP_KERNEL);
int ret;
if (!f)
return -ENOMEM;
mutex_init(&f->sem);
mutex_lock(&f->sem);
f->inocache = ic;
ret = jffs2_do_read_inode_internal(c, f, &n);
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
jffs2_xattr_do_crccheck_inode(c, ic);
kfree (f);
return ret;
}
void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
{
struct jffs2_full_dirent *fd, *fds;
int deleted;
jffs2_xattr_delete_inode(c, f->inocache);
mutex_lock(&f->sem);
deleted = f->inocache && !f->inocache->pino_nlink;
if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
if (f->metadata) {
if (deleted)
jffs2_mark_node_obsolete(c, f->metadata->raw);
jffs2_free_full_dnode(f->metadata);
}
jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
fds = f->dents;
while(fds) {
fd = fds;
fds = fd->next;
jffs2_free_full_dirent(fd);
}
if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
if (f->inocache->nodes == (void *)f->inocache)
jffs2_del_ino_cache(c, f->inocache);
}
mutex_unlock(&f->sem);
}