source: rtems/cpukit/libfs/src/jffs2/src/fs-rtems.c @ 5db68a5

Last change on this file since 5db68a5 was 5db68a5, checked in by Kinsey Moore <kinsey.moore@…>, on 10/04/19 at 21:11:30

cpukit/jffs2: Add support for NAND under JFFS2

This adds write buffer and bad block support required for JFFS2
operation on NAND devices. This also adds the minor modifications
necessary for RTEMS support in the Linux header stubs and in wbuf.c.
Memory and NOR backed applications should experience no difference in
operation since they do not expose the callbacks required for write
buffer support.

  • Property mode set to 100644
File size: 46.6 KB
Line 
1#include "rtems-jffs2-config.h"
2
3/*
4 * JFFS2 -- Journalling Flash File System, Version 2.
5 *
6 * Copyright © 2001-2003 Free Software Foundation, Inc.
7 * Copyright © 2001-2007 Red Hat, Inc.
8 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
9 * Copyright © 2013, 2016 embedded brains GmbH <rtems@embedded-brains.de>
10 *
11 * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com>
12 * Contributors: David Woodhouse, Nick Garnett, Richard Panton.
13 *
14 * Port to the RTEMS by embedded brains GmbH.
15 *
16 * For licensing information, see the file 'LICENCE' in this directory.
17 *
18 * $Id: fs-ecos.c,v 1.44 2005/07/24 15:29:57 dedekind Exp $
19 *
20 */
21
22#include <linux/kernel.h>
23#include "nodelist.h"
24#include <linux/pagemap.h>
25#include <linux/crc32.h>
26#include <linux/mtd/mtd.h>
27#include "compr.h"
28#include <errno.h>
29#include <string.h>
30#include <assert.h>
31#include <rtems/libio.h>
32#include <rtems/libio_.h>
33#include <rtems/sysinit.h>
34
35/* Ensure that the JFFS2 values are identical to the POSIX defines */
36
37RTEMS_STATIC_ASSERT(DT_DIR == (S_IFDIR >> 12), DT_DIR);
38RTEMS_STATIC_ASSERT(DT_LNK == (S_IFLNK >> 12), DT_LNK);
39RTEMS_STATIC_ASSERT(DT_REG == (S_IFREG >> 12), DT_REG);
40
41RTEMS_STATIC_ASSERT(00400 == S_IRUSR, S_IRUSR);
42RTEMS_STATIC_ASSERT(00200 == S_IWUSR, S_IWUSR);
43RTEMS_STATIC_ASSERT(00100 == S_IXUSR, S_IXUSR);
44RTEMS_STATIC_ASSERT(00040 == S_IRGRP, S_IRGRP);
45RTEMS_STATIC_ASSERT(00020 == S_IWGRP, S_IWGRP);
46RTEMS_STATIC_ASSERT(00010 == S_IXGRP, S_IXGRP);
47RTEMS_STATIC_ASSERT(00004 == S_IROTH, S_IROTH);
48RTEMS_STATIC_ASSERT(00002 == S_IWOTH, S_IWOTH);
49RTEMS_STATIC_ASSERT(00001 == S_IXOTH, S_IXOTH);
50
51RTEMS_STATIC_ASSERT(0140000 == S_IFSOCK, S_IFSOCK);
52RTEMS_STATIC_ASSERT(0120000 == S_IFLNK, S_IFLNK);
53RTEMS_STATIC_ASSERT(0100000 == S_IFREG, S_IFREG);
54RTEMS_STATIC_ASSERT(0060000 == S_IFBLK, S_IFBLK);
55RTEMS_STATIC_ASSERT(0040000 == S_IFDIR, S_IFDIR);
56RTEMS_STATIC_ASSERT(0020000 == S_IFCHR, S_IFCHR);
57RTEMS_STATIC_ASSERT(0010000 == S_IFIFO, S_IFIFO);
58RTEMS_STATIC_ASSERT(0004000 == S_ISUID, S_ISUID);
59RTEMS_STATIC_ASSERT(0002000 == S_ISGID, S_ISGID);
60RTEMS_STATIC_ASSERT(0001000 == S_ISVTX, S_ISVTX);
61
62static int jffs2_read_inode (struct _inode *inode);
63static void jffs2_clear_inode (struct _inode *inode);
64
65//==========================================================================
66// Ref count and nlink management
67
68
69// FIXME: This seems like real cruft. Wouldn't it be better just to do the
70// right thing?
71static void icache_evict(struct _inode *root_i, struct _inode *i)
72{
73        struct _inode *this = root_i, *next;
74
75 restart:
76        D2(printf("icache_evict\n"));
77        // If this is an absolute search path from the root,
78        // remove all cached inodes with i_count of zero (these are only
79        // held where needed for dotdot filepaths)
80        while (this) {
81                next = this->i_cache_next;
82                if (this != i && this->i_count == 0) {
83                        struct _inode *parent = this->i_parent;
84                        if (this->i_cache_next)
85                                this->i_cache_next->i_cache_prev = this->i_cache_prev;
86                        if (this->i_cache_prev)
87                                this->i_cache_prev->i_cache_next = this->i_cache_next;
88                        jffs2_clear_inode(this);
89                        memset(this, 0x5a, sizeof(*this));
90                        free(this);
91                        if (parent && parent != this) {
92                                parent->i_count--;
93                                this = root_i;
94                                goto restart;
95                        }
96                }
97                this = next;
98        }
99}
100
101// -------------------------------------------------------------------------
102// jffs2_fo_write()
103// Write data to file.
104static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri,
105                       unsigned long offset)
106{
107        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
108        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
109        struct jffs2_full_dnode *fn;
110        uint32_t alloc_len;
111        int ret = 0;
112
113        /* Make new hole frag from old EOF to new page */
114        D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
115                  (unsigned int)inode->i_size, offset));
116
117        ret = jffs2_reserve_space(c, sizeof(*ri), &alloc_len, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
118        if (ret)
119                return ret;
120
121        mutex_lock(&f->sem);
122
123        ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
124        ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
125        ri->totlen = cpu_to_je32(sizeof(*ri));
126        ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
127
128        ri->version = cpu_to_je32(++f->highest_version);
129        ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset));
130
131        ri->offset = cpu_to_je32(inode->i_size);
132        ri->dsize = cpu_to_je32(offset - inode->i_size);
133        ri->csize = cpu_to_je32(0);
134        ri->compr = JFFS2_COMPR_ZERO;
135        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
136        ri->data_crc = cpu_to_je32(0);
137               
138        fn = jffs2_write_dnode(c, f, ri, NULL, 0, ALLOC_NORMAL);
139        jffs2_complete_reservation(c);
140        if (IS_ERR(fn)) {
141                ret = PTR_ERR(fn);
142                mutex_unlock(&f->sem);
143                return ret;
144        }
145        ret = jffs2_add_full_dnode_to_inode(c, f, fn);
146        if (f->metadata) {
147                jffs2_mark_node_obsolete(c, f->metadata->raw);
148                jffs2_free_full_dnode(f->metadata);
149                f->metadata = NULL;
150        }
151        if (ret) {
152                D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret));
153                jffs2_mark_node_obsolete(c, fn->raw);
154                jffs2_free_full_dnode(fn);
155                mutex_unlock(&f->sem);
156                return ret;
157        }
158        inode->i_size = offset;
159        mutex_unlock(&f->sem);
160        return 0;
161}
162
163static int jffs2_do_setattr (struct _inode *inode, struct iattr *iattr)
164{
165        struct jffs2_full_dnode *old_metadata, *new_metadata;
166        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
167        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
168        struct jffs2_raw_inode *ri;
169        unsigned char *mdata = NULL;
170        int mdatalen = 0;
171        unsigned int ivalid;
172        uint32_t alloclen;
173        int ret;
174        int alloc_type = ALLOC_NORMAL;
175
176        jffs2_dbg(1, "%s(): ino #%lu\n", __func__, inode->i_ino);
177
178        /* Special cases - we don't want more than one data node
179           for these types on the medium at any time. So setattr
180           must read the original data associated with the node
181           (i.e. the device numbers or the target name) and write
182           it out again with the appropriate data attached */
183        if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
184                return -EIO;
185        } else if (S_ISLNK(inode->i_mode)) {
186                mutex_lock(&f->sem);
187                mdatalen = f->metadata->size;
188                mdata = kmalloc(f->metadata->size, GFP_USER);
189                if (!mdata) {
190                        mutex_unlock(&f->sem);
191                        return -ENOMEM;
192                }
193                ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
194                if (ret) {
195                        mutex_unlock(&f->sem);
196                        kfree(mdata);
197                        return ret;
198                }
199                mutex_unlock(&f->sem);
200                jffs2_dbg(1, "%s(): Writing %d bytes of symlink target\n",
201                          __func__, mdatalen);
202        }
203
204        ri = jffs2_alloc_raw_inode();
205        if (!ri) {
206                if (S_ISLNK(inode->i_mode))
207                        kfree(mdata);
208                return -ENOMEM;
209        }
210
211        ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &alloclen,
212                                  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
213        if (ret) {
214                jffs2_free_raw_inode(ri);
215                if (S_ISLNK(inode->i_mode))
216                         kfree(mdata);
217                return ret;
218        }
219        mutex_lock(&f->sem);
220        ivalid = iattr->ia_valid;
221
222        ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
223        ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
224        ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
225        ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
226
227        ri->ino = cpu_to_je32(inode->i_ino);
228        ri->version = cpu_to_je32(++f->highest_version);
229
230        ri->uid = cpu_to_je16((ivalid & ATTR_UID)?
231                from_kuid(&init_user_ns, iattr->ia_uid):i_uid_read(inode));
232        ri->gid = cpu_to_je16((ivalid & ATTR_GID)?
233                from_kgid(&init_user_ns, iattr->ia_gid):i_gid_read(inode));
234
235        if (ivalid & ATTR_MODE)
236                ri->mode = cpu_to_jemode(iattr->ia_mode);
237        else
238                ri->mode = cpu_to_jemode(inode->i_mode);
239
240
241        ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
242        ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
243        ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
244        ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
245
246        ri->offset = cpu_to_je32(0);
247        ri->csize = ri->dsize = cpu_to_je32(mdatalen);
248        ri->compr = JFFS2_COMPR_NONE;
249        if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
250                /* It's an extension. Make it a hole node */
251                ri->compr = JFFS2_COMPR_ZERO;
252                ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
253                ri->offset = cpu_to_je32(inode->i_size);
254        } else if (ivalid & ATTR_SIZE && !iattr->ia_size) {
255                /* For truncate-to-zero, treat it as deletion because
256                   it'll always be obsoleting all previous nodes */
257                alloc_type = ALLOC_DELETION;
258        }
259        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
260        if (mdatalen)
261                ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
262        else
263                ri->data_crc = cpu_to_je32(0);
264
265        new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, alloc_type);
266        if (S_ISLNK(inode->i_mode))
267                kfree(mdata);
268
269        if (IS_ERR(new_metadata)) {
270                jffs2_complete_reservation(c);
271                jffs2_free_raw_inode(ri);
272                mutex_unlock(&f->sem);
273                return PTR_ERR(new_metadata);
274        }
275        /* It worked. Update the inode */
276        inode->i_atime = ITIME(je32_to_cpu(ri->atime));
277        inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
278        inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
279        inode->i_mode = jemode_to_cpu(ri->mode);
280        i_uid_write(inode, je16_to_cpu(ri->uid));
281        i_gid_write(inode, je16_to_cpu(ri->gid));
282
283
284        old_metadata = f->metadata;
285
286        if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
287                jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size);
288
289        if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
290                jffs2_add_full_dnode_to_inode(c, f, new_metadata);
291                inode->i_size = iattr->ia_size;
292                f->metadata = NULL;
293        } else {
294                f->metadata = new_metadata;
295        }
296        if (old_metadata) {
297                jffs2_mark_node_obsolete(c, old_metadata->raw);
298                jffs2_free_full_dnode(old_metadata);
299        }
300        jffs2_free_raw_inode(ri);
301
302        mutex_unlock(&f->sem);
303        jffs2_complete_reservation(c);
304
305        /* We have to do the truncate_setsize() without f->sem held, since
306           some pages may be locked and waiting for it in readpage().
307           We are protected from a simultaneous write() extending i_size
308           back past iattr->ia_size, because do_truncate() holds the
309           generic inode semaphore. */
310        if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
311                truncate_setsize(inode, iattr->ia_size);
312        }       
313
314        return 0;
315}
316
317typedef struct {
318        struct super_block sb;
319        struct jffs2_inode_cache *inode_cache[];
320} rtems_jffs2_fs_info;
321
322static void rtems_jffs2_do_lock(struct super_block *sb)
323{
324        rtems_recursive_mutex_lock(&sb->s_mutex);
325}
326
327static void rtems_jffs2_do_unlock(struct super_block *sb)
328{
329        rtems_recursive_mutex_unlock(&sb->s_mutex);
330}
331
332static void rtems_jffs2_free_directory_entries(struct _inode *inode)
333{
334        struct jffs2_full_dirent *current = inode->jffs2_i.dents;
335
336        while (current != NULL) {
337                struct jffs2_full_dirent *victim = current;
338
339                current = victim->next;
340                jffs2_free_full_dirent(victim);
341        }
342}
343
344static void rtems_jffs2_flash_control_destroy(rtems_jffs2_flash_control *fc)
345{
346        if (fc->destroy != NULL) {
347                (*fc->destroy)(fc);
348        }
349}
350static void rtems_jffs2_compressor_control_destroy(rtems_jffs2_compressor_control *cc)
351{
352        if (cc != NULL && cc->destroy != NULL) {
353                (*cc->destroy)(cc);
354        }
355}
356
357
358static void rtems_jffs2_free_fs_info(rtems_jffs2_fs_info *fs_info, bool do_mount_fs_was_successful)
359{
360        struct super_block *sb = &fs_info->sb;
361        struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
362
363        if (do_mount_fs_was_successful) {
364                jffs2_free_ino_caches(c);
365                jffs2_free_raw_node_refs(c);
366                free(c->blocks);
367        }
368
369        rtems_jffs2_flash_control_destroy(fs_info->sb.s_flash_control);
370        rtems_jffs2_compressor_control_destroy(fs_info->sb.s_compressor_control);
371        rtems_recursive_mutex_destroy(&sb->s_mutex);
372        free(fs_info);
373}
374
375static int rtems_jffs2_eno_to_rv_and_errno(int eno)
376{
377        if (eno == 0) {
378                return 0;
379        } else {
380                errno = eno;
381
382                return -1;
383        }
384}
385
386static struct _inode *rtems_jffs2_get_inode_by_location(
387        const rtems_filesystem_location_info_t *loc
388)
389{
390        return loc->node_access;
391}
392
393static struct _inode *rtems_jffs2_get_inode_by_iop(
394        const rtems_libio_t *iop
395)
396{
397        return iop->pathinfo.node_access;
398}
399
400static int rtems_jffs2_fstat(
401        const rtems_filesystem_location_info_t *loc,
402        struct stat *buf
403)
404{
405        struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
406        struct super_block *sb = inode->i_sb;
407        rtems_jffs2_flash_control *fc = sb->s_flash_control;
408
409        rtems_jffs2_do_lock(sb);
410
411        buf->st_dev = fc->device_identifier;
412        buf->st_blksize = PAGE_SIZE;
413        buf->st_mode = inode->i_mode;
414        buf->st_ino = inode->i_ino;
415        buf->st_nlink = inode->i_nlink;
416        buf->st_uid = inode->i_uid;
417        buf->st_gid = inode->i_gid;
418        buf->st_size = inode->i_size;
419        buf->st_atime = inode->i_atime;
420        buf->st_mtime = inode->i_mtime;
421        buf->st_ctime = inode->i_ctime;
422
423        rtems_jffs2_do_unlock(sb);
424
425        return 0;
426}
427
428static int rtems_jffs2_fill_dirent(struct dirent *de, off_t off, uint32_t ino, const char *name, unsigned char type)
429{
430        int eno = 0;
431        size_t len;
432
433        memset(de, 0, sizeof(*de));
434
435        de->d_off = off * sizeof(*de);
436        de->d_reclen = sizeof(*de);
437        de->d_ino = ino;
438#ifdef RTEMS_JFFS2_HAVE_D_TYPE
439        de->d_type = type;
440#endif
441
442        len = strlen(name);
443        de->d_namlen = len;
444
445        if (len < sizeof(de->d_name) - 1) {
446                memcpy(&de->d_name[0], name, len);
447        } else {
448                eno = EOVERFLOW;
449        }
450
451        return eno;
452}
453
454static ssize_t rtems_jffs2_dir_read(rtems_libio_t *iop, void *buf, size_t len)
455{
456        struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
457        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
458        struct dirent *de = buf;
459        off_t fd_off = 2;
460        int eno = 0;
461        struct jffs2_full_dirent *fd;
462        off_t begin;
463        off_t end;
464        off_t off;
465
466        rtems_jffs2_do_lock(inode->i_sb);
467
468        fd = f->dents;
469        begin = iop->offset;
470        end = begin + len / sizeof(*de);
471        off = begin;
472
473        if (off == 0 && off < end) {
474                eno = rtems_jffs2_fill_dirent(de, off, inode->i_ino, ".", DT_DIR);
475                assert(eno == 0);
476                ++off;
477                ++de;
478        }
479
480        if (off == 1 && off < end) {
481                eno = rtems_jffs2_fill_dirent(de, off, inode->i_parent->i_ino, "..", DT_DIR);
482                assert(eno == 0);
483                ++off;
484                ++de;
485        }
486
487        while (eno == 0 && off < end && fd != NULL) {
488                if (fd->ino != 0) {
489                        if (off == fd_off) {
490                                eno = rtems_jffs2_fill_dirent(de, off, fd->ino, fd->name, fd->type);
491                                ++off;
492                                ++de;
493                        }
494
495                        ++fd_off;
496                }
497
498                fd = fd->next;
499        }
500
501        rtems_jffs2_do_unlock(inode->i_sb);
502
503        if (eno == 0) {
504                iop->offset = off;
505
506                return (off - begin) * sizeof(*de);
507        } else {
508                return rtems_jffs2_eno_to_rv_and_errno(eno);
509        }
510}
511
512static uint32_t rtems_jffs2_count_blocks(const struct list_head *list)
513{
514        uint32_t count = 0;
515        struct jffs2_eraseblock *jeb;
516
517        list_for_each_entry(jeb, list, list) {
518                ++count;
519        }
520
521        return count;
522}
523
524static void rtems_jffs2_get_info(
525        const struct jffs2_sb_info *c,
526        rtems_jffs2_info           *info
527)
528{
529        info->flash_size = c->flash_size;
530        info->flash_blocks = c->nr_blocks;
531        info->flash_block_size = c->sector_size;
532        info->used_size = c->used_size;
533        info->dirty_size = c->dirty_size;
534        info->wasted_size = c->wasted_size;
535        info->free_size = c->free_size;
536        info->bad_size = c->bad_size;
537        info->clean_blocks = rtems_jffs2_count_blocks(&c->clean_list);
538        info->dirty_blocks = rtems_jffs2_count_blocks(&c->very_dirty_list)
539                + rtems_jffs2_count_blocks(&c->dirty_list);
540        info->dirty_blocks += c->gcblock != NULL;
541        info->erasable_blocks = rtems_jffs2_count_blocks(&c->erasable_list)
542                + rtems_jffs2_count_blocks(&c->erasable_pending_wbuf_list)
543                + rtems_jffs2_count_blocks(&c->erasing_list)
544                + rtems_jffs2_count_blocks(&c->erase_checking_list)
545                + rtems_jffs2_count_blocks(&c->erase_pending_list)
546                + rtems_jffs2_count_blocks(&c->erase_complete_list);
547        info->free_blocks = rtems_jffs2_count_blocks(&c->free_list);
548        info->free_blocks += c->nextblock != NULL;
549        info->bad_blocks = rtems_jffs2_count_blocks(&c->bad_list);
550}
551
552static int rtems_jffs2_on_demand_garbage_collection(struct jffs2_sb_info *c)
553{
554        if (jffs2_thread_should_wake(c)) {
555                return -jffs2_garbage_collect_pass(c);
556        } else {
557                return 0;
558        }
559}
560
561static int rtems_jffs2_ioctl(
562        rtems_libio_t   *iop,
563        ioctl_command_t  request,
564        void            *buffer
565)
566{
567        struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
568        int eno;
569
570        rtems_jffs2_do_lock(inode->i_sb);
571
572        switch (request) {
573                case RTEMS_JFFS2_GET_INFO:
574                        rtems_jffs2_get_info(&inode->i_sb->jffs2_sb, buffer);
575                        eno = 0;
576                        break;
577                case RTEMS_JFFS2_ON_DEMAND_GARBAGE_COLLECTION:
578                        eno = rtems_jffs2_on_demand_garbage_collection(&inode->i_sb->jffs2_sb);
579                        break;
580                case RTEMS_JFFS2_FORCE_GARBAGE_COLLECTION:
581                        eno = -jffs2_garbage_collect_pass(&inode->i_sb->jffs2_sb);
582                        break;
583                default:
584                        eno = EINVAL;
585                        break;
586        }
587
588        rtems_jffs2_do_unlock(inode->i_sb);
589
590        return rtems_jffs2_eno_to_rv_and_errno(eno);
591}
592
593static const rtems_filesystem_file_handlers_r rtems_jffs2_directory_handlers = {
594        .open_h = rtems_filesystem_default_open,
595        .close_h = rtems_filesystem_default_close,
596        .read_h = rtems_jffs2_dir_read,
597        .write_h = rtems_filesystem_default_write,
598        .ioctl_h = rtems_jffs2_ioctl,
599        .lseek_h = rtems_filesystem_default_lseek_directory,
600        .fstat_h = rtems_jffs2_fstat,
601        .ftruncate_h = rtems_filesystem_default_ftruncate_directory,
602        .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
603        .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
604        .fcntl_h = rtems_filesystem_default_fcntl,
605        .kqfilter_h = rtems_filesystem_default_kqfilter,
606        .mmap_h = rtems_filesystem_default_mmap,
607        .poll_h = rtems_filesystem_default_poll,
608        .readv_h = rtems_filesystem_default_readv,
609        .writev_h = rtems_filesystem_default_writev
610};
611
612static ssize_t rtems_jffs2_file_read(rtems_libio_t *iop, void *buf, size_t len)
613{
614        struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
615        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
616        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
617        int err = 0;
618        off_t pos;
619
620        rtems_jffs2_do_lock(inode->i_sb);
621
622        pos = iop->offset;
623
624        if (pos >= inode->i_size) {
625                len = 0;
626        } else {
627                uint32_t pos_32 = (uint32_t) pos;
628                uint32_t max_available = inode->i_size - pos_32;
629
630                if (len > max_available) {
631                        len = max_available;
632                }
633
634                err = jffs2_read_inode_range(c, f, buf, pos_32, len);
635        }
636
637        if (err == 0) {
638                iop->offset += len;
639        }
640
641        rtems_jffs2_do_unlock(inode->i_sb);
642
643        if (err == 0) {
644                return (ssize_t) len;
645        } else {
646                errno = -err;
647
648                return -1;
649        }
650}
651
652static ssize_t rtems_jffs2_file_write(rtems_libio_t *iop, const void *buf, size_t len)
653{
654        struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
655        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
656        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
657        struct jffs2_raw_inode ri;
658        uint32_t writtenlen;
659        off_t pos;
660        int eno = 0;
661
662        memset(&ri, 0, sizeof(ri));
663
664        ri.ino = cpu_to_je32(f->inocache->ino);
665        ri.mode = cpu_to_jemode(inode->i_mode);
666        ri.uid = cpu_to_je16(inode->i_uid);
667        ri.gid = cpu_to_je16(inode->i_gid);
668        ri.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds());
669
670        rtems_jffs2_do_lock(inode->i_sb);
671
672        if (rtems_libio_iop_is_append(iop)) {
673                pos = inode->i_size;
674        } else {
675                pos = iop->offset;
676        }
677
678        if (pos > inode->i_size) {
679                ri.version = cpu_to_je32(++f->highest_version);
680                eno = -jffs2_extend_file(inode, &ri, pos);
681        }
682
683        if (eno == 0) {
684                ri.isize = cpu_to_je32(inode->i_size);
685
686                eno = -jffs2_write_inode_range(c, f, &ri, (void *) buf, pos, len, &writtenlen);
687        }
688
689        if (eno == 0) {
690                pos += writtenlen;
691
692                inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime);
693
694                if (pos > inode->i_size) {
695                        inode->i_size = pos;
696                }
697
698                iop->offset = pos;
699
700                if (writtenlen != len) {
701                        eno = ENOSPC;
702                }
703        }
704
705        rtems_jffs2_do_unlock(inode->i_sb);
706
707        if (eno == 0) {
708                return writtenlen;
709        } else {
710                errno = eno;
711
712                return -1;
713        }
714}
715
716static int rtems_jffs2_file_ftruncate(rtems_libio_t *iop, off_t length)
717{
718        struct _inode *inode = rtems_jffs2_get_inode_by_iop(iop);
719        struct iattr iattr;
720        int eno;
721
722        iattr.ia_valid = ATTR_SIZE | ATTR_MTIME | ATTR_CTIME;
723        iattr.ia_size = length;
724        iattr.ia_mtime = get_seconds();
725        iattr.ia_ctime = iattr.ia_mtime;
726
727        rtems_jffs2_do_lock(inode->i_sb);
728
729        eno = -jffs2_do_setattr(inode, &iattr);
730
731        rtems_jffs2_do_unlock(inode->i_sb);
732
733        return rtems_jffs2_eno_to_rv_and_errno(eno);
734}
735
736static const rtems_filesystem_file_handlers_r rtems_jffs2_file_handlers = {
737        .open_h = rtems_filesystem_default_open,
738        .close_h = rtems_filesystem_default_close,
739        .read_h = rtems_jffs2_file_read,
740        .write_h = rtems_jffs2_file_write,
741        .ioctl_h = rtems_jffs2_ioctl,
742        .lseek_h = rtems_filesystem_default_lseek_file,
743        .fstat_h = rtems_jffs2_fstat,
744        .ftruncate_h = rtems_jffs2_file_ftruncate,
745        .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
746        .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
747        .fcntl_h = rtems_filesystem_default_fcntl,
748        .kqfilter_h = rtems_filesystem_default_kqfilter,
749        .mmap_h = rtems_filesystem_default_mmap,
750        .poll_h = rtems_filesystem_default_poll,
751        .readv_h = rtems_filesystem_default_readv,
752        .writev_h = rtems_filesystem_default_writev
753};
754
755static const rtems_filesystem_file_handlers_r rtems_jffs2_link_handlers = {
756        .open_h = rtems_filesystem_default_open,
757        .close_h = rtems_filesystem_default_close,
758        .read_h = rtems_filesystem_default_read,
759        .write_h = rtems_filesystem_default_write,
760        .ioctl_h = rtems_jffs2_ioctl,
761        .lseek_h = rtems_filesystem_default_lseek,
762        .fstat_h = rtems_jffs2_fstat,
763        .ftruncate_h = rtems_filesystem_default_ftruncate,
764        .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
765        .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
766        .fcntl_h = rtems_filesystem_default_fcntl,
767        .kqfilter_h = rtems_filesystem_default_kqfilter,
768        .mmap_h = rtems_filesystem_default_mmap,
769        .poll_h = rtems_filesystem_default_poll,
770        .readv_h = rtems_filesystem_default_readv,
771        .writev_h = rtems_filesystem_default_writev
772};
773
774static void rtems_jffs2_set_location(rtems_filesystem_location_info_t *loc, struct _inode *inode)
775{
776        loc->node_access = inode;
777
778        switch (inode->i_mode & S_IFMT) {
779                case S_IFREG:
780                        loc->handlers = &rtems_jffs2_file_handlers;
781                        break;
782                case S_IFDIR:
783                        loc->handlers = &rtems_jffs2_directory_handlers;
784                        break;
785                case S_IFLNK:
786                        loc->handlers = &rtems_jffs2_link_handlers;
787                        break;
788                default:
789                        loc->handlers = &rtems_filesystem_null_handlers;
790                        break;
791        };
792}
793
794static bool rtems_jffs2_eval_is_directory(
795        rtems_filesystem_eval_path_context_t *ctx,
796        void *arg
797)
798{
799        rtems_filesystem_location_info_t *currentloc =
800                rtems_filesystem_eval_path_get_currentloc(ctx);
801        struct _inode *inode = rtems_jffs2_get_inode_by_location(currentloc);
802
803        return S_ISDIR(inode->i_mode);
804}
805
806static rtems_filesystem_eval_path_generic_status rtems_jffs2_eval_token(
807        rtems_filesystem_eval_path_context_t *ctx,
808        void *arg,
809        const char *token,
810        size_t tokenlen
811)
812{
813        rtems_filesystem_eval_path_generic_status status =
814                RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
815        rtems_filesystem_location_info_t *currentloc =
816                rtems_filesystem_eval_path_get_currentloc(ctx);
817        struct _inode *dir_i = rtems_jffs2_get_inode_by_location(currentloc);
818        bool access_ok = rtems_filesystem_eval_path_check_access(
819                ctx,
820                RTEMS_FS_PERMS_EXEC,
821                dir_i->i_mode,
822                dir_i->i_uid,
823                dir_i->i_gid
824        );
825
826        if (access_ok) {
827                struct _inode *entry_i;
828
829                if (rtems_filesystem_is_current_directory(token, tokenlen)) {
830                        entry_i = dir_i;
831                        ++entry_i->i_count;
832                } else if (rtems_filesystem_is_parent_directory(token, tokenlen)) {
833                        entry_i = dir_i->i_parent;
834                        ++entry_i->i_count;
835                } else {
836                        entry_i = jffs2_lookup(dir_i, token, (int) tokenlen);
837                }
838
839                if (IS_ERR(entry_i)) {
840                        rtems_filesystem_eval_path_error(ctx, PTR_ERR(entry_i));
841                } else if (entry_i != NULL) {
842                        bool terminal = !rtems_filesystem_eval_path_has_path(ctx);
843                        int eval_flags = rtems_filesystem_eval_path_get_flags(ctx);
844                        bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0;
845
846                        rtems_filesystem_eval_path_clear_token(ctx);
847
848                        if (S_ISLNK(entry_i->i_mode) && (follow_sym_link || !terminal)) {
849                                struct jffs2_inode_info *f = JFFS2_INODE_INFO(entry_i);
850                                const char *target = f->target;
851
852                                rtems_filesystem_eval_path_recursive(ctx, target, strlen(target));
853
854                                jffs2_iput(entry_i);
855                        } else {
856                                if (S_ISDIR(entry_i->i_mode) && entry_i->i_parent == NULL) {
857                                        entry_i->i_parent = dir_i;
858                                        ++dir_i->i_count;
859                                }
860
861                                jffs2_iput(dir_i);
862                                rtems_jffs2_set_location(currentloc, entry_i);
863
864                                if (rtems_filesystem_eval_path_has_path(ctx)) {
865                                        status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
866                                }
867                        }
868                } else {
869                        status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
870                }
871        }
872
873        return status;
874}
875
876static const rtems_filesystem_eval_path_generic_config rtems_jffs2_eval_config = {
877        .is_directory = rtems_jffs2_eval_is_directory,
878        .eval_token = rtems_jffs2_eval_token
879};
880
881static void rtems_jffs2_lock(const rtems_filesystem_mount_table_entry_t *mt_entry)
882{
883        rtems_jffs2_fs_info *fs_info = mt_entry->fs_info;
884        struct super_block *sb = &fs_info->sb;
885
886        rtems_jffs2_do_lock(sb);
887}
888
889static void rtems_jffs2_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry)
890{
891        rtems_jffs2_fs_info *fs_info = mt_entry->fs_info;
892        struct super_block *sb = &fs_info->sb;
893
894        rtems_jffs2_do_unlock(sb);
895}
896
897static void rtems_jffs2_eval_path(rtems_filesystem_eval_path_context_t *ctx)
898{
899        rtems_filesystem_eval_path_generic(ctx, NULL, &rtems_jffs2_eval_config);
900}
901
902static int rtems_jffs2_link(
903        const rtems_filesystem_location_info_t *parentloc,
904        const rtems_filesystem_location_info_t *targetloc,
905        const char *name,
906        size_t namelen
907)
908{
909        struct _inode *old_d_inode = rtems_jffs2_get_inode_by_location(targetloc);
910        struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc);
911        int eno;
912
913        eno = -jffs2_link(old_d_inode, dir_i, name, namelen);
914
915        return rtems_jffs2_eno_to_rv_and_errno(eno);
916}
917
918static bool rtems_jffs2_are_nodes_equal(
919        const rtems_filesystem_location_info_t *a,
920        const rtems_filesystem_location_info_t *b
921)
922{
923        struct _inode *inode_a = rtems_jffs2_get_inode_by_location(a);
924        struct _inode *inode_b = rtems_jffs2_get_inode_by_location(b);
925
926        return inode_a->i_ino == inode_b->i_ino;
927}
928
929static int rtems_jffs2_mknod(
930        const rtems_filesystem_location_info_t *parentloc,
931        const char *name,
932        size_t namelen,
933        mode_t mode,
934        dev_t dev
935)
936{
937        struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc);
938        int eno;
939
940        switch (mode & S_IFMT) {
941                case S_IFDIR:
942                        eno = -jffs2_mknod(dir_i, name, namelen, mode, NULL, 0);
943                        break;
944                case S_IFREG:
945                        eno = -jffs2_create(dir_i, name, namelen, mode);
946                        break;
947                default:
948                        eno = EINVAL;
949                        break;
950        }
951
952        return rtems_jffs2_eno_to_rv_and_errno(eno);
953}
954
955static int rtems_jffs2_cache_fd_name(struct _inode *inode, char **name, size_t *namelen)
956{
957        struct super_block *sb = inode->i_sb;
958        char *fd_name = inode->i_fd->name;
959        size_t fd_namelen = strlen(fd_name);
960        int eno = 0;
961
962        if (fd_namelen <= sizeof(sb->s_name_buf)) {
963                *namelen = fd_namelen;
964                *name = memcpy(&sb->s_name_buf[0], fd_name, fd_namelen);
965        } else {
966                eno = ENOMEM;
967        }
968
969        return eno;
970}
971
972static int rtems_jffs2_rmnod(
973        const rtems_filesystem_location_info_t *parentloc,
974        const rtems_filesystem_location_info_t *loc
975)
976{
977        struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc);
978        struct _inode *entry_i = rtems_jffs2_get_inode_by_location(loc);
979        char *name;
980        size_t namelen;
981        int eno = rtems_jffs2_cache_fd_name(entry_i, &name, &namelen);
982
983        if (eno == 0) {
984                switch (dir_i->i_mode & S_IFMT) {
985                        case S_IFDIR:
986                                eno = -jffs2_rmdir(dir_i, entry_i, name, namelen);
987                                break;
988                        case S_IFREG:
989                                eno = -jffs2_unlink(dir_i, entry_i, name, namelen);
990                                break;
991                        default:
992                                eno = EINVAL;
993                                break;
994                }
995        }
996
997        return rtems_jffs2_eno_to_rv_and_errno(eno);
998}
999
1000static int rtems_jffs2_fchmod(
1001        const rtems_filesystem_location_info_t *loc,
1002        mode_t mode
1003)
1004{
1005        struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
1006        struct iattr iattr;
1007        int eno;
1008
1009        iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
1010        iattr.ia_mode = mode;
1011        iattr.ia_ctime = get_seconds();
1012
1013        eno = -jffs2_do_setattr(inode, &iattr);
1014
1015        return rtems_jffs2_eno_to_rv_and_errno(eno);
1016}
1017
1018static int rtems_jffs2_chown(
1019        const rtems_filesystem_location_info_t *loc,
1020        uid_t owner,
1021        gid_t group
1022)
1023{
1024        struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
1025        struct iattr iattr;
1026        int eno;
1027
1028        iattr.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
1029        iattr.ia_uid = owner;
1030        iattr.ia_gid = group;
1031        iattr.ia_ctime = get_seconds();
1032
1033        eno = -jffs2_do_setattr(inode, &iattr);
1034
1035        return rtems_jffs2_eno_to_rv_and_errno(eno);
1036}
1037
1038static int rtems_jffs2_clonenode(rtems_filesystem_location_info_t *loc)
1039{
1040        struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
1041
1042        ++inode->i_count;
1043
1044        return 0;
1045}
1046
1047static void rtems_jffs2_freenode(const rtems_filesystem_location_info_t *loc)
1048{
1049        struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
1050
1051        jffs2_iput(inode);
1052}
1053
1054static void jffs2_remove_delayed_work(struct delayed_work *dwork);
1055
1056static void rtems_jffs2_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry)
1057{
1058        rtems_jffs2_fs_info *fs_info = mt_entry->fs_info;
1059        struct _inode *root_i = mt_entry->mt_fs_root->location.node_access;
1060#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
1061        struct jffs2_sb_info *c = JFFS2_SB_INFO(&fs_info->sb);
1062
1063        /* Remove wbuf delayed work */
1064        jffs2_remove_delayed_work(&c->wbuf_dwork);
1065
1066        /* Flush any pending writes */
1067        if (!sb_rdonly(&fs_info->sb)) {
1068                jffs2_flush_wbuf_gc(c, 0);
1069        }
1070#endif
1071
1072        jffs2_sum_exit(c);
1073
1074        icache_evict(root_i, NULL);
1075        assert(root_i->i_cache_next == NULL);
1076        assert(root_i->i_count == 1);
1077        jffs2_iput(root_i);
1078
1079        rtems_jffs2_free_directory_entries(root_i);
1080        free(root_i);
1081
1082#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
1083        jffs2_nand_flash_cleanup(c);
1084        free(c->mtd);
1085        c->mtd = NULL;
1086#endif
1087
1088        rtems_jffs2_free_fs_info(fs_info, true);
1089}
1090
1091static int rtems_jffs2_rename(
1092        const rtems_filesystem_location_info_t *oldparentloc,
1093        const rtems_filesystem_location_info_t *oldloc,
1094        const rtems_filesystem_location_info_t *newparentloc,
1095        const char *name,
1096        size_t namelen
1097)
1098{
1099        struct _inode *old_dir_i = rtems_jffs2_get_inode_by_location(oldparentloc);
1100        struct _inode *new_dir_i = rtems_jffs2_get_inode_by_location(newparentloc);
1101        struct _inode *d_inode = rtems_jffs2_get_inode_by_location(oldloc);
1102        char *oldname;
1103        size_t oldnamelen;
1104        int eno = rtems_jffs2_cache_fd_name(d_inode, &oldname, &oldnamelen);
1105
1106        if (eno == 0) {
1107                eno = -jffs2_rename(old_dir_i, d_inode, oldname, oldnamelen, new_dir_i, name, namelen);
1108        }
1109
1110        return rtems_jffs2_eno_to_rv_and_errno(eno);
1111}
1112
1113static int rtems_jffs2_statvfs(
1114        const rtems_filesystem_location_info_t *__restrict loc,
1115        struct statvfs *__restrict buf
1116)
1117{
1118        struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
1119        struct super_block *sb = inode->i_sb;
1120        struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1121        unsigned long avail;
1122
1123        spin_lock(&c->erase_completion_lock);
1124        avail = c->dirty_size + c->free_size;
1125        if (avail > c->sector_size * c->resv_blocks_write) {
1126                avail -= c->sector_size * c->resv_blocks_write;
1127        } else {
1128                avail = 0;
1129        }
1130        spin_unlock(&c->erase_completion_lock);
1131
1132        buf->f_bavail = avail >> PAGE_SHIFT;
1133        buf->f_blocks = c->flash_size >> PAGE_SHIFT;
1134        buf->f_bsize = 1UL << PAGE_SHIFT;
1135        buf->f_fsid = JFFS2_SUPER_MAGIC;
1136        buf->f_namemax = JFFS2_MAX_NAME_LEN;
1137
1138        buf->f_bfree = buf->f_bavail;
1139        buf->f_frsize = buf->f_bsize;
1140
1141        return 0;
1142}
1143
1144static int rtems_jffs2_utimens(
1145        const rtems_filesystem_location_info_t *loc,
1146        struct timespec times[2]
1147)
1148{
1149        struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
1150        struct iattr iattr;
1151        int eno;
1152
1153        iattr.ia_valid = ATTR_ATIME | ATTR_MTIME | ATTR_CTIME;
1154        iattr.ia_atime = times[0].tv_sec;
1155        iattr.ia_mtime = times[1].tv_sec;
1156        iattr.ia_ctime = get_seconds();
1157
1158        eno = -jffs2_do_setattr(inode, &iattr);
1159
1160        return rtems_jffs2_eno_to_rv_and_errno(eno);
1161}
1162
1163static int rtems_jffs2_symlink(
1164        const rtems_filesystem_location_info_t *parentloc,
1165        const char *name,
1166        size_t namelen,
1167        const char *target
1168)
1169{
1170        struct _inode *dir_i = rtems_jffs2_get_inode_by_location(parentloc);
1171        int eno;
1172
1173        eno = -jffs2_mknod(dir_i, name, namelen, S_IFLNK | S_IRWXUGO, target, strlen(target));
1174
1175        return rtems_jffs2_eno_to_rv_and_errno(eno);
1176}
1177
1178static ssize_t rtems_jffs2_readlink(
1179        const rtems_filesystem_location_info_t *loc,
1180        char *buf,
1181        size_t bufsize
1182)
1183{
1184        struct _inode *inode = rtems_jffs2_get_inode_by_location(loc);
1185        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1186        const char *target = f->target;
1187        ssize_t i;
1188
1189        for (i = 0; i < (ssize_t) bufsize && target[i] != '\0'; ++i) {
1190                buf[i] = target[i];
1191        }
1192
1193        return i;
1194}
1195
1196static const rtems_filesystem_operations_table rtems_jffs2_ops = {
1197        .lock_h = rtems_jffs2_lock,
1198        .unlock_h = rtems_jffs2_unlock,
1199        .eval_path_h = rtems_jffs2_eval_path,
1200        .link_h = rtems_jffs2_link,
1201        .are_nodes_equal_h = rtems_jffs2_are_nodes_equal,
1202        .mknod_h = rtems_jffs2_mknod,
1203        .rmnod_h = rtems_jffs2_rmnod,
1204        .fchmod_h = rtems_jffs2_fchmod,
1205        .chown_h = rtems_jffs2_chown,
1206        .clonenod_h = rtems_jffs2_clonenode,
1207        .freenod_h = rtems_jffs2_freenode,
1208        .mount_h = rtems_filesystem_default_mount,
1209        .unmount_h = rtems_filesystem_default_unmount,
1210        .fsunmount_me_h = rtems_jffs2_fsunmount,
1211        .utimens_h = rtems_jffs2_utimens,
1212        .symlink_h = rtems_jffs2_symlink,
1213        .readlink_h = rtems_jffs2_readlink,
1214        .rename_h = rtems_jffs2_rename,
1215        .statvfs_h = rtems_jffs2_statvfs
1216};
1217
1218static int calculate_inocache_hashsize(uint32_t flash_size)
1219{
1220        /*
1221         * Pick a inocache hash size based on the size of the medium.
1222         * Count how many megabytes we're dealing with, apply a hashsize twice
1223         * that size, but rounding down to the usual big powers of 2. And keep
1224         * to sensible bounds.
1225         */
1226
1227        int size_mb = flash_size / 1024 / 1024;
1228        int hashsize = (size_mb * 2) & ~0x3f;
1229
1230        if (hashsize < INOCACHE_HASHSIZE_MIN)
1231                return INOCACHE_HASHSIZE_MIN;
1232        if (hashsize > INOCACHE_HASHSIZE_MAX)
1233                return INOCACHE_HASHSIZE_MAX;
1234
1235        return hashsize;
1236}
1237
1238/* Chain for holding delayed work */
1239rtems_chain_control delayed_work_chain;
1240
1241/* Lock for protecting the delayed work chain */
1242struct mutex delayed_work_mutex;
1243
1244void jffs2_queue_delayed_work(struct delayed_work *work, int delay_ms)
1245{
1246        mutex_lock(&delayed_work_mutex);
1247        if (rtems_chain_is_node_off_chain(&work->work.node)) {
1248                work->execution_time = rtems_clock_get_uptime_nanoseconds() + delay_ms*1000000;
1249                rtems_chain_append(&delayed_work_chain, &work->work.node);
1250        }
1251        mutex_unlock(&delayed_work_mutex);
1252}
1253
1254static void jffs2_remove_delayed_work(struct delayed_work *dwork)
1255{
1256        struct delayed_work* work;
1257        rtems_chain_node*    node;
1258
1259        mutex_lock(&delayed_work_mutex);
1260        if (rtems_chain_is_node_off_chain(&dwork->work.node)) {
1261                mutex_unlock(&delayed_work_mutex);
1262                return;
1263        }
1264
1265        node = rtems_chain_first(&delayed_work_chain);
1266        while (!rtems_chain_is_tail(&delayed_work_chain, node)) {
1267                work = (struct delayed_work*) node;
1268                rtems_chain_node* next_node = rtems_chain_next(node);
1269                if (work == dwork) {
1270                        rtems_chain_extract(node);
1271                        mutex_unlock(&delayed_work_mutex);
1272                        return;
1273                }
1274                node = next_node;
1275        }
1276        mutex_unlock(&delayed_work_mutex);
1277}
1278
1279static void process_delayed_work(void)
1280{
1281        struct delayed_work* work;
1282        rtems_chain_node*    node;
1283
1284        mutex_lock(&delayed_work_mutex);
1285
1286        if (rtems_chain_is_empty(&delayed_work_chain)) {
1287                mutex_unlock(&delayed_work_mutex);
1288                return;
1289        }
1290
1291        node = rtems_chain_first(&delayed_work_chain);
1292        while (!rtems_chain_is_tail(&delayed_work_chain, node)) {
1293                work = (struct delayed_work*) node;
1294                rtems_chain_node* next_node = rtems_chain_next(node);
1295                if (rtems_clock_get_uptime_nanoseconds() >= work->execution_time) {
1296                        rtems_chain_extract(node);
1297                        work->callback(&work->work);
1298                }
1299                node = next_node;
1300        }
1301        mutex_unlock(&delayed_work_mutex);
1302}
1303/* Task for processing delayed work */
1304static rtems_task delayed_work_task(
1305  rtems_task_argument unused
1306)
1307{
1308        (void)unused;
1309        while (1) {
1310                process_delayed_work();
1311                sleep(1);
1312        }
1313}
1314
1315rtems_id delayed_work_task_id;
1316
1317static void jffs2_init_delayed_work_task(void)
1318{
1319        /* Initialize chain for delayed work */
1320        rtems_chain_initialize_empty(&delayed_work_chain);
1321
1322        /* Initialize lock for delayed work */
1323        mutex_init(&delayed_work_mutex);
1324
1325        /* Create task for delayed work */
1326        rtems_status_code err = rtems_task_create(
1327                rtems_build_name( 'J', 'F', 'F', 'S' ),
1328                jffs2_config.delayed_write_priority,
1329                RTEMS_MINIMUM_STACK_SIZE,
1330                RTEMS_DEFAULT_MODES,
1331                RTEMS_DEFAULT_ATTRIBUTES,
1332                &delayed_work_task_id
1333        );
1334        if (err != RTEMS_SUCCESSFUL) {
1335                printk("JFFS2 delayed work task processor creation failed\n");
1336        }
1337}
1338
1339RTEMS_SYSINIT_ITEM(
1340  jffs2_init_delayed_work_task,
1341  RTEMS_SYSINIT_LIBIO,
1342  RTEMS_SYSINIT_ORDER_MIDDLE
1343);
1344
1345int rtems_jffs2_initialize(
1346        rtems_filesystem_mount_table_entry_t *mt_entry,
1347        const void *data
1348)
1349{
1350        const rtems_jffs2_mount_data *jffs2_mount_data = data;
1351        rtems_jffs2_flash_control *fc = jffs2_mount_data->flash_control;
1352        int inocache_hashsize = calculate_inocache_hashsize(fc->flash_size);
1353        rtems_jffs2_fs_info *fs_info = calloc(
1354                1,
1355                sizeof(*fs_info) + (size_t) inocache_hashsize * sizeof(fs_info->inode_cache[0])
1356        );
1357        bool do_mount_fs_was_successful = false;
1358        struct super_block *sb;
1359        struct jffs2_sb_info *c;
1360        int err;
1361
1362        if (fs_info != NULL) {
1363                err = 0;
1364        } else {
1365                err = -ENOMEM;
1366        }
1367
1368        sb = &fs_info->sb;
1369        c = JFFS2_SB_INFO(sb);
1370        c->mtd = NULL;
1371
1372        if (err == 0) {
1373                rtems_recursive_mutex_init(&sb->s_mutex, RTEMS_FILESYSTEM_TYPE_JFFS2);
1374        }
1375
1376        /* Start task for delayed work if it hasn't already been started */
1377        if (err == 0) {
1378                err = rtems_task_start( delayed_work_task_id, delayed_work_task, 0 );
1379                /* Task already running from previous mount */
1380                if (err == RTEMS_INCORRECT_STATE) {
1381                        err = 0;
1382                }
1383        }
1384
1385        if (err == 0) {
1386                uint32_t blocks = fc->flash_size / fc->block_size;
1387
1388                if ((fc->block_size * blocks) != fc->flash_size) {
1389                        fc->flash_size = fc->block_size * blocks;
1390                        pr_info("Flash size not aligned to erasesize, reducing to %dKiB\n",
1391                                fc->flash_size / 1024);
1392                }
1393
1394                if (fc->flash_size < 5*fc->block_size) {
1395                        pr_err("Too few erase blocks (%d)\n",
1396                               fc->flash_size / fc->block_size);
1397                        err = -EINVAL;
1398                }
1399        }
1400
1401        if (err == 0) {
1402                sb->s_is_readonly = !mt_entry->writeable;
1403                sb->s_flash_control = fc;
1404                sb->s_compressor_control = jffs2_mount_data->compressor_control;
1405
1406#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
1407                c->mtd = malloc(sizeof(struct mtd_info));
1408                if (!c->mtd) {
1409                        err = -ENOMEM;
1410                }
1411        }
1412
1413        if (err == 0) {
1414                c->mtd->oobavail = jffs2_flash_get_oob_size(c);
1415                c->mtd->oobsize = c->mtd->oobavail;
1416                c->mtd->size = fc->flash_size;
1417                c->mtd->erasesize = fc->block_size;
1418                c->mtd->writesize = fc->write_size;
1419#endif
1420                c->inocache_hashsize = inocache_hashsize;
1421                c->inocache_list = &fs_info->inode_cache[0];
1422                c->sector_size = fc->block_size;
1423                c->flash_size = fc->flash_size;
1424                c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
1425#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
1426                err = jffs2_nand_flash_setup(c);
1427        }
1428
1429        if (err == 0) {
1430#endif
1431                err = jffs2_do_mount_fs(c);
1432        }
1433
1434        if (err == 0) {
1435                do_mount_fs_was_successful = true;
1436
1437                sb->s_root = jffs2_iget(sb, 1);
1438                if (IS_ERR(sb->s_root)) {
1439                        err = PTR_ERR(sb->s_root);
1440                }
1441        }
1442
1443        if (err == 0) {
1444                sb->s_root->i_parent = sb->s_root;
1445
1446                if (!jffs2_is_readonly(c)) {
1447                        jffs2_erase_pending_blocks(c, 0);
1448                }
1449
1450                mt_entry->fs_info = fs_info;
1451                mt_entry->ops = &rtems_jffs2_ops;
1452                mt_entry->mt_fs_root->location.node_access = sb->s_root;
1453                mt_entry->mt_fs_root->location.handlers = &rtems_jffs2_directory_handlers;
1454
1455                return 0;
1456        } else {
1457                if (fs_info != NULL) {
1458                        free(c->mtd);
1459                        c->mtd = NULL;
1460                        rtems_jffs2_free_fs_info(fs_info, do_mount_fs_was_successful);
1461                } else {
1462                        rtems_jffs2_flash_control_destroy(fc);
1463                        rtems_jffs2_compressor_control_destroy(jffs2_mount_data->compressor_control);
1464                }
1465
1466                errno = -err;
1467
1468                return -1;
1469        }
1470}
1471
1472//==========================================================================
1473//
1474// Called by JFFS2
1475// ===============
1476//
1477//
1478//==========================================================================
1479
1480static struct _inode *new_inode(struct super_block *sb)
1481{
1482
1483        // Only called in write.c jffs2_new_inode
1484        // Always adds itself to inode cache
1485
1486        struct _inode *inode;
1487        struct _inode *cached_inode;
1488
1489        inode = malloc(sizeof (struct _inode));
1490        if (inode == NULL)
1491                return 0;
1492
1493        D2(printf
1494           ("malloc new_inode %x ####################################\n",
1495            inode));
1496
1497        memset(inode, 0, sizeof (struct _inode));
1498        inode->i_sb = sb;
1499        inode->i_ino = 1;
1500        inode->i_count = 1;
1501        inode->i_nlink = 1;     // Let JFFS2 manage the link count
1502        inode->i_size = 0;
1503
1504        inode->i_cache_next = NULL;     // Newest inode, about to be cached
1505
1506        // Add to the icache
1507        for (cached_inode = sb->s_root; cached_inode != NULL;
1508             cached_inode = cached_inode->i_cache_next) {
1509                if (cached_inode->i_cache_next == NULL) {
1510                        cached_inode->i_cache_next = inode;     // Current last in cache points to newcomer
1511                        inode->i_cache_prev = cached_inode;     // Newcomer points back to last
1512                        break;
1513                }
1514        }
1515        return inode;
1516}
1517
1518static struct _inode *ilookup(struct super_block *sb, cyg_uint32 ino)
1519{
1520        struct _inode *inode = NULL;
1521
1522        D2(printf("ilookup\n"));
1523        // Check for this inode in the cache
1524        for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) {
1525                if (inode->i_ino == ino) {
1526                        inode->i_count++;
1527                        break;
1528                }
1529        }
1530        return inode;
1531}
1532
1533struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino)
1534{
1535        // Called in super.c jffs2_read_super, dir.c jffs2_lookup,
1536        // and gc.c jffs2_garbage_collect_pass
1537
1538        // Must first check for cached inode
1539        // If this fails let new_inode create one
1540
1541        struct _inode *inode;
1542        int err;
1543
1544        D2(printf("jffs2_iget\n"));
1545
1546        inode = ilookup(sb, ino);
1547        if (inode)
1548                return inode;
1549
1550        // Not cached, so malloc it
1551        inode = new_inode(sb);
1552        if (inode == NULL)
1553                return ERR_PTR(-ENOMEM);
1554
1555        inode->i_ino = ino;
1556
1557        err = jffs2_read_inode(inode);
1558        if (err) {
1559                printk("jffs2_read_inode() failed\n");
1560                inode->i_nlink = 0; // free _this_ bad inode right now
1561                jffs2_iput(inode);
1562                inode = NULL;
1563                return ERR_PTR(err);
1564        }
1565        return inode;
1566}
1567
1568// -------------------------------------------------------------------------
1569// Decrement the reference count on an inode. If this makes the ref count
1570// zero, then this inode can be freed.
1571
1572void jffs2_iput(struct _inode *i)
1573{
1574        // Called in jffs2_find
1575        // (and jffs2_open and jffs2_ops_mkdir?)
1576        // super.c jffs2_read_super,
1577        // and gc.c jffs2_garbage_collect_pass
1578 recurse:
1579        assert(i != NULL);
1580
1581        i->i_count--;
1582
1583        if (i->i_count < 0)
1584                BUG();
1585
1586        if (i->i_count)
1587                return;
1588       
1589        if (!i->i_nlink) {
1590                struct _inode *parent;
1591
1592                // Remove from the icache linked list and free immediately
1593                if (i->i_cache_prev)
1594                        i->i_cache_prev->i_cache_next = i->i_cache_next;
1595                if (i->i_cache_next)
1596                        i->i_cache_next->i_cache_prev = i->i_cache_prev;
1597
1598                parent = i->i_parent;
1599                jffs2_clear_inode(i);
1600                memset(i, 0x5a, sizeof(*i));
1601                free(i);
1602
1603                if (parent && parent != i) {
1604                        i = parent;
1605                        goto recurse;
1606                }
1607
1608        } else {
1609                // Evict some _other_ inode with i_count zero, leaving
1610                // this latest one in the cache for a while
1611                icache_evict(i->i_sb->s_root, i);
1612        }
1613}
1614
1615
1616// -------------------------------------------------------------------------
1617// EOF jffs2.c
1618
1619
1620static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
1621{
1622        memset(f, 0, sizeof(*f));
1623        mutex_init(&f->sem);
1624}
1625
1626static void jffs2_clear_inode (struct _inode *inode)
1627{
1628        /* We can forget about this inode for now - drop all
1629         *  the nodelists associated with it, etc.
1630         */
1631        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1632        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1633
1634        D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
1635
1636        jffs2_do_clear_inode(c, f);
1637}
1638
1639
1640/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
1641   fill in the raw_inode while you're at it. */
1642struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri)
1643{
1644        struct _inode *inode;
1645        struct super_block *sb = dir_i->i_sb;
1646        struct jffs2_sb_info *c;
1647        struct jffs2_inode_info *f;
1648        int ret;
1649
1650        D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
1651
1652        c = JFFS2_SB_INFO(sb);
1653       
1654        inode = new_inode(sb);
1655       
1656        if (!inode)
1657                return ERR_PTR(-ENOMEM);
1658
1659        f = JFFS2_INODE_INFO(inode);
1660        jffs2_init_inode_info(f);
1661
1662        memset(ri, 0, sizeof(*ri));
1663        /* Set OS-specific defaults for new inodes */
1664        ri->uid = cpu_to_je16(geteuid());
1665        ri->gid = cpu_to_je16(getegid());
1666        ri->mode =  cpu_to_jemode(mode);
1667        ret = jffs2_do_new_inode (c, f, mode, ri);
1668        if (ret) {
1669                // forceful evict: f->sem is locked already, and the
1670                // inode is bad.
1671                if (inode->i_cache_prev)
1672                       inode->i_cache_prev->i_cache_next = inode->i_cache_next;
1673                if (inode->i_cache_next)
1674                       inode->i_cache_next->i_cache_prev = inode->i_cache_prev;
1675                mutex_unlock(&(f->sem));
1676                jffs2_clear_inode(inode);
1677                memset(inode, 0x6a, sizeof(*inode));
1678                free(inode);
1679                return ERR_PTR(ret);
1680        }
1681        inode->i_nlink = 1;
1682        inode->i_ino = je32_to_cpu(ri->ino);
1683        inode->i_mode = jemode_to_cpu(ri->mode);
1684        inode->i_gid = je16_to_cpu(ri->gid);
1685        inode->i_uid = je16_to_cpu(ri->uid);
1686        inode->i_atime = inode->i_ctime = inode->i_mtime = get_seconds();
1687        ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime);
1688
1689        inode->i_size = 0;
1690
1691        return inode;
1692}
1693
1694
1695static int jffs2_read_inode (struct _inode *inode)
1696{
1697        struct jffs2_inode_info *f;
1698        struct jffs2_sb_info *c;
1699        struct jffs2_raw_inode latest_node;
1700        int ret;
1701
1702        D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
1703
1704        f = JFFS2_INODE_INFO(inode);
1705        c = JFFS2_SB_INFO(inode->i_sb);
1706
1707        jffs2_init_inode_info(f);
1708        mutex_lock(&f->sem);
1709       
1710        ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
1711
1712        if (ret) {
1713                mutex_unlock(&f->sem);
1714                return ret;
1715        }
1716        inode->i_mode = jemode_to_cpu(latest_node.mode);
1717        inode->i_uid = je16_to_cpu(latest_node.uid);
1718        inode->i_gid = je16_to_cpu(latest_node.gid);
1719        inode->i_size = je32_to_cpu(latest_node.isize);
1720        inode->i_atime = je32_to_cpu(latest_node.atime);
1721        inode->i_mtime = je32_to_cpu(latest_node.mtime);
1722        inode->i_ctime = je32_to_cpu(latest_node.ctime);
1723
1724        inode->i_nlink = f->inocache->pino_nlink;
1725        mutex_unlock(&f->sem);
1726
1727        D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
1728        return 0;
1729}
1730
1731
1732void jffs2_gc_release_inode(struct jffs2_sb_info *c,
1733                                   struct jffs2_inode_info *f)
1734{
1735        jffs2_iput(OFNI_EDONI_2SFFJ(f));
1736}
1737
1738struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
1739                                              int inum, int unlinked)
1740{
1741        struct _inode *inode;
1742        struct jffs2_inode_cache *ic;
1743
1744        if (unlinked) {
1745                /* The inode has zero nlink but its nodes weren't yet marked
1746                   obsolete. This has to be because we're still waiting for
1747                   the final (close() and) iput() to happen.
1748
1749                   There's a possibility that the final iput() could have
1750                   happened while we were contemplating. In order to ensure
1751                   that we don't cause a new read_inode() (which would fail)
1752                   for the inode in question, we use ilookup() in this case
1753                   instead of iget().
1754
1755                   The nlink can't _become_ zero at this point because we're
1756                   holding the alloc_sem, and jffs2_do_unlink() would also
1757                   need that while decrementing nlink on any inode.
1758                */
1759                inode = ilookup(OFNI_BS_2SFFJ(c), inum);
1760                if (!inode) {
1761                        jffs2_dbg(1, "ilookup() failed for ino #%u; inode is probably deleted.\n",
1762                                  inum);
1763
1764                        spin_lock(&c->inocache_lock);
1765                        ic = jffs2_get_ino_cache(c, inum);
1766                        if (!ic) {
1767                                jffs2_dbg(1, "Inode cache for ino #%u is gone\n",
1768                                          inum);
1769                                spin_unlock(&c->inocache_lock);
1770                                return NULL;
1771                        }
1772                        if (ic->state != INO_STATE_CHECKEDABSENT) {
1773                                /* Wait for progress. Don't just loop */
1774                                jffs2_dbg(1, "Waiting for ino #%u in state %d\n",
1775                                          ic->ino, ic->state);
1776                                sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
1777                        } else {
1778                                spin_unlock(&c->inocache_lock);
1779                        }
1780
1781                        return NULL;
1782                }
1783        } else {
1784                /* Inode has links to it still; they're not going away because
1785                   jffs2_do_unlink() would need the alloc_sem and we have it.
1786                   Just iget() it, and if read_inode() is necessary that's OK.
1787                */
1788                inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum);
1789                if (IS_ERR(inode))
1790                        return ERR_CAST(inode);
1791        }
1792
1793        return JFFS2_INODE_INFO(inode);
1794}
Note: See TracBrowser for help on using the repository browser.