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

4.11
Last change on this file since 672038b was 672038b, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 12, 2013 at 2:46:51 PM

JFFS2: Import from eCos

Import of Linux compatibility layer and JFFS2 file system support from
eCos.

The files are imported from eCos CVS on 2013-09-16.

cvs -d :pserver:anoncvs@ecos.sourceware.org:/cvs/ecos login
cvs -z3 -d :pserver:anoncvs@ecos.sourceware.org:/cvs/ecos co -P ecos

The files

"ecos/packages/compat/linux/current/asm/atomic.h",
"ecos/packages/compat/linux/current/asm/bug.h",
"ecos/packages/compat/linux/current/asm/page.h",
"ecos/packages/compat/linux/current/cyg/crc/crc.h",
"ecos/packages/compat/linux/current/cyg/infra/cyg_type.h",
"ecos/packages/compat/linux/current/linux/compiler.h",
"ecos/packages/compat/linux/current/linux/completion.h",
"ecos/packages/compat/linux/current/linux/config.h",
"ecos/packages/compat/linux/current/linux/crc32.h",
"ecos/packages/compat/linux/current/linux/errno.h",
"ecos/packages/compat/linux/current/linux/fs.h",
"ecos/packages/compat/linux/current/linux/kernel.h",
"ecos/packages/compat/linux/current/linux/list.h",
"ecos/packages/compat/linux/current/linux/mtd/compatmac.h",
"ecos/packages/compat/linux/current/linux/mtd/mtd.h",
"ecos/packages/compat/linux/current/linux/pagemap.h",
"ecos/packages/compat/linux/current/linux/rbtree.h",
"ecos/packages/compat/linux/current/linux/rwsem.h",
"ecos/packages/compat/linux/current/linux/sched.h",
"ecos/packages/compat/linux/current/linux/slab.h",
"ecos/packages/compat/linux/current/linux/spinlock.h",
"ecos/packages/compat/linux/current/linux/stat.h",
"ecos/packages/compat/linux/current/linux/string.h",
"ecos/packages/compat/linux/current/linux/timer.h",
"ecos/packages/compat/linux/current/linux/types.h",
"ecos/packages/compat/linux/current/linux/version.h",
"ecos/packages/compat/linux/current/linux/vmalloc.h",
"ecos/packages/compat/linux/current/linux/wait.h",
"ecos/packages/compat/linux/current/linux/workqueue.h", and
"ecos/packages/compat/linux/current/linux/zlib.h"
"ecos/packages/compat/linux/current/linux/zutil.h"

are copied to "cpukit/libfs/src/jffs2/include".

The file "ecos/packages/services/crc/current/src/crc32.c" is copied to
"cpukit/libfs/src/jffs2/src/compat-crc32.c".

The file "ecos/packages/compat/linux/current/src/rbtree.c" is copied to
"cpukit/libfs/src/jffs2/src/compat-rbtree.c".

The file "ecos/packages/fs/jffs2/current/src/dir-ecos.c" is copied to
"cpukit/libfs/src/jffs2/src/dir-rtems.c".

The file "ecos/packages/fs/jffs2/current/src/flashio.c" is copied to
"cpukit/libfs/src/jffs2/src/flashio.c".

The file "ecos/packages/fs/jffs2/current/src/fs-ecos.c" is copied to
"cpukit/libfs/src/jffs2/src/fs-rtems.c".

The file "ecos/packages/fs/jffs2/current/src/malloc-ecos.c" is copied to
"cpukit/libfs/src/jffs2/src/malloc-rtems.c".

The file "ecos/packages/fs/jffs2/current/src/os-ecos.h" is copied to
"cpukit/libfs/src/jffs2/src/os-rtems.h".

The LICENSE file referenced in some files of this patch set is part of a
previous patch set imported from Linux.

  • Property mode set to 100644
File size: 55.3 KB
Line 
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 2001-2003 Free Software Foundation, Inc.
5 *
6 * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com>
7 * Contributors: David Woodhouse, Nick Garnett, Richard Panton.
8 *
9 * For licensing information, see the file 'LICENCE' in this directory.
10 *
11 * $Id: fs-ecos.c,v 1.44 2005/07/24 15:29:57 dedekind Exp $
12 *
13 */
14
15#include <linux/kernel.h>
16#include "nodelist.h"
17#include <linux/pagemap.h>
18#include <linux/crc32.h>
19#include "compr.h"
20#include <errno.h>
21#include <string.h>
22#include <cyg/io/config_keys.h>
23
24#if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && \
25    (defined (__arm__) || defined (_mips))
26#error This compiler is known to be broken. Please see:
27#error "http://ecos.sourceware.org/ml/ecos-patches/2003-08/msg00006.html"
28#endif
29
30//==========================================================================
31// Forward definitions
32
33// Filesystem operations
34static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte);
35static int jffs2_umount(cyg_mtab_entry * mte);
36static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
37                      int mode, cyg_file * fte);
38#ifdef CYGOPT_FS_JFFS2_WRITE
39static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir,
40                            const char *name);
41static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);
42static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);
43static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
44                            const char *name1, cyg_dir dir2, const char *name2);
45static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1,
46                          cyg_dir dir2, const char *name2, int type);
47#endif
48static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
49                         cyg_file * fte);
50static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
51                       cyg_dir * dir_out);
52static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
53                      struct stat *buf);
54static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
55                         int key, void *buf, int len);
56static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
57                         int key, void *buf, int len);
58
59// File operations
60static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
61#ifdef CYGOPT_FS_JFFS2_WRITE
62static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
63#endif
64static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);
65static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
66                          CYG_ADDRWORD data);
67static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode);
68static int jffs2_fo_close(struct CYG_FILE_TAG *fp);
69static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf);
70static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
71                            int len);
72static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
73                            int len);
74
75// Directory operations
76static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
77static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);
78
79
80static int jffs2_read_inode (struct _inode *inode);
81static void jffs2_clear_inode (struct _inode *inode);
82static int jffs2_truncate_file (struct _inode *inode);
83
84//==========================================================================
85// Filesystem table entries
86
87// -------------------------------------------------------------------------
88// Fstab entry.
89// This defines the entry in the filesystem table.
90// For simplicity we use _FILESYSTEM synchronization for all accesses since
91// we should never block in any filesystem operations.
92
93#ifdef CYGOPT_FS_JFFS2_WRITE
94FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
95            CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM,
96            jffs2_mount,
97            jffs2_umount,
98            jffs2_open,
99            jffs2_ops_unlink,
100            jffs2_ops_mkdir,
101            jffs2_ops_rmdir,
102            jffs2_ops_rename,
103            jffs2_ops_link,
104            jffs2_opendir,
105            jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
106#else
107FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
108            CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM,
109            jffs2_mount,
110            jffs2_umount,
111            jffs2_open,
112            (cyg_fsop_unlink *)cyg_fileio_erofs,
113            (cyg_fsop_mkdir *)cyg_fileio_erofs,
114            (cyg_fsop_rmdir *)cyg_fileio_erofs,
115            (cyg_fsop_rename *)cyg_fileio_erofs,
116            (cyg_fsop_link *)cyg_fileio_erofs,
117            jffs2_opendir,
118            jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
119#endif
120
121// -------------------------------------------------------------------------
122// File operations.
123// This set of file operations are used for normal open files.
124
125static cyg_fileops jffs2_fileops = {
126        jffs2_fo_read,
127#ifdef CYGOPT_FS_JFFS2_WRITE
128        jffs2_fo_write,
129#else
130        (cyg_fileop_write *) cyg_fileio_erofs,
131#endif
132        jffs2_fo_lseek,
133        jffs2_fo_ioctl,
134        cyg_fileio_seltrue,
135        jffs2_fo_fsync,
136        jffs2_fo_close,
137        jffs2_fo_fstat,
138        jffs2_fo_getinfo,
139        jffs2_fo_setinfo
140};
141
142// -------------------------------------------------------------------------
143// Directory file operations.
144// This set of operations are used for open directories. Most entries
145// point to error-returning stub functions. Only the read, lseek and
146// close entries are functional.
147
148static cyg_fileops jffs2_dirops = {
149        jffs2_fo_dirread,
150        (cyg_fileop_write *) cyg_fileio_enosys,
151        jffs2_fo_dirlseek,
152        (cyg_fileop_ioctl *) cyg_fileio_enosys,
153        cyg_fileio_seltrue,
154        (cyg_fileop_fsync *) cyg_fileio_enosys,
155        jffs2_fo_close,
156        (cyg_fileop_fstat *) cyg_fileio_enosys,
157        (cyg_fileop_getinfo *) cyg_fileio_enosys,
158        (cyg_fileop_setinfo *) cyg_fileio_enosys
159};
160
161//==========================================================================
162// STATIC VARIABLES !!!
163
164static unsigned char gc_buffer[PAGE_CACHE_SIZE];        //avoids malloc when user may be under memory pressure
165static unsigned char n_fs_mounted = 0;  // a counter to track the number of jffs2 instances mounted
166
167//==========================================================================
168// Directory operations
169
170struct jffs2_dirsearch {
171        struct _inode *dir;         // directory to search
172        const unsigned char *path;  // path to follow
173        struct _inode *node;        // Node found
174        const unsigned char *name;  // last name fragment used
175        int namelen;                // name fragment length
176        cyg_bool last;              // last name in path?
177};
178
179typedef struct jffs2_dirsearch jffs2_dirsearch;
180
181//==========================================================================
182// Ref count and nlink management
183
184
185// FIXME: This seems like real cruft. Wouldn't it be better just to do the
186// right thing?
187static void icache_evict(struct _inode *root_i, struct _inode *i)
188{
189        struct _inode *this = root_i, *next;
190
191 restart:
192        D2(printf("icache_evict\n"));
193        // If this is an absolute search path from the root,
194        // remove all cached inodes with i_count of zero (these are only
195        // held where needed for dotdot filepaths)
196        while (this) {
197                next = this->i_cache_next;
198                if (this != i && this->i_count == 0) {
199                        struct _inode *parent = this->i_parent;
200                        if (this->i_cache_next)
201                                this->i_cache_next->i_cache_prev = this->i_cache_prev;
202                        if (this->i_cache_prev)
203                                this->i_cache_prev->i_cache_next = this->i_cache_next;
204                        jffs2_clear_inode(this);
205                        memset(this, 0x5a, sizeof(*this));
206                        free(this);
207                        if (parent && parent != this) {
208                                parent->i_count--;
209                                this = root_i;
210                                goto restart;
211                        }
212                }
213                this = next;
214        }
215}
216
217//==========================================================================
218// Directory search
219
220// -------------------------------------------------------------------------
221// init_dirsearch()
222// Initialize a dirsearch object to start a search
223
224static void init_dirsearch(jffs2_dirsearch * ds,
225                           struct _inode *dir, const unsigned char *name)
226{
227        D2(printf("init_dirsearch name = %s\n", name));
228        D2(printf("init_dirsearch dir = %x\n", dir));
229
230        dir->i_count++;
231        ds->dir = dir;
232        ds->path = name;
233        ds->node = dir;
234        ds->name = name;
235        ds->namelen = 0;
236        ds->last = false;
237}
238
239// -------------------------------------------------------------------------
240// find_entry()
241// Search a single directory for the next name in a path and update the
242// dirsearch object appropriately.
243
244static int find_entry(jffs2_dirsearch * ds)
245{
246        struct _inode *dir = ds->dir;
247        const unsigned char *name = ds->path;
248        const unsigned char *n = name;
249        char namelen = 0;
250        struct _inode *d;
251
252        D2(printf("find_entry\n"));
253
254        // check that we really have a directory
255        if (!S_ISDIR(dir->i_mode))
256                return ENOTDIR;
257
258        // Isolate the next element of the path name.
259        while (*n != '\0' && *n != '/')
260                n++, namelen++;
261
262        // Check if this is the last path element.
263        while( *n == '/') n++;
264        if (*n == '\0')
265                ds->last = true;
266
267        // update name in dirsearch object
268        ds->name = name;
269        ds->namelen = namelen;
270
271        if (name[0] == '.')
272                switch (namelen) {
273                default:
274                        break;
275                case 2:
276                        // Dot followed by not Dot, treat as any other name
277                        if (name[1] != '.')
278                                break;
279                        // Dot Dot
280                        // Move back up the search path
281                        D2(printf("find_entry found ..\n"));
282                        ds->dir = ds->node;
283                        ds->node = ds->dir->i_parent;
284                        ds->node->i_count++;
285                        return ENOERR;
286                case 1:
287                        // Dot is consumed
288                        D2(printf("find_entry found .\n"));
289                        ds->node = ds->dir;
290                        ds->dir->i_count++;
291                        return ENOERR;
292                }
293
294        // Here we have the name and its length set up.
295        // Search the directory for a matching entry
296
297        D2(printf("find_entry for name = %s\n", ds->path));
298        d = jffs2_lookup(dir, name, namelen);
299        D2(printf("find_entry got dir = %x\n", d));
300
301        if (d == NULL)
302                return ENOENT;
303        if (IS_ERR(d))
304                return -PTR_ERR(d);
305
306        // If it's a new directory inode, increase refcount on its parent
307        if (S_ISDIR(d->i_mode) && !d->i_parent) {
308                d->i_parent = dir;
309                dir->i_count++;
310        }
311
312        // pass back the node we have found
313        ds->node = d;
314        return ENOERR;
315
316}
317
318// -------------------------------------------------------------------------
319// jffs2_find()
320// Main interface to directory search code. This is used in all file
321// level operations to locate the object named by the pathname.
322
323// Returns with use count incremented on both the sought object and
324// the directory it was found in
325static int jffs2_find(jffs2_dirsearch * d)
326{
327        int err;
328
329        D2(printf("jffs2_find for path =%s\n", d->path));
330
331        // Short circuit empty paths
332        if (*(d->path) == '\0') {
333                d->node->i_count++;
334                return ENOERR;
335        }
336
337        // iterate down directory tree until we find the object
338        // we want.
339        for (;;) {
340                err = find_entry(d);
341
342                if (err != ENOERR)
343                        return err;
344
345                if (d->last)
346                        return ENOERR;
347
348                /* We're done with it, although it we found a subdir that
349                   will have caused the refcount to have been increased */
350                jffs2_iput(d->dir);
351
352                // Update dirsearch object to search next directory.
353                d->dir = d->node;
354                d->path += d->namelen;
355                while (*(d->path) == '/')
356                        d->path++;      // skip dirname separators
357        }
358}
359
360//==========================================================================
361// Pathconf support
362// This function provides support for pathconf() and fpathconf().
363
364static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info)
365{
366        int err = ENOERR;
367        D2(printf("jffs2_pathconf\n"));
368
369        switch (info->name) {
370        case _PC_LINK_MAX:
371                info->value = LINK_MAX;
372                break;
373
374        case _PC_MAX_CANON:
375                info->value = -1;       // not supported
376                err = EINVAL;
377                break;
378
379        case _PC_MAX_INPUT:
380                info->value = -1;       // not supported
381                err = EINVAL;
382                break;
383
384        case _PC_NAME_MAX:
385                info->value = NAME_MAX;
386                break;
387
388        case _PC_PATH_MAX:
389                info->value = PATH_MAX;
390                break;
391
392        case _PC_PIPE_BUF:
393                info->value = -1;       // not supported
394                err = EINVAL;
395                break;
396
397        case _PC_ASYNC_IO:
398                info->value = -1;       // not supported
399                err = EINVAL;
400                break;
401
402        case _PC_CHOWN_RESTRICTED:
403                info->value = -1;       // not supported
404                err = EINVAL;
405                break;
406
407        case _PC_NO_TRUNC:
408                info->value = 0;
409                break;
410
411        case _PC_PRIO_IO:
412                info->value = 0;
413                break;
414
415        case _PC_SYNC_IO:
416                info->value = 0;
417                break;
418
419        case _PC_VDISABLE:
420                info->value = -1;       // not supported
421                err = EINVAL;
422                break;
423
424        default:
425                err = EINVAL;
426                break;
427        }
428
429        return err;
430}
431
432//==========================================================================
433// Filesystem operations
434
435// -------------------------------------------------------------------------
436// jffs2_mount()
437// Process a mount request. This mainly creates a root for the
438// filesystem.
439static int jffs2_read_super(struct super_block *sb)
440{
441        struct jffs2_sb_info *c;
442        Cyg_ErrNo err;
443        cyg_uint32 len;
444        cyg_io_flash_getconfig_devsize_t ds;
445        cyg_io_flash_getconfig_blocksize_t bs;
446
447        D1(printk(KERN_DEBUG "jffs2: read_super\n"));
448
449        c = JFFS2_SB_INFO(sb);
450
451        len = sizeof (ds);
452        err = cyg_io_get_config(sb->s_dev,
453                                CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len);
454        if (err != ENOERR) {
455                D1(printf
456                   ("jffs2: cyg_io_get_config failed to get dev size: %d\n",
457                    err));
458                return err;
459        }
460        len = sizeof (bs);
461        bs.offset = 0;
462        err = cyg_io_get_config(sb->s_dev,
463                                CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len);
464        if (err != ENOERR) {
465                D1(printf
466                   ("jffs2: cyg_io_get_config failed to get block size: %d\n",
467                    err));
468                return err;
469        }
470
471        c->sector_size = bs.block_size;
472        c->flash_size = ds.dev_size;
473        c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
474
475        err = jffs2_do_mount_fs(c);
476        if (err)
477                return -err;
478
479        D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
480        sb->s_root = jffs2_iget(sb, 1);
481        if (IS_ERR(sb->s_root)) {
482                D1(printk(KERN_WARNING "get root inode failed\n"));
483                err = PTR_ERR(sb->s_root);
484                sb->s_root = NULL;
485                goto out_nodes;
486        }
487
488        return 0;
489
490      out_nodes:
491        jffs2_free_ino_caches(c);
492        jffs2_free_raw_node_refs(c);
493        free(c->blocks);
494
495        return err;
496}
497
498static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte)
499{
500        extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end;
501        struct super_block *jffs2_sb = NULL;
502        struct jffs2_sb_info *c;
503        cyg_mtab_entry *m;
504        cyg_io_handle_t t;
505        Cyg_ErrNo err;
506
507        D2(printf("jffs2_mount\n"));
508
509        err = cyg_io_lookup(mte->devname, &t);
510        if (err != ENOERR)
511                return -err;
512
513        // Iterate through the mount table to see if we're mounted
514        // FIXME: this should be done better - perhaps if the superblock
515        // can be stored as an inode in the icache.
516        for (m = &cyg_mtab[0]; m != &cyg_mtab_end; m++) {
517                // stop if there are more than the configured maximum
518                if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) {
519                        m = &cyg_mtab_end;
520                        break;
521                }
522                if (m->valid && strcmp(m->fsname, "jffs2") == 0 &&
523                    strcmp(m->devname, mte->devname) == 0) {
524                        jffs2_sb = (struct super_block *) m->data;
525                }
526        }
527
528        if (jffs2_sb == NULL) {
529                jffs2_sb = malloc(sizeof (struct super_block));
530
531                if (jffs2_sb == NULL)
532                        return ENOMEM;
533
534                c = JFFS2_SB_INFO(jffs2_sb);
535                memset(jffs2_sb, 0, sizeof (struct super_block));
536                jffs2_sb->s_dev = t;
537
538                c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
539                if (!c->inocache_list) {
540                        free(jffs2_sb);
541                        return ENOMEM;
542                }
543                memset(c->inocache_list, 0, sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
544                if (n_fs_mounted++ == 0) {
545                        jffs2_create_slab_caches(); // No error check, cannot fail
546                        jffs2_compressors_init(); 
547                }
548
549                err = jffs2_read_super(jffs2_sb);
550
551                if (err) {
552                        if (--n_fs_mounted == 0) {
553                                jffs2_destroy_slab_caches();
554                                jffs2_compressors_exit();
555                        }
556                       
557                        free(jffs2_sb);
558                        free(c->inocache_list);
559                        return err;
560                }
561
562                jffs2_sb->s_root->i_parent = jffs2_sb->s_root;  // points to itself, no dotdot paths above mountpoint
563                jffs2_sb->s_root->i_cache_prev = NULL;  // root inode, so always null
564                jffs2_sb->s_root->i_cache_next = NULL;
565                jffs2_sb->s_root->i_count = 1;  // Ensures the root inode is always in ram until umount
566
567                D2(printf("jffs2_mount erasing pending blocks\n"));
568#ifdef CYGOPT_FS_JFFS2_WRITE
569                if (!jffs2_is_readonly(c))
570                    jffs2_erase_pending_blocks(c,0);
571#endif
572#ifdef CYGOPT_FS_JFFS2_GCTHREAD
573                jffs2_start_garbage_collect_thread(c);
574#endif
575        }
576        mte->data = (CYG_ADDRWORD) jffs2_sb;
577
578        jffs2_sb->s_mount_count++;
579        mte->root = (cyg_dir) jffs2_sb->s_root;
580        D2(printf("jffs2_mounted superblock at %x\n", mte->root));
581
582        return ENOERR;
583}
584
585extern cyg_dir cyg_cdir_dir;
586extern cyg_mtab_entry *cyg_cdir_mtab_entry;
587
588// -------------------------------------------------------------------------
589// jffs2_umount()
590// Unmount the filesystem.
591
592static int jffs2_umount(cyg_mtab_entry * mte)
593{
594        struct _inode *root = (struct _inode *) mte->root;
595        struct super_block *jffs2_sb = root->i_sb;
596        struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb);
597        struct jffs2_full_dirent *fd, *next;
598
599        D2(printf("jffs2_umount\n"));
600
601        // Only really umount if this is the only mount
602        if (jffs2_sb->s_mount_count == 1) {
603                icache_evict(root, NULL);
604                if (root->i_cache_next != NULL) {
605                        struct _inode *inode = root;
606                        printf("Refuse to unmount.\n");
607                        while (inode) {
608                                printf("Ino #%u has use count %d\n",
609                                       inode->i_ino, inode->i_count);
610                                inode = inode->i_cache_next;
611                        }
612                        // root icount was set to 1 on mount
613                        return EBUSY;
614                }
615                if (root->i_count == 2 &&
616                    cyg_cdir_mtab_entry == mte &&
617                    cyg_cdir_dir == (cyg_dir)root &&
618                    !strcmp(mte->name, "/")) {
619                        /* If we were mounted on root, there's no
620                           way for the cwd to change out and free
621                           the file system for unmounting. So we hack
622                           it -- if cwd is '/' we unset it. Perhaps
623                           we should allow chdir(NULL) to unset
624                           cyg_cdir_dir? */
625                        cyg_cdir_dir = CYG_DIR_NULL;
626                        jffs2_iput(root);
627                }
628                /* Argh. The fileio code sets this; never clears it */
629                if (cyg_cdir_mtab_entry == mte)
630                        cyg_cdir_mtab_entry = NULL;
631
632                if (root->i_count != 1) {
633                        printf("Ino #1 has use count %d\n",
634                               root->i_count);
635                        return EBUSY;
636                }
637#ifdef CYGOPT_FS_JFFS2_GCTHREAD
638                jffs2_stop_garbage_collect_thread(c);
639#endif
640                jffs2_iput(root);       // Time to free the root inode
641
642                // free directory entries
643                for (fd = root->jffs2_i.dents; fd; fd = next) {
644                  next=fd->next;
645                  jffs2_free_full_dirent(fd);
646                }
647
648                free(root);
649                //Clear root inode
650                //root_i = NULL;
651
652                // Clean up the super block and root inode
653                jffs2_free_ino_caches(c);
654                jffs2_free_raw_node_refs(c);
655                free(c->blocks);
656                free(c->inocache_list);
657                free(jffs2_sb);
658                // Clear superblock & root pointer
659                mte->root = CYG_DIR_NULL;
660                mte->data = 0;
661                mte->fs->data = 0;      // fstab entry, visible to all mounts. No current mount
662                // That's all folks.
663                D2(printf("jffs2_umount No current mounts\n"));
664        } else {
665                jffs2_sb->s_mount_count--;
666        }
667        if (--n_fs_mounted == 0) {
668                jffs2_destroy_slab_caches();       
669                jffs2_compressors_exit();
670        }
671        return ENOERR;
672}
673
674// -------------------------------------------------------------------------
675// jffs2_open()
676// Open a file for reading or writing.
677
678static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
679                      int mode, cyg_file * file)
680{
681
682        jffs2_dirsearch ds;
683        struct _inode *node = NULL;
684        int err;
685
686        D2(printf("jffs2_open\n"));
687
688        /* If no chdir has been called and we were the first file system
689           mounted, we get called with dir == NULL. Deal with it */
690        if (!dir)
691                dir = mte->root;
692
693#ifndef CYGOPT_FS_JFFS2_WRITE
694        if (mode & (O_CREAT|O_TRUNC|O_WRONLY))
695                return EROFS;
696#endif
697        init_dirsearch(&ds, (struct _inode *) dir, 
698                       (const unsigned char *) name);
699
700        err = jffs2_find(&ds);
701
702        if (err == ENOENT) {
703#ifdef CYGOPT_FS_JFFS2_WRITE
704                if (ds.last && (mode & O_CREAT)) {
705
706                        // No node there, if the O_CREAT bit is set then we must
707                        // create a new one. The dir and name fields of the dirsearch
708                        // object will have been updated so we know where to put it.
709
710                        err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node);
711
712                        if (err != 0) {
713                                //Possible orphaned inode on the flash - but will be gc'd
714                                jffs2_iput(ds.dir);
715                                return -err;
716                        }
717
718                        err = ENOERR;
719                }
720#endif
721        } else if (err == ENOERR) {
722                // The node exists. If the O_CREAT and O_EXCL bits are set, we
723                // must fail the open.
724
725                if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
726                        jffs2_iput(ds.node);
727                        err = EEXIST;
728                } else
729                        node = ds.node;
730        }
731
732        // Finished with the directory now
733        jffs2_iput(ds.dir);
734
735        if (err != ENOERR)
736                return err;
737
738        // Check that we actually have a file here
739        if (S_ISDIR(node->i_mode)) {
740                jffs2_iput(node);
741                return EISDIR;
742        }
743
744             // If the O_TRUNC bit is set we must clean out the file data.
745        if (mode & O_TRUNC) {
746#ifdef CYGOPT_FS_JFFS2_WRITE
747             err = jffs2_truncate_file(node);
748             if (err) {
749                  jffs2_iput(node);
750                  return err;
751             }
752#else
753             jffs2_iput(node);
754             return EROFS;
755#endif
756        }
757       
758        // Initialise the file object
759        file->f_flag |= mode & CYG_FILE_MODE_MASK;
760        file->f_type = CYG_FILE_TYPE_FILE;
761        file->f_ops = &jffs2_fileops;
762        file->f_offset = (mode & O_APPEND) ? node->i_size : 0;
763        file->f_data = (CYG_ADDRWORD) node;
764        file->f_xops = 0;
765
766        return ENOERR;
767}
768
769#ifdef CYGOPT_FS_JFFS2_WRITE
770// -------------------------------------------------------------------------
771// jffs2_ops_unlink()
772// Remove a file link from its directory.
773
774static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
775{
776        jffs2_dirsearch ds;
777        int err;
778
779        D2(printf("jffs2_ops_unlink\n"));
780
781        init_dirsearch(&ds, (struct _inode *) dir, 
782                       (const unsigned char *)name);
783
784        err = jffs2_find(&ds);
785
786        if (err != ENOERR) {
787                jffs2_iput(ds.dir);
788                return err;
789        }
790
791        // Cannot unlink directories, use rmdir() instead
792        if (S_ISDIR(ds.node->i_mode)) {
793                jffs2_iput(ds.dir);
794                jffs2_iput(ds.node);
795                return EPERM;
796        }
797
798        // Delete it from its directory
799
800        err = jffs2_unlink(ds.dir, ds.node, ds.name);
801        jffs2_iput(ds.dir);
802        jffs2_iput(ds.node);
803
804        return -err;
805}
806
807// -------------------------------------------------------------------------
808// jffs2_ops_mkdir()
809// Create a new directory.
810
811static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
812{
813        jffs2_dirsearch ds;
814        int err;
815
816        D2(printf("jffs2_ops_mkdir\n"));
817
818        init_dirsearch(&ds, (struct _inode *) dir, 
819                       (const unsigned char *)name);
820
821        err = jffs2_find(&ds);
822
823        if (err == ENOENT) {
824                if (ds.last) {
825                        // The entry does not exist, and it is the last element in
826                        // the pathname, so we can create it here.
827
828                        err = -jffs2_mkdir(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR);
829                }
830                // If this was not the last element, then an intermediate
831                // directory does not exist.
832        } else {
833                // If there we no error, something already exists with that
834                // name, so we cannot create another one.
835               if (err == ENOERR) {
836                        jffs2_iput(ds.node);
837                        err = EEXIST;
838               }
839        }
840        jffs2_iput(ds.dir);
841        return err;
842}
843
844// -------------------------------------------------------------------------
845// jffs2_ops_rmdir()
846// Remove a directory.
847
848static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
849{
850        jffs2_dirsearch ds;
851        int err;
852
853        D2(printf("jffs2_ops_rmdir\n"));
854
855        init_dirsearch(&ds, (struct _inode *) dir, 
856                       (const unsigned char *)name);
857
858        err = jffs2_find(&ds);
859
860        if (err != ENOERR) {
861                jffs2_iput(ds.dir);
862                return err;
863        }
864
865        // Check that this is actually a directory.
866        if (!S_ISDIR(ds.node->i_mode)) {
867                jffs2_iput(ds.dir);
868                jffs2_iput(ds.node);
869                return EPERM;
870        }
871
872        err = jffs2_rmdir(ds.dir, ds.node, ds.name);
873
874        jffs2_iput(ds.dir);
875        jffs2_iput(ds.node);
876        return -err;
877}
878
879// -------------------------------------------------------------------------
880// jffs2_ops_rename()
881// Rename a file/dir.
882
883static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
884                            const char *name1, cyg_dir dir2, const char *name2)
885{
886        jffs2_dirsearch ds1, ds2;
887        int err;
888
889        D2(printf("jffs2_ops_rename\n"));
890
891        init_dirsearch(&ds1, (struct _inode *) dir1, 
892                       (const unsigned char *)name1);
893
894        err = jffs2_find(&ds1);
895
896        if (err != ENOERR) {
897                jffs2_iput(ds1.dir);
898                return err;
899        }
900
901        init_dirsearch(&ds2, (struct _inode *) dir2, 
902                       (const unsigned char *)name2);
903
904        err = jffs2_find(&ds2);
905
906        // Allow through renames to non-existent objects.
907        if (ds2.last && err == ENOENT) {
908                ds2.node = NULL;
909                err = ENOERR;
910        }
911
912        if (err != ENOERR) {
913                jffs2_iput(ds1.dir);
914                jffs2_iput(ds1.node);
915                jffs2_iput(ds2.dir);
916                return err;
917        }
918
919        // Null rename, just return
920        if (ds1.node == ds2.node) {
921                err = ENOERR;
922                goto out;
923        }
924
925        // First deal with any entry that is at the destination
926        if (ds2.node) {
927                // Check that we are renaming like-for-like
928
929                if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) {
930                        err = EISDIR;
931                        goto out;
932                }
933
934                if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) {
935                        err = ENOTDIR;
936                        goto out;
937                }
938
939                // Now delete the destination directory entry
940                /* Er, what happened to atomicity of rename()? */
941                err = -jffs2_unlink(ds2.dir, ds2.node, ds2.name);
942
943                if (err != 0)
944                        goto out;
945
946        }
947        // Now we know that there is no clashing node at the destination,
948        // make a new direntry at the destination and delete the old entry
949        // at the source.
950
951        err = -jffs2_rename(ds1.dir, ds1.node, ds1.name, ds2.dir, ds2.name);
952
953        // Update directory times
954        if (!err)
955                ds1.dir->i_ctime =
956                    ds1.dir->i_mtime =
957                    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
958 out:
959        jffs2_iput(ds1.dir);
960        if (S_ISDIR(ds1.node->i_mode)) {
961                /* Renamed a directory to elsewhere... so fix up its
962                   i_parent pointer and the i_counts of its old and
963                   new parents. */
964                jffs2_iput(ds1.node->i_parent);
965                ds1.node->i_parent = ds2.dir;
966                /* We effectively increase its use count by not... */
967        } else {
968                jffs2_iput(ds2.dir); /* ... doing this */
969        }
970        jffs2_iput(ds1.node);
971        if (ds2.node)
972                jffs2_iput(ds2.node);
973 
974        return err;
975}
976
977// -------------------------------------------------------------------------
978// jffs2_ops_link()
979// Make a new directory entry for a file.
980
981static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1,
982                          cyg_dir dir2, const char *name2, int type)
983{
984        jffs2_dirsearch ds1, ds2;
985        int err;
986
987        D2(printf("jffs2_ops_link\n"));
988
989        // Only do hard links for now in this filesystem
990        if (type != CYG_FSLINK_HARD)
991                return EINVAL;
992
993        init_dirsearch(&ds1, (struct _inode *) dir1, 
994                       (const unsigned char *) name1);
995
996        err = jffs2_find(&ds1);
997
998        if (err != ENOERR) {
999                jffs2_iput(ds1.dir);
1000                return err;
1001        }
1002
1003        init_dirsearch(&ds2, (struct _inode *) dir2, 
1004                       (const unsigned char *) name2);
1005
1006        err = jffs2_find(&ds2);
1007
1008        // Don't allow links to existing objects
1009        if (err == ENOERR) {
1010                jffs2_iput(ds1.dir);
1011                jffs2_iput(ds1.node);
1012                jffs2_iput(ds2.dir);
1013                jffs2_iput(ds2.node);
1014                return EEXIST;
1015        }
1016
1017        // Allow through links to non-existing terminal objects
1018        if (ds2.last && err == ENOENT) {
1019                ds2.node = NULL;
1020                err = ENOERR;
1021        }
1022
1023        if (err != ENOERR) {
1024                jffs2_iput(ds1.dir);
1025                jffs2_iput(ds1.node);
1026                jffs2_iput(ds2.dir);
1027                return err;
1028        }
1029
1030        // Now we know that there is no existing node at the destination,
1031        // make a new direntry at the destination.
1032
1033        err = jffs2_link(ds1.node, ds2.dir, ds2.name);
1034
1035        if (err == 0)
1036                ds1.node->i_ctime =
1037                    ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
1038
1039        jffs2_iput(ds1.dir);
1040        jffs2_iput(ds1.node);
1041        jffs2_iput(ds2.dir);
1042
1043        return -err;
1044}
1045#endif /* CYGOPT_FS_JFFS2_WRITE */
1046// -------------------------------------------------------------------------
1047// jffs2_opendir()
1048// Open a directory for reading.
1049
1050static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
1051                         cyg_file * file)
1052{
1053        jffs2_dirsearch ds;
1054        int err;
1055
1056        D2(printf("jffs2_opendir\n"));
1057
1058        init_dirsearch(&ds, (struct _inode *) dir, 
1059                       (const unsigned char *) name);
1060
1061        err = jffs2_find(&ds);
1062
1063        jffs2_iput(ds.dir);
1064
1065        if (err != ENOERR)
1066                return err;
1067
1068        // check it is really a directory.
1069        if (!S_ISDIR(ds.node->i_mode)) {
1070                jffs2_iput(ds.node);
1071                return ENOTDIR;
1072        }
1073
1074        // Initialize the file object, setting the f_ops field to a
1075        // special set of file ops.
1076
1077        file->f_type = CYG_FILE_TYPE_FILE;
1078        file->f_ops = &jffs2_dirops;
1079        file->f_offset = 0;
1080        file->f_data = (CYG_ADDRWORD) ds.node;
1081        file->f_xops = 0;
1082
1083        return ENOERR;
1084
1085}
1086
1087// -------------------------------------------------------------------------
1088// jffs2_chdir()
1089// Change directory support.
1090
1091static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
1092                       cyg_dir * dir_out)
1093{
1094        D2(printf("jffs2_chdir\n"));
1095
1096        if (dir_out != NULL) {
1097                // This is a request to get a new directory pointer in
1098                // *dir_out.
1099
1100                jffs2_dirsearch ds;
1101                int err;
1102
1103                init_dirsearch(&ds, (struct _inode *) dir, 
1104                               (const unsigned char *) name);
1105
1106                err = jffs2_find(&ds);
1107                jffs2_iput(ds.dir);
1108
1109                if (err != ENOERR)
1110                        return err;
1111
1112                // check it is a directory
1113                if (!S_ISDIR(ds.node->i_mode)) {
1114                        jffs2_iput(ds.node);
1115                        return ENOTDIR;
1116                }
1117               
1118                // Pass it out
1119                *dir_out = (cyg_dir) ds.node;
1120        } else {
1121                // If no output dir is required, this means that the mte and
1122                // dir arguments are the current cdir setting and we should
1123                // forget this fact.
1124
1125                struct _inode *node = (struct _inode *) dir;
1126
1127                // Just decrement directory reference count.
1128                jffs2_iput(node);
1129        }
1130
1131        return ENOERR;
1132}
1133
1134// -------------------------------------------------------------------------
1135// jffs2_stat()
1136// Get struct stat info for named object.
1137
1138static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
1139                      struct stat *buf)
1140{
1141        jffs2_dirsearch ds;
1142        int err;
1143
1144        D2(printf("jffs2_stat\n"));
1145
1146        init_dirsearch(&ds, (struct _inode *) dir, 
1147                       (const unsigned char *) name);
1148
1149        err = jffs2_find(&ds);
1150        jffs2_iput(ds.dir);
1151
1152        if (err != ENOERR)
1153                return err;
1154
1155        // Fill in the status
1156        buf->st_mode = ds.node->i_mode;
1157        buf->st_ino = ds.node->i_ino;
1158        buf->st_dev = 0;
1159        buf->st_nlink = ds.node->i_nlink;
1160        buf->st_uid = ds.node->i_uid;
1161        buf->st_gid = ds.node->i_gid;
1162        buf->st_size = ds.node->i_size;
1163        buf->st_atime = ds.node->i_atime;
1164        buf->st_mtime = ds.node->i_mtime;
1165        buf->st_ctime = ds.node->i_ctime;
1166
1167        jffs2_iput(ds.node);
1168
1169        return ENOERR;
1170}
1171
1172// -------------------------------------------------------------------------
1173// jffs2_getinfo()
1174// Getinfo. Currently only support pathconf().
1175
1176static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
1177                         int key, void *buf, int len)
1178{
1179        jffs2_dirsearch ds;
1180        int err;
1181
1182        D2(printf("jffs2_getinfo\n"));
1183
1184        init_dirsearch(&ds, (struct _inode *) dir, 
1185                       (const unsigned char *) name);
1186
1187        err = jffs2_find(&ds);
1188        jffs2_iput(ds.dir);
1189
1190        if (err != ENOERR)
1191                return err;
1192
1193        switch (key) {
1194        case FS_INFO_CONF:
1195                err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf);
1196                break;
1197
1198        default:
1199                err = EINVAL;
1200        }
1201
1202        jffs2_iput(ds.node);
1203        return err;
1204}
1205
1206// -------------------------------------------------------------------------
1207// jffs2_setinfo()
1208// Setinfo. Nothing to support here at present.
1209
1210static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
1211                         int key, void *buf, int len)
1212{
1213        // No setinfo keys supported at present
1214
1215        D2(printf("jffs2_setinfo\n"));
1216
1217        return EINVAL;
1218}
1219
1220//==========================================================================
1221// File operations
1222
1223// -------------------------------------------------------------------------
1224// jffs2_fo_read()
1225// Read data from the file.
1226
1227static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1228{
1229        struct _inode *inode = (struct _inode *) fp->f_data;
1230        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1231        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1232        int i;
1233        ssize_t resid = uio->uio_resid;
1234        off_t pos = fp->f_offset;
1235
1236        down(&f->sem);
1237
1238        // Loop over the io vectors until there are none left
1239        for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) {
1240                int ret;
1241                cyg_iovec *iov = &uio->uio_iov[i];
1242                off_t len = min(iov->iov_len, inode->i_size - pos);
1243
1244                D2(printf("jffs2_fo_read inode size %d\n", inode->i_size));
1245
1246                ret =
1247                    jffs2_read_inode_range(c, f,
1248                                           (unsigned char *) iov->iov_base, pos,
1249                                           len);
1250                if (ret) {
1251                        D1(printf
1252                           ("jffs2_fo_read(): read_inode_range failed %d\n",
1253                            ret));
1254                        uio->uio_resid = resid;
1255                        up(&f->sem);
1256                        return -ret;
1257                }
1258                resid -= len;
1259                pos += len;
1260        }
1261
1262        // We successfully read some data, update the node's access time
1263        // and update the file offset and transfer residue.
1264
1265        inode->i_atime = cyg_timestamp();
1266
1267        uio->uio_resid = resid;
1268        fp->f_offset = pos;
1269
1270        up(&f->sem);
1271
1272        return ENOERR;
1273}
1274
1275
1276#ifdef CYGOPT_FS_JFFS2_WRITE
1277// -------------------------------------------------------------------------
1278// jffs2_fo_write()
1279// Write data to file.
1280static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri,
1281                       unsigned long offset)
1282{
1283        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1284        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1285        struct jffs2_full_dnode *fn;
1286        uint32_t phys_ofs, alloc_len;
1287        int ret = 0;
1288
1289        /* Make new hole frag from old EOF to new page */
1290        D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
1291                  (unsigned int)inode->i_size, offset));
1292
1293        ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
1294        if (ret)
1295                return ret;
1296
1297        down(&f->sem);
1298
1299        ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
1300        ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
1301        ri->totlen = cpu_to_je32(sizeof(*ri));
1302        ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
1303
1304        ri->version = cpu_to_je32(++f->highest_version);
1305        ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset));
1306
1307        ri->offset = cpu_to_je32(inode->i_size);
1308        ri->dsize = cpu_to_je32(offset - inode->i_size);
1309        ri->csize = cpu_to_je32(0);
1310        ri->compr = JFFS2_COMPR_ZERO;
1311        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
1312        ri->data_crc = cpu_to_je32(0);
1313               
1314        fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
1315        jffs2_complete_reservation(c);
1316        if (IS_ERR(fn)) {
1317                ret = PTR_ERR(fn);
1318                up(&f->sem);
1319                return ret;
1320        }
1321        ret = jffs2_add_full_dnode_to_inode(c, f, fn);
1322        if (f->metadata) {
1323                jffs2_mark_node_obsolete(c, f->metadata->raw);
1324                jffs2_free_full_dnode(f->metadata);
1325                f->metadata = NULL;
1326        }
1327        if (ret) {
1328                D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret));
1329                jffs2_mark_node_obsolete(c, fn->raw);
1330                jffs2_free_full_dnode(fn);
1331                up(&f->sem);
1332                return ret;
1333        }
1334        inode->i_size = offset;
1335        up(&f->sem);
1336        return 0;
1337}
1338
1339// jffs2_fo_open()
1340// Truncate a file
1341static int jffs2_truncate_file (struct _inode *inode)
1342{
1343     struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1344     struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1345     struct jffs2_full_dnode *new_metadata, * old_metadata;
1346     struct jffs2_raw_inode *ri;
1347     uint32_t phys_ofs, alloclen;
1348     int err;
1349     
1350     ri = jffs2_alloc_raw_inode();
1351     if (!ri) {
1352          return ENOMEM;
1353     }
1354     err = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
1355     
1356     if (err) {
1357          jffs2_free_raw_inode(ri);
1358          return err;
1359     }
1360     down(&f->sem);
1361     ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
1362     ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
1363     ri->totlen = cpu_to_je32(sizeof(*ri));
1364     ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
1365     
1366     ri->ino = cpu_to_je32(inode->i_ino);
1367     ri->version = cpu_to_je32(++f->highest_version);
1368     
1369     ri->uid = cpu_to_je16(inode->i_uid);
1370     ri->gid = cpu_to_je16(inode->i_gid);
1371     ri->mode = cpu_to_jemode(inode->i_mode);
1372     ri->isize = cpu_to_je32(0);
1373     ri->atime = cpu_to_je32(inode->i_atime);
1374     ri->mtime = cpu_to_je32(cyg_timestamp());
1375     ri->offset = cpu_to_je32(0);
1376     ri->csize = ri->dsize = cpu_to_je32(0);
1377     ri->compr = JFFS2_COMPR_NONE;
1378     ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
1379     ri->data_crc = cpu_to_je32(0);
1380     new_metadata = jffs2_write_dnode(c, f, ri, NULL, 0, 
1381                                      phys_ofs, ALLOC_NORMAL);
1382     if (IS_ERR(new_metadata)) {
1383          jffs2_complete_reservation(c);
1384          jffs2_free_raw_inode(ri);
1385          up(&f->sem);
1386          return PTR_ERR(new_metadata);
1387     }
1388     
1389     /* It worked. Update the inode */
1390     inode->i_mtime = cyg_timestamp();
1391     inode->i_size = 0;
1392     old_metadata = f->metadata;
1393     jffs2_truncate_fragtree (c, &f->fragtree, 0);
1394     f->metadata = new_metadata;
1395     if (old_metadata) {
1396          jffs2_mark_node_obsolete(c, old_metadata->raw);
1397          jffs2_free_full_dnode(old_metadata);
1398     }
1399     jffs2_free_raw_inode(ri);
1400     
1401     up(&f->sem);
1402     jffs2_complete_reservation(c);
1403     
1404     return 0;
1405}
1406
1407static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1408{
1409        struct _inode *inode = (struct _inode *) fp->f_data;
1410        off_t pos = fp->f_offset;
1411        ssize_t resid = uio->uio_resid;
1412        struct jffs2_raw_inode ri;
1413        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1414        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1415        int i;
1416
1417        // If the APPEND mode bit was supplied, force all writes to
1418        // the end of the file.
1419        if (fp->f_flag & CYG_FAPPEND)
1420                pos = fp->f_offset = inode->i_size;
1421
1422        if (pos < 0)
1423                return EINVAL;
1424
1425        memset(&ri, 0, sizeof(ri));
1426
1427        ri.ino = cpu_to_je32(f->inocache->ino);
1428        ri.mode = cpu_to_jemode(inode->i_mode);
1429        ri.uid = cpu_to_je16(inode->i_uid);
1430        ri.gid = cpu_to_je16(inode->i_gid);
1431        ri.atime = ri.ctime = ri.mtime = cpu_to_je32(cyg_timestamp());
1432
1433        if (pos > inode->i_size) {
1434                int err;
1435                ri.version = cpu_to_je32(++f->highest_version);
1436                err = jffs2_extend_file(inode, &ri, pos);
1437                if (err)
1438                        return -err;
1439        }
1440        ri.isize = cpu_to_je32(inode->i_size);
1441
1442        // Now loop over the iovecs until they are all done, or
1443        // we get an error.
1444        for (i = 0; i < uio->uio_iovcnt; i++) {
1445                cyg_iovec *iov = &uio->uio_iov[i];
1446                unsigned char *buf = iov->iov_base;
1447                off_t len = iov->iov_len;
1448
1449                uint32_t writtenlen;
1450                int err;
1451
1452                D2(printf("jffs2_fo_write page_start_pos %d\n", pos));
1453                D2(printf("jffs2_fo_write transfer size %d\n", len));
1454
1455                err = jffs2_write_inode_range(c, f, &ri, buf,
1456                                              pos, len, &writtenlen);
1457                if (err)
1458                        return -err;
1459               
1460                if (writtenlen != len)
1461                        return ENOSPC;
1462
1463                pos += len;
1464                resid -= len;
1465        }
1466
1467        // We wrote some data successfully, update the modified and access
1468        // times of the inode, increase its size appropriately, and update
1469        // the file offset and transfer residue.
1470        inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime);
1471        if (pos > inode->i_size)
1472                inode->i_size = pos;
1473
1474        uio->uio_resid = resid;
1475        fp->f_offset = pos;
1476
1477        return ENOERR;
1478}
1479#endif /* CYGOPT_FS_JFFS2_WRITE */
1480
1481// -------------------------------------------------------------------------
1482// jffs2_fo_lseek()
1483// Seek to a new file position.
1484
1485static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * apos, int whence)
1486{
1487        struct _inode *node = (struct _inode *) fp->f_data;
1488        off_t pos = *apos;
1489
1490        D2(printf("jffs2_fo_lseek\n"));
1491
1492        switch (whence) {
1493        case SEEK_SET:
1494                // Pos is already where we want to be.
1495                break;
1496
1497        case SEEK_CUR:
1498                // Add pos to current offset.
1499                pos += fp->f_offset;
1500                break;
1501
1502        case SEEK_END:
1503                // Add pos to file size.
1504                pos += node->i_size;
1505                break;
1506
1507        default:
1508                return EINVAL;
1509        }
1510
1511        if (pos < 0 )
1512                return EINVAL;
1513
1514        // All OK, set fp offset and return new position.
1515        *apos = fp->f_offset = pos;
1516
1517        return ENOERR;
1518}
1519
1520// -------------------------------------------------------------------------
1521// jffs2_fo_ioctl()
1522// Handle ioctls. Currently none are defined.
1523
1524static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
1525                          CYG_ADDRWORD data)
1526{
1527        // No Ioctls currenly defined.
1528
1529        D2(printf("jffs2_fo_ioctl\n"));
1530
1531        return EINVAL;
1532}
1533
1534// -------------------------------------------------------------------------
1535// jffs2_fo_fsync().
1536// Force the file out to data storage.
1537
1538static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
1539{
1540        // Data is always permanently where it belongs, nothing to do
1541        // here.
1542
1543        D2(printf("jffs2_fo_fsync\n"));
1544
1545        return ENOERR;
1546}
1547
1548// -------------------------------------------------------------------------
1549// jffs2_fo_close()
1550// Close a file. We just decrement the refcnt and let it go away if
1551// that is all that is keeping it here.
1552
1553static int jffs2_fo_close(struct CYG_FILE_TAG *fp)
1554{
1555        struct _inode *node = (struct _inode *) fp->f_data;
1556
1557        D2(printf("jffs2_fo_close\n"));
1558
1559        jffs2_iput(node);
1560
1561        fp->f_data = 0;         // zero data pointer
1562
1563        return ENOERR;
1564}
1565
1566// -------------------------------------------------------------------------
1567//jffs2_fo_fstat()
1568// Get file status.
1569
1570static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
1571{
1572        struct _inode *node = (struct _inode *) fp->f_data;
1573
1574        D2(printf("jffs2_fo_fstat\n"));
1575
1576        // Fill in the status
1577        buf->st_mode = node->i_mode;
1578        buf->st_ino = node->i_ino;
1579        buf->st_dev = 0;
1580        buf->st_nlink = node->i_nlink;
1581        buf->st_uid = node->i_uid;
1582        buf->st_gid = node->i_gid;
1583        buf->st_size = node->i_size;
1584        buf->st_atime = node->i_atime;
1585        buf->st_mtime = node->i_mtime;
1586        buf->st_ctime = node->i_ctime;
1587
1588        return ENOERR;
1589}
1590
1591// -------------------------------------------------------------------------
1592// jffs2_fo_getinfo()
1593// Get info. Currently only supports fpathconf().
1594
1595static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
1596                            int len)
1597{
1598        struct _inode *node = (struct _inode *) fp->f_data;
1599        int err;
1600
1601        D2(printf("jffs2_fo_getinfo\n"));
1602
1603        switch (key) {
1604        case FS_INFO_CONF:
1605                err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf);
1606                break;
1607
1608        default:
1609                err = EINVAL;
1610        }
1611        return err;
1612
1613        return ENOERR;
1614}
1615
1616// -------------------------------------------------------------------------
1617// jffs2_fo_setinfo()
1618// Set info. Nothing supported here.
1619
1620static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
1621                            int len)
1622{
1623        // No setinfo key supported at present
1624
1625        D2(printf("jffs2_fo_setinfo\n"));
1626
1627        return ENOERR;
1628}
1629
1630//==========================================================================
1631// Directory operations
1632
1633// -------------------------------------------------------------------------
1634// jffs2_fo_dirread()
1635// Read a single directory entry from a file.
1636
1637static __inline void filldir(char *nbuf, int nlen, const unsigned char *name, int namlen)
1638{
1639        int len = nlen < namlen ? nlen : namlen;
1640        memcpy(nbuf, name, len);
1641        nbuf[len] = '\0';
1642}
1643
1644static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1645{
1646        struct _inode *d_inode = (struct _inode *) fp->f_data;
1647        struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base;
1648        char *nbuf = ent->d_name;
1649#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
1650        struct _inode *c_ino;
1651#endif
1652        int nlen = sizeof (ent->d_name) - 1;
1653        off_t len = uio->uio_iov[0].iov_len;
1654        struct jffs2_inode_info *f;
1655        struct jffs2_sb_info *c;
1656        struct _inode *inode = d_inode;
1657        struct jffs2_full_dirent *fd;
1658        unsigned long offset, curofs;
1659        int found = 1;
1660
1661        if (len < sizeof (struct dirent))
1662                return EINVAL;
1663
1664        D1(printk
1665           (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino));
1666
1667        f = JFFS2_INODE_INFO(inode);
1668        c = JFFS2_SB_INFO(inode->i_sb);
1669
1670        offset = fp->f_offset;
1671
1672        if (offset == 0) {
1673                D1(printk
1674                   (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino));
1675                filldir(nbuf, nlen, (const unsigned char *) ".", 1);
1676#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
1677                // Flags here are the same as jffs2_mkdir. Make sure
1678                // d_type is the same as st_mode of calling stat.
1679                ent->d_type = 
1680                  jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR));
1681#endif
1682                goto out;
1683        }
1684        if (offset == 1) {
1685                filldir(nbuf, nlen, (const unsigned char *) "..", 2);
1686#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
1687                // Flags here are the same as jffs2_mkdir. Make sure
1688                // d_type is the same as st_mode of calling stat.
1689                ent->d_type = 
1690                  jemode_to_cpu(cpu_to_jemode(S_IRUGO|S_IXUGO|S_IWUSR|S_IFDIR));
1691#endif
1692                goto out;
1693        }
1694
1695        curofs = 1;
1696        down(&f->sem);
1697        for (fd = f->dents; fd; fd = fd->next) {
1698
1699                curofs++;
1700                /* First loop: curofs = 2; offset = 2 */
1701                if (curofs < offset) {
1702                        D2(printk
1703                           (KERN_DEBUG
1704                            "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
1705                            fd->name, fd->ino, fd->type, curofs, offset));
1706                        continue;
1707                }
1708                if (!fd->ino) {
1709                        D2(printk
1710                           (KERN_DEBUG "Skipping deletion dirent \"%s\"\n",
1711                            fd->name));
1712                        offset++;
1713                        continue;
1714                }
1715                D2(printk
1716                   (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset,
1717                    fd->name, fd->ino, fd->type));
1718                filldir(nbuf, nlen, fd->name, strlen((char *)fd->name));
1719#ifdef CYGPKG_FS_JFFS2_RET_DIRENT_DTYPE
1720                c_ino = jffs2_iget(inode->i_sb, fd->ino);
1721                if(IS_ERR(c_ino)) {
1722                        D1(printk(KERN_WARNING "get entry inode failed\n"));
1723                        // fileio already set it to zero, so not needed here
1724                        // ent->d_type = 0;
1725                }
1726                else {
1727                        ent->d_type = c_ino->i_mode;
1728                        jffs2_iput(c_ino);
1729                }
1730#endif
1731                goto out_sem;
1732        }
1733        /* Reached the end of the directory */
1734        found = 0;
1735      out_sem:
1736        up(&f->sem);
1737      out:
1738        fp->f_offset = ++offset;
1739        if (found) {
1740                uio->uio_resid -= sizeof (struct dirent);
1741        }
1742        return ENOERR;
1743}
1744
1745// -------------------------------------------------------------------------
1746// jffs2_fo_dirlseek()
1747// Seek directory to start.
1748
1749static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence)
1750{
1751        // Only allow SEEK_SET to zero
1752
1753        D2(printf("jffs2_fo_dirlseek\n"));
1754
1755        if (whence != SEEK_SET || *pos != 0)
1756                return EINVAL;
1757
1758        *pos = fp->f_offset = 0;
1759
1760        return ENOERR;
1761}
1762
1763//==========================================================================
1764//
1765// Called by JFFS2
1766// ===============
1767//
1768//
1769//==========================================================================
1770
1771unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
1772                                   struct jffs2_inode_info *f, 
1773                                   unsigned long offset,
1774                                   unsigned long *priv)
1775{
1776        /* FIXME: This works only with one file system mounted at a time */
1777        int ret;
1778
1779        ret = jffs2_read_inode_range(c, f, gc_buffer, 
1780                                     offset & ~(PAGE_CACHE_SIZE-1), PAGE_CACHE_SIZE);
1781        if (ret)
1782                return ERR_PTR(ret);
1783
1784        return gc_buffer;
1785}
1786
1787void jffs2_gc_release_page(struct jffs2_sb_info *c,
1788                           unsigned char *ptr,
1789                           unsigned long *priv)
1790{
1791        /* Do nothing */
1792}
1793
1794static struct _inode *new_inode(struct super_block *sb)
1795{
1796
1797        // Only called in write.c jffs2_new_inode
1798        // Always adds itself to inode cache
1799
1800        struct _inode *inode;
1801        struct _inode *cached_inode;
1802
1803        inode = malloc(sizeof (struct _inode));
1804        if (inode == NULL)
1805                return 0;
1806
1807        D2(printf
1808           ("malloc new_inode %x ####################################\n",
1809            inode));
1810
1811        memset(inode, 0, sizeof (struct _inode));
1812        inode->i_sb = sb;
1813        inode->i_ino = 1;
1814        inode->i_count = 1;
1815        inode->i_nlink = 1;     // Let JFFS2 manage the link count
1816        inode->i_size = 0;
1817
1818        inode->i_cache_next = NULL;     // Newest inode, about to be cached
1819
1820        // Add to the icache
1821        for (cached_inode = sb->s_root; cached_inode != NULL;
1822             cached_inode = cached_inode->i_cache_next) {
1823                if (cached_inode->i_cache_next == NULL) {
1824                        cached_inode->i_cache_next = inode;     // Current last in cache points to newcomer
1825                        inode->i_cache_prev = cached_inode;     // Newcomer points back to last
1826                        break;
1827                }
1828        }
1829        return inode;
1830}
1831
1832static struct _inode *ilookup(struct super_block *sb, cyg_uint32 ino)
1833{
1834        struct _inode *inode = NULL;
1835
1836        D2(printf("ilookup\n"));
1837        // Check for this inode in the cache
1838        for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) {
1839                if (inode->i_ino == ino) {
1840                        inode->i_count++;
1841                        break;
1842                }
1843        }
1844        return inode;
1845}
1846
1847struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino)
1848{
1849        // Called in super.c jffs2_read_super, dir.c jffs2_lookup,
1850        // and gc.c jffs2_garbage_collect_pass
1851
1852        // Must first check for cached inode
1853        // If this fails let new_inode create one
1854
1855        struct _inode *inode;
1856        int err;
1857
1858        D2(printf("jffs2_iget\n"));
1859
1860        inode = ilookup(sb, ino);
1861        if (inode)
1862                return inode;
1863
1864        // Not cached, so malloc it
1865        inode = new_inode(sb);
1866        if (inode == NULL)
1867                return ERR_PTR(-ENOMEM);
1868
1869        inode->i_ino = ino;
1870
1871        err = jffs2_read_inode(inode);
1872        if (err) {
1873                printf("jffs2_read_inode() failed\n");
1874                inode->i_nlink = 0; // free _this_ bad inode right now
1875                jffs2_iput(inode);
1876                inode = NULL;
1877                return ERR_PTR(err);
1878        }
1879        return inode;
1880}
1881
1882// -------------------------------------------------------------------------
1883// Decrement the reference count on an inode. If this makes the ref count
1884// zero, then this inode can be freed.
1885
1886void jffs2_iput(struct _inode *i)
1887{
1888        // Called in jffs2_find
1889        // (and jffs2_open and jffs2_ops_mkdir?)
1890        // super.c jffs2_read_super,
1891        // and gc.c jffs2_garbage_collect_pass
1892 recurse:
1893        if (!i) {
1894                printf("jffs2_iput() called with NULL inode\n");
1895                // and let it fault...
1896        }
1897
1898        i->i_count--;
1899
1900        if (i->i_count < 0)
1901                BUG();
1902
1903        if (i->i_count)
1904                return;
1905       
1906        if (!i->i_nlink) {
1907                struct _inode *parent;
1908
1909                // Remove from the icache linked list and free immediately
1910                if (i->i_cache_prev)
1911                        i->i_cache_prev->i_cache_next = i->i_cache_next;
1912                if (i->i_cache_next)
1913                        i->i_cache_next->i_cache_prev = i->i_cache_prev;
1914
1915                parent = i->i_parent;
1916                jffs2_clear_inode(i);
1917                memset(i, 0x5a, sizeof(*i));
1918                free(i);
1919
1920                if (parent && parent != i) {
1921                        i = parent;
1922                        goto recurse;
1923                }
1924
1925        } else {
1926                // Evict some _other_ inode with i_count zero, leaving
1927                // this latest one in the cache for a while
1928                icache_evict(i->i_sb->s_root, i);
1929        }
1930}
1931
1932
1933// -------------------------------------------------------------------------
1934// EOF jffs2.c
1935
1936
1937static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
1938{
1939        memset(f, 0, sizeof(*f));
1940        init_MUTEX_LOCKED(&f->sem);
1941}
1942
1943static void jffs2_clear_inode (struct _inode *inode)
1944{
1945        /* We can forget about this inode for now - drop all
1946         *  the nodelists associated with it, etc.
1947         */
1948        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
1949        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
1950
1951        D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
1952
1953        jffs2_do_clear_inode(c, f);
1954}
1955
1956
1957/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
1958   fill in the raw_inode while you're at it. */
1959struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri)
1960{
1961        struct _inode *inode;
1962        struct super_block *sb = dir_i->i_sb;
1963        struct jffs2_sb_info *c;
1964        struct jffs2_inode_info *f;
1965        int ret;
1966
1967        D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
1968
1969        c = JFFS2_SB_INFO(sb);
1970       
1971        inode = new_inode(sb);
1972       
1973        if (!inode)
1974                return ERR_PTR(-ENOMEM);
1975
1976        f = JFFS2_INODE_INFO(inode);
1977        jffs2_init_inode_info(f);
1978
1979        memset(ri, 0, sizeof(*ri));
1980        /* Set OS-specific defaults for new inodes */
1981        ri->uid = ri->gid = cpu_to_je16(0);
1982        ri->mode =  cpu_to_jemode(mode);
1983        ret = jffs2_do_new_inode (c, f, mode, ri);
1984        if (ret) {
1985                // forceful evict: f->sem is locked already, and the
1986                // inode is bad.
1987                if (inode->i_cache_prev)
1988                       inode->i_cache_prev->i_cache_next = inode->i_cache_next;
1989                if (inode->i_cache_next)
1990                       inode->i_cache_next->i_cache_prev = inode->i_cache_prev; 
1991                up(&(f->sem));
1992                jffs2_clear_inode(inode);
1993                memset(inode, 0x6a, sizeof(*inode));
1994                free(inode);
1995                return ERR_PTR(ret);
1996        }
1997        inode->i_nlink = 1;
1998        inode->i_ino = je32_to_cpu(ri->ino);
1999        inode->i_mode = jemode_to_cpu(ri->mode);
2000        inode->i_gid = je16_to_cpu(ri->gid);
2001        inode->i_uid = je16_to_cpu(ri->uid);
2002        inode->i_atime = inode->i_ctime = inode->i_mtime = cyg_timestamp();
2003        ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime);
2004
2005        inode->i_size = 0;
2006
2007        return inode;
2008}
2009
2010
2011static int jffs2_read_inode (struct _inode *inode)
2012{
2013        struct jffs2_inode_info *f;
2014        struct jffs2_sb_info *c;
2015        struct jffs2_raw_inode latest_node;
2016        int ret;
2017
2018        D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
2019
2020        f = JFFS2_INODE_INFO(inode);
2021        c = JFFS2_SB_INFO(inode->i_sb);
2022
2023        jffs2_init_inode_info(f);
2024       
2025        ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
2026
2027        if (ret) {
2028                up(&f->sem);
2029                return ret;
2030        }
2031        inode->i_mode = jemode_to_cpu(latest_node.mode);
2032        inode->i_uid = je16_to_cpu(latest_node.uid);
2033        inode->i_gid = je16_to_cpu(latest_node.gid);
2034        inode->i_size = je32_to_cpu(latest_node.isize);
2035        inode->i_atime = je32_to_cpu(latest_node.atime);
2036        inode->i_mtime = je32_to_cpu(latest_node.mtime);
2037        inode->i_ctime = je32_to_cpu(latest_node.ctime);
2038
2039        inode->i_nlink = f->inocache->nlink;
2040        up(&f->sem);
2041
2042        D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
2043        return 0;
2044}
2045
2046
2047void jffs2_gc_release_inode(struct jffs2_sb_info *c,
2048                                   struct jffs2_inode_info *f)
2049{
2050        jffs2_iput(OFNI_EDONI_2SFFJ(f));
2051}
2052
2053struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
2054                                                     int inum, int nlink)
2055{
2056        struct _inode *inode;
2057        struct jffs2_inode_cache *ic;
2058        if (!nlink) {
2059                /* The inode has zero nlink but its nodes weren't yet marked
2060                   obsolete. This has to be because we're still waiting for
2061                   the final (close() and) jffs2_iput() to happen.
2062
2063                   There's a possibility that the final jffs2_iput() could have
2064                   happened while we were contemplating. In order to ensure
2065                   that we don't cause a new read_inode() (which would fail)
2066                   for the inode in question, we use ilookup() in this case
2067                   instead of jffs2_iget().
2068
2069                   The nlink can't _become_ zero at this point because we're
2070                   holding the alloc_sem, and jffs2_do_unlink() would also
2071                   need that while decrementing nlink on any inode.
2072                */
2073                inode = ilookup(OFNI_BS_2SFFJ(c), inum);
2074                if (!inode) {
2075                        D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
2076                                  inum));
2077
2078                        spin_lock(&c->inocache_lock);
2079                        ic = jffs2_get_ino_cache(c, inum);
2080                        if (!ic) {
2081                                D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
2082                                spin_unlock(&c->inocache_lock);
2083                                return NULL;
2084                        }
2085                        if (ic->state != INO_STATE_CHECKEDABSENT) {
2086                                /* Wait for progress. Don't just loop */
2087                                D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
2088                                          ic->ino, ic->state));
2089                                sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
2090                        } else {
2091                                spin_unlock(&c->inocache_lock);
2092                        }
2093
2094                        return NULL;
2095                }
2096        } else {
2097                /* Inode has links to it still; they're not going away because
2098                   jffs2_do_unlink() would need the alloc_sem and we have it.
2099                   Just jffs2_iget() it, and if read_inode() is necessary that's OK.
2100                */
2101                inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum);
2102                if (IS_ERR(inode))
2103                        return (void *)inode;
2104        }
2105
2106        return JFFS2_INODE_INFO(inode);
2107}
2108
2109
2110
2111uint32_t jffs2_from_os_mode(uint32_t osmode)
2112{
2113        uint32_t jmode = ((osmode & S_IRUSR)?00400:0) |
2114                ((osmode & S_IWUSR)?00200:0) |
2115                ((osmode & S_IXUSR)?00100:0) |
2116                ((osmode & S_IRGRP)?00040:0) |
2117                ((osmode & S_IWGRP)?00020:0) |
2118                ((osmode & S_IXGRP)?00010:0) |
2119                ((osmode & S_IROTH)?00004:0) |
2120                ((osmode & S_IWOTH)?00002:0) |
2121                ((osmode & S_IXOTH)?00001:0);
2122
2123        switch (osmode & S_IFMT) {
2124        case S_IFSOCK:
2125                return jmode | 0140000;
2126        case S_IFLNK:
2127                return jmode | 0120000;
2128        case S_IFREG:
2129                return jmode | 0100000;
2130        case S_IFBLK:
2131                return jmode | 0060000;
2132        case S_IFDIR:
2133                return jmode | 0040000;
2134        case S_IFCHR:
2135                return jmode | 0020000;
2136        case S_IFIFO:
2137                return jmode | 0010000;
2138        case S_ISUID:
2139                return jmode | 0004000;
2140        case S_ISGID:
2141                return jmode | 0002000;
2142#ifdef S_ISVTX
2143        case S_ISVTX:
2144                return jmode | 0001000;
2145#endif
2146        }
2147        printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode);
2148        BUG();
2149        return 0;
2150}
2151
2152uint32_t jffs2_to_os_mode (uint32_t jmode)
2153{
2154        uint32_t osmode = ((jmode & 00400)?S_IRUSR:0) |
2155                ((jmode & 00200)?S_IWUSR:0) |
2156                ((jmode & 00100)?S_IXUSR:0) |
2157                ((jmode & 00040)?S_IRGRP:0) |
2158                ((jmode & 00020)?S_IWGRP:0) |
2159                ((jmode & 00010)?S_IXGRP:0) |
2160                ((jmode & 00004)?S_IROTH:0) |
2161                ((jmode & 00002)?S_IWOTH:0) |
2162                ((jmode & 00001)?S_IXOTH:0);
2163
2164        switch(jmode & 00170000) {
2165        case 0140000:
2166                return osmode | S_IFSOCK;
2167        case 0120000:
2168                return osmode | S_IFLNK;
2169        case 0100000:
2170                return osmode | S_IFREG;
2171        case 0060000:
2172                return osmode | S_IFBLK;
2173        case 0040000:
2174                return osmode | S_IFDIR;
2175        case 0020000:
2176                return osmode | S_IFCHR;
2177        case 0010000:
2178                return osmode | S_IFIFO;
2179        case 0004000:
2180                return osmode | S_ISUID;
2181        case 0002000:
2182                return osmode | S_ISGID;
2183#ifdef S_ISVTX
2184        case 0001000:
2185                return osmode | S_ISVTX;
2186#endif
2187        }
2188        printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode);
2189        BUG();
2190        return 0;
2191}
Note: See TracBrowser for help on using the repository browser.