Coverage Report

Created: 2026-10-17 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/fs/jffs2/fs.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
 * JFFS2 -- Journalling Flash File System, Version 2.
4
 *
5
 * Copyright © 2001-2007 Red Hat, Inc.
6
 * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
7
 *
8
 * Created by David Woodhouse <dwmw2@infradead.org>
9
 */
10
#define pr_fmt(fmt) "jffs2: " fmt
11
#include <common.h>
12
#include <crc.h>
13
#include <driver.h>
14
#include <init.h>
15
#include <fs.h>
16
#include <malloc.h>
17
#include <linux/kernel.h>
18
#include <linux/sched.h>
19
#include <linux/list.h>
20
#include <linux/mtd/mtd.h>
21
#include <linux/pagemap.h>
22
#include <linux/stat.h>
23
#include "compr.h"
24
#include "nodelist.h"
25
#include "os-linux.h"
26
27
static int jffs2_flash_setup(struct jffs2_sb_info *c);
28
29
/* from include/linux/fs.h */
30
static inline void i_uid_write(struct inode *inode, uid_t uid)
31
0
{
32
0
  inode->i_uid = uid;
33
0
}
34
35
static inline void i_gid_write(struct inode *inode, gid_t gid)
36
0
{
37
0
  inode->i_gid = gid;
38
0
}
39
40
const struct inode_operations jffs2_file_inode_operations;
41
42
static int jffs2_open(struct inode *inode, struct file *file)
43
0
{
44
0
  struct jffs2_file *jf;
45
46
0
  jf = xzalloc(sizeof(*jf));
47
48
0
  jf->inode = inode;
49
0
  jf->buf = xmalloc(JFFS2_BLOCK_SIZE);
50
0
  jf->offset = -1;
51
52
0
  file->private_data = jf;
53
54
0
  return 0;
55
0
}
56
57
static int jffs2_close(struct inode *inode, struct file *f)
58
0
{
59
0
  struct jffs2_file *jf = f->private_data;
60
61
0
  free(jf->buf);
62
0
  free(jf);
63
64
0
  return 0;
65
0
}
66
67
static int jffs2_get_block(struct jffs2_file *jf, unsigned int pos)
68
0
{
69
0
  struct jffs2_sb_info *c = JFFS2_SB_INFO(jf->inode->i_sb);
70
0
  struct jffs2_inode_info *f = JFFS2_INODE_INFO(jf->inode);
71
0
  int ret;
72
73
  /* pos always has to be 4096 bytes aligned here */
74
0
  WARN_ON(pos % JFFS2_BLOCK_SIZE != 0);
75
76
0
  if (pos != jf->offset) {
77
0
    ret = jffs2_read_inode_range(c, f, jf->buf, pos,
78
0
               JFFS2_BLOCK_SIZE);
79
0
    if (ret && ret != -ENOENT)
80
0
      return ret;
81
0
    jf->offset = pos;
82
0
  }
83
84
0
  return 0;
85
0
}
86
87
static int jffs2_read(struct file *f, void *buf, size_t insize)
88
0
{
89
0
  struct jffs2_file *jf = f->private_data;
90
0
  unsigned int pos = f->f_pos;
91
0
  unsigned int ofs;
92
0
  unsigned int now;
93
0
  unsigned int size = insize;
94
0
  int ret;
95
96
  /* Read till end of current block */
97
0
  ofs = f->f_pos % JFFS2_BLOCK_SIZE;
98
0
  if (ofs) {
99
0
    ret = jffs2_get_block(jf, f->f_pos - ofs); /* Align down block */
100
0
    if (ret)
101
0
      return ret;
102
103
0
    now = min(size, JFFS2_BLOCK_SIZE - ofs);
104
105
    /* Complete block has been read, re-apply ofset now */
106
0
    memcpy(buf, jf->buf + ofs, now);
107
0
    size -= now;
108
0
    pos += now;
109
0
    buf += now;
110
0
  }
111
112
  /* Do full blocks */
113
0
  while (size >= JFFS2_BLOCK_SIZE) {
114
0
    ret = jffs2_get_block(jf, pos);
115
0
    if (ret)
116
0
      return ret;
117
118
0
    memcpy(buf, jf->buf, JFFS2_BLOCK_SIZE);
119
0
    size -= JFFS2_BLOCK_SIZE;
120
0
    pos += JFFS2_BLOCK_SIZE;
121
0
    buf += JFFS2_BLOCK_SIZE;
122
0
  }
123
124
  /* And the rest */
125
0
  if (size) {
126
0
    ret = jffs2_get_block(jf, pos);
127
0
    if (ret)
128
0
      return ret;
129
0
    memcpy(buf, jf->buf, size);
130
0
  }
131
132
0
  return insize;
133
134
0
}
135
136
const struct file_operations jffs2_file_operations = {
137
  .open = jffs2_open,
138
  .release = jffs2_close,
139
  .read = jffs2_read,
140
};
141
142
struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
143
0
{
144
0
  struct jffs2_inode_info *f;
145
0
  struct jffs2_sb_info *c;
146
0
  struct jffs2_raw_inode latest_node;
147
0
  struct inode *inode;
148
0
  int ret;
149
150
0
  jffs2_dbg(1, "%s(): ino == %lu\n", __func__, ino);
151
152
0
  inode = iget_locked(sb, ino);
153
0
  if (!inode)
154
0
    return ERR_PTR(-ENOMEM);
155
0
  if (!(inode->i_state & I_NEW))
156
0
    return inode;
157
158
0
  f = JFFS2_INODE_INFO(inode);
159
0
  c = JFFS2_SB_INFO(inode->i_sb);
160
161
0
  jffs2_init_inode_info(f);
162
0
  mutex_lock(&f->sem);
163
164
0
  ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
165
0
  if (ret)
166
0
    goto error;
167
168
0
  inode->i_mode = jemode_to_cpu(latest_node.mode);
169
0
  i_uid_write(inode, je16_to_cpu(latest_node.uid));
170
0
  i_gid_write(inode, je16_to_cpu(latest_node.gid));
171
0
  inode->i_size = je32_to_cpu(latest_node.isize);
172
0
  inode->i_atime = ITIME(je32_to_cpu(latest_node.atime));
173
0
  inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
174
0
  inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
175
176
0
  set_nlink(inode, f->inocache->pino_nlink);
177
178
0
  inode->i_blocks = (inode->i_size + 511) >> 9;
179
180
0
  switch (inode->i_mode & S_IFMT) {
181
182
0
  case S_IFLNK:
183
0
    inode->i_op = &simple_symlink_inode_operations;
184
0
    inode->i_link = f->target;
185
0
    break;
186
187
0
  case S_IFDIR:
188
0
  {
189
0
    struct jffs2_full_dirent *fd;
190
0
    set_nlink(inode, 2); /* parent and '.' */
191
192
0
    for (fd=f->dents; fd; fd = fd->next) {
193
0
      if (fd->type == DT_DIR && fd->ino)
194
0
        inc_nlink(inode);
195
0
    }
196
    /* Root dir gets i_nlink 3 for some reason */
197
0
    if (inode->i_ino == 1)
198
0
      inc_nlink(inode);
199
200
0
    inode->i_op = &jffs2_dir_inode_operations;
201
0
    inode->i_fop = &jffs2_dir_operations;
202
0
    break;
203
0
  }
204
0
  case S_IFREG:
205
0
    inode->i_op = &jffs2_file_inode_operations;
206
0
    inode->i_fop = &jffs2_file_operations;
207
0
    break;
208
209
0
  case S_IFBLK:
210
0
  case S_IFCHR:
211
0
  case S_IFSOCK:
212
0
  case S_IFIFO:
213
0
    break;
214
215
0
  default:
216
0
    pr_warn("%s(): Bogus i_mode %o for ino %lu\n",
217
0
      __func__, inode->i_mode, (unsigned long)inode->i_ino);
218
0
  }
219
220
0
  mutex_unlock(&f->sem);
221
222
0
  jffs2_dbg(1, "jffs2_read_inode() returning\n");
223
0
  return inode;
224
225
0
error:
226
0
  mutex_unlock(&f->sem);
227
0
  iget_failed(inode);
228
0
  return ERR_PTR(ret);
229
0
}
230
231
static int calculate_inocache_hashsize(uint32_t flash_size)
232
0
{
233
  /*
234
   * Pick a inocache hash size based on the size of the medium.
235
   * Count how many megabytes we're dealing with, apply a hashsize twice
236
   * that size, but rounding down to the usual big powers of 2. And keep
237
   * to sensible bounds.
238
   */
239
240
0
  int size_mb = flash_size / 1024 / 1024;
241
0
  int hashsize = (size_mb * 2) & ~0x3f;
242
243
0
  if (hashsize < INOCACHE_HASHSIZE_MIN)
244
0
    return INOCACHE_HASHSIZE_MIN;
245
0
  if (hashsize > INOCACHE_HASHSIZE_MAX)
246
0
    return INOCACHE_HASHSIZE_MAX;
247
248
0
  return hashsize;
249
0
}
250
251
static void jffs2_put_super(struct super_block *sb)
252
0
{
253
0
  if (sb->s_fs_info) {
254
0
    struct jffs2_sb_info *ctx = sb->s_fs_info;
255
256
0
    jffs2_free_ino_caches(ctx);
257
0
    jffs2_free_raw_node_refs(ctx);
258
0
    kfree(ctx->blocks);
259
0
    kfree(ctx->inocache_list);
260
0
    jffs2_flash_cleanup(ctx);
261
262
0
    kfree(sb->s_fs_info);
263
0
  }
264
0
}
265
266
int jffs2_do_fill_super(struct super_block *sb, int silent)
267
0
{
268
0
  struct jffs2_sb_info *c;
269
0
  struct inode *root_i;
270
0
  int ret;
271
0
  size_t blocks;
272
273
0
  c = JFFS2_SB_INFO(sb);
274
275
0
  c->flash_size = c->mtd->size;
276
0
  c->sector_size = c->mtd->erasesize;
277
0
  blocks = c->flash_size / c->sector_size;
278
279
  /*
280
   * Size alignment check
281
   */
282
0
  if ((c->sector_size * blocks) != c->flash_size) {
283
0
    c->flash_size = c->sector_size * blocks;
284
0
    pr_info("Flash size not aligned to erasesize, reducing to %dKiB",
285
0
      c->flash_size / 1024);
286
0
  }
287
288
0
  if (c->flash_size < 5*c->sector_size) {
289
0
    pr_err("Too few erase blocks (%d)",
290
0
           c->flash_size / c->sector_size);
291
0
    return -EINVAL;
292
0
  }
293
294
0
  c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
295
296
  /* NAND (or other bizarre) flash... do setup accordingly */
297
0
  ret = jffs2_flash_setup(c);
298
0
  if (ret)
299
0
    return ret;
300
301
0
  c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size);
302
0
  c->inocache_list = kcalloc(c->inocache_hashsize, sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
303
0
  if (!c->inocache_list) {
304
0
    ret = -ENOMEM;
305
0
    goto out_wbuf;
306
0
  }
307
308
0
  jffs2_init_xattr_subsystem(c);
309
310
0
  if ((ret = jffs2_do_mount_fs(c)))
311
0
    goto out_inohash;
312
313
0
  jffs2_dbg(1, "%s(): Getting root inode\n", __func__);
314
0
  root_i = jffs2_iget(sb, 1);
315
0
  if (IS_ERR(root_i)) {
316
0
    jffs2_dbg(1, "get root inode failed\n");
317
0
    ret = PTR_ERR(root_i);
318
0
    goto out_root;
319
0
  }
320
321
0
  ret = -ENOMEM;
322
323
0
  jffs2_dbg(1, "%s(): d_make_root()\n", __func__);
324
0
  sb->s_root = d_make_root(root_i);
325
0
  if (!sb->s_root)
326
0
    goto out_root;
327
328
0
  sb->s_maxbytes = 0xFFFFFFFF;
329
0
  sb->s_blocksize = PAGE_SIZE;
330
0
  sb->s_blocksize_bits = PAGE_SHIFT;
331
0
  sb->s_magic = JFFS2_SUPER_MAGIC;
332
333
0
  return 0;
334
335
0
out_root:
336
0
  jffs2_free_ino_caches(c);
337
0
  jffs2_free_raw_node_refs(c);
338
0
out_inohash:
339
0
  kfree(c->inocache_list);
340
0
out_wbuf:
341
0
  jffs2_flash_cleanup(c);
342
0
  return ret;
343
0
}
344
345
0
static int jffs2_flash_setup(struct jffs2_sb_info *c) {
346
0
  int ret = 0;
347
348
0
  if (jffs2_cleanmarker_oob(c)) {
349
    /* NAND flash... do setup accordingly */
350
0
    ret = jffs2_nand_flash_setup(c);
351
0
    if (ret)
352
0
      return ret;
353
0
  }
354
355
  /* and Dataflash */
356
0
  if (jffs2_dataflash(c)) {
357
0
    ret = jffs2_dataflash_setup(c);
358
0
    if (ret)
359
0
      return ret;
360
0
  }
361
362
  /* and an UBI volume */
363
0
  if (jffs2_ubivol(c)) {
364
0
    ret = jffs2_ubivol_setup(c);
365
0
    if (ret)
366
0
      return ret;
367
0
  }
368
369
0
  return ret;
370
0
}
371
372
0
void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
373
374
0
  if (jffs2_cleanmarker_oob(c)) {
375
0
    jffs2_nand_flash_cleanup(c);
376
0
  }
377
378
  /* and DataFlash */
379
0
  if (jffs2_dataflash(c)) {
380
0
    jffs2_dataflash_cleanup(c);
381
0
  }
382
383
  /* and Intel "Sibley" flash */
384
0
  if (jffs2_nor_wbuf_flash(c)) {
385
0
    jffs2_nor_wbuf_flash_cleanup(c);
386
0
  }
387
388
  /* and an UBI volume */
389
0
  if (jffs2_ubivol(c)) {
390
0
    jffs2_ubivol_cleanup(c);
391
0
  }
392
0
}
393
394
static int jffs2_probe_cnt;
395
396
static int jffs2_probe(struct device *dev)
397
0
{
398
0
  struct fs_device *fsdev;
399
0
  struct super_block *sb;
400
0
  struct jffs2_sb_info *ctx;
401
0
  int ret;
402
403
0
  fsdev = dev_to_fs_device(dev);
404
0
  sb = &fsdev->sb;
405
406
0
  ret = fsdev_open_cdev(fsdev);
407
0
  if (ret)
408
0
    goto err_out;
409
410
0
  ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL);
411
0
  if (!ctx)
412
0
    return -ENOMEM;
413
414
0
  ctx->mtd = fsdev->cdev->mtd;
415
416
0
  sb->s_fs_info = ctx;
417
418
0
  if (!jffs2_probe_cnt) {
419
0
    ret = jffs2_compressors_init();
420
0
    if (ret) {
421
0
      pr_err("error: Failed to initialise compressors\n");
422
0
      goto err_out;
423
0
    }
424
0
  }
425
426
0
        if (jffs2_fill_super(fsdev, 0)) {
427
0
    dev_err(dev, "no valid jffs2 found\n");
428
0
    ret = -EINVAL;
429
0
    goto err_compressors;
430
0
  }
431
432
0
  jffs2_probe_cnt++;
433
434
0
  return 0;
435
436
0
err_compressors:
437
0
  jffs2_compressors_exit();
438
0
err_out:
439
440
0
  return ret;
441
0
}
442
443
static void jffs2_remove(struct device *dev)
444
0
{
445
0
  struct fs_device *fsdev;
446
0
  struct super_block *sb;
447
448
0
  fsdev = dev_to_fs_device(dev);
449
0
  sb = &fsdev->sb;
450
451
0
  jffs2_probe_cnt--;
452
453
0
  if (!jffs2_probe_cnt) {
454
0
    jffs2_compressors_exit();
455
0
  }
456
457
0
  jffs2_put_super(sb);
458
0
}
459
460
461
static struct fs_driver jffs2_driver = {
462
  .type = filetype_jffs2,
463
  .drv = {
464
    .probe  = jffs2_probe,
465
    .remove = jffs2_remove,
466
    .name = "jffs2",
467
  }
468
};
469
470
static int jffs2_init(void)
471
26
{
472
26
  return register_fs_driver(&jffs2_driver);
473
26
}
474
coredevice_initcall(jffs2_init);