You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (82 commits) [MTD] m25p80: Add Support for ATMEL AT25DF641 64-Megabit SPI Flash [MTD] m25p80: add FAST_READ access support to M25Pxx [MTD] [NAND] bf5xx_nand: Avoid crash if bfin_mac is installed. [MTD] [NAND] at91_nand: control NCE signal [MTD] [NAND] AT91 hardware ECC compile fix for at91sam9263 / at91sam9260 [MTD] [NAND] Hardware ECC controller on at91sam9263 / at91sam9260 [JFFS2] Introduce dbg_readinode2 log level, use it to shut read_dnode() up [JFFS2] Fix jffs2_reserve_space() when all blocks are pending erasure. [JFFS2] Add erase_checking_list to hold blocks being marked. UBI: add a message [JFFS2] Return values of jffs2_block_check_erase error paths [MTD] Clean up AR7 partition map support [MTD] [NOR] Fix Intel CFI driver for collie flash [JFFS2] Finally remove redundant ref->__totlen field. [JFFS2] Honour TEST_TOTLEN macro in debugging code. ref->__totlen is going! [JFFS2] Add paranoia debugging for superblock counts [JFFS2] Fix free space leak with in-band cleanmarkers [JFFS2] Self-sufficient #includes in jffs2_fs_i.h: include <linux/mutex.h> [MTD] [NAND] Verify probe by retrying to checking the results match [MTD] [NAND] S3C2410 Allow ECC disable to be specified by the board ...
This commit is contained in:
+11
-11
@@ -14,7 +14,7 @@ be fairly close.
|
||||
alloc_sem
|
||||
---------
|
||||
|
||||
The alloc_sem is a per-filesystem semaphore, used primarily to ensure
|
||||
The alloc_sem is a per-filesystem mutex, used primarily to ensure
|
||||
contiguous allocation of space on the medium. It is automatically
|
||||
obtained during space allocations (jffs2_reserve_space()) and freed
|
||||
upon write completion (jffs2_complete_reservation()). Note that
|
||||
@@ -41,10 +41,10 @@ if the wbuf is currently holding any data is permitted, though.
|
||||
Ordering constraints: See f->sem.
|
||||
|
||||
|
||||
File Semaphore f->sem
|
||||
File Mutex f->sem
|
||||
---------------------
|
||||
|
||||
This is the JFFS2-internal equivalent of the inode semaphore i->i_sem.
|
||||
This is the JFFS2-internal equivalent of the inode mutex i->i_sem.
|
||||
It protects the contents of the jffs2_inode_info private inode data,
|
||||
including the linked list of node fragments (but see the notes below on
|
||||
erase_completion_lock), etc.
|
||||
@@ -60,14 +60,14 @@ lead to deadlock, unless we played games with unlocking the i_sem
|
||||
before calling the space allocation functions.
|
||||
|
||||
Instead of playing such games, we just have an extra internal
|
||||
semaphore, which is obtained by the garbage collection code and also
|
||||
mutex, which is obtained by the garbage collection code and also
|
||||
by the normal file system code _after_ allocation of space.
|
||||
|
||||
Ordering constraints:
|
||||
|
||||
1. Never attempt to allocate space or lock alloc_sem with
|
||||
any f->sem held.
|
||||
2. Never attempt to lock two file semaphores in one thread.
|
||||
2. Never attempt to lock two file mutexes in one thread.
|
||||
No ordering rules have been made for doing so.
|
||||
|
||||
|
||||
@@ -86,8 +86,8 @@ a simple spin_lock() rather than spin_lock_bh().
|
||||
|
||||
Note that the per-inode list of physical nodes (f->nodes) is a special
|
||||
case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in
|
||||
the list are protected by the file semaphore f->sem. But the erase
|
||||
code may remove _obsolete_ nodes from the list while holding only the
|
||||
the list are protected by the file mutex f->sem. But the erase code
|
||||
may remove _obsolete_ nodes from the list while holding only the
|
||||
erase_completion_lock. So you can walk the list only while holding the
|
||||
erase_completion_lock, and can drop the lock temporarily mid-walk as
|
||||
long as the pointer you're holding is to a _valid_ node, not an
|
||||
@@ -124,10 +124,10 @@ Ordering constraints:
|
||||
erase_free_sem
|
||||
--------------
|
||||
|
||||
This semaphore is only used by the erase code which frees obsolete
|
||||
node references and the jffs2_garbage_collect_deletion_dirent()
|
||||
function. The latter function on NAND flash must read _obsolete_ nodes
|
||||
to determine whether the 'deletion dirent' under consideration can be
|
||||
This mutex is only used by the erase code which frees obsolete node
|
||||
references and the jffs2_garbage_collect_deletion_dirent() function.
|
||||
The latter function on NAND flash must read _obsolete_ nodes to
|
||||
determine whether the 'deletion dirent' under consideration can be
|
||||
discarded or whether it is still required to show that an inode has
|
||||
been unlinked. Because reading from the flash may sleep, the
|
||||
erase_completion_lock cannot be held, so an alternative, more
|
||||
|
||||
@@ -345,6 +345,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
|
||||
INIT_LIST_HEAD(&c->dirty_list);
|
||||
INIT_LIST_HEAD(&c->erasable_list);
|
||||
INIT_LIST_HEAD(&c->erasing_list);
|
||||
INIT_LIST_HEAD(&c->erase_checking_list);
|
||||
INIT_LIST_HEAD(&c->erase_pending_list);
|
||||
INIT_LIST_HEAD(&c->erasable_pending_wbuf_list);
|
||||
INIT_LIST_HEAD(&c->erase_complete_list);
|
||||
|
||||
+159
-5
@@ -62,9 +62,9 @@ __jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
|
||||
void
|
||||
__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
|
||||
{
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
__jffs2_dbg_fragtree_paranoia_check_nolock(f);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -153,6 +153,139 @@ __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
void __jffs2_dbg_superblock_counts(struct jffs2_sb_info *c)
|
||||
{
|
||||
struct jffs2_eraseblock *jeb;
|
||||
uint32_t free = 0, dirty = 0, used = 0, wasted = 0,
|
||||
erasing = 0, bad = 0, unchecked = 0;
|
||||
int nr_counted = 0;
|
||||
int dump = 0;
|
||||
|
||||
if (c->gcblock) {
|
||||
nr_counted++;
|
||||
free += c->gcblock->free_size;
|
||||
dirty += c->gcblock->dirty_size;
|
||||
used += c->gcblock->used_size;
|
||||
wasted += c->gcblock->wasted_size;
|
||||
unchecked += c->gcblock->unchecked_size;
|
||||
}
|
||||
if (c->nextblock) {
|
||||
nr_counted++;
|
||||
free += c->nextblock->free_size;
|
||||
dirty += c->nextblock->dirty_size;
|
||||
used += c->nextblock->used_size;
|
||||
wasted += c->nextblock->wasted_size;
|
||||
unchecked += c->nextblock->unchecked_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->clean_list, list) {
|
||||
nr_counted++;
|
||||
free += jeb->free_size;
|
||||
dirty += jeb->dirty_size;
|
||||
used += jeb->used_size;
|
||||
wasted += jeb->wasted_size;
|
||||
unchecked += jeb->unchecked_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->very_dirty_list, list) {
|
||||
nr_counted++;
|
||||
free += jeb->free_size;
|
||||
dirty += jeb->dirty_size;
|
||||
used += jeb->used_size;
|
||||
wasted += jeb->wasted_size;
|
||||
unchecked += jeb->unchecked_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->dirty_list, list) {
|
||||
nr_counted++;
|
||||
free += jeb->free_size;
|
||||
dirty += jeb->dirty_size;
|
||||
used += jeb->used_size;
|
||||
wasted += jeb->wasted_size;
|
||||
unchecked += jeb->unchecked_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->erasable_list, list) {
|
||||
nr_counted++;
|
||||
free += jeb->free_size;
|
||||
dirty += jeb->dirty_size;
|
||||
used += jeb->used_size;
|
||||
wasted += jeb->wasted_size;
|
||||
unchecked += jeb->unchecked_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->erasable_pending_wbuf_list, list) {
|
||||
nr_counted++;
|
||||
free += jeb->free_size;
|
||||
dirty += jeb->dirty_size;
|
||||
used += jeb->used_size;
|
||||
wasted += jeb->wasted_size;
|
||||
unchecked += jeb->unchecked_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->erase_pending_list, list) {
|
||||
nr_counted++;
|
||||
free += jeb->free_size;
|
||||
dirty += jeb->dirty_size;
|
||||
used += jeb->used_size;
|
||||
wasted += jeb->wasted_size;
|
||||
unchecked += jeb->unchecked_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->free_list, list) {
|
||||
nr_counted++;
|
||||
free += jeb->free_size;
|
||||
dirty += jeb->dirty_size;
|
||||
used += jeb->used_size;
|
||||
wasted += jeb->wasted_size;
|
||||
unchecked += jeb->unchecked_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->bad_used_list, list) {
|
||||
nr_counted++;
|
||||
free += jeb->free_size;
|
||||
dirty += jeb->dirty_size;
|
||||
used += jeb->used_size;
|
||||
wasted += jeb->wasted_size;
|
||||
unchecked += jeb->unchecked_size;
|
||||
}
|
||||
|
||||
list_for_each_entry(jeb, &c->erasing_list, list) {
|
||||
nr_counted++;
|
||||
erasing += c->sector_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->erase_checking_list, list) {
|
||||
nr_counted++;
|
||||
erasing += c->sector_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->erase_complete_list, list) {
|
||||
nr_counted++;
|
||||
erasing += c->sector_size;
|
||||
}
|
||||
list_for_each_entry(jeb, &c->bad_list, list) {
|
||||
nr_counted++;
|
||||
bad += c->sector_size;
|
||||
}
|
||||
|
||||
#define check(sz) \
|
||||
if (sz != c->sz##_size) { \
|
||||
printk(KERN_WARNING #sz "_size mismatch counted 0x%x, c->" #sz "_size 0x%x\n", \
|
||||
sz, c->sz##_size); \
|
||||
dump = 1; \
|
||||
}
|
||||
check(free);
|
||||
check(dirty);
|
||||
check(used);
|
||||
check(wasted);
|
||||
check(unchecked);
|
||||
check(bad);
|
||||
check(erasing);
|
||||
#undef check
|
||||
|
||||
if (nr_counted != c->nr_blocks) {
|
||||
printk(KERN_WARNING "%s counted only 0x%x blocks of 0x%x. Where are the others?\n",
|
||||
__func__, nr_counted, c->nr_blocks);
|
||||
dump = 1;
|
||||
}
|
||||
|
||||
if (dump) {
|
||||
__jffs2_dbg_dump_block_lists_nolock(c);
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
|
||||
*/
|
||||
@@ -229,6 +362,9 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(c->flags & (JFFS2_SB_FLAG_BUILDING|JFFS2_SB_FLAG_SCANNING)))
|
||||
__jffs2_dbg_superblock_counts(c);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
@@ -268,7 +404,10 @@ __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
|
||||
|
||||
printk(JFFS2_DBG);
|
||||
for (ref = jeb->first_node; ; ref = ref_next(ref)) {
|
||||
printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
|
||||
printk("%#08x", ref_offset(ref));
|
||||
#ifdef TEST_TOTLEN
|
||||
printk("(%x)", ref->__totlen);
|
||||
#endif
|
||||
if (ref_next(ref))
|
||||
printk("->");
|
||||
else
|
||||
@@ -447,6 +586,21 @@ __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list_empty(&c->erase_checking_list)) {
|
||||
printk(JFFS2_DBG "erase_checking_list: empty\n");
|
||||
} else {
|
||||
struct list_head *this;
|
||||
|
||||
list_for_each(this, &c->erase_checking_list) {
|
||||
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
|
||||
|
||||
if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
|
||||
printk(JFFS2_DBG "erase_checking_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
|
||||
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
|
||||
jeb->unchecked_size, jeb->free_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (list_empty(&c->erase_pending_list)) {
|
||||
printk(JFFS2_DBG "erase_pending_list: empty\n");
|
||||
@@ -532,9 +686,9 @@ __jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
|
||||
void
|
||||
__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
|
||||
{
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
jffs2_dbg_dump_fragtree_nolock(f);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#if CONFIG_JFFS2_FS_DEBUG > 1
|
||||
#define JFFS2_DBG_FRAGTREE2_MESSAGES
|
||||
#define JFFS2_DBG_READINODE2_MESSAGES
|
||||
#define JFFS2_DBG_MEMALLOC_MESSAGES
|
||||
#endif
|
||||
|
||||
@@ -115,6 +116,11 @@
|
||||
#else
|
||||
#define dbg_readinode(fmt, ...)
|
||||
#endif
|
||||
#ifdef JFFS2_DBG_READINODE2_MESSAGES
|
||||
#define dbg_readinode2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define dbg_readinode2(fmt, ...)
|
||||
#endif
|
||||
|
||||
/* Fragtree build debugging messages */
|
||||
#ifdef JFFS2_DBG_FRAGTREE_MESSAGES
|
||||
|
||||
+29
-29
@@ -86,7 +86,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
|
||||
dir_f = JFFS2_INODE_INFO(dir_i);
|
||||
c = JFFS2_SB_INFO(dir_i->i_sb);
|
||||
|
||||
down(&dir_f->sem);
|
||||
mutex_lock(&dir_f->sem);
|
||||
|
||||
/* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
|
||||
for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) {
|
||||
@@ -99,7 +99,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
|
||||
}
|
||||
if (fd)
|
||||
ino = fd->ino;
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
if (ino) {
|
||||
inode = jffs2_iget(dir_i->i_sb, ino);
|
||||
if (IS_ERR(inode)) {
|
||||
@@ -146,7 +146,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
}
|
||||
|
||||
curofs=1;
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
for (fd = f->dents; fd; fd = fd->next) {
|
||||
|
||||
curofs++;
|
||||
@@ -166,7 +166,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
break;
|
||||
offset++;
|
||||
}
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
out:
|
||||
filp->f_pos = offset;
|
||||
return 0;
|
||||
@@ -275,9 +275,9 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
|
||||
ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
|
||||
|
||||
if (!ret) {
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
d_instantiate(dentry, old_dentry->d_inode);
|
||||
dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
|
||||
atomic_inc(&old_dentry->d_inode->i_count);
|
||||
@@ -351,7 +351,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
||||
|
||||
if (IS_ERR(fn)) {
|
||||
/* Eeek. Wave bye bye */
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_clear_inode(inode);
|
||||
return PTR_ERR(fn);
|
||||
@@ -361,7 +361,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
||||
f->target = kmalloc(targetlen + 1, GFP_KERNEL);
|
||||
if (!f->target) {
|
||||
printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_clear_inode(inode);
|
||||
return -ENOMEM;
|
||||
@@ -374,7 +374,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
||||
obsoleted by the first data write
|
||||
*/
|
||||
f->metadata = fn;
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
@@ -406,7 +406,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
||||
}
|
||||
|
||||
dir_f = JFFS2_INODE_INFO(dir_i);
|
||||
down(&dir_f->sem);
|
||||
mutex_lock(&dir_f->sem);
|
||||
|
||||
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
|
||||
@@ -429,7 +429,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
||||
as if it were the final unlink() */
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_free_raw_dirent(rd);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
jffs2_clear_inode(inode);
|
||||
return PTR_ERR(fd);
|
||||
}
|
||||
@@ -442,7 +442,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
||||
one if necessary. */
|
||||
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
|
||||
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
@@ -507,7 +507,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
|
||||
|
||||
if (IS_ERR(fn)) {
|
||||
/* Eeek. Wave bye bye */
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_clear_inode(inode);
|
||||
return PTR_ERR(fn);
|
||||
@@ -516,7 +516,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
|
||||
obsoleted by the first data write
|
||||
*/
|
||||
f->metadata = fn;
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
@@ -548,7 +548,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
|
||||
}
|
||||
|
||||
dir_f = JFFS2_INODE_INFO(dir_i);
|
||||
down(&dir_f->sem);
|
||||
mutex_lock(&dir_f->sem);
|
||||
|
||||
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
|
||||
@@ -571,7 +571,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
|
||||
as if it were the final unlink() */
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_free_raw_dirent(rd);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
jffs2_clear_inode(inode);
|
||||
return PTR_ERR(fd);
|
||||
}
|
||||
@@ -585,7 +585,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
|
||||
one if necessary. */
|
||||
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
|
||||
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
@@ -673,7 +673,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
|
||||
|
||||
if (IS_ERR(fn)) {
|
||||
/* Eeek. Wave bye bye */
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_clear_inode(inode);
|
||||
return PTR_ERR(fn);
|
||||
@@ -682,7 +682,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
|
||||
obsoleted by the first data write
|
||||
*/
|
||||
f->metadata = fn;
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
@@ -714,7 +714,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
|
||||
}
|
||||
|
||||
dir_f = JFFS2_INODE_INFO(dir_i);
|
||||
down(&dir_f->sem);
|
||||
mutex_lock(&dir_f->sem);
|
||||
|
||||
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
|
||||
@@ -740,7 +740,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
|
||||
as if it were the final unlink() */
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_free_raw_dirent(rd);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
jffs2_clear_inode(inode);
|
||||
return PTR_ERR(fd);
|
||||
}
|
||||
@@ -753,7 +753,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
|
||||
one if necessary. */
|
||||
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
|
||||
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
@@ -780,14 +780,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||
if (S_ISDIR(new_dentry->d_inode->i_mode)) {
|
||||
struct jffs2_full_dirent *fd;
|
||||
|
||||
down(&victim_f->sem);
|
||||
mutex_lock(&victim_f->sem);
|
||||
for (fd = victim_f->dents; fd; fd = fd->next) {
|
||||
if (fd->ino) {
|
||||
up(&victim_f->sem);
|
||||
mutex_unlock(&victim_f->sem);
|
||||
return -ENOTEMPTY;
|
||||
}
|
||||
}
|
||||
up(&victim_f->sem);
|
||||
mutex_unlock(&victim_f->sem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -816,9 +816,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||
/* Don't oops if the victim was a dirent pointing to an
|
||||
inode which didn't exist. */
|
||||
if (victim_f->inocache) {
|
||||
down(&victim_f->sem);
|
||||
mutex_lock(&victim_f->sem);
|
||||
victim_f->inocache->nlink--;
|
||||
up(&victim_f->sem);
|
||||
mutex_unlock(&victim_f->sem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,11 +836,11 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||
if (ret) {
|
||||
/* Oh shit. We really ought to make a single node which can do both atomically */
|
||||
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
inc_nlink(old_dentry->d_inode);
|
||||
if (f->inocache)
|
||||
f->inocache->nlink++;
|
||||
up(&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);
|
||||
/* Might as well let the VFS know */
|
||||
|
||||
+42
-38
@@ -50,14 +50,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
|
||||
instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
|
||||
if (!instr) {
|
||||
printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
list_move(&jeb->list, &c->erase_pending_list);
|
||||
c->erasing_size -= c->sector_size;
|
||||
c->dirty_size += c->sector_size;
|
||||
jeb->dirty_size = c->sector_size;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -84,14 +84,14 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
|
||||
if (ret == -ENOMEM || ret == -EAGAIN) {
|
||||
/* Erase failed immediately. Refile it on the list */
|
||||
D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
list_move(&jeb->list, &c->erase_pending_list);
|
||||
c->erasing_size -= c->sector_size;
|
||||
c->dirty_size += c->sector_size;
|
||||
jeb->dirty_size = c->sector_size;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
|
||||
{
|
||||
struct jffs2_eraseblock *jeb;
|
||||
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
@@ -116,9 +116,9 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
|
||||
|
||||
if (!list_empty(&c->erase_complete_list)) {
|
||||
jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
|
||||
list_del(&jeb->list);
|
||||
list_move(&jeb->list, &c->erase_checking_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
jffs2_mark_erased_block(c, jeb);
|
||||
|
||||
if (!--count) {
|
||||
@@ -139,7 +139,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
|
||||
jffs2_free_jeb_node_refs(c, jeb);
|
||||
list_add(&jeb->list, &c->erasing_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
|
||||
jffs2_erase_block(c, jeb);
|
||||
|
||||
@@ -149,12 +149,12 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
|
||||
|
||||
/* Be nice */
|
||||
yield();
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
}
|
||||
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
done:
|
||||
D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
|
||||
}
|
||||
@@ -162,11 +162,11 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
|
||||
static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
|
||||
{
|
||||
D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
list_move_tail(&jeb->list, &c->erase_complete_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
/* Ensure that kupdated calls us again to mark them clean */
|
||||
jffs2_erase_pending_trigger(c);
|
||||
}
|
||||
@@ -180,26 +180,26 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock
|
||||
failed too many times. */
|
||||
if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
|
||||
/* We'd like to give this block another try. */
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
list_move(&jeb->list, &c->erase_pending_list);
|
||||
c->erasing_size -= c->sector_size;
|
||||
c->dirty_size += c->sector_size;
|
||||
jeb->dirty_size = c->sector_size;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
c->erasing_size -= c->sector_size;
|
||||
c->bad_size += c->sector_size;
|
||||
list_move(&jeb->list, &c->bad_list);
|
||||
c->nr_erasing_blocks--;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
wake_up(&c->erase_wait);
|
||||
}
|
||||
|
||||
@@ -350,9 +350,11 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
|
||||
break;
|
||||
} while(--retlen);
|
||||
c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size);
|
||||
if (retlen)
|
||||
if (retlen) {
|
||||
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
|
||||
*wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
do_flash_read:
|
||||
@@ -373,10 +375,12 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
|
||||
ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
if (retlen != readlen) {
|
||||
printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen);
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
for (i=0; i<readlen; i += sizeof(unsigned long)) {
|
||||
@@ -385,6 +389,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
|
||||
if (*datum + 1) {
|
||||
*bad_offset += i;
|
||||
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset);
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
@@ -419,9 +424,6 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
||||
if (jffs2_write_nand_cleanmarker(c, jeb))
|
||||
goto filebad;
|
||||
}
|
||||
|
||||
/* Everything else got zeroed before the erase */
|
||||
jeb->free_size = c->sector_size;
|
||||
} else {
|
||||
|
||||
struct kvec vecs[1];
|
||||
@@ -449,48 +451,50 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
||||
|
||||
goto filebad;
|
||||
}
|
||||
|
||||
/* Everything else got zeroed before the erase */
|
||||
jeb->free_size = c->sector_size;
|
||||
/* FIXME Special case for cleanmarker in empty block */
|
||||
jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL);
|
||||
}
|
||||
/* Everything else got zeroed before the erase */
|
||||
jeb->free_size = c->sector_size;
|
||||
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
|
||||
c->erasing_size -= c->sector_size;
|
||||
c->free_size += jeb->free_size;
|
||||
c->used_size += jeb->used_size;
|
||||
c->free_size += c->sector_size;
|
||||
|
||||
jffs2_dbg_acct_sanity_check_nolock(c,jeb);
|
||||
jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
|
||||
/* Account for cleanmarker now, if it's in-band */
|
||||
if (c->cleanmarker_size && !jffs2_cleanmarker_oob(c))
|
||||
jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL);
|
||||
|
||||
list_add_tail(&jeb->list, &c->free_list);
|
||||
list_move_tail(&jeb->list, &c->free_list);
|
||||
c->nr_erasing_blocks--;
|
||||
c->nr_free_blocks++;
|
||||
|
||||
jffs2_dbg_acct_sanity_check_nolock(c, jeb);
|
||||
jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
|
||||
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
wake_up(&c->erase_wait);
|
||||
return;
|
||||
|
||||
filebad:
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
/* Stick it on a list (any list) so erase_failed can take it
|
||||
right off again. Silly, but shouldn't happen often. */
|
||||
list_add(&jeb->list, &c->erasing_list);
|
||||
list_move(&jeb->list, &c->erasing_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
jffs2_erase_failed(c, jeb, bad_offset);
|
||||
return;
|
||||
|
||||
refile:
|
||||
/* Stick it back on the list from whence it came and come back later */
|
||||
jffs2_erase_pending_trigger(c);
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
list_add(&jeb->list, &c->erase_complete_list);
|
||||
list_move(&jeb->list, &c->erase_complete_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
+8
-8
@@ -115,9 +115,9 @@ static int jffs2_readpage (struct file *filp, struct page *pg)
|
||||
struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host);
|
||||
int ret;
|
||||
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
ret = jffs2_do_readpage_unlock(pg->mapping->host, pg);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
|
||||
if (ret)
|
||||
goto out_page;
|
||||
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
memset(&ri, 0, sizeof(ri));
|
||||
|
||||
ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
@@ -181,7 +181,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
|
||||
if (IS_ERR(fn)) {
|
||||
ret = PTR_ERR(fn);
|
||||
jffs2_complete_reservation(c);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
goto out_page;
|
||||
}
|
||||
ret = jffs2_add_full_dnode_to_inode(c, f, fn);
|
||||
@@ -195,12 +195,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
|
||||
jffs2_mark_node_obsolete(c, fn->raw);
|
||||
jffs2_free_full_dnode(fn);
|
||||
jffs2_complete_reservation(c);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
goto out_page;
|
||||
}
|
||||
jffs2_complete_reservation(c);
|
||||
inode->i_size = pageofs;
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -209,9 +209,9 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
|
||||
* case of a short-copy.
|
||||
*/
|
||||
if (!PageUptodate(pg)) {
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
ret = jffs2_do_readpage_nolock(inode, pg);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
if (ret)
|
||||
goto out_page;
|
||||
}
|
||||
|
||||
+25
-17
@@ -36,6 +36,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
unsigned int ivalid;
|
||||
uint32_t alloclen;
|
||||
int ret;
|
||||
int alloc_type = ALLOC_NORMAL;
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
|
||||
|
||||
@@ -50,20 +51,20 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
mdata = (char *)&dev;
|
||||
D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
mdatalen = f->metadata->size;
|
||||
mdata = kmalloc(f->metadata->size, GFP_USER);
|
||||
if (!mdata) {
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
|
||||
if (ret) {
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
kfree(mdata);
|
||||
return ret;
|
||||
}
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen));
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
kfree(mdata);
|
||||
return ret;
|
||||
}
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
ivalid = iattr->ia_valid;
|
||||
|
||||
ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
@@ -115,6 +116,10 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
ri->compr = JFFS2_COMPR_ZERO;
|
||||
ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
|
||||
ri->offset = cpu_to_je32(inode->i_size);
|
||||
} else if (ivalid & ATTR_SIZE && !iattr->ia_size) {
|
||||
/* For truncate-to-zero, treat it as deletion because
|
||||
it'll always be obsoleting all previous nodes */
|
||||
alloc_type = ALLOC_DELETION;
|
||||
}
|
||||
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
|
||||
if (mdatalen)
|
||||
@@ -122,14 +127,14 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
else
|
||||
ri->data_crc = cpu_to_je32(0);
|
||||
|
||||
new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, ALLOC_NORMAL);
|
||||
new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type);
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
kfree(mdata);
|
||||
|
||||
if (IS_ERR(new_metadata)) {
|
||||
jffs2_complete_reservation(c);
|
||||
jffs2_free_raw_inode(ri);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
return PTR_ERR(new_metadata);
|
||||
}
|
||||
/* It worked. Update the inode */
|
||||
@@ -149,6 +154,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
|
||||
jffs2_add_full_dnode_to_inode(c, f, new_metadata);
|
||||
inode->i_size = iattr->ia_size;
|
||||
inode->i_blocks = (inode->i_size + 511) >> 9;
|
||||
f->metadata = NULL;
|
||||
} else {
|
||||
f->metadata = new_metadata;
|
||||
@@ -159,7 +165,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
}
|
||||
jffs2_free_raw_inode(ri);
|
||||
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
/* We have to do the vmtruncate() without f->sem held, since
|
||||
@@ -167,8 +173,10 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
|
||||
We are protected from a simultaneous write() extending i_size
|
||||
back past iattr->ia_size, because do_truncate() holds the
|
||||
generic inode semaphore. */
|
||||
if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
|
||||
vmtruncate(inode, iattr->ia_size);
|
||||
if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
|
||||
vmtruncate(inode, iattr->ia_size);
|
||||
inode->i_blocks = (inode->i_size + 511) >> 9;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -248,12 +256,12 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
|
||||
c = JFFS2_SB_INFO(inode->i_sb);
|
||||
|
||||
jffs2_init_inode_info(f);
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
|
||||
ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
|
||||
|
||||
if (ret) {
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
iget_failed(inode);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
@@ -330,7 +338,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
|
||||
printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino);
|
||||
}
|
||||
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
|
||||
unlock_new_inode(inode);
|
||||
@@ -339,7 +347,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
|
||||
error_io:
|
||||
ret = -EIO;
|
||||
error:
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
iget_failed(inode);
|
||||
return ERR_PTR(ret);
|
||||
@@ -380,9 +388,9 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
|
||||
Flush the writebuffer, if neccecary, else we loose it */
|
||||
if (!(sb->s_flags & MS_RDONLY)) {
|
||||
jffs2_stop_garbage_collect_thread(c);
|
||||
down(&c->alloc_sem);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
jffs2_flush_wbuf_pad(c);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
}
|
||||
|
||||
if (!(*flags & MS_RDONLY))
|
||||
@@ -429,7 +437,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
|
||||
|
||||
f = JFFS2_INODE_INFO(inode);
|
||||
jffs2_init_inode_info(f);
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
|
||||
memset(ri, 0, sizeof(*ri));
|
||||
/* Set OS-specific defaults for new inodes */
|
||||
|
||||
+24
-18
@@ -126,7 +126,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
int ret = 0, inum, nlink;
|
||||
int xattr = 0;
|
||||
|
||||
if (down_interruptible(&c->alloc_sem))
|
||||
if (mutex_lock_interruptible(&c->alloc_sem))
|
||||
return -EINTR;
|
||||
|
||||
for (;;) {
|
||||
@@ -143,7 +143,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
c->unchecked_size);
|
||||
jffs2_dbg_dump_block_lists_nolock(c);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
made no progress in this case, but that should be OK */
|
||||
c->checked_ino--;
|
||||
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
|
||||
return 0;
|
||||
|
||||
@@ -210,7 +210,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino);
|
||||
|
||||
jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -221,9 +221,15 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
jeb = jffs2_find_gc_block(c);
|
||||
|
||||
if (!jeb) {
|
||||
D1 (printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
|
||||
/* Couldn't find a free block. But maybe we can just erase one and make 'progress'? */
|
||||
if (!list_empty(&c->erase_pending_list)) {
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return -EAGAIN;
|
||||
}
|
||||
D1(printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -232,7 +238,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size));
|
||||
|
||||
if (!jeb->used_size) {
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
goto eraseit;
|
||||
}
|
||||
|
||||
@@ -248,7 +254,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
|
||||
jeb->gc_node = raw;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
@@ -266,7 +272,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
/* Just mark it obsolete */
|
||||
jffs2_mark_node_obsolete(c, raw);
|
||||
}
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
goto eraseit_lock;
|
||||
}
|
||||
|
||||
@@ -334,7 +340,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
*/
|
||||
printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
|
||||
ic->ino, ic->state);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
spin_unlock(&c->inocache_lock);
|
||||
BUG();
|
||||
|
||||
@@ -345,7 +351,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
the alloc_sem() (for marking nodes invalid) so we must
|
||||
drop the alloc_sem before sleeping. */
|
||||
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
|
||||
ic->ino, ic->state));
|
||||
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
|
||||
@@ -416,7 +422,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
|
||||
ret = -ENOSPC;
|
||||
}
|
||||
release_sem:
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
|
||||
eraseit_lock:
|
||||
/* If we've finished this block, start it erasing */
|
||||
@@ -445,7 +451,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era
|
||||
uint32_t start = 0, end = 0, nrfrags = 0;
|
||||
int ret = 0;
|
||||
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
|
||||
/* Now we have the lock for this inode. Check that it's still the one at the head
|
||||
of the list. */
|
||||
@@ -525,7 +531,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era
|
||||
}
|
||||
}
|
||||
upnout:
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -846,7 +852,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
|
||||
/* Prevent the erase code from nicking the obsolete node refs while
|
||||
we're looking at them. I really don't like this extra lock but
|
||||
can't see any alternative. Suggestions on a postcard to... */
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
|
||||
for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
|
||||
|
||||
@@ -899,7 +905,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
|
||||
/* OK. The name really does match. There really is still an older node on
|
||||
the flash which our deletion dirent obsoletes. So we have to write out
|
||||
a new deletion dirent to replace it */
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
|
||||
D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",
|
||||
ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)));
|
||||
@@ -908,7 +914,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
|
||||
return jffs2_garbage_collect_dirent(c, jeb, f, fd);
|
||||
}
|
||||
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
kfree(rd);
|
||||
}
|
||||
|
||||
@@ -1081,7 +1087,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
|
||||
static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *orig_jeb,
|
||||
struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
|
||||
uint32_t start, uint32_t end)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include "nodelist.h"
|
||||
|
||||
int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
struct jffs2_inode_info {
|
||||
/* We need an internal mutex similar to inode->i_mutex.
|
||||
@@ -24,7 +24,7 @@ struct jffs2_inode_info {
|
||||
before letting GC proceed. Or we'd have to put ugliness
|
||||
into the GC code so it didn't attempt to obtain the i_mutex
|
||||
for the inode(s) which are already locked */
|
||||
struct semaphore sem;
|
||||
struct mutex sem;
|
||||
|
||||
/* The highest (datanode) version number used for this ino */
|
||||
uint32_t highest_version;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/list.h>
|
||||
@@ -44,7 +44,7 @@ struct jffs2_sb_info {
|
||||
struct completion gc_thread_start; /* GC thread start completion */
|
||||
struct completion gc_thread_exit; /* GC thread exit completion port */
|
||||
|
||||
struct semaphore alloc_sem; /* Used to protect all the following
|
||||
struct mutex alloc_sem; /* Used to protect all the following
|
||||
fields, and also to protect against
|
||||
out-of-order writing of nodes. And GC. */
|
||||
uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER
|
||||
@@ -87,6 +87,7 @@ struct jffs2_sb_info {
|
||||
struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */
|
||||
struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */
|
||||
struct list_head erasing_list; /* Blocks which are currently erasing */
|
||||
struct list_head erase_checking_list; /* Blocks which are being checked and marked */
|
||||
struct list_head erase_pending_list; /* Blocks which need erasing now */
|
||||
struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */
|
||||
struct list_head free_list; /* Blocks which are free and ready to be used */
|
||||
@@ -104,7 +105,7 @@ struct jffs2_sb_info {
|
||||
/* Sem to allow jffs2_garbage_collect_deletion_dirent to
|
||||
drop the erase_completion_lock while it's holding a pointer
|
||||
to an obsoleted node. I don't like this. Alternatives welcomed. */
|
||||
struct semaphore erase_free_sem;
|
||||
struct mutex erase_free_sem;
|
||||
|
||||
uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */
|
||||
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ struct jffs2_raw_node_ref
|
||||
xattr_ref or xattr_datum instead. The common part of those structures
|
||||
has NULL in the first word. See jffs2_raw_ref_to_ic() below */
|
||||
uint32_t flash_offset;
|
||||
#define TEST_TOTLEN
|
||||
#undef TEST_TOTLEN
|
||||
#ifdef TEST_TOTLEN
|
||||
uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */
|
||||
#endif
|
||||
|
||||
+13
-11
@@ -48,7 +48,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
minsize = PAD(minsize);
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
|
||||
down(&c->alloc_sem);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));
|
||||
|
||||
@@ -57,7 +57,6 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
/* this needs a little more thought (true <tglx> :)) */
|
||||
while(ret == -EAGAIN) {
|
||||
while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
|
||||
int ret;
|
||||
uint32_t dirty, avail;
|
||||
|
||||
/* calculate real dirty size
|
||||
@@ -82,7 +81,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
dirty, c->unchecked_size, c->sector_size));
|
||||
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
@@ -105,11 +104,11 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
|
||||
avail, blocksneeded * c->sector_size));
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
|
||||
D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
|
||||
c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
|
||||
@@ -117,7 +116,10 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
|
||||
ret = jffs2_garbage_collect_pass(c);
|
||||
if (ret)
|
||||
|
||||
if (ret == -EAGAIN)
|
||||
jffs2_erase_pending_blocks(c, 1);
|
||||
else if (ret)
|
||||
return ret;
|
||||
|
||||
cond_resched();
|
||||
@@ -125,7 +127,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
|
||||
down(&c->alloc_sem);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
}
|
||||
|
||||
@@ -138,7 +140,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
|
||||
if (!ret)
|
||||
ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1);
|
||||
if (ret)
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -463,7 +465,7 @@ void jffs2_complete_reservation(struct jffs2_sb_info *c)
|
||||
{
|
||||
D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n"));
|
||||
jffs2_garbage_collect_trigger(c);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
}
|
||||
|
||||
static inline int on_list(struct list_head *obj, struct list_head *head)
|
||||
@@ -512,7 +514,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
||||
any jffs2_raw_node_refs. So we don't need to stop erases from
|
||||
happening, or protect against people holding an obsolete
|
||||
jffs2_raw_node_ref without the erase_completion_lock. */
|
||||
down(&c->erase_free_sem);
|
||||
mutex_lock(&c->erase_free_sem);
|
||||
}
|
||||
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
@@ -715,7 +717,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
||||
}
|
||||
|
||||
out_erase_sem:
|
||||
up(&c->erase_free_sem);
|
||||
mutex_unlock(&c->erase_free_sem);
|
||||
}
|
||||
|
||||
int jffs2_thread_should_wake(struct jffs2_sb_info *c)
|
||||
|
||||
+20
-18
@@ -825,8 +825,9 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
||||
else // normal case...
|
||||
tn->fn->size = je32_to_cpu(rd->dsize);
|
||||
|
||||
dbg_readinode("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);
|
||||
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);
|
||||
|
||||
@@ -836,13 +837,13 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
|
||||
jffs2_free_tmp_dnode_info(tn);
|
||||
return ret;
|
||||
}
|
||||
#ifdef JFFS2_DBG_READINODE_MESSAGES
|
||||
dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version));
|
||||
#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_readinode("%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);
|
||||
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
|
||||
@@ -1193,7 +1194,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
||||
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. */
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return ret?ret:-EIO;
|
||||
}
|
||||
@@ -1202,7 +1203,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
||||
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));
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -1242,7 +1243,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
||||
f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
|
||||
if (!f->target) {
|
||||
JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize));
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -1255,7 +1256,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
||||
ret = -EIO;
|
||||
kfree(f->target);
|
||||
f->target = NULL;
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -ret;
|
||||
}
|
||||
@@ -1273,14 +1274,14 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
||||
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));
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
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));
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -1289,7 +1290,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
|
||||
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 */
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -1379,12 +1380,13 @@ int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
init_MUTEX_LOCKED(&f->sem);
|
||||
mutex_init(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
f->inocache = ic;
|
||||
|
||||
ret = jffs2_do_read_inode_internal(c, f, &n);
|
||||
if (!ret) {
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_do_clear_inode(c, f);
|
||||
}
|
||||
kfree (f);
|
||||
@@ -1398,7 +1400,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
|
||||
|
||||
jffs2_clear_acl(f);
|
||||
jffs2_xattr_delete_inode(c, f->inocache);
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
deleted = f->inocache && !f->inocache->nlink;
|
||||
|
||||
if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
|
||||
@@ -1430,5 +1432,5 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
|
||||
jffs2_del_ino_cache(c, f->inocache);
|
||||
}
|
||||
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
}
|
||||
|
||||
+7
-7
@@ -47,7 +47,7 @@ static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo)
|
||||
{
|
||||
struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
|
||||
|
||||
init_MUTEX(&ei->sem);
|
||||
mutex_init(&ei->sem);
|
||||
inode_init_once(&ei->vfs_inode);
|
||||
}
|
||||
|
||||
@@ -55,9 +55,9 @@ static int jffs2_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
|
||||
|
||||
down(&c->alloc_sem);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
jffs2_flush_wbuf_pad(c);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -95,8 +95,8 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
|
||||
|
||||
/* Initialize JFFS2 superblock locks, the further initialization will
|
||||
* be done later */
|
||||
init_MUTEX(&c->alloc_sem);
|
||||
init_MUTEX(&c->erase_free_sem);
|
||||
mutex_init(&c->alloc_sem);
|
||||
mutex_init(&c->erase_free_sem);
|
||||
init_waitqueue_head(&c->erase_wait);
|
||||
init_waitqueue_head(&c->inocache_wq);
|
||||
spin_lock_init(&c->erase_completion_lock);
|
||||
@@ -125,9 +125,9 @@ static void jffs2_put_super (struct super_block *sb)
|
||||
|
||||
D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
|
||||
|
||||
down(&c->alloc_sem);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
jffs2_flush_wbuf_pad(c);
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
|
||||
jffs2_sum_exit(c);
|
||||
|
||||
|
||||
+20
-8
@@ -578,8 +578,8 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
|
||||
if (!jffs2_is_writebuffered(c))
|
||||
return 0;
|
||||
|
||||
if (!down_trylock(&c->alloc_sem)) {
|
||||
up(&c->alloc_sem);
|
||||
if (mutex_trylock(&c->alloc_sem)) {
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
|
||||
BUG();
|
||||
}
|
||||
@@ -702,10 +702,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
|
||||
if (!c->wbuf)
|
||||
return 0;
|
||||
|
||||
down(&c->alloc_sem);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
if (!jffs2_wbuf_pending_for_ino(c, ino)) {
|
||||
D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -725,14 +725,14 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
|
||||
} else while (old_wbuf_len &&
|
||||
old_wbuf_ofs == c->wbuf_ofs) {
|
||||
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));
|
||||
|
||||
ret = jffs2_garbage_collect_pass(c);
|
||||
if (ret) {
|
||||
/* GC failed. Flush it with padding instead */
|
||||
down(&c->alloc_sem);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
down_write(&c->wbuf_sem);
|
||||
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
|
||||
/* retry flushing wbuf in case jffs2_wbuf_recover
|
||||
@@ -742,12 +742,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
|
||||
up_write(&c->wbuf_sem);
|
||||
break;
|
||||
}
|
||||
down(&c->alloc_sem);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
}
|
||||
|
||||
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));
|
||||
|
||||
up(&c->alloc_sem);
|
||||
mutex_unlock(&c->alloc_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1236,12 +1236,24 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
|
||||
if (!c->wbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
|
||||
c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
|
||||
if (!c->wbuf_verify) {
|
||||
kfree(c->oobbuf);
|
||||
kfree(c->wbuf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
|
||||
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
|
||||
kfree(c->wbuf_verify);
|
||||
#endif
|
||||
kfree(c->wbuf);
|
||||
}
|
||||
|
||||
|
||||
+26
-26
@@ -137,12 +137,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
|
||||
JFFS2_SUMMARY_INODE_SIZE);
|
||||
} else {
|
||||
/* Locking pain */
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &dummy,
|
||||
alloc_mode, JFFS2_SUMMARY_INODE_SIZE);
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
@@ -285,12 +285,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
|
||||
JFFS2_SUMMARY_DIRENT_SIZE(namelen));
|
||||
} else {
|
||||
/* Locking pain */
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &dummy,
|
||||
alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
@@ -353,7 +353,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||
D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
|
||||
break;
|
||||
}
|
||||
down(&f->sem);
|
||||
mutex_lock(&f->sem);
|
||||
datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
|
||||
cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
|
||||
|
||||
@@ -381,7 +381,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||
|
||||
if (IS_ERR(fn)) {
|
||||
ret = PTR_ERR(fn);
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
if (!retried) {
|
||||
/* Write error to be retried */
|
||||
@@ -403,11 +403,11 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
|
||||
jffs2_mark_node_obsolete(c, fn->raw);
|
||||
jffs2_free_full_dnode(fn);
|
||||
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
break;
|
||||
}
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
if (!datalen) {
|
||||
printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n");
|
||||
@@ -439,7 +439,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
|
||||
JFFS2_SUMMARY_INODE_SIZE);
|
||||
D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
|
||||
if (ret) {
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -454,7 +454,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
|
||||
if (IS_ERR(fn)) {
|
||||
D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
|
||||
/* Eeek. Wave bye bye */
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
return PTR_ERR(fn);
|
||||
}
|
||||
@@ -463,7 +463,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
|
||||
*/
|
||||
f->metadata = fn;
|
||||
|
||||
up(&f->sem);
|
||||
mutex_unlock(&f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode);
|
||||
@@ -489,7 +489,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
down(&dir_f->sem);
|
||||
mutex_lock(&dir_f->sem);
|
||||
|
||||
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
|
||||
@@ -513,7 +513,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
|
||||
/* dirent failed to write. Delete the inode normally
|
||||
as if it were the final unlink() */
|
||||
jffs2_complete_reservation(c);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
return PTR_ERR(fd);
|
||||
}
|
||||
|
||||
@@ -522,7 +522,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
|
||||
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
|
||||
|
||||
jffs2_complete_reservation(c);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -551,7 +551,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
|
||||
return ret;
|
||||
}
|
||||
|
||||
down(&dir_f->sem);
|
||||
mutex_lock(&dir_f->sem);
|
||||
|
||||
/* Build a deletion node */
|
||||
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
@@ -574,21 +574,21 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
|
||||
|
||||
if (IS_ERR(fd)) {
|
||||
jffs2_complete_reservation(c);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
return PTR_ERR(fd);
|
||||
}
|
||||
|
||||
/* File it. This will mark the old one obsolete. */
|
||||
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
} else {
|
||||
struct jffs2_full_dirent *fd = dir_f->dents;
|
||||
uint32_t nhash = full_name_hash(name, namelen);
|
||||
|
||||
fd = dir_f->dents;
|
||||
/* 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);
|
||||
mutex_lock(&c->alloc_sem);
|
||||
mutex_lock(&dir_f->sem);
|
||||
|
||||
for (fd = dir_f->dents; fd; fd = fd->next) {
|
||||
if (fd->nhash == nhash &&
|
||||
@@ -607,7 +607,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
|
||||
break;
|
||||
}
|
||||
}
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
}
|
||||
|
||||
/* dead_f is NULL if this was a rename not a real unlink */
|
||||
@@ -615,7 +615,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
|
||||
pointing to an inode which didn't exist. */
|
||||
if (dead_f && dead_f->inocache) {
|
||||
|
||||
down(&dead_f->sem);
|
||||
mutex_lock(&dead_f->sem);
|
||||
|
||||
if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
|
||||
while (dead_f->dents) {
|
||||
@@ -639,7 +639,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
|
||||
|
||||
dead_f->inocache->nlink--;
|
||||
/* NB: Caller must set inode nlink if appropriate */
|
||||
up(&dead_f->sem);
|
||||
mutex_unlock(&dead_f->sem);
|
||||
}
|
||||
|
||||
jffs2_complete_reservation(c);
|
||||
@@ -666,7 +666,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
|
||||
return ret;
|
||||
}
|
||||
|
||||
down(&dir_f->sem);
|
||||
mutex_lock(&dir_f->sem);
|
||||
|
||||
/* Build a deletion node */
|
||||
rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
|
||||
@@ -691,7 +691,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
|
||||
|
||||
if (IS_ERR(fd)) {
|
||||
jffs2_complete_reservation(c);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
return PTR_ERR(fd);
|
||||
}
|
||||
|
||||
@@ -699,7 +699,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
|
||||
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
|
||||
|
||||
jffs2_complete_reservation(c);
|
||||
up(&dir_f->sem);
|
||||
mutex_unlock(&dir_f->sem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user