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

Last change on this file since b17bcb3 was b17bcb3, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 13, 2017 at 5:18:28 AM

JFFS2: Use self-contained recursive mutex

Update #2843.

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