Commit 2c4aabcc authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.infradead.org/mtd-2.6

* git://git.infradead.org/mtd-2.6:
  [MTD][NOR] Add physical address to point() method
  [JFFS2] Track parent inode for directories (for NFS export)
  [JFFS2] Invert last argument of jffs2_gc_fetch_inode(), make it boolean.
  [JFFS2] Quiet lockdep false positive.
  [JFFS2] Clean up jffs2_alloc_inode() and jffs2_i_init_once()
  [MTD] Delete long-unused jedec.h header file.
  [MTD] [NAND] at91_nand: use at91_nand_{en,dis}able consistently.
parents bcf35afb a98889f3
...@@ -82,9 +82,8 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *); ...@@ -82,9 +82,8 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **); static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf); size_t *retlen, void **virt, resource_size_t *phys);
static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
size_t len);
static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode); static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
...@@ -1240,7 +1239,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a ...@@ -1240,7 +1239,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
return ret; return ret;
} }
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, void **virt, resource_size_t *phys)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
...@@ -1257,8 +1257,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si ...@@ -1257,8 +1257,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
chipnum = (from >> cfi->chipshift); chipnum = (from >> cfi->chipshift);
ofs = from - (chipnum << cfi->chipshift); ofs = from - (chipnum << cfi->chipshift);
*mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs; *virt = map->virt + cfi->chips[chipnum].start + ofs;
*retlen = 0; *retlen = 0;
if (phys)
*phys = map->phys + cfi->chips[chipnum].start + ofs;
while (len) { while (len) {
unsigned long thislen; unsigned long thislen;
...@@ -1291,7 +1293,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si ...@@ -1291,7 +1293,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
return 0; return 0;
} }
static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
......
...@@ -48,18 +48,21 @@ static int ram_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -48,18 +48,21 @@ static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
static int ram_point(struct mtd_info *mtd, loff_t from, size_t len, static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
if (from + len > mtd->size) if (from + len > mtd->size)
return -EINVAL; return -EINVAL;
*mtdbuf = mtd->priv + from; /* can we return a physical address with this driver? */
if (phys)
return -EINVAL;
*virt = mtd->priv + from;
*retlen = len; *retlen = len;
return 0; return 0;
} }
static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from, static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
size_t len)
{ {
} }
......
...@@ -57,20 +57,21 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -57,20 +57,21 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
static int phram_point(struct mtd_info *mtd, loff_t from, size_t len, static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
u_char *start = mtd->priv;
if (from + len > mtd->size) if (from + len > mtd->size)
return -EINVAL; return -EINVAL;
*mtdbuf = start + from; /* can we return a physical address with this driver? */
if (phys)
return -EINVAL;
*virt = mtd->priv + from;
*retlen = len; *retlen = len;
return 0; return 0;
} }
static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
size_t len)
{ {
} }
......
...@@ -134,7 +134,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -134,7 +134,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
eoff_lo = end & (priv->asize - 1); eoff_lo = end & (priv->asize - 1);
soff_lo = instr->addr & (priv->asize - 1); soff_lo = instr->addr & (priv->asize - 1);
pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr); pmc551_point(mtd, instr->addr, instr->len, &retlen,
(void **)&ptr, NULL);
if (soff_hi == eoff_hi || mtd->size == priv->asize) { if (soff_hi == eoff_hi || mtd->size == priv->asize) {
/* The whole thing fits within one access, so just one shot /* The whole thing fits within one access, so just one shot
...@@ -154,7 +155,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -154,7 +155,8 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
soff_hi += priv->asize; soff_hi += priv->asize;
pmc551_point(mtd, (priv->base_map0 | soff_hi), pmc551_point(mtd, (priv->base_map0 | soff_hi),
priv->asize, &retlen, &ptr); priv->asize, &retlen,
(void **)&ptr, NULL);
} }
memset(ptr, 0xff, eoff_lo); memset(ptr, 0xff, eoff_lo);
} }
...@@ -170,7 +172,7 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -170,7 +172,7 @@ static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char ** mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
struct mypriv *priv = mtd->priv; struct mypriv *priv = mtd->priv;
u32 soff_hi; u32 soff_hi;
...@@ -188,6 +190,10 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -188,6 +190,10 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
return -EINVAL; return -EINVAL;
} }
/* can we return a physical address with this driver? */
if (phys)
return -EINVAL;
soff_hi = from & ~(priv->asize - 1); soff_hi = from & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1); soff_lo = from & (priv->asize - 1);
...@@ -198,13 +204,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -198,13 +204,12 @@ static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
priv->curr_map0 = soff_hi; priv->curr_map0 = soff_hi;
} }
*mtdbuf = priv->start + soff_lo; *virt = priv->start + soff_lo;
*retlen = len; *retlen = len;
return 0; return 0;
} }
static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from, static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
size_t len)
{ {
#ifdef CONFIG_MTD_PMC551_DEBUG #ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_unpoint()\n"); printk(KERN_DEBUG "pmc551_unpoint()\n");
...@@ -242,7 +247,7 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -242,7 +247,7 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
soff_lo = from & (priv->asize - 1); soff_lo = from & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1); eoff_lo = end & (priv->asize - 1);
pmc551_point(mtd, from, len, retlen, &ptr); pmc551_point(mtd, from, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) { if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot /* The whole thing fits within one access, so just one shot
...@@ -263,7 +268,8 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -263,7 +268,8 @@ static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
goto out; goto out;
} }
soff_hi += priv->asize; soff_hi += priv->asize;
pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr); pmc551_point(mtd, soff_hi, priv->asize, retlen,
(void **)&ptr, NULL);
} }
memcpy(copyto, ptr, eoff_lo); memcpy(copyto, ptr, eoff_lo);
copyto += eoff_lo; copyto += eoff_lo;
...@@ -308,7 +314,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -308,7 +314,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
soff_lo = to & (priv->asize - 1); soff_lo = to & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1); eoff_lo = end & (priv->asize - 1);
pmc551_point(mtd, to, len, retlen, &ptr); pmc551_point(mtd, to, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) { if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot /* The whole thing fits within one access, so just one shot
...@@ -329,7 +335,8 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -329,7 +335,8 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
goto out; goto out;
} }
soff_hi += priv->asize; soff_hi += priv->asize;
pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr); pmc551_point(mtd, soff_hi, priv->asize, retlen,
(void **)&ptr, NULL);
} }
memcpy(ptr, copyfrom, eoff_lo); memcpy(ptr, copyfrom, eoff_lo);
copyfrom += eoff_lo; copyfrom += eoff_lo;
......
...@@ -76,8 +76,9 @@ static char *map; ...@@ -76,8 +76,9 @@ static char *map;
static slram_mtd_list_t *slram_mtdlist = NULL; static slram_mtd_list_t *slram_mtdlist = NULL;
static int slram_erase(struct mtd_info *, struct erase_info *); static int slram_erase(struct mtd_info *, struct erase_info *);
static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **); static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t); resource_size_t *);
static void slram_unpoint(struct mtd_info *, loff_t, size_t);
static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
...@@ -104,19 +105,23 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -104,19 +105,23 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
} }
static int slram_point(struct mtd_info *mtd, loff_t from, size_t len, static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
slram_priv_t *priv = mtd->priv; slram_priv_t *priv = mtd->priv;
/* can we return a physical address with this driver? */
if (phys)
return -EINVAL;
if (from + len > mtd->size) if (from + len > mtd->size)
return -EINVAL; return -EINVAL;
*mtdbuf = priv->start + from; *virt = priv->start + from;
*retlen = len; *retlen = len;
return(0); return(0);
} }
static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{ {
} }
......
...@@ -40,10 +40,12 @@ struct mtd_partition uclinux_romfs[] = { ...@@ -40,10 +40,12 @@ struct mtd_partition uclinux_romfs[] = {
/****************************************************************************/ /****************************************************************************/
int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len, int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **mtdbuf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
struct map_info *map = mtd->priv; struct map_info *map = mtd->priv;
*mtdbuf = (u_char *) (map->virt + ((int) from)); *virt = map->virt + from;
if (phys)
*phys = map->phys + from;
*retlen = len; *retlen = len;
return(0); return(0);
} }
......
...@@ -68,7 +68,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -68,7 +68,7 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
} }
static int part_point (struct mtd_info *mtd, loff_t from, size_t len, static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char **buf) size_t *retlen, void **virt, resource_size_t *phys)
{ {
struct mtd_part *part = PART(mtd); struct mtd_part *part = PART(mtd);
if (from >= mtd->size) if (from >= mtd->size)
...@@ -76,14 +76,14 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -76,14 +76,14 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
else if (from + len > mtd->size) else if (from + len > mtd->size)
len = mtd->size - from; len = mtd->size - from;
return part->master->point (part->master, from + part->offset, return part->master->point (part->master, from + part->offset,
len, retlen, buf); len, retlen, virt, phys);
} }
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{ {
struct mtd_part *part = PART(mtd); struct mtd_part *part = PART(mtd);
part->master->unpoint (part->master, addr, from + part->offset, len); part->master->unpoint(part->master, from + part->offset, len);
} }
static int part_read_oob(struct mtd_info *mtd, loff_t from, static int part_read_oob(struct mtd_info *mtd, loff_t from,
......
...@@ -93,6 +93,24 @@ struct at91_nand_host { ...@@ -93,6 +93,24 @@ struct at91_nand_host {
void __iomem *ecc; void __iomem *ecc;
}; };
/*
* Enable NAND.
*/
static void at91_nand_enable(struct at91_nand_host *host)
{
if (host->board->enable_pin)
at91_set_gpio_value(host->board->enable_pin, 0);
}
/*
* Disable NAND.
*/
static void at91_nand_disable(struct at91_nand_host *host)
{
if (host->board->enable_pin)
at91_set_gpio_value(host->board->enable_pin, 1);
}
/* /*
* Hardware specific access to control-lines * Hardware specific access to control-lines
*/ */
...@@ -101,11 +119,11 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) ...@@ -101,11 +119,11 @@ static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
struct nand_chip *nand_chip = mtd->priv; struct nand_chip *nand_chip = mtd->priv;
struct at91_nand_host *host = nand_chip->priv; struct at91_nand_host *host = nand_chip->priv;
if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) { if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_NCE) if (ctrl & NAND_NCE)
at91_set_gpio_value(host->board->enable_pin, 0); at91_nand_enable(host);
else else
at91_set_gpio_value(host->board->enable_pin, 1); at91_nand_disable(host);
} }
if (cmd == NAND_CMD_NONE) if (cmd == NAND_CMD_NONE)
return; return;
...@@ -127,24 +145,6 @@ static int at91_nand_device_ready(struct mtd_info *mtd) ...@@ -127,24 +145,6 @@ static int at91_nand_device_ready(struct mtd_info *mtd)
return at91_get_gpio_value(host->board->rdy_pin); return at91_get_gpio_value(host->board->rdy_pin);
} }
/*
* Enable NAND.
*/
static void at91_nand_enable(struct at91_nand_host *host)
{
if (host->board->enable_pin)
at91_set_gpio_value(host->board->enable_pin, 0);
}
/*
* Disable NAND.
*/
static void at91_nand_disable(struct at91_nand_host *host)
{
if (host->board->enable_pin)
at91_set_gpio_value(host->board->enable_pin, 1);
}
/* /*
* write oob for small pages * write oob for small pages
*/ */
......
...@@ -46,7 +46,7 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) ...@@ -46,7 +46,7 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
struct jffs2_inode_cache *ic) struct jffs2_inode_cache *ic)
{ {
struct jffs2_full_dirent *fd; struct jffs2_full_dirent *fd;
...@@ -68,11 +68,17 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, ...@@ -68,11 +68,17 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
continue; continue;
} }
if (child_ic->nlink++ && fd->type == DT_DIR) { if (fd->type == DT_DIR) {
JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", if (child_ic->pino_nlink) {
fd->name, fd->ino, ic->ino); JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
/* TODO: What do we do about it? */ fd->name, fd->ino, ic->ino);
} /* TODO: What do we do about it? */
} else {
child_ic->pino_nlink = ic->ino;
}
} else
child_ic->pino_nlink++;
dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
/* Can't free scan_dents so far. We might need them in pass 2 */ /* Can't free scan_dents so far. We might need them in pass 2 */
} }
...@@ -125,7 +131,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ...@@ -125,7 +131,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
dbg_fsbuild("pass 2 starting\n"); dbg_fsbuild("pass 2 starting\n");
for_each_inode(i, c, ic) { for_each_inode(i, c, ic) {
if (ic->nlink) if (ic->pino_nlink)
continue; continue;
jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
...@@ -232,16 +238,19 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, ...@@ -232,16 +238,19 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
/* Reduce nlink of the child. If it's now zero, stick it on the /* Reduce nlink of the child. If it's now zero, stick it on the
dead_fds list to be cleaned up later. Else just free the fd */ dead_fds list to be cleaned up later. Else just free the fd */
child_ic->nlink--; if (fd->type == DT_DIR)
child_ic->pino_nlink = 0;
else
child_ic->pino_nlink--;
if (!child_ic->nlink) { if (!child_ic->pino_nlink) {
dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n", dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
fd->ino, fd->name); fd->ino, fd->name);
fd->next = *dead_fds; fd->next = *dead_fds;
*dead_fds = fd; *dead_fds = fd;
} else { } else {
dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
fd->ino, fd->name, child_ic->nlink); fd->ino, fd->name, child_ic->pino_nlink);
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
} }
} }
......
...@@ -208,6 +208,13 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, ...@@ -208,6 +208,13 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
f = JFFS2_INODE_INFO(inode); f = JFFS2_INODE_INFO(inode);
dir_f = JFFS2_INODE_INFO(dir_i); dir_f = JFFS2_INODE_INFO(dir_i);
/* jffs2_do_create() will want to lock it, _after_ reserving
space and taking c-alloc_sem. If we keep it locked here,
lockdep gets unhappy (although it's a false positive;
nothing else will be looking at this inode yet so there's
no chance of AB-BA deadlock involving its f->sem). */
mutex_unlock(&f->sem);
ret = jffs2_do_create(c, dir_f, f, ri, ret = jffs2_do_create(c, dir_f, f, ri,
dentry->d_name.name, dentry->d_name.len); dentry->d_name.name, dentry->d_name.len);
if (ret) if (ret)
...@@ -219,7 +226,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, ...@@ -219,7 +226,8 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages)); inode->i_ino, inode->i_mode, inode->i_nlink,
f->inocache->pino_nlink, inode->i_mapping->nrpages));
return 0; return 0;
fail: fail:
...@@ -243,7 +251,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) ...@@ -243,7 +251,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
dentry->d_name.len, dead_f, now); dentry->d_name.len, dead_f, now);
if (dead_f->inocache) if (dead_f->inocache)
dentry->d_inode->i_nlink = dead_f->inocache->nlink; dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink;
if (!ret) if (!ret)
dir_i->i_mtime = dir_i->i_ctime = ITIME(now); dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
return ret; return ret;
...@@ -276,7 +284,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de ...@@ -276,7 +284,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
if (!ret) { if (!ret) {
mutex_lock(&f->sem); mutex_lock(&f->sem);
old_dentry->d_inode->i_nlink = ++f->inocache->nlink; old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink;
mutex_unlock(&f->sem); mutex_unlock(&f->sem);
d_instantiate(dentry, old_dentry->d_inode); d_instantiate(dentry, old_dentry->d_inode);
dir_i->i_mtime = dir_i->i_ctime = ITIME(now); dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
...@@ -493,11 +501,14 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -493,11 +501,14 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
inode->i_op = &jffs2_dir_inode_operations; inode->i_op = &jffs2_dir_inode_operations;
inode->i_fop = &jffs2_dir_operations; inode->i_fop = &jffs2_dir_operations;
/* Directories get nlink 2 at start */
inode->i_nlink = 2;
f = JFFS2_INODE_INFO(inode); f = JFFS2_INODE_INFO(inode);
/* Directories get nlink 2 at start */
inode->i_nlink = 2;
/* but ic->pino_nlink is the parent ino# */
f->inocache->pino_nlink = dir_i->i_ino;
ri->data_crc = cpu_to_je32(0); ri->data_crc = cpu_to_je32(0);
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
...@@ -594,17 +605,25 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -594,17 +605,25 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
{ {
struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
struct jffs2_full_dirent *fd; struct jffs2_full_dirent *fd;
int ret; int ret;
uint32_t now = get_seconds();
for (fd = f->dents ; fd; fd = fd->next) { for (fd = f->dents ; fd; fd = fd->next) {
if (fd->ino) if (fd->ino)
return -ENOTEMPTY; return -ENOTEMPTY;
} }
ret = jffs2_unlink(dir_i, dentry);
if (!ret) ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
dentry->d_name.len, f, now);
if (!ret) {
dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
clear_nlink(dentry->d_inode);
drop_nlink(dir_i); drop_nlink(dir_i);
}
return ret; return ret;
} }
...@@ -817,7 +836,10 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, ...@@ -817,7 +836,10 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
inode which didn't exist. */ inode which didn't exist. */
if (victim_f->inocache) { if (victim_f->inocache) {
mutex_lock(&victim_f->sem); mutex_lock(&victim_f->sem);
victim_f->inocache->nlink--; if (S_ISDIR(new_dentry->d_inode->i_mode))
victim_f->inocache->pino_nlink = 0;
else
victim_f->inocache->pino_nlink--;
mutex_unlock(&victim_f->sem); mutex_unlock(&victim_f->sem);
} }
} }
...@@ -838,8 +860,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, ...@@ -838,8 +860,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
mutex_lock(&f->sem); mutex_lock(&f->sem);
inc_nlink(old_dentry->d_inode); inc_nlink(old_dentry->d_inode);
if (f->inocache) if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode))
f->inocache->nlink++; f->inocache->pino_nlink++;
mutex_unlock(&f->sem); mutex_unlock(&f->sem);
printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
......
...@@ -294,7 +294,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, ...@@ -294,7 +294,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
break; break;
#endif #endif
default: default:
if (ic->nodes == (void *)ic && ic->nlink == 0) if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
jffs2_del_ino_cache(c, ic); jffs2_del_ino_cache(c, ic);
} }
} }
...@@ -332,7 +332,8 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl ...@@ -332,7 +332,8 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (c->mtd->point) { if (c->mtd->point) {
unsigned long *wordebuf; unsigned long *wordebuf;
ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf); ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size,
&retlen, &ebuf, NULL);
if (ret) { if (ret) {
D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
goto do_flash_read; goto do_flash_read;
...@@ -340,7 +341,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl ...@@ -340,7 +341,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (retlen < c->sector_size) { if (retlen < c->sector_size) {
/* Don't muck about if it won't let us point to the whole erase sector */ /* Don't muck about if it won't let us point to the whole erase sector */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen); c->mtd->unpoint(c->mtd, jeb->offset, retlen);
goto do_flash_read; goto do_flash_read;
} }
wordebuf = ebuf-sizeof(*wordebuf); wordebuf = ebuf-sizeof(*wordebuf);
...@@ -349,7 +350,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl ...@@ -349,7 +350,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
if (*++wordebuf != ~0) if (*++wordebuf != ~0)
break; break;
} while(--retlen); } while(--retlen);
c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size); c->mtd->unpoint(c->mtd, jeb->offset, c->sector_size);
if (retlen) { if (retlen) {
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n", printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
*wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf)); *wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
......
...@@ -273,7 +273,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) ...@@ -273,7 +273,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
inode->i_nlink = f->inocache->nlink; inode->i_nlink = f->inocache->pino_nlink;
inode->i_blocks = (inode->i_size + 511) >> 9; inode->i_blocks = (inode->i_size + 511) >> 9;
...@@ -286,13 +286,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) ...@@ -286,13 +286,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
case S_IFDIR: case S_IFDIR:
{ {
struct jffs2_full_dirent *fd; struct jffs2_full_dirent *fd;
inode->i_nlink = 2; /* parent and '.' */
for (fd=f->dents; fd; fd = fd->next) { for (fd=f->dents; fd; fd = fd->next) {
if (fd->type == DT_DIR && fd->ino) if (fd->type == DT_DIR && fd->ino)
inc_nlink(inode); inc_nlink(inode);
} }
/* and '..' */
inc_nlink(inode);
/* Root dir gets i_nlink 3 for some reason */ /* Root dir gets i_nlink 3 for some reason */
if (inode->i_ino == 1) if (inode->i_ino == 1)
inc_nlink(inode); inc_nlink(inode);
...@@ -586,11 +585,12 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c, ...@@ -586,11 +585,12 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c,
} }
struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
int inum, int nlink) int inum, int unlinked)
{ {
struct inode *inode; struct inode *inode;
struct jffs2_inode_cache *ic; struct jffs2_inode_cache *ic;
if (!nlink) {
if (unlinked) {
/* The inode has zero nlink but its nodes weren't yet marked /* The inode has zero nlink but its nodes weren't yet marked
obsolete. This has to be because we're still waiting for obsolete. This has to be because we're still waiting for
the final (close() and) iput() to happen. the final (close() and) iput() to happen.
...@@ -638,8 +638,8 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, ...@@ -638,8 +638,8 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
return ERR_CAST(inode); return ERR_CAST(inode);
} }
if (is_bad_inode(inode)) { if (is_bad_inode(inode)) {
printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n", printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. unlinked %d\n",
inum, nlink); inum, unlinked);
/* NB. This will happen again. We need to do something appropriate here. */ /* NB. This will happen again. We need to do something appropriate here. */
iput(inode); iput(inode);
return ERR_PTR(-EIO); return ERR_PTR(-EIO);
......
...@@ -161,8 +161,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -161,8 +161,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
continue; continue;
} }
if (!ic->nlink) { if (!ic->pino_nlink) {
D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n", D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink/pino zero\n",
ic->ino)); ic->ino));
spin_unlock(&c->inocache_lock); spin_unlock(&c->inocache_lock);
jffs2_xattr_delete_inode(c, ic); jffs2_xattr_delete_inode(c, ic);
...@@ -398,10 +398,10 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -398,10 +398,10 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
it's vaguely possible. */ it's vaguely possible. */
inum = ic->ino; inum = ic->ino;
nlink = ic->nlink; nlink = ic->pino_nlink;
spin_unlock(&c->inocache_lock); spin_unlock(&c->inocache_lock);
f = jffs2_gc_fetch_inode(c, inum, nlink); f = jffs2_gc_fetch_inode(c, inum, !nlink);
if (IS_ERR(f)) { if (IS_ERR(f)) {
ret = PTR_ERR(f); ret = PTR_ERR(f);
goto release_sem; goto release_sem;
......
...@@ -177,7 +177,10 @@ struct jffs2_inode_cache { ...@@ -177,7 +177,10 @@ struct jffs2_inode_cache {
#ifdef CONFIG_JFFS2_FS_XATTR #ifdef CONFIG_JFFS2_FS_XATTR
struct jffs2_xattr_ref *xref; struct jffs2_xattr_ref *xref;
#endif #endif
int nlink; uint32_t pino_nlink; /* Directories store parent inode
here; other inodes store nlink.
Zero always means that it's
completely unlinked. */
}; };
/* Inode states for 'state' above. We need the 'GC' state to prevent /* Inode states for 'state' above. We need the 'GC' state to prevent
......
...@@ -709,7 +709,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -709,7 +709,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
break; break;
#endif #endif
default: default:
if (ic->nodes == (void *)ic && ic->nlink == 0) if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
jffs2_del_ino_cache(c, ic); jffs2_del_ino_cache(c, ic);
break; break;
} }
......
...@@ -187,7 +187,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent); ...@@ -187,7 +187,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
void jffs2_gc_release_inode(struct jffs2_sb_info *c, void jffs2_gc_release_inode(struct jffs2_sb_info *c,
struct jffs2_inode_info *f); struct jffs2_inode_info *f);
struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
int inum, int nlink); int inum, int unlinked);
unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
struct jffs2_inode_info *f, struct jffs2_inode_info *f,
......
...@@ -63,10 +63,11 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info ...@@ -63,10 +63,11 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
/* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
* adding and jffs2_flash_read_end() interface. */ * adding and jffs2_flash_read_end() interface. */
if (c->mtd->point) { if (c->mtd->point) {
err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); err = c->mtd->point(c->mtd, ofs, len, &retlen,
(void **)&buffer, NULL);
if (!err && retlen < len) { if (!err && retlen < len) {
JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
c->mtd->unpoint(c->mtd, buffer, ofs, retlen); c->mtd->unpoint(c->mtd, ofs, retlen);
} else if (err) } else if (err)
JFFS2_WARNING("MTD point failed: error code %d.\n", err); JFFS2_WARNING("MTD point failed: error code %d.\n", err);
else else
...@@ -100,7 +101,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info ...@@ -100,7 +101,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
kfree(buffer); kfree(buffer);
#ifndef __ECOS #ifndef __ECOS
else else
c->mtd->unpoint(c->mtd, buffer, ofs, len); c->mtd->unpoint(c->mtd, ofs, len);
#endif #endif
if (crc != tn->data_crc) { if (crc != tn->data_crc) {
...@@ -136,7 +137,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info ...@@ -136,7 +137,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info
kfree(buffer); kfree(buffer);
#ifndef __ECOS #ifndef __ECOS
else else
c->mtd->unpoint(c->mtd, buffer, ofs, len); c->mtd->unpoint(c->mtd, ofs, len);
#endif #endif
return err; return err;
} }
...@@ -1123,7 +1124,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, ...@@ -1123,7 +1124,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
size_t retlen; size_t retlen;
int ret; int ret;
dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink); dbg_readinode("ino #%u pino/nlink is %d\n", f->inocache->ino,
f->inocache->pino_nlink);
memset(&rii, 0, sizeof(rii)); memset(&rii, 0, sizeof(rii));
...@@ -1358,7 +1360,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -1358,7 +1360,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
} }
dbg_readinode("creating inocache for root inode\n"); dbg_readinode("creating inocache for root inode\n");
memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
f->inocache->ino = f->inocache->nlink = 1; f->inocache->ino = f->inocache->pino_nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_READING; f->inocache->state = INO_STATE_READING;
jffs2_add_ino_cache(c, f->inocache); jffs2_add_ino_cache(c, f->inocache);
...@@ -1401,7 +1403,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) ...@@ -1401,7 +1403,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
jffs2_clear_acl(f); jffs2_clear_acl(f);
jffs2_xattr_delete_inode(c, f->inocache); jffs2_xattr_delete_inode(c, f->inocache);
mutex_lock(&f->sem); mutex_lock(&f->sem);
deleted = f->inocache && !f->inocache->nlink; deleted = f->inocache && !f->inocache->pino_nlink;
if (f->inocache && f->inocache->state != INO_STATE_CHECKING) if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
......
...@@ -97,11 +97,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -97,11 +97,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
size_t pointlen; size_t pointlen;
if (c->mtd->point) { if (c->mtd->point) {
ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf); ret = c->mtd->point(c->mtd, 0, c->mtd->size, &pointlen,
(void **)&flashbuf, NULL);
if (!ret && pointlen < c->mtd->size) { if (!ret && pointlen < c->mtd->size) {
/* Don't muck about if it won't let us point to the whole flash */ /* Don't muck about if it won't let us point to the whole flash */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen); c->mtd->unpoint(c->mtd, 0, pointlen);
flashbuf = NULL; flashbuf = NULL;
} }
if (ret) if (ret)
...@@ -267,7 +268,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -267,7 +268,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
kfree(flashbuf); kfree(flashbuf);
#ifndef __ECOS #ifndef __ECOS
else else
c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); c->mtd->unpoint(c->mtd, 0, c->mtd->size);
#endif #endif
if (s) if (s)
kfree(s); kfree(s);
...@@ -940,7 +941,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin ...@@ -940,7 +941,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin
ic->nodes = (void *)ic; ic->nodes = (void *)ic;
jffs2_add_ino_cache(c, ic); jffs2_add_ino_cache(c, ic);
if (ino == 1) if (ino == 1)
ic->nlink = 1; ic->pino_nlink = 1;
return ic; return ic;
} }
......
...@@ -31,11 +31,12 @@ static struct kmem_cache *jffs2_inode_cachep; ...@@ -31,11 +31,12 @@ static struct kmem_cache *jffs2_inode_cachep;
static struct inode *jffs2_alloc_inode(struct super_block *sb) static struct inode *jffs2_alloc_inode(struct super_block *sb)
{ {
struct jffs2_inode_info *ei; struct jffs2_inode_info *f;
ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
if (!ei) f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
if (!f)
return NULL; return NULL;
return &ei->vfs_inode; return &f->vfs_inode;
} }
static void jffs2_destroy_inode(struct inode *inode) static void jffs2_destroy_inode(struct inode *inode)
...@@ -45,10 +46,10 @@ static void jffs2_destroy_inode(struct inode *inode) ...@@ -45,10 +46,10 @@ static void jffs2_destroy_inode(struct inode *inode)
static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo) static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo)
{ {
struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; struct jffs2_inode_info *f = foo;
mutex_init(&ei->sem); mutex_init(&f->sem);
inode_init_once(&ei->vfs_inode); inode_init_once(&f->vfs_inode);
} }
static int jffs2_sync_fs(struct super_block *sb, int wait) static int jffs2_sync_fs(struct super_block *sb, int wait)
......
...@@ -494,7 +494,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -494,7 +494,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
/* If it's an in-core inode, then we have to adjust any /* If it's an in-core inode, then we have to adjust any
full_dirent or full_dnode structure to point to the full_dirent or full_dnode structure to point to the
new version instead of the old */ new version instead of the old */
f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink); f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink);
if (IS_ERR(f)) { if (IS_ERR(f)) {
/* Should never happen; it _must_ be present */ /* Should never happen; it _must_ be present */
JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n", JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",
......
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
#include "compr.h" #include "compr.h"
int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri) int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
uint32_t mode, struct jffs2_raw_inode *ri)
{ {
struct jffs2_inode_cache *ic; struct jffs2_inode_cache *ic;
...@@ -31,7 +32,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint ...@@ -31,7 +32,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
memset(ic, 0, sizeof(*ic)); memset(ic, 0, sizeof(*ic));
f->inocache = ic; f->inocache = ic;
f->inocache->nlink = 1; f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_PRESENT; f->inocache->state = INO_STATE_PRESENT;
...@@ -438,10 +439,10 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str ...@@ -438,10 +439,10 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
JFFS2_SUMMARY_INODE_SIZE); JFFS2_SUMMARY_INODE_SIZE);
D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
if (ret) { if (ret)
mutex_unlock(&f->sem);
return ret; return ret;
}
mutex_lock(&f->sem);
ri->data_crc = cpu_to_je32(0); ri->data_crc = cpu_to_je32(0);
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
...@@ -635,9 +636,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, ...@@ -635,9 +636,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
jffs2_mark_node_obsolete(c, fd->raw); jffs2_mark_node_obsolete(c, fd->raw);
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
} }
} dead_f->inocache->pino_nlink = 0;
} else
dead_f->inocache->nlink--; dead_f->inocache->pino_nlink--;
/* NB: Caller must set inode nlink if appropriate */ /* NB: Caller must set inode nlink if appropriate */
mutex_unlock(&dead_f->sem); mutex_unlock(&dead_f->sem);
} }
......
...@@ -592,7 +592,7 @@ void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache ...@@ -592,7 +592,7 @@ void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache
When an inode with XATTR is removed, those XATTRs must be removed. */ When an inode with XATTR is removed, those XATTRs must be removed. */
struct jffs2_xattr_ref *ref, *_ref; struct jffs2_xattr_ref *ref, *_ref;
if (!ic || ic->nlink > 0) if (!ic || ic->pino_nlink > 0)
return; return;
down_write(&c->xattr_sem); down_write(&c->xattr_sem);
...@@ -829,7 +829,7 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) ...@@ -829,7 +829,7 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c)
ref->xd and ref->ic are not valid yet. */ ref->xd and ref->ic are not valid yet. */
xd = jffs2_find_xattr_datum(c, ref->xid); xd = jffs2_find_xattr_datum(c, ref->xid);
ic = jffs2_get_ino_cache(c, ref->ino); ic = jffs2_get_ino_cache(c, ref->ino);
if (!xd || !ic || !ic->nlink) { if (!xd || !ic || !ic->pino_nlink) {
dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n", dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
ref->ino, ref->xid, ref->xseqno); ref->ino, ref->xid, ref->xseqno);
ref->xseqno |= XREF_DELETE_MARKER; ref->xseqno |= XREF_DELETE_MARKER;
......
/* JEDEC Flash Interface.
* This is an older type of interface for self programming flash. It is
* commonly use in older AMD chips and is obsolete compared with CFI.
* It is called JEDEC because the JEDEC association distributes the ID codes
* for the chips.
*
* See the AMD flash databook for information on how to operate the interface.
*
* $Id: jedec.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $
*/
#ifndef __LINUX_MTD_JEDEC_H__
#define __LINUX_MTD_JEDEC_H__
#include <linux/types.h>
#define MAX_JEDEC_CHIPS 16
// Listing of all supported chips and their information
struct JEDECTable
{
__u16 jedec;
char *name;
unsigned long size;
unsigned long sectorsize;
__u32 capabilities;
};
// JEDEC being 0 is the end of the chip array
struct jedec_flash_chip
{
__u16 jedec;
unsigned long size;
unsigned long sectorsize;
// *(__u8*)(base + (adder << addrshift)) = data << datashift
// Address size = size << addrshift
unsigned long base; // Byte 0 of the flash, will be unaligned
unsigned int datashift; // Useful for 32bit/16bit accesses
unsigned int addrshift;
unsigned long offset; // linerized start. base==offset for unbanked, uninterleaved flash
__u32 capabilities;
// These markers are filled in by the flash_chip_scan function
unsigned long start;
unsigned long length;
};
struct jedec_private
{
unsigned long size; // Total size of all the devices
/* Bank handling. If sum(bank_fill) == size then this is linear flash.
Otherwise the mapping has holes in it. bank_fill may be used to
find the holes, but in the common symetric case
bank_fill[0] == bank_fill[*], thus addresses may be computed
mathmatically. bank_fill must be powers of two */
unsigned is_banked;
unsigned long bank_fill[MAX_JEDEC_CHIPS];
struct jedec_flash_chip chips[MAX_JEDEC_CHIPS];
};
#endif
...@@ -143,10 +143,12 @@ struct mtd_info { ...@@ -143,10 +143,12 @@ struct mtd_info {
int (*erase) (struct mtd_info *mtd, struct erase_info *instr); int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */ /* This stuff for eXecute-In-Place */
int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); /* phys is optional and may be set to NULL */
int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, void **virt, resource_size_t *phys);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */ /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len); void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
......
...@@ -36,8 +36,9 @@ struct mypriv { ...@@ -36,8 +36,9 @@ struct mypriv {
* Function Prototypes * Function Prototypes
*/ */
static int pmc551_erase(struct mtd_info *, struct erase_info *); static int pmc551_erase(struct mtd_info *, struct erase_info *);
static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t); static void pmc551_unpoint(struct mtd_info *, loff_t, size_t);
static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, void **virt, resource_size_t *phys);
static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
......
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