source: rtems/cpukit/libfs/src/jffs2/src/fs-rtems.c @ 3c96bee

4.115
Last change on this file since 3c96bee was 3c96bee, checked in by Sebastian Huber <sebastian.huber@…>, on 09/12/13 at 13:32:07

JFFS2: Add RTEMS support

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