summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libfs/src')
-rw-r--r--cpukit/libfs/src/defaults/default_are_nodes_equal.c2
-rw-r--r--cpukit/libfs/src/defaults/default_clone.c2
-rw-r--r--cpukit/libfs/src/defaults/default_eval_path.c2
-rw-r--r--cpukit/libfs/src/defaults/default_fsync_success.c2
-rw-r--r--cpukit/libfs/src/defaults/default_ftruncate_directory.c2
-rw-r--r--cpukit/libfs/src/defaults/default_handlers.c2
-rw-r--r--cpukit/libfs/src/defaults/default_kqfilter.c2
-rw-r--r--cpukit/libfs/src/defaults/default_lock_and_unlock.c2
-rw-r--r--cpukit/libfs/src/defaults/default_lseek_directory.c2
-rw-r--r--cpukit/libfs/src/defaults/default_lseek_file.c2
-rw-r--r--cpukit/libfs/src/defaults/default_ops.c2
-rw-r--r--cpukit/libfs/src/defaults/default_poll.c2
-rw-r--r--cpukit/libfs/src/defaults/default_readv.c2
-rw-r--r--cpukit/libfs/src/defaults/default_writev.c2
-rw-r--r--cpukit/libfs/src/dosfs/fat.c2
-rw-r--r--cpukit/libfs/src/dosfs/fat_fat_operations.c12
-rw-r--r--cpukit/libfs/src/dosfs/msdos.h6
-rw-r--r--cpukit/libfs/src/dosfs/msdos_conv.c2
-rw-r--r--cpukit/libfs/src/dosfs/msdos_conv_default.c2
-rw-r--r--cpukit/libfs/src/dosfs/msdos_conv_utf8.c2
-rw-r--r--cpukit/libfs/src/dosfs/msdos_create.c2
-rw-r--r--cpukit/libfs/src/dosfs/msdos_dir.c16
-rw-r--r--cpukit/libfs/src/dosfs/msdos_file.c7
-rw-r--r--cpukit/libfs/src/dosfs/msdos_init.c4
-rw-r--r--cpukit/libfs/src/dosfs/msdos_misc.c7
-rw-r--r--cpukit/libfs/src/dosfs/msdos_mknod.c2
-rw-r--r--cpukit/libfs/src/ftpfs/ftpfs.c2
-rw-r--r--cpukit/libfs/src/ftpfs/tftpDriver.c29
-rw-r--r--cpukit/libfs/src/ftpfs/tftp_driver.h2
-rw-r--r--cpukit/libfs/src/ftpfs/tftpfs.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_add_node.c4
-rw-r--r--cpukit/libfs/src/imfs/imfs_chown.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_eval.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_eval_devfs.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_fchmod.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_fifo.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_linfile.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_link.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_load_tar.c8
-rw-r--r--cpukit/libfs/src/imfs/imfs_make_generic_node.c4
-rw-r--r--cpukit/libfs/src/imfs/imfs_make_linfile.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_memfile.c3
-rw-r--r--cpukit/libfs/src/imfs/imfs_mknod.c4
-rw-r--r--cpukit/libfs/src/imfs/imfs_mount.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_node.c4
-rw-r--r--cpukit/libfs/src/imfs/imfs_node_destroy_default.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_rename.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_rmnod.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_stat.c2
-rw-r--r--cpukit/libfs/src/imfs/imfs_unmount.c2
-rw-r--r--cpukit/libfs/src/imfs/ioman.c2
-rw-r--r--cpukit/libfs/src/jffs2/VERSION3
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/fs.h3
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/jffs2.h8
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/jiffies.h1
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/kernel-rtems.h2
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/list.h8
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h37
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/mtd/rawnand.h26
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/mutex.h2
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/printk.h6
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/rwsem.h12
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/slab.h1
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/workqueue.h32
-rw-r--r--cpukit/libfs/src/jffs2/include/linux/writeback.h1
-rw-r--r--cpukit/libfs/src/jffs2/src/acl.h5
-rw-r--r--cpukit/libfs/src/jffs2/src/build.c4
-rw-r--r--cpukit/libfs/src/jffs2/src/compr.c2
-rw-r--r--cpukit/libfs/src/jffs2/src/compr_rtime.c3
-rw-r--r--cpukit/libfs/src/jffs2/src/debug.h23
-rw-r--r--cpukit/libfs/src/jffs2/src/dir-rtems.c6
-rw-r--r--cpukit/libfs/src/jffs2/src/erase.c6
-rw-r--r--cpukit/libfs/src/jffs2/src/flashio.c75
-rw-r--r--cpukit/libfs/src/jffs2/src/fs-rtems.c208
-rw-r--r--cpukit/libfs/src/jffs2/src/gc.c2
-rw-r--r--cpukit/libfs/src/jffs2/src/jffs2_fs_i.h4
-rw-r--r--cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h6
-rw-r--r--cpukit/libfs/src/jffs2/src/nodelist.h4
-rw-r--r--cpukit/libfs/src/jffs2/src/os-rtems.h77
-rw-r--r--cpukit/libfs/src/jffs2/src/readinode.c16
-rw-r--r--cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h3
-rw-r--r--cpukit/libfs/src/jffs2/src/scan.c32
-rw-r--r--cpukit/libfs/src/jffs2/src/summary.h16
-rw-r--r--cpukit/libfs/src/jffs2/src/wbuf.c1352
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-rtems.c2
85 files changed, 2020 insertions, 152 deletions
diff --git a/cpukit/libfs/src/defaults/default_are_nodes_equal.c b/cpukit/libfs/src/defaults/default_are_nodes_equal.c
index bdcac110d5..2b9ddee13b 100644
--- a/cpukit/libfs/src/defaults/default_are_nodes_equal.c
+++ b/cpukit/libfs/src/defaults/default_are_nodes_equal.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_clone.c b/cpukit/libfs/src/defaults/default_clone.c
index 7d42355fa0..b173a24d1b 100644
--- a/cpukit/libfs/src/defaults/default_clone.c
+++ b/cpukit/libfs/src/defaults/default_clone.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_eval_path.c b/cpukit/libfs/src/defaults/default_eval_path.c
index c2514df93d..2c9e56dbcf 100644
--- a/cpukit/libfs/src/defaults/default_eval_path.c
+++ b/cpukit/libfs/src/defaults/default_eval_path.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_fsync_success.c b/cpukit/libfs/src/defaults/default_fsync_success.c
index bbbeb1c8b8..71267fc5cd 100644
--- a/cpukit/libfs/src/defaults/default_fsync_success.c
+++ b/cpukit/libfs/src/defaults/default_fsync_success.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_ftruncate_directory.c b/cpukit/libfs/src/defaults/default_ftruncate_directory.c
index 33ae65ffcf..94b54064df 100644
--- a/cpukit/libfs/src/defaults/default_ftruncate_directory.c
+++ b/cpukit/libfs/src/defaults/default_ftruncate_directory.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_handlers.c b/cpukit/libfs/src/defaults/default_handlers.c
index 0e61c5a24c..134d42d81b 100644
--- a/cpukit/libfs/src/defaults/default_handlers.c
+++ b/cpukit/libfs/src/defaults/default_handlers.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2010 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2010 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_kqfilter.c b/cpukit/libfs/src/defaults/default_kqfilter.c
index 3f060845fd..97c61c3391 100644
--- a/cpukit/libfs/src/defaults/default_kqfilter.c
+++ b/cpukit/libfs/src/defaults/default_kqfilter.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2013, 2017 embedded brains GmbH. All rights reserved.
+ * Copyright (C) 2013, 2017 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_lock_and_unlock.c b/cpukit/libfs/src/defaults/default_lock_and_unlock.c
index 584614a8cf..a45af94a88 100644
--- a/cpukit/libfs/src/defaults/default_lock_and_unlock.c
+++ b/cpukit/libfs/src/defaults/default_lock_and_unlock.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_lseek_directory.c b/cpukit/libfs/src/defaults/default_lseek_directory.c
index 4b80c164e3..69ef3cc820 100644
--- a/cpukit/libfs/src/defaults/default_lseek_directory.c
+++ b/cpukit/libfs/src/defaults/default_lseek_directory.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_lseek_file.c b/cpukit/libfs/src/defaults/default_lseek_file.c
index e3901b5f9c..91d48e8cd4 100644
--- a/cpukit/libfs/src/defaults/default_lseek_file.c
+++ b/cpukit/libfs/src/defaults/default_lseek_file.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_ops.c b/cpukit/libfs/src/defaults/default_ops.c
index 45069e76d7..35290ae6af 100644
--- a/cpukit/libfs/src/defaults/default_ops.c
+++ b/cpukit/libfs/src/defaults/default_ops.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (C) 2010 embedded brains GmbH
+ * Copyright (C) 2010 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_poll.c b/cpukit/libfs/src/defaults/default_poll.c
index afa09c2c20..5fa94c2de9 100644
--- a/cpukit/libfs/src/defaults/default_poll.c
+++ b/cpukit/libfs/src/defaults/default_poll.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2013, 2017 embedded brains GmbH. All rights reserved.
+ * Copyright (C) 2013, 2017 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_readv.c b/cpukit/libfs/src/defaults/default_readv.c
index 40db4f3054..797426c9c3 100644
--- a/cpukit/libfs/src/defaults/default_readv.c
+++ b/cpukit/libfs/src/defaults/default_readv.c
@@ -12,7 +12,7 @@
* COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
- * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/defaults/default_writev.c b/cpukit/libfs/src/defaults/default_writev.c
index 31c1c76da2..908bb7edc4 100644
--- a/cpukit/libfs/src/defaults/default_writev.c
+++ b/cpukit/libfs/src/defaults/default_writev.c
@@ -12,7 +12,7 @@
* COPYRIGHT (c) 1989-2011.
* On-Line Applications Research Corporation (OAR).
*
- * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c
index 9229406dec..88b4a2859b 100644
--- a/cpukit/libfs/src/dosfs/fat.c
+++ b/cpukit/libfs/src/dosfs/fat.c
@@ -93,7 +93,6 @@ fat_buf_release(fat_fs_info_t *fs_info)
uint32_t sec_num = fs_info->c.blk_num;
bool sec_of_fat = ((sec_num >= fs_info->vol.fat_loc) &&
(sec_num < fs_info->vol.rdir_loc));
- uint32_t blk = fat_sector_num_to_block_num(fs_info, sec_num);
uint32_t blk_ofs = fat_sector_offset_to_block_offset(fs_info,
sec_num,
0);
@@ -115,6 +114,7 @@ fat_buf_release(fat_fs_info_t *fs_info)
for (i = 1; i < fs_info->vol.fats; i++)
{
rtems_bdbuf_buffer *bd;
+ uint32_t blk;
sec_num = fs_info->c.blk_num + fs_info->vol.fat_length * i,
blk = fat_sector_num_to_block_num(fs_info, sec_num);
diff --git a/cpukit/libfs/src/dosfs/fat_fat_operations.c b/cpukit/libfs/src/dosfs/fat_fat_operations.c
index 24a408f9c7..fe6bbf03ce 100644
--- a/cpukit/libfs/src/dosfs/fat_fat_operations.c
+++ b/cpukit/libfs/src/dosfs/fat_fat_operations.c
@@ -203,9 +203,9 @@ fat_free_fat_clusters_chain(
cur_cln = next_cln;
}
- fs_info->vol.next_cl = chain;
- if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
- fs_info->vol.free_cls += freed_cls_cnt;
+ fs_info->vol.next_cl = chain;
+ if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
+ fs_info->vol.free_cls += freed_cls_cnt;
fat_buf_release(fs_info);
if (rc1 != RC_OK)
@@ -356,7 +356,7 @@ fat_set_fat_cluster(
if (rc != RC_OK)
return rc;
- *sec_buf &= 0x00;
+ *sec_buf = 0x00;
*sec_buf |= (uint8_t)((fat16_clv & 0xFF00)>>8);
@@ -364,7 +364,7 @@ fat_set_fat_cluster(
}
else
{
- *(sec_buf + ofs + 1) &= 0x00;
+ *(sec_buf + ofs + 1) = 0x00;
*(sec_buf + ofs + 1) |= (uint8_t )((fat16_clv & 0xFF00)>>8);
}
@@ -372,7 +372,7 @@ fat_set_fat_cluster(
else
{
fat16_clv = ((uint16_t )in_val) & FAT_FAT12_MASK;
- *(sec_buf + ofs) &= 0x00;
+ *(sec_buf + ofs) = 0x00;
*(sec_buf + ofs) |= (uint8_t)(fat16_clv & 0x00FF);
diff --git a/cpukit/libfs/src/dosfs/msdos.h b/cpukit/libfs/src/dosfs/msdos.h
index df9600a02d..e6d650c8d5 100644
--- a/cpukit/libfs/src/dosfs/msdos.h
+++ b/cpukit/libfs/src/dosfs/msdos.h
@@ -11,7 +11,7 @@
* Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
*
* Modifications to support UTF-8 in the file system are
- * Copyright (c) 2013 embedded brains GmbH.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -72,12 +72,12 @@ typedef struct msdos_fs_info_s
rtems_dosfs_convert_control *converter;
} msdos_fs_info_t;
-RTEMS_INLINE_ROUTINE void msdos_fs_lock(msdos_fs_info_t *fs_info)
+static inline void msdos_fs_lock(msdos_fs_info_t *fs_info)
{
rtems_recursive_mutex_lock(&fs_info->vol_mutex);
}
-RTEMS_INLINE_ROUTINE void msdos_fs_unlock(msdos_fs_info_t *fs_info)
+static inline void msdos_fs_unlock(msdos_fs_info_t *fs_info)
{
rtems_recursive_mutex_unlock(&fs_info->vol_mutex);
}
diff --git a/cpukit/libfs/src/dosfs/msdos_conv.c b/cpukit/libfs/src/dosfs/msdos_conv.c
index 7efd5a7e80..ba28a07512 100644
--- a/cpukit/libfs/src/dosfs/msdos_conv.c
+++ b/cpukit/libfs/src/dosfs/msdos_conv.c
@@ -25,7 +25,7 @@
* October 1992
*
* Modifications to support UTF-8 in the file system are
- * Copyright (c) 2013 embedded brains GmbH.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*/
#ifdef HAVE_CONFIG_H
diff --git a/cpukit/libfs/src/dosfs/msdos_conv_default.c b/cpukit/libfs/src/dosfs/msdos_conv_default.c
index 2a42738db0..43cff88c6c 100644
--- a/cpukit/libfs/src/dosfs/msdos_conv_default.c
+++ b/cpukit/libfs/src/dosfs/msdos_conv_default.c
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
diff --git a/cpukit/libfs/src/dosfs/msdos_conv_utf8.c b/cpukit/libfs/src/dosfs/msdos_conv_utf8.c
index 332d33d2dc..36027eb2f3 100644
--- a/cpukit/libfs/src/dosfs/msdos_conv_utf8.c
+++ b/cpukit/libfs/src/dosfs/msdos_conv_utf8.c
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
diff --git a/cpukit/libfs/src/dosfs/msdos_create.c b/cpukit/libfs/src/dosfs/msdos_create.c
index 26df0451c9..f71969f787 100644
--- a/cpukit/libfs/src/dosfs/msdos_create.c
+++ b/cpukit/libfs/src/dosfs/msdos_create.c
@@ -202,7 +202,7 @@ msdos_creat_node(const rtems_filesystem_location_info_t *parent_loc,
fs_info->fat.vol.bpc,
&unused);
if (rc != RC_OK)
- goto err;
+ goto error;
/*
* dot and dotdot entries are identical to new node except the
diff --git a/cpukit/libfs/src/dosfs/msdos_dir.c b/cpukit/libfs/src/dosfs/msdos_dir.c
index 093020cbfd..d9585635d9 100644
--- a/cpukit/libfs/src/dosfs/msdos_dir.c
+++ b/cpukit/libfs/src/dosfs/msdos_dir.c
@@ -11,7 +11,7 @@
* Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
*
* Modifications to support UTF-8 in the file system are
- * Copyright (c) 2013 embedded brains GmbH.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -339,14 +339,14 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
iop->offset = iop->offset + sizeof(struct dirent);
cmpltd += (sizeof(struct dirent));
count -= (sizeof(struct dirent));
+ }
- /* inode number extracted, close fat-file */
- rc = fat_file_close(&fs_info->fat, tmp_fat_fd);
- if (rc != RC_OK)
- {
- msdos_fs_unlock(fs_info);
- return rc;
- }
+ /* inode number extracted, close fat-file */
+ rc = fat_file_close(&fs_info->fat, tmp_fat_fd);
+ if (rc != RC_OK)
+ {
+ msdos_fs_unlock(fs_info);
+ return rc;
}
}
diff --git a/cpukit/libfs/src/dosfs/msdos_file.c b/cpukit/libfs/src/dosfs/msdos_file.c
index d142968337..e25f292484 100644
--- a/cpukit/libfs/src/dosfs/msdos_file.c
+++ b/cpukit/libfs/src/dosfs/msdos_file.c
@@ -179,7 +179,7 @@ msdos_file_ftruncate(rtems_libio_t *iop, off_t length)
length,
&new_length);
if (rc == RC_OK && length != new_length) {
- fat_file_truncate(&fs_info->fat, fat_fd, old_length);
+ (void) fat_file_truncate(&fs_info->fat, fat_fd, old_length);
errno = ENOSPC;
rc = -1;
}
@@ -223,6 +223,11 @@ msdos_file_sync(rtems_libio_t *iop)
}
rc = fat_sync(&fs_info->fat);
+ if (rc != RC_OK)
+ {
+ msdos_fs_unlock(fs_info);
+ return rc;
+ }
msdos_fs_unlock(fs_info);
diff --git a/cpukit/libfs/src/dosfs/msdos_init.c b/cpukit/libfs/src/dosfs/msdos_init.c
index 36f1442a26..2ea3c025c7 100644
--- a/cpukit/libfs/src/dosfs/msdos_init.c
+++ b/cpukit/libfs/src/dosfs/msdos_init.c
@@ -11,10 +11,10 @@
* Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Modifications to support UTF-8 in the file system are
- * Copyright (c) 2013 embedded brains GmbH.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c
index a82389bc42..cd59c494ea 100644
--- a/cpukit/libfs/src/dosfs/msdos_misc.c
+++ b/cpukit/libfs/src/dosfs/msdos_misc.c
@@ -11,7 +11,7 @@
* Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
*
* Modifications to support UTF-8 in the file system are
- * Copyright (c) 2013 embedded brains GmbH.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -288,7 +288,6 @@ msdos_long_to_short(rtems_dosfs_convert_control *converter,
&codepage_name_len);
if (eno == EINVAL)
{
- eno = 0;
type = MSDOS_NAME_LONG;
}
else
@@ -1304,7 +1303,6 @@ static int
msdos_find_file_in_directory (
const uint8_t *filename_converted,
const size_t name_len_for_compare,
- const size_t name_len_for_save,
const msdos_name_type_t name_type,
msdos_fs_info_t *fs_info,
fat_file_fd_t *fat_fd,
@@ -1747,6 +1745,8 @@ msdos_add_file (
/* Get position of short file name entry */
ret = msdos_get_pos(fs_info, fat_fd, bts2rd, short_file_offset,
&dir_pos->sname);
+ if (ret != RC_OK)
+ return ret;
/*
* Handle the entry writes.
@@ -1918,7 +1918,6 @@ msdos_find_name_in_fat_file (
retval = msdos_find_file_in_directory (
buffer,
name_len_for_compare,
- name_len_for_save,
name_type,
fs_info,
fat_fd,
diff --git a/cpukit/libfs/src/dosfs/msdos_mknod.c b/cpukit/libfs/src/dosfs/msdos_mknod.c
index 934805c5f1..8fe01e4985 100644
--- a/cpukit/libfs/src/dosfs/msdos_mknod.c
+++ b/cpukit/libfs/src/dosfs/msdos_mknod.c
@@ -44,7 +44,7 @@ int msdos_mknod(
)
{
int rc = RC_OK;
- fat_file_type_t type = 0;
+ fat_file_type_t type = FAT_DIRECTORY;
/*
* Figure out what type of msdos node this is.
diff --git a/cpukit/libfs/src/ftpfs/ftpfs.c b/cpukit/libfs/src/ftpfs/ftpfs.c
index 06d06bc9cc..cec30f9071 100644
--- a/cpukit/libfs/src/ftpfs/ftpfs.c
+++ b/cpukit/libfs/src/ftpfs/ftpfs.c
@@ -7,7 +7,7 @@
*/
/*
- * COPYRIGHT (C) 2009-2012 embedded brains GmbH.
+ * COPYRIGHT (C) 2009-2012 embedded brains GmbH & Co. KG
* COPYRIGHT (C) 2002 IMD Ingenieurbuero fuer Microcomputertechnik.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/cpukit/libfs/src/ftpfs/tftpDriver.c b/cpukit/libfs/src/ftpfs/tftpDriver.c
index 59136ef59f..5d9fa12000 100644
--- a/cpukit/libfs/src/ftpfs/tftpDriver.c
+++ b/cpukit/libfs/src/ftpfs/tftpDriver.c
@@ -22,7 +22,7 @@
/*
* Copyright (C) 1998 W. Eric Norum <eric@norum.ca>
- * Copyright (C) 2012, 2022 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2012, 2022 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -525,8 +525,10 @@ static void send_error (
/*
* Send it
+ *
+ * Ignoring result because error packets are sent once and maybe lost.
*/
- sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
+ (void) sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
}
/*
@@ -552,11 +554,21 @@ getPacket (struct tftpStream *tp, int retryCount)
} else if (retryCount == 0) {
tv.tv_sec = tp->config.first_timeout / 1000L;
tv.tv_usec = (tp->config.first_timeout % 1000L) * 1000L;
- setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
+ /*
+ * Ignoring result because all possible errors indicate wrong
+ * arguments and these arguments are OK as tested by test suite.
+ */
+ (void) setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv,
+ sizeof tv);
} else {
tv.tv_sec = tp->config.timeout / 1000L;
tv.tv_usec = (tp->config.timeout % 1000L) * 1000L;
- setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
+ /*
+ * Ignoring result because all possible errors indicate wrong
+ * arguments and these arguments are OK as tested by test suite.
+ */
+ (void) setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv,
+ sizeof tv);
}
for (;;) {
union {
@@ -591,7 +603,12 @@ getPacket (struct tftpStream *tp, int retryCount)
if (retryCount != GET_PACKET_DONT_WAIT) {
tv.tv_sec = 0;
tv.tv_usec = 0;
- setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
+ /*
+ * Ignoring result because all possible errors indicate wrong
+ * arguments and these arguments are OK as tested by test suite.
+ */
+ (void) setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv,
+ sizeof tv);
}
return len;
}
@@ -724,7 +741,7 @@ static int process_data_packet (struct tftpStream *tp, ssize_t len)
/*
* Send it. Errors during send will not matter for this last ACK.
*/
- sendto (
+ (void) sendto (
tp->socket,
send_buf,
plen,
diff --git a/cpukit/libfs/src/ftpfs/tftp_driver.h b/cpukit/libfs/src/ftpfs/tftp_driver.h
index 949bea1820..690ff415f6 100644
--- a/cpukit/libfs/src/ftpfs/tftp_driver.h
+++ b/cpukit/libfs/src/ftpfs/tftp_driver.h
@@ -13,7 +13,7 @@
*/
/*
- * Copyright (C) 2022 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2022 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/ftpfs/tftpfs.c b/cpukit/libfs/src/ftpfs/tftpfs.c
index b699694117..1fa39c96f2 100644
--- a/cpukit/libfs/src/ftpfs/tftpfs.c
+++ b/cpukit/libfs/src/ftpfs/tftpfs.c
@@ -17,7 +17,7 @@
/*
* Copyright (C) 1998 W. Eric Norum <eric@norum.ca>
- * Copyright (C) 2012, 2022 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2012, 2022 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/imfs_add_node.c b/cpukit/libfs/src/imfs/imfs_add_node.c
index 814736284d..2fd25fcc46 100644
--- a/cpukit/libfs/src/imfs/imfs_add_node.c
+++ b/cpukit/libfs/src/imfs/imfs_add_node.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2020 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,7 +37,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
int IMFS_add_node( const char *path, IMFS_jnode_t *node, void *arg )
{
diff --git a/cpukit/libfs/src/imfs/imfs_chown.c b/cpukit/libfs/src/imfs/imfs_chown.c
index 5a0049ba2d..20210470a1 100644
--- a/cpukit/libfs/src/imfs/imfs_chown.c
+++ b/cpukit/libfs/src/imfs/imfs_chown.c
@@ -38,7 +38,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
#include <unistd.h>
diff --git a/cpukit/libfs/src/imfs/imfs_eval.c b/cpukit/libfs/src/imfs/imfs_eval.c
index bb71fe1a3b..e20a85b5d5 100644
--- a/cpukit/libfs/src/imfs/imfs_eval.c
+++ b/cpukit/libfs/src/imfs/imfs_eval.c
@@ -13,7 +13,7 @@
* On-Line Applications Research Corporation (OAR).
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/imfs_eval_devfs.c b/cpukit/libfs/src/imfs/imfs_eval_devfs.c
index 69c8cc4c0f..1eea1c7dd8 100644
--- a/cpukit/libfs/src/imfs/imfs_eval_devfs.c
+++ b/cpukit/libfs/src/imfs/imfs_eval_devfs.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2020 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/imfs_fchmod.c b/cpukit/libfs/src/imfs/imfs_fchmod.c
index 7f885a1987..6f6c57ff23 100644
--- a/cpukit/libfs/src/imfs/imfs_fchmod.c
+++ b/cpukit/libfs/src/imfs/imfs_fchmod.c
@@ -38,7 +38,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
int IMFS_fchmod(
const rtems_filesystem_location_info_t *loc,
diff --git a/cpukit/libfs/src/imfs/imfs_fifo.c b/cpukit/libfs/src/imfs/imfs_fifo.c
index a3154e18bd..be86187663 100644
--- a/cpukit/libfs/src/imfs/imfs_fifo.c
+++ b/cpukit/libfs/src/imfs/imfs_fifo.c
@@ -37,7 +37,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
#include <sys/filio.h>
diff --git a/cpukit/libfs/src/imfs/imfs_linfile.c b/cpukit/libfs/src/imfs/imfs_linfile.c
index 4f961d19e8..c9b1ec9e90 100644
--- a/cpukit/libfs/src/imfs/imfs_linfile.c
+++ b/cpukit/libfs/src/imfs/imfs_linfile.c
@@ -38,7 +38,7 @@
#include <string.h>
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
static ssize_t IMFS_linfile_read(
rtems_libio_t *iop,
diff --git a/cpukit/libfs/src/imfs/imfs_link.c b/cpukit/libfs/src/imfs/imfs_link.c
index 301a280211..3ea05b0807 100644
--- a/cpukit/libfs/src/imfs/imfs_link.c
+++ b/cpukit/libfs/src/imfs/imfs_link.c
@@ -38,7 +38,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
static const IMFS_node_control IMFS_node_control_hard_link;
diff --git a/cpukit/libfs/src/imfs/imfs_load_tar.c b/cpukit/libfs/src/imfs/imfs_load_tar.c
index ec651d820a..18c5366b56 100644
--- a/cpukit/libfs/src/imfs/imfs_load_tar.c
+++ b/cpukit/libfs/src/imfs/imfs_load_tar.c
@@ -45,7 +45,7 @@
int rtems_tarfs_load(
const char *mountpoint,
- uint8_t *tar_image,
+ const void *tar_image,
size_t tar_size
)
{
@@ -57,6 +57,7 @@ int rtems_tarfs_load(
size_t len;
Untar_HeaderContext ctx;
unsigned long ptr;
+ const uint8_t *image;
len = strlen( mountpoint );
if ( len >= sizeof( buf ) - UNTAR_FILE_NAME_SIZE - 2 ) {
@@ -82,11 +83,12 @@ int rtems_tarfs_load(
}
ptr = 0;
+ image = tar_image;
while ( ptr + 512 <= tar_size ) {
int retval;
- retval = Untar_ProcessHeader( &ctx, (const char *) &tar_image[ ptr ] );
+ retval = Untar_ProcessHeader( &ctx, (const char *) &image[ ptr ] );
if ( retval != UNTAR_SUCCESSFUL ) {
return -1;
}
@@ -97,7 +99,7 @@ int rtems_tarfs_load(
retval = IMFS_make_linearfile(
ctx.file_path,
ctx.mode,
- &tar_image[ ptr ],
+ &image[ ptr ],
ctx.file_size
);
if ( retval != 0 ) {
diff --git a/cpukit/libfs/src/imfs/imfs_make_generic_node.c b/cpukit/libfs/src/imfs/imfs_make_generic_node.c
index abecf5ec53..73c44e31db 100644
--- a/cpukit/libfs/src/imfs/imfs_make_generic_node.c
+++ b/cpukit/libfs/src/imfs/imfs_make_generic_node.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (c) 2012 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,7 +37,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
#include <string.h>
diff --git a/cpukit/libfs/src/imfs/imfs_make_linfile.c b/cpukit/libfs/src/imfs/imfs_make_linfile.c
index 0a81e3848d..30a3e76117 100644
--- a/cpukit/libfs/src/imfs/imfs_make_linfile.c
+++ b/cpukit/libfs/src/imfs/imfs_make_linfile.c
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (C) 2019 embedded brains GmbH
+ * Copyright (C) 2019 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/imfs_memfile.c b/cpukit/libfs/src/imfs/imfs_memfile.c
index 769a570ecf..3930fd6ae5 100644
--- a/cpukit/libfs/src/imfs/imfs_memfile.c
+++ b/cpukit/libfs/src/imfs/imfs_memfile.c
@@ -38,7 +38,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
#include <stdlib.h>
#include <string.h>
@@ -638,7 +638,6 @@ ssize_t IMFS_memfile_write(
fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src );
#endif
memcpy( &(*block_ptr)[ 0 ], src, my_length );
- my_length = 0;
copied += to_copy;
}
diff --git a/cpukit/libfs/src/imfs/imfs_mknod.c b/cpukit/libfs/src/imfs/imfs_mknod.c
index 17aa1d3802..7c708f9fa8 100644
--- a/cpukit/libfs/src/imfs/imfs_mknod.c
+++ b/cpukit/libfs/src/imfs/imfs_mknod.c
@@ -13,7 +13,7 @@
* On-Line Applications Research Corporation (OAR).
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,7 +41,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
static const IMFS_mknod_control *get_control(
const IMFS_mknod_controls *controls,
diff --git a/cpukit/libfs/src/imfs/imfs_mount.c b/cpukit/libfs/src/imfs/imfs_mount.c
index ba4e258f7a..c35f9f96f4 100644
--- a/cpukit/libfs/src/imfs/imfs_mount.c
+++ b/cpukit/libfs/src/imfs/imfs_mount.c
@@ -13,7 +13,7 @@
* On-Line Applications Research Corporation (OAR).
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/imfs_node.c b/cpukit/libfs/src/imfs/imfs_node.c
index 91bd89d66c..7d2308fe1d 100644
--- a/cpukit/libfs/src/imfs/imfs_node.c
+++ b/cpukit/libfs/src/imfs/imfs_node.c
@@ -13,7 +13,7 @@
* On-Line Applications Research Corporation (OAR).
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,7 +41,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
IMFS_jnode_t *IMFS_initialize_node(
IMFS_jnode_t *node,
diff --git a/cpukit/libfs/src/imfs/imfs_node_destroy_default.c b/cpukit/libfs/src/imfs/imfs_node_destroy_default.c
index 84f06a30fb..852baaf305 100644
--- a/cpukit/libfs/src/imfs/imfs_node_destroy_default.c
+++ b/cpukit/libfs/src/imfs/imfs_node_destroy_default.c
@@ -9,7 +9,7 @@
*/
/*
- * Copyright (C) 2014 embedded brains GmbH (http://www.embedded-brains.de)
+ * Copyright (C) 2014 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/imfs_rename.c b/cpukit/libfs/src/imfs/imfs_rename.c
index d925591b32..94876d9217 100644
--- a/cpukit/libfs/src/imfs/imfs_rename.c
+++ b/cpukit/libfs/src/imfs/imfs_rename.c
@@ -38,7 +38,7 @@
#include "config.h"
#endif
-#include <rtems/imfs.h>
+#include <rtems/imfsimpl.h>
#include <string.h>
#include <stdlib.h>
diff --git a/cpukit/libfs/src/imfs/imfs_rmnod.c b/cpukit/libfs/src/imfs/imfs_rmnod.c
index 121283cdd9..ed60baeff3 100644
--- a/cpukit/libfs/src/imfs/imfs_rmnod.c
+++ b/cpukit/libfs/src/imfs/imfs_rmnod.c
@@ -13,7 +13,7 @@
* On-Line Applications Research Corporation (OAR).
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/imfs_stat.c b/cpukit/libfs/src/imfs/imfs_stat.c
index 260f0ade02..82bf40e07d 100644
--- a/cpukit/libfs/src/imfs/imfs_stat.c
+++ b/cpukit/libfs/src/imfs/imfs_stat.c
@@ -13,7 +13,7 @@
* On-Line Applications Research Corporation (OAR).
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/imfs_unmount.c b/cpukit/libfs/src/imfs/imfs_unmount.c
index 448573b63a..b4289e0f9d 100644
--- a/cpukit/libfs/src/imfs/imfs_unmount.c
+++ b/cpukit/libfs/src/imfs/imfs_unmount.c
@@ -13,7 +13,7 @@
* On-Line Applications Research Corporation (OAR).
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/imfs/ioman.c b/cpukit/libfs/src/imfs/ioman.c
index a9958b5c82..cc04fd7136 100644
--- a/cpukit/libfs/src/imfs/ioman.c
+++ b/cpukit/libfs/src/imfs/ioman.c
@@ -13,7 +13,7 @@
* On-Line Applications Research Corporation (OAR).
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/cpukit/libfs/src/jffs2/VERSION b/cpukit/libfs/src/jffs2/VERSION
index b13bed5750..7302f10ef6 100644
--- a/cpukit/libfs/src/jffs2/VERSION
+++ b/cpukit/libfs/src/jffs2/VERSION
@@ -3,7 +3,7 @@ This directory contains a port of the JFFS2 file system from Linux v5.9.
To update to a newer Linux version use this command in a Git clone of Linux to
generate the relevant patches:
- git format-patch v5.9..v9.99 --
+ git format-patch v6.1..v9.99 -- \
include/uapi/linux/jffs2.h \
fs/jffs2/LICENCE \
fs/jffs2/acl.h \
@@ -26,6 +26,7 @@ generate the relevant patches:
fs/jffs2/readinode.c \
fs/jffs2/scan.c \
fs/jffs2/summary.h \
+ fs/jffs2/wbuf.c \
fs/jffs2/write.c \
fs/jffs2/xattr.h
diff --git a/cpukit/libfs/src/jffs2/include/linux/fs.h b/cpukit/libfs/src/jffs2/include/linux/fs.h
index a638e7b6bf..9e40d105dc 100644
--- a/cpukit/libfs/src/jffs2/include/linux/fs.h
+++ b/cpukit/libfs/src/jffs2/include/linux/fs.h
@@ -34,4 +34,7 @@ struct iattr {
time_t ia_ctime;
};
+#define SB_RDONLY 1
+#define sb_rdonly(sb) ((sb)->s_flags & SB_RDONLY)
+
#endif /* __LINUX_FS_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/jffs2.h b/cpukit/libfs/src/jffs2/include/linux/jffs2.h
index 784ba0b969..637ee4a793 100644
--- a/cpukit/libfs/src/jffs2/include/linux/jffs2.h
+++ b/cpukit/libfs/src/jffs2/include/linux/jffs2.h
@@ -123,7 +123,7 @@ struct jffs2_raw_dirent
__u8 unused[2];
jint32_t node_crc;
jint32_t name_crc;
- __u8 name[0];
+ __u8 name[];
};
/* The JFFS2 raw inode structure: Used for storage on physical media. */
@@ -155,7 +155,7 @@ struct jffs2_raw_inode
jint16_t flags; /* See JFFS2_INO_FLAG_* */
jint32_t data_crc; /* CRC for the (compressed) data. */
jint32_t node_crc; /* CRC for the raw inode (excluding data) */
- __u8 data[0];
+ __u8 data[];
};
struct jffs2_raw_xattr {
@@ -170,7 +170,7 @@ struct jffs2_raw_xattr {
jint16_t value_len;
jint32_t data_crc;
jint32_t node_crc;
- __u8 data[0];
+ __u8 data[];
} __attribute__((packed));
struct jffs2_raw_xref
@@ -196,7 +196,7 @@ struct jffs2_raw_summary
jint32_t padded; /* sum of the size of padding nodes */
jint32_t sum_crc; /* summary information crc */
jint32_t node_crc; /* node crc */
- jint32_t sum[0]; /* inode summary info */
+ jint32_t sum[]; /* inode summary info */
};
union jffs2_node_union
diff --git a/cpukit/libfs/src/jffs2/include/linux/jiffies.h b/cpukit/libfs/src/jffs2/include/linux/jiffies.h
new file mode 100644
index 0000000000..77debb5d27
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/jiffies.h
@@ -0,0 +1 @@
+#include <linux/workqueue.h>
diff --git a/cpukit/libfs/src/jffs2/include/linux/kernel-rtems.h b/cpukit/libfs/src/jffs2/include/linux/kernel-rtems.h
index eb5f422116..ed46ce2391 100644
--- a/cpukit/libfs/src/jffs2/include/linux/kernel-rtems.h
+++ b/cpukit/libfs/src/jffs2/include/linux/kernel-rtems.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2013 embedded brains GmbH & Co. KG
*
* Copyright 2016 Chris Johns <chrisj@rtems.org>
*
diff --git a/cpukit/libfs/src/jffs2/include/linux/list.h b/cpukit/libfs/src/jffs2/include/linux/list.h
index 4dc8a5a6b7..efb7fb8019 100644
--- a/cpukit/libfs/src/jffs2/include/linux/list.h
+++ b/cpukit/libfs/src/jffs2/include/linux/list.h
@@ -139,6 +139,14 @@ list_empty( struct list_head *list )
(_ent_) != (_list_); \
(_ent_) = (_ent_)->next )
+/* list_for_each_safe - using _ent_, iterate through list _list_
+ while protecting against removal of list elements */
+
+#define list_for_each_safe( _ent_, _tmp_, _list_ ) \
+ for ( (_ent_) = (_list_)->next, (_tmp_) = (_ent_)->next; \
+ (_ent_) != (_list_); \
+ (_ent_) = (_tmp_), (_tmp_) = (_ent_)->next )
+
/*
* list_for_each_entry - this function can be use to iterate over all
* items in a list* _list_ with it's head at _head_ and link _item_
diff --git a/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h b/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
index bcf0a9aa70..548201483f 100644
--- a/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
+++ b/cpukit/libfs/src/jffs2/include/linux/mtd/mtd.h
@@ -6,6 +6,14 @@
#define MTD_FAIL_ADDR_UNKNOWN -1LL
+struct mtd_info {
+ uint32_t oobavail;
+ uint32_t oobsize;
+ uint32_t size;
+ uint32_t erasesize;
+ uint32_t writesize;
+};
+
static inline int do_mtd_point(size_t *retlen, void **ebuf)
{
*retlen = 0;
@@ -20,4 +28,33 @@ static inline int do_mtd_point(size_t *retlen, void **ebuf)
#define mtd_kmalloc_up_to(a, b) kmalloc(*(b), GFP_KERNEL)
+struct mtd_oob_ops {
+ uint32_t mode;
+ size_t len;
+ size_t retlen;
+ size_t ooblen;
+ size_t oobretlen;
+ uint32_t ooboffs;
+ uint8_t *datbuf;
+ uint8_t *oobbuf;
+};
+
+#define EUCLEAN EAGAIN
+static inline int mtd_is_bitflip(int err) { return (err == -EUCLEAN); }
+
+#define mtd_block_isbad(mtd_sp, offset) ({ \
+ bool bad; \
+ int sc = jffs2_flash_block_is_bad(RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd), offset, &bad); \
+ if (sc) { \
+ return sc; \
+ } \
+ bad; \
+})
+#define mtd_block_markbad(mtd_sp, offset) \
+ jffs2_flash_block_mark_bad(RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd), offset)
+#define mtd_write(mtd_sp, ofs, len, retlen, buf) \
+ jffs2_flash_direct_write(RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd), ofs, len, retlen, buf)
+#define mtd_read(mtd_sp, ofs, len, retlen, buf) \
+ jffs2_flash_direct_read(RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd), ofs, len, retlen, buf)
+
#endif /* __LINUX_MTD_MTD_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/mtd/rawnand.h b/cpukit/libfs/src/jffs2/include/linux/mtd/rawnand.h
new file mode 100644
index 0000000000..fe47ba6fbf
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/mtd/rawnand.h
@@ -0,0 +1,26 @@
+#ifndef __LINUX_MTD_RAWNAND_H__
+#define __LINUX_MTD_RAWNAND_H__
+
+#define mtd_read_oob(mtd_sp, offset, ops) ({ \
+ struct jffs2_sb_info *sb_info = RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd); \
+ int sc = jffs2_flash_oob_read(sb_info, offset, (ops)->oobbuf, (ops)->ooblen); \
+ if (sc) { \
+ sc = -EIO; \
+ } else { \
+ (ops)->oobretlen = (ops)->ooblen; \
+ } \
+ sc; \
+})
+#define mtd_write_oob(mtd_sp, offset, ops) ({ \
+ struct jffs2_sb_info *sb_info = RTEMS_CONTAINER_OF(&(mtd_sp), struct jffs2_sb_info, mtd); \
+ int sc = jffs2_flash_oob_write(sb_info, offset, (ops)->oobbuf, (ops)->ooblen); \
+ if (sc != RTEMS_SUCCESSFUL) { \
+ sc = -EIO; \
+ } else { \
+ (ops)->oobretlen = (ops)->ooblen; \
+ } \
+ sc; \
+})
+#define MTD_OPS_AUTO_OOB 1
+
+#endif /* __LINUX_MTD_RAWNAND_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/mutex.h b/cpukit/libfs/src/jffs2/include/linux/mutex.h
index f5e1efb1af..cc82a3f17a 100644
--- a/cpukit/libfs/src/jffs2/include/linux/mutex.h
+++ b/cpukit/libfs/src/jffs2/include/linux/mutex.h
@@ -26,4 +26,6 @@ static inline void mutex_unlock(struct mutex *m)
(void) m;
}
+#define mutex_is_locked(m) 1
+
#endif
diff --git a/cpukit/libfs/src/jffs2/include/linux/printk.h b/cpukit/libfs/src/jffs2/include/linux/printk.h
new file mode 100644
index 0000000000..515188faa1
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/printk.h
@@ -0,0 +1,6 @@
+#ifndef __LINUX_PRINTK_H__
+#define __LINUX_PRINTK_H__
+
+#define no_printk(fmt, ...) do { } while (0)
+
+#endif /* __LINUX_PRINTK_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/rwsem.h b/cpukit/libfs/src/jffs2/include/linux/rwsem.h
index 57bfdf13b7..e59e1cede3 100644
--- a/cpukit/libfs/src/jffs2/include/linux/rwsem.h
+++ b/cpukit/libfs/src/jffs2/include/linux/rwsem.h
@@ -1,6 +1,16 @@
#ifndef __LINUX_RWSEM_H__
#define __LINUX_RWSEM_H__
-struct rw_semaphore;
+struct rw_semaphore {};
+
+#define init_rwsem(rwsem)
+
+#define down_read(rwsem)
+
+#define down_write(rwsem)
+
+#define up_read(rwsem)
+
+#define up_write(rwsem)
#endif /* __LINUX_RWSEM_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/slab.h b/cpukit/libfs/src/jffs2/include/linux/slab.h
index 532586e210..d664f50dfb 100644
--- a/cpukit/libfs/src/jffs2/include/linux/slab.h
+++ b/cpukit/libfs/src/jffs2/include/linux/slab.h
@@ -7,6 +7,7 @@
#define kzalloc(x, y) calloc(1, x)
#define kmalloc(x, y) malloc(x)
+#define kmalloc_array(x, y, z) kmalloc((x * y), z)
#define kfree(x) free(x)
#define kvfree(x) free(x)
#define vmalloc(x) malloc(x)
diff --git a/cpukit/libfs/src/jffs2/include/linux/workqueue.h b/cpukit/libfs/src/jffs2/include/linux/workqueue.h
index 90d98288af..9811c7cd3e 100644
--- a/cpukit/libfs/src/jffs2/include/linux/workqueue.h
+++ b/cpukit/libfs/src/jffs2/include/linux/workqueue.h
@@ -1,10 +1,34 @@
#ifndef __LINUX_WORKQUEUE_H__
#define __LINUX_WORKQUEUE_H__
-struct work_struct { } ;
+#include <rtems/chain.h>
+#include <linux/mutex.h>
-#define INIT_WORK(x,y,z) /* */
-#define schedule_work(x) do { } while(0)
-#define flush_scheduled_work() do { } while(0)
+struct work_struct { rtems_chain_node node; };
+
+#define queue_delayed_work(workqueue, delayed_work, delay_ms) ({ \
+ jffs2_queue_delayed_work(delayed_work, delay_ms); \
+ 0; \
+})
+
+#define INIT_DELAYED_WORK(delayed_work, delayed_workqueue_callback) ({ \
+ (delayed_work)->callback = delayed_workqueue_callback; \
+})
+
+#define msecs_to_jiffies(a) (a)
+
+typedef void (*work_callback_t)(struct work_struct *work);
+struct delayed_work {
+ struct work_struct work;
+ struct mutex dw_mutex;
+ volatile bool pending;
+ volatile uint64_t execution_time;
+ work_callback_t callback;
+ /* Superblock provided for locking */
+ struct super_block *sb;
+};
+
+#define to_delayed_work(work) RTEMS_CONTAINER_OF(work, struct delayed_work, work)
+void jffs2_queue_delayed_work(struct delayed_work *work, int delay_ms);
#endif /* __LINUX_WORKQUEUE_H__ */
diff --git a/cpukit/libfs/src/jffs2/include/linux/writeback.h b/cpukit/libfs/src/jffs2/include/linux/writeback.h
new file mode 100644
index 0000000000..9899205383
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/include/linux/writeback.h
@@ -0,0 +1 @@
+/* This file intentionally left empty as a stub for wbuf.c */
diff --git a/cpukit/libfs/src/jffs2/src/acl.h b/cpukit/libfs/src/jffs2/src/acl.h
index 12d0271bdd..9d9fb7cf09 100644
--- a/cpukit/libfs/src/jffs2/src/acl.h
+++ b/cpukit/libfs/src/jffs2/src/acl.h
@@ -27,8 +27,9 @@ struct jffs2_acl_header {
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
-struct posix_acl *jffs2_get_acl(struct inode *inode, int type);
-int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+struct posix_acl *jffs2_get_acl(struct inode *inode, int type, bool rcu);
+int jffs2_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
+ struct posix_acl *acl, int type);
extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *);
extern int jffs2_init_acl_post(struct inode *);
diff --git a/cpukit/libfs/src/jffs2/src/build.c b/cpukit/libfs/src/jffs2/src/build.c
index d35bc83bbb..12e2ef820b 100644
--- a/cpukit/libfs/src/jffs2/src/build.c
+++ b/cpukit/libfs/src/jffs2/src/build.c
@@ -417,13 +417,15 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c);
ret = -EIO;
- goto out_free;
+ goto out_sum_exit;
}
jffs2_calc_trigger_levels(c);
return 0;
+ out_sum_exit:
+ jffs2_sum_exit(c);
out_free:
kvfree(c->blocks);
diff --git a/cpukit/libfs/src/jffs2/src/compr.c b/cpukit/libfs/src/jffs2/src/compr.c
index a9e821a6a1..19605754de 100644
--- a/cpukit/libfs/src/jffs2/src/compr.c
+++ b/cpukit/libfs/src/jffs2/src/compr.c
@@ -7,7 +7,7 @@
* Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
* Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* University of Szeged, Hungary
- * Copyright © 2013 embedded brains GmbH <rtems@embedded-brains.de>
+ * Copyright © 2013 embedded brains GmbH & Co. KG
*
* Created by Arjan van de Ven <arjan@infradead.org>
*
diff --git a/cpukit/libfs/src/jffs2/src/compr_rtime.c b/cpukit/libfs/src/jffs2/src/compr_rtime.c
index c8313ed234..e3c761dcfe 100644
--- a/cpukit/libfs/src/jffs2/src/compr_rtime.c
+++ b/cpukit/libfs/src/jffs2/src/compr_rtime.c
@@ -44,6 +44,9 @@ uint16_t rtems_jffs2_compressor_rtime_compress(
(void) self;
+ if (*dstlen <= 3)
+ return JFFS2_COMPR_NONE;
+
memset(positions,0,sizeof(positions));
while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
diff --git a/cpukit/libfs/src/jffs2/src/debug.h b/cpukit/libfs/src/jffs2/src/debug.h
index 6c905b3854..6b4afd4e75 100644
--- a/cpukit/libfs/src/jffs2/src/debug.h
+++ b/cpukit/libfs/src/jffs2/src/debug.h
@@ -13,6 +13,7 @@
#ifndef _JFFS2_DEBUG_H_
#define _JFFS2_DEBUG_H_
+#include <linux/printk.h>
#include <linux/sched.h>
#ifndef CONFIG_JFFS2_FS_DEBUG
@@ -117,73 +118,73 @@ do { \
#ifdef JFFS2_DBG_READINODE_MESSAGES
#define dbg_readinode(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_readinode(fmt, ...)
+#define dbg_readinode(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
#ifdef JFFS2_DBG_READINODE2_MESSAGES
#define dbg_readinode2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_readinode2(fmt, ...)
+#define dbg_readinode2(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* Fragtree build debugging messages */
#ifdef JFFS2_DBG_FRAGTREE_MESSAGES
#define dbg_fragtree(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_fragtree(fmt, ...)
+#define dbg_fragtree(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
#ifdef JFFS2_DBG_FRAGTREE2_MESSAGES
#define dbg_fragtree2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_fragtree2(fmt, ...)
+#define dbg_fragtree2(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* Directory entry list manilulation debugging messages */
#ifdef JFFS2_DBG_DENTLIST_MESSAGES
#define dbg_dentlist(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_dentlist(fmt, ...)
+#define dbg_dentlist(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* Print the messages about manipulating node_refs */
#ifdef JFFS2_DBG_NODEREF_MESSAGES
#define dbg_noderef(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_noderef(fmt, ...)
+#define dbg_noderef(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* Manipulations with the list of inodes (JFFS2 inocache) */
#ifdef JFFS2_DBG_INOCACHE_MESSAGES
#define dbg_inocache(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_inocache(fmt, ...)
+#define dbg_inocache(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* Summary debugging messages */
#ifdef JFFS2_DBG_SUMMARY_MESSAGES
#define dbg_summary(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_summary(fmt, ...)
+#define dbg_summary(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* File system build messages */
#ifdef JFFS2_DBG_FSBUILD_MESSAGES
#define dbg_fsbuild(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_fsbuild(fmt, ...)
+#define dbg_fsbuild(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* Watch the object allocations */
#ifdef JFFS2_DBG_MEMALLOC_MESSAGES
#define dbg_memalloc(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_memalloc(fmt, ...)
+#define dbg_memalloc(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* Watch the XATTR subsystem */
#ifdef JFFS2_DBG_XATTR_MESSAGES
#define dbg_xattr(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
#else
-#define dbg_xattr(fmt, ...)
+#define dbg_xattr(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
/* "Sanity" checks */
diff --git a/cpukit/libfs/src/jffs2/src/dir-rtems.c b/cpukit/libfs/src/jffs2/src/dir-rtems.c
index 9fa70bcec4..91906bac94 100644
--- a/cpukit/libfs/src/jffs2/src/dir-rtems.c
+++ b/cpukit/libfs/src/jffs2/src/dir-rtems.c
@@ -6,11 +6,11 @@
* Copyright © 2001-2003 Free Software Foundation, Inc.
* Copyright © 2001-2007 Red Hat, Inc.
* Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
- * Copyright © 2013 embedded brains GmbH <rtems@embedded-brains.de>
+ * Copyright © 2013 embedded brains GmbH & Co. KG
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
- * Port to the RTEMS by embedded brains GmbH.
+ * Port to the RTEMS by embedded brains GmbH & Co. KG
*
* For licensing information, see the file 'LICENCE' in this directory.
*
@@ -214,6 +214,8 @@ int jffs2_mknod(
f = JFFS2_INODE_INFO(inode);
+ mutex_lock(&f->sem);
+
inode->i_size = datalen;
ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
diff --git a/cpukit/libfs/src/jffs2/src/erase.c b/cpukit/libfs/src/jffs2/src/erase.c
index e8ab569462..6966ed9b0a 100644
--- a/cpukit/libfs/src/jffs2/src/erase.c
+++ b/cpukit/libfs/src/jffs2/src/erase.c
@@ -45,9 +45,9 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
jffs2_dbg(1, "%s(): erase block %#08x (range %#08x-%#08x)\n",
__func__,
jeb->offset, jeb->offset, jeb->offset + c->sector_size);
- instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
+ instr = kzalloc(sizeof(struct erase_info), GFP_KERNEL);
if (!instr) {
- pr_warn("kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
+ pr_warn("kzalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
mutex_lock(&c->erase_free_sem);
spin_lock(&c->erase_completion_lock);
list_move(&jeb->list, &c->erase_pending_list);
@@ -59,8 +59,6 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
return;
}
- memset(instr, 0, sizeof(*instr));
-
instr->addr = jeb->offset;
instr->len = c->sector_size;
diff --git a/cpukit/libfs/src/jffs2/src/flashio.c b/cpukit/libfs/src/jffs2/src/flashio.c
index 7b689a5a7c..6b0a9433fa 100644
--- a/cpukit/libfs/src/jffs2/src/flashio.c
+++ b/cpukit/libfs/src/jffs2/src/flashio.c
@@ -17,8 +17,23 @@
#include <linux/kernel.h>
#include "nodelist.h"
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
int jffs2_flash_read(struct jffs2_sb_info * c,
- cyg_uint32 read_buffer_offset, const size_t size,
+ loff_t read_buffer_offset, const size_t size,
+ size_t * return_size, unsigned char *write_buffer)
+{
+ return jffs2_flash_direct_read(c, read_buffer_offset, size, return_size, write_buffer);
+}
+
+int jffs2_flash_write(struct jffs2_sb_info * c,
+ loff_t write_buffer_offset, size_t size,
+ size_t * return_size, const unsigned char *read_buffer)
+{
+ return jffs2_flash_direct_write(c, write_buffer_offset, size, return_size, read_buffer);
+}
+#endif
+int jffs2_flash_direct_read(struct jffs2_sb_info * c,
+ loff_t read_buffer_offset, const size_t size,
size_t * return_size, unsigned char *write_buffer)
{
const struct super_block *sb = OFNI_BS_2SFFJ(c);
@@ -29,9 +44,9 @@ int jffs2_flash_read(struct jffs2_sb_info * c,
return (*fc->read)(fc, read_buffer_offset, write_buffer, size);
}
-int jffs2_flash_write(struct jffs2_sb_info * c,
- cyg_uint32 write_buffer_offset, const size_t size,
- size_t * return_size, unsigned char *read_buffer)
+int jffs2_flash_direct_write(struct jffs2_sb_info * c,
+ loff_t write_buffer_offset, const size_t size,
+ size_t * return_size, const unsigned char *read_buffer)
{
const struct super_block *sb = OFNI_BS_2SFFJ(c);
rtems_jffs2_flash_control *fc = sb->s_flash_control;
@@ -133,3 +148,55 @@ int jffs2_flash_erase(struct jffs2_sb_info * c,
return (*fc->erase)(fc, jeb->offset);
}
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+int jffs2_flash_block_is_bad(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset, bool *bad)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ return (*fc->block_is_bad)(fc, block_offset, bad);
+}
+
+int jffs2_flash_block_mark_bad(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ return (*fc->block_mark_bad)(fc, block_offset);
+}
+
+int jffs2_flash_oob_write(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ uint8_t *oobbuf,
+ uint32_t ooblen)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ return (*fc->oob_write)(fc, block_offset, oobbuf, ooblen);
+}
+
+int jffs2_flash_oob_read(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ uint8_t *oobbuf,
+ uint32_t ooblen)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ return (*fc->oob_read)(fc, block_offset, oobbuf, ooblen);
+}
+
+int jffs2_flash_get_oob_size(struct jffs2_sb_info * c)
+{
+ const struct super_block *sb = OFNI_BS_2SFFJ(c);
+ rtems_jffs2_flash_control *fc = sb->s_flash_control;
+
+ if (fc->get_oob_size == NULL) {
+ return 0;
+ }
+ return (*fc->get_oob_size)(fc);
+}
+#endif
diff --git a/cpukit/libfs/src/jffs2/src/fs-rtems.c b/cpukit/libfs/src/jffs2/src/fs-rtems.c
index b863c74547..029cba6618 100644
--- a/cpukit/libfs/src/jffs2/src/fs-rtems.c
+++ b/cpukit/libfs/src/jffs2/src/fs-rtems.c
@@ -6,12 +6,12 @@
* Copyright © 2001-2003 Free Software Foundation, Inc.
* Copyright © 2001-2007 Red Hat, Inc.
* Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org>
- * Copyright © 2013, 2016 embedded brains GmbH <rtems@embedded-brains.de>
+ * Copyright (C) 2013, 2016 embedded brains GmbH & Co. KG
*
* Created by Dominic Ostrowski <dominic.ostrowski@3glab.com>
* Contributors: David Woodhouse, Nick Garnett, Richard Panton.
*
- * Port to the RTEMS by embedded brains GmbH.
+ * Port to the RTEMS by embedded brains GmbH & Co. KG
*
* For licensing information, see the file 'LICENCE' in this directory.
*
@@ -23,12 +23,14 @@
#include "nodelist.h"
#include <linux/pagemap.h>
#include <linux/crc32.h>
+#include <linux/mtd/mtd.h>
#include "compr.h"
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <rtems/libio.h>
#include <rtems/libio_.h>
+#include <rtems/sysinit.h>
/* Ensure that the JFFS2 values are identical to the POSIX defines */
@@ -577,6 +579,9 @@ static int rtems_jffs2_ioctl(
break;
case RTEMS_JFFS2_FORCE_GARBAGE_COLLECTION:
eno = -jffs2_garbage_collect_pass(&inode->i_sb->jffs2_sb);
+ if (!eno) {
+ eno = -jffs2_flush_wbuf_pad(&inode->i_sb->jffs2_sb);
+ }
break;
default:
eno = EINVAL;
@@ -1049,10 +1054,26 @@ static void rtems_jffs2_freenode(const rtems_filesystem_location_info_t *loc)
jffs2_iput(inode);
}
+static void jffs2_remove_delayed_work(struct delayed_work *dwork);
+
static void rtems_jffs2_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry)
{
rtems_jffs2_fs_info *fs_info = mt_entry->fs_info;
struct _inode *root_i = mt_entry->mt_fs_root->location.node_access;
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(&fs_info->sb);
+
+ /* Remove wbuf delayed work */
+ jffs2_remove_delayed_work(&c->wbuf_dwork);
+
+ /* Flush any pending writes */
+ if (!sb_rdonly(&fs_info->sb)) {
+ jffs2_flush_wbuf_gc(c, 0);
+ jffs2_flush_wbuf_pad(c);
+ }
+#endif
+
+ jffs2_sum_exit(c);
icache_evict(root_i, NULL);
assert(root_i->i_cache_next == NULL);
@@ -1062,6 +1083,12 @@ static void rtems_jffs2_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry
rtems_jffs2_free_directory_entries(root_i);
free(root_i);
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ jffs2_nand_flash_cleanup(c);
+ free(c->mtd);
+ c->mtd = NULL;
+#endif
+
rtems_jffs2_free_fs_info(fs_info, true);
}
@@ -1212,6 +1239,127 @@ static int calculate_inocache_hashsize(uint32_t flash_size)
return hashsize;
}
+/* Chain for holding delayed work */
+rtems_chain_control delayed_work_chain;
+
+/* Lock for protecting the delayed work chain */
+struct mutex delayed_work_mutex;
+
+/*
+ * All delayed work structs are initialized and added to the chain during FS
+ * init. Must be called with no locks held
+ */
+static void add_delayed_work_to_chain(struct delayed_work *work)
+{
+ /* Initialize delayed work */
+ mutex_init(&work->dw_mutex);
+ work->pending = false;
+ _Chain_Initialize_node(&work->work.node); \
+ work->callback = NULL;
+
+ mutex_lock(&delayed_work_mutex);
+ rtems_chain_append_unprotected(&delayed_work_chain, &work->work.node);
+ mutex_unlock(&delayed_work_mutex);
+}
+
+void jffs2_queue_delayed_work(struct delayed_work *work, int delay_ms)
+{
+ mutex_lock(&work->dw_mutex);
+ if (!work->pending) {
+ work->execution_time = rtems_clock_get_uptime_nanoseconds();
+ work->execution_time += delay_ms*1000000;
+ work->pending = true;
+ }
+ mutex_unlock(&work->dw_mutex);
+}
+
+/* Clean up during FS unmount */
+static void jffs2_remove_delayed_work(struct delayed_work *dwork)
+{
+ mutex_lock(&delayed_work_mutex);
+ rtems_chain_extract_unprotected(&dwork->work.node);
+ mutex_unlock(&delayed_work_mutex);
+ /* Don't run pending delayed work, this will happen during unmount */
+}
+
+static void process_delayed_work(void)
+{
+ struct delayed_work* work;
+ rtems_chain_node* node;
+
+ mutex_lock(&delayed_work_mutex);
+
+ if (rtems_chain_is_empty(&delayed_work_chain)) {
+ mutex_unlock(&delayed_work_mutex);
+ return;
+ }
+
+ node = rtems_chain_first(&delayed_work_chain);
+ while (!rtems_chain_is_tail(&delayed_work_chain, node)) {
+ work = (struct delayed_work*) node;
+ node = rtems_chain_next(node);
+
+ if (!work->pending) {
+ continue;
+ }
+
+ if (rtems_clock_get_uptime_nanoseconds() < work->execution_time) {
+ continue;
+ }
+
+ mutex_lock(&work->dw_mutex);
+ work->pending = false;
+ mutex_unlock(&work->dw_mutex);
+
+ rtems_jffs2_do_lock(work->sb);
+ work->callback(&work->work);
+ rtems_jffs2_do_unlock(work->sb);
+ }
+ mutex_unlock(&delayed_work_mutex);
+}
+
+/* Task for processing delayed work */
+static rtems_task delayed_work_task(
+ rtems_task_argument unused
+)
+{
+ (void)unused;
+ while (1) {
+ process_delayed_work();
+ usleep(1);
+ }
+}
+
+rtems_id delayed_work_task_id;
+
+static void jffs2_init_delayed_work_task(void)
+{
+ /* Initialize chain for delayed work */
+ rtems_chain_initialize_empty(&delayed_work_chain);
+
+ /* Initialize lock for delayed work */
+ mutex_init(&delayed_work_mutex);
+
+ /* Create task for delayed work */
+ rtems_status_code err = rtems_task_create(
+ rtems_build_name( 'J', 'F', 'F', 'S' ),
+ jffs2_config.delayed_write_priority,
+ RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_DEFAULT_MODES,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &delayed_work_task_id
+ );
+ if (err != RTEMS_SUCCESSFUL) {
+ printk("JFFS2 delayed work task processor creation failed\n");
+ }
+}
+
+RTEMS_SYSINIT_ITEM(
+ jffs2_init_delayed_work_task,
+ RTEMS_SYSINIT_LIBIO,
+ RTEMS_SYSINIT_ORDER_MIDDLE
+);
+
int rtems_jffs2_initialize(
rtems_filesystem_mount_table_entry_t *mt_entry,
const void *data
@@ -1235,13 +1383,29 @@ int rtems_jffs2_initialize(
err = -ENOMEM;
}
- sb = &fs_info->sb;
- c = JFFS2_SB_INFO(sb);
if (err == 0) {
+ sb = &fs_info->sb;
+ c = JFFS2_SB_INFO(sb);
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ c->wbuf_dwork.sb = sb;
+ add_delayed_work_to_chain(&c->wbuf_dwork);
+#endif
+ spin_lock_init(&c->erase_completion_lock);
+ spin_lock_init(&c->inocache_lock);
+ c->mtd = NULL;
rtems_recursive_mutex_init(&sb->s_mutex, RTEMS_FILESYSTEM_TYPE_JFFS2);
}
+ /* Start task for delayed work if it hasn't already been started */
+ if (err == 0) {
+ err = rtems_task_start( delayed_work_task_id, delayed_work_task, 0 );
+ /* Task already running from previous mount */
+ if (err == RTEMS_INCORRECT_STATE) {
+ err = 0;
+ }
+ }
+
if (err == 0) {
uint32_t blocks = fc->flash_size / fc->block_size;
@@ -1263,12 +1427,31 @@ int rtems_jffs2_initialize(
sb->s_flash_control = fc;
sb->s_compressor_control = jffs2_mount_data->compressor_control;
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ c->mtd = malloc(sizeof(struct mtd_info));
+ if (!c->mtd) {
+ err = -ENOMEM;
+ }
+ }
+
+ if (err == 0) {
+ c->mtd->oobavail = jffs2_flash_get_oob_size(c);
+ c->mtd->oobsize = c->mtd->oobavail;
+ c->mtd->size = fc->flash_size;
+ c->mtd->erasesize = fc->block_size;
+ c->mtd->writesize = fc->write_size;
+#endif
c->inocache_hashsize = inocache_hashsize;
c->inocache_list = &fs_info->inode_cache[0];
c->sector_size = fc->block_size;
c->flash_size = fc->flash_size;
c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ err = jffs2_nand_flash_setup(c);
+ }
+ if (err == 0) {
+#endif
err = jffs2_do_mount_fs(c);
}
@@ -1296,6 +1479,11 @@ int rtems_jffs2_initialize(
return 0;
} else {
if (fs_info != NULL) {
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+ jffs2_remove_delayed_work(&c->wbuf_dwork);
+#endif
+ free(c->mtd);
+ c->mtd = NULL;
rtems_jffs2_free_fs_info(fs_info, do_mount_fs_was_successful);
} else {
rtems_jffs2_flash_control_destroy(fc);
@@ -1342,6 +1530,8 @@ static struct _inode *new_inode(struct super_block *sb)
inode->i_cache_next = NULL; // Newest inode, about to be cached
+ mutex_init(&JFFS2_INODE_INFO(inode)->sem);
+
// Add to the icache
for (cached_inode = sb->s_root; cached_inode != NULL;
cached_inode = cached_inode->i_cache_next) {
@@ -1458,7 +1648,14 @@ void jffs2_iput(struct _inode *i)
static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
{
- memset(f, 0, sizeof(*f));
+ /* These must be set manually to preserve other members */
+ f->highest_version = 0;
+ f->fragtree = RB_ROOT;
+ f->metadata = NULL;
+ f->dents = NULL;
+ f->target = NULL;
+ f->flags = 0;
+ f->usercompr = 0;
}
static void jffs2_clear_inode (struct _inode *inode)
@@ -1543,6 +1740,7 @@ static int jffs2_read_inode (struct _inode *inode)
c = JFFS2_SB_INFO(inode->i_sb);
jffs2_init_inode_info(f);
+ mutex_lock(&f->sem);
ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
diff --git a/cpukit/libfs/src/jffs2/src/gc.c b/cpukit/libfs/src/jffs2/src/gc.c
index 04ec073d2b..3d0d8c56d9 100644
--- a/cpukit/libfs/src/jffs2/src/gc.c
+++ b/cpukit/libfs/src/jffs2/src/gc.c
@@ -1340,7 +1340,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
mutex_unlock(&f->sem);
#ifndef __rtems__
page = read_cache_page(inode->i_mapping, start >> PAGE_SHIFT,
- jffs2_do_readpage_unlock, inode);
+ __jffs2_read_folio, NULL);
if (IS_ERR(page)) {
pr_warn("read_cache_page() returned error: %ld\n",
PTR_ERR(page));
diff --git a/cpukit/libfs/src/jffs2/src/jffs2_fs_i.h b/cpukit/libfs/src/jffs2/src/jffs2_fs_i.h
index 6b6050e9eb..64ff8abc01 100644
--- a/cpukit/libfs/src/jffs2/src/jffs2_fs_i.h
+++ b/cpukit/libfs/src/jffs2/src/jffs2_fs_i.h
@@ -18,11 +18,11 @@
#include <linux/mutex.h>
struct jffs2_inode_info {
- /* We need an internal mutex similar to inode->i_mutex.
+ /* We need an internal mutex similar to inode->i_rwsem.
Unfortunately, we can't used the existing one, because
either the GC would deadlock, or we'd have to release it
before letting GC proceed. Or we'd have to put ugliness
- into the GC code so it didn't attempt to obtain the i_mutex
+ into the GC code so it didn't attempt to obtain the i_rwsem
for the inode(s) which are already locked */
struct mutex sem;
diff --git a/cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h b/cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h
index 778275f48a..7960f92f85 100644
--- a/cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h
+++ b/cpukit/libfs/src/jffs2/src/jffs2_fs_sb.h
@@ -1,3 +1,5 @@
+#include "rtems-jffs2-config.h"
+
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
@@ -38,6 +40,7 @@ struct jffs2_mount_opts {
* users. This is implemented simply by means of not allowing the
* latter users to write to the file system if the amount if the
* available space is less then 'rp_size'. */
+ bool set_rp_size;
unsigned int rp_size;
};
@@ -72,6 +75,9 @@ struct jffs2_sb_info {
uint32_t bad_size;
uint32_t sector_size;
uint32_t unchecked_size;
+#ifdef __rtems__
+ uint32_t obsolete_size;
+#endif
uint32_t nr_free_blocks;
uint32_t nr_erasing_blocks;
diff --git a/cpukit/libfs/src/jffs2/src/nodelist.h b/cpukit/libfs/src/jffs2/src/nodelist.h
index 4eee0ac8ff..b30aa5bbf6 100644
--- a/cpukit/libfs/src/jffs2/src/nodelist.h
+++ b/cpukit/libfs/src/jffs2/src/nodelist.h
@@ -351,14 +351,14 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
#define frag_parent(frag) rb_entry(rb_parent(&(frag)->rb), struct jffs2_node_frag, rb)
#define frag_left(frag) rb_entry((frag)->rb.rb_left, struct jffs2_node_frag, rb)
#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb)
-#define frag_erase(frag, list) rb_erase(&frag->rb, list);
+#define frag_erase(frag, list) rb_erase(&frag->rb, list)
#define tn_next(tn) rb_entry(rb_next(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
#define tn_prev(tn) rb_entry(rb_prev(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
#define tn_parent(tn) rb_entry(rb_parent(&(tn)->rb), struct jffs2_tmp_dnode_info, rb)
#define tn_left(tn) rb_entry((tn)->rb.rb_left, struct jffs2_tmp_dnode_info, rb)
#define tn_right(tn) rb_entry((tn)->rb.rb_right, struct jffs2_tmp_dnode_info, rb)
-#define tn_erase(tn, list) rb_erase(&tn->rb, list);
+#define tn_erase(tn, list) rb_erase(&tn->rb, list)
#define tn_last(list) rb_entry(rb_last(list), struct jffs2_tmp_dnode_info, rb)
#define tn_first(list) rb_entry(rb_first(list), struct jffs2_tmp_dnode_info, rb)
diff --git a/cpukit/libfs/src/jffs2/src/os-rtems.h b/cpukit/libfs/src/jffs2/src/os-rtems.h
index d9e4330371..4bc6f5df13 100644
--- a/cpukit/libfs/src/jffs2/src/os-rtems.h
+++ b/cpukit/libfs/src/jffs2/src/os-rtems.h
@@ -2,11 +2,11 @@
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright © 2002-2003 Free Software Foundation, Inc.
- * Copyright © 2013 embedded brains GmbH <rtems@embedded-brains.de>
+ * Copyright © 2013 embedded brains GmbH & Co. KG
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
- * Port to the RTEMS by embedded brains GmbH.
+ * Port to the RTEMS by embedded brains GmbH & Co. KG
*
* For licensing information, see the file 'LICENCE' in this directory.
*
@@ -52,8 +52,7 @@ static inline unsigned int full_name_hash(const void *salt, const unsigned char
return hash;
}
-/* NAND flash not currently supported on RTEMS */
-#define jffs2_can_mark_obsolete(c) (1)
+#define container_of(a, b, c) RTEMS_CONTAINER_OF(a, b, c)
#define JFFS2_INODE_INFO(i) (&(i)->jffs2_i)
#define OFNI_EDONI_2SFFJ(f) RTEMS_CONTAINER_OF(f, struct _inode, jffs2_i)
@@ -101,6 +100,10 @@ struct _inode {
struct super_block {
struct jffs2_sb_info jffs2_sb;
+ /*
+ * If granular locking is ever enabled for JFFS2, the inode cache
+ * (s_root) needs to be protected due to NAND delayed writes.
+ */
struct _inode * s_root;
rtems_jffs2_flash_control *s_flash_control;
rtems_jffs2_compressor_control *s_compressor_control;
@@ -108,6 +111,7 @@ struct super_block {
unsigned char s_gc_buffer[PAGE_CACHE_SIZE]; // Avoids malloc when user may be under memory pressure
rtems_recursive_mutex s_mutex;
char s_name_buf[JFFS2_MAX_NAME_LEN];
+ uint32_t s_flags;
};
#define sleep_on_spinunlock(wq, sl) spin_unlock(sl)
@@ -151,13 +155,15 @@ static inline uint32_t jffs2_to_os_mode (uint32_t jmode)
/* flashio.c */
-int jffs2_flash_read(struct jffs2_sb_info *c, cyg_uint32 read_buffer_offset,
- const size_t size, size_t * return_size, unsigned char * write_buffer);
-int jffs2_flash_write(struct jffs2_sb_info *c, cyg_uint32 write_buffer_offset,
- const size_t size, size_t * return_size, unsigned char * read_buffer);
+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t read_buffer_offset,
+ size_t size, size_t * return_size, unsigned char * write_buffer);
+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t write_buffer_offset,
+ size_t size, size_t * return_size, const unsigned char * read_buffer);
int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
unsigned long count, loff_t to, size_t *retlen);
int jffs2_flash_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
+int jffs2_flash_direct_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
// dir-rtems.c
struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *name, size_t namelen);
@@ -173,8 +179,9 @@ int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsign
static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
{ }
-#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
+
#define jffs2_can_mark_obsolete(c) (1)
#define jffs2_is_writebuffered(c) (0)
#define jffs2_cleanmarker_oob(c) (0)
@@ -191,9 +198,55 @@ static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
#define jffs2_wbuf_timeout NULL
#define jffs2_wbuf_process NULL
#define jffs2_nor_ecc(c) (0)
-#else
-#error no nand yet
-#endif
+#else /* CONFIG_JFFS2_FS_WRITEBUFFER */
+/* dirty_writeback_interval is in centiseconds, 500cs == 5s */
+#define dirty_writeback_interval 500
+#define MTD_BIT_WRITEABLE 0x800
+#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
+
+#define jffs2_can_mark_obsolete(c) (OFNI_BS_2SFFJ(c)->s_flash_control->block_is_bad == NULL)
+
+#define jffs2_cleanmarker_oob(c) (OFNI_BS_2SFFJ(c)->s_flash_control->block_is_bad != NULL)
+
+#define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
+
+/* wbuf.c */
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
+int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
+void jffs2_wbuf_timeout(unsigned long data);
+void jffs2_wbuf_process(void *data);
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
+int jffs2_flash_block_is_bad(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ bool *bad);
+int jffs2_flash_block_mark_bad(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset);
+int jffs2_flash_oob_write(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ uint8_t *oobbuf,
+ uint32_t ooblen);
+int jffs2_flash_oob_read(struct jffs2_sb_info * c,
+ cyg_uint32 block_offset,
+ uint8_t *oobbuf,
+ uint32_t ooblen);
+int jffs2_flash_get_oob_size(struct jffs2_sb_info * c);
+
+int jffs2_dataflash_setup(struct jffs2_sb_info *c);
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
+int jffs2_ubivol_setup(struct jffs2_sb_info *c);
+void jffs2_ubivol_cleanup(struct jffs2_sb_info *c);
+
+int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c);
+void jffs2_dirty_trigger(struct jffs2_sb_info *c);
+
+#endif /* CONFIG_JFFS2_FS_WRITEBUFFER */
#ifndef BUG_ON
#define BUG_ON(x) do { if (unlikely(x)) BUG(); } while(0)
diff --git a/cpukit/libfs/src/jffs2/src/readinode.c b/cpukit/libfs/src/jffs2/src/readinode.c
index 831fb8f3f9..9f554f8644 100644
--- a/cpukit/libfs/src/jffs2/src/readinode.c
+++ b/cpukit/libfs/src/jffs2/src/readinode.c
@@ -693,6 +693,22 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r
jffs2_free_full_dirent(fd);
return -EIO;
}
+
+#ifdef CONFIG_JFFS2_SUMMARY
+ /*
+ * we use CONFIG_JFFS2_SUMMARY because without it, we
+ * have checked it while mounting
+ */
+ crc = crc32(0, fd->name, rd->nsize);
+ if (unlikely(crc != je32_to_cpu(rd->name_crc))) {
+ JFFS2_NOTICE("name CRC failed on dirent node at"
+ "%#08x: read %#08x,calculated %#08x\n",
+ ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
+ jffs2_mark_node_obsolete(c, ref);
+ jffs2_free_full_dirent(fd);
+ return 0;
+ }
+#endif
}
fd->nhash = full_name_hash(NULL, fd->name, rd->nsize);
diff --git a/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h b/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h
index 56395e1528..0e88d81989 100644
--- a/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h
+++ b/cpukit/libfs/src/jffs2/src/rtems-jffs2-config.h
@@ -7,7 +7,7 @@
*/
/*
- * Copyright (C) 2018 embedded brains Gmbh (http://www.embedded-brains.de)
+ * Copyright (C) 2018 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -34,3 +34,4 @@
#define __ECOS 1
#define KBUILD_MODNAME "JFFS2"
#define fallthrough __attribute__((__fallthrough__))
+#define CONFIG_JFFS2_FS_WRITEBUFFER
diff --git a/cpukit/libfs/src/jffs2/src/scan.c b/cpukit/libfs/src/jffs2/src/scan.c
index 765bf55478..8ac4a40414 100644
--- a/cpukit/libfs/src/jffs2/src/scan.c
+++ b/cpukit/libfs/src/jffs2/src/scan.c
@@ -139,7 +139,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
if (!s) {
JFFS2_WARNING("Can't allocate memory for summary\n");
ret = -ENOMEM;
- goto out;
+ goto out_buf;
}
}
@@ -264,27 +264,47 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
}
#endif
if (c->nr_erasing_blocks) {
+#ifdef __rtems__
+ if (c->obsolete_size != c->dirty_size) {
+#endif
if (!c->used_size && !c->unchecked_size &&
((c->nr_free_blocks+empty_blocks+bad_blocks) != c->nr_blocks || bad_blocks == c->nr_blocks)) {
pr_notice("Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
pr_notice("empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",
empty_blocks, bad_blocks, c->nr_blocks);
+#ifdef __rtems__
+ pr_notice("nr_erasing_blocks %d, used 0x%x, dirty 0x%x, wasted 0x%x, free 0x%x, erasing 0x%x, bad 0x%x, obsolete 0x%x, unchecked 0x%x\n",
+ c->nr_erasing_blocks,
+ c->used_size,
+ c->dirty_size,
+ c->wasted_size,
+ c->free_size,
+ c->erasing_size,
+ c->bad_size,
+ c->obsolete_size,
+ c->unchecked_size);
+#endif
ret = -EIO;
goto out;
}
+#ifdef __rtems__
+ }
+#endif
spin_lock(&c->erase_completion_lock);
jffs2_garbage_collect_trigger(c);
spin_unlock(&c->erase_completion_lock);
}
ret = 0;
out:
+ jffs2_sum_reset_collected(s);
+ kfree(s);
+ out_buf:
if (buf_size)
kfree(flashbuf);
#ifndef __ECOS
else
mtd_unpoint(c->mtd, 0, c->mtd->size);
#endif
- kfree(s);
return ret;
}
@@ -644,6 +664,9 @@ scan_more:
sizeof(struct jffs2_unknown_node),
jeb->offset, c->sector_size, ofs,
sizeof(*node));
+#ifdef __rtems__
+ c->obsolete_size += (jeb->offset + c->sector_size - ofs);
+#endif
if ((err = jffs2_scan_dirty_space(c, jeb, (jeb->offset + c->sector_size)-ofs)))
return err;
break;
@@ -794,6 +817,9 @@ scan_more:
if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
return err;
ofs += PAD(je32_to_cpu(node->totlen));
+#ifdef __rtems__
+ c->obsolete_size += PAD(je32_to_cpu(node->totlen));
+#endif
continue;
}
@@ -1082,7 +1108,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
memcpy(&fd->name, rd->name, checkedlen);
fd->name[checkedlen] = 0;
- crc = crc32(0, fd->name, rd->nsize);
+ crc = crc32(0, fd->name, checkedlen);
if (crc != je32_to_cpu(rd->name_crc)) {
pr_notice("%s(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
__func__, ofs, je32_to_cpu(rd->name_crc), crc);
diff --git a/cpukit/libfs/src/jffs2/src/summary.h b/cpukit/libfs/src/jffs2/src/summary.h
index e4131cb1f1..36d9a12807 100644
--- a/cpukit/libfs/src/jffs2/src/summary.h
+++ b/cpukit/libfs/src/jffs2/src/summary.h
@@ -194,18 +194,18 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
#define jffs2_sum_active() (0)
#define jffs2_sum_init(a) (0)
-#define jffs2_sum_exit(a)
+#define jffs2_sum_exit(a) do { } while (0)
#define jffs2_sum_disable_collecting(a)
#define jffs2_sum_is_disabled(a) (0)
-#define jffs2_sum_reset_collected(a)
+#define jffs2_sum_reset_collected(a) do { } while (0)
#define jffs2_sum_add_kvec(a,b,c,d) (0)
-#define jffs2_sum_move_collected(a,b)
+#define jffs2_sum_move_collected(a,b) do { } while (0)
#define jffs2_sum_write_sumnode(a) (0)
-#define jffs2_sum_add_padding_mem(a,b)
-#define jffs2_sum_add_inode_mem(a,b,c)
-#define jffs2_sum_add_dirent_mem(a,b,c)
-#define jffs2_sum_add_xattr_mem(a,b,c)
-#define jffs2_sum_add_xref_mem(a,b,c)
+#define jffs2_sum_add_padding_mem(a,b) do { } while (0)
+#define jffs2_sum_add_inode_mem(a,b,c) do { } while (0)
+#define jffs2_sum_add_dirent_mem(a,b,c) do { } while (0)
+#define jffs2_sum_add_xattr_mem(a,b,c) do { } while (0)
+#define jffs2_sum_add_xref_mem(a,b,c) do { } while (0)
#define jffs2_sum_scan_sumnode(a,b,c,d,e) (0)
#endif /* CONFIG_JFFS2_SUMMARY */
diff --git a/cpukit/libfs/src/jffs2/src/wbuf.c b/cpukit/libfs/src/jffs2/src/wbuf.c
new file mode 100644
index 0000000000..04e2b03efc
--- /dev/null
+++ b/cpukit/libfs/src/jffs2/src/wbuf.c
@@ -0,0 +1,1352 @@
+#include "rtems-jffs2-config.h"
+
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright © 2001-2007 Red Hat, Inc.
+ * Copyright © 2004 Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/crc32.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/writeback.h>
+
+#include "nodelist.h"
+
+/* For testing write failures */
+#undef BREAKME
+#undef BREAKMEHEADER
+
+#ifdef BREAKME
+static unsigned char *brokenbuf;
+#endif
+
+#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
+#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
+
+/* max. erase failures before we mark a block bad */
+#define MAX_ERASE_FAILURES 2
+
+struct jffs2_inodirty {
+ uint32_t ino;
+ struct jffs2_inodirty *next;
+};
+
+static struct jffs2_inodirty inodirty_nomem;
+
+static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino)
+{
+ struct jffs2_inodirty *this = c->wbuf_inodes;
+
+ /* If a malloc failed, consider _everything_ dirty */
+ if (this == &inodirty_nomem)
+ return 1;
+
+ /* If ino == 0, _any_ non-GC writes mean 'yes' */
+ if (this && !ino)
+ return 1;
+
+ /* Look to see if the inode in question is pending in the wbuf */
+ while (this) {
+ if (this->ino == ino)
+ return 1;
+ this = this->next;
+ }
+ return 0;
+}
+
+static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c)
+{
+ struct jffs2_inodirty *this;
+
+ this = c->wbuf_inodes;
+
+ if (this != &inodirty_nomem) {
+ while (this) {
+ struct jffs2_inodirty *next = this->next;
+ kfree(this);
+ this = next;
+ }
+ }
+ c->wbuf_inodes = NULL;
+}
+
+static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
+{
+ struct jffs2_inodirty *new;
+
+ /* Schedule delayed write-buffer write-out */
+ jffs2_dirty_trigger(c);
+
+ if (jffs2_wbuf_pending_for_ino(c, ino))
+ return;
+
+ new = kmalloc(sizeof(*new), GFP_KERNEL);
+ if (!new) {
+ jffs2_dbg(1, "No memory to allocate inodirty. Fallback to all considered dirty\n");
+ jffs2_clear_wbuf_ino_list(c);
+ c->wbuf_inodes = &inodirty_nomem;
+ return;
+ }
+ new->ino = ino;
+ new->next = c->wbuf_inodes;
+ c->wbuf_inodes = new;
+ return;
+}
+
+static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
+{
+ struct list_head *this, *next;
+ static int n;
+
+ if (list_empty(&c->erasable_pending_wbuf_list))
+ return;
+
+ list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) {
+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+ jffs2_dbg(1, "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n",
+ jeb->offset);
+ list_del(this);
+ if ((jiffies + (n++)) & 127) {
+ /* Most of the time, we just erase it immediately. Otherwise we
+ spend ages scanning it on mount, etc. */
+ jffs2_dbg(1, "...and adding to erase_pending_list\n");
+ list_add_tail(&jeb->list, &c->erase_pending_list);
+ c->nr_erasing_blocks++;
+ jffs2_garbage_collect_trigger(c);
+ } else {
+ /* Sometimes, however, we leave it elsewhere so it doesn't get
+ immediately reused, and we spread the load a bit. */
+ jffs2_dbg(1, "...and adding to erasable_list\n");
+ list_add_tail(&jeb->list, &c->erasable_list);
+ }
+ }
+}
+
+#define REFILE_NOTEMPTY 0
+#define REFILE_ANYWAY 1
+
+static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty)
+{
+ jffs2_dbg(1, "About to refile bad block at %08x\n", jeb->offset);
+
+ /* File the existing block on the bad_used_list.... */
+ if (c->nextblock == jeb)
+ c->nextblock = NULL;
+ else /* Not sure this should ever happen... need more coffee */
+ list_del(&jeb->list);
+ if (jeb->first_node) {
+ jffs2_dbg(1, "Refiling block at %08x to bad_used_list\n",
+ jeb->offset);
+ list_add(&jeb->list, &c->bad_used_list);
+ } else {
+ BUG_ON(allow_empty == REFILE_NOTEMPTY);
+ /* It has to have had some nodes or we couldn't be here */
+ jffs2_dbg(1, "Refiling block at %08x to erase_pending_list\n",
+ jeb->offset);
+ list_add(&jeb->list, &c->erase_pending_list);
+ c->nr_erasing_blocks++;
+ jffs2_garbage_collect_trigger(c);
+ }
+
+ if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) {
+ uint32_t oldfree = jeb->free_size;
+
+ jffs2_link_node_ref(c, jeb,
+ (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE,
+ oldfree, NULL);
+ /* convert to wasted */
+ c->wasted_size += oldfree;
+ jeb->wasted_size += oldfree;
+ c->dirty_size -= oldfree;
+ jeb->dirty_size -= oldfree;
+ }
+
+ jffs2_dbg_dump_block_lists_nolock(c);
+ jffs2_dbg_acct_sanity_check_nolock(c,jeb);
+ jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
+}
+
+static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c,
+ struct jffs2_inode_info *f,
+ struct jffs2_raw_node_ref *raw,
+ union jffs2_node_union *node)
+{
+ struct jffs2_node_frag *frag;
+ struct jffs2_full_dirent *fd;
+
+ dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x}\n",
+ node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype));
+
+ BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 &&
+ je16_to_cpu(node->u.magic) != 0);
+
+ switch (je16_to_cpu(node->u.nodetype)) {
+ case JFFS2_NODETYPE_INODE:
+ if (f->metadata && f->metadata->raw == raw) {
+ dbg_noderef("Will replace ->raw in f->metadata at %p\n", f->metadata);
+ return &f->metadata->raw;
+ }
+ frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset));
+ BUG_ON(!frag);
+ /* Find a frag which refers to the full_dnode we want to modify */
+ while (!frag->node || frag->node->raw != raw) {
+ frag = frag_next(frag);
+ BUG_ON(!frag);
+ }
+ dbg_noderef("Will replace ->raw in full_dnode at %p\n", frag->node);
+ return &frag->node->raw;
+
+ case JFFS2_NODETYPE_DIRENT:
+ for (fd = f->dents; fd; fd = fd->next) {
+ if (fd->raw == raw) {
+ dbg_noderef("Will replace ->raw in full_dirent at %p\n", fd);
+ return &fd->raw;
+ }
+ }
+ BUG();
+
+ default:
+ dbg_noderef("Don't care about replacing raw for nodetype %x\n",
+ je16_to_cpu(node->u.nodetype));
+ break;
+ }
+ return NULL;
+}
+
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+static int jffs2_verify_write(struct jffs2_sb_info *c, unsigned char *buf,
+ uint32_t ofs)
+{
+ int ret;
+ size_t retlen;
+ char *eccstr;
+
+ ret = mtd_read(c->mtd, ofs, c->wbuf_pagesize, &retlen, c->wbuf_verify);
+ if (ret && ret != -EUCLEAN && ret != -EBADMSG) {
+ pr_warn("%s(): Read back of page at %08x failed: %d\n",
+ __func__, c->wbuf_ofs, ret);
+ return ret;
+ } else if (retlen != c->wbuf_pagesize) {
+ pr_warn("%s(): Read back of page at %08x gave short read: %zd not %d\n",
+ __func__, ofs, retlen, c->wbuf_pagesize);
+ return -EIO;
+ }
+ if (!memcmp(buf, c->wbuf_verify, c->wbuf_pagesize))
+ return 0;
+
+ if (ret == -EUCLEAN)
+ eccstr = "corrected";
+ else if (ret == -EBADMSG)
+ eccstr = "correction failed";
+ else
+ eccstr = "OK or unused";
+
+ pr_warn("Write verify error (ECC %s) at %08x. Wrote:\n",
+ eccstr, c->wbuf_ofs);
+ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+ c->wbuf, c->wbuf_pagesize, 0);
+
+ pr_warn("Read back:\n");
+ print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1,
+ c->wbuf_verify, c->wbuf_pagesize, 0);
+
+ return -EIO;
+}
+#else
+#define jffs2_verify_write(c,b,o) (0)
+#endif
+
+/* Recover from failure to write wbuf. Recover the nodes up to the
+ * wbuf, not the one which we were starting to try to write. */
+
+static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
+{
+ struct jffs2_eraseblock *jeb, *new_jeb;
+ struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL;
+ size_t retlen;
+ int ret;
+ int nr_refile = 0;
+ unsigned char *buf;
+ uint32_t start, end, ofs, len;
+
+ jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
+
+ spin_lock(&c->erase_completion_lock);
+ if (c->wbuf_ofs % c->mtd->erasesize)
+ jffs2_block_refile(c, jeb, REFILE_NOTEMPTY);
+ else
+ jffs2_block_refile(c, jeb, REFILE_ANYWAY);
+ spin_unlock(&c->erase_completion_lock);
+
+ BUG_ON(!ref_obsolete(jeb->last_node));
+
+ /* Find the first node to be recovered, by skipping over every
+ node which ends before the wbuf starts, or which is obsolete. */
+ for (next = raw = jeb->first_node; next; raw = next) {
+ next = ref_next(raw);
+
+ if (ref_obsolete(raw) ||
+ (next && ref_offset(next) <= c->wbuf_ofs)) {
+ dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
+ ref_offset(raw), ref_flags(raw),
+ (ref_offset(raw) + ref_totlen(c, jeb, raw)),
+ c->wbuf_ofs);
+ continue;
+ }
+ dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x\n",
+ ref_offset(raw), ref_flags(raw),
+ (ref_offset(raw) + ref_totlen(c, jeb, raw)));
+
+ first_raw = raw;
+ break;
+ }
+
+ if (!first_raw) {
+ /* All nodes were obsolete. Nothing to recover. */
+ jffs2_dbg(1, "No non-obsolete nodes to be recovered. Just filing block bad\n");
+ c->wbuf_len = 0;
+ return;
+ }
+
+ start = ref_offset(first_raw);
+ end = ref_offset(jeb->last_node);
+ nr_refile = 1;
+
+ /* Count the number of refs which need to be copied */
+ while ((raw = ref_next(raw)) != jeb->last_node)
+ nr_refile++;
+
+ dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes)\n",
+ start, end, end - start, nr_refile);
+
+ buf = NULL;
+ if (start < c->wbuf_ofs) {
+ /* First affected node was already partially written.
+ * Attempt to reread the old data into our buffer. */
+
+ buf = kmalloc(end - start, GFP_KERNEL);
+ if (!buf) {
+ pr_crit("Malloc failure in wbuf recovery. Data loss ensues.\n");
+
+ goto read_failed;
+ }
+
+ /* Do the read... */
+ ret = mtd_read(c->mtd, start, c->wbuf_ofs - start, &retlen,
+ buf);
+
+ /* ECC recovered ? */
+ if ((ret == -EUCLEAN || ret == -EBADMSG) &&
+ (retlen == c->wbuf_ofs - start))
+ ret = 0;
+
+ if (ret || retlen != c->wbuf_ofs - start) {
+ pr_crit("Old data are already lost in wbuf recovery. Data loss ensues.\n");
+
+ kfree(buf);
+ buf = NULL;
+ read_failed:
+ first_raw = ref_next(first_raw);
+ nr_refile--;
+ while (first_raw && ref_obsolete(first_raw)) {
+ first_raw = ref_next(first_raw);
+ nr_refile--;
+ }
+
+ /* If this was the only node to be recovered, give up */
+ if (!first_raw) {
+ c->wbuf_len = 0;
+ return;
+ }
+
+ /* It wasn't. Go on and try to recover nodes complete in the wbuf */
+ start = ref_offset(first_raw);
+ dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes)\n",
+ start, end, end - start, nr_refile);
+
+ } else {
+ /* Read succeeded. Copy the remaining data from the wbuf */
+ memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs);
+ }
+ }
+ /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards.
+ Either 'buf' contains the data, or we find it in the wbuf */
+
+ /* ... and get an allocation of space from a shiny new block instead */
+ ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE);
+ if (ret) {
+ pr_warn("Failed to allocate space for wbuf recovery. Data loss ensues.\n");
+ kfree(buf);
+ return;
+ }
+
+ /* The summary is not recovered, so it must be disabled for this erase block */
+ jffs2_sum_disable_collecting(c->summary);
+
+ ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile);
+ if (ret) {
+ pr_warn("Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
+ kfree(buf);
+ return;
+ }
+
+ ofs = write_ofs(c);
+
+ if (end-start >= c->wbuf_pagesize) {
+ /* Need to do another write immediately, but it's possible
+ that this is just because the wbuf itself is completely
+ full, and there's nothing earlier read back from the
+ flash. Hence 'buf' isn't necessarily what we're writing
+ from. */
+ unsigned char *rewrite_buf = buf?:c->wbuf;
+ uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
+
+ jffs2_dbg(1, "Write 0x%x bytes at 0x%08x in wbuf recover\n",
+ towrite, ofs);
+
+#ifdef BREAKMEHEADER
+ static int breakme;
+ if (breakme++ == 20) {
+ pr_notice("Faking write error at 0x%08x\n", ofs);
+ breakme = 0;
+ mtd_write(c->mtd, ofs, towrite, &retlen, brokenbuf);
+ ret = -EIO;
+ } else
+#endif
+ ret = mtd_write(c->mtd, ofs, towrite, &retlen,
+ rewrite_buf);
+
+ if (ret || retlen != towrite || jffs2_verify_write(c, rewrite_buf, ofs)) {
+ /* Argh. We tried. Really we did. */
+ pr_crit("Recovery of wbuf failed due to a second write error\n");
+ kfree(buf);
+
+ if (retlen)
+ jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL);
+
+ return;
+ }
+ pr_notice("Recovery of wbuf succeeded to %08x\n", ofs);
+
+ c->wbuf_len = (end - start) - towrite;
+ c->wbuf_ofs = ofs + towrite;
+ memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
+ /* Don't muck about with c->wbuf_inodes. False positives are harmless. */
+ } else {
+ /* OK, now we're left with the dregs in whichever buffer we're using */
+ if (buf) {
+ memcpy(c->wbuf, buf, end-start);
+ } else {
+ memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start);
+ }
+ c->wbuf_ofs = ofs;
+ c->wbuf_len = end - start;
+ }
+
+ /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */
+ new_jeb = &c->blocks[ofs / c->sector_size];
+
+ spin_lock(&c->erase_completion_lock);
+ for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) {
+ uint32_t rawlen = ref_totlen(c, jeb, raw);
+ struct jffs2_inode_cache *ic;
+ struct jffs2_raw_node_ref *new_ref;
+ struct jffs2_raw_node_ref **adjust_ref = NULL;
+ struct jffs2_inode_info *f = NULL;
+
+ jffs2_dbg(1, "Refiling block of %08x at %08x(%d) to %08x\n",
+ rawlen, ref_offset(raw), ref_flags(raw), ofs);
+
+ ic = jffs2_raw_ref_to_ic(raw);
+
+ /* Ick. This XATTR mess should be fixed shortly... */
+ if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) {
+ struct jffs2_xattr_datum *xd = (void *)ic;
+ BUG_ON(xd->node != raw);
+ adjust_ref = &xd->node;
+ raw->next_in_ino = NULL;
+ ic = NULL;
+ } else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) {
+ struct jffs2_xattr_datum *xr = (void *)ic;
+ BUG_ON(xr->node != raw);
+ adjust_ref = &xr->node;
+ raw->next_in_ino = NULL;
+ ic = NULL;
+ } else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) {
+ struct jffs2_raw_node_ref **p = &ic->nodes;
+
+ /* Remove the old node from the per-inode list */
+ while (*p && *p != (void *)ic) {
+ if (*p == raw) {
+ (*p) = (raw->next_in_ino);
+ raw->next_in_ino = NULL;
+ break;
+ }
+ p = &((*p)->next_in_ino);
+ }
+
+ if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) {
+ /* If it's an in-core inode, then we have to adjust any
+ full_dirent or full_dnode structure to point to the
+ new version instead of the old */
+ f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink);
+ if (IS_ERR(f)) {
+ /* Should never happen; it _must_ be present */
+ JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",
+ ic->ino, PTR_ERR(f));
+ BUG();
+ }
+ /* We don't lock f->sem. There's a number of ways we could
+ end up in here with it already being locked, and nobody's
+ going to modify it on us anyway because we hold the
+ alloc_sem. We're only changing one ->raw pointer too,
+ which we can get away with without upsetting readers. */
+ adjust_ref = jffs2_incore_replace_raw(c, f, raw,
+ (void *)(buf?:c->wbuf) + (ref_offset(raw) - start));
+ } else if (unlikely(ic->state != INO_STATE_PRESENT &&
+ ic->state != INO_STATE_CHECKEDABSENT &&
+ ic->state != INO_STATE_GC)) {
+ JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state);
+ BUG();
+ }
+ }
+
+ new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic);
+
+ if (adjust_ref) {
+ BUG_ON(*adjust_ref != raw);
+ *adjust_ref = new_ref;
+ }
+ if (f)
+ jffs2_gc_release_inode(c, f);
+
+ if (!ref_obsolete(raw)) {
+ jeb->dirty_size += rawlen;
+ jeb->used_size -= rawlen;
+ c->dirty_size += rawlen;
+ c->used_size -= rawlen;
+ raw->flash_offset = ref_offset(raw) | REF_OBSOLETE;
+ BUG_ON(raw->next_in_ino);
+ }
+ ofs += rawlen;
+ }
+
+ kfree(buf);
+
+ /* Fix up the original jeb now it's on the bad_list */
+ if (first_raw == jeb->first_node) {
+ jffs2_dbg(1, "Failing block at %08x is now empty. Moving to erase_pending_list\n",
+ jeb->offset);
+ list_move(&jeb->list, &c->erase_pending_list);
+ c->nr_erasing_blocks++;
+ jffs2_garbage_collect_trigger(c);
+ }
+
+ jffs2_dbg_acct_sanity_check_nolock(c, jeb);
+ jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
+
+ jffs2_dbg_acct_sanity_check_nolock(c, new_jeb);
+ jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb);
+
+ spin_unlock(&c->erase_completion_lock);
+
+ jffs2_dbg(1, "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n",
+ c->wbuf_ofs, c->wbuf_len);
+
+}
+
+/* Meaning of pad argument:
+ 0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway.
+ 1: Pad, do not adjust nextblock free_size
+ 2: Pad, adjust nextblock free_size
+*/
+#define NOPAD 0
+#define PAD_NOACCOUNT 1
+#define PAD_ACCOUNTING 2
+
+static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
+{
+ struct jffs2_eraseblock *wbuf_jeb;
+ int ret;
+ size_t retlen;
+
+ /* Nothing to do if not write-buffering the flash. In particular, we shouldn't
+ del_timer() the timer we never initialised. */
+ if (!jffs2_is_writebuffered(c))
+ return 0;
+
+ if (!mutex_is_locked(&c->alloc_sem)) {
+ pr_crit("jffs2_flush_wbuf() called with alloc_sem not locked!\n");
+ BUG();
+ }
+
+ if (!c->wbuf_len) /* already checked c->wbuf above */
+ return 0;
+
+ wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
+ if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1))
+ return -ENOMEM;
+
+ /* claim remaining space on the page
+ this happens, if we have a change to a new block,
+ or if fsync forces us to flush the writebuffer.
+ if we have a switch to next page, we will not have
+ enough remaining space for this.
+ */
+ if (pad ) {
+ c->wbuf_len = PAD(c->wbuf_len);
+
+ /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR
+ with 8 byte page size */
+ memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
+
+ if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
+ struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
+ padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
+ padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
+ padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
+ }
+ }
+ /* else jffs2_flash_writev has actually filled in the rest of the
+ buffer for us, and will deal with the node refs etc. later. */
+
+#ifdef BREAKME
+ static int breakme;
+ if (breakme++ == 20) {
+ pr_notice("Faking write error at 0x%08x\n", c->wbuf_ofs);
+ breakme = 0;
+ mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen,
+ brokenbuf);
+ ret = -EIO;
+ } else
+#endif
+
+ ret = mtd_write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
+ &retlen, c->wbuf);
+
+ if (ret) {
+ pr_warn("jffs2_flush_wbuf(): Write failed with %d\n", ret);
+ goto wfail;
+ } else if (retlen != c->wbuf_pagesize) {
+ pr_warn("jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
+ retlen, c->wbuf_pagesize);
+ ret = -EIO;
+ goto wfail;
+ } else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {
+ wfail:
+ jffs2_wbuf_recover(c);
+
+ return ret;
+ }
+
+ /* Adjust free size of the block if we padded. */
+ if (pad) {
+ uint32_t waste = c->wbuf_pagesize - c->wbuf_len;
+
+ jffs2_dbg(1, "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
+ (wbuf_jeb == c->nextblock) ? "next" : "",
+ wbuf_jeb->offset);
+
+ /* wbuf_pagesize - wbuf_len is the amount of space that's to be
+ padded. If there is less free space in the block than that,
+ something screwed up */
+ if (wbuf_jeb->free_size < waste) {
+ pr_crit("jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
+ c->wbuf_ofs, c->wbuf_len, waste);
+ pr_crit("jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
+ wbuf_jeb->offset, wbuf_jeb->free_size);
+ BUG();
+ }
+
+ spin_lock(&c->erase_completion_lock);
+
+ jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL);
+ /* FIXME: that made it count as dirty. Convert to wasted */
+ wbuf_jeb->dirty_size -= waste;
+ c->dirty_size -= waste;
+ wbuf_jeb->wasted_size += waste;
+ c->wasted_size += waste;
+ } else
+ spin_lock(&c->erase_completion_lock);
+
+ /* Stick any now-obsoleted blocks on the erase_pending_list */
+ jffs2_refile_wbuf_blocks(c);
+ jffs2_clear_wbuf_ino_list(c);
+ spin_unlock(&c->erase_completion_lock);
+
+ memset(c->wbuf,0xff,c->wbuf_pagesize);
+ /* adjust write buffer offset, else we get a non contiguous write bug */
+ c->wbuf_ofs += c->wbuf_pagesize;
+ c->wbuf_len = 0;
+ return 0;
+}
+
+/* Trigger garbage collection to flush the write-buffer.
+ If ino arg is zero, do it if _any_ real (i.e. not GC) writes are
+ outstanding. If ino arg non-zero, do it only if a write for the
+ given inode is outstanding. */
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
+{
+ uint32_t old_wbuf_ofs;
+ uint32_t old_wbuf_len;
+ int ret = 0;
+
+ jffs2_dbg(1, "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino);
+
+ if (!c->wbuf)
+ return 0;
+
+ mutex_lock(&c->alloc_sem);
+ if (!jffs2_wbuf_pending_for_ino(c, ino)) {
+ jffs2_dbg(1, "Ino #%d not pending in wbuf. Returning\n", ino);
+ mutex_unlock(&c->alloc_sem);
+ return 0;
+ }
+
+ old_wbuf_ofs = c->wbuf_ofs;
+ old_wbuf_len = c->wbuf_len;
+
+ if (c->unchecked_size) {
+ /* GC won't make any progress for a while */
+ jffs2_dbg(1, "%s(): padding. Not finished checking\n",
+ __func__);
+ down_write(&c->wbuf_sem);
+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+ /* retry flushing wbuf in case jffs2_wbuf_recover
+ left some data in the wbuf */
+ if (ret)
+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+ up_write(&c->wbuf_sem);
+ } else while (old_wbuf_len &&
+ old_wbuf_ofs == c->wbuf_ofs) {
+
+ mutex_unlock(&c->alloc_sem);
+
+ jffs2_dbg(1, "%s(): calls gc pass\n", __func__);
+
+ ret = jffs2_garbage_collect_pass(c);
+ if (ret) {
+ /* GC failed. Flush it with padding instead */
+ mutex_lock(&c->alloc_sem);
+ down_write(&c->wbuf_sem);
+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+ /* retry flushing wbuf in case jffs2_wbuf_recover
+ left some data in the wbuf */
+ if (ret)
+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+ up_write(&c->wbuf_sem);
+ break;
+ }
+ mutex_lock(&c->alloc_sem);
+ }
+
+ jffs2_dbg(1, "%s(): ends...\n", __func__);
+
+ mutex_unlock(&c->alloc_sem);
+ return ret;
+}
+
+/* Pad write-buffer to end and write it, wasting space. */
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
+{
+ int ret;
+
+ if (!c->wbuf)
+ return 0;
+
+ down_write(&c->wbuf_sem);
+ ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
+ /* retry - maybe wbuf recover left some data in wbuf. */
+ if (ret)
+ ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
+ up_write(&c->wbuf_sem);
+
+ return ret;
+}
+
+static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf,
+ size_t len)
+{
+ if (len && !c->wbuf_len && (len >= c->wbuf_pagesize))
+ return 0;
+
+ if (len > (c->wbuf_pagesize - c->wbuf_len))
+ len = c->wbuf_pagesize - c->wbuf_len;
+ memcpy(c->wbuf + c->wbuf_len, buf, len);
+ c->wbuf_len += (uint32_t) len;
+ return len;
+}
+
+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
+ unsigned long count, loff_t to, size_t *retlen,
+ uint32_t ino)
+{
+ struct jffs2_eraseblock *jeb;
+ size_t wbuf_retlen, donelen = 0;
+ uint32_t outvec_to = to;
+ int ret, invec;
+
+ /* If not writebuffered flash, don't bother */
+ if (!jffs2_is_writebuffered(c))
+ return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
+
+ down_write(&c->wbuf_sem);
+
+ /* If wbuf_ofs is not initialized, set it to target address */
+ if (c->wbuf_ofs == 0xFFFFFFFF) {
+ c->wbuf_ofs = PAGE_DIV(to);
+ c->wbuf_len = PAGE_MOD(to);
+ memset(c->wbuf,0xff,c->wbuf_pagesize);
+ }
+
+ /*
+ * Sanity checks on target address. It's permitted to write
+ * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to
+ * write at the beginning of a new erase block. Anything else,
+ * and you die. New block starts at xxx000c (0-b = block
+ * header)
+ */
+ if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
+ /* It's a write to a new block */
+ if (c->wbuf_len) {
+ jffs2_dbg(1, "%s(): to 0x%lx causes flush of wbuf at 0x%08x\n",
+ __func__, (unsigned long)to, c->wbuf_ofs);
+ ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
+ if (ret)
+ goto outerr;
+ }
+ /* set pointer to new block */
+ c->wbuf_ofs = PAGE_DIV(to);
+ c->wbuf_len = PAGE_MOD(to);
+ }
+
+ if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
+ /* We're not writing immediately after the writebuffer. Bad. */
+ pr_crit("%s(): Non-contiguous write to %08lx\n",
+ __func__, (unsigned long)to);
+ if (c->wbuf_len)
+ pr_crit("wbuf was previously %08x-%08x\n",
+ c->wbuf_ofs, c->wbuf_ofs + c->wbuf_len);
+ BUG();
+ }
+
+ /* adjust alignment offset */
+ if (c->wbuf_len != PAGE_MOD(to)) {
+ c->wbuf_len = PAGE_MOD(to);
+ /* take care of alignment to next page */
+ if (!c->wbuf_len) {
+ c->wbuf_len = c->wbuf_pagesize;
+ ret = __jffs2_flush_wbuf(c, NOPAD);
+ if (ret)
+ goto outerr;
+ }
+ }
+
+ for (invec = 0; invec < count; invec++) {
+ int vlen = invecs[invec].iov_len;
+ uint8_t *v = invecs[invec].iov_base;
+
+ wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);
+
+ if (c->wbuf_len == c->wbuf_pagesize) {
+ ret = __jffs2_flush_wbuf(c, NOPAD);
+ if (ret)
+ goto outerr;
+ }
+ vlen -= wbuf_retlen;
+ outvec_to += wbuf_retlen;
+ donelen += wbuf_retlen;
+ v += wbuf_retlen;
+
+ if (vlen >= c->wbuf_pagesize) {
+ ret = mtd_write(c->mtd, outvec_to, PAGE_DIV(vlen),
+ &wbuf_retlen, v);
+ if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen))
+ goto outfile;
+
+ vlen -= wbuf_retlen;
+ outvec_to += wbuf_retlen;
+ c->wbuf_ofs = outvec_to;
+ donelen += wbuf_retlen;
+ v += wbuf_retlen;
+ }
+
+ wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);
+ if (c->wbuf_len == c->wbuf_pagesize) {
+ ret = __jffs2_flush_wbuf(c, NOPAD);
+ if (ret)
+ goto outerr;
+ }
+
+ outvec_to += wbuf_retlen;
+ donelen += wbuf_retlen;
+ }
+
+ /*
+ * If there's a remainder in the wbuf and it's a non-GC write,
+ * remember that the wbuf affects this ino
+ */
+ *retlen = donelen;
+
+ if (jffs2_sum_active()) {
+ int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to);
+ if (res)
+ return res;
+ }
+
+ if (c->wbuf_len && ino)
+ jffs2_wbuf_dirties_inode(c, ino);
+
+ ret = 0;
+ up_write(&c->wbuf_sem);
+ return ret;
+
+outfile:
+ /*
+ * At this point we have no problem, c->wbuf is empty. However
+ * refile nextblock to avoid writing again to same address.
+ */
+
+ spin_lock(&c->erase_completion_lock);
+
+ jeb = &c->blocks[outvec_to / c->sector_size];
+ jffs2_block_refile(c, jeb, REFILE_ANYWAY);
+
+ spin_unlock(&c->erase_completion_lock);
+
+outerr:
+ *retlen = 0;
+ up_write(&c->wbuf_sem);
+ return ret;
+}
+
+/*
+ * This is the entry for flash write.
+ * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev
+*/
+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct kvec vecs[1];
+
+ if (!jffs2_is_writebuffered(c))
+ return jffs2_flash_direct_write(c, ofs, len, retlen, buf);
+
+ vecs[0].iov_base = (unsigned char *) buf;
+ vecs[0].iov_len = len;
+ return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0);
+}
+
+/*
+ Handle readback from writebuffer and ECC failure return
+*/
+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf)
+{
+ loff_t orbf = 0, owbf = 0, lwbf = 0;
+ int ret;
+
+ if (!jffs2_is_writebuffered(c))
+ return mtd_read(c->mtd, ofs, len, retlen, buf);
+
+ /* Read flash */
+ down_read(&c->wbuf_sem);
+ ret = mtd_read(c->mtd, ofs, len, retlen, buf);
+
+ if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) {
+ if (ret == -EBADMSG)
+ pr_warn("mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
+ len, ofs);
+ /*
+ * We have the raw data without ECC correction in the buffer,
+ * maybe we are lucky and all data or parts are correct. We
+ * check the node. If data are corrupted node check will sort
+ * it out. We keep this block, it will fail on write or erase
+ * and the we mark it bad. Or should we do that now? But we
+ * should give him a chance. Maybe we had a system crash or
+ * power loss before the ecc write or a erase was completed.
+ * So we return success. :)
+ */
+ ret = 0;
+ }
+
+ /* if no writebuffer available or write buffer empty, return */
+ if (!c->wbuf_pagesize || !c->wbuf_len)
+ goto exit;
+
+ /* if we read in a different block, return */
+ if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))
+ goto exit;
+
+ if (ofs >= c->wbuf_ofs) {
+ owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */
+ if (owbf > c->wbuf_len) /* is read beyond write buffer ? */
+ goto exit;
+ lwbf = c->wbuf_len - owbf; /* number of bytes to copy */
+ if (lwbf > len)
+ lwbf = len;
+ } else {
+ orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */
+ if (orbf > len) /* is write beyond write buffer ? */
+ goto exit;
+ lwbf = len - orbf; /* number of bytes to copy */
+ if (lwbf > c->wbuf_len)
+ lwbf = c->wbuf_len;
+ }
+ if (lwbf > 0)
+ memcpy(buf+orbf,c->wbuf+owbf,lwbf);
+
+exit:
+ up_read(&c->wbuf_sem);
+ return ret;
+}
+
+#define NR_OOB_SCAN_PAGES 4
+
+/* For historical reasons we use only 8 bytes for OOB clean marker */
+#define OOB_CM_SIZE 8
+
+static const struct jffs2_unknown_node oob_cleanmarker =
+{
+ .magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK),
+ .nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
+ .totlen = constant_cpu_to_je32(8)
+};
+
+/*
+ * Check, if the out of band area is empty. This function knows about the clean
+ * marker and if it is present in OOB, treats the OOB as empty anyway.
+ */
+int jffs2_check_oob_empty(struct jffs2_sb_info *c,
+ struct jffs2_eraseblock *jeb, int mode)
+{
+ int i, ret;
+ int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
+ struct mtd_oob_ops ops = { };
+
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail;
+ ops.oobbuf = c->oobbuf;
+ ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
+ ops.datbuf = NULL;
+
+ ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
+ if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) {
+ pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+ jeb->offset, ops.ooblen, ops.oobretlen, ret);
+ if (!ret || mtd_is_bitflip(ret))
+ ret = -EIO;
+ return ret;
+ }
+
+ for(i = 0; i < ops.ooblen; i++) {
+ if (mode && i < cmlen)
+ /* Yeah, we know about the cleanmarker */
+ continue;
+
+ if (ops.oobbuf[i] != 0xFF) {
+ jffs2_dbg(2, "Found %02x at %x in OOB for "
+ "%08x\n", ops.oobbuf[i], i, jeb->offset);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Check for a valid cleanmarker.
+ * Returns: 0 if a valid cleanmarker was found
+ * 1 if no cleanmarker was found
+ * negative error code if an error occurred
+ */
+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,
+ struct jffs2_eraseblock *jeb)
+{
+ struct mtd_oob_ops ops = { };
+ int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
+
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.ooblen = cmlen;
+ ops.oobbuf = c->oobbuf;
+ ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
+ ops.datbuf = NULL;
+
+ ret = mtd_read_oob(c->mtd, jeb->offset, &ops);
+ if ((ret && !mtd_is_bitflip(ret)) || ops.oobretlen != ops.ooblen) {
+ pr_err("cannot read OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+ jeb->offset, ops.ooblen, ops.oobretlen, ret);
+ if (!ret || mtd_is_bitflip(ret))
+ ret = -EIO;
+ return ret;
+ }
+
+ return !!memcmp(&oob_cleanmarker, c->oobbuf, cmlen);
+}
+
+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,
+ struct jffs2_eraseblock *jeb)
+{
+ int ret;
+ struct mtd_oob_ops ops = { };
+ int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);
+
+ ops.mode = MTD_OPS_AUTO_OOB;
+ ops.ooblen = cmlen;
+ ops.oobbuf = (uint8_t *)&oob_cleanmarker;
+ ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
+ ops.datbuf = NULL;
+
+ ret = mtd_write_oob(c->mtd, jeb->offset, &ops);
+ if (ret || ops.oobretlen != ops.ooblen) {
+ pr_err("cannot write OOB for EB at %08x, requested %zd bytes, read %zd bytes, error %d\n",
+ jeb->offset, ops.ooblen, ops.oobretlen, ret);
+ if (!ret)
+ ret = -EIO;
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * On NAND we try to mark this block bad. If the block was erased more
+ * than MAX_ERASE_FAILURES we mark it finally bad.
+ * Don't care about failures. This block remains on the erase-pending
+ * or badblock list as long as nobody manipulates the flash with
+ * a bootloader or something like that.
+ */
+
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
+{
+ int ret;
+
+ /* if the count is < max, we try to write the counter to the 2nd page oob area */
+ if( ++jeb->bad_count < MAX_ERASE_FAILURES)
+ return 0;
+
+ pr_warn("marking eraseblock at %08x as bad\n", bad_offset);
+ ret = mtd_block_markbad(c->mtd, bad_offset);
+
+ if (ret) {
+ jffs2_dbg(1, "%s(): Write failed for block at %08x: error %d\n",
+ __func__, jeb->offset, ret);
+ return ret;
+ }
+ return 1;
+}
+
+static struct jffs2_sb_info *work_to_sb(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+
+ dwork = to_delayed_work(work);
+ return container_of(dwork, struct jffs2_sb_info, wbuf_dwork);
+}
+
+static void delayed_wbuf_sync(struct work_struct *work)
+{
+ struct jffs2_sb_info *c = work_to_sb(work);
+ struct super_block *sb = OFNI_BS_2SFFJ(c);
+
+ if (!sb_rdonly(sb)) {
+ jffs2_dbg(1, "%s()\n", __func__);
+ jffs2_flush_wbuf_gc(c, 0);
+ }
+}
+
+void jffs2_dirty_trigger(struct jffs2_sb_info *c)
+{
+ struct super_block *sb = OFNI_BS_2SFFJ(c);
+ unsigned long delay;
+
+ if (sb_rdonly(sb))
+ return;
+
+ delay = msecs_to_jiffies(dirty_writeback_interval * 10);
+ if (queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay))
+ jffs2_dbg(1, "%s()\n", __func__);
+}
+
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+{
+ if (!c->mtd->oobsize)
+ return 0;
+
+ /* Cleanmarker is out-of-band, so inline size zero */
+ c->cleanmarker_size = 0;
+
+ if (c->mtd->oobavail == 0) {
+ pr_err("inconsistent device description\n");
+ return -EINVAL;
+ }
+
+ jffs2_dbg(1, "using OOB on NAND\n");
+
+ c->oobavail = c->mtd->oobavail;
+
+ /* Initialise write buffer */
+ init_rwsem(&c->wbuf_sem);
+ INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
+ c->wbuf_pagesize = c->mtd->writesize;
+ c->wbuf_ofs = 0xFFFFFFFF;
+
+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf)
+ return -ENOMEM;
+
+ c->oobbuf = kmalloc_array(NR_OOB_SCAN_PAGES, c->oobavail, GFP_KERNEL);
+ if (!c->oobbuf) {
+ kfree(c->wbuf);
+ return -ENOMEM;
+ }
+
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf_verify) {
+ kfree(c->oobbuf);
+ kfree(c->wbuf);
+ return -ENOMEM;
+ }
+#endif
+ return 0;
+}
+
+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
+{
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ kfree(c->wbuf_verify);
+#endif
+ kfree(c->wbuf);
+ kfree(c->oobbuf);
+}
+
+int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
+ c->cleanmarker_size = 0; /* No cleanmarkers needed */
+
+ /* Initialize write buffer */
+ init_rwsem(&c->wbuf_sem);
+ INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
+ c->wbuf_pagesize = c->mtd->erasesize;
+
+ /* Find a suitable c->sector_size
+ * - Not too much sectors
+ * - Sectors have to be at least 4 K + some bytes
+ * - All known dataflashes have erase sizes of 528 or 1056
+ * - we take at least 8 eraseblocks and want to have at least 8K size
+ * - The concatenation should be a power of 2
+ */
+
+ c->sector_size = 8 * c->mtd->erasesize;
+
+ while (c->sector_size < 8192) {
+ c->sector_size *= 2;
+ }
+
+ /* It may be necessary to adjust the flash size */
+ c->flash_size = c->mtd->size;
+
+ if ((c->flash_size % c->sector_size) != 0) {
+ c->flash_size = (c->flash_size / c->sector_size) * c->sector_size;
+ pr_warn("flash size adjusted to %dKiB\n", c->flash_size);
+ }
+
+ c->wbuf_ofs = 0xFFFFFFFF;
+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf)
+ return -ENOMEM;
+
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf_verify) {
+ kfree(c->wbuf);
+ return -ENOMEM;
+ }
+#endif
+
+ pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n",
+ c->wbuf_pagesize, c->sector_size);
+
+ return 0;
+}
+
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ kfree(c->wbuf_verify);
+#endif
+ kfree(c->wbuf);
+}
+
+int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
+ /* Cleanmarker currently occupies whole programming regions,
+ * either one or 2 for 8Byte STMicro flashes. */
+ c->cleanmarker_size = max(16u, c->mtd->writesize);
+
+ /* Initialize write buffer */
+ init_rwsem(&c->wbuf_sem);
+ INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
+
+ c->wbuf_pagesize = c->mtd->writesize;
+ c->wbuf_ofs = 0xFFFFFFFF;
+
+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf)
+ return -ENOMEM;
+
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf_verify) {
+ kfree(c->wbuf);
+ return -ENOMEM;
+ }
+#endif
+ return 0;
+}
+
+void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) {
+#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
+ kfree(c->wbuf_verify);
+#endif
+ kfree(c->wbuf);
+}
+
+int jffs2_ubivol_setup(struct jffs2_sb_info *c) {
+ c->cleanmarker_size = 0;
+
+ if (c->mtd->writesize == 1)
+ /* We do not need write-buffer */
+ return 0;
+
+ init_rwsem(&c->wbuf_sem);
+ INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
+
+ c->wbuf_pagesize = c->mtd->writesize;
+ c->wbuf_ofs = 0xFFFFFFFF;
+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf)
+ return -ENOMEM;
+
+ pr_info("write-buffering enabled buffer (%d) erasesize (%d)\n",
+ c->wbuf_pagesize, c->sector_size);
+
+ return 0;
+}
+
+void jffs2_ubivol_cleanup(struct jffs2_sb_info *c) {
+ kfree(c->wbuf);
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems.c b/cpukit/libfs/src/rfs/rtems-rfs-rtems.c
index 4db48a8422..58c082f2ee 100644
--- a/cpukit/libfs/src/rfs/rtems-rfs-rtems.c
+++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems.c
@@ -12,7 +12,7 @@
* COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions