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 .
2010-08-08 17:15:22 +04:00
* Copyright © 2004 - 2010 David Woodhouse < dwmw2 @ infradead . org >
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/fs.h>
# include <linux/time.h>
# include <linux/pagemap.h>
# include <linux/highmem.h>
# include <linux/crc32.h>
# include <linux/jffs2.h>
# include "nodelist.h"
2007-10-16 12:25:18 +04:00
static int jffs2_write_end ( struct file * filp , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned copied ,
struct page * pg , void * fsdata ) ;
static int jffs2_write_begin ( struct file * filp , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned flags ,
struct page * * pagep , void * * fsdata ) ;
2005-04-17 02:20:36 +04:00
static int jffs2_readpage ( struct file * filp , struct page * pg ) ;
2011-07-17 04:44:56 +04:00
int jffs2_fsync ( struct file * filp , loff_t start , loff_t end , int datasync )
2005-04-17 02:20:36 +04:00
{
2010-05-26 19:53:25 +04:00
struct inode * inode = filp - > f_mapping - > host ;
2005-04-17 02:20:36 +04:00
struct jffs2_sb_info * c = JFFS2_SB_INFO ( inode - > i_sb ) ;
2011-07-17 04:44:56 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
2011-07-17 04:44:56 +04:00
ret = filemap_write_and_wait_range ( inode - > i_mapping , start , end ) ;
if ( ret )
return ret ;
mutex_lock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
/* Trigger GC to flush any pending writes for this inode */
jffs2_flush_wbuf_gc ( c , inode - > i_ino ) ;
2011-07-17 04:44:56 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-11-07 14:16:07 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-03-28 13:56:42 +04:00
const struct file_operations jffs2_file_operations =
2005-04-17 02:20:36 +04:00
{
. llseek = generic_file_llseek ,
. open = generic_file_open ,
2014-04-02 22:33:16 +04:00
. read = new_sync_read ,
. read_iter = generic_file_read_iter ,
2014-04-03 11:17:43 +04:00
. write = new_sync_write ,
. write_iter = generic_file_write_iter ,
2008-07-07 16:45:59 +04:00
. unlocked_ioctl = jffs2_ioctl ,
2005-04-17 02:20:36 +04:00
. mmap = generic_file_readonly_mmap ,
. fsync = jffs2_fsync ,
2007-06-01 13:49:19 +04:00
. splice_read = generic_file_splice_read ,
2005-04-17 02:20:36 +04:00
} ;
/* jffs2_file_inode_operations */
2007-02-12 11:55:39 +03:00
const struct inode_operations jffs2_file_inode_operations =
2005-04-17 02:20:36 +04:00
{
2011-07-23 19:37:31 +04:00
. get_acl = jffs2_get_acl ,
2013-12-20 17:16:47 +04:00
. set_acl = jffs2_set_acl ,
2006-05-13 10:09:47 +04:00
. setattr = jffs2_setattr ,
. setxattr = jffs2_setxattr ,
. getxattr = jffs2_getxattr ,
. listxattr = jffs2_listxattr ,
. removexattr = jffs2_removexattr
2005-04-17 02:20:36 +04:00
} ;
2006-06-28 15:26:44 +04:00
const struct address_space_operations jffs2_file_address_operations =
2005-04-17 02:20:36 +04:00
{
. readpage = jffs2_readpage ,
2007-10-16 12:25:18 +04:00
. write_begin = jffs2_write_begin ,
. write_end = jffs2_write_end ,
2005-04-17 02:20:36 +04:00
} ;
static int jffs2_do_readpage_nolock ( struct inode * inode , struct page * pg )
{
struct jffs2_inode_info * f = JFFS2_INODE_INFO ( inode ) ;
struct jffs2_sb_info * c = JFFS2_SB_INFO ( inode - > i_sb ) ;
unsigned char * pg_buf ;
int ret ;
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 2 , " %s(): ino #%lu, page at offset 0x%lx \n " ,
__func__ , inode - > i_ino , pg - > index < < PAGE_CACHE_SHIFT ) ;
2005-04-17 02:20:36 +04:00
2005-05-01 19:59:01 +04:00
BUG_ON ( ! PageLocked ( pg ) ) ;
2005-04-17 02:20:36 +04:00
pg_buf = kmap ( pg ) ;
/* FIXME: Can kmap fail? */
ret = jffs2_read_inode_range ( c , f , pg_buf , pg - > index < < PAGE_CACHE_SHIFT , PAGE_CACHE_SIZE ) ;
if ( ret ) {
ClearPageUptodate ( pg ) ;
SetPageError ( pg ) ;
} else {
SetPageUptodate ( pg ) ;
ClearPageError ( pg ) ;
}
flush_dcache_page ( pg ) ;
kunmap ( pg ) ;
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 2 , " readpage finished \n " ) ;
2009-08-04 15:11:47 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
int jffs2_do_readpage_unlock ( struct inode * inode , struct page * pg )
{
int ret = jffs2_do_readpage_nolock ( inode , pg ) ;
unlock_page ( pg ) ;
return ret ;
}
static int jffs2_readpage ( struct file * filp , struct page * pg )
{
struct jffs2_inode_info * f = JFFS2_INODE_INFO ( pg - > mapping - > host ) ;
int ret ;
2005-11-07 14:16:07 +03:00
2008-04-22 18:13:40 +04:00
mutex_lock ( & f - > sem ) ;
2005-04-17 02:20:36 +04:00
ret = jffs2_do_readpage_unlock ( pg - > mapping - > host , pg ) ;
2008-04-22 18:13:40 +04:00
mutex_unlock ( & f - > sem ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2007-10-16 12:25:18 +04:00
static int jffs2_write_begin ( struct file * filp , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned flags ,
struct page * * pagep , void * * fsdata )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:25:18 +04:00
struct page * pg ;
struct inode * inode = mapping - > host ;
2005-04-17 02:20:36 +04:00
struct jffs2_inode_info * f = JFFS2_INODE_INFO ( inode ) ;
2012-10-18 00:59:30 +04:00
struct jffs2_sb_info * c = JFFS2_SB_INFO ( inode - > i_sb ) ;
struct jffs2_raw_inode ri ;
uint32_t alloc_len = 0 ;
2007-10-16 12:25:18 +04:00
pgoff_t index = pos > > PAGE_CACHE_SHIFT ;
2008-04-14 23:45:06 +04:00
uint32_t pageofs = index < < PAGE_CACHE_SHIFT ;
2005-04-17 02:20:36 +04:00
int ret = 0 ;
2012-10-18 00:59:30 +04:00
jffs2_dbg ( 1 , " %s() \n " , __func__ ) ;
if ( pageofs > inode - > i_size ) {
ret = jffs2_reserve_space ( c , sizeof ( ri ) , & alloc_len ,
ALLOC_NORMAL , JFFS2_SUMMARY_INODE_SIZE ) ;
if ( ret )
return ret ;
}
mutex_lock ( & f - > sem ) ;
fs: symlink write_begin allocation context fix
With the write_begin/write_end aops, page_symlink was broken because it
could no longer pass a GFP_NOFS type mask into the point where the
allocations happened. They are done in write_begin, which would always
assume that the filesystem can be entered from reclaim. This bug could
cause filesystem deadlocks.
The funny thing with having a gfp_t mask there is that it doesn't really
allow the caller to arbitrarily tinker with the context in which it can be
called. It couldn't ever be GFP_ATOMIC, for example, because it needs to
take the page lock. The only thing any callers care about is __GFP_FS
anyway, so turn that into a single flag.
Add a new flag for write_begin, AOP_FLAG_NOFS. Filesystems can now act on
this flag in their write_begin function. Change __grab_cache_page to
accept a nofs argument as well, to honour that flag (while we're there,
change the name to grab_cache_page_write_begin which is more instructive
and does away with random leading underscores).
This is really a more flexible way to go in the end anyway -- if a
filesystem happens to want any extra allocations aside from the pagecache
ones in ints write_begin function, it may now use GFP_KERNEL (rather than
GFP_NOFS) for common case allocations (eg. ocfs2_alloc_write_ctxt, for a
random example).
[kosaki.motohiro@jp.fujitsu.com: fix ubifs]
[kosaki.motohiro@jp.fujitsu.com: fix fuse]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: <stable@kernel.org> [2.6.28.x]
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
[ Cleaned up the calling convention: just pass in the AOP flags
untouched to the grab_cache_page_write_begin() function. That
just simplifies everybody, and may even allow future expansion of the
logic. - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-01-04 23:00:53 +03:00
pg = grab_cache_page_write_begin ( mapping , index , flags ) ;
2012-10-18 00:59:30 +04:00
if ( ! pg ) {
if ( alloc_len )
jffs2_complete_reservation ( c ) ;
mutex_unlock ( & f - > sem ) ;
2007-10-16 12:25:18 +04:00
return - ENOMEM ;
2012-10-18 00:59:30 +04:00
}
2007-10-16 12:25:18 +04:00
* pagep = pg ;
2012-10-18 00:59:30 +04:00
if ( alloc_len ) {
2005-04-17 02:20:36 +04:00
/* Make new hole frag from old EOF to new page */
struct jffs2_full_dnode * fn ;
2005-11-07 14:16:07 +03:00
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " Writing new hole frag 0x%x-0x%x between current EOF and new page \n " ,
( unsigned int ) inode - > i_size , pageofs ) ;
2005-04-17 02:20:36 +04:00
memset ( & ri , 0 , sizeof ( ri ) ) ;
ri . magic = cpu_to_je16 ( JFFS2_MAGIC_BITMASK ) ;
ri . nodetype = cpu_to_je16 ( JFFS2_NODETYPE_INODE ) ;
ri . totlen = cpu_to_je32 ( sizeof ( ri ) ) ;
ri . hdr_crc = cpu_to_je32 ( crc32 ( 0 , & ri , sizeof ( struct jffs2_unknown_node ) - 4 ) ) ;
ri . ino = cpu_to_je32 ( f - > inocache - > ino ) ;
ri . version = cpu_to_je32 ( + + f - > highest_version ) ;
ri . mode = cpu_to_jemode ( inode - > i_mode ) ;
2012-02-08 04:28:39 +04:00
ri . uid = cpu_to_je16 ( i_uid_read ( inode ) ) ;
ri . gid = cpu_to_je16 ( i_gid_read ( inode ) ) ;
2005-04-17 02:20:36 +04:00
ri . isize = cpu_to_je32 ( max ( ( uint32_t ) inode - > i_size , pageofs ) ) ;
ri . atime = ri . ctime = ri . mtime = cpu_to_je32 ( get_seconds ( ) ) ;
ri . offset = cpu_to_je32 ( inode - > i_size ) ;
ri . dsize = cpu_to_je32 ( pageofs - inode - > i_size ) ;
ri . csize = cpu_to_je32 ( 0 ) ;
ri . compr = JFFS2_COMPR_ZERO ;
ri . node_crc = cpu_to_je32 ( crc32 ( 0 , & ri , sizeof ( ri ) - 8 ) ) ;
ri . data_crc = cpu_to_je32 ( 0 ) ;
2005-11-07 14:16:07 +03:00
2006-05-23 03:38:06 +04:00
fn = jffs2_write_dnode ( c , f , & ri , NULL , 0 , ALLOC_NORMAL ) ;
2005-04-17 02:20:36 +04:00
if ( IS_ERR ( fn ) ) {
ret = PTR_ERR ( fn ) ;
jffs2_complete_reservation ( c ) ;
2007-10-16 12:25:18 +04:00
goto out_page ;
2005-04-17 02:20:36 +04:00
}
ret = jffs2_add_full_dnode_to_inode ( c , f , fn ) ;
if ( f - > metadata ) {
jffs2_mark_node_obsolete ( c , f - > metadata - > raw ) ;
jffs2_free_full_dnode ( f - > metadata ) ;
f - > metadata = NULL ;
}
if ( ret ) {
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " Eep. add_full_dnode_to_inode() failed in write_begin, returned %d \n " ,
ret ) ;
2005-04-17 02:20:36 +04:00
jffs2_mark_node_obsolete ( c , fn - > raw ) ;
jffs2_free_full_dnode ( fn ) ;
jffs2_complete_reservation ( c ) ;
2007-10-16 12:25:18 +04:00
goto out_page ;
2005-04-17 02:20:36 +04:00
}
jffs2_complete_reservation ( c ) ;
inode - > i_size = pageofs ;
}
2005-11-07 14:16:07 +03:00
2007-10-16 12:25:18 +04:00
/*
* Read in the page if it wasn ' t already present . Cannot optimize away
* the whole page write case until jffs2_write_end can handle the
* case of a short - copy .
*/
if ( ! PageUptodate ( pg ) ) {
2005-04-17 02:20:36 +04:00
ret = jffs2_do_readpage_nolock ( inode , pg ) ;
2007-10-16 12:25:18 +04:00
if ( ret )
goto out_page ;
2005-04-17 02:20:36 +04:00
}
2012-10-18 00:59:30 +04:00
mutex_unlock ( & f - > sem ) ;
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " end write_begin(). pg->flags %lx \n " , pg - > flags ) ;
2007-10-16 12:25:18 +04:00
return ret ;
out_page :
unlock_page ( pg ) ;
page_cache_release ( pg ) ;
2012-10-18 00:59:30 +04:00
mutex_unlock ( & f - > sem ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2007-10-16 12:25:18 +04:00
static int jffs2_write_end ( struct file * filp , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned copied ,
struct page * pg , void * fsdata )
2005-04-17 02:20:36 +04:00
{
/* Actually commit the write from the page cache page we're looking at.
* For now , we write the full page out each time . It sucks , but it ' s simple
*/
2007-10-16 12:25:18 +04:00
struct inode * inode = mapping - > host ;
2005-04-17 02:20:36 +04:00
struct jffs2_inode_info * f = JFFS2_INODE_INFO ( inode ) ;
struct jffs2_sb_info * c = JFFS2_SB_INFO ( inode - > i_sb ) ;
struct jffs2_raw_inode * ri ;
2007-10-16 12:25:18 +04:00
unsigned start = pos & ( PAGE_CACHE_SIZE - 1 ) ;
unsigned end = start + copied ;
2005-04-17 02:20:36 +04:00
unsigned aligned_start = start & ~ 3 ;
int ret = 0 ;
uint32_t writtenlen = 0 ;
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx \n " ,
__func__ , inode - > i_ino , pg - > index < < PAGE_CACHE_SHIFT ,
start , end , pg - > flags ) ;
2005-04-17 02:20:36 +04:00
2007-10-16 12:25:18 +04:00
/* We need to avoid deadlock with page_cache_read() in
jffs2_garbage_collect_pass ( ) . So the page must be
up to date to prevent page_cache_read ( ) from trying
to re - lock it . */
BUG_ON ( ! PageUptodate ( pg ) ) ;
2006-05-14 07:06:24 +04:00
if ( end = = PAGE_CACHE_SIZE ) {
2007-10-16 12:25:18 +04:00
/* When writing out the end of a page, write out the
_whole_ page . This helps to reduce the number of
nodes in files which have many short writes , like
syslog files . */
2007-10-19 11:16:53 +04:00
aligned_start = 0 ;
2005-04-17 02:20:36 +04:00
}
ri = jffs2_alloc_raw_inode ( ) ;
if ( ! ri ) {
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): Allocation of raw inode failed \n " ,
__func__ ) ;
2007-10-16 12:25:18 +04:00
unlock_page ( pg ) ;
page_cache_release ( pg ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
/* Set the fields that the generic jffs2_write_inode_range() code can't find */
ri - > ino = cpu_to_je32 ( inode - > i_ino ) ;
ri - > mode = cpu_to_jemode ( inode - > i_mode ) ;
2012-02-08 04:28:39 +04:00
ri - > uid = cpu_to_je16 ( i_uid_read ( inode ) ) ;
ri - > gid = cpu_to_je16 ( i_gid_read ( inode ) ) ;
2005-04-17 02:20:36 +04:00
ri - > isize = cpu_to_je32 ( ( uint32_t ) inode - > i_size ) ;
ri - > atime = ri - > ctime = ri - > mtime = cpu_to_je32 ( get_seconds ( ) ) ;
/* In 2.4, it was already kmapped by generic_file_write(). Doesn't
hurt to do it again . The alternative is ifdefs , which are ugly . */
kmap ( pg ) ;
ret = jffs2_write_inode_range ( c , f , ri , page_address ( pg ) + aligned_start ,
( pg - > index < < PAGE_CACHE_SHIFT ) + aligned_start ,
end - aligned_start , & writtenlen ) ;
kunmap ( pg ) ;
if ( ret ) {
/* There was an error writing. */
SetPageError ( pg ) ;
}
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
/* Adjust writtenlen for the padding we did, so we don't confuse our caller */
2007-10-19 11:16:53 +04:00
writtenlen - = min ( writtenlen , ( start - aligned_start ) ) ;
2005-04-17 02:20:36 +04:00
if ( writtenlen ) {
2007-10-19 11:16:53 +04:00
if ( inode - > i_size < pos + writtenlen ) {
inode - > i_size = pos + writtenlen ;
2005-04-17 02:20:36 +04:00
inode - > i_blocks = ( inode - > i_size + 511 ) > > 9 ;
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
inode - > i_ctime = inode - > i_mtime = ITIME ( je32_to_cpu ( ri - > ctime ) ) ;
}
}
jffs2_free_raw_inode ( ri ) ;
if ( start + writtenlen < end ) {
/* generic_file_write has written more to the page cache than we've
2005-11-07 14:16:07 +03:00
actually written to the medium . Mark the page ! Uptodate so that
2005-04-17 02:20:36 +04:00
it gets reread */
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s(): Not all bytes written. Marking page !uptodate \n " ,
__func__ ) ;
2005-04-17 02:20:36 +04:00
SetPageError ( pg ) ;
ClearPageUptodate ( pg ) ;
}
2012-02-16 03:56:43 +04:00
jffs2_dbg ( 1 , " %s() returning %d \n " ,
__func__ , writtenlen > 0 ? writtenlen : ret ) ;
2007-10-16 12:25:18 +04:00
unlock_page ( pg ) ;
page_cache_release ( pg ) ;
return writtenlen > 0 ? writtenlen : ret ;
2005-04-17 02:20:36 +04:00
}