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

5
Last change on this file since 6ac6a5c8 was 6ac6a5c8, checked in by Sebastian Huber <sebastian.huber@…>, on 03/27/18 at 11:01:56

jffs2: Do not use command line defines

Update #3375.

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