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