diff --git a/fs/Kernel.gni b/fs/Kernel.gni new file mode 100644 index 0000000000000000000000000000000000000000..46df746bcbea52295a0403fd6419af3884934abe --- /dev/null +++ b/fs/Kernel.gni @@ -0,0 +1,57 @@ +# Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used +# to endorse or promote products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +LINUX_KERNEL_FS_JFFS2_SRC_FILES = [ + "//kernel/linux/linux-5.10/fs/jffs2/background.c", + "//kernel/linux/linux-5.10/fs/jffs2/build.c", + "//kernel/linux/linux-5.10/fs/jffs2/compr.c", + "//kernel/linux/linux-5.10/fs/jffs2/compr_rtime.c", + "//kernel/linux/linux-5.10/fs/jffs2/compr_rubin.c", + "//kernel/linux/linux-5.10/fs/jffs2/compr_zlib.c", + "//kernel/linux/linux-5.10/fs/jffs2/debug.c", + "//kernel/linux/linux-5.10/fs/jffs2/dir.c", + "//kernel/linux/linux-5.10/fs/jffs2/erase.c", + "//kernel/linux/linux-5.10/fs/jffs2/file.c", + "//kernel/linux/linux-5.10/fs/jffs2/fs.c", + "//kernel/linux/linux-5.10/fs/jffs2/gc.c", + "//kernel/linux/linux-5.10/fs/jffs2/malloc.c", + "//kernel/linux/linux-5.10/fs/jffs2/nodelist.c", + "//kernel/linux/linux-5.10/fs/jffs2/nodemgmt.c", + "//kernel/linux/linux-5.10/fs/jffs2/read.c", + "//kernel/linux/linux-5.10/fs/jffs2/readinode.c", + "//kernel/linux/linux-5.10/fs/jffs2/scan.c", + "//kernel/linux/linux-5.10/fs/jffs2/summary.c", + "//kernel/linux/linux-5.10/fs/jffs2/super.c", + "//kernel/linux/linux-5.10/fs/jffs2/write.c", + "//kernel/linux/linux-5.10/fs/jffs2/writev.c", +] + +LINUX_KERNEL_FS_JFFS2_INCLUDE_DIRS = [ + "//kernel/linux/linux-5.10/fs", + "//kernel/linux/linux-5.10/fs/jffs2", +] diff --git a/fs/aio.c b/fs/aio.c index 5e5333d72c6997a8aa45f3822638c2d2cdef0eb6..bd182bcca23ae185d0699f7cc894bb0f590214b9 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -182,9 +182,8 @@ struct poll_iocb { struct file *file; struct wait_queue_head *head; __poll_t events; + bool done; bool cancelled; - bool work_scheduled; - bool work_need_resched; struct wait_queue_entry wait; struct work_struct work; }; @@ -1622,51 +1621,6 @@ static void aio_poll_put_work(struct work_struct *work) iocb_put(iocb); } -/* - * Safely lock the waitqueue which the request is on, synchronizing with the - * case where the ->poll() provider decides to free its waitqueue early. - * - * Returns true on success, meaning that req->head->lock was locked, req->wait - * is on req->head, and an RCU read lock was taken. Returns false if the - * request was already removed from its waitqueue (which might no longer exist). - */ -static bool poll_iocb_lock_wq(struct poll_iocb *req) -{ - wait_queue_head_t *head; - - /* - * While we hold the waitqueue lock and the waitqueue is nonempty, - * wake_up_pollfree() will wait for us. However, taking the waitqueue - * lock in the first place can race with the waitqueue being freed. - * - * We solve this as eventpoll does: by taking advantage of the fact that - * all users of wake_up_pollfree() will RCU-delay the actual free. If - * we enter rcu_read_lock() and see that the pointer to the queue is - * non-NULL, we can then lock it without the memory being freed out from - * under us, then check whether the request is still on the queue. - * - * Keep holding rcu_read_lock() as long as we hold the queue lock, in - * case the caller deletes the entry from the queue, leaving it empty. - * In that case, only RCU prevents the queue memory from being freed. - */ - rcu_read_lock(); - head = smp_load_acquire(&req->head); - if (head) { - spin_lock(&head->lock); - if (!list_empty(&req->wait.entry)) - return true; - spin_unlock(&head->lock); - } - rcu_read_unlock(); - return false; -} - -static void poll_iocb_unlock_wq(struct poll_iocb *req) -{ - spin_unlock(&req->head->lock); - rcu_read_unlock(); -} - static void aio_poll_complete_work(struct work_struct *work) { struct poll_iocb *req = container_of(work, struct poll_iocb, work); @@ -1686,27 +1640,14 @@ static void aio_poll_complete_work(struct work_struct *work) * avoid further branches in the fast path. */ spin_lock_irq(&ctx->ctx_lock); - if (poll_iocb_lock_wq(req)) { - if (!mask && !READ_ONCE(req->cancelled)) { - /* - * The request isn't actually ready to be completed yet. - * Reschedule completion if another wakeup came in. - */ - if (req->work_need_resched) { - schedule_work(&req->work); - req->work_need_resched = false; - } else { - req->work_scheduled = false; - } - poll_iocb_unlock_wq(req); - spin_unlock_irq(&ctx->ctx_lock); - return; - } - list_del_init(&req->wait.entry); - poll_iocb_unlock_wq(req); - } /* else, POLLFREE has freed the waitqueue, so we must complete */ + if (!mask && !READ_ONCE(req->cancelled)) { + add_wait_queue(req->head, &req->wait); + spin_unlock_irq(&ctx->ctx_lock); + return; + } list_del_init(&iocb->ki_list); iocb->ki_res.res = mangle_poll(mask); + req->done = true; spin_unlock_irq(&ctx->ctx_lock); iocb_put(iocb); @@ -1718,14 +1659,13 @@ static int aio_poll_cancel(struct kiocb *iocb) struct aio_kiocb *aiocb = container_of(iocb, struct aio_kiocb, rw); struct poll_iocb *req = &aiocb->poll; - if (poll_iocb_lock_wq(req)) { - WRITE_ONCE(req->cancelled, true); - if (!req->work_scheduled) { - schedule_work(&aiocb->poll.work); - req->work_scheduled = true; - } - poll_iocb_unlock_wq(req); - } /* else, the request was force-cancelled by POLLFREE already */ + spin_lock(&req->head->lock); + WRITE_ONCE(req->cancelled, true); + if (!list_empty(&req->wait.entry)) { + list_del_init(&req->wait.entry); + schedule_work(&aiocb->poll.work); + } + spin_unlock(&req->head->lock); return 0; } @@ -1742,26 +1682,20 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, if (mask && !(mask & req->events)) return 0; - /* - * Complete the request inline if possible. This requires that three - * conditions be met: - * 1. An event mask must have been passed. If a plain wakeup was done - * instead, then mask == 0 and we have to call vfs_poll() to get - * the events, so inline completion isn't possible. - * 2. The completion work must not have already been scheduled. - * 3. ctx_lock must not be busy. We have to use trylock because we - * already hold the waitqueue lock, so this inverts the normal - * locking order. Use irqsave/irqrestore because not all - * filesystems (e.g. fuse) call this function with IRQs disabled, - * yet IRQs have to be disabled before ctx_lock is obtained. - */ - if (mask && !req->work_scheduled && - spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) { + list_del_init(&req->wait.entry); + + if (mask && spin_trylock_irqsave(&iocb->ki_ctx->ctx_lock, flags)) { struct kioctx *ctx = iocb->ki_ctx; - list_del_init(&req->wait.entry); + /* + * Try to complete the iocb inline if we can. Use + * irqsave/irqrestore because not all filesystems (e.g. fuse) + * call this function with IRQs disabled and because IRQs + * have to be disabled before ctx_lock is obtained. + */ list_del(&iocb->ki_list); iocb->ki_res.res = mangle_poll(mask); + req->done = true; if (iocb->ki_eventfd && eventfd_signal_count()) { iocb = NULL; INIT_WORK(&req->work, aio_poll_put_work); @@ -1771,43 +1705,7 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, if (iocb) iocb_put(iocb); } else { - /* - * Schedule the completion work if needed. If it was already - * scheduled, record that another wakeup came in. - * - * Don't remove the request from the waitqueue here, as it might - * not actually be complete yet (we won't know until vfs_poll() - * is called), and we must not miss any wakeups. POLLFREE is an - * exception to this; see below. - */ - if (req->work_scheduled) { - req->work_need_resched = true; - } else { - schedule_work(&req->work); - req->work_scheduled = true; - } - - /* - * If the waitqueue is being freed early but we can't complete - * the request inline, we have to tear down the request as best - * we can. That means immediately removing the request from its - * waitqueue and preventing all further accesses to the - * waitqueue via the request. We also need to schedule the - * completion work (done above). Also mark the request as - * cancelled, to potentially skip an unneeded call to ->poll(). - */ - if (mask & POLLFREE) { - WRITE_ONCE(req->cancelled, true); - list_del_init(&req->wait.entry); - - /* - * Careful: this *must* be the last step, since as soon - * as req->head is NULL'ed out, the request can be - * completed and freed, since aio_poll_complete_work() - * will no longer need to take the waitqueue lock. - */ - smp_store_release(&req->head, NULL); - } + schedule_work(&req->work); } return 1; } @@ -1815,7 +1713,6 @@ static int aio_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, struct aio_poll_table { struct poll_table_struct pt; struct aio_kiocb *iocb; - bool queued; int error; }; @@ -1826,12 +1723,11 @@ aio_poll_queue_proc(struct file *file, struct wait_queue_head *head, struct aio_poll_table *pt = container_of(p, struct aio_poll_table, pt); /* multiple wait queues per file are not supported */ - if (unlikely(pt->queued)) { + if (unlikely(pt->iocb->poll.head)) { pt->error = -EINVAL; return; } - pt->queued = true; pt->error = 0; pt->iocb->poll.head = head; add_wait_queue(head, &pt->iocb->poll.wait); @@ -1856,14 +1752,12 @@ static int aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb) req->events = demangle_poll(iocb->aio_buf) | EPOLLERR | EPOLLHUP; req->head = NULL; + req->done = false; req->cancelled = false; - req->work_scheduled = false; - req->work_need_resched = false; apt.pt._qproc = aio_poll_queue_proc; apt.pt._key = req->events; apt.iocb = aiocb; - apt.queued = false; apt.error = -EINVAL; /* same as no support for IOCB_CMD_POLL */ /* initialized the list so that we can do list_empty checks */ @@ -1872,35 +1766,23 @@ static int aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb) mask = vfs_poll(req->file, &apt.pt) & req->events; spin_lock_irq(&ctx->ctx_lock); - if (likely(apt.queued)) { - bool on_queue = poll_iocb_lock_wq(req); - - if (!on_queue || req->work_scheduled) { - /* - * aio_poll_wake() already either scheduled the async - * completion work, or completed the request inline. - */ - if (apt.error) /* unsupported case: multiple queues */ + if (likely(req->head)) { + spin_lock(&req->head->lock); + if (unlikely(list_empty(&req->wait.entry))) { + if (apt.error) cancel = true; apt.error = 0; mask = 0; } if (mask || apt.error) { - /* Steal to complete synchronously. */ list_del_init(&req->wait.entry); } else if (cancel) { - /* Cancel if possible (may be too late though). */ WRITE_ONCE(req->cancelled, true); - } else if (on_queue) { - /* - * Actually waiting for an event, so add the request to - * active_reqs so that it can be cancelled if needed. - */ + } else if (!req->done) { /* actually waiting for an event */ list_add_tail(&aiocb->ki_list, &ctx->active_reqs); aiocb->ki_cancel = aio_poll_cancel; } - if (on_queue) - poll_iocb_unlock_wq(req); + spin_unlock(&req->head->lock); } if (mask) { /* no async, we'd stolen it */ aiocb->ki_res.res = mangle_poll(mask); diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 12d0271bdde387cf07e7a6a3853b4a7c9d3861f1..1050be0066cbf5d0fc67e9797da056d9dd42705d 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h @@ -8,6 +8,8 @@ * For licensing information, see the file 'LICENCE' in this directory. * */ +#ifndef _JFFS2_ACL_H_ +#define _JFFS2_ACL_H_ struct jffs2_acl_entry { jint16_t e_tag; @@ -27,11 +29,6 @@ struct jffs2_acl_header { #ifdef CONFIG_JFFS2_FS_POSIX_ACL -struct posix_acl *jffs2_get_acl(struct inode *inode, int type); -int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type); -extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *); -extern int jffs2_init_acl_post(struct inode *); - #else #define jffs2_get_acl (NULL) @@ -40,3 +37,4 @@ extern int jffs2_init_acl_post(struct inode *); #define jffs2_init_acl_post(inode) (0) #endif /* CONFIG_JFFS2_FS_POSIX_ACL */ +#endif /* _JFFS2_ACL_H_ */ diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 2b4d5013dc5d0b48a38514ca602169ea1cdc7274..8ea7877b59c769d543eb4ce21c0f62050a05faf4 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -10,156 +10,113 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include -#include -#include -#include -#include -#include -#include +#include #include "nodelist.h" +#include "vfs_jffs2.h" +#include "mtd_partition.h" +#define GC_THREAD_FLAG_TRIG 1 +#define GC_THREAD_FLAG_STOP 2 +#define GC_THREAD_FLAG_HAS_EXIT 4 -static int jffs2_garbage_collect_thread(void *); +extern struct MtdNorDev jffs2_dev_list[CONFIG_MTD_PATTITION_NUM]; +static void jffs2_garbage_collect_thread(unsigned long data); void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) { - assert_spin_locked(&c->erase_completion_lock); - if (c->gc_task && jffs2_thread_should_wake(c)) - send_sig(SIGHUP, c->gc_task, 1); + struct super_block *sb = OFNI_BS_2SFFJ(c); + /* Wake up the thread */ + jffs2_dbg(1, "jffs2_garbage_collect_trigger\n"); + LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_TRIG); } /* This must only ever be called when no GC thread is currently running */ -int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) +void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) { - struct task_struct *tsk; - int ret = 0; - - BUG_ON(c->gc_task); - - init_completion(&c->gc_thread_start); - init_completion(&c->gc_thread_exit); - - tsk = kthread_run(jffs2_garbage_collect_thread, c, "jffs2_gcd_mtd%d", c->mtd->index); - if (IS_ERR(tsk)) { - pr_warn("fork failed for JFFS2 garbage collect thread: %ld\n", - -PTR_ERR(tsk)); - complete(&c->gc_thread_exit); - ret = PTR_ERR(tsk); - } else { - /* Wait for it... */ - jffs2_dbg(1, "Garbage collect thread is pid %d\n", tsk->pid); - wait_for_completion(&c->gc_thread_start); - ret = tsk->pid; + struct super_block *sb = OFNI_BS_2SFFJ(c); + TSK_INIT_PARAM_S stGcTask; + + if (c == NULL) + return; + + if (sb->s_root == NULL) + return; + + LOS_EventInit(&sb->s_gc_thread_flags); + + /* Start the thread. Doesn't matter if it fails -- it's only an + * optimisation anyway */ + (void)memset_s(&stGcTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); + + stGcTask.pfnTaskEntry = (TSK_ENTRY_FUNC)jffs2_garbage_collect_thread; + stGcTask.auwArgs[0] = (UINTPTR)c; + stGcTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; + stGcTask.pcName = "jffs2_gc_thread"; +#ifdef LOSCFG_KERNEL_SMP + unsigned int i; + for (i = 0; i < CONFIG_MTD_PATTITION_NUM; i++) { + if (sb->s_dev == &jffs2_dev_list[i]) + break; } + stGcTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(i % LOSCFG_KERNEL_CORE_NUM); +#endif + stGcTask.usTaskPrio = JFFS2_GC_THREAD_PRIORITY; - return ret; + if (LOS_TaskCreate(&sb->s_gc_thread, &stGcTask)) + JFFS2_ERROR("Create gc task failed!!!\n"); } void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) { - int wait = 0; - spin_lock(&c->erase_completion_lock); - if (c->gc_task) { - jffs2_dbg(1, "Killing GC task %d\n", c->gc_task->pid); - send_sig(SIGKILL, c->gc_task, 1); - wait = 1; - } - spin_unlock(&c->erase_completion_lock); - if (wait) - wait_for_completion(&c->gc_thread_exit); + struct super_block *sb = OFNI_BS_2SFFJ(c); + + JFFS2_DEBUG("jffs2_stop_garbage_collect_thread\n"); + /* Stop the thread and wait for it if necessary */ + + LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_STOP); + + JFFS2_DEBUG("jffs2_stop_garbage_collect_thread wait\n"); + + (void)LOS_EventRead(&sb->s_gc_thread_flags, + GC_THREAD_FLAG_HAS_EXIT, + LOS_WAITMODE_OR | LOS_WAITMODE_CLR, + LOS_WAIT_FOREVER); + + // Kill and free the resources ... this is safe due to the flag + // from the thread. + (void)LOS_TaskDelete(sb->s_gc_thread); + (void)LOS_EventWrite(&sb->s_gc_thread_flags, 0xFFFFFFFF); } -static int jffs2_garbage_collect_thread(void *_c) +static void jffs2_garbage_collect_thread(unsigned long data) { - struct jffs2_sb_info *c = _c; - sigset_t hupmask; - - siginitset(&hupmask, sigmask(SIGHUP)); - allow_signal(SIGKILL); - allow_signal(SIGSTOP); - allow_signal(SIGHUP); - - c->gc_task = current; - complete(&c->gc_thread_start); - - set_user_nice(current, 10); - - set_freezable(); - for (;;) { - sigprocmask(SIG_UNBLOCK, &hupmask, NULL); - again: - spin_lock(&c->erase_completion_lock); - if (!jffs2_thread_should_wake(c)) { - set_current_state (TASK_INTERRUPTIBLE); - spin_unlock(&c->erase_completion_lock); - jffs2_dbg(1, "%s(): sleeping...\n", __func__); - schedule(); - } else { - spin_unlock(&c->erase_completion_lock); - } - /* Problem - immediately after bootup, the GCD spends a lot - * of time in places like jffs2_kill_fragtree(); so much so - * that userspace processes (like gdm and X) are starved - * despite plenty of cond_resched()s and renicing. Yield() - * doesn't help, either (presumably because userspace and GCD - * are generally competing for a higher latency resource - - * disk). - * This forces the GCD to slow the hell down. Pulling an - * inode in with read_inode() is much preferable to having - * the GC thread get there first. */ - schedule_timeout_interruptible(msecs_to_jiffies(50)); - - if (kthread_should_stop()) { - jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__); - goto die; - } + struct jffs2_sb_info *c = (struct jffs2_sb_info *)data; + struct super_block *sb = OFNI_BS_2SFFJ(c); + unsigned int flag = 0; - /* Put_super will send a SIGKILL and then wait on the sem. - */ - while (signal_pending(current) || freezing(current)) { - unsigned long signr; - - if (try_to_freeze()) - goto again; - - signr = kernel_dequeue_signal(); - - switch(signr) { - case SIGSTOP: - jffs2_dbg(1, "%s(): SIGSTOP received\n", - __func__); - kernel_signal_stop(); - break; - - case SIGKILL: - jffs2_dbg(1, "%s(): SIGKILL received\n", - __func__); - goto die; - - case SIGHUP: - jffs2_dbg(1, "%s(): SIGHUP received\n", - __func__); - break; - default: - jffs2_dbg(1, "%s(): signal %ld received\n", - __func__, signr); - } - } - /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */ - sigprocmask(SIG_BLOCK, &hupmask, NULL); + jffs2_dbg(1, "jffs2_garbage_collect_thread START\n"); + while(1) { + flag = LOS_EventRead(&sb->s_gc_thread_flags, + GC_THREAD_FLAG_TRIG | GC_THREAD_FLAG_STOP, + LOS_WAITMODE_OR | LOS_WAITMODE_CLR, + LOS_WAIT_FOREVER + ); + if (flag & GC_THREAD_FLAG_STOP) + break; + + jffs2_dbg(1, "jffs2: GC THREAD GC BEGIN\n"); + + if (sb->s_root == NULL) + return; - jffs2_dbg(1, "%s(): pass\n", __func__); if (jffs2_garbage_collect_pass(c) == -ENOSPC) { - pr_notice("No space for garbage collection. Aborting GC thread\n"); - goto die; + PRINTK("No space for garbage collection. " + "Aborting JFFS2 GC thread\n"); + break; } + jffs2_dbg(1, "jffs2: GC THREAD GC END\n"); } - die: - spin_lock(&c->erase_completion_lock); - c->gc_task = NULL; - spin_unlock(&c->erase_completion_lock); - complete_and_exit(&c->gc_thread_exit, 0); + JFFS2_DEBUG("jffs2_garbage_collect_thread EXIT\n"); + LOS_EventWrite(&sb->s_gc_thread_flags, GC_THREAD_FLAG_HAS_EXIT); } diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index b288c8ae1236b0f81f271e0fcfcaf5ee246b2933..1ae70b334943d8827a391c4145b81e890a720e09 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -10,15 +10,13 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include #include #include #include -#include -#include -#include /* kvfree() */ +#include #include "nodelist.h" +#include "los_exc.h" static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **); @@ -372,20 +370,24 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) int ret; int i; int size; + struct super_block *sb; + struct MtdNorDev *device; c->free_size = c->flash_size; c->nr_blocks = c->flash_size / c->sector_size; - size = sizeof(struct jffs2_eraseblock) * c->nr_blocks; + sb = OFNI_BS_2SFFJ(c); + device = (struct MtdNorDev *)(sb->s_dev); + size = sizeof(struct jffs2_eraseblock) *(c->nr_blocks + device->blockStart); #ifndef __ECOS if (jffs2_blocks_use_vmalloc(c)) - c->blocks = vzalloc(size); + c->blocks = malloc(size); else #endif c->blocks = kzalloc(size, GFP_KERNEL); if (!c->blocks) return -ENOMEM; - for (i=0; inr_blocks; i++) { + for (i = device->blockStart; i < c->nr_blocks + device->blockStart; i++) { INIT_LIST_HEAD(&c->blocks[i].list); c->blocks[i].offset = i * c->sector_size; c->blocks[i].free_size = c->sector_size; @@ -423,7 +425,16 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) return 0; out_free: - kvfree(c->blocks); +#ifndef __ECOS + if (jffs2_blocks_use_vmalloc(c)) +#ifdef LOSCFG_KERNEL_VM + LOS_VFree(c->blocks); +#else + free(c->blocks); +#endif + else +#endif + kfree(c->blocks); return ret; } diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 4849a4c9a0e24f1b8b4202630d68e491eac113dc..cf710480a3752a515c567db86521d705b059610a 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -12,14 +12,13 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include "compr.h" +#include "jffs2.h" +#include "user_copy.h" -static DEFINE_SPINLOCK(jffs2_compressor_list_lock); - +static spinlock_t jffs2_compressor_list_lock; /* Available compressors are on this list */ -static LIST_HEAD(jffs2_compressor_list); +static LINUX_LIST_HEAD(jffs2_compressor_list); /* Actual compression mode */ static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; @@ -71,15 +70,15 @@ static int jffs2_is_best_compression(struct jffs2_compressor *this, * could not be compressed; probably because we couldn't find the requested * compression mode. */ -static int jffs2_selected_compress(u8 compr, unsigned char *data_in, - unsigned char **cpage_out, u32 *datalen, u32 *cdatalen) +static int jffs2_selected_compress(uint8_t compr, unsigned char *data_in, + unsigned char **cpage_out, uint32_t *datalen, uint32_t *cdatalen) { struct jffs2_compressor *this; int err, ret = JFFS2_COMPR_NONE; uint32_t orig_slen, orig_dlen; - char *output_buf; + unsigned char *output_buf; - output_buf = kmalloc(*cdatalen, GFP_KERNEL); + output_buf = kmalloc(*cdatalen,GFP_KERNEL); if (!output_buf) { pr_warn("No memory for compressor allocation. Compression failed.\n"); return ret; @@ -265,11 +264,16 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, switch (comprtype & 0xff) { case JFFS2_COMPR_NONE: /* This should be special-cased elsewhere, but we might as well deal with it */ - memcpy(data_out, cdata_in, datalen); + if (LOS_CopyFromKernel(data_out, datalen, cdata_in, datalen) != 0) { + return -EFAULT; + } none_stat_decompr_blocks++; break; case JFFS2_COMPR_ZERO: - memset(data_out, 0, datalen); + ret = LOS_UserMemClear(data_out, datalen); + if (ret != 0) { + return ret; + } break; default: spin_lock(&jffs2_compressor_list_lock); diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 5e91d578f4ed858c2ac575f375619000c5c6814c..7a8e89fd9bcab9e37c3ad7cfcca7f9a73758d4ac 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -13,18 +13,20 @@ #define __JFFS2_COMPR_H__ #include -#include #include #include #include #include #include -#include -#include -#include "jffs2_fs_i.h" -#include "jffs2_fs_sb.h" +#include #include "nodelist.h" +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + #define JFFS2_RUBINMIPS_PRIORITY 10 #define JFFS2_DYNRUBIN_PRIORITY 20 #define JFFS2_LZARI_PRIORITY 30 @@ -102,4 +104,10 @@ int jffs2_lzo_init(void); void jffs2_lzo_exit(void); #endif +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + #endif /* __JFFS2_COMPR_H__ */ diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 79e771ab624f47d7bb20323941a6a22e9c643127..357bd91df3c84c2958e38f22dc8449dc6ae01022 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include "jffs2.h" #include "compr.h" /* _compress returns the compressed size, -1 if bigger */ diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index 556de100ebd5a5318fec58cc47c6187315ed2b7b..1dcd106b30310820df59c8508f76f7f9c358f113 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c @@ -10,15 +10,12 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include -#include #include +#include "jffs2.h" #include "compr.h" - #define RUBIN_REG_SIZE 16 #define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1)) #define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1) @@ -48,7 +45,7 @@ static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve) { - pp->buf = buf; + pp->buf = (unsigned char *)buf; pp->buflen = buflen; pp->ofs = ofs; pp->reserve = reserve; @@ -267,7 +264,7 @@ static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, int pos=0; struct rubin_state rs; - init_pushpull(&rs.pp, cpage_out, *dstlen * 8, 0, 32); + init_pushpull(&rs.pp, (char *)cpage_out, *dstlen * 8, 0, 32); init_rubin(&rs, bit_divider, bits); @@ -366,14 +363,14 @@ static int jffs2_dynrubin_compress(unsigned char *data_in, } static void rubin_do_decompress(int bit_divider, int *bits, - unsigned char *cdata_in, + unsigned char *cdata_in, unsigned char *page_out, uint32_t srclen, uint32_t destlen) { int outpos = 0; struct rubin_state rs; - init_pushpull(&rs.pp, cdata_in, srclen, 0, 0); + init_pushpull(&rs.pp, (char *)cdata_in, srclen, 0, 0); init_decode(&rs, bit_divider, bits); while (outpos < destlen) diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 5698dae5d92dd5f7c3b8db3674348ae80fea45f0..2a38a6b6619025b8fb0c5fac5a3a7084354e8f71 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -10,15 +10,10 @@ * */ -#if !defined(__KERNEL__) && !defined(__ECOS) -#error "The userspace support got too messy and was removed. Update your mkfs.jffs2" -#endif - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include -#include +#include #include +#include #include "nodelist.h" #include "compr.h" @@ -35,39 +30,8 @@ static DEFINE_MUTEX(deflate_mutex); static DEFINE_MUTEX(inflate_mutex); static z_stream inf_strm, def_strm; -#ifdef __KERNEL__ /* Linux-only */ -#include -#include -#include - -static int __init alloc_workspaces(void) -{ - def_strm.workspace = vmalloc(zlib_deflate_workspacesize(MAX_WBITS, - MAX_MEM_LEVEL)); - if (!def_strm.workspace) - return -ENOMEM; - - jffs2_dbg(1, "Allocated %d bytes for deflate workspace\n", - zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)); - inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); - if (!inf_strm.workspace) { - vfree(def_strm.workspace); - return -ENOMEM; - } - jffs2_dbg(1, "Allocated %d bytes for inflate workspace\n", - zlib_inflate_workspacesize()); - return 0; -} - -static void free_workspaces(void) -{ - vfree(def_strm.workspace); - vfree(inf_strm.workspace); -} -#else #define alloc_workspaces() (0) #define free_workspaces() do { } while(0) -#endif /* __KERNEL__ */ static int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, @@ -80,7 +44,7 @@ static int jffs2_zlib_compress(unsigned char *data_in, mutex_lock(&deflate_mutex); - if (Z_OK != zlib_deflateInit(&def_strm, 3)) { + if (Z_OK != deflateInit(&def_strm, 3)) { pr_warn("deflateInit failed\n"); mutex_unlock(&deflate_mutex); return -1; @@ -98,21 +62,21 @@ static int jffs2_zlib_compress(unsigned char *data_in, (*sourcelen-def_strm.total_in), def_strm.avail_out); jffs2_dbg(1, "calling deflate with avail_in %ld, avail_out %ld\n", def_strm.avail_in, def_strm.avail_out); - ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); + ret = deflate(&def_strm, Z_PARTIAL_FLUSH); jffs2_dbg(1, "deflate returned with avail_in %ld, avail_out %ld, total_in %ld, total_out %ld\n", def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out); if (ret != Z_OK) { jffs2_dbg(1, "deflate in loop returned %d\n", ret); - zlib_deflateEnd(&def_strm); + deflateEnd(&def_strm); mutex_unlock(&deflate_mutex); return -1; } } def_strm.avail_out += STREAM_END_SPACE; def_strm.avail_in = 0; - ret = zlib_deflate(&def_strm, Z_FINISH); - zlib_deflateEnd(&def_strm); + ret = deflate(&def_strm, Z_FINISH); + deflateEnd(&def_strm); if (ret != Z_STREAM_END) { jffs2_dbg(1, "final deflate returned %d\n", ret); @@ -171,18 +135,18 @@ static int jffs2_zlib_decompress(unsigned char *data_in, } - if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) { + if (Z_OK != inflateInit2(&inf_strm, wbits)) { pr_warn("inflateInit failed\n"); mutex_unlock(&inflate_mutex); return 1; } - while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK) + while((ret = inflate(&inf_strm, Z_FINISH)) == Z_OK) ; if (ret != Z_STREAM_END) { pr_notice("inflate returned %d\n", ret); } - zlib_inflateEnd(&inf_strm); + inflateEnd(&inf_strm); mutex_unlock(&inflate_mutex); return 0; } @@ -204,13 +168,30 @@ int __init jffs2_zlib_init(void) { int ret; + ret = pthread_mutex_init(&inflate_mutex, NULL); + if (ret) { + return ret; + } + + ret = pthread_mutex_init(&deflate_mutex, NULL); + if (ret) { + pthread_mutex_destroy(&inflate_mutex); + return ret; + } + ret = alloc_workspaces(); - if (ret) - return ret; + if (ret) { + pthread_mutex_destroy(&inflate_mutex); + pthread_mutex_destroy(&deflate_mutex); + return ret; + } ret = jffs2_register_compressor(&jffs2_zlib_comp); - if (ret) - free_workspaces(); + if (ret) { + pthread_mutex_destroy(&inflate_mutex); + pthread_mutex_destroy(&deflate_mutex); + free_workspaces(); + } return ret; } @@ -219,4 +200,6 @@ void jffs2_zlib_exit(void) { jffs2_unregister_compressor(&jffs2_zlib_comp); free_workspaces(); + pthread_mutex_destroy(&inflate_mutex); + pthread_mutex_destroy(&deflate_mutex); } diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index 9d26b1b9fc014e847f4748e7b29e11b9091e7ef9..7e93fe638502d4dac863e268b14de29a16195a8c 100644 --- a/fs/jffs2/debug.c +++ b/fs/jffs2/debug.c @@ -10,15 +10,12 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include -#include -#include -#include #include +#include +#include "los_crc32.h" #include "nodelist.h" #include "debug.h" @@ -133,7 +130,7 @@ __jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c, if (!buf) return; - ret = jffs2_flash_read(c, ofs, len, &retlen, buf); + ret = jffs2_flash_read(c, ofs, len, &retlen, (char *)buf); if (ret || (retlen != len)) { JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n", len, ret, retlen); @@ -780,7 +777,7 @@ __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs) printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs); - ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node); + ret = jffs2_flash_read(c, ofs, len, &retlen, (char *)&node); if (ret || (retlen != len)) { JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n", len, ret, retlen); diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index 4fd9be4cbc984a56b6b8bbb85c3d97d8c8a3166c..e15a05951a2e1fa07252ecd471f0e66259add032 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h @@ -14,7 +14,12 @@ #define _JFFS2_DEBUG_H_ #include - +#include "los_process.h" +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ #ifndef CONFIG_JFFS2_FS_DEBUG #define CONFIG_JFFS2_FS_DEBUG 0 #endif @@ -71,25 +76,26 @@ do { \ /* The prefixes of JFFS2 messages */ #define JFFS2_DBG KERN_DEBUG +#define JFFS2_DBG_LVL KERN_DEBUG #define JFFS2_DBG_PREFIX "[JFFS2 DBG]" #define JFFS2_DBG_MSG_PREFIX JFFS2_DBG JFFS2_DBG_PREFIX /* JFFS2 message macros */ #define JFFS2_ERROR(fmt, ...) \ - pr_err("error: (%d) %s: " fmt, \ - task_pid_nr(current), __func__, ##__VA_ARGS__) + pr_err("error: (%u) %s: " fmt, \ + LOS_GetCurrProcessID, __func__, ##__VA_ARGS__) #define JFFS2_WARNING(fmt, ...) \ - pr_warn("warning: (%d) %s: " fmt, \ - task_pid_nr(current), __func__, ##__VA_ARGS__) + pr_warn("warning: (%u) %s: " fmt, \ + LOS_GetCurrProcessID, __func__, ##__VA_ARGS__) #define JFFS2_NOTICE(fmt, ...) \ - pr_notice("notice: (%d) %s: " fmt, \ - task_pid_nr(current), __func__, ##__VA_ARGS__) + pr_notice("notice: (%u) %s: " fmt, \ + LOS_GetCurrProcessID, __func__, ##__VA_ARGS__) #define JFFS2_DEBUG(fmt, ...) \ - printk(KERN_DEBUG "[JFFS2 DBG] (%d) %s: " fmt, \ - task_pid_nr(current), __func__, ##__VA_ARGS__) + printk(KERN_DEBUG "[JFFS2 DBG] (%u) %s: " fmt, \ + LOS_GetCurrProcessID, __func__, ##__VA_ARGS__) /* * We split our debugging messages on several parts, depending on the JFFS2 @@ -272,4 +278,10 @@ __jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs); #define jffs2_dbg_acct_sanity_check_nolock(c, jeb) #endif /* !JFFS2_DBG_SANITY_CHECKS */ +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + #endif /* _JFFS2_DEBUG_H_ */ diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 776493713153f97b2e12942726b55ca6bfa877a5..fc038e834f494db5dab20006bb50e4793dd47688 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -10,95 +10,42 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include #include #include #include -#include -#include -#include "jffs2_fs_i.h" -#include "jffs2_fs_sb.h" -#include +#include "los_crc32.h" #include "nodelist.h" - -static int jffs2_readdir (struct file *, struct dir_context *); - -static int jffs2_create (struct inode *,struct dentry *,umode_t, - bool); -static struct dentry *jffs2_lookup (struct inode *,struct dentry *, - unsigned int); -static int jffs2_link (struct dentry *,struct inode *,struct dentry *); -static int jffs2_unlink (struct inode *,struct dentry *); -static int jffs2_symlink (struct inode *,struct dentry *,const char *); -static int jffs2_mkdir (struct inode *,struct dentry *,umode_t); -static int jffs2_rmdir (struct inode *,struct dentry *); -static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t); -static int jffs2_rename (struct inode *, struct dentry *, - struct inode *, struct dentry *, - unsigned int); - -const struct file_operations jffs2_dir_operations = -{ - .read = generic_read_dir, - .iterate_shared=jffs2_readdir, - .unlocked_ioctl=jffs2_ioctl, - .fsync = jffs2_fsync, - .llseek = generic_file_llseek, -}; - - -const struct inode_operations jffs2_dir_inode_operations = -{ - .create = jffs2_create, - .lookup = jffs2_lookup, - .link = jffs2_link, - .unlink = jffs2_unlink, - .symlink = jffs2_symlink, - .mkdir = jffs2_mkdir, - .rmdir = jffs2_rmdir, - .mknod = jffs2_mknod, - .rename = jffs2_rename, - .get_acl = jffs2_get_acl, - .set_acl = jffs2_set_acl, - .setattr = jffs2_setattr, - .listxattr = jffs2_listxattr, -}; - -/***********************************************************************/ - +#include "vfs_jffs2.h" +#include "jffs2_hash.h" /* We keep the dirent list sorted in increasing order of name hash, and we use the same hash function as the dentries. Makes this nice and simple */ -static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, - unsigned int flags) +struct jffs2_inode *jffs2_lookup(struct jffs2_inode *dir_i, const unsigned char *d_name, int namelen) { struct jffs2_inode_info *dir_f; struct jffs2_full_dirent *fd = NULL, *fd_list; uint32_t ino = 0; - struct inode *inode = NULL; - unsigned int nhash; + uint32_t hash = full_name_hash(d_name, namelen); + struct jffs2_inode *inode = NULL; jffs2_dbg(1, "jffs2_lookup()\n"); - if (target->d_name.len > JFFS2_MAX_NAME_LEN) + if (namelen > JFFS2_MAX_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); dir_f = JFFS2_INODE_INFO(dir_i); - /* The 'nhash' on the fd_list is not the same as the dentry hash */ - nhash = full_name_hash(NULL, target->d_name.name, target->d_name.len); - 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 <= nhash; fd_list = fd_list->next) { - if (fd_list->nhash == nhash && - (!fd || fd_list->version > fd->version) && - strlen(fd_list->name) == target->d_name.len && - !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) { + for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= hash; fd_list = fd_list->next) { + if (fd_list->nhash == hash && + (!fd || fd_list->version > fd->version) && + strlen((char *)fd_list->name) == namelen && + !strncmp((char *)fd_list->name, (char *)d_name, namelen)) { fd = fd_list; } } @@ -111,176 +58,57 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, pr_warn("iget() failed for ino #%u\n", ino); } - return d_splice_alias(inode, target); -} - -/***********************************************************************/ - - -static int jffs2_readdir(struct file *file, struct dir_context *ctx) -{ - struct inode *inode = file_inode(file); - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_full_dirent *fd; - unsigned long curofs = 1; - - jffs2_dbg(1, "jffs2_readdir() for dir_i #%lu\n", inode->i_ino); - - if (!dir_emit_dots(file, ctx)) - return 0; - - mutex_lock(&f->sem); - for (fd = f->dents; fd; fd = fd->next) { - curofs++; - /* First loop: curofs = 2; pos = 2 */ - if (curofs < ctx->pos) { - jffs2_dbg(2, "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", - fd->name, fd->ino, fd->type, curofs, (unsigned long)ctx->pos); - continue; - } - if (!fd->ino) { - jffs2_dbg(2, "Skipping deletion dirent \"%s\"\n", - fd->name); - ctx->pos++; - continue; - } - jffs2_dbg(2, "Dirent %ld: \"%s\", ino #%u, type %d\n", - (unsigned long)ctx->pos, fd->name, fd->ino, fd->type); - if (!dir_emit(ctx, fd->name, strlen(fd->name), fd->ino, fd->type)) - break; - ctx->pos++; - } - mutex_unlock(&f->sem); - return 0; -} - -/***********************************************************************/ - - -static int jffs2_create(struct inode *dir_i, struct dentry *dentry, - umode_t mode, bool excl) -{ - struct jffs2_raw_inode *ri; - struct jffs2_inode_info *f, *dir_f; - struct jffs2_sb_info *c; - struct inode *inode; - int ret; - - ri = jffs2_alloc_raw_inode(); - if (!ri) - return -ENOMEM; - - c = JFFS2_SB_INFO(dir_i->i_sb); - - jffs2_dbg(1, "%s()\n", __func__); - - inode = jffs2_new_inode(dir_i, mode, ri); - - if (IS_ERR(inode)) { - jffs2_dbg(1, "jffs2_new_inode() failed\n"); - jffs2_free_raw_inode(ri); - return PTR_ERR(inode); - } - - inode->i_op = &jffs2_file_inode_operations; - inode->i_fop = &jffs2_file_operations; - inode->i_mapping->a_ops = &jffs2_file_address_operations; - inode->i_mapping->nrpages = 0; - - f = JFFS2_INODE_INFO(inode); - 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, &dentry->d_name); - if (ret) - goto fail; - - dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); - - jffs2_free_raw_inode(ri); - - jffs2_dbg(1, "%s(): Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", - __func__, inode->i_ino, inode->i_mode, inode->i_nlink, - f->inocache->pino_nlink, inode->i_mapping->nrpages); - - d_instantiate_new(dentry, inode); - return 0; - - fail: - iget_failed(inode); - jffs2_free_raw_inode(ri); - return ret; + return inode; } -/***********************************************************************/ - - -static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) +int jffs2_unlink(struct jffs2_inode *dir_i, struct jffs2_inode *d_inode, const unsigned char *d_name) { 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 *dead_f = JFFS2_INODE_INFO(d_inode(dentry)); + struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode); int ret; - uint32_t now = JFFS2_NOW(); + uint32_t now = Jffs2CurSec(); - ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, - dentry->d_name.len, dead_f, now); + ret = jffs2_do_unlink(c, dir_f, (const char *)d_name, + strlen((char *)d_name), dead_f, now); if (dead_f->inocache) - set_nlink(d_inode(dentry), dead_f->inocache->pino_nlink); + d_inode->i_nlink = dead_f->inocache->pino_nlink; if (!ret) - dir_i->i_mtime = dir_i->i_ctime = ITIME(now); + dir_i->i_mtime = dir_i->i_ctime = now; return ret; } -/***********************************************************************/ - -static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) +int jffs2_link(struct jffs2_inode *old_d_inode, struct jffs2_inode *dir_i, const unsigned char *d_name) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_sb); - struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(old_dentry)); + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_d_inode->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode); struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); int ret; uint8_t type; uint32_t now; - /* Don't let people make hard links to bad inodes. */ - if (!f->inocache) - return -EIO; - - if (d_is_dir(old_dentry)) - return -EPERM; - /* XXX: This is ugly */ - type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; + type = (old_d_inode->i_mode & S_IFMT) >> 12; if (!type) type = DT_REG; - now = JFFS2_NOW(); - ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now); + now = Jffs2CurSec(); + ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, (const char *)d_name, + strlen((char *)d_name), now); if (!ret) { mutex_lock(&f->sem); - set_nlink(d_inode(old_dentry), ++f->inocache->pino_nlink); + old_d_inode->i_nlink = ++f->inocache->pino_nlink; mutex_unlock(&f->sem); - d_instantiate(dentry, d_inode(old_dentry)); - dir_i->i_mtime = dir_i->i_ctime = ITIME(now); - ihold(d_inode(old_dentry)); + dir_i->i_mtime = dir_i->i_ctime = now; } return ret; } -/***********************************************************************/ - -static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char *target) +int jffs2_symlink(struct jffs2_inode *dir_i, struct jffs2_inode **d_inode, const unsigned char *d_name, const char *target) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; - struct inode *inode; + struct jffs2_inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; @@ -304,7 +132,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ - namelen = dentry->d_name.len; + namelen = strlen((char *)d_name); ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); @@ -321,8 +149,6 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char return PTR_ERR(inode); } - inode->i_op = &jffs2_symlink_inode_operations; - f = JFFS2_INODE_INFO(inode); inode->i_size = targetlen; @@ -334,7 +160,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - fn = jffs2_write_dnode(c, f, ri, target, targetlen, ALLOC_NORMAL); + fn = jffs2_write_dnode(c, f, ri, (const unsigned char *)target, targetlen, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -347,7 +173,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char } /* We use f->target field to store the target path. */ - f->target = kmemdup(target, targetlen + 1, GFP_KERNEL); + + f->target = (unsigned char *)malloc(targetlen + 1); if (!f->target) { pr_warn("Can't allocate %d bytes of memory\n", targetlen + 1); mutex_unlock(&f->sem); @@ -355,7 +182,15 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ret = -ENOMEM; goto fail; } - inode->i_link = f->target; + + ret = LOS_CopyToKernel((char *)f->target, targetlen + 1, target, targetlen + 1); + if (ret != EOK) { + (void)free(f->target); + f->target = NULL; + mutex_unlock(&f->sem); + jffs2_complete_reservation(c); + goto fail; + } jffs2_dbg(1, "%s(): symlink's target '%s' cached\n", __func__, (char *)f->target); @@ -368,14 +203,6 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char jffs2_complete_reservation(c); - ret = jffs2_init_security(inode, dir_i, &dentry->d_name); - if (ret) - goto fail; - - ret = jffs2_init_acl_post(inode); - if (ret) - goto fail; - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) @@ -400,13 +227,13 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char rd->pino = cpu_to_je32(dir_i->i_ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(inode->i_ino); - rd->mctime = cpu_to_je32(JFFS2_NOW()); + rd->mctime = cpu_to_je32(Jffs2CurSec()); rd->nsize = namelen; rd->type = DT_LNK; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); - rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); + rd->name_crc = cpu_to_je32(crc32(0, (const char *)d_name, namelen)); - fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); + fd = jffs2_write_dirent(c, dir_f, rd, (const unsigned char *)d_name, namelen, ALLOC_NORMAL); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally @@ -418,7 +245,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char goto fail; } - dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); + dir_i->i_mtime = dir_i->i_ctime = je32_to_cpu(rd->mctime); jffs2_free_raw_dirent(rd); @@ -429,20 +256,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); - d_instantiate_new(dentry, inode); + *d_inode = inode; return 0; fail: - iget_failed(inode); + inode->i_nlink = 0; + jffs2_iput(inode); return ret; } - -static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode) +int jffs2_mkdir(struct jffs2_inode *dir_i, const unsigned char *d_name, int mode, struct jffs2_inode **new_i) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; - struct inode *inode; + struct jffs2_inode *inode; struct jffs2_raw_inode *ri; struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; @@ -450,7 +277,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode int namelen; uint32_t alloclen; int ret; - + mode &= ~S_IFMT; mode |= S_IFDIR; ri = jffs2_alloc_raw_inode(); @@ -462,9 +289,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode /* Try to reserve enough space for both node and dirent. * Just the node will do for now, though */ - namelen = dentry->d_name.len; - ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, - JFFS2_SUMMARY_INODE_SIZE); + namelen = strlen((char *)d_name); + ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); @@ -478,14 +304,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode jffs2_complete_reservation(c); return PTR_ERR(inode); } - - inode->i_op = &jffs2_dir_inode_operations; - inode->i_fop = &jffs2_dir_operations; - f = JFFS2_INODE_INFO(inode); - /* Directories get nlink 2 at start */ - set_nlink(inode, 2); /* but ic->pino_nlink is the parent ino# */ f->inocache->pino_nlink = dir_i->i_ino; @@ -500,6 +320,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode /* Eeek. Wave bye bye */ mutex_unlock(&f->sem); jffs2_complete_reservation(c); + ret = PTR_ERR(fn); goto fail; } @@ -511,14 +332,6 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode jffs2_complete_reservation(c); - ret = jffs2_init_security(inode, dir_i, &dentry->d_name); - if (ret) - goto fail; - - ret = jffs2_init_acl_post(inode); - if (ret) - goto fail; - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) @@ -543,13 +356,13 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode rd->pino = cpu_to_je32(dir_i->i_ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = cpu_to_je32(inode->i_ino); - rd->mctime = cpu_to_je32(JFFS2_NOW()); + rd->mctime = cpu_to_je32(Jffs2CurSec()); rd->nsize = namelen; rd->type = DT_DIR; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); - rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); + rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen)); - fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); + fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, ALLOC_NORMAL); if (IS_ERR(fd)) { /* dirent failed to write. Delete the inode normally @@ -557,12 +370,12 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode jffs2_complete_reservation(c); jffs2_free_raw_dirent(rd); mutex_unlock(&dir_f->sem); + inode->i_nlink = 0; ret = PTR_ERR(fd); goto fail; } - dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); - inc_nlink(dir_i); + dir_i->i_mtime = dir_i->i_ctime = je32_to_cpu(rd->mctime); jffs2_free_raw_dirent(rd); @@ -572,23 +385,24 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, umode_t mode mutex_unlock(&dir_f->sem); jffs2_complete_reservation(c); + *new_i = inode; - d_instantiate_new(dentry, inode); return 0; fail: - iget_failed(inode); + inode->i_nlink = 0; + jffs2_iput(inode); return ret; } -static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) +int jffs2_rmdir (struct jffs2_inode *dir_i, struct jffs2_inode *d_inode, const unsigned char *d_name) { 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(d_inode(dentry)); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode); struct jffs2_full_dirent *fd; int ret; - uint32_t now = JFFS2_NOW(); + uint32_t now = Jffs2CurSec(); mutex_lock(&f->sem); for (fd = f->dents ; fd; fd = fd->next) { @@ -599,273 +413,172 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) } mutex_unlock(&f->sem); - 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(d_inode(dentry)); - drop_nlink(dir_i); - } + ret = jffs2_do_unlink(c, dir_f, (const char *)d_name, + strlen((char *)d_name), f, now); + if (f->inocache) + d_inode->i_nlink = f->inocache->pino_nlink; + if (!ret) + dir_i->i_mtime = dir_i->i_ctime = now; + return ret; } -static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode, dev_t rdev) +int jffs2_rename (struct jffs2_inode *old_dir_i, struct jffs2_inode *d_inode, const unsigned char *old_d_name, + struct jffs2_inode *new_dir_i, const unsigned char *new_d_name) { - struct jffs2_inode_info *f, *dir_f; - struct jffs2_sb_info *c; - struct inode *inode; - struct jffs2_raw_inode *ri; - struct jffs2_raw_dirent *rd; - struct jffs2_full_dnode *fn; - struct jffs2_full_dirent *fd; - int namelen; - union jffs2_device_node dev; - int devlen = 0; - uint32_t alloclen; int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); + uint8_t type; + uint32_t now; - ri = jffs2_alloc_raw_inode(); - if (!ri) - return -ENOMEM; - - c = JFFS2_SB_INFO(dir_i->i_sb); - - if (S_ISBLK(mode) || S_ISCHR(mode)) - devlen = jffs2_encode_dev(&dev, rdev); + /* XXX: This is ugly */ + type = (d_inode->i_mode & S_IFMT) >> 12; + if (!type) type = DT_REG; - /* Try to reserve enough space for both node and dirent. - * Just the node will do for now, though - */ - namelen = dentry->d_name.len; - ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &alloclen, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + now = Jffs2CurSec(); + ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), + d_inode->i_ino, type, + (const char *)new_d_name, strlen((char *)new_d_name), now); - if (ret) { - jffs2_free_raw_inode(ri); + if (ret) return ret; - } - inode = jffs2_new_inode(dir_i, mode, ri); - if (IS_ERR(inode)) { - jffs2_free_raw_inode(ri); - jffs2_complete_reservation(c); - return PTR_ERR(inode); + /* If it was a directory we moved, and there was no victim, + increase i_nlink on its new parent */ + if ((d_inode->i_mode & S_IFMT) == S_IFDIR) { + new_dir_i->i_nlink++; } - inode->i_op = &jffs2_file_inode_operations; - init_special_inode(inode, inode->i_mode, rdev); - - f = JFFS2_INODE_INFO(inode); - ri->dsize = ri->csize = cpu_to_je32(devlen); - ri->totlen = cpu_to_je32(sizeof(*ri) + devlen); - ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); - - ri->compr = JFFS2_COMPR_NONE; - ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); - ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - - fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, ALLOC_NORMAL); + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), + (const char *)old_d_name, strlen((char *)old_d_name), NULL, now); - jffs2_free_raw_inode(ri); + /* We don't touch inode->i_nlink */ - if (IS_ERR(fn)) { - /* Eeek. Wave bye bye */ + 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(d_inode); + mutex_lock(&f->sem); + if (f->inocache) + d_inode->i_nlink = f->inocache->pino_nlink++; mutex_unlock(&f->sem); - jffs2_complete_reservation(c); - ret = PTR_ERR(fn); - goto fail; - } - /* No data here. Only a metadata node, which will be - obsoleted by the first data write - */ - f->metadata = fn; - mutex_unlock(&f->sem); - - jffs2_complete_reservation(c); - - ret = jffs2_init_security(inode, dir_i, &dentry->d_name); - if (ret) - goto fail; - - ret = jffs2_init_acl_post(inode); - if (ret) - goto fail; - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen, - ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); - if (ret) - goto fail; - - rd = jffs2_alloc_raw_dirent(); - if (!rd) { - /* Argh. Now we treat it like a normal delete */ - jffs2_complete_reservation(c); - ret = -ENOMEM; - goto fail; + pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n", + __func__, ret); + /* Might as well let the VFS know */ + new_dir_i->i_mtime = new_dir_i->i_ctime = now; + return ret; } - dir_f = JFFS2_INODE_INFO(dir_i); - mutex_lock(&dir_f->sem); - rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); - rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); - rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); - rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); + new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = now; - rd->pino = cpu_to_je32(dir_i->i_ino); - rd->version = cpu_to_je32(++dir_f->highest_version); - rd->ino = cpu_to_je32(inode->i_ino); - rd->mctime = cpu_to_je32(JFFS2_NOW()); - rd->nsize = namelen; + return 0; +} - /* XXX: This is ugly. */ - rd->type = (mode & S_IFMT) >> 12; +int jffs2_create(struct jffs2_inode *dir_i, const unsigned char *d_name, int mode, + struct jffs2_inode **new_i) +{ + struct jffs2_raw_inode *ri; + struct jffs2_inode_info *f, *dir_f; + struct jffs2_sb_info *c; + struct jffs2_inode *inode; + int ret; + mode &= ~S_IFMT; + mode |= S_IFREG; + ri = jffs2_alloc_raw_inode(); + if (!ri) + return -ENOMEM; - rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); - rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); + c = JFFS2_SB_INFO(dir_i->i_sb); - fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, ALLOC_NORMAL); + D1(printk(KERN_DEBUG "jffs2_create()\n")); + inode = jffs2_new_inode(dir_i, mode, ri); - if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally - as if it were the final unlink() */ - jffs2_complete_reservation(c); - jffs2_free_raw_dirent(rd); - mutex_unlock(&dir_f->sem); - ret = PTR_ERR(fd); - goto fail; + if (IS_ERR(inode)) { + D1(printk(KERN_DEBUG "jffs2_new_inode() failed, error:%ld\n", PTR_ERR(inode))); + jffs2_free_raw_inode(ri); + return PTR_ERR(inode); } - dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); + f = JFFS2_INODE_INFO(inode); + dir_f = JFFS2_INODE_INFO(dir_i); - jffs2_free_raw_dirent(rd); + /* 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, + (const char *)d_name, + strlen((char *)d_name)); - /* Link the fd into the inode's list, obsoleting an old - one if necessary. */ - jffs2_add_fd_to_list(c, fd, &dir_f->dents); + if (ret) { + inode->i_nlink = 0; + jffs2_iput(inode); + jffs2_free_raw_inode(ri); + return ret; + } - mutex_unlock(&dir_f->sem); - jffs2_complete_reservation(c); + jffs2_free_raw_inode(ri); - d_instantiate_new(dentry, inode); + D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d)\n", + inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->pino_nlink)); + *new_i = inode; return 0; +} - fail: - iget_failed(inode); - return ret; +static __inline void fill_name(char *dst_name, int nlen, const unsigned char *name, int namlen) +{ + int len = nlen < namlen ? nlen : namlen; + (void)memcpy_s(dst_name, nlen, name, len); + dst_name[len] = '\0'; } -static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, - struct inode *new_dir_i, struct dentry *new_dentry, - unsigned int flags) +int jffs2_readdir(struct jffs2_inode *inode, off_t *offset, off_t *int_off, struct dirent *ent) { - int ret; - struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); - struct jffs2_inode_info *victim_f = NULL; - uint8_t type; - uint32_t now; + struct jffs2_inode_info *f; + struct jffs2_full_dirent *fd; + off_t curofs = 0; - if (flags & ~RENAME_NOREPLACE) - return -EINVAL; + f = JFFS2_INODE_INFO(inode); - /* The VFS will check for us and prevent trying to rename a - * file over a directory and vice versa, but if it's a directory, - * the VFS can't check whether the victim is empty. The filesystem - * needs to do that for itself. - */ - if (d_really_is_positive(new_dentry)) { - victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); - if (d_is_dir(new_dentry)) { - struct jffs2_full_dirent *fd; - - mutex_lock(&victim_f->sem); - for (fd = victim_f->dents; fd; fd = fd->next) { - if (fd->ino) { - mutex_unlock(&victim_f->sem); - return -ENOTEMPTY; - } - } - mutex_unlock(&victim_f->sem); + mutex_lock(&f->sem); + for (fd = f->dents; fd; fd = fd->next) { + if (curofs++ < *int_off) { + D2(printk + (KERN_DEBUG + "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", + fd->name, fd->ino, fd->type, curofs, offset)); + continue; } - } - - /* XXX: We probably ought to alloc enough space for - both nodes at the same time. Writing the new link, - then getting -ENOSPC, is quite bad :) - */ - - /* Make a hard link */ - - /* XXX: This is ugly */ - type = (d_inode(old_dentry)->i_mode & S_IFMT) >> 12; - if (!type) type = DT_REG; - - now = JFFS2_NOW(); - ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), - d_inode(old_dentry)->i_ino, type, - new_dentry->d_name.name, new_dentry->d_name.len, now); - - if (ret) - return ret; - - if (victim_f) { - /* There was a victim. Kill it off nicely */ - if (d_is_dir(new_dentry)) - clear_nlink(d_inode(new_dentry)); - else - drop_nlink(d_inode(new_dentry)); - /* Don't oops if the victim was a dirent pointing to an - inode which didn't exist. */ - if (victim_f->inocache) { - mutex_lock(&victim_f->sem); - if (d_is_dir(new_dentry)) - victim_f->inocache->pino_nlink = 0; - else - victim_f->inocache->pino_nlink--; - mutex_unlock(&victim_f->sem); + if (!fd->ino) { + D2(printk (KERN_DEBUG "Skipping deletion dirent \"%s\"\n", fd->name)); + (*int_off)++; + continue; } - } - /* If it was a directory we moved, and there was no victim, - increase i_nlink on its new parent */ - if (d_is_dir(old_dentry) && !victim_f) - inc_nlink(new_dir_i); - - /* Unlink the original */ - ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), - old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); - - /* We don't touch inode->i_nlink */ - - 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(d_inode(old_dentry)); - mutex_lock(&f->sem); - inc_nlink(d_inode(old_dentry)); - if (f->inocache && !d_is_dir(old_dentry)) - f->inocache->pino_nlink++; - mutex_unlock(&f->sem); + D2(printk + (KERN_DEBUG "%s-%d: Dirent %ld: \"%s\", ino #%u, type %d\n", __FUNCTION__, __LINE__, offset, + fd->name, fd->ino, fd->type)); + fill_name(ent->d_name, sizeof(ent->d_name) - 1, fd->name, strlen((char *)fd->name)); + ent->d_type = fd->type; + ent->d_off = ++(*offset); + ent->d_reclen = (uint16_t)sizeof(struct dirent); - pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n", - __func__, ret); - /* - * We can't keep the target in dcache after that. - * For one thing, we can't afford dentry aliases for directories. - * For another, if there was a victim, we _can't_ set new inode - * for that sucker and we have to trigger mount eviction - the - * caller won't do it on its own since we are returning an error. - */ - d_invalidate(new_dentry); - new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now); - return ret; + (*int_off)++; + break; } - if (d_is_dir(old_dentry)) - drop_nlink(old_dir_i); + mutex_unlock(&f->sem); - new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); + if (fd == NULL) { + D2(printk(KERN_DEBUG "reached the end of the directory\n")); + return ENOENT; + } - return 0; + return ENOERR; } diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 7e9abdb8971225f483451a8f9182bebdfceb99d8..b17883c9e1f8412369fb25fa55e0f75d044b2aff 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -10,16 +10,14 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include -#include #include -#include #include #include +#include "mtd_dev.h" #include "nodelist.h" +#include "los_crc32.h" static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset); static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); @@ -29,50 +27,15 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { int ret; - uint32_t bad_offset; -#ifdef __ECOS - ret = jffs2_flash_erase(c, jeb); - if (!ret) { - jffs2_erase_succeeded(c, jeb); - return; - } - bad_offset = jeb->offset; -#else /* Linux */ - struct erase_info *instr; - - jffs2_dbg(1, "%s(): erase block %#08x (range %#08x-%#08x)\n", - __func__, - jeb->offset, jeb->offset, jeb->offset + c->sector_size); - instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL); - if (!instr) { - pr_warn("kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); - 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); - mutex_unlock(&c->erase_free_sem); - return; - } - - memset(instr, 0, sizeof(*instr)); + uint64_t bad_offset = 0; - instr->addr = jeb->offset; - instr->len = c->sector_size; - - ret = mtd_erase(c->mtd, instr); + ret = c->mtd->erase(c->mtd, jeb->offset, c->sector_size, &bad_offset); if (!ret) { jffs2_erase_succeeded(c, jeb); - kfree(instr); + //kfree(instr); return; } - bad_offset = instr->fail_addr; - kfree(instr); -#endif /* __ECOS */ - if (ret == -ENOMEM || ret == -EAGAIN) { /* Erase failed immediately. Refile it on the list */ jffs2_dbg(1, "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", @@ -168,29 +131,10 @@ static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblo jffs2_garbage_collect_trigger(c); spin_unlock(&c->erase_completion_lock); mutex_unlock(&c->erase_free_sem); - wake_up(&c->erase_wait); } static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset) { - /* For NAND, if the failure did not occur at the device level for a - specific physical page, don't bother updating the bad block table. */ - if (jffs2_cleanmarker_oob(c) && (bad_offset != (uint32_t)MTD_FAIL_ADDR_UNKNOWN)) { - /* We had a device-level failure to erase. Let's see if we've - failed too many times. */ - if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) { - /* We'd like to give this block another try. */ - 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); - mutex_unlock(&c->erase_free_sem); - return; - } - } mutex_lock(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); @@ -200,7 +144,6 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock c->nr_erasing_blocks--; spin_unlock(&c->erase_completion_lock); mutex_unlock(&c->erase_free_sem); - wake_up(&c->erase_wait); } /* Hmmm. Maybe we should accept the extra space it takes and make @@ -315,40 +258,8 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl void *ebuf; uint32_t ofs; size_t retlen; - int ret; - unsigned long *wordebuf; + int ret = -EIO; - ret = mtd_point(c->mtd, jeb->offset, c->sector_size, &retlen, - &ebuf, NULL); - if (ret != -EOPNOTSUPP) { - if (ret) { - jffs2_dbg(1, "MTD point failed %d\n", ret); - goto do_flash_read; - } - if (retlen < c->sector_size) { - /* Don't muck about if it won't let us point to the whole erase sector */ - jffs2_dbg(1, "MTD point returned len too short: 0x%zx\n", - retlen); - mtd_unpoint(c->mtd, jeb->offset, retlen); - goto do_flash_read; - } - wordebuf = ebuf-sizeof(*wordebuf); - retlen /= sizeof(*wordebuf); - do { - if (*++wordebuf != ~0) - break; - } while(--retlen); - mtd_unpoint(c->mtd, jeb->offset, c->sector_size); - if (retlen) { - pr_warn("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: ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ebuf) { pr_warn("Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", @@ -364,7 +275,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl *bad_offset = ofs; - ret = mtd_read(c->mtd, ofs, readlen, &retlen, ebuf); + ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); if (ret) { pr_warn("Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); @@ -379,7 +290,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl } for (i=0; ierase_completion_lock); mutex_unlock(&c->erase_free_sem); - wake_up(&c->erase_wait); return; filebad: diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 4fc8cd698d1a4ac0b4f13b694a0c63c214c276ce..c7b5011f0b8541577f4798e3b388cdef23b732fa 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -9,325 +9,34 @@ * For licensing information, see the file 'LICENCE' in this directory. * */ +#include "los_vm_common.h" -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include #include "nodelist.h" +#include "vfs_jffs2.h" -static int jffs2_write_end(struct file *filp, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *pg, void *fsdata); -static int jffs2_write_begin(struct file *filp, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata); -static int jffs2_readpage (struct file *filp, struct page *pg); - -int jffs2_fsync(struct file *filp, loff_t start, loff_t end, int datasync) -{ - struct inode *inode = filp->f_mapping->host; - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - int ret; - - ret = file_write_and_wait_range(filp, start, end); - if (ret) - return ret; - inode_lock(inode); - /* Trigger GC to flush any pending writes for this inode */ - jffs2_flush_wbuf_gc(c, inode->i_ino); - inode_unlock(inode); +static unsigned char gc_buffer[PAGE_SIZE]; //avoids malloc when user may be under memory pressure - return 0; -} -const struct file_operations jffs2_file_operations = +unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + unsigned long offset, + unsigned long *priv) { - .llseek = generic_file_llseek, - .open = generic_file_open, - .read_iter = generic_file_read_iter, - .write_iter = generic_file_write_iter, - .unlocked_ioctl=jffs2_ioctl, - .mmap = generic_file_readonly_mmap, - .fsync = jffs2_fsync, - .splice_read = generic_file_splice_read, - .splice_write = iter_file_splice_write, -}; - -/* jffs2_file_inode_operations */ - -const struct inode_operations jffs2_file_inode_operations = -{ - .get_acl = jffs2_get_acl, - .set_acl = jffs2_set_acl, - .setattr = jffs2_setattr, - .listxattr = jffs2_listxattr, -}; - -const struct address_space_operations jffs2_file_address_operations = -{ - .readpage = jffs2_readpage, - .write_begin = jffs2_write_begin, - .write_end = jffs2_write_end, -}; - -static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) -{ - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - unsigned char *pg_buf; + /* FIXME: This works only with one file system mounted at a time */ int ret; - jffs2_dbg(2, "%s(): ino #%lu, page at offset 0x%lx\n", - __func__, inode->i_ino, pg->index << PAGE_SHIFT); - - BUG_ON(!PageLocked(pg)); - - pg_buf = kmap(pg); - /* FIXME: Can kmap fail? */ - - ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_SHIFT, - PAGE_SIZE); - - if (ret) { - ClearPageUptodate(pg); - SetPageError(pg); - } else { - SetPageUptodate(pg); - ClearPageError(pg); - } - - flush_dcache_page(pg); - kunmap(pg); - - jffs2_dbg(2, "readpage finished\n"); - return ret; -} - -int jffs2_do_readpage_unlock(void *data, struct page *pg) -{ - int ret = jffs2_do_readpage_nolock(data, pg); - unlock_page(pg); - return ret; -} - - -static int jffs2_readpage (struct file *filp, struct page *pg) -{ - struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host); - int ret; + ret = jffs2_read_inode_range(c, f, gc_buffer, + offset & ~(PAGE_SIZE-1), PAGE_SIZE); + if (ret) + return ERR_PTR(ret); - mutex_lock(&f->sem); - ret = jffs2_do_readpage_unlock(pg->mapping->host, pg); - mutex_unlock(&f->sem); - return ret; + return gc_buffer; } - -static int jffs2_write_begin(struct file *filp, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) +void jffs2_gc_release_page(struct jffs2_sb_info *c, + unsigned char *ptr, + unsigned long *priv) { - struct page *pg; - struct inode *inode = mapping->host; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - pgoff_t index = pos >> PAGE_SHIFT; - uint32_t pageofs = index << PAGE_SHIFT; - int ret = 0; - - pg = grab_cache_page_write_begin(mapping, index, flags); - if (!pg) - return -ENOMEM; - *pagep = pg; - - jffs2_dbg(1, "%s()\n", __func__); - - if (pageofs > inode->i_size) { - /* Make new hole frag from old EOF to new page */ - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode ri; - struct jffs2_full_dnode *fn; - uint32_t alloc_len; - - jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", - (unsigned int)inode->i_size, pageofs); - - ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); - if (ret) - goto out_page; - - mutex_lock(&f->sem); - memset(&ri, 0, sizeof(ri)); - - ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); - ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); - ri.totlen = cpu_to_je32(sizeof(ri)); - ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); - - ri.ino = cpu_to_je32(f->inocache->ino); - ri.version = cpu_to_je32(++f->highest_version); - ri.mode = cpu_to_jemode(inode->i_mode); - ri.uid = cpu_to_je16(i_uid_read(inode)); - ri.gid = cpu_to_je16(i_gid_read(inode)); - ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); - ri.atime = ri.ctime = ri.mtime = cpu_to_je32(JFFS2_NOW()); - ri.offset = cpu_to_je32(inode->i_size); - ri.dsize = cpu_to_je32(pageofs - inode->i_size); - ri.csize = cpu_to_je32(0); - ri.compr = JFFS2_COMPR_ZERO; - ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); - ri.data_crc = cpu_to_je32(0); - - fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_NORMAL); - - if (IS_ERR(fn)) { - ret = PTR_ERR(fn); - jffs2_complete_reservation(c); - mutex_unlock(&f->sem); - goto out_page; - } - ret = jffs2_add_full_dnode_to_inode(c, f, fn); - if (f->metadata) { - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - } - if (ret) { - jffs2_dbg(1, "Eep. add_full_dnode_to_inode() failed in write_begin, returned %d\n", - ret); - jffs2_mark_node_obsolete(c, fn->raw); - jffs2_free_full_dnode(fn); - jffs2_complete_reservation(c); - mutex_unlock(&f->sem); - goto out_page; - } - jffs2_complete_reservation(c); - inode->i_size = pageofs; - mutex_unlock(&f->sem); - } - - /* - * Read in the page if it wasn't already present. Cannot optimize away - * the whole page write case until jffs2_write_end can handle the - * case of a short-copy. - */ - if (!PageUptodate(pg)) { - mutex_lock(&f->sem); - ret = jffs2_do_readpage_nolock(inode, pg); - mutex_unlock(&f->sem); - if (ret) - goto out_page; - } - jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); - return ret; - -out_page: - unlock_page(pg); - put_page(pg); - return ret; + /* Do nothing */ } -static int jffs2_write_end(struct file *filp, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *pg, void *fsdata) -{ - /* Actually commit the write from the page cache page we're looking at. - * For now, we write the full page out each time. It sucks, but it's simple - */ - struct inode *inode = mapping->host; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode *ri; - unsigned start = pos & (PAGE_SIZE - 1); - unsigned end = start + copied; - unsigned aligned_start = start & ~3; - int ret = 0; - uint32_t writtenlen = 0; - - jffs2_dbg(1, "%s(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", - __func__, inode->i_ino, pg->index << PAGE_SHIFT, - start, end, pg->flags); - - /* We need to avoid deadlock with page_cache_read() in - jffs2_garbage_collect_pass(). So the page must be - up to date to prevent page_cache_read() from trying - to re-lock it. */ - BUG_ON(!PageUptodate(pg)); - - if (end == PAGE_SIZE) { - /* When writing out the end of a page, write out the - _whole_ page. This helps to reduce the number of - nodes in files which have many short writes, like - syslog files. */ - aligned_start = 0; - } - - ri = jffs2_alloc_raw_inode(); - - if (!ri) { - jffs2_dbg(1, "%s(): Allocation of raw inode failed\n", - __func__); - unlock_page(pg); - put_page(pg); - return -ENOMEM; - } - - /* Set the fields that the generic jffs2_write_inode_range() code can't find */ - ri->ino = cpu_to_je32(inode->i_ino); - ri->mode = cpu_to_jemode(inode->i_mode); - ri->uid = cpu_to_je16(i_uid_read(inode)); - ri->gid = cpu_to_je16(i_gid_read(inode)); - ri->isize = cpu_to_je32((uint32_t)inode->i_size); - ri->atime = ri->ctime = ri->mtime = cpu_to_je32(JFFS2_NOW()); - - /* In 2.4, it was already kmapped by generic_file_write(). Doesn't - hurt to do it again. The alternative is ifdefs, which are ugly. */ - kmap(pg); - - ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start, - (pg->index << PAGE_SHIFT) + aligned_start, - end - aligned_start, &writtenlen); - - kunmap(pg); - - if (ret) { - /* There was an error writing. */ - SetPageError(pg); - } - - /* Adjust writtenlen for the padding we did, so we don't confuse our caller */ - writtenlen -= min(writtenlen, (start - aligned_start)); - - if (writtenlen) { - if (inode->i_size < pos + writtenlen) { - inode->i_size = pos + writtenlen; - inode->i_blocks = (inode->i_size + 511) >> 9; - - inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); - } - } - - jffs2_free_raw_inode(ri); - - if (start+writtenlen < end) { - /* generic_file_write has written more to the page cache than we've - actually written to the medium. Mark the page !Uptodate so that - it gets reread */ - jffs2_dbg(1, "%s(): Not all bytes written. Marking page !uptodate\n", - __func__); - SetPageError(pg); - ClearPageUptodate(pg); - } - - jffs2_dbg(1, "%s() returning %d\n", - __func__, writtenlen > 0 ? writtenlen : ret); - unlock_page(pg); - put_page(pg); - return writtenlen > 0 ? writtenlen : ret; -} diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 78858f6e95839cb03859fd36d67dfd85d7c6ba74..8aa7afde4549f74b777d4cce932a5df49b3bb52f 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -10,136 +10,129 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include "nodelist.h" +#include "os-linux.h" +#include "los_crc32.h" +#include "jffs2_hash.h" +#include "capability_type.h" +#include "capability_api.h" -static int jffs2_flash_setup(struct jffs2_sb_info *c); - -int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) +int jffs2_setattr (struct jffs2_inode *inode, struct IATTR *attr) { struct jffs2_full_dnode *old_metadata, *new_metadata; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_raw_inode *ri; - union jffs2_device_node dev; - unsigned char *mdata = NULL; - int mdatalen = 0; unsigned int ivalid; + mode_t tmp_mode; + uint c_uid = OsCurrUserGet()->effUserID; + uint c_gid = OsCurrUserGet()->effGid; uint32_t alloclen; int ret; int alloc_type = ALLOC_NORMAL; jffs2_dbg(1, "%s(): ino #%lu\n", __func__, inode->i_ino); - - /* Special cases - we don't want more than one data node - for these types on the medium at any time. So setattr - must read the original data associated with the node - (i.e. the device numbers or the target name) and write - it out again with the appropriate data attached */ - if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { - /* For these, we don't actually need to read the old node */ - mdatalen = jffs2_encode_dev(&dev, inode->i_rdev); - mdata = (char *)&dev; - jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n", - __func__, mdatalen); - } else if (S_ISLNK(inode->i_mode)) { - mutex_lock(&f->sem); - mdatalen = f->metadata->size; - mdata = kmalloc(f->metadata->size, GFP_USER); - if (!mdata) { - mutex_unlock(&f->sem); - return -ENOMEM; - } - ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen); - if (ret) { - mutex_unlock(&f->sem); - kfree(mdata); - return ret; - } - mutex_unlock(&f->sem); - jffs2_dbg(1, "%s(): Writing %d bytes of symlink target\n", - __func__, mdatalen); - } - ri = jffs2_alloc_raw_inode(); if (!ri) { - if (S_ISLNK(inode->i_mode)) - kfree(mdata); return -ENOMEM; } - ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &alloclen, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) { jffs2_free_raw_inode(ri); - if (S_ISLNK(inode->i_mode)) - kfree(mdata); return ret; } mutex_lock(&f->sem); - ivalid = iattr->ia_valid; + ivalid = attr->attr_chg_valid; + tmp_mode = inode->i_mode; ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); - ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); - ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); + ri->totlen = cpu_to_je32(sizeof(*ri)); + ri->hdr_crc = cpu_to_je32(crc32(0, ri, (sizeof(struct jffs2_unknown_node)-4))); ri->ino = cpu_to_je32(inode->i_ino); ri->version = cpu_to_je32(++f->highest_version); + ri->uid = cpu_to_je16(inode->i_uid); + ri->gid = cpu_to_je16(inode->i_gid); - ri->uid = cpu_to_je16((ivalid & ATTR_UID)? - from_kuid(&init_user_ns, iattr->ia_uid):i_uid_read(inode)); - ri->gid = cpu_to_je16((ivalid & ATTR_GID)? - from_kgid(&init_user_ns, iattr->ia_gid):i_gid_read(inode)); + if (ivalid & CHG_UID) { + if (((c_uid != inode->i_uid) || (attr->attr_chg_uid != inode->i_uid)) && (!IsCapPermit(CAP_CHOWN))) { + jffs2_complete_reservation(c); + jffs2_free_raw_inode(ri); + mutex_unlock(&f->sem); + return -EPERM; + } else { + ri->uid = cpu_to_je16(attr->attr_chg_uid); + } + } + + if (ivalid & CHG_GID) { + if (((c_gid != inode->i_gid) || (attr->attr_chg_gid != inode->i_gid)) && (!IsCapPermit(CAP_CHOWN))) { + jffs2_complete_reservation(c); + jffs2_free_raw_inode(ri); + mutex_unlock(&f->sem); + return -EPERM; + } else { + ri->gid = cpu_to_je16(attr->attr_chg_gid); + } + } + + if (ivalid & CHG_MODE) { + if (!IsCapPermit(CAP_FOWNER) && (c_uid != inode->i_uid)) { + jffs2_complete_reservation(c); + jffs2_free_raw_inode(ri); + mutex_unlock(&f->sem); + return -EPERM; + } else { + attr->attr_chg_mode &= ~S_IFMT; // delete file type + tmp_mode &= S_IFMT; + tmp_mode = attr->attr_chg_mode | tmp_mode; // add old file type + } + } - if (ivalid & ATTR_MODE) - ri->mode = cpu_to_jemode(iattr->ia_mode); - else - ri->mode = cpu_to_jemode(inode->i_mode); + if (ivalid & CHG_ATIME) { + if ((c_uid != inode->i_uid) || (attr->attr_chg_uid != inode->i_uid)) { + return -EPERM; + } else { + ri->atime = cpu_to_je32(attr->attr_chg_atime); + } + } else { + ri->atime = cpu_to_je32(inode->i_atime); + } + if (ivalid & CHG_MTIME) { + if ((c_uid != inode->i_uid) || (attr->attr_chg_uid != inode->i_uid)) { + return -EPERM; + } else { + ri->mtime = cpu_to_je32(attr->attr_chg_mtime); + } + } else { + ri->mtime = cpu_to_je32(Jffs2CurSec()); + } + ri->mode = cpu_to_jemode(tmp_mode); - ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size); - ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime)); - ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime)); - ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime)); + ri->isize = cpu_to_je32((ivalid & CHG_SIZE) ? attr->attr_chg_size : inode->i_size); + ri->ctime = cpu_to_je32(Jffs2CurSec()); ri->offset = cpu_to_je32(0); - ri->csize = ri->dsize = cpu_to_je32(mdatalen); + ri->csize = ri->dsize = cpu_to_je32(0); ri->compr = JFFS2_COMPR_NONE; - if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { + if (ivalid & CHG_SIZE && inode->i_size < attr->attr_chg_size) { /* It's an extension. Make it a hole node */ ri->compr = JFFS2_COMPR_ZERO; - ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); + ri->dsize = cpu_to_je32(attr->attr_chg_size - inode->i_size); ri->offset = cpu_to_je32(inode->i_size); - } else if (ivalid & ATTR_SIZE && !iattr->ia_size) { + } else if (ivalid & CHG_SIZE && !attr->attr_chg_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) - ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); - else - ri->data_crc = cpu_to_je32(0); - - new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type); - if (S_ISLNK(inode->i_mode)) - kfree(mdata); - + ri->node_crc = cpu_to_je32(crc32(0, ri, (sizeof(*ri)-8))); + ri->data_crc = cpu_to_je32(0); + new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, alloc_type); if (IS_ERR(new_metadata)) { jffs2_complete_reservation(c); jffs2_free_raw_inode(ri); @@ -147,23 +140,20 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) return PTR_ERR(new_metadata); } /* It worked. Update the inode */ - inode->i_atime = ITIME(je32_to_cpu(ri->atime)); - inode->i_ctime = ITIME(je32_to_cpu(ri->ctime)); - inode->i_mtime = ITIME(je32_to_cpu(ri->mtime)); + inode->i_atime = je32_to_cpu(ri->atime); + inode->i_ctime = je32_to_cpu(ri->ctime); + inode->i_mtime = je32_to_cpu(ri->mtime); inode->i_mode = jemode_to_cpu(ri->mode); - i_uid_write(inode, je16_to_cpu(ri->uid)); - i_gid_write(inode, je16_to_cpu(ri->gid)); - + inode->i_uid = je16_to_cpu(ri->uid); + inode->i_gid = je16_to_cpu(ri->gid); old_metadata = f->metadata; + if (ivalid & CHG_SIZE && inode->i_size > attr->attr_chg_size) + jffs2_truncate_fragtree (c, &f->fragtree, attr->attr_chg_size); - if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) - jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size); - - if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { + if (ivalid & CHG_SIZE && inode->i_size < attr->attr_chg_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; + inode->i_size = attr->attr_chg_size; f->metadata = NULL; } else { f->metadata = new_metadata; @@ -182,315 +172,201 @@ 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) { - truncate_setsize(inode, iattr->ia_size); - inode->i_blocks = (inode->i_size + 511) >> 9; + if (ivalid & CHG_SIZE && inode->i_size > attr->attr_chg_size) { + inode->i_size = attr->attr_chg_size; // truncate_setsize } return 0; } -int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) +static void jffs2_clear_inode (struct jffs2_inode *inode) { - struct inode *inode = d_inode(dentry); - int rc; + /* We can forget about this inode for now - drop all + * the nodelists associated with it, etc. + */ + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + + jffs2_do_clear_inode(c, f); +} - rc = setattr_prepare(dentry, iattr); - if (rc) - return rc; +static struct jffs2_inode *ilookup(struct super_block *sb, uint32_t ino) +{ + struct jffs2_inode *node = NULL; - rc = jffs2_do_setattr(inode, iattr); - if (!rc && (iattr->ia_valid & ATTR_MODE)) - rc = posix_acl_chmod(inode, inode->i_mode); + if (sb->s_root == NULL) { + return NULL; + } - return rc; + // Check for this inode in the cache + Jffs2NodeLock(); + (void)Jffs2HashGet(&sb->s_node_hash_lock, &sb->s_node_hash[0], sb, ino, &node); + Jffs2NodeUnlock(); + return node; } -int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf) +struct jffs2_inode *new_inode(struct super_block *sb) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(dentry->d_sb); - unsigned long avail; - - buf->f_type = JFFS2_SUPER_MAGIC; - buf->f_bsize = 1 << PAGE_SHIFT; - buf->f_blocks = c->flash_size >> PAGE_SHIFT; - buf->f_files = 0; - buf->f_ffree = 0; - buf->f_namelen = JFFS2_MAX_NAME_LEN; - buf->f_fsid.val[0] = JFFS2_SUPER_MAGIC; - buf->f_fsid.val[1] = c->mtd->index; - - spin_lock(&c->erase_completion_lock); - avail = c->dirty_size + c->free_size; - if (avail > c->sector_size * c->resv_blocks_write) - avail -= c->sector_size * c->resv_blocks_write; - else - avail = 0; - spin_unlock(&c->erase_completion_lock); - - buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; + struct jffs2_inode *inode = NULL; - return 0; -} + inode = zalloc(sizeof (struct jffs2_inode)); + if (inode == NULL) + return 0; + D2(PRINTK("malloc new_inode %x ####################################\n", + inode)); -void jffs2_evict_inode (struct inode *inode) -{ - /* We can forget about this inode for now - drop all - * the nodelists associated with it, etc. - */ - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + inode->i_sb = sb; + inode->i_ino = 1; + inode->i_nlink = 1; // Let JFFS2 manage the link count + inode->i_size = 0; + LOS_ListInit((&(inode->i_hashlist))); - jffs2_dbg(1, "%s(): ino #%lu mode %o\n", - __func__, inode->i_ino, inode->i_mode); - truncate_inode_pages_final(&inode->i_data); - clear_inode(inode); - jffs2_do_clear_inode(c, f); + return inode; } -struct inode *jffs2_iget(struct super_block *sb, unsigned long ino) +struct jffs2_inode *jffs2_iget(struct super_block *sb, uint32_t ino) { struct jffs2_inode_info *f; struct jffs2_sb_info *c; struct jffs2_raw_inode latest_node; - union jffs2_device_node jdev; - struct inode *inode; - dev_t rdev = 0; + struct jffs2_inode *inode; int ret; - jffs2_dbg(1, "%s(): ino == %lu\n", __func__, ino); - - inode = iget_locked(sb, ino); - if (!inode) - return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) + Jffs2NodeLock(); + inode = ilookup(sb, ino); + if (inode) { + Jffs2NodeUnlock(); return inode; + } + inode = new_inode(sb); + if (inode == NULL) { + Jffs2NodeUnlock(); + return (struct jffs2_inode *)-ENOMEM; + } + inode->i_ino = ino; f = JFFS2_INODE_INFO(inode); c = JFFS2_SB_INFO(inode->i_sb); - jffs2_init_inode_info(f); - mutex_lock(&f->sem); + (void)mutex_init(&f->sem); + (void)mutex_lock(&f->sem); ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); - if (ret) - goto error; + if (ret) { + (void)mutex_unlock(&f->sem); + inode->i_nlink = 0; + free(inode); + Jffs2NodeUnlock(); + return (struct jffs2_inode *)ret; + } inode->i_mode = jemode_to_cpu(latest_node.mode); - i_uid_write(inode, je16_to_cpu(latest_node.uid)); - i_gid_write(inode, je16_to_cpu(latest_node.gid)); + inode->i_uid = je16_to_cpu(latest_node.uid); + inode->i_gid = je16_to_cpu(latest_node.gid); inode->i_size = je32_to_cpu(latest_node.isize); - inode->i_atime = ITIME(je32_to_cpu(latest_node.atime)); - inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); - inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); - - set_nlink(inode, f->inocache->pino_nlink); - - inode->i_blocks = (inode->i_size + 511) >> 9; + inode->i_atime = je32_to_cpu(latest_node.atime); + inode->i_mtime = je32_to_cpu(latest_node.mtime); + inode->i_ctime = je32_to_cpu(latest_node.ctime); + inode->i_nlink = f->inocache->pino_nlink; - switch (inode->i_mode & S_IFMT) { + (void)mutex_unlock(&f->sem); - case S_IFLNK: - inode->i_op = &jffs2_symlink_inode_operations; - inode->i_link = f->target; - break; - - case S_IFDIR: - { - struct jffs2_full_dirent *fd; - set_nlink(inode, 2); /* parent and '.' */ - - for (fd=f->dents; fd; fd = fd->next) { - if (fd->type == DT_DIR && fd->ino) - inc_nlink(inode); - } - /* Root dir gets i_nlink 3 for some reason */ - if (inode->i_ino == 1) - inc_nlink(inode); - - inode->i_op = &jffs2_dir_inode_operations; - inode->i_fop = &jffs2_dir_operations; - break; - } - case S_IFREG: - inode->i_op = &jffs2_file_inode_operations; - inode->i_fop = &jffs2_file_operations; - inode->i_mapping->a_ops = &jffs2_file_address_operations; - inode->i_mapping->nrpages = 0; - break; - - case S_IFBLK: - case S_IFCHR: - /* Read the device numbers from the media */ - if (f->metadata->size != sizeof(jdev.old_id) && - f->metadata->size != sizeof(jdev.new_id)) { - pr_notice("Device node has strange size %d\n", - f->metadata->size); - goto error_io; - } - jffs2_dbg(1, "Reading device numbers from flash\n"); - ret = jffs2_read_dnode(c, f, f->metadata, (char *)&jdev, 0, f->metadata->size); - if (ret < 0) { - /* Eep */ - pr_notice("Read device numbers for inode %lu failed\n", - (unsigned long)inode->i_ino); - goto error; - } - if (f->metadata->size == sizeof(jdev.old_id)) - rdev = old_decode_dev(je16_to_cpu(jdev.old_id)); - else - rdev = new_decode_dev(je32_to_cpu(jdev.new_id)); - fallthrough; - - case S_IFSOCK: - case S_IFIFO: - inode->i_op = &jffs2_file_inode_operations; - init_special_inode(inode, inode->i_mode, rdev); - break; - - default: - pr_warn("%s(): Bogus i_mode %o for ino %lu\n", - __func__, inode->i_mode, (unsigned long)inode->i_ino); - } - - mutex_unlock(&f->sem); + (void)Jffs2HashInsert(&sb->s_node_hash_lock, &sb->s_node_hash[0], inode, ino); jffs2_dbg(1, "jffs2_read_inode() returning\n"); - unlock_new_inode(inode); - return inode; + Jffs2NodeUnlock(); -error_io: - ret = -EIO; -error: - mutex_unlock(&f->sem); - iget_failed(inode); - return ERR_PTR(ret); + return inode; } -void jffs2_dirty_inode(struct inode *inode, int flags) -{ - struct iattr iattr; - if (!(inode->i_state & I_DIRTY_DATASYNC)) { - jffs2_dbg(2, "%s(): not calling setattr() for ino #%lu\n", - __func__, inode->i_ino); - return; - } - - jffs2_dbg(1, "%s(): calling setattr() for ino #%lu\n", - __func__, inode->i_ino); - - iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME; - iattr.ia_mode = inode->i_mode; - iattr.ia_uid = inode->i_uid; - iattr.ia_gid = inode->i_gid; - iattr.ia_atime = inode->i_atime; - iattr.ia_mtime = inode->i_mtime; - iattr.ia_ctime = inode->i_ctime; - - jffs2_do_setattr(inode, &iattr); -} +// ------------------------------------------------------------------------- +// Decrement the reference count on an inode. If this makes the ref count +// zero, then this inode can be freed. -int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc) +int jffs2_iput(struct jffs2_inode *i) { - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - - if (c->flags & JFFS2_SB_FLAG_RO && !sb_rdonly(sb)) - return -EROFS; - - /* We stop if it was running, then restart if it needs to. - This also catches the case where it was stopped and this - is just a remount to restart it. - Flush the writebuffer, if neccecary, else we loose it */ - if (!sb_rdonly(sb)) { - jffs2_stop_garbage_collect_thread(c); - mutex_lock(&c->alloc_sem); - jffs2_flush_wbuf_pad(c); - mutex_unlock(&c->alloc_sem); - } - - if (!(fc->sb_flags & SB_RDONLY)) - jffs2_start_garbage_collect_thread(c); + // Called in jffs2_find + // (and jffs2_open and jffs2_ops_mkdir?) + // super.c jffs2_fill_super, + // and gc.c jffs2_garbage_collect_pass + struct jffs2_inode_info *f = NULL; + + Jffs2NodeLock(); + if (!i || i->i_nlink) { + // and let it fault... + Jffs2NodeUnlock(); + return -EBUSY; + } + + jffs2_clear_inode(i); + f = JFFS2_INODE_INFO(i); + (void)mutex_destroy(&(f->sem)); + (void)Jffs2HashRemove(&i->i_sb->s_node_hash_lock, i); + (void)memset_s(i, sizeof(*i), 0x5a, sizeof(*i)); + free(i); + Jffs2NodeUnlock(); - fc->sb_flags |= SB_NOATIME; return 0; } + /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, fill in the raw_inode while you're at it. */ -struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_raw_inode *ri) +struct jffs2_inode *jffs2_new_inode (struct jffs2_inode *dir_i, int mode, struct jffs2_raw_inode *ri) { - struct inode *inode; + struct jffs2_inode *inode; struct super_block *sb = dir_i->i_sb; struct jffs2_sb_info *c; struct jffs2_inode_info *f; int ret; - jffs2_dbg(1, "%s(): dir_i %ld, mode 0x%x\n", - __func__, dir_i->i_ino, mode); - c = JFFS2_SB_INFO(sb); + Jffs2NodeLock(); inode = new_inode(sb); if (!inode) - return ERR_PTR(-ENOMEM); + return (struct jffs2_inode *)-ENOMEM; f = JFFS2_INODE_INFO(inode); - jffs2_init_inode_info(f); - mutex_lock(&f->sem); + (void)mutex_init(&f->sem); + (void)mutex_lock(&f->sem);; memset(ri, 0, sizeof(*ri)); /* Set OS-specific defaults for new inodes */ - ri->uid = cpu_to_je16(from_kuid(&init_user_ns, current_fsuid())); + ri->uid = cpu_to_je16(OsCurrUserGet()->effUserID); + ri->gid = cpu_to_je16(OsCurrUserGet()->effGid); - if (dir_i->i_mode & S_ISGID) { - ri->gid = cpu_to_je16(i_gid_read(dir_i)); - if (S_ISDIR(mode)) - mode |= S_ISGID; - } else { - ri->gid = cpu_to_je16(from_kgid(&init_user_ns, current_fsgid())); - } - - /* POSIX ACLs have to be processed now, at least partly. - The umask is only applied if there's no default ACL */ - ret = jffs2_init_acl_pre(dir_i, inode, &mode); - if (ret) { - mutex_unlock(&f->sem); - make_bad_inode(inode); - iput(inode); - return ERR_PTR(ret); - } ret = jffs2_do_new_inode (c, f, mode, ri); if (ret) { - mutex_unlock(&f->sem); - make_bad_inode(inode); - iput(inode); - return ERR_PTR(ret); + mutex_unlock(&(f->sem)); + jffs2_clear_inode(inode); + (void)mutex_destroy(&(f->sem)); + (void)memset_s(inode, sizeof(*inode), 0x6a, sizeof(*inode)); + free(inode); + Jffs2NodeUnlock(); + return (struct jffs2_inode *)ret; + } - set_nlink(inode, 1); + inode->i_nlink = 1; inode->i_ino = je32_to_cpu(ri->ino); inode->i_mode = jemode_to_cpu(ri->mode); - i_gid_write(inode, je16_to_cpu(ri->gid)); - i_uid_write(inode, je16_to_cpu(ri->uid)); - inode->i_atime = inode->i_ctime = inode->i_mtime = current_time(inode); - ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime)); + inode->i_gid = je16_to_cpu(ri->gid); + inode->i_uid = je16_to_cpu(ri->uid); + inode->i_atime = inode->i_ctime = inode->i_mtime = Jffs2CurSec(); + ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime); - inode->i_blocks = 0; inode->i_size = 0; - if (insert_inode_locked(inode) < 0) { - mutex_unlock(&f->sem); - make_bad_inode(inode); - iput(inode); - return ERR_PTR(-EINVAL); - } + (void)Jffs2HashInsert(&sb->s_node_hash_lock, &sb->s_node_hash[0], inode, inode->i_ino); + Jffs2NodeUnlock(); return inode; } -static int calculate_inocache_hashsize(uint32_t flash_size) +int calculate_inocache_hashsize(uint32_t flash_size) { /* * Pick a inocache hash size based on the size of the medium. @@ -510,117 +386,17 @@ static int calculate_inocache_hashsize(uint32_t flash_size) return hashsize; } -int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc) -{ - struct jffs2_sb_info *c; - struct inode *root_i; - int ret; - size_t blocks; - - c = JFFS2_SB_INFO(sb); - - /* Do not support the MLC nand */ - if (c->mtd->type == MTD_MLCNANDFLASH) - return -EINVAL; - -#ifndef CONFIG_JFFS2_FS_WRITEBUFFER - if (c->mtd->type == MTD_NANDFLASH) { - errorf(fc, "Cannot operate on NAND flash unless jffs2 NAND support is compiled in"); - return -EINVAL; - } - if (c->mtd->type == MTD_DATAFLASH) { - errorf(fc, "Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in"); - return -EINVAL; - } -#endif - - c->flash_size = c->mtd->size; - c->sector_size = c->mtd->erasesize; - blocks = c->flash_size / c->sector_size; - - /* - * Size alignment check - */ - if ((c->sector_size * blocks) != c->flash_size) { - c->flash_size = c->sector_size * blocks; - infof(fc, "Flash size not aligned to erasesize, reducing to %dKiB", - c->flash_size / 1024); - } - - if (c->flash_size < 5*c->sector_size) { - errorf(fc, "Too few erase blocks (%d)", - c->flash_size / c->sector_size); - return -EINVAL; - } - - c->cleanmarker_size = sizeof(struct jffs2_unknown_node); - - /* NAND (or other bizarre) flash... do setup accordingly */ - ret = jffs2_flash_setup(c); - if (ret) - return ret; - - c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size); - c->inocache_list = kcalloc(c->inocache_hashsize, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); - if (!c->inocache_list) { - ret = -ENOMEM; - goto out_wbuf; - } - - jffs2_init_xattr_subsystem(c); - - if ((ret = jffs2_do_mount_fs(c))) - goto out_inohash; - - jffs2_dbg(1, "%s(): Getting root inode\n", __func__); - root_i = jffs2_iget(sb, 1); - if (IS_ERR(root_i)) { - jffs2_dbg(1, "get root inode failed\n"); - ret = PTR_ERR(root_i); - goto out_root; - } - - ret = -ENOMEM; - - jffs2_dbg(1, "%s(): d_make_root()\n", __func__); - sb->s_root = d_make_root(root_i); - if (!sb->s_root) - goto out_root; - - sb->s_maxbytes = 0xFFFFFFFF; - sb->s_blocksize = PAGE_SIZE; - sb->s_blocksize_bits = PAGE_SHIFT; - sb->s_magic = JFFS2_SUPER_MAGIC; - sb->s_time_min = 0; - sb->s_time_max = U32_MAX; - - if (!sb_rdonly(sb)) - jffs2_start_garbage_collect_thread(c); - return 0; - -out_root: - jffs2_free_ino_caches(c); - jffs2_free_raw_node_refs(c); - kvfree(c->blocks); - out_inohash: - jffs2_clear_xattr_subsystem(c); - kfree(c->inocache_list); - out_wbuf: - jffs2_flash_cleanup(c); - - return ret; -} - void jffs2_gc_release_inode(struct jffs2_sb_info *c, - struct jffs2_inode_info *f) + struct jffs2_inode_info *f) { - iput(OFNI_EDONI_2SFFJ(f)); + struct jffs2_inode *node = OFNI_EDONI_2SFFJ(f); + jffs2_iput(node); } struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, int inum, int unlinked) { - struct inode *inode; + struct jffs2_inode *inode; struct jffs2_inode_cache *ic; if (unlinked) { @@ -668,72 +444,9 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, Just iget() it, and if read_inode() is necessary that's OK. */ inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum); - if (IS_ERR(inode)) - return ERR_CAST(inode); - } - if (is_bad_inode(inode)) { - pr_notice("Eep. read_inode() failed for ino #%u. unlinked %d\n", - inum, unlinked); - /* NB. This will happen again. We need to do something appropriate here. */ - iput(inode); - return ERR_PTR(-EIO); + if (inode <= 0) + return (struct jffs2_inode_info *)inode; } return JFFS2_INODE_INFO(inode); } - -static int jffs2_flash_setup(struct jffs2_sb_info *c) { - int ret = 0; - - if (jffs2_cleanmarker_oob(c)) { - /* NAND flash... do setup accordingly */ - ret = jffs2_nand_flash_setup(c); - if (ret) - return ret; - } - - /* and Dataflash */ - if (jffs2_dataflash(c)) { - ret = jffs2_dataflash_setup(c); - if (ret) - return ret; - } - - /* and Intel "Sibley" flash */ - if (jffs2_nor_wbuf_flash(c)) { - ret = jffs2_nor_wbuf_flash_setup(c); - if (ret) - return ret; - } - - /* and an UBI volume */ - if (jffs2_ubivol(c)) { - ret = jffs2_ubivol_setup(c); - if (ret) - return ret; - } - - return ret; -} - -void jffs2_flash_cleanup(struct jffs2_sb_info *c) { - - if (jffs2_cleanmarker_oob(c)) { - jffs2_nand_flash_cleanup(c); - } - - /* and DataFlash */ - if (jffs2_dataflash(c)) { - jffs2_dataflash_cleanup(c); - } - - /* and Intel "Sibley" flash */ - if (jffs2_nor_wbuf_flash(c)) { - jffs2_nor_wbuf_flash_cleanup(c); - } - - /* and an UBI volume */ - if (jffs2_ubivol(c)) { - jffs2_ubivol_cleanup(c); - } -} diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 373b3b7c9f44570ed523332720e116556805214f..f191522a866d13e846fba628ca6bfee315232d58 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -10,17 +10,17 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include -#include #include #include -#include +#include +#include #include #include +#include "mtd_dev.h" #include "nodelist.h" #include "compr.h" +#include "los_crc32.h" static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, @@ -131,7 +131,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) int ret = 0, inum, nlink; int xattr = 0; - if (mutex_lock_interruptible(&c->alloc_sem)) + if (mutex_lock(&c->alloc_sem)) return -EINTR; @@ -198,6 +198,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) switch(ic->state) { case INO_STATE_CHECKEDABSENT: case INO_STATE_PRESENT: + jffs2_dbg(1, "Skipping ino #%u already checked\n", + ic->ino); spin_unlock(&c->inocache_lock); continue; @@ -207,6 +209,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ic->ino, ic->state); spin_unlock(&c->inocache_lock); BUG(); + break; case INO_STATE_READING: /* We need to wait for it to finish, lest we move on @@ -224,6 +227,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) default: BUG(); + break; case INO_STATE_UNCHECKED: ; @@ -290,7 +294,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) raw = jeb->gc_node; gcblock_dirty = jeb->dirty_size; - while(ref_obsolete(raw)) { + while(raw && ref_obsolete(raw)) { jffs2_dbg(1, "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)); raw = ref_next(raw); @@ -310,7 +314,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) jffs2_dbg(1, "Going to garbage collect node at 0x%08x\n", ref_offset(raw)); - if (!raw->next_in_ino) { + if (raw &&!raw->next_in_ino) { /* Inode-less node. Clean marker, snapshot or something like that */ spin_unlock(&c->erase_completion_lock); if (ref_flags(raw) == REF_PRISTINE) { @@ -368,7 +372,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) We can just copy any pristine nodes, but have to prevent anyone else from doing read_inode() while we're at it, so we set the state accordingly */ - if (ref_flags(raw) == REF_PRISTINE) + if (raw && ref_flags(raw) == REF_PRISTINE) ic->state = INO_STATE_GC; else { jffs2_dbg(1, "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", @@ -393,6 +397,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) mutex_unlock(&c->alloc_sem); spin_unlock(&c->inocache_lock); BUG(); + break; case INO_STATE_READING: /* Someone's currently trying to read it. We must wait for @@ -430,7 +435,6 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) spin_lock(&c->inocache_lock); ic->state = INO_STATE_CHECKEDABSENT; - wake_up(&c->inocache_wq); if (ret != -EBADFD) { spin_unlock(&c->inocache_lock); @@ -460,9 +464,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ret = 0; goto release_sem; } - ret = jffs2_garbage_collect_live(c, jeb, raw, f); - jffs2_gc_release_inode(c, f); test_gcnode: @@ -541,7 +543,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_era break; /* We've found them all */ } } - if (fn) { + if (fn != NULL && frag != NULL) { if (ref_flags(raw) == REF_PRISTINE) { ret = jffs2_garbage_collect_pristine(c, f->inocache, raw); if (!ret) { @@ -635,6 +637,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, if (je32_to_cpu(node->u.hdr_crc) != crc) { pr_warn("Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); + jffs2_dbg_dump_node(c, ref_offset(raw)); goto bail; } @@ -645,6 +648,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, pr_warn("Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(raw), je32_to_cpu(node->i.node_crc), crc); + jffs2_dbg_dump_node(c, ref_offset(raw)); goto bail; } @@ -654,6 +658,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, pr_warn("Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(raw), je32_to_cpu(node->i.data_crc), crc); + jffs2_dbg_dump_node(c, ref_offset(raw)); goto bail; } } @@ -665,12 +670,14 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, pr_warn("Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(raw), je32_to_cpu(node->d.node_crc), crc); + jffs2_dbg_dump_node(c, ref_offset(raw)); goto bail; } - if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) { + if (strnlen((const char *)node->d.name, node->d.nsize) != node->d.nsize) { pr_warn("Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw)); + jffs2_dbg_dump_node(c, ref_offset(raw)); goto bail; } @@ -680,6 +687,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, pr_warn("Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); + jffs2_dbg_dump_node(c, ref_offset(raw)); goto bail; } } @@ -689,6 +697,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, if (ic) { pr_warn("Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", ref_offset(raw), je16_to_cpu(node->u.nodetype)); + jffs2_dbg_dump_node(c, ref_offset(raw)); goto bail; } } @@ -697,7 +706,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, retry: phys_ofs = write_ofs(c); - ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); + ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (const u_char *)node); if (ret || (retlen != rawlen)) { pr_notice("Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", @@ -761,7 +770,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; struct jffs2_node_frag *last_frag; - union jffs2_device_node dev; + jint16_t dev; char *mdata = NULL; int mdatalen = 0; uint32_t alloclen, ilen; @@ -770,8 +779,9 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ if (S_ISBLK(JFFS2_F_I_MODE(f)) || S_ISCHR(JFFS2_F_I_MODE(f)) ) { /* For these, we don't actually need to read the old node */ - mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f)); + dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | JFFS2_F_I_RDEV_MIN(f))); mdata = (char *)&dev; + mdatalen = sizeof(dev); jffs2_dbg(1, "%s(): Writing %d bytes of kdev_t\n", __func__, mdatalen); } else if (S_ISLNK(JFFS2_F_I_MODE(f))) { @@ -781,7 +791,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ pr_warn("kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n"); return -ENOMEM; } - ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen); + ret = jffs2_read_dnode(c, f, fn, (unsigned char *)mdata, 0, mdatalen); if (ret) { pr_warn("read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", ret); @@ -831,7 +841,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); - new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, ALLOC_GC); + new_fn = jffs2_write_dnode(c, f, &ri, (unsigned char *)mdata, mdatalen, ALLOC_GC); if (IS_ERR(new_fn)) { pr_warn("Error writing new dnode: %ld\n", PTR_ERR(new_fn)); @@ -857,7 +867,7 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); - rd.nsize = strlen(fd->name); + rd.nsize = strlen((const char *)fd->name); rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize); rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4)); @@ -908,7 +918,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct struct jffs2_raw_node_ref *raw; int ret; size_t retlen; - int name_len = strlen(fd->name); + int name_len = strlen((const char *)fd->name); uint32_t name_crc = crc32(0, fd->name, name_len); uint32_t rawlen = ref_totlen(c, jeb, fd->raw); @@ -1053,6 +1063,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras pr_warn("%s: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", __func__, ref_offset(fn->raw), je32_to_cpu(ri.node_crc), crc); + jffs2_dbg_dump_node(c, ref_offset(fn->raw)); /* FIXME: We could possibly deal with this by writing new holes for each frag */ pr_warn("Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", start, end, f->inocache->ino); @@ -1165,13 +1176,12 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, uint32_t start, uint32_t end) { - struct inode *inode = OFNI_EDONI_2SFFJ(f); struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; uint32_t alloclen, offset, orig_end, orig_start; int ret = 0; unsigned char *comprbuf = NULL, *writebuf; - struct page *page; + unsigned long pg; unsigned char *pg_ptr; memset(&ri, 0, sizeof(ri)); @@ -1203,7 +1213,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era BUG_ON(frag->ofs != start); /* First grow down... */ - while((frag = frag_prev(frag)) && frag->ofs >= min) { + while(frag && (frag = frag_prev(frag)) && frag->ofs >= min) { /* If the previous frag doesn't even reach the beginning, there's excessive fragmentation. Just merge. */ @@ -1259,7 +1269,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era /* Find last frag which is actually part of the node we're to GC. */ frag = jffs2_lookup_node_frag(&f->fragtree, end-1); - while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) { + while(frag && (frag = frag_next(frag)) && frag->ofs+frag->size <= max) { /* If the previous frag doesn't even reach the beginning, there's lots of fragmentation. Just merge. */ @@ -1317,27 +1327,21 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era BUG_ON(start > orig_start); } - /* The rules state that we must obtain the page lock *before* f->sem, so - * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's - * actually going to *change* so we're safe; we only allow reading. - * - * It is important to note that jffs2_write_begin() will ensure that its - * page is marked Uptodate before allocating space. That means that if we - * end up here trying to GC the *same* page that jffs2_write_begin() is - * trying to write out, read_cache_page() will not deadlock. */ - mutex_unlock(&f->sem); - page = read_cache_page(inode->i_mapping, start >> PAGE_SHIFT, - jffs2_do_readpage_unlock, inode); - if (IS_ERR(page)) { + /* First, use readpage() to read the appropriate page into the page cache */ + /* Q: What happens if we actually try to GC the _same_ page for which commit_write() + * triggered garbage collection in the first place? + * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the + * page OK. We'll actually write it out again in commit_write, which is a little + * suboptimal, but at least we're correct. + */ + pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); + + if (IS_ERR(pg_ptr)) { pr_warn("read_cache_page() returned error: %ld\n", - PTR_ERR(page)); - mutex_lock(&f->sem); - return PTR_ERR(page); + PTR_ERR(pg_ptr)); + return PTR_ERR(pg_ptr); } - pg_ptr = kmap(page); - mutex_lock(&f->sem); - offset = start; while(offset < orig_end) { uint32_t datalen; @@ -1400,7 +1404,6 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era } } - kunmap(page); - put_page(page); + jffs2_gc_release_page(c, pg_ptr, &pg); return ret; } diff --git a/fs/jffs2/jffs2.h b/fs/jffs2/jffs2.h new file mode 100644 index 0000000000000000000000000000000000000000..d4c76aa1d8b63b5a3e22813c0f7d05730685f586 --- /dev/null +++ b/fs/jffs2/jffs2.h @@ -0,0 +1,231 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright © 2001-2007 Red Hat, Inc. + * Copyright © 2004-2010 David Woodhouse + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. + */ + +#ifndef __LINUX_JFFS2_H__ +#define __LINUX_JFFS2_H__ + +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define KBUILD_MODNAME "Jffs2: " +/* You must include something which defines the C99 uintXX_t types. + We don't do it from here because this file is used in too many + different environments. */ + +#define JFFS2_SUPER_MAGIC 0x72b6 + +/* Values we may expect to find in the 'magic' field */ +#define JFFS2_OLD_MAGIC_BITMASK 0x1984 +#define JFFS2_MAGIC_BITMASK 0x1985 +#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ +#define JFFS2_EMPTY_BITMASK 0xffff +#define JFFS2_DIRTY_BITMASK 0x0000 + +/* Summary node MAGIC marker */ +#define JFFS2_SUM_MAGIC 0x02851885 + +/* We only allow a single char for length, and 0xFF is empty flash so + we don't want it confused with a real length. Hence max 254. +*/ +#define JFFS2_MAX_NAME_LEN 254 + +/* How small can we sensibly write nodes? */ +#define JFFS2_MIN_DATA_LEN 128 + +#define JFFS2_COMPR_NONE 0x00 +#define JFFS2_COMPR_ZERO 0x01 +#define JFFS2_COMPR_RTIME 0x02 +#define JFFS2_COMPR_RUBINMIPS 0x03 +#define JFFS2_COMPR_COPY 0x04 +#define JFFS2_COMPR_DYNRUBIN 0x05 +#define JFFS2_COMPR_ZLIB 0x06 +#define JFFS2_COMPR_LZO 0x07 +/* Compatibility flags. */ +#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ +#define JFFS2_NODE_ACCURATE 0x2000 +/* INCOMPAT: Fail to mount the filesystem */ +#define JFFS2_FEATURE_INCOMPAT 0xc000 +/* ROCOMPAT: Mount read-only */ +#define JFFS2_FEATURE_ROCOMPAT 0x8000 +/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 +/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 + +#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) +#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) +#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) + +#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) + +#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) +#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) + +/* XATTR Related */ +#define JFFS2_XPREFIX_USER 1 /* for "user." */ +#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */ +#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */ +#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */ +#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */ + +#define JFFS2_ACL_VERSION 0x0001 + +// Maybe later... +//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) + + +#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at + mount time, don't wait for it to + happen later */ +#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific + compression type */ + + +/* These can go once we've made sure we've caught all uses without + byteswapping */ + +typedef struct { + uint32_t v32; +} __attribute__((packed)) jint32_t; + +typedef struct { + uint32_t m; +} __attribute__((packed)) jmode_t; + +typedef struct { + uint16_t v16; +} __attribute__((packed)) jint16_t; + +struct jffs2_unknown_node +{ + /* All start like this */ + jint16_t magic; + jint16_t nodetype; + jint32_t totlen; /* So we can skip over nodes we don't grok */ + jint32_t hdr_crc; +}; + +struct jffs2_raw_dirent +{ + jint16_t magic; + jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t pino; + jint32_t version; + jint32_t ino; /* == zero for unlink */ + jint32_t mctime; + uint8_t nsize; + uint8_t type; + uint8_t unused[2]; + jint32_t node_crc; + jint32_t name_crc; + uint8_t name[0]; +}; + +/* The JFFS2 raw inode structure: Used for storage on physical media. */ +/* The uid, gid, atime, mtime and ctime members could be longer, but + are left like this for space efficiency. If and when people decide + they really need them extended, it's simple enough to add support for + a new type of raw node. +*/ +struct jffs2_raw_inode +{ + jint16_t magic; /* A constant magic number. */ + jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */ + jint32_t totlen; /* Total length of this node (inc data, etc.) */ + jint32_t hdr_crc; + jint32_t ino; /* Inode number. */ + jint32_t version; /* Version number. */ + jmode_t mode; /* The file's type or mode. */ + jint16_t uid; /* The file's owner. */ + jint16_t gid; /* The file's group. */ + jint32_t isize; /* Total resultant size of this inode (used for truncations) */ + jint32_t atime; /* Last access time. */ + jint32_t mtime; /* Last modification time. */ + jint32_t ctime; /* Change time. */ + jint32_t offset; /* Where to begin to write. */ + jint32_t csize; /* (Compressed) data size */ + jint32_t dsize; /* Size of the node's data. (after decompression) */ + uint8_t compr; /* Compression algorithm used */ + uint8_t usercompr; /* Compression algorithm requested by the user */ + jint16_t flags; /* See JFFS2_INO_FLAG_* */ + jint32_t data_crc; /* CRC for the (compressed) data. */ + jint32_t node_crc; /* CRC for the raw inode (excluding data) */ + uint8_t data[0]; +}; + +struct jffs2_raw_xattr { + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t xid; /* XATTR identifier number */ + jint32_t version; + uint8_t xprefix; + uint8_t name_len; + jint16_t value_len; + jint32_t data_crc; + jint32_t node_crc; + uint8_t data[0]; +} __attribute__((packed)); + +struct jffs2_raw_xref +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t ino; /* inode number */ + jint32_t xid; /* XATTR identifier number */ + jint32_t xseqno; /* xref sequential number */ + jint32_t node_crc; +} __attribute__((packed)); + +struct jffs2_raw_summary +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t sum_num; /* number of sum entries*/ + jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */ + jint32_t padded; /* sum of the size of padding nodes */ + jint32_t sum_crc; /* summary information crc */ + jint32_t node_crc; /* node crc */ + jint32_t sum[0]; /* inode summary info */ +}; + +union jffs2_node_union +{ + struct jffs2_raw_inode i; + struct jffs2_raw_dirent d; + struct jffs2_raw_xattr x; + struct jffs2_raw_xref r; + struct jffs2_raw_summary s; + struct jffs2_unknown_node u; +}; + +/* Data payload for device nodes. */ +union jffs2_device_node { + jint16_t old_id; + jint32_t new_id; +}; + +#endif /* __LINUX_JFFS2_H__ */ diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index 2e4a86763c07cd12b945518690768c4a0388de5f..77681a2e99d9f2ffb709478ad3987c107dd4c1ff 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h @@ -14,8 +14,13 @@ #define _JFFS2_FS_I #include -#include -#include +#include + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ struct jffs2_inode_info { /* We need an internal mutex similar to inode->i_mutex. @@ -24,7 +29,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 mutex sem; + struct pthread_mutex sem; /* The highest (datanode) version number used for this ino */ uint32_t highest_version; @@ -50,7 +55,29 @@ struct jffs2_inode_info { uint16_t flags; uint8_t usercompr; - struct inode vfs_inode; }; +struct super_block; + +struct jffs2_inode { + uint32_t i_ino; + mode_t i_mode; + nlink_t i_nlink; + uid_t i_uid; + gid_t i_gid; + time_t i_atime; + time_t i_mtime; + time_t i_ctime; + off_t i_size; + struct super_block *i_sb; + LOS_DL_LIST i_hashlist; + struct jffs2_inode_info jffs2_i; +}; + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + #endif /* _JFFS2_FS_I */ diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 5a7091746f68b3686e076751c23f0442b6cc1888..771d5547ccf95eb69ffb750312cc0f49fa1180b3 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -17,11 +17,18 @@ #include #include #include -#include #include #include #include #include +#include "vfs_jffs2.h" +#include "mtd_dev.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ #define JFFS2_SB_FLAG_RO 1 #define JFFS2_SB_FLAG_SCANNING 2 /* Flash scanning is in progress */ @@ -47,18 +54,19 @@ struct jffs2_mount_opts { Nee jffs_control */ struct jffs2_sb_info { - struct mtd_info *mtd; + struct MtdDev *mtd; uint32_t highest_ino; uint32_t check_ino; /* *NEXT* inode to be checked */ + unsigned int flags; struct task_struct *gc_task; /* GC task struct */ struct completion gc_thread_start; /* GC thread start completion */ struct completion gc_thread_exit; /* GC thread exit completion port */ - struct mutex alloc_sem; /* Used to protect all the following + struct pthread_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 @@ -120,7 +128,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 mutex erase_free_sem; + struct pthread_mutex erase_free_sem; uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */ @@ -160,4 +168,27 @@ struct jffs2_sb_info { void *os_priv; }; +struct super_block { + struct jffs2_sb_info jffs2_sb; + LIST_HEAD s_node_hash[JFFS2_NODE_HASH_BUCKETS]; + LosMux s_node_hash_lock; + struct jffs2_inode *s_root; + void *s_dev; + + UINT32 s_lock; /* Lock the inode cache */ + EVENT_CB_S s_gc_thread_flags; /* Communication with the gcthread */ + unsigned int s_gc_thread; + unsigned long s_mount_flags; +}; + +#define JFFS2_SB_INFO(sb) (&(sb)->jffs2_sb) +#define OFNI_BS_2SFFJ(c) \ + ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->jffs2_sb)) ) ) + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + #endif /* _JFFS2_FS_SB */ diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index ce11897932889dfcd707140e331e11615e0ebaed..84ecc042eff1bc47c9cb8b0ec3aadb18025791f3 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -9,111 +9,31 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include -#include -#include +#include #include "nodelist.h" -/* These are initialised to NULL in the kernel startup code. - If you're porting to other operating systems, beware */ -static struct kmem_cache *full_dnode_slab; -static struct kmem_cache *raw_dirent_slab; -static struct kmem_cache *raw_inode_slab; -static struct kmem_cache *tmp_dnode_info_slab; -static struct kmem_cache *raw_node_ref_slab; -static struct kmem_cache *node_frag_slab; -static struct kmem_cache *inode_cache_slab; -#ifdef CONFIG_JFFS2_FS_XATTR -static struct kmem_cache *xattr_datum_cache; -static struct kmem_cache *xattr_ref_cache; +#if !defined(JFFS2NUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE) +# define JFFS2NUM_FS_JFFS2_RAW_NODE_REF_CACHE_POOL_SIZE 0 #endif int __init jffs2_create_slab_caches(void) { - full_dnode_slab = kmem_cache_create("jffs2_full_dnode", - sizeof(struct jffs2_full_dnode), - 0, 0, NULL); - if (!full_dnode_slab) - goto err; - - raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", - sizeof(struct jffs2_raw_dirent), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!raw_dirent_slab) - goto err; - - raw_inode_slab = kmem_cache_create("jffs2_raw_inode", - sizeof(struct jffs2_raw_inode), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!raw_inode_slab) - goto err; - - tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", - sizeof(struct jffs2_tmp_dnode_info), - 0, 0, NULL); - if (!tmp_dnode_info_slab) - goto err; - - raw_node_ref_slab = kmem_cache_create("jffs2_refblock", - sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), - 0, 0, NULL); - if (!raw_node_ref_slab) - goto err; - - node_frag_slab = kmem_cache_create("jffs2_node_frag", - sizeof(struct jffs2_node_frag), - 0, 0, NULL); - if (!node_frag_slab) - goto err; - - inode_cache_slab = kmem_cache_create("jffs2_inode_cache", - sizeof(struct jffs2_inode_cache), - 0, 0, NULL); - if (!inode_cache_slab) - goto err; - -#ifdef CONFIG_JFFS2_FS_XATTR - xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", - sizeof(struct jffs2_xattr_datum), - 0, 0, NULL); - if (!xattr_datum_cache) - goto err; - - xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", - sizeof(struct jffs2_xattr_ref), - 0, 0, NULL); - if (!xattr_ref_cache) - goto err; -#endif - return 0; - err: - jffs2_destroy_slab_caches(); - return -ENOMEM; + } void jffs2_destroy_slab_caches(void) { - kmem_cache_destroy(full_dnode_slab); - kmem_cache_destroy(raw_dirent_slab); - kmem_cache_destroy(raw_inode_slab); - kmem_cache_destroy(tmp_dnode_info_slab); - kmem_cache_destroy(raw_node_ref_slab); - kmem_cache_destroy(node_frag_slab); - kmem_cache_destroy(inode_cache_slab); -#ifdef CONFIG_JFFS2_FS_XATTR - kmem_cache_destroy(xattr_datum_cache); - kmem_cache_destroy(xattr_ref_cache); -#endif + return; } + struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) { struct jffs2_full_dirent *ret; - ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); + ret = zalloc(sizeof(struct jffs2_full_dirent) + namesize); dbg_memalloc("%p\n", ret); return ret; } @@ -127,7 +47,7 @@ void jffs2_free_full_dirent(struct jffs2_full_dirent *x) struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) { struct jffs2_full_dnode *ret; - ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + ret = zalloc(sizeof(struct jffs2_full_dnode)); dbg_memalloc("%p\n", ret); return ret; } @@ -135,13 +55,13 @@ struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) void jffs2_free_full_dnode(struct jffs2_full_dnode *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(full_dnode_slab, x); + free(x); } struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) { struct jffs2_raw_dirent *ret; - ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + ret = zalloc(sizeof(struct jffs2_raw_dirent)); dbg_memalloc("%p\n", ret); return ret; } @@ -149,13 +69,13 @@ struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(raw_dirent_slab, x); + free(x); } struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) { struct jffs2_raw_inode *ret; - ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + ret = zalloc(sizeof(struct jffs2_raw_inode)); dbg_memalloc("%p\n", ret); return ret; } @@ -163,13 +83,13 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) void jffs2_free_raw_inode(struct jffs2_raw_inode *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(raw_inode_slab, x); + free(x); } struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) { struct jffs2_tmp_dnode_info *ret; - ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + ret = zalloc(sizeof(struct jffs2_tmp_dnode_info)); dbg_memalloc("%p\n", ret); return ret; @@ -178,14 +98,14 @@ struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(tmp_dnode_info_slab, x); + free(x); } static struct jffs2_raw_node_ref *jffs2_alloc_refblock(void) { struct jffs2_raw_node_ref *ret; - ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + ret = malloc(sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK+1)); if (ret) { int i = 0; for (i=0; i < REFS_PER_BLOCK; i++) { @@ -242,13 +162,13 @@ int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, void jffs2_free_refblock(struct jffs2_raw_node_ref *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(raw_node_ref_slab, x); + free(x); } struct jffs2_node_frag *jffs2_alloc_node_frag(void) { struct jffs2_node_frag *ret; - ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + ret = malloc(sizeof(struct jffs2_node_frag)); dbg_memalloc("%p\n", ret); return ret; } @@ -256,13 +176,14 @@ struct jffs2_node_frag *jffs2_alloc_node_frag(void) void jffs2_free_node_frag(struct jffs2_node_frag *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(node_frag_slab, x); + free(x); } + struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) { struct jffs2_inode_cache *ret; - ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); + ret = zalloc(sizeof(struct jffs2_inode_cache));; dbg_memalloc("%p\n", ret); return ret; } @@ -270,14 +191,14 @@ struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) void jffs2_free_inode_cache(struct jffs2_inode_cache *x) { dbg_memalloc("%p\n", x); - kmem_cache_free(inode_cache_slab, x); + kfree(x); } #ifdef CONFIG_JFFS2_FS_XATTR struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) { struct jffs2_xattr_datum *xd; - xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL); + xd = malloc(sizeof(struct jffs2_xattr_datum)); dbg_memalloc("%p\n", xd); if (!xd) return NULL; @@ -291,13 +212,13 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) void jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd) { dbg_memalloc("%p\n", xd); - kmem_cache_free(xattr_datum_cache, xd); + kfree(xd); } struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) { struct jffs2_xattr_ref *ref; - ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL); + ref = malloc(sizeof(struct jffs2_xattr_ref)); dbg_memalloc("%p\n", ref); if (!ref) return NULL; @@ -310,6 +231,6 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref) { dbg_memalloc("%p\n", ref); - kmem_cache_free(xattr_ref_cache, ref); + kfree(ref); } #endif diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index b86c78d178c60a3af10f6ae4c688d6acce8f8dbf..737d95aa1d08e7dc731b3d1515c992049c09e25a 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -9,16 +9,15 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include -#include #include -#include #include +#include #include "nodelist.h" +#include "jffs2.h" +#include "los_crc32.h" static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this); @@ -30,7 +29,7 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new dbg_dentlist("add dirent \"%s\", ino #%u\n", new->name, new->ino); while ((*prev) && (*prev)->nhash <= new->nhash) { - if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { + if ((*prev)->nhash == new->nhash && !strcmp((const char *)((*prev)->name), (const char *)new->name)) { /* Duplicate. Free one */ if (new->version < (*prev)->version) { dbg_dentlist("Eep! Marking new dirent node obsolete, old is \"%s\", ino #%u\n", @@ -41,7 +40,7 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new dbg_dentlist("marking old dirent \"%s\", ino #%u obsolete\n", (*prev)->name, (*prev)->ino); new->next = (*prev)->next; - /* It may have been a 'placeholder' deletion dirent, + /* It may have been a 'placeholder' deletion dirent, if jffs2_can_mark_obsolete() (see jffs2_do_unlink()) */ if ((*prev)->raw) jffs2_mark_node_obsolete(c, ((*prev)->raw)); @@ -65,13 +64,14 @@ uint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, /* We know frag->ofs <= size. That's what lookup does for us */ if (frag && frag->ofs != size) { if (frag->ofs+frag->size > size) { + dbg_fragtree("truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size); frag->size = size - frag->ofs; } frag = frag_next(frag); } while (frag && frag->ofs >= size) { struct jffs2_node_frag *next = frag_next(frag); - + dbg_fragtree("removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size); frag_erase(frag, list); jffs2_obsolete_node_frag(c, frag); frag = next; @@ -401,7 +401,7 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in } } jffs2_dbg_fragtree_paranoia_check_nolock(f); - + jffs2_dbg_dump_fragtree_nolock(f); return 0; } @@ -409,7 +409,6 @@ void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache { spin_lock(&c->inocache_lock); ic->state = state; - wake_up(&c->inocache_wq); spin_unlock(&c->inocache_lock); } @@ -505,8 +504,12 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) { int i; struct jffs2_raw_node_ref *this, *next; + struct super_block *sb = NULL; + struct MtdNorDev *device = NULL; + sb = OFNI_BS_2SFFJ(c); + device = (struct MtdNorDev*)(sb->s_dev); - for (i=0; inr_blocks; i++) { + for (i=device->blockStart; inr_blocks+device->blockStart; i++) { this = c->blocks[i].first_node; while (this) { if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE) @@ -536,14 +539,22 @@ struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_ while(next) { frag = rb_entry(next, struct jffs2_node_frag, rb); + dbg_fragtree2("considering frag %#04x-%#04x (%p). left %p, right %p\n", + frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right); if (frag->ofs + frag->size <= offset) { + dbg_fragtree2("going right from frag %#04x-%#04x, before the region we care about\n", + frag->ofs, frag->ofs+frag->size); /* Remember the closest smaller match on the way down */ if (!prev || frag->ofs > prev->ofs) prev = frag; next = frag->rb.rb_right; } else if (frag->ofs > offset) { + dbg_fragtree2("going left from frag %#04x-%#04x, after the region we care about\n", + frag->ofs, frag->ofs+frag->size); next = frag->rb.rb_left; } else { + dbg_fragtree2("returning frag %#04x-%#04x, matched\n", + frag->ofs, frag->ofs+frag->size); return frag; } } @@ -564,10 +575,12 @@ struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_ they're killed. */ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) { - struct jffs2_node_frag *frag, *next; + struct jffs2_node_frag *frag; + struct rb_node *tn,*next; dbg_fragtree("killing\n"); - rbtree_postorder_for_each_entry_safe(frag, next, root, rb) { + RB_POSTORDER_FOREACH_SAFE(tn, linux_root, (struct linux_root *)root, next) { + frag = (struct jffs2_node_frag *)tn; if (frag->node && !(--frag->node->frags)) { /* Not a hole, and it's the final remaining frag of this node. Free the node */ @@ -604,7 +617,7 @@ struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, ref++; } - dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, + dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, ref->flash_offset, ofs, ref->next_in_ino, len); ref->flash_offset = ofs; @@ -617,7 +630,7 @@ struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, JFFS2_ERROR("Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n", ref, ref_offset(ref), ref_offset(ref)+len, - ref_offset(jeb->last_node), + ref_offset(jeb->last_node), ref_offset(jeb->last_node)+last_len); BUG(); } @@ -734,7 +747,7 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je pr_crit("next %p (0x%08x-0x%08x)\n", ref_next(ref), ref_offset(ref_next(ref)), ref_offset(ref_next(ref)) + ref->__totlen); - } else + } else pr_crit("No next ref. jeb->last_node is %p\n", jeb->last_node); diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 8ff4d1a1e774bcf07d493427af9d5772f2cd33e0..f1eaca071f7649e50eba9c94121746c2b2e19c52 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -12,20 +12,28 @@ #ifndef __JFFS2_NODELIST_H__ #define __JFFS2_NODELIST_H__ -#include +#include #include -#include +#include +#include "jffs2.h" #include "jffs2_fs_sb.h" #include "jffs2_fs_i.h" #include "xattr.h" #include "acl.h" #include "summary.h" - -#ifdef __ECOS -#include "os-ecos.h" -#else +#include "vfs_jffs2.h" #include "os-linux.h" -#endif + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +struct kvec { + void *iov_base; + long iov_len; +}; #define JFFS2_NATIVE_ENDIAN @@ -193,6 +201,8 @@ struct jffs2_inode_cache { #define INO_STATE_READING 5 /* In read_inode() */ #define INO_STATE_CLEARING 6 /* In clear_inode() */ +#define INOCACHE_HASHSIZE 128 + #define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */ #define INO_FLAGS_IS_DIR 0x02 /* is a directory */ @@ -313,34 +323,26 @@ static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c) #define PAD(x) (((x)+3)&~3) -static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev) -{ - if (old_valid_dev(rdev)) { - jdev->old_id = cpu_to_je16(old_encode_dev(rdev)); - return sizeof(jdev->old_id); - } else { - jdev->new_id = cpu_to_je32(new_encode_dev(rdev)); - return sizeof(jdev->new_id); - } -} static inline struct jffs2_node_frag *frag_first(struct rb_root *root) { - struct rb_node *node = rb_first(root); + struct rb_node *node = root->rb_node; if (!node) return NULL; - + while(node->rb_left) + node = node->rb_left; return rb_entry(node, struct jffs2_node_frag, rb); } static inline struct jffs2_node_frag *frag_last(struct rb_root *root) { - struct rb_node *node = rb_last(root); + struct rb_node *node = root->rb_node; if (!node) return NULL; - + while(node->rb_right) + node = node->rb_right; return rb_entry(node, struct jffs2_node_frag, rb); } @@ -404,8 +406,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, unsigned char *buf, uint32_t offset, uint32_t writelen, uint32_t *retlen); -int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, - struct jffs2_raw_inode *ri, const struct qstr *qstr); +int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, + struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, + const char *name, int namelen); int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f, uint32_t time); int jffs2_do_link(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, @@ -481,4 +484,10 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc #include "debug.h" +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + #endif /* __JFFS2_NODELIST_H__ */ diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index a7bbe879cfc3ddfd5320669d046fc2e7c46e2e0c..e2b2adcbee8957c4c9d314539ff3b8ca2f40bb3f 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -9,46 +9,14 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include -#include #include -#include +#include +#include +#include #include "nodelist.h" #include "debug.h" -/* - * Check whether the user is allowed to write. - */ -static int jffs2_rp_can_write(struct jffs2_sb_info *c) -{ - uint32_t avail; - struct jffs2_mount_opts *opts = &c->mount_opts; - - avail = c->dirty_size + c->free_size + c->unchecked_size + - c->erasing_size - c->resv_blocks_write * c->sector_size - - c->nospc_dirty_size; - - if (avail < 2 * opts->rp_size) - jffs2_dbg(1, "rpsize %u, dirty_size %u, free_size %u, " - "erasing_size %u, unchecked_size %u, " - "nr_erasing_blocks %u, avail %u, resrv %u\n", - opts->rp_size, c->dirty_size, c->free_size, - c->erasing_size, c->unchecked_size, - c->nr_erasing_blocks, avail, c->nospc_dirty_size); - - if (avail > opts->rp_size) - return 1; - - /* Always allow root */ - if (capable(CAP_SYS_RESOURCE)) - return 1; - - jffs2_dbg(1, "forbid writing\n"); - return 0; -} - /** * jffs2_reserve_space - request physical space to write nodes to flash * @c: superblock info @@ -57,8 +25,8 @@ static int jffs2_rp_can_write(struct jffs2_sb_info *c) * @prio: Allocation type - ALLOC_{NORMAL,DELETION} * * Requests a block of physical space on the flash. Returns zero for success - * and puts 'len' into the appropriate place, or returns -ENOSPC or other - * error if appropriate. Doesn't return len since that's + * and puts 'len' into the appropriate place, or returns -ENOSPC or other + * error if appropriate. Doesn't return len since that's * * If it returns zero, jffs2_reserve_space() also downs the per-filesystem * allocation semaphore, to prevent more than one allocation from being @@ -86,15 +54,6 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, spin_lock(&c->erase_completion_lock); - /* - * Check if the free space is greater then size of the reserved pool. - * If not, only allow root to proceed with writing. - */ - if (prio != ALLOC_DELETION && !jffs2_rp_can_write(c)) { - ret = -ENOSPC; - goto out; - } - /* this needs a little more thought (true :)) */ while(ret == -EAGAIN) { while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { @@ -165,24 +124,7 @@ 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 == -EAGAIN) { - spin_lock(&c->erase_completion_lock); - if (c->nr_erasing_blocks && - list_empty(&c->erase_pending_list) && - list_empty(&c->erase_complete_list)) { - DECLARE_WAITQUEUE(wait, current); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&c->erase_wait, &wait); - jffs2_dbg(1, "%s waiting for erase to complete\n", - __func__); - spin_unlock(&c->erase_completion_lock); - - schedule(); - remove_wait_queue(&c->erase_wait, &wait); - } else - spin_unlock(&c->erase_completion_lock); - } else if (ret) + if (ret) return ret; cond_resched(); @@ -200,7 +142,6 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, } } -out: spin_unlock(&c->erase_completion_lock); if (!ret) ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); @@ -509,7 +450,7 @@ struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, jffs2_dbg(1, "%s(): Node at 0x%x(%d), size 0x%x\n", __func__, ofs & ~3, ofs & 3, len); #if 1 - /* Allow non-obsolete nodes only to be added at the end of c->nextblock, + /* Allow non-obsolete nodes only to be added at the end of c->nextblock, if c->nextblock is set. Note that wbuf.c will file obsolete nodes even after refiling c->nextblock */ if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) @@ -584,6 +525,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref int ret, addedsize; size_t retlen; uint32_t freed_len; + struct super_block *sb; + struct MtdNorDev *device; if(unlikely(!ref)) { pr_notice("EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); @@ -595,9 +538,10 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref return; } blocknr = ref->flash_offset / c->sector_size; - if (blocknr >= c->nr_blocks) { - pr_notice("raw node at 0x%08x is off the end of device!\n", - ref->flash_offset); + sb = OFNI_BS_2SFFJ(c); + device = (struct MtdNorDev*)(sb->s_dev); + if (blocknr >= c->nr_blocks +device->blockStart) { + pr_notice("raw node at 0x%08x is off the end of device!\n",ref->flash_offset); BUG(); } jeb = &c->blocks[blocknr]; @@ -778,7 +722,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref } /* XXX FIXME: This is ugly now */ n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE); - ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); + ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (const u_char *)&n); if (ret) { pr_warn("Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index ef1cfa61549e6cefa1e98673b4cf0269b1f892fa..62c1c6b8350ce4b27be718203607f47db4354d5b 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -12,59 +12,57 @@ #ifndef __JFFS2_OS_LINUX_H__ #define __JFFS2_OS_LINUX_H__ +#include +#include "fs/fs.h" +#include "jffs2.h" +#include "jffs2_fs_sb.h" + + +/* jffs2 debug output opion */ +#define CONFIG_JFFS2_FS_DEBUG 0 /* 1 or 2 */ + +/* jffs2 gc thread section */ +#define JFFS2_GC_THREAD_PRIORITY 10 /* GC thread's priority */ + +/* zlib section*/ +#define CONFIG_JFFS2_ZLIB +#define CONFIG_JFFS2_RTIME +#define CONFIG_JFFS2_RUBIN + /* JFFS2 uses Linux mode bits natively -- no need for conversion */ #define os_to_jffs2_mode(x) (x) #define jffs2_to_os_mode(x) (x) +#ifndef BUG_ON +#define BUG_ON(x) do {if (unlikely(x)) BUG();} while (0) +#endif + struct kstatfs; struct kvec; -#define JFFS2_INODE_INFO(i) (container_of(i, struct jffs2_inode_info, vfs_inode)) -#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode) -#define JFFS2_SB_INFO(sb) (sb->s_fs_info) -#define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv) +#define JFFS2_INODE_INFO(i) (&(i)->jffs2_i) +#define OFNI_EDONI_2SFFJ(f) \ + ((struct jffs2_inode *) (((char *)f) - ((char *)(&((struct jffs2_inode *)NULL)->jffs2_i)))) #define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size) #define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode) -#define JFFS2_F_I_UID(f) (i_uid_read(OFNI_EDONI_2SFFJ(f))) -#define JFFS2_F_I_GID(f) (i_gid_read(OFNI_EDONI_2SFFJ(f))) -#define JFFS2_F_I_RDEV(f) (OFNI_EDONI_2SFFJ(f)->i_rdev) - -#define JFFS2_CLAMP_TIME(t) ((uint32_t)clamp_t(time64_t, (t), 0, U32_MAX)) -#define ITIME(sec) ((struct timespec64){sec, 0}) -#define JFFS2_NOW() JFFS2_CLAMP_TIME(ktime_get_real_seconds()) -#define I_SEC(tv) JFFS2_CLAMP_TIME((tv).tv_sec) -#define JFFS2_F_I_CTIME(f) I_SEC(OFNI_EDONI_2SFFJ(f)->i_ctime) -#define JFFS2_F_I_MTIME(f) I_SEC(OFNI_EDONI_2SFFJ(f)->i_mtime) -#define JFFS2_F_I_ATIME(f) I_SEC(OFNI_EDONI_2SFFJ(f)->i_atime) -#define sleep_on_spinunlock(wq, s) \ - do { \ - DECLARE_WAITQUEUE(__wait, current); \ - add_wait_queue((wq), &__wait); \ - set_current_state(TASK_UNINTERRUPTIBLE); \ - spin_unlock(s); \ - schedule(); \ - remove_wait_queue((wq), &__wait); \ - } while(0) - -static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) -{ - f->highest_version = 0; - f->fragtree = RB_ROOT; - f->metadata = NULL; - f->dents = NULL; - f->target = NULL; - f->flags = 0; - f->usercompr = 0; -} - - -#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & SB_RDONLY) +#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) +#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) +#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime) +#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime) +#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime) + +#define ITIME(sec) ((struct timespec){sec, 0}) +#define I_SEC(tv) ((tv).tv_sec) + +#define sleep_on_spinunlock(wq, sl) do {spin_unlock(sl); msleep(100);} while (0) + +#define jffs2_is_readonly(c) (0) #define SECTOR_ADDR(x) ( (((unsigned long)(x) / c->sector_size) * c->sector_size) ) -#ifndef CONFIG_JFFS2_FS_WRITEBUFFER +#ifndef CONFIG_JFFS2_FS_WRITEBUFFER #ifdef CONFIG_JFFS2_SUMMARY #define jffs2_can_mark_obsolete(c) (0) @@ -77,10 +75,10 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) #define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf) -#define jffs2_flash_read(c, ofs, len, retlen, buf) (mtd_read((c)->mtd, ofs, len, retlen, buf)) -#define jffs2_flush_wbuf_pad(c) ({ do{} while(0); (void)(c), 0; }) +#define jffs2_flash_read(c, ofs, len, retlen, buf) jffs2_flash_direct_read(c, ofs, len, retlen, buf) +#define jffs2_flush_wbuf_pad(c) (c=c) #define jffs2_flush_wbuf_gc(c, i) ({ do{} while(0); (void)(c), (void) i, 0; }) -#define jffs2_write_nand_badblock(c,jeb,bad_offset) (1) +#define jffs2_write_nand_badblock(c,jeb,p) (0) #define jffs2_nand_flash_setup(c) (0) #define jffs2_nand_flash_cleanup(c) do {} while(0) #define jffs2_wbuf_dirty(c) (0) @@ -100,7 +98,8 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #else /* NAND and/or ECC'd NOR support present */ -#define jffs2_is_writebuffered(c) (c->wbuf != NULL) +/* current not support */ +#define jffs2_is_writebuffered(c) (0) #ifdef CONFIG_JFFS2_SUMMARY #define jffs2_can_mark_obsolete(c) (0) @@ -142,38 +141,28 @@ void jffs2_dirty_trigger(struct jffs2_sb_info *c); #endif /* WRITEBUFFER */ /* background.c */ -int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); +void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c); /* dir.c */ -extern const struct file_operations jffs2_dir_operations; -extern const struct inode_operations jffs2_dir_inode_operations; - -/* file.c */ -extern const struct file_operations jffs2_file_operations; -extern const struct inode_operations jffs2_file_inode_operations; -extern const struct address_space_operations jffs2_file_address_operations; -int jffs2_fsync(struct file *, loff_t, loff_t, int); -int jffs2_do_readpage_unlock(void *data, struct page *pg); - -/* ioctl.c */ -long jffs2_ioctl(struct file *, unsigned int, unsigned long); - -/* symlink.c */ -extern const struct inode_operations jffs2_symlink_inode_operations; +struct jffs2_inode *jffs2_lookup(struct jffs2_inode *dir_i, const unsigned char *name, int namelen); +int jffs2_create(struct jffs2_inode *dir_i, const unsigned char *d_name, int mode, struct jffs2_inode **new_i); +int jffs2_mkdir (struct jffs2_inode *dir_i, const unsigned char *d_name, int mode, struct jffs2_inode **new_i); +int jffs2_link (struct jffs2_inode *old_d_inode, struct jffs2_inode *dir_i, const unsigned char *d_name); +int jffs2_symlink(struct jffs2_inode *dir_i, struct jffs2_inode **d_inode, const unsigned char *d_name, const char *target); +int jffs2_unlink(struct jffs2_inode *dir_i, struct jffs2_inode *d_inode, const unsigned char *d_name); +int jffs2_rmdir (struct jffs2_inode *dir_i, struct jffs2_inode *d_inode, const unsigned char *d_name); +int jffs2_rename (struct jffs2_inode *old_dir_i, struct jffs2_inode *d_inode, const unsigned char *old_d_name, + struct jffs2_inode *new_dir_i, const unsigned char *new_d_name); +int jffs2_readdir(struct jffs2_inode *inode, off_t *offset, off_t *int_off, struct dirent *ent); /* fs.c */ -int jffs2_setattr (struct dentry *, struct iattr *); -int jffs2_do_setattr (struct inode *, struct iattr *); -struct inode *jffs2_iget(struct super_block *, unsigned long); -void jffs2_evict_inode (struct inode *); -void jffs2_dirty_inode(struct inode *inode, int flags); -struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, - struct jffs2_raw_inode *ri); -int jffs2_statfs (struct dentry *, struct kstatfs *); -int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc); -int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc); +int jffs2_setattr (struct jffs2_inode *inode, struct IATTR *attr); +struct jffs2_inode *jffs2_iget(struct super_block *sb, uint32_t ino); +int jffs2_iput(struct jffs2_inode * i); +struct jffs2_inode *jffs2_new_inode (struct jffs2_inode *dir_i, int mode, struct jffs2_raw_inode *ri); + void jffs2_gc_release_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, @@ -183,15 +172,25 @@ unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, struct jffs2_inode_info *f, unsigned long offset, unsigned long *priv); +void jffs2_gc_release_page(struct jffs2_sb_info *c, + unsigned char *pg, + unsigned long *priv); void jffs2_flash_cleanup(struct jffs2_sb_info *c); +int calculate_inocache_hashsize(uint32_t flash_size); /* writev.c */ int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf); +int jffs2_flash_direct_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, + size_t *retlen, const char *buf); -#endif /* __JFFS2_OS_LINUX_H__ */ +/* super.c */ +int jffs2_fill_super(struct super_block *sb); +int jffs2_mount(int part_no, struct jffs2_inode **root_node, unsigned long mountflags); +int jffs2_umount(struct jffs2_inode *root_node); +#endif /* __JFFS2_OS_LINUX_H__ */ diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index 0b042b1fc82fea33eed64866617e0bd67aafa0ba..a8b9da5ff7676b6d9da11fa10f7bc4359e86aef5 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c @@ -9,16 +9,15 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include -#include #include -#include #include +#include #include "nodelist.h" #include "compr.h" +#include "los_crc32.h" +#include "user_copy.h" int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fd, unsigned char *buf, @@ -57,6 +56,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, if (crc != je32_to_cpu(ri->node_crc)) { pr_warn("Node CRC %08x != calculated CRC %08x for node at %08x\n", je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw)); + jffs2_dbg_dump_node(c, ref_offset(fd->raw)); ret = -EIO; goto out_ri; } @@ -75,9 +75,8 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, goto out_ri; }); - if (ri->compr == JFFS2_COMPR_ZERO) { - memset(buf, 0, len); + ret = LOS_UserMemClear(buf, len); goto out_ri; } @@ -88,7 +87,11 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy */ if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { - readbuf = buf; + readbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); + if (!readbuf) { + ret = -ENOMEM; + goto out_ri; + } } else { readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL); if (!readbuf) { @@ -97,14 +100,10 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, } } if (ri->compr != JFFS2_COMPR_NONE) { - if (len < je32_to_cpu(ri->dsize)) { - decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); - if (!decomprbuf) { - ret = -ENOMEM; - goto out_readbuf; - } - } else { - decomprbuf = buf; + decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); + if (!decomprbuf) { + ret = -ENOMEM; + goto out_readbuf; } } else { decomprbuf = readbuf; @@ -113,7 +112,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, jffs2_dbg(2, "Read %d bytes to %p\n", je32_to_cpu(ri->csize), readbuf); ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri), - je32_to_cpu(ri->csize), &readlen, readbuf); + je32_to_cpu(ri->csize), &readlen, (char *)readbuf); if (!ret && readlen != je32_to_cpu(ri->csize)) ret = -EIO; @@ -124,6 +123,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, if (crc != je32_to_cpu(ri->data_crc)) { pr_warn("Data CRC %08x != calculated CRC %08x for node at %08x\n", je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw)); + jffs2_dbg_dump_node(c, ref_offset(fd->raw)); ret = -EIO; goto out_decomprbuf; } @@ -139,8 +139,8 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, } } - if (len < je32_to_cpu(ri->dsize)) { - memcpy(buf, decomprbuf+ofs, len); + if (LOS_CopyFromKernel(buf, len, decomprbuf + ofs, len) != 0) { + ret = -EFAULT; } out_decomprbuf: if(decomprbuf != buf && decomprbuf != readbuf) @@ -184,7 +184,10 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, } jffs2_dbg(1, "Filling non-frag hole from %d-%d\n", offset, offset + holesize); - memset(buf, 0, holesize); + ret = LOS_UserMemClear(buf, holesize); + if (ret != 0) { + return ret; + } buf += holesize; offset += holesize; continue; @@ -193,7 +196,10 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, jffs2_dbg(1, "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size); - memset(buf, 0, holeend - offset); + ret = LOS_UserMemClear(buf, holeend - offset); + if (ret != 0) { + return ret; + } buf += holeend - offset; offset = holeend; frag = frag_next(frag); @@ -214,7 +220,7 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, if (ret) { jffs2_dbg(1, "%s(): error %d\n", __func__, ret); - memset(buf, 0, readlen); + (void)LOS_UserMemClear(buf, readlen); return ret; } buf += readlen; @@ -226,3 +232,15 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, return 0; } +int jffs2_flash_direct_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, + size_t *retlen, const char *buf) +{ + int ret; + ret = c->mtd->read(c->mtd, ofs, len, (char *)buf); + if (ret >= 0) { + *retlen = ret; + return 0; + } + *retlen = 0; + return ret; +} \ No newline at end of file diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 03b4f99614bef86ee840e34131b652675d7fa8b6..601ba67fda4f0a31559048171994297dc143e47a 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -9,17 +9,18 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include #include -#include +#include +#include #include -#include #include +#include #include "nodelist.h" +#include "os-linux.h" +#include "los_crc32.h" /* * Check the data CRC of the node. @@ -31,9 +32,9 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) { struct jffs2_raw_node_ref *ref = tn->fn->raw; - int err = 0, pointed = 0; + int err = 0; struct jffs2_eraseblock *jeb; - unsigned char *buffer; + unsigned char *buffer = NULL; uint32_t crc, ofs, len; size_t retlen; @@ -61,48 +62,28 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n", ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); -#ifndef __ECOS - /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), - * adding and jffs2_flash_read_end() interface. */ - err = mtd_point(c->mtd, ofs, len, &retlen, (void **)&buffer, NULL); - if (!err && retlen < len) { - JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); - mtd_unpoint(c->mtd, ofs, retlen); - } else if (err) { - if (err != -EOPNOTSUPP) - JFFS2_WARNING("MTD point failed: error code %d.\n", err); - } else - pointed = 1; /* succefully pointed to device */ -#endif - - if (!pointed) { - buffer = kmalloc(len, GFP_KERNEL); - if (unlikely(!buffer)) - return -ENOMEM; + buffer = kmalloc(len, GFP_KERNEL); + if (unlikely(!buffer)) + return -ENOMEM; - /* TODO: this is very frequent pattern, make it a separate - * routine */ - err = jffs2_flash_read(c, ofs, len, &retlen, buffer); - if (err) { - JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); - goto free_out; - } + /* TODO: this is very frequent pattern, make it a separate + * routine */ + err = jffs2_flash_read(c, ofs, len, &retlen, (char *)buffer); + if (err) { + JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); + goto free_out; + } - if (retlen != len) { - JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); - err = -EIO; - goto free_out; - } + if (retlen != len) { + JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); + err = -EIO; + goto free_out; } /* Continue calculating CRC */ crc = crc32(tn->partial_crc, buffer, len); - if(!pointed) - kfree(buffer); -#ifndef __ECOS - else - mtd_unpoint(c->mtd, ofs, len); -#endif + + kfree(buffer); if (crc != tn->data_crc) { JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", @@ -133,12 +114,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info return 0; free_out: - if(!pointed) - kfree(buffer); -#ifndef __ECOS - else - mtd_unpoint(c->mtd, ofs, len); -#endif + kfree(buffer); return err; } @@ -415,8 +391,12 @@ static void eat_last(struct rb_root *root, struct rb_node *node) link = &parent->rb_right; *link = node->rb_left; - if (node->rb_left) - node->rb_left->__rb_parent_color = node->__rb_parent_color; + if (node->rb_left) { + node->rb_left->rb_parent_color = node->rb_parent_color; + // set child parent only + rb_parent(node->rb_left) = parent; + node->rb_left = NULL; + } } /* We put the version tree in reverse order, so we can use the same eat_last() @@ -464,8 +444,8 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, #ifdef JFFS2_DBG_READINODE_MESSAGES this = tn_last(&rii->tn_root); while (this) { - dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs, - this->fn->ofs+this->fn->size, this->overlapped); + dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d,left %p,right %p ,parent %p\n", this, this->version, this->fn->ofs, + this->fn->ofs+this->fn->size, this->overlapped,this->rb.rb_left,this->rb.rb_right,rb_parent(&(this->rb))); this = tn_prev(this); } #endif @@ -543,11 +523,13 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) { - struct jffs2_tmp_dnode_info *tn, *next; + struct jffs2_tmp_dnode_info *tn; + struct rb_node *rbn,*next; - rbtree_postorder_for_each_entry_safe(tn, next, list, rb) { - jffs2_free_full_dnode(tn->fn); - jffs2_free_tmp_dnode_info(tn); + RB_POSTORDER_FOREACH_SAFE(rbn, linux_root, (struct linux_root *)list, next) { + tn = (struct jffs2_tmp_dnode_info *)rbn; + jffs2_free_full_dnode(tn->fn); + jffs2_free_tmp_dnode_info(tn); } *list = RB_ROOT; @@ -659,7 +641,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r int already = read - sizeof(*rd); err = jffs2_flash_read(c, (ref_offset(ref)) + read, - rd->nsize - already, &read, &fd->name[already]); + rd->nsize - already, &read, (char *)&fd->name[already]); if (unlikely(read != rd->nsize - already) && likely(!err)) { jffs2_free_full_dirent(fd); JFFS2_ERROR("short read: wanted %d bytes, got %zd\n", @@ -690,7 +672,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r #endif } - fd->nhash = full_name_hash(NULL, fd->name, rd->nsize); + fd->nhash = full_name_hash(fd->name, rd->nsize); fd->next = NULL; fd->name[rd->nsize] = '\0'; @@ -956,7 +938,7 @@ static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, dbg_readinode("read more %d bytes\n", to_read); - err = jffs2_flash_read(c, offs, to_read, &retlen, buf + *rdlen); + err = jffs2_flash_read(c, offs, to_read, &retlen, (char *)(buf + *rdlen)); if (err) { JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", to_read, offs, err); @@ -1042,7 +1024,7 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref)); /* FIXME: point() */ - err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, buf); + err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, (char *)buf); if (err) { JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ref_offset(ref), err); goto free_out; @@ -1079,6 +1061,7 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf case JFFS2_NODETYPE_DIRENT: + dbg_readinode("node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)); if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent) && len < sizeof(struct jffs2_raw_dirent)) { err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf); @@ -1094,6 +1077,7 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf case JFFS2_NODETYPE_INODE: + dbg_readinode("node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)); if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode) && len < sizeof(struct jffs2_raw_inode)) { err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf); @@ -1289,8 +1273,6 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, dbg_readinode("symlink's target '%s' cached\n", f->target); } - fallthrough; - case S_IFBLK: case S_IFCHR: /* Certain inode types should have only one data node, and it's @@ -1315,7 +1297,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, /* OK. We're happy */ f->metadata = frag_first(&f->fragtree)->node; jffs2_free_node_frag(frag_first(&f->fragtree)); - f->fragtree = RB_ROOT; + f->fragtree.rb_node = NULL; break; } if (f->inocache->state == INO_STATE_READING) @@ -1362,6 +1344,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, break; default: + JFFS2_ERROR("Unknow f->inocache->state %d!\n", f->inocache->state); BUG(); } } @@ -1375,7 +1358,6 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, return -ENOMEM; } dbg_readinode("creating inocache for root inode\n"); - memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); f->inocache->ino = f->inocache->pino_nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->state = INO_STATE_READING; diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index b676056826beb69a05aca4ce7028720d2eeea5cf..fa9dc80482ce443261048c14c38f85c0c5a8e6f1 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -9,18 +9,17 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include -#include #include -#include #include #include "nodelist.h" #include "summary.h" #include "debug.h" +#include "mtd_dev.h" +#include "los_typedef.h" +#include "los_crc32.h" #define DEFAULT_EMPTY_SCAN_SIZE 256 @@ -74,7 +73,7 @@ static int file_dirty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) return ret; if ((ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size))) return ret; - /* Turned wasted size into dirty, since we apparently + /* Turned wasted size into dirty, since we apparently think it's recoverable now. */ jeb->dirty_size += jeb->wasted_size; c->dirty_size += jeb->wasted_size; @@ -95,40 +94,26 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) unsigned char *flashbuf = NULL; uint32_t buf_size = 0; struct jffs2_summary *s = NULL; /* summary info collected by the scan process */ -#ifndef __ECOS - size_t pointlen, try_size; - - ret = mtd_point(c->mtd, 0, c->mtd->size, &pointlen, - (void **)&flashbuf, NULL); - if (!ret && pointlen < c->mtd->size) { - /* Don't muck about if it won't let us point to the whole flash */ - jffs2_dbg(1, "MTD point returned len too short: 0x%zx\n", - pointlen); - mtd_unpoint(c->mtd, 0, pointlen); - flashbuf = NULL; - } - if (ret && ret != -EOPNOTSUPP) - jffs2_dbg(1, "MTD point failed %d\n", ret); -#endif + struct super_block *sb = NULL; + struct MtdNorDev *device = NULL; + if (!flashbuf) { /* For NAND it's quicker to read a whole eraseblock at a time, apparently */ if (jffs2_cleanmarker_oob(c)) - try_size = c->sector_size; + buf_size = c->sector_size; else - try_size = PAGE_SIZE; + buf_size = PAGE_SIZE; jffs2_dbg(1, "Trying to allocate readbuf of %zu " - "bytes\n", try_size); + "bytes\n", buf_size); - flashbuf = mtd_kmalloc_up_to(c->mtd, &try_size); + flashbuf = kmalloc(buf_size, GFP_KERNEL); if (!flashbuf) return -ENOMEM; jffs2_dbg(1, "Allocated readbuf of %zu bytes\n", - try_size); - - buf_size = (uint32_t)try_size; + buf_size); } if (jffs2_sum_active()) { @@ -140,7 +125,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } } - for (i=0; inr_blocks; i++) { + sb = OFNI_BS_2SFFJ(c); + device = (struct MtdNorDev*)(sb->s_dev); + for (i=device->blockStart; inr_blocks + device->blockStart; i++) { struct jffs2_eraseblock *jeb = &c->blocks[i]; cond_resched(); @@ -269,19 +256,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ret = -EIO; goto out; } - spin_lock(&c->erase_completion_lock); - jffs2_garbage_collect_trigger(c); - spin_unlock(&c->erase_completion_lock); } ret = 0; out: - if (buf_size) - kfree(flashbuf); -#ifndef __ECOS - else - mtd_unpoint(c->mtd, 0, c->mtd->size); -#endif - kfree(s); + + kfree(flashbuf); + return ret; } @@ -411,7 +391,7 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock if (!ref) return -ENOMEM; - /* BEFORE jffs2_build_xattr_subsystem() called, + /* BEFORE jffs2_build_xattr_subsystem() called, * and AFTER xattr_ref is marked as a dead xref, * ref->xid is used to store 32bit xid, xd is not used * ref->ino is used to store 32bit inode-number, ic is not used @@ -484,10 +464,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo struct jffs2_sum_marker *sm; void *sumptr = NULL; uint32_t sumlen; - + if (!buf_size) { /* XIP case. Just look, point at the summary if it's there */ - sm = (void *)buf + c->sector_size - sizeof(*sm); + sm = (struct jffs2_sum_marker *)((uint8_t *)buf + c->sector_size - sizeof(*sm)); if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { sumptr = buf + je32_to_cpu(sm->offset); sumlen = c->sector_size - je32_to_cpu(sm->offset); @@ -500,13 +480,13 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo buf_len = sizeof(*sm); /* Read as much as we want into the _end_ of the preallocated buffer */ - err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, + err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, jeb->offset + c->sector_size - buf_len, - buf_len); + buf_len); if (err) return err; - sm = (void *)buf + buf_size - sizeof(*sm); + sm = (struct jffs2_sum_marker *)((uint8_t *)buf + buf_size - sizeof(*sm)); if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { sumlen = c->sector_size - je32_to_cpu(sm->offset); sumptr = buf + buf_size - sumlen; @@ -521,11 +501,11 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo sumptr = kmalloc(sumlen, GFP_KERNEL); if (!sumptr) return -ENOMEM; - memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len); + memcpy((uint8_t *)sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len); } if (buf_len < sumlen) { /* Need to read more so that the entire summary node is present */ - err = jffs2_fill_scan_buf(c, sumptr, + err = jffs2_fill_scan_buf(c, sumptr, jeb->offset + c->sector_size - sumlen, sumlen - buf_len); if (err) { @@ -543,7 +523,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (buf_size && sumlen > buf_size) kfree(sumptr); - /* If it returns with a real error, bail. + /* If it returns with a real error, bail. If it returns positive, that's a block classification (i.e. BLK_STATE_xxx) so return that too. If it returns zero, fall through to full scan. */ @@ -605,7 +585,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo /* Now ofs is a complete physical flash offset as it always was... */ ofs += jeb->offset; - noise = 10; + noise = 1; dbg_summary("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset); @@ -698,7 +678,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo scan_end = buf_len; goto more_empty; } - + /* See how much more there is to read in this eraseblock... */ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); if (!buf_len) { @@ -948,7 +928,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo jffs2_dbg(1, "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size); - + /* mark_node_obsolete can add to wasted !! */ if (jeb->wasted_size) { jeb->dirty_size += jeb->wasted_size; @@ -976,7 +956,6 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin pr_notice("%s(): allocation of inode cache failed\n", __func__); return NULL; } - memset(ic, 0, sizeof(*ic)); ic->ino = ino; ic->nodes = (void *)ic; @@ -1067,7 +1046,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo pseudo_random += je32_to_cpu(rd->version); /* Should never happen. Did. (OLPC trac #4184)*/ - checkedlen = strnlen(rd->name, rd->nsize); + checkedlen = strnlen((const char *)rd->name, rd->nsize); if (checkedlen < rd->nsize) { pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n", ofs, checkedlen); @@ -1104,7 +1083,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(NULL, fd->name, checkedlen); + fd->nhash = full_name_hash(fd->name, checkedlen); fd->type = rd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 4fe64519870f1ac0845d771618607d0ce53335e8..58281e1746873a1e5fd5eb9e996779a9b94ada37 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -10,16 +10,20 @@ * For licensing information, see the file 'LICENCE' in this directory. * */ +#include "summary.h" +#ifdef CONFIG_JFFS2_SUMMARY + +#ifndef pr_fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif #include #include -#include +#include #include -#include +#include "los_crc32.h" #include -#include #include "nodelist.h" #include "debug.h" @@ -388,11 +392,25 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras { struct jffs2_inode_cache *ic; struct jffs2_full_dirent *fd; - void *sp; + uintptr_t sp; int i, ino; int err; - sp = summary->sum; + sp = (uintptr_t)summary->sum; + +#if 0 + PRINTK("summary: %x %x %d %d %x %x %d %x %x %p %p\n", + je16_to_cpu(summary->magic), + je16_to_cpu(summary->nodetype), + je32_to_cpu(summary->totlen), + je32_to_cpu(summary->hdr_crc), + je32_to_cpu(summary->sum_num), + je32_to_cpu(summary->cln_mkr), + je32_to_cpu(summary->padded), + je32_to_cpu(summary->sum_crc), + je32_to_cpu(summary->node_crc), + sp, summary->sum); +#endif for (i=0; isum_num); i++) { dbg_summary("processing summary index %d\n", i); @@ -404,10 +422,12 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras if (err) return err; + //PRINTK("sum type %d \n", je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)); + switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { case JFFS2_NODETYPE_INODE: { struct jffs2_sum_inode_flash *spi; - spi = sp; + spi = (struct jffs2_sum_inode_flash *)sp; ino = je32_to_cpu(spi->inode); @@ -428,13 +448,29 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras sp += JFFS2_SUMMARY_INODE_SIZE; + //PRINTK("1 sp + %d %p\n", JFFS2_SUMMARY_INODE_SIZE, sp); + break; } case JFFS2_NODETYPE_DIRENT: { struct jffs2_sum_dirent_flash *spd; int checkedlen; - spd = sp; + spd = (struct jffs2_sum_dirent_flash *)sp; + + +#if 0 + PRINTK("dir: %x %d %d %d %d %d %d %d %d\n", + je16_to_cpu(spd->nodetype), + je32_to_cpu(spd->totlen), + je32_to_cpu(spd->offset), + je32_to_cpu(spd->pino), + je32_to_cpu(spd->version), + je32_to_cpu(spd->ino), + spd->nsize, + spd->type, + spd->name); +#endif dbg_summary("Dirent at 0x%08x-0x%08x\n", jeb->offset + je32_to_cpu(spd->offset), @@ -442,7 +478,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras /* This should never happen, but https://dev.laptop.org/ticket/4184 */ - checkedlen = strnlen(spd->name, spd->nsize); + checkedlen = strnlen((const char *)spd->name, spd->nsize); if (!checkedlen) { pr_err("Dirent at %08x has zero at start of name. Aborting mount.\n", jeb->offset + @@ -463,6 +499,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras memcpy(&fd->name, spd->name, checkedlen); fd->name[checkedlen] = 0; + //PRINTK("add %s \n", fd->name); ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); if (!ic) { @@ -476,15 +513,19 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras fd->next = NULL; fd->version = je32_to_cpu(spd->version); fd->ino = je32_to_cpu(spd->ino); - fd->nhash = full_name_hash(NULL, fd->name, checkedlen); + fd->nhash = full_name_hash((const unsigned char *)fd->name, checkedlen); fd->type = spd->type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents); *pseudo_random += je32_to_cpu(spd->version); + //PRINTK("2 sp before add %p\n", sp); + sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); + //PRINTK("2 sp + %d %p\n", JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize), sp); + break; } #ifdef CONFIG_JFFS2_FS_XATTR @@ -493,7 +534,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras struct jffs2_sum_xattr_flash *spx; spx = (struct jffs2_sum_xattr_flash *)sp; - dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", + dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", jeb->offset + je32_to_cpu(spx->offset), jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen), je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); @@ -526,7 +567,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras spr = (struct jffs2_sum_xref_flash *)sp; dbg_summary("xref at %#08x-%#08x\n", jeb->offset + je32_to_cpu(spr->offset), - jeb->offset + je32_to_cpu(spr->offset) + + jeb->offset + je32_to_cpu(spr->offset) + (uint32_t)PAD(sizeof(struct jffs2_raw_xref))); ref = jffs2_alloc_xattr_ref(); @@ -679,7 +720,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock struct jffs2_sum_marker *sm; struct kvec vecs[2]; uint32_t sum_ofs; - void *wpage; + uintptr_t wpage; int ret; size_t retlen; @@ -713,14 +754,14 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock isum.padded = cpu_to_je32(c->summary->sum_padded); isum.cln_mkr = cpu_to_je32(c->cleanmarker_size); isum.sum_num = cpu_to_je32(c->summary->sum_num); - wpage = c->summary->sum_buf; + wpage = (uintptr_t)c->summary->sum_buf; while (c->summary->sum_num) { temp = c->summary->sum_list_head; switch (je16_to_cpu(temp->u.nodetype)) { case JFFS2_NODETYPE_INODE: { - struct jffs2_sum_inode_flash *sino_ptr = wpage; + struct jffs2_sum_inode_flash *sino_ptr = (struct jffs2_sum_inode_flash *)wpage; sino_ptr->nodetype = temp->i.nodetype; sino_ptr->inode = temp->i.inode; @@ -734,7 +775,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock } case JFFS2_NODETYPE_DIRENT: { - struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; + struct jffs2_sum_dirent_flash *sdrnt_ptr = (struct jffs2_sum_dirent_flash *)wpage; sdrnt_ptr->nodetype = temp->d.nodetype; sdrnt_ptr->totlen = temp->d.totlen; @@ -802,7 +843,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock wpage += padsize; - sm = wpage; + sm = (struct jffs2_sum_marker *)wpage; sm->offset = cpu_to_je32(c->sector_size - jeb->free_size); sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC); @@ -847,7 +888,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock /* Write out summary information - called from jffs2_do_reserve_space */ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) - __must_hold(&c->erase_completion_block) + //__must_hold(&c->erase_completion_block) { int datasize, infosize, padsize; struct jffs2_eraseblock *jeb; @@ -875,3 +916,5 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) spin_lock(&c->erase_completion_lock); return ret; } + +#endif diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index e4131cb1f1d4f8e9934c6dc278156bea8c511a55..668f1083df8fac884d42b1fffd20eed0a979a09d 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -19,8 +19,9 @@ anyway. */ #define MAX_SUMMARY_SIZE 65536 -#include -#include +#include +#include +#include "jffs2.h" #define BLK_STATE_ALLFF 0 #define BLK_STATE_CLEAN 1 @@ -169,6 +170,10 @@ struct jffs2_sum_marker #define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) +#ifdef LOSCFG_FS_JFFS2_SUMMARY +#define CONFIG_JFFS2_SUMMARY +#endif + #ifdef CONFIG_JFFS2_SUMMARY /* SUMMARY SUPPORT ENABLED */ #define jffs2_sum_active() (1) diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 81ca58c10b728cc6a7c4e132a80c503c0dde1df3..6f2e5f8c7f78e042faf5a92442e1f5101c1d4001 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -9,433 +9,188 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "compr.h" +#include "jffs2.h" #include "nodelist.h" +#include "jffs2_fs_sb.h" +#include "mtd_dev.h" +#include "mtd_partition.h" +#include "compr.h" +#include "jffs2_hash.h" -static void jffs2_put_super(struct super_block *); - -static struct kmem_cache *jffs2_inode_cachep; - -static struct inode *jffs2_alloc_inode(struct super_block *sb) -{ - struct jffs2_inode_info *f; - - f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); - if (!f) - return NULL; - return &f->vfs_inode; -} +static unsigned char jffs2_mounted_number = 0; /* a counter to track the number of jffs2 instances mounted */ +struct MtdNorDev jffs2_dev_list[CONFIG_MTD_PATTITION_NUM]; -static void jffs2_free_inode(struct inode *inode) +/* + * fill in the superblock + */ +int jffs2_fill_super(struct super_block *sb) { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); + int ret; + struct jffs2_sb_info *c; + struct MtdNorDev *device; - kfree(f->target); - kmem_cache_free(jffs2_inode_cachep, f); -} + c = JFFS2_SB_INFO(sb); + device = (struct MtdNorDev*)(sb->s_dev); -static void jffs2_i_init_once(void *foo) -{ - struct jffs2_inode_info *f = foo; + (void)mutex_init(&c->alloc_sem); + (void)mutex_init(&c->erase_free_sem); + spin_lock_init(&c->erase_completion_lock); + spin_lock_init(&c->inocache_lock); - mutex_init(&f->sem); - inode_init_once(&f->vfs_inode); -} + /* sector size is the erase block size */ + c->sector_size = device->blockSize; + c->flash_size = (device->blockEnd - device->blockStart + 1) * device->blockSize; + c->cleanmarker_size = sizeof(struct jffs2_unknown_node); -static const char *jffs2_compr_name(unsigned int compr) -{ - switch (compr) { - case JFFS2_COMPR_MODE_NONE: - return "none"; -#ifdef CONFIG_JFFS2_LZO - case JFFS2_COMPR_MODE_FORCELZO: - return "lzo"; -#endif -#ifdef CONFIG_JFFS2_ZLIB - case JFFS2_COMPR_MODE_FORCEZLIB: - return "zlib"; -#endif - default: - /* should never happen; programmer error */ - WARN_ON(1); - return ""; + ret = jffs2_do_mount_fs(c); + if (ret) { + (void)mutex_destroy(&c->alloc_sem); + (void)mutex_destroy(&c->erase_free_sem); + return ret; } -} + D1(printk(KERN_DEBUG "jffs2_fill_super(): Getting root inode\n")); -static int jffs2_show_options(struct seq_file *s, struct dentry *root) -{ - struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb); - struct jffs2_mount_opts *opts = &c->mount_opts; + sb->s_root = jffs2_iget(sb, 1); - if (opts->override_compr) - seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr)); - if (opts->set_rp_size) - seq_printf(s, ",rp_size=%u", opts->rp_size / 1024); + if (IS_ERR(sb->s_root)) { + D1(printk(KERN_WARNING "get root inode failed\n")); + ret = PTR_ERR(sb->s_root); + sb->s_root = NULL; + jffs2_free_ino_caches(c); + jffs2_free_raw_node_refs(c); + free(c->blocks); + (void)mutex_destroy(&c->alloc_sem); + (void)mutex_destroy(&c->erase_free_sem); + return ret; + } return 0; } -static int jffs2_sync_fs(struct super_block *sb, int wait) -{ - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - -#ifdef CONFIG_JFFS2_FS_WRITEBUFFER - if (jffs2_is_writebuffered(c)) - cancel_delayed_work_sync(&c->wbuf_dwork); -#endif - - mutex_lock(&c->alloc_sem); - jffs2_flush_wbuf_pad(c); - mutex_unlock(&c->alloc_sem); - return 0; -} - -static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, - uint32_t generation) -{ - /* We don't care about i_generation. We'll destroy the flash - before we start re-using inode numbers anyway. And even - if that wasn't true, we'd have other problems...*/ - return jffs2_iget(sb, ino); -} - -static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type) +int jffs2_mount(int part_no, struct jffs2_inode **root_node, unsigned long mountflags) { - return generic_fh_to_dentry(sb, fid, fh_len, fh_type, - jffs2_nfs_get_inode); -} - -static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type) -{ - return generic_fh_to_parent(sb, fid, fh_len, fh_type, - jffs2_nfs_get_inode); -} - -static struct dentry *jffs2_get_parent(struct dentry *child) -{ - struct jffs2_inode_info *f; - uint32_t pino; - - BUG_ON(!d_is_dir(child)); - - f = JFFS2_INODE_INFO(d_inode(child)); - - pino = f->inocache->pino_nlink; - - JFFS2_DEBUG("Parent of directory ino #%u is #%u\n", - f->inocache->ino, pino); - - return d_obtain_alias(jffs2_iget(child->d_sb, pino)); -} - -static const struct export_operations jffs2_export_ops = { - .get_parent = jffs2_get_parent, - .fh_to_dentry = jffs2_fh_to_dentry, - .fh_to_parent = jffs2_fh_to_parent, -}; - -/* - * JFFS2 mount options. - * - * Opt_source: The source device - * Opt_override_compr: override default compressor - * Opt_rp_size: size of reserved pool in KiB - */ -enum { - Opt_override_compr, - Opt_rp_size, -}; - -static const struct constant_table jffs2_param_compr[] = { - {"none", JFFS2_COMPR_MODE_NONE }, -#ifdef CONFIG_JFFS2_LZO - {"lzo", JFFS2_COMPR_MODE_FORCELZO }, -#endif -#ifdef CONFIG_JFFS2_ZLIB - {"zlib", JFFS2_COMPR_MODE_FORCEZLIB }, -#endif - {} -}; - -static const struct fs_parameter_spec jffs2_fs_parameters[] = { - fsparam_enum ("compr", Opt_override_compr, jffs2_param_compr), - fsparam_u32 ("rp_size", Opt_rp_size), - {} -}; - -static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param) -{ - struct fs_parse_result result; - struct jffs2_sb_info *c = fc->s_fs_info; - int opt; + struct super_block *sb = NULL; + struct jffs2_sb_info *c = NULL; + LOS_DL_LIST *part_head = NULL; + struct MtdDev *spinor_mtd = NULL; + mtd_partition *mtd_part = GetSpinorPartitionHead(); + int ret; - opt = fs_parse(fc, jffs2_fs_parameters, param, &result); - if (opt < 0) - return opt; + jffs2_dbg(1, "begin los_jffs2_mount:%d\n", part_no); - switch (opt) { - case Opt_override_compr: - c->mount_opts.compr = result.uint_32; - c->mount_opts.override_compr = true; - break; - case Opt_rp_size: - if (result.uint_32 > UINT_MAX / 1024) - return invalf(fc, "jffs2: rp_size unrepresentable"); - c->mount_opts.rp_size = result.uint_32 * 1024; - c->mount_opts.set_rp_size = true; - break; - default: - return -EINVAL; + sb = zalloc(sizeof(struct super_block)); + if (sb == NULL) { + return -ENOMEM; } - return 0; -} - -static inline void jffs2_update_mount_opts(struct fs_context *fc) -{ - struct jffs2_sb_info *new_c = fc->s_fs_info; - struct jffs2_sb_info *c = JFFS2_SB_INFO(fc->root->d_sb); - - mutex_lock(&c->alloc_sem); - if (new_c->mount_opts.override_compr) { - c->mount_opts.override_compr = new_c->mount_opts.override_compr; - c->mount_opts.compr = new_c->mount_opts.compr; + ret = Jffs2HashInit(&sb->s_node_hash_lock, &sb->s_node_hash[0]); + if (ret) { + free(sb); + return ret; } - if (new_c->mount_opts.set_rp_size) { - c->mount_opts.set_rp_size = new_c->mount_opts.set_rp_size; - c->mount_opts.rp_size = new_c->mount_opts.rp_size; + part_head = &(GetSpinorPartitionHead()->node_info); + LOS_DL_LIST_FOR_EACH_ENTRY(mtd_part,part_head, mtd_partition, node_info) { + if (mtd_part->patitionnum == part_no) + break; } - mutex_unlock(&c->alloc_sem); -} - -static int jffs2_reconfigure(struct fs_context *fc) -{ - struct super_block *sb = fc->root->d_sb; - - sync_filesystem(sb); - jffs2_update_mount_opts(fc); - - return jffs2_do_remount_fs(sb, fc); -} - -static const struct super_operations jffs2_super_operations = -{ - .alloc_inode = jffs2_alloc_inode, - .free_inode = jffs2_free_inode, - .put_super = jffs2_put_super, - .statfs = jffs2_statfs, - .evict_inode = jffs2_evict_inode, - .dirty_inode = jffs2_dirty_inode, - .show_options = jffs2_show_options, - .sync_fs = jffs2_sync_fs, -}; - -/* - * fill in the superblock - */ -static int jffs2_fill_super(struct super_block *sb, struct fs_context *fc) -{ - struct jffs2_sb_info *c = sb->s_fs_info; - - jffs2_dbg(1, "jffs2_get_sb_mtd():" - " New superblock for device %d (\"%s\")\n", - sb->s_mtd->index, sb->s_mtd->name); - - c->mtd = sb->s_mtd; - c->os_priv = sb; - - if (c->mount_opts.rp_size > c->mtd->size) - return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB", - c->mtd->size / 1024); - - /* Initialize JFFS2 superblock locks, the further initialization will - * be done later */ - 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); - spin_lock_init(&c->inocache_lock); - - sb->s_op = &jffs2_super_operations; - sb->s_export_op = &jffs2_export_ops; - sb->s_flags = sb->s_flags | SB_NOATIME; - sb->s_xattr = jffs2_xattr_handlers; -#ifdef CONFIG_JFFS2_FS_POSIX_ACL - sb->s_flags |= SB_POSIXACL; +#ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7 + spinor_mtd = GetMtd("spinor"); +#else + spinor_mtd = (struct MtdDev *)LOS_DL_LIST_ENTRY(part_head->pstNext, mtd_partition, node_info)->mtd_info; #endif - return jffs2_do_fill_super(sb, fc); -} + if (spinor_mtd == NULL) { + free(sb); + return -EPERM; + } + jffs2_dev_list[part_no].blockEnd = mtd_part->end_block; + jffs2_dev_list[part_no].blockSize = spinor_mtd->eraseSize; + jffs2_dev_list[part_no].blockStart = mtd_part->start_block; +#ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7 + (void)FreeMtd(spinor_mtd); +#endif + sb->jffs2_sb.mtd = mtd_part->mtd_info; + sb->s_dev = &jffs2_dev_list[part_no]; -static int jffs2_get_tree(struct fs_context *fc) -{ - return get_tree_mtd(fc, jffs2_fill_super); -} + c = JFFS2_SB_INFO(sb); + c->flash_size = (mtd_part->end_block - mtd_part->start_block + 1) * spinor_mtd->eraseSize; + c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size); + c->sector_size = spinor_mtd->eraseSize; -static void jffs2_free_fc(struct fs_context *fc) -{ - kfree(fc->s_fs_info); -} + jffs2_dbg(1, "C mtd_size:%d,mtd-erase:%d,blocks:%d,hashsize:%d\n", + c->flash_size, c->sector_size, c->flash_size / c->sector_size, c->inocache_hashsize); -static const struct fs_context_operations jffs2_context_ops = { - .free = jffs2_free_fc, - .parse_param = jffs2_parse_param, - .get_tree = jffs2_get_tree, - .reconfigure = jffs2_reconfigure, -}; + c->inocache_list = zalloc(sizeof(struct jffs2_inode_cache *) * c->inocache_hashsize); + if (c->inocache_list == NULL) { + free(sb); + return -ENOMEM; + } + if (jffs2_mounted_number++ == 0) { + (void)jffs2_create_slab_caches(); // No error check, cannot fail + (void)jffs2_compressors_init(); + } -static int jffs2_init_fs_context(struct fs_context *fc) -{ - struct jffs2_sb_info *ctx; + ret = jffs2_fill_super(sb); + if (ret) { + if (--jffs2_mounted_number == 0) { + jffs2_destroy_slab_caches(); + (void)jffs2_compressors_exit(); + } + + free(sb); + free(c->inocache_list); + c->inocache_list = NULL; + return ret; + } - ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + if (!(mountflags & MS_RDONLY)) { + jffs2_start_garbage_collect_thread(c); + } - fc->s_fs_info = ctx; - fc->ops = &jffs2_context_ops; + sb->s_mount_flags = mountflags; + *root_node = sb->s_root; return 0; } -static void jffs2_put_super (struct super_block *sb) +int jffs2_umount(struct jffs2_inode *root_node) { + struct super_block *sb = root_node->i_sb; struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); + struct jffs2_full_dirent *fd, *next; - jffs2_dbg(2, "%s()\n", __func__); + D2(PRINTK("Jffs2Umount\n")); - mutex_lock(&c->alloc_sem); - jffs2_flush_wbuf_pad(c); - mutex_unlock(&c->alloc_sem); - - jffs2_sum_exit(c); - - jffs2_free_ino_caches(c); - jffs2_free_raw_node_refs(c); - kvfree(c->blocks); - jffs2_flash_cleanup(c); - kfree(c->inocache_list); - jffs2_clear_xattr_subsystem(c); - mtd_sync(c->mtd); - jffs2_dbg(1, "%s(): returning\n", __func__); -} - -static void jffs2_kill_sb(struct super_block *sb) -{ - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - if (c && !sb_rdonly(sb)) + // Only really umount if this is the only mount + if (!(sb->s_mount_flags & MS_RDONLY)) { jffs2_stop_garbage_collect_thread(c); - kill_mtd_super(sb); - kfree(c); -} - -static struct file_system_type jffs2_fs_type = { - .owner = THIS_MODULE, - .name = "jffs2", - .init_fs_context = jffs2_init_fs_context, - .parameters = jffs2_fs_parameters, - .kill_sb = jffs2_kill_sb, -}; -MODULE_ALIAS_FS("jffs2"); - -static int __init init_jffs2_fs(void) -{ - int ret; + } - /* Paranoia checks for on-medium structures. If we ask GCC - to pack them with __attribute__((packed)) then it _also_ - assumes that they're not aligned -- so it emits crappy - code on some architectures. Ideally we want an attribute - which means just 'no padding', without the alignment - thing. But GCC doesn't have that -- we have to just - hope the structs are the right sizes, instead. */ - BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); - BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); - BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); - BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + // free directory entries + for (fd = root_node->jffs2_i.dents; fd; fd = next) { + next = fd->next; + jffs2_free_full_dirent(fd); + } - pr_info("version 2.2." -#ifdef CONFIG_JFFS2_FS_WRITEBUFFER - " (NAND)" -#endif -#ifdef CONFIG_JFFS2_SUMMARY - " (SUMMARY) " -#endif - " © 2001-2006 Red Hat, Inc.\n"); + free(root_node); - jffs2_inode_cachep = kmem_cache_create("jffs2_i", - sizeof(struct jffs2_inode_info), - 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD|SLAB_ACCOUNT), - jffs2_i_init_once); - if (!jffs2_inode_cachep) { - pr_err("error: Failed to initialise inode cache\n"); - return -ENOMEM; - } - ret = jffs2_compressors_init(); - if (ret) { - pr_err("error: Failed to initialise compressors\n"); - goto out; - } - ret = jffs2_create_slab_caches(); - if (ret) { - pr_err("error: Failed to initialise slab caches\n"); - goto out_compressors; - } - ret = register_filesystem(&jffs2_fs_type); - if (ret) { - pr_err("error: Failed to register filesystem\n"); - goto out_slab; + // Clean up the super block and root_node inode + jffs2_free_ino_caches(c); + jffs2_free_raw_node_refs(c); + free(c->blocks); + c->blocks = NULL; + free(c->inocache_list); + c->inocache_list = NULL; + (void)Jffs2HashDeinit(&sb->s_node_hash_lock); + + (void)mutex_destroy(&c->alloc_sem); + (void)mutex_destroy(&c->erase_free_sem); + free(sb); + // That's all folks. + D2(PRINTK("Jffs2Umount No current mounts\n")); + + if (--jffs2_mounted_number == 0) { + jffs2_destroy_slab_caches(); + (void)jffs2_compressors_exit(); } return 0; - - out_slab: - jffs2_destroy_slab_caches(); - out_compressors: - jffs2_compressors_exit(); - out: - kmem_cache_destroy(jffs2_inode_cachep); - return ret; -} - -static void __exit exit_jffs2_fs(void) -{ - unregister_filesystem(&jffs2_fs_type); - jffs2_destroy_slab_caches(); - jffs2_compressors_exit(); - - /* - * Make sure all delayed rcu free inodes are flushed before we - * destroy cache. - */ - rcu_barrier(); - kmem_cache_destroy(jffs2_inode_cachep); } - -module_init(init_jffs2_fs); -module_exit(exit_jffs2_fs); - -MODULE_DESCRIPTION("The Journalling Flash File System, v2"); -MODULE_AUTHOR("Red Hat, Inc."); -MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for - // the sake of this tag. It's Free Software. diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index cda9a361368e8e2c9949e577718691e931bd06bd..dda38141ae8822c59a0f610faefa6714b247ad04 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -9,16 +9,15 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include #include #include -#include #include -#include +#include +#include "mtd_dev.h" #include "nodelist.h" #include "compr.h" - +#include "los_crc32.h" int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri) @@ -30,8 +29,6 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, return -ENOMEM; } - memset(ic, 0, sizeof(*ic)); - f->inocache = ic; f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */ f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; @@ -69,8 +66,10 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 int retried = 0; unsigned long cnt = 2; - D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { - pr_crit("Eep. CRC not correct in jffs2_write_dnode()\n"); + D1(if (je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { + printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode(), je32_to_cpu(ri->hdr_crc):%d, " + "crc32(0, ri, sizeof(struct jffs2_unknown_node) - 4):%d\n", je32_to_cpu(ri->hdr_crc), + crc32(0, ri, sizeof(struct jffs2_unknown_node) - 4)); BUG(); } ); @@ -219,11 +218,13 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff je32_to_cpu(rd->name_crc)); D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { - pr_crit("Eep. CRC not correct in jffs2_write_dirent()\n"); + printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent(), je32_to_cpu(rd->hdr_crc):%d, " + "crc32(0, rd, sizeof(struct jffs2_unknown_node) - 4):%d\n", je32_to_cpu(rd->hdr_crc), + crc32(0, rd, sizeof(struct jffs2_unknown_node) - 4)); BUG(); }); - if (strnlen(name, namelen) != namelen) { + if (strnlen((const char *)name, namelen) != namelen) { /* This should never happen, but seems to have done on at least one occasion: https://dev.laptop.org/ticket/4184 */ pr_crit("Error in jffs2_write_dirent() -- name contains zero bytes!\n"); @@ -245,7 +246,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(NULL, name, namelen); + fd->nhash = full_name_hash(name, namelen); fd->type = rd->type; memcpy(fd->name, name, namelen); fd->name[namelen]=0; @@ -343,10 +344,24 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, { int ret = 0; uint32_t writtenlen = 0; + unsigned char *bufRet = NULL; + unsigned char *bufRetBak = NULL; jffs2_dbg(1, "%s(): Ino #%u, ofs 0x%x, len 0x%x\n", __func__, f->inocache->ino, offset, writelen); + if (writelen > 0) { + bufRet = kmalloc(writelen, GFP_KERNEL); + if (bufRet == NULL) { + return -ENOMEM; + } + bufRetBak = bufRet; + if (LOS_CopyToKernel(bufRet, writelen, buf, writelen) != 0) { + kfree(bufRet); + return -EFAULT; + } + } + while(writelen) { struct jffs2_full_dnode *fn; unsigned char *comprbuf = NULL; @@ -370,7 +385,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, PAGE_SIZE - (offset & (PAGE_SIZE-1))); cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen); - comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen); + comprtype = jffs2_compress(c, f, bufRet, &comprbuf, &datalen, &cdatalen); ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); @@ -390,7 +405,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, ALLOC_NORETRY); - jffs2_free_comprbuf(comprbuf, buf); + jffs2_free_comprbuf(comprbuf, bufRet); if (IS_ERR(fn)) { ret = PTR_ERR(fn); @@ -432,15 +447,18 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, writtenlen += datalen; offset += datalen; writelen -= datalen; - buf += datalen; + bufRet += datalen; } *retlen = writtenlen; + if (bufRetBak != NULL) { + kfree(bufRetBak); + } return ret; } int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, - const struct qstr *qstr) + const char *name, int namelen) { struct jffs2_raw_dirent *rd; struct jffs2_full_dnode *fn; @@ -468,7 +486,8 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, jemode_to_cpu(ri->mode)); if (IS_ERR(fn)) { - jffs2_dbg(1, "jffs2_write_dnode() failed\n"); + jffs2_dbg(1, "jffs2_write_dnode() failed,error:%ld\n", + PTR_ERR(fn)); /* Eeek. Wave bye bye */ mutex_unlock(&f->sem); jffs2_complete_reservation(c); @@ -482,19 +501,12 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, mutex_unlock(&f->sem); jffs2_complete_reservation(c); - ret = jffs2_init_security(&f->vfs_inode, &dir_f->vfs_inode, qstr); - if (ret) - return ret; - ret = jffs2_init_acl_post(&f->vfs_inode); - if (ret) - return ret; - - ret = jffs2_reserve_space(c, sizeof(*rd)+qstr->len, &alloclen, - ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(qstr->len)); + ret = jffs2_reserve_space(c, sizeof(*rd)+ namelen, &alloclen, + ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen)); if (ret) { /* Eep. */ - jffs2_dbg(1, "jffs2_reserve_space() for dirent failed\n"); + jffs2_dbg(1, "jffs2_reserve_space() for dirent failed,ret:%d\n",ret); return ret; } @@ -509,19 +521,19 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); - rd->totlen = cpu_to_je32(sizeof(*rd) + qstr->len); + rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); rd->pino = cpu_to_je32(dir_f->inocache->ino); rd->version = cpu_to_je32(++dir_f->highest_version); rd->ino = ri->ino; rd->mctime = ri->ctime; - rd->nsize = qstr->len; + rd->nsize = namelen; rd->type = DT_REG; rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); - rd->name_crc = cpu_to_je32(crc32(0, qstr->name, qstr->len)); + rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); - fd = jffs2_write_dirent(c, dir_f, rd, qstr->name, qstr->len, ALLOC_NORMAL); + fd = jffs2_write_dirent(c, dir_f, rd, (const unsigned char *)name, namelen, ALLOC_NORMAL); jffs2_free_raw_dirent(rd); @@ -553,7 +565,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t alloclen; int ret; - if (!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(); @@ -584,7 +596,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); - fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, ALLOC_DELETION); + fd = jffs2_write_dirent(c, dir_f, rd, (const unsigned char *)name, namelen, ALLOC_DELETION); jffs2_free_raw_dirent(rd); @@ -598,7 +610,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, jffs2_add_fd_to_list(c, fd, &dir_f->dents); mutex_unlock(&dir_f->sem); } else { - uint32_t nhash = full_name_hash(NULL, name, namelen); + uint32_t nhash = full_name_hash((const unsigned char *)name, namelen); fd = dir_f->dents; /* We don't actually want to reserve any space, but we do @@ -703,7 +715,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); - fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, ALLOC_NORMAL); + fd = jffs2_write_dirent(c, dir_f, rd, (const unsigned char *)name, namelen, ALLOC_NORMAL); jffs2_free_raw_dirent(rd); diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c index a1bda9dab3f8b67e1306b7695c4461f7010a47bf..c3c695bdc8217af8743ec36d8ef158ecd31cc712 100644 --- a/fs/jffs2/writev.c +++ b/fs/jffs2/writev.c @@ -10,42 +10,97 @@ */ #include -#include +#include "mtd_dev.h" #include "nodelist.h" int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen) { - if (!jffs2_is_writebuffered(c)) { - if (jffs2_sum_active()) { - int res; - res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to); - if (res) { - return res; + unsigned long i; + size_t totlen = 0, thislen; + int ret = 0; + + for (i = 0; i < count; i++) { + // writes need to be aligned but the data we're passed may not be + // Observation suggests most unaligned writes are small, so we + // optimize for that case. + + if (((vecs[i].iov_len & (sizeof(int) - 1))) || + (((unsigned long) vecs[i].iov_base & (sizeof(unsigned long) - 1)))) { + // are there iov's after this one? Or is it so much we'd need + // to do multiple writes anyway? + if ((i + 1) < count || vecs[i].iov_len > 256) { + // cop out and malloc + unsigned long j; + size_t sizetomalloc = 0, totvecsize = 0; + char *cbuf, *cbufptr; + + for (j = i; j < count; j++) + totvecsize += vecs[j].iov_len; + + // pad up in case unaligned + sizetomalloc = totvecsize + sizeof(int) - 1; + sizetomalloc &= ~(sizeof(int) - 1); + cbuf = (char *) malloc(sizetomalloc); + // malloc returns aligned memory + if (!cbuf) { + ret = -ENOMEM; + goto writev_out; + } + cbufptr = cbuf; + for (j = i; j < count; j++) { + (void)memcpy_s(cbufptr, vecs[j].iov_len, vecs[j].iov_base, vecs[j].iov_len); + cbufptr += vecs[j].iov_len; + } + ret = jffs2_flash_write(c, to, sizetomalloc, &thislen, + (unsigned char *) cbuf); + if (thislen > totvecsize) // in case it was aligned up + thislen = totvecsize; + totlen += thislen; + free(cbuf); + goto writev_out; + } else { + // otherwise optimize for the common case + int buf[256/sizeof(int)]; // int, so int aligned + size_t lentowrite; + + lentowrite = vecs[i].iov_len; + // pad up in case its unaligned + lentowrite += sizeof(int) - 1; + lentowrite &= ~(sizeof(int) - 1); + ret = memcpy_s(buf, sizeof(buf), vecs[i].iov_base, vecs[i].iov_len); + if (ret != EOK) + goto writev_out; + + ret = jffs2_flash_write(c, to, lentowrite, &thislen, + (unsigned char *) &buf[0]); + if (thislen > vecs[i].iov_len) + thislen = vecs[i].iov_len; } + } else { + ret = jffs2_flash_write(c, to, vecs[i].iov_len, &thislen, + vecs[i].iov_base); } + totlen += thislen; + if (ret || thislen != vecs[i].iov_len) break; + to += vecs[i].iov_len; } - return mtd_writev(c->mtd, vecs, count, to, retlen); +writev_out: + if (retlen) *retlen = totlen; + + return ret; } int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) { int ret; - ret = mtd_write(c->mtd, ofs, len, retlen, buf); - - if (jffs2_sum_active()) { - struct kvec vecs[1]; - int res; - - vecs[0].iov_base = (unsigned char *) buf; - vecs[0].iov_len = len; - - res = jffs2_sum_add_kvec(c, vecs, 1, (uint32_t) ofs); - if (res) { - return res; - } + ret = c->mtd->write(c->mtd, ofs, len, (char *)buf); + if (ret >= 0) { + *retlen = ret; + return 0; } + *retlen = 0; return ret; } diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 720007b2fd65defb63ded33466f60a9ec52ec364..184608a1c68429d1914da93598d7d2dcf1d63dcd 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -12,7 +12,6 @@ #ifndef _JFFS2_FS_XATTR_H_ #define _JFFS2_FS_XATTR_H_ -#include #include #define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */ @@ -48,7 +47,7 @@ struct jffs2_xattr_ref struct jffs2_raw_node_ref *node; uint8_t class; uint8_t flags; /* Currently unused */ - u16 unused; + uint16_t unused; uint32_t xseqno; union { @@ -89,11 +88,6 @@ extern int jffs2_verify_xattr(struct jffs2_sb_info *c); extern void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd); extern void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref); -extern int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, - char *buffer, size_t size); -extern int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, - const char *buffer, size_t size, int flags); - extern const struct xattr_handler *jffs2_xattr_handlers[]; extern const struct xattr_handler jffs2_user_xattr_handler; extern const struct xattr_handler jffs2_trusted_xattr_handler; @@ -117,8 +111,6 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t); #endif /* CONFIG_JFFS2_FS_XATTR */ #ifdef CONFIG_JFFS2_FS_SECURITY -extern int jffs2_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr); extern const struct xattr_handler jffs2_security_xattr_handler; #else #define jffs2_init_security(inode,dir,qstr) (0) diff --git a/fs/signalfd.c b/fs/signalfd.c index b94fb5f81797a6ab74914da7e95597d3ee343e46..456046e158737450055c77283321867f03b23ee0 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -35,7 +35,17 @@ void signalfd_cleanup(struct sighand_struct *sighand) { - wake_up_pollfree(&sighand->signalfd_wqh); + wait_queue_head_t *wqh = &sighand->signalfd_wqh; + /* + * The lockless check can race with remove_wait_queue() in progress, + * but in this case its caller should run under rcu_read_lock() and + * sighand_cachep is SLAB_TYPESAFE_BY_RCU, we can safely return. + */ + if (likely(!waitqueue_active(wqh))) + return; + + /* wait_queue_entry_t->func(POLLFREE) should do remove_wait_queue() */ + wake_up_poll(wqh, EPOLLHUP | POLLFREE); } struct signalfd_ctx {