2005-04-17 02:20:36 +04:00
/*
* JFFS2 - - Journalling Flash File System , Version 2.
*
2007-04-25 17:16:47 +04:00
* Copyright © 2001 - 2007 Red Hat , Inc .
2005-04-17 02:20:36 +04:00
*
* Created by David Woodhouse < dwmw2 @ infradead . org >
*
* For licensing information , see the file ' LICENCE ' in this directory .
*
*/
2012-02-16 03:56:45 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/list.h>
# include <linux/fs.h>
2006-10-11 15:52:47 +04:00
# include <linux/err.h>
2005-04-17 02:20:36 +04:00
# include <linux/mount.h>
2019-03-25 19:38:32 +03:00
# include <linux/fs_context.h>
# include <linux/fs_parser.h>
2005-04-17 02:20:36 +04:00
# include <linux/jffs2.h>
# include <linux/pagemap.h>
2007-05-11 09:51:50 +04:00
# include <linux/mtd/super.h>
2005-04-17 02:20:36 +04:00
# include <linux/ctype.h>
# include <linux/namei.h>
2011-10-17 05:15:16 +04:00
# include <linux/seq_file.h>
2008-07-31 23:39:25 +04:00
# include <linux/exportfs.h>
2005-04-17 02:20:36 +04:00
# include "compr.h"
# include "nodelist.h"
static void jffs2_put_super ( struct super_block * ) ;
2006-12-07 07:33:20 +03:00
static struct kmem_cache * jffs2_inode_cachep ;
2005-04-17 02:20:36 +04:00
static struct inode * jffs2_alloc_inode ( struct super_block * sb )
{
2008-05-01 15:28:04 +04:00
struct jffs2_inode_info * f ;
f = kmem_cache_alloc ( jffs2_inode_cachep , GFP_KERNEL ) ;
if ( ! f )
2005-04-17 02:20:36 +04:00
return NULL ;
2008-05-01 15:28:04 +04:00
return & f - > vfs_inode ;
2005-04-17 02:20:36 +04:00
}
2019-04-16 03:15:58 +03:00
static void jffs2_free_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2019-03-26 04:39:50 +03:00
struct jffs2_inode_info * f = JFFS2_INODE_INFO ( inode ) ;
kfree ( f - > target ) ;
kmem_cache_free ( jffs2_inode_cachep , f ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-26 06:45:34 +04:00
static void jffs2_i_init_once ( void * foo )
2005-04-17 02:20:36 +04:00
{
2008-05-01 15:28:04 +04:00
struct jffs2_inode_info * f = foo ;
2005-04-17 02:20:36 +04:00
2008-05-01 15:28:04 +04:00
mutex_init ( & f - > sem ) ;
inode_init_once ( & f - > vfs_inode ) ;
2005-04-17 02:20:36 +04:00
}
2011-10-17 05:15:16 +04:00
static const char * jffs2_compr_name ( unsigned int compr )
{
switch ( compr ) {
case JFFS2_COMPR_MODE_NONE :
return " none " ;
2011-10-17 05:15:23 +04:00
# ifdef CONFIG_JFFS2_LZO
case JFFS2_COMPR_MODE_FORCELZO :
return " lzo " ;
# endif
# ifdef CONFIG_JFFS2_ZLIB
case JFFS2_COMPR_MODE_FORCEZLIB :
return " zlib " ;
# endif
2011-10-17 05:15:16 +04:00
default :
/* should never happen; programmer error */
WARN_ON ( 1 ) ;
return " " ;
}
}
2011-12-09 06:32:45 +04:00
static int jffs2_show_options ( struct seq_file * s , struct dentry * root )
2011-10-17 05:15:16 +04:00
{
2011-12-09 06:32:45 +04:00
struct jffs2_sb_info * c = JFFS2_SB_INFO ( root - > d_sb ) ;
2011-10-17 05:15:16 +04:00
struct jffs2_mount_opts * opts = & c - > mount_opts ;
if ( opts - > override_compr )
seq_printf ( s , " ,compr=%s " , jffs2_compr_name ( opts - > compr ) ) ;
2012-04-11 01:22:35 +04:00
if ( opts - > rp_size )
seq_printf ( s , " ,rp_size=%u " , opts - > rp_size / 1024 ) ;
2011-10-17 05:15:16 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
static int jffs2_sync_fs ( struct super_block * sb , int wait )
{
struct jffs2_sb_info * c = JFFS2_SB_INFO ( sb ) ;
2012-08-23 11:10:07 +04:00
# ifdef CONFIG_JFFS2_FS_WRITEBUFFER
2018-10-19 11:30:20 +03:00
if ( jffs2_is_writebuffered ( c ) )
cancel_delayed_work_sync ( & c - > wbuf_dwork ) ;
2012-08-23 11:10:07 +04:00
# endif
2008-04-22 18:13:40 +04:00
mutex_lock ( & c - > alloc_sem ) ;
2005-04-17 02:20:36 +04:00
jffs2_flush_wbuf_pad ( c ) ;
2008-04-22 18:13:40 +04:00
mutex_unlock ( & c - > alloc_sem ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-07-31 23:39:25 +04:00
static struct inode * jffs2_nfs_get_inode ( struct super_block * sb , uint64_t ino ,
uint32_t generation )
{
/* We don't care about i_generation. We'll destroy the flash
before we start re - using inode numbers anyway . And even
if that wasn ' t true , we ' d have other problems . . . */
return jffs2_iget ( sb , ino ) ;
}
static struct dentry * jffs2_fh_to_dentry ( struct super_block * sb , struct fid * fid ,
int fh_len , int fh_type )
{
return generic_fh_to_dentry ( sb , fid , fh_len , fh_type ,
jffs2_nfs_get_inode ) ;
}
static struct dentry * jffs2_fh_to_parent ( struct super_block * sb , struct fid * fid ,
int fh_len , int fh_type )
{
return generic_fh_to_parent ( sb , fid , fh_len , fh_type ,
jffs2_nfs_get_inode ) ;
}
static struct dentry * jffs2_get_parent ( struct dentry * child )
{
struct jffs2_inode_info * f ;
uint32_t pino ;
VFS: (Scripted) Convert S_ISLNK/DIR/REG(dentry->d_inode) to d_is_*(dentry)
Convert the following where appropriate:
(1) S_ISLNK(dentry->d_inode) to d_is_symlink(dentry).
(2) S_ISREG(dentry->d_inode) to d_is_reg(dentry).
(3) S_ISDIR(dentry->d_inode) to d_is_dir(dentry). This is actually more
complicated than it appears as some calls should be converted to
d_can_lookup() instead. The difference is whether the directory in
question is a real dir with a ->lookup op or whether it's a fake dir with
a ->d_automount op.
In some circumstances, we can subsume checks for dentry->d_inode not being
NULL into this, provided we the code isn't in a filesystem that expects
d_inode to be NULL if the dirent really *is* negative (ie. if we're going to
use d_inode() rather than d_backing_inode() to get the inode pointer).
Note that the dentry type field may be set to something other than
DCACHE_MISS_TYPE when d_inode is NULL in the case of unionmount, where the VFS
manages the fall-through from a negative dentry to a lower layer. In such a
case, the dentry type of the negative union dentry is set to the same as the
type of the lower dentry.
However, if you know d_inode is not NULL at the call site, then you can use
the d_is_xxx() functions even in a filesystem.
There is one further complication: a 0,0 chardev dentry may be labelled
DCACHE_WHITEOUT_TYPE rather than DCACHE_SPECIAL_TYPE. Strictly, this was
intended for special directory entry types that don't have attached inodes.
The following perl+coccinelle script was used:
use strict;
my @callers;
open($fd, 'git grep -l \'S_IS[A-Z].*->d_inode\' |') ||
die "Can't grep for S_ISDIR and co. callers";
@callers = <$fd>;
close($fd);
unless (@callers) {
print "No matches\n";
exit(0);
}
my @cocci = (
'@@',
'expression E;',
'@@',
'',
'- S_ISLNK(E->d_inode->i_mode)',
'+ d_is_symlink(E)',
'',
'@@',
'expression E;',
'@@',
'',
'- S_ISDIR(E->d_inode->i_mode)',
'+ d_is_dir(E)',
'',
'@@',
'expression E;',
'@@',
'',
'- S_ISREG(E->d_inode->i_mode)',
'+ d_is_reg(E)' );
my $coccifile = "tmp.sp.cocci";
open($fd, ">$coccifile") || die $coccifile;
print($fd "$_\n") || die $coccifile foreach (@cocci);
close($fd);
foreach my $file (@callers) {
chomp $file;
print "Processing ", $file, "\n";
system("spatch", "--sp-file", $coccifile, $file, "--in-place", "--no-show-diff") == 0 ||
die "spatch failed";
}
[AV: overlayfs parts skipped]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2015-01-29 15:02:35 +03:00
BUG_ON ( ! d_is_dir ( child ) ) ;
2008-07-31 23:39:25 +04:00
2015-03-18 01:25:59 +03:00
f = JFFS2_INODE_INFO ( d_inode ( child ) ) ;
2008-07-31 23:39:25 +04:00
pino = f - > inocache - > pino_nlink ;
JFFS2_DEBUG ( " Parent of directory ino #%u is #%u \n " ,
f - > inocache - > ino , pino ) ;
2016-04-10 08:33:30 +03:00
return d_obtain_alias ( jffs2_iget ( child - > d_sb , pino ) ) ;
2008-07-31 23:39:25 +04:00
}
2009-09-22 04:01:10 +04:00
static const struct export_operations jffs2_export_ops = {
2008-07-31 23:39:25 +04:00
. get_parent = jffs2_get_parent ,
. fh_to_dentry = jffs2_fh_to_dentry ,
. fh_to_parent = jffs2_fh_to_parent ,
} ;
2011-10-17 05:15:16 +04:00
/*
* JFFS2 mount options .
*
2019-03-25 19:38:32 +03:00
* Opt_source : The source device
2011-10-17 05:15:16 +04:00
* Opt_override_compr : override default compressor
2012-04-11 01:22:35 +04:00
* Opt_rp_size : size of reserved pool in KiB
2011-10-17 05:15:16 +04:00
*/
enum {
Opt_override_compr ,
2012-04-11 01:22:35 +04:00
Opt_rp_size ,
2011-10-17 05:15:16 +04:00
} ;
2019-12-16 21:33:32 +03:00
static const struct constant_table jffs2_param_compr [ ] = {
2019-09-07 05:12:08 +03:00
{ " none " , JFFS2_COMPR_MODE_NONE } ,
2011-10-17 05:15:23 +04:00
# ifdef CONFIG_JFFS2_LZO
2019-09-07 05:12:08 +03:00
{ " lzo " , JFFS2_COMPR_MODE_FORCELZO } ,
2011-10-17 05:15:23 +04:00
# endif
# ifdef CONFIG_JFFS2_ZLIB
2019-09-07 05:12:08 +03:00
{ " zlib " , JFFS2_COMPR_MODE_FORCEZLIB } ,
2011-10-17 05:15:23 +04:00
# endif
2019-03-25 19:38:32 +03:00
{ }
} ;
2019-09-07 14:23:15 +03:00
static const struct fs_parameter_spec jffs2_fs_parameters [ ] = {
2019-09-07 05:12:08 +03:00
fsparam_enum ( " compr " , Opt_override_compr , jffs2_param_compr ) ,
fsparam_u32 ( " rp_size " , Opt_rp_size ) ,
{ }
} ;
2019-03-25 19:38:32 +03:00
static int jffs2_parse_param ( struct fs_context * fc , struct fs_parameter * param )
{
struct fs_parse_result result ;
struct jffs2_sb_info * c = fc - > s_fs_info ;
int opt ;
2019-09-07 14:23:15 +03:00
opt = fs_parse ( fc , jffs2_fs_parameters , param , & result ) ;
2019-03-25 19:38:32 +03:00
if ( opt < 0 )
return opt ;
switch ( opt ) {
case Opt_override_compr :
c - > mount_opts . compr = result . uint_32 ;
c - > mount_opts . override_compr = true ;
break ;
case Opt_rp_size :
if ( result . uint_32 > UINT_MAX / 1024 )
return invalf ( fc , " jffs2: rp_size unrepresentable " ) ;
opt = result . uint_32 * 1024 ;
if ( opt > c - > mtd - > size )
return invalf ( fc , " jffs2: Too large reserve pool specified, max is %llu KB " ,
c - > mtd - > size / 1024 ) ;
c - > mount_opts . rp_size = opt ;
break ;
default :
return - EINVAL ;
2011-10-17 05:15:16 +04:00
}
return 0 ;
}
2019-03-25 19:38:32 +03:00
static int jffs2_reconfigure ( struct fs_context * fc )
2011-10-17 05:15:16 +04:00
{
2019-03-25 19:38:32 +03:00
struct super_block * sb = fc - > root - > d_sb ;
2011-10-17 05:15:16 +04:00
2014-03-13 18:14:33 +04:00
sync_filesystem ( sb ) ;
2019-03-25 19:38:32 +03:00
return jffs2_do_remount_fs ( sb , fc ) ;
2011-10-17 05:15:16 +04:00
}
2007-02-12 11:55:41 +03:00
static const struct super_operations jffs2_super_operations =
2005-04-17 02:20:36 +04:00
{
. alloc_inode = jffs2_alloc_inode ,
2019-04-16 03:15:58 +03:00
. free_inode = jffs2_free_inode ,
2005-04-17 02:20:36 +04:00
. put_super = jffs2_put_super ,
. statfs = jffs2_statfs ,
2010-06-07 22:34:48 +04:00
. evict_inode = jffs2_evict_inode ,
2005-04-17 02:20:36 +04:00
. dirty_inode = jffs2_dirty_inode ,
2011-10-17 05:15:16 +04:00
. show_options = jffs2_show_options ,
2005-04-17 02:20:36 +04:00
. sync_fs = jffs2_sync_fs ,
} ;
2007-05-11 09:51:50 +04:00
/*
* fill in the superblock
*/
2019-03-25 19:38:32 +03:00
static int jffs2_fill_super ( struct super_block * sb , struct fs_context * fc )
2005-04-17 02:20:36 +04:00
{
2019-03-25 19:38:32 +03:00
struct jffs2_sb_info * c = sb - > s_fs_info ;
2010-08-16 00:51:10 +04:00
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " jffs2_get_sb_mtd(): "
2007-05-11 09:51:50 +04:00
" New superblock for device %d ( \" %s \" ) \n " ,
2012-02-16 03:56:43 +04:00
sb - > s_mtd - > index , sb - > s_mtd - > name ) ;
2005-04-17 02:20:36 +04:00
2007-05-11 09:51:50 +04:00
c - > mtd = sb - > s_mtd ;
c - > os_priv = sb ;
2011-10-17 05:15:16 +04:00
2007-05-11 09:51:50 +04:00
/* Initialize JFFS2 superblock locks, the further initialization will
* be done later */
2008-04-22 18:13:40 +04:00
mutex_init ( & c - > alloc_sem ) ;
mutex_init ( & c - > erase_free_sem ) ;
2005-07-12 20:37:12 +04:00
init_waitqueue_head ( & c - > erase_wait ) ;
init_waitqueue_head ( & c - > inocache_wq ) ;
spin_lock_init ( & c - > erase_completion_lock ) ;
spin_lock_init ( & c - > inocache_lock ) ;
2005-04-17 02:20:36 +04:00
sb - > s_op = & jffs2_super_operations ;
2008-07-31 23:39:25 +04:00
sb - > s_export_op = & jffs2_export_ops ;
2017-11-28 00:05:09 +03:00
sb - > s_flags = sb - > s_flags | SB_NOATIME ;
2006-05-13 10:09:47 +04:00
sb - > s_xattr = jffs2_xattr_handlers ;
# ifdef CONFIG_JFFS2_FS_POSIX_ACL
2017-11-28 00:05:09 +03:00
sb - > s_flags | = SB_POSIXACL ;
2006-05-13 10:09:47 +04:00
# endif
2019-03-25 19:38:32 +03:00
return jffs2_do_fill_super ( sb , fc ) ;
}
static int jffs2_get_tree ( struct fs_context * fc )
{
return get_tree_mtd ( fc , jffs2_fill_super ) ;
}
static void jffs2_free_fc ( struct fs_context * fc )
{
kfree ( fc - > s_fs_info ) ;
2005-04-17 02:20:36 +04:00
}
2019-03-25 19:38:32 +03:00
static const struct fs_context_operations jffs2_context_ops = {
. free = jffs2_free_fc ,
. parse_param = jffs2_parse_param ,
. get_tree = jffs2_get_tree ,
. reconfigure = jffs2_reconfigure ,
} ;
static int jffs2_init_fs_context ( struct fs_context * fc )
2005-04-17 02:20:36 +04:00
{
2019-03-25 19:38:32 +03:00
struct jffs2_sb_info * ctx ;
ctx = kzalloc ( sizeof ( struct jffs2_sb_info ) , GFP_KERNEL ) ;
if ( ! ctx )
return - ENOMEM ;
fc - > s_fs_info = ctx ;
fc - > ops = & jffs2_context_ops ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
static void jffs2_put_super ( struct super_block * sb )
{
struct jffs2_sb_info * c = JFFS2_SB_INFO ( sb ) ;
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 2 , " %s() \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
2008-04-22 18:13:40 +04:00
mutex_lock ( & c - > alloc_sem ) ;
2005-04-17 02:20:36 +04:00
jffs2_flush_wbuf_pad ( c ) ;
2008-04-22 18:13:40 +04:00
mutex_unlock ( & c - > alloc_sem ) ;
2005-09-07 12:35:26 +04:00
jffs2_sum_exit ( c ) ;
2005-04-17 02:20:36 +04:00
jffs2_free_ino_caches ( c ) ;
jffs2_free_raw_node_refs ( c ) ;
2016-01-23 02:11:02 +03:00
kvfree ( c - > blocks ) ;
2005-04-17 02:20:36 +04:00
jffs2_flash_cleanup ( c ) ;
kfree ( c - > inocache_list ) ;
2006-05-13 10:09:47 +04:00
jffs2_clear_xattr_subsystem ( c ) ;
2011-12-30 18:35:35 +04:00
mtd_sync ( c - > mtd ) ;
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): returning \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
}
static void jffs2_kill_sb ( struct super_block * sb )
{
struct jffs2_sb_info * c = JFFS2_SB_INFO ( sb ) ;
2018-04-03 06:56:44 +03:00
if ( c & & ! sb_rdonly ( sb ) )
2005-05-18 15:37:28 +04:00
jffs2_stop_garbage_collect_thread ( c ) ;
2007-05-11 09:51:50 +04:00
kill_mtd_super ( sb ) ;
2005-04-17 02:20:36 +04:00
kfree ( c ) ;
}
static struct file_system_type jffs2_fs_type = {
. owner = THIS_MODULE ,
. name = " jffs2 " ,
2019-03-25 19:38:32 +03:00
. init_fs_context = jffs2_init_fs_context ,
2019-09-07 14:23:15 +03:00
. parameters = jffs2_fs_parameters ,
2005-04-17 02:20:36 +04:00
. kill_sb = jffs2_kill_sb ,
} ;
2013-03-03 07:39:14 +04:00
MODULE_ALIAS_FS ( " jffs2 " ) ;
2005-04-17 02:20:36 +04:00
static int __init init_jffs2_fs ( void )
{
int ret ;
2006-05-15 03:49:43 +04:00
/* Paranoia checks for on-medium structures. If we ask GCC
to pack them with __attribute__ ( ( packed ) ) then it _also_
assumes that they ' re not aligned - - so it emits crappy
code on some architectures . Ideally we want an attribute
which means just ' no padding ' , without the alignment
thing . But GCC doesn ' t have that - - we have to just
hope the structs are the right sizes , instead . */
2006-10-11 12:22:05 +04:00
BUILD_BUG_ON ( sizeof ( struct jffs2_unknown_node ) ! = 12 ) ;
BUILD_BUG_ON ( sizeof ( struct jffs2_raw_dirent ) ! = 40 ) ;
BUILD_BUG_ON ( sizeof ( struct jffs2_raw_inode ) ! = 68 ) ;
BUILD_BUG_ON ( sizeof ( struct jffs2_raw_summary ) ! = 32 ) ;
2006-05-15 03:49:43 +04:00
2012-02-16 03:56:45 +04:00
pr_info ( " version 2.2. "
2005-02-09 12:24:26 +03:00
# ifdef CONFIG_JFFS2_FS_WRITEBUFFER
2005-04-17 02:20:36 +04:00
" (NAND) "
2005-09-07 12:35:26 +04:00
# endif
# ifdef CONFIG_JFFS2_SUMMARY
" (SUMMARY) "
2005-04-17 02:20:36 +04:00
# endif
2007-04-25 17:16:47 +04:00
" © 2001-2006 Red Hat, Inc. \n " ) ;
2005-04-17 02:20:36 +04:00
jffs2_inode_cachep = kmem_cache_create ( " jffs2_i " ,
sizeof ( struct jffs2_inode_info ) ,
2006-03-24 14:16:06 +03:00
0 , ( SLAB_RECLAIM_ACCOUNT |
2016-01-15 02:18:21 +03:00
SLAB_MEM_SPREAD | SLAB_ACCOUNT ) ,
2007-07-20 05:11:58 +04:00
jffs2_i_init_once ) ;
2005-04-17 02:20:36 +04:00
if ( ! jffs2_inode_cachep ) {
2012-02-16 03:56:45 +04:00
pr_err ( " error: Failed to initialise inode cache \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
ret = jffs2_compressors_init ( ) ;
if ( ret ) {
2012-02-16 03:56:45 +04:00
pr_err ( " error: Failed to initialise compressors \n " ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
ret = jffs2_create_slab_caches ( ) ;
if ( ret ) {
2012-02-16 03:56:45 +04:00
pr_err ( " error: Failed to initialise slab caches \n " ) ;
2005-04-17 02:20:36 +04:00
goto out_compressors ;
}
ret = register_filesystem ( & jffs2_fs_type ) ;
if ( ret ) {
2012-02-16 03:56:45 +04:00
pr_err ( " error: Failed to register filesystem \n " ) ;
2005-04-17 02:20:36 +04:00
goto out_slab ;
}
return 0 ;
out_slab :
jffs2_destroy_slab_caches ( ) ;
out_compressors :
jffs2_compressors_exit ( ) ;
out :
kmem_cache_destroy ( jffs2_inode_cachep ) ;
return ret ;
}
static void __exit exit_jffs2_fs ( void )
{
unregister_filesystem ( & jffs2_fs_type ) ;
jffs2_destroy_slab_caches ( ) ;
jffs2_compressors_exit ( ) ;
2012-09-26 05:33:07 +04:00
/*
* Make sure all delayed rcu free inodes are flushed before we
* destroy cache .
*/
rcu_barrier ( ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_destroy ( jffs2_inode_cachep ) ;
}
module_init ( init_jffs2_fs ) ;
module_exit ( exit_jffs2_fs ) ;
MODULE_DESCRIPTION ( " The Journalling Flash File System, v2 " ) ;
MODULE_AUTHOR ( " Red Hat, Inc. " ) ;
2005-11-07 14:16:07 +03:00
MODULE_LICENSE ( " GPL " ) ; // Actually dual-licensed, but it doesn't matter for
2005-04-17 02:20:36 +04:00
// the sake of this tag. It's Free Software.