2005-04-17 02:20:36 +04:00
/*
* Compressed rom filesystem for Linux .
*
* Copyright ( C ) 1999 Linus Torvalds .
*
* This file is released under the GPL .
*/
/*
* These are the VFS interfaces to the compressed rom filesystem .
* The actual compression is based on zlib , see the other files .
*/
2014-08-09 01:22:50 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/pagemap.h>
# include <linux/init.h>
# include <linux/string.h>
# include <linux/blkdev.h>
# include <linux/slab.h>
# include <linux/vfs.h>
2006-03-26 13:37:12 +04:00
# include <linux/mutex.h>
2013-12-11 01:54:28 +04:00
# include <uapi/linux/cramfs_fs.h>
2014-08-09 01:22:55 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
2013-12-11 01:54:28 +04:00
# include "internal.h"
/*
* cramfs super - block data in memory
*/
struct cramfs_sb_info {
unsigned long magic ;
unsigned long size ;
unsigned long blocks ;
unsigned long files ;
unsigned long flags ;
} ;
static inline struct cramfs_sb_info * CRAMFS_SB ( struct super_block * sb )
{
return sb - > s_fs_info ;
}
2007-02-12 11:55:41 +03:00
static const struct super_operations cramfs_ops ;
2007-02-12 11:55:38 +03:00
static const struct inode_operations cramfs_dir_inode_operations ;
2006-03-28 13:56:42 +04:00
static const struct file_operations cramfs_directory_operations ;
2006-06-28 15:26:44 +04:00
static const struct address_space_operations cramfs_aops ;
2005-04-17 02:20:36 +04:00
2006-03-26 13:37:12 +04:00
static DEFINE_MUTEX ( read_mutex ) ;
2005-04-17 02:20:36 +04:00
2011-01-13 04:01:10 +03:00
/* These macros may change in future, to provide better st_ino semantics. */
2005-04-17 02:20:36 +04:00
# define OFFSET(x) ((x)->i_ino)
2011-07-18 03:04:14 +04:00
static unsigned long cramino ( const struct cramfs_inode * cino , unsigned int offset )
2005-09-07 02:17:40 +04:00
{
2011-01-13 04:01:10 +03:00
if ( ! cino - > offset )
return offset + 1 ;
if ( ! cino - > size )
return offset + 1 ;
/*
* The file mode test fixes buggy mkcramfs implementations where
* cramfs_inode - > offset is set to a non zero value for entries
* which did not contain data , like devices node and fifos .
*/
switch ( cino - > mode & S_IFMT ) {
case S_IFREG :
case S_IFDIR :
case S_IFLNK :
return cino - > offset < < 2 ;
default :
break ;
}
return offset + 1 ;
}
static struct inode * get_cramfs_inode ( struct super_block * sb ,
2011-07-18 03:04:14 +04:00
const struct cramfs_inode * cramfs_inode , unsigned int offset )
2011-01-13 04:01:10 +03:00
{
struct inode * inode ;
2010-06-05 05:19:01 +04:00
static struct timespec zerotime ;
2011-01-13 04:01:10 +03:00
inode = iget_locked ( sb , cramino ( cramfs_inode , offset ) ) ;
if ( ! inode )
return ERR_PTR ( - ENOMEM ) ;
if ( ! ( inode - > i_state & I_NEW ) )
return inode ;
switch ( cramfs_inode - > mode & S_IFMT ) {
case S_IFREG :
inode - > i_fop = & generic_ro_fops ;
inode - > i_data . a_ops = & cramfs_aops ;
break ;
case S_IFDIR :
inode - > i_op = & cramfs_dir_inode_operations ;
inode - > i_fop = & cramfs_directory_operations ;
break ;
case S_IFLNK :
inode - > i_op = & page_symlink_inode_operations ;
2015-11-17 09:07:57 +03:00
inode_nohighmem ( inode ) ;
2011-01-13 04:01:10 +03:00
inode - > i_data . a_ops = & cramfs_aops ;
break ;
default :
init_special_inode ( inode , cramfs_inode - > mode ,
old_decode_dev ( cramfs_inode - > size ) ) ;
}
2010-06-05 05:19:01 +04:00
inode - > i_mode = cramfs_inode - > mode ;
2012-02-10 23:06:08 +04:00
i_uid_write ( inode , cramfs_inode - > uid ) ;
i_gid_write ( inode , cramfs_inode - > gid ) ;
2011-01-13 04:01:10 +03:00
/* if the lower 2 bits are zero, the inode contains data */
if ( ! ( inode - > i_ino & 3 ) ) {
inode - > i_size = cramfs_inode - > size ;
inode - > i_blocks = ( cramfs_inode - > size - 1 ) / 512 + 1 ;
}
2010-06-05 05:19:01 +04:00
/* Struct copy intentional */
inode - > i_mtime = inode - > i_atime = inode - > i_ctime = zerotime ;
/* inode->i_nlink is left 1 - arguably wrong for directories,
but it ' s the best we can do without reading the directory
contents . 1 yields the right result in GNU find , even
without - noleaf option . */
2005-09-07 02:17:40 +04:00
2011-01-13 04:01:10 +03:00
unlock_new_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
return inode ;
}
/*
* We have our own block cache : don ' t fill up the buffer cache
* with the rom - image , because the way the filesystem is set
* up the accesses should be fairly regular and cached in the
* page cache and dentry tree anyway . .
*
* This also acts as a way to guarantee contiguous areas of up to
* BLKS_PER_BUF * PAGE_CACHE_SIZE , so that the caller doesn ' t need to
* worry about end - of - buffer issues even when decompressing a full
* page cache .
*/
# define READ_BUFFERS (2)
/* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */
# define NEXT_BUFFER(_ix) ((_ix) ^ 1)
/*
* BLKS_PER_BUF_SHIFT should be at least 2 to allow for " compressed "
* data that takes up more space than the original and with unlucky
* alignment .
*/
# define BLKS_PER_BUF_SHIFT (2)
# define BLKS_PER_BUF (1 << BLKS_PER_BUF_SHIFT)
# define BUFFER_SIZE (BLKS_PER_BUF*PAGE_CACHE_SIZE)
static unsigned char read_buffers [ READ_BUFFERS ] [ BUFFER_SIZE ] ;
static unsigned buffer_blocknr [ READ_BUFFERS ] ;
2014-08-09 01:22:52 +04:00
static struct super_block * buffer_dev [ READ_BUFFERS ] ;
2005-04-17 02:20:36 +04:00
static int next_buffer ;
/*
* Returns a pointer to a buffer containing at least LEN bytes of
* filesystem starting at byte offset OFFSET into the filesystem .
*/
static void * cramfs_read ( struct super_block * sb , unsigned int offset , unsigned int len )
{
struct address_space * mapping = sb - > s_bdev - > bd_inode - > i_mapping ;
struct page * pages [ BLKS_PER_BUF ] ;
2007-10-18 14:06:54 +04:00
unsigned i , blocknr , buffer ;
2005-04-17 02:20:36 +04:00
unsigned long devsize ;
char * data ;
if ( ! len )
return NULL ;
blocknr = offset > > PAGE_CACHE_SHIFT ;
offset & = PAGE_CACHE_SIZE - 1 ;
/* Check if an existing buffer already has the data.. */
for ( i = 0 ; i < READ_BUFFERS ; i + + ) {
unsigned int blk_offset ;
if ( buffer_dev [ i ] ! = sb )
continue ;
if ( blocknr < buffer_blocknr [ i ] )
continue ;
blk_offset = ( blocknr - buffer_blocknr [ i ] ) < < PAGE_CACHE_SHIFT ;
blk_offset + = offset ;
if ( blk_offset + len > BUFFER_SIZE )
continue ;
return read_buffers [ i ] + blk_offset ;
}
devsize = mapping - > host - > i_size > > PAGE_CACHE_SHIFT ;
/* Ok, read in BLKS_PER_BUF pages completely first. */
for ( i = 0 ; i < BLKS_PER_BUF ; i + + ) {
struct page * page = NULL ;
if ( blocknr + i < devsize ) {
2014-04-04 01:48:18 +04:00
page = read_mapping_page ( mapping , blocknr + i , NULL ) ;
2005-04-17 02:20:36 +04:00
/* synchronous error? */
if ( IS_ERR ( page ) )
page = NULL ;
}
pages [ i ] = page ;
}
for ( i = 0 ; i < BLKS_PER_BUF ; i + + ) {
struct page * page = pages [ i ] ;
2014-08-09 01:22:52 +04:00
2005-04-17 02:20:36 +04:00
if ( page ) {
wait_on_page_locked ( page ) ;
if ( ! PageUptodate ( page ) ) {
/* asynchronous error */
page_cache_release ( page ) ;
pages [ i ] = NULL ;
}
}
}
buffer = next_buffer ;
next_buffer = NEXT_BUFFER ( buffer ) ;
buffer_blocknr [ buffer ] = blocknr ;
buffer_dev [ buffer ] = sb ;
data = read_buffers [ buffer ] ;
for ( i = 0 ; i < BLKS_PER_BUF ; i + + ) {
struct page * page = pages [ i ] ;
2014-08-09 01:22:52 +04:00
2005-04-17 02:20:36 +04:00
if ( page ) {
memcpy ( data , kmap ( page ) , PAGE_CACHE_SIZE ) ;
kunmap ( page ) ;
page_cache_release ( page ) ;
} else
memset ( data , 0 , PAGE_CACHE_SIZE ) ;
data + = PAGE_CACHE_SIZE ;
}
return read_buffers [ buffer ] + offset ;
}
2013-12-11 01:35:14 +04:00
static void cramfs_kill_sb ( struct super_block * sb )
2005-04-17 02:20:36 +04:00
{
2013-12-11 01:54:28 +04:00
struct cramfs_sb_info * sbi = CRAMFS_SB ( sb ) ;
2014-08-09 01:22:52 +04:00
2013-12-11 01:35:14 +04:00
kill_block_super ( sb ) ;
kfree ( sbi ) ;
2005-04-17 02:20:36 +04:00
}
static int cramfs_remount ( struct super_block * sb , int * flags , char * data )
{
2014-03-13 18:14:33 +04:00
sync_filesystem ( sb ) ;
2005-04-17 02:20:36 +04:00
* flags | = MS_RDONLY ;
return 0 ;
}
static int cramfs_fill_super ( struct super_block * sb , void * data , int silent )
{
int i ;
struct cramfs_super super ;
unsigned long root_offset ;
struct cramfs_sb_info * sbi ;
struct inode * root ;
sb - > s_flags | = MS_RDONLY ;
2006-09-27 12:49:37 +04:00
sbi = kzalloc ( sizeof ( struct cramfs_sb_info ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! sbi )
return - ENOMEM ;
sb - > s_fs_info = sbi ;
/* Invalidate the read buffers on mount: think disk change.. */
2006-03-26 13:37:12 +04:00
mutex_lock ( & read_mutex ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < READ_BUFFERS ; i + + )
buffer_blocknr [ i ] = - 1 ;
/* Read the first block and get the superblock from it */
memcpy ( & super , cramfs_read ( sb , 0 , sizeof ( super ) ) , sizeof ( super ) ) ;
2006-03-26 13:37:12 +04:00
mutex_unlock ( & read_mutex ) ;
2005-04-17 02:20:36 +04:00
/* Do sanity checks on the superblock */
if ( super . magic ! = CRAMFS_MAGIC ) {
2012-02-11 16:35:12 +04:00
/* check for wrong endianness */
2007-10-17 10:27:12 +04:00
if ( super . magic = = CRAMFS_MAGIC_WEND ) {
if ( ! silent )
2014-08-09 01:22:50 +04:00
pr_err ( " wrong endianness \n " ) ;
2013-12-11 01:35:14 +04:00
return - EINVAL ;
2007-10-17 10:27:12 +04:00
}
2005-04-17 02:20:36 +04:00
/* check at 512 byte offset */
2006-03-26 13:37:12 +04:00
mutex_lock ( & read_mutex ) ;
2005-04-17 02:20:36 +04:00
memcpy ( & super , cramfs_read ( sb , 512 , sizeof ( super ) ) , sizeof ( super ) ) ;
2006-03-26 13:37:12 +04:00
mutex_unlock ( & read_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( super . magic ! = CRAMFS_MAGIC ) {
2007-10-17 10:27:12 +04:00
if ( super . magic = = CRAMFS_MAGIC_WEND & & ! silent )
2014-08-09 01:22:50 +04:00
pr_err ( " wrong endianness \n " ) ;
2007-10-17 10:27:12 +04:00
else if ( ! silent )
2014-08-09 01:22:50 +04:00
pr_err ( " wrong magic \n " ) ;
2013-12-11 01:35:14 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
}
/* get feature flags first */
if ( super . flags & ~ CRAMFS_SUPPORTED_FLAGS ) {
2014-08-09 01:22:50 +04:00
pr_err ( " unsupported filesystem features \n " ) ;
2013-12-11 01:35:14 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
/* Check that the root inode is in a sane state */
if ( ! S_ISDIR ( super . root . mode ) ) {
2014-08-09 01:22:50 +04:00
pr_err ( " root is not a directory \n " ) ;
2013-12-11 01:35:14 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2011-01-13 04:01:10 +03:00
/* correct strange, hard-coded permissions of mkcramfs */
super . root . mode | = ( S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) ;
2005-04-17 02:20:36 +04:00
root_offset = super . root . offset < < 2 ;
if ( super . flags & CRAMFS_FLAG_FSID_VERSION_2 ) {
2014-08-09 01:22:52 +04:00
sbi - > size = super . size ;
sbi - > blocks = super . fsid . blocks ;
sbi - > files = super . fsid . files ;
2005-04-17 02:20:36 +04:00
} else {
2014-08-09 01:22:52 +04:00
sbi - > size = 1 < < 28 ;
sbi - > blocks = 0 ;
sbi - > files = 0 ;
2005-04-17 02:20:36 +04:00
}
2014-08-09 01:22:52 +04:00
sbi - > magic = super . magic ;
sbi - > flags = super . flags ;
2005-04-17 02:20:36 +04:00
if ( root_offset = = 0 )
2014-08-09 01:22:50 +04:00
pr_info ( " empty filesystem " ) ;
2005-04-17 02:20:36 +04:00
else if ( ! ( super . flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET ) & &
( ( root_offset ! = sizeof ( struct cramfs_super ) ) & &
( root_offset ! = 512 + sizeof ( struct cramfs_super ) ) ) )
{
2014-08-09 01:22:50 +04:00
pr_err ( " bad root offset %lu \n " , root_offset ) ;
2013-12-11 01:35:14 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
/* Set it all up.. */
sb - > s_op = & cramfs_ops ;
2011-01-13 04:01:10 +03:00
root = get_cramfs_inode ( sb , & super . root , 0 ) ;
2011-07-18 03:04:14 +04:00
if ( IS_ERR ( root ) )
2013-12-11 01:35:14 +04:00
return PTR_ERR ( root ) ;
2012-01-09 07:15:13 +04:00
sb - > s_root = d_make_root ( root ) ;
if ( ! sb - > s_root )
2013-12-11 01:35:14 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-06-23 13:02:58 +04:00
static int cramfs_statfs ( struct dentry * dentry , struct kstatfs * buf )
2005-04-17 02:20:36 +04:00
{
2006-06-23 13:02:58 +04:00
struct super_block * sb = dentry - > d_sb ;
2009-04-03 03:59:33 +04:00
u64 id = huge_encode_dev ( sb - > s_bdev - > bd_dev ) ;
2006-06-23 13:02:58 +04:00
2005-04-17 02:20:36 +04:00
buf - > f_type = CRAMFS_MAGIC ;
buf - > f_bsize = PAGE_CACHE_SIZE ;
buf - > f_blocks = CRAMFS_SB ( sb ) - > blocks ;
buf - > f_bfree = 0 ;
buf - > f_bavail = 0 ;
buf - > f_files = CRAMFS_SB ( sb ) - > files ;
buf - > f_ffree = 0 ;
2009-04-03 03:59:33 +04:00
buf - > f_fsid . val [ 0 ] = ( u32 ) id ;
buf - > f_fsid . val [ 1 ] = ( u32 ) ( id > > 32 ) ;
2005-04-17 02:20:36 +04:00
buf - > f_namelen = CRAMFS_MAXPATHLEN ;
return 0 ;
}
/*
* Read a cramfs directory entry .
*/
2013-05-18 02:02:17 +04:00
static int cramfs_readdir ( struct file * file , struct dir_context * ctx )
2005-04-17 02:20:36 +04:00
{
2013-05-18 02:02:17 +04:00
struct inode * inode = file_inode ( file ) ;
2005-04-17 02:20:36 +04:00
struct super_block * sb = inode - > i_sb ;
char * buf ;
unsigned int offset ;
/* Offset within the thing. */
2013-05-18 02:02:17 +04:00
if ( ctx - > pos > = inode - > i_size )
2005-04-17 02:20:36 +04:00
return 0 ;
2013-05-18 02:02:17 +04:00
offset = ctx - > pos ;
2005-04-17 02:20:36 +04:00
/* Directory entries are always 4-byte aligned */
if ( offset & 3 )
return - EINVAL ;
2007-10-18 14:06:55 +04:00
buf = kmalloc ( CRAMFS_MAXPATHLEN , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! buf )
return - ENOMEM ;
while ( offset < inode - > i_size ) {
struct cramfs_inode * de ;
unsigned long nextoffset ;
char * name ;
ino_t ino ;
2011-07-26 11:30:54 +04:00
umode_t mode ;
2013-05-18 02:02:17 +04:00
int namelen ;
2005-04-17 02:20:36 +04:00
2006-03-26 13:37:12 +04:00
mutex_lock ( & read_mutex ) ;
2007-10-18 14:06:55 +04:00
de = cramfs_read ( sb , OFFSET ( inode ) + offset , sizeof ( * de ) + CRAMFS_MAXPATHLEN ) ;
2005-04-17 02:20:36 +04:00
name = ( char * ) ( de + 1 ) ;
/*
* Namelengths on disk are shifted by two
* and the name padded out to 4 - byte boundaries
* with zeroes .
*/
namelen = de - > namelen < < 2 ;
memcpy ( buf , name , namelen ) ;
2011-01-13 04:01:10 +03:00
ino = cramino ( de , OFFSET ( inode ) + offset ) ;
2005-04-17 02:20:36 +04:00
mode = de - > mode ;
2006-03-26 13:37:12 +04:00
mutex_unlock ( & read_mutex ) ;
2005-04-17 02:20:36 +04:00
nextoffset = offset + sizeof ( * de ) + namelen ;
for ( ; ; ) {
if ( ! namelen ) {
kfree ( buf ) ;
return - EIO ;
}
if ( buf [ namelen - 1 ] )
break ;
namelen - - ;
}
2013-05-18 02:02:17 +04:00
if ( ! dir_emit ( ctx , buf , namelen , ino , mode > > 12 ) )
2005-04-17 02:20:36 +04:00
break ;
2013-05-18 02:02:17 +04:00
ctx - > pos = offset = nextoffset ;
2005-04-17 02:20:36 +04:00
}
kfree ( buf ) ;
return 0 ;
}
/*
* Lookup and fill in the inode data . .
*/
2014-08-09 01:22:52 +04:00
static struct dentry * cramfs_lookup ( struct inode * dir , struct dentry * dentry , unsigned int flags )
2005-04-17 02:20:36 +04:00
{
unsigned int offset = 0 ;
2011-07-18 03:04:14 +04:00
struct inode * inode = NULL ;
2005-04-17 02:20:36 +04:00
int sorted ;
2006-03-26 13:37:12 +04:00
mutex_lock ( & read_mutex ) ;
2005-04-17 02:20:36 +04:00
sorted = CRAMFS_SB ( dir - > i_sb ) - > flags & CRAMFS_FLAG_SORTED_DIRS ;
while ( offset < dir - > i_size ) {
struct cramfs_inode * de ;
char * name ;
int namelen , retval ;
2011-01-13 04:01:10 +03:00
int dir_off = OFFSET ( dir ) + offset ;
2005-04-17 02:20:36 +04:00
2011-01-13 04:01:10 +03:00
de = cramfs_read ( dir - > i_sb , dir_off , sizeof ( * de ) + CRAMFS_MAXPATHLEN ) ;
2005-04-17 02:20:36 +04:00
name = ( char * ) ( de + 1 ) ;
/* Try to take advantage of sorted directories */
if ( sorted & & ( dentry - > d_name . name [ 0 ] < name [ 0 ] ) )
break ;
namelen = de - > namelen < < 2 ;
offset + = sizeof ( * de ) + namelen ;
/* Quick check that the name is roughly the right length */
if ( ( ( dentry - > d_name . len + 3 ) & ~ 3 ) ! = namelen )
continue ;
for ( ; ; ) {
if ( ! namelen ) {
2011-07-18 03:04:14 +04:00
inode = ERR_PTR ( - EIO ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
if ( name [ namelen - 1 ] )
break ;
namelen - - ;
}
if ( namelen ! = dentry - > d_name . len )
continue ;
retval = memcmp ( dentry - > d_name . name , name , namelen ) ;
if ( retval > 0 )
continue ;
if ( ! retval ) {
2011-07-18 03:04:14 +04:00
inode = get_cramfs_inode ( dir - > i_sb , de , dir_off ) ;
break ;
2005-04-17 02:20:36 +04:00
}
/* else (retval < 0) */
if ( sorted )
break ;
}
2011-07-18 03:04:14 +04:00
out :
2006-03-26 13:37:12 +04:00
mutex_unlock ( & read_mutex ) ;
2011-07-18 03:04:14 +04:00
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
d_add ( dentry , inode ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2014-08-09 01:22:52 +04:00
static int cramfs_readpage ( struct file * file , struct page * page )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = page - > mapping - > host ;
2009-04-03 03:59:15 +04:00
u32 maxblock ;
int bytes_filled ;
2005-04-17 02:20:36 +04:00
void * pgdata ;
maxblock = ( inode - > i_size + PAGE_CACHE_SIZE - 1 ) > > PAGE_CACHE_SHIFT ;
bytes_filled = 0 ;
2009-04-03 03:59:15 +04:00
pgdata = kmap ( page ) ;
2005-04-17 02:20:36 +04:00
if ( page - > index < maxblock ) {
struct super_block * sb = inode - > i_sb ;
u32 blkptr_offset = OFFSET ( inode ) + page - > index * 4 ;
u32 start_offset , compr_len ;
start_offset = OFFSET ( inode ) + maxblock * 4 ;
2006-03-26 13:37:12 +04:00
mutex_lock ( & read_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( page - > index )
2009-04-03 03:59:15 +04:00
start_offset = * ( u32 * ) cramfs_read ( sb , blkptr_offset - 4 ,
4 ) ;
compr_len = ( * ( u32 * ) cramfs_read ( sb , blkptr_offset , 4 ) -
start_offset ) ;
2006-03-26 13:37:12 +04:00
mutex_unlock ( & read_mutex ) ;
2009-04-03 03:59:15 +04:00
2005-04-17 02:20:36 +04:00
if ( compr_len = = 0 )
; /* hole */
2009-04-03 03:59:15 +04:00
else if ( unlikely ( compr_len > ( PAGE_CACHE_SIZE < < 1 ) ) ) {
2014-08-09 01:22:50 +04:00
pr_err ( " bad compressed blocksize %u \n " ,
2009-04-03 03:59:15 +04:00
compr_len ) ;
goto err ;
} else {
2006-03-26 13:37:12 +04:00
mutex_lock ( & read_mutex ) ;
2005-04-17 02:20:36 +04:00
bytes_filled = cramfs_uncompress_block ( pgdata ,
PAGE_CACHE_SIZE ,
cramfs_read ( sb , start_offset , compr_len ) ,
compr_len ) ;
2006-03-26 13:37:12 +04:00
mutex_unlock ( & read_mutex ) ;
2009-04-03 03:59:15 +04:00
if ( unlikely ( bytes_filled < 0 ) )
goto err ;
2005-04-17 02:20:36 +04:00
}
2009-04-03 03:59:15 +04:00
}
2005-04-17 02:20:36 +04:00
memset ( pgdata + bytes_filled , 0 , PAGE_CACHE_SIZE - bytes_filled ) ;
flush_dcache_page ( page ) ;
2009-04-03 03:59:15 +04:00
kunmap ( page ) ;
2005-04-17 02:20:36 +04:00
SetPageUptodate ( page ) ;
unlock_page ( page ) ;
return 0 ;
2009-04-03 03:59:15 +04:00
err :
kunmap ( page ) ;
ClearPageUptodate ( page ) ;
SetPageError ( page ) ;
unlock_page ( page ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-06-28 15:26:44 +04:00
static const struct address_space_operations cramfs_aops = {
2005-04-17 02:20:36 +04:00
. readpage = cramfs_readpage
} ;
/*
* Our operations :
*/
/*
* A directory can only readdir
*/
2006-03-28 13:56:42 +04:00
static const struct file_operations cramfs_directory_operations = {
2005-04-17 02:20:36 +04:00
. llseek = generic_file_llseek ,
. read = generic_read_dir ,
2013-05-18 02:02:17 +04:00
. iterate = cramfs_readdir ,
2005-04-17 02:20:36 +04:00
} ;
2007-02-12 11:55:38 +03:00
static const struct inode_operations cramfs_dir_inode_operations = {
2005-04-17 02:20:36 +04:00
. lookup = cramfs_lookup ,
} ;
2007-02-12 11:55:41 +03:00
static const struct super_operations cramfs_ops = {
2005-04-17 02:20:36 +04:00
. remount_fs = cramfs_remount ,
. statfs = cramfs_statfs ,
} ;
2010-07-25 00:46:55 +04:00
static struct dentry * cramfs_mount ( struct file_system_type * fs_type ,
int flags , const char * dev_name , void * data )
2005-04-17 02:20:36 +04:00
{
2010-07-25 00:46:55 +04:00
return mount_bdev ( fs_type , flags , dev_name , data , cramfs_fill_super ) ;
2005-04-17 02:20:36 +04:00
}
static struct file_system_type cramfs_fs_type = {
. owner = THIS_MODULE ,
. name = " cramfs " ,
2010-07-25 00:46:55 +04:00
. mount = cramfs_mount ,
2013-12-11 01:35:14 +04:00
. kill_sb = cramfs_kill_sb ,
2005-04-17 02:20:36 +04:00
. fs_flags = FS_REQUIRES_DEV ,
} ;
2013-03-03 07:39:14 +04:00
MODULE_ALIAS_FS ( " cramfs " ) ;
2005-04-17 02:20:36 +04:00
static int __init init_cramfs_fs ( void )
{
2006-09-29 13:01:04 +04:00
int rv ;
rv = cramfs_uncompress_init ( ) ;
if ( rv < 0 )
return rv ;
rv = register_filesystem ( & cramfs_fs_type ) ;
if ( rv < 0 )
cramfs_uncompress_exit ( ) ;
return rv ;
2005-04-17 02:20:36 +04:00
}
static void __exit exit_cramfs_fs ( void )
{
cramfs_uncompress_exit ( ) ;
unregister_filesystem ( & cramfs_fs_type ) ;
}
module_init ( init_cramfs_fs )
module_exit ( exit_cramfs_fs )
MODULE_LICENSE ( " GPL " ) ;