/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright © 2001-2007 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $
- *
*/
#include <linux/kernel.h>
flash_ofs |= REF_NORMAL;
}
fn->raw = jffs2_add_physical_node_ref(c, flash_ofs, PAD(sizeof(*ri)+datalen), f->inocache);
+ if (IS_ERR(fn->raw)) {
+ void *hold_err = fn->raw;
+ /* Release the full_dnode which is now useless, and return */
+ jffs2_free_full_dnode(fn);
+ return ERR_CAST(hold_err);
+ }
fn->ofs = je32_to_cpu(ri->offset);
fn->size = je32_to_cpu(ri->dsize);
fn->frags = 0;
BUG();
});
+ if (strnlen(name, namelen) != namelen) {
+ /* This should never happen, but seems to have done on at least one
+ occasion: https://dev.laptop.org/ticket/4184 */
+ printk(KERN_CRIT "Error in jffs2_write_dirent() -- name contains zero bytes!\n");
+ printk(KERN_CRIT "Directory inode #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x\n",
+ je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
+ je32_to_cpu(rd->name_crc));
+ WARN_ON(1);
+ return ERR_PTR(-EIO);
+ }
+
vecs[0].iov_base = rd;
vecs[0].iov_len = sizeof(*rd);
vecs[1].iov_base = (unsigned char *)name;
fd->version = je32_to_cpu(rd->version);
fd->ino = je32_to_cpu(rd->ino);
- fd->nhash = full_name_hash(name, strlen(name));
+ fd->nhash = full_name_hash(name, namelen);
fd->type = rd->type;
memcpy(fd->name, name, namelen);
fd->name[namelen]=0;
return ERR_PTR(ret?ret:-EIO);
}
/* Mark the space used */
- fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | REF_PRISTINE, PAD(sizeof(*rd)+namelen), f->inocache);
+ fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | dirent_node_state(rd),
+ PAD(sizeof(*rd)+namelen), f->inocache);
+ if (IS_ERR(fd->raw)) {
+ void *hold_err = fd->raw;
+ /* Release the full_dirent which is now useless, and return */
+ jffs2_free_full_dirent(fd);
+ return ERR_CAST(hold_err);
+ }
if (retried) {
jffs2_dbg_acct_sanity_check(c,NULL);
up(&f->sem);
jffs2_complete_reservation(c);
+
+ ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode);
+ if (ret)
+ return ret;
+ ret = jffs2_init_acl_post(&f->vfs_inode);
+ if (ret)
+ return ret;
+
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
uint32_t alloclen;
int ret;
- if (1 /* alternative branch needs testing */ ||
- !jffs2_can_mark_obsolete(c)) {
+ if (!jffs2_can_mark_obsolete(c)) {
/* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
rd = jffs2_alloc_raw_dirent();
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
up(&dir_f->sem);
} else {
- struct jffs2_full_dirent **prev = &dir_f->dents;
+ struct jffs2_full_dirent *fd = dir_f->dents;
uint32_t nhash = full_name_hash(name, namelen);
+ /* We don't actually want to reserve any space, but we do
+ want to be holding the alloc_sem when we write to flash */
+ down(&c->alloc_sem);
down(&dir_f->sem);
- while ((*prev) && (*prev)->nhash <= nhash) {
- if ((*prev)->nhash == nhash &&
- !memcmp((*prev)->name, name, namelen) &&
- !(*prev)->name[namelen]) {
- struct jffs2_full_dirent *this = *prev;
+ for (fd = dir_f->dents; fd; fd = fd->next) {
+ if (fd->nhash == nhash &&
+ !memcmp(fd->name, name, namelen) &&
+ !fd->name[namelen]) {
D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
- this->ino, ref_offset(this->raw)));
-
- *prev = this->next;
- jffs2_mark_node_obsolete(c, (this->raw));
- jffs2_free_full_dirent(this);
+ fd->ino, ref_offset(fd->raw)));
+ jffs2_mark_node_obsolete(c, fd->raw);
+ /* We don't want to remove it from the list immediately,
+ because that screws up getdents()/seek() semantics even
+ more than they're screwed already. Turn it into a
+ node-less deletion dirent instead -- a placeholder */
+ fd->raw = NULL;
+ fd->ino = 0;
break;
}
- prev = &((*prev)->next);
}
up(&dir_f->sem);
}
D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
fd->name, dead_f->inocache->ino));
}
- jffs2_mark_node_obsolete(c, fd->raw);
+ if (fd->raw)
+ jffs2_mark_node_obsolete(c, fd->raw);
jffs2_free_full_dirent(fd);
}
}