diff options
Diffstat (limited to 'cpukit/libfs')
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 |