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 .
*
*/
# 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 ) ;
2010-05-26 19:53:25 +04:00
int jffs2_fsync ( struct file * filp , 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 ) ;
/* Trigger GC to flush any pending writes for this inode */
jffs2_flush_wbuf_gc ( c , inode - > i_ino ) ;
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 ,
2006-10-01 10:28:48 +04:00
. read = do_sync_read ,
. aio_read = generic_file_aio_read ,
. write = do_sync_write ,
. aio_write = generic_file_aio_write ,
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
{
2009-08-28 23:29:03 +04:00
. check_acl = jffs2_check_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 ;
D2 ( printk ( KERN_DEBUG " jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx \n " , inode - > i_ino , pg - > index < < PAGE_CACHE_SHIFT ) ) ;
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 ) ;
D2 ( printk ( KERN_DEBUG " 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 ) ;
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 ;
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 ) ;
2007-10-16 12:25:18 +04:00
if ( ! pg )
return - ENOMEM ;
* pagep = pg ;
D1 ( printk ( KERN_DEBUG " jffs2_write_begin() \n " ) ) ;
2005-04-17 02:20:36 +04:00
if ( pageofs > inode - > i_size ) {
/* Make new hole frag from old EOF to new page */
struct jffs2_sb_info * c = JFFS2_SB_INFO ( inode - > i_sb ) ;
struct jffs2_raw_inode ri ;
struct jffs2_full_dnode * fn ;
2006-05-23 03:38:06 +04:00
uint32_t alloc_len ;
2005-11-07 14:16:07 +03:00
2005-04-17 02:20:36 +04:00
D1 ( printk ( KERN_DEBUG " Writing new hole frag 0x%x-0x%x between current EOF and new page \n " ,
( unsigned int ) inode - > i_size , pageofs ) ) ;
2006-05-23 03:38:06 +04:00
ret = jffs2_reserve_space ( c , sizeof ( ri ) , & alloc_len ,
ALLOC_NORMAL , JFFS2_SUMMARY_INODE_SIZE ) ;
2005-04-17 02:20:36 +04:00
if ( ret )
2007-10-16 12:25:18 +04:00
goto out_page ;
2005-04-17 02:20:36 +04:00
2008-04-22 18:13:40 +04:00
mutex_lock ( & f - > sem ) ;
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 ) ;
ri . uid = cpu_to_je16 ( inode - > i_uid ) ;
ri . gid = cpu_to_je16 ( inode - > i_gid ) ;
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 ) ;
2008-04-22 18:13:40 +04:00
mutex_unlock ( & f - > sem ) ;
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 ) {
2007-10-16 12:25:18 +04:00
D1 ( printk ( KERN_DEBUG " 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 ) ;
2008-04-22 18:13:40 +04:00
mutex_unlock ( & f - > sem ) ;
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 ;
2008-04-22 18:13:40 +04:00
mutex_unlock ( & f - > sem ) ;
2005-04-17 02:20:36 +04:00
}
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 ) ) {
2008-04-22 18:13:40 +04:00
mutex_lock ( & f - > sem ) ;
2005-04-17 02:20:36 +04:00
ret = jffs2_do_readpage_nolock ( inode , pg ) ;
2008-04-22 18:13:40 +04:00
mutex_unlock ( & f - > sem ) ;
2007-10-16 12:25:18 +04:00
if ( ret )
goto out_page ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:25:18 +04:00
D1 ( printk ( KERN_DEBUG " end write_begin(). pg->flags %lx \n " , pg - > flags ) ) ;
return ret ;
out_page :
unlock_page ( pg ) ;
page_cache_release ( pg ) ;
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 ;
2007-10-16 12:25:18 +04:00
D1 ( printk ( KERN_DEBUG " jffs2_write_end(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx \n " ,
2005-04-17 02:20:36 +04:00
inode - > i_ino , pg - > index < < PAGE_CACHE_SHIFT , start , end , pg - > flags ) ) ;
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 ) {
2007-10-16 12:25:18 +04:00
D1 ( printk ( KERN_DEBUG " jffs2_write_end(): Allocation of raw inode failed \n " ) ) ;
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 ) ;
ri - > uid = cpu_to_je16 ( inode - > i_uid ) ;
ri - > gid = cpu_to_je16 ( inode - > i_gid ) ;
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 */
2007-10-16 12:25:18 +04:00
D1 ( printk ( KERN_DEBUG " jffs2_write_end(): Not all bytes written. Marking page !uptodate \n " ) ) ;
2005-04-17 02:20:36 +04:00
SetPageError ( pg ) ;
ClearPageUptodate ( pg ) ;
}
2007-10-16 12:25:18 +04:00
D1 ( printk ( KERN_DEBUG " jffs2_write_end() returning %d \n " ,
writtenlen > 0 ? writtenlen : ret ) ) ;
unlock_page ( pg ) ;
page_cache_release ( pg ) ;
return writtenlen > 0 ? writtenlen : ret ;
2005-04-17 02:20:36 +04:00
}