2005-04-17 02:20:36 +04:00
/*
* file . c
*
* Copyright ( C ) 1995 , 1996 by Volker Lendecke
* Modified 1997 Peter Waltenberg , Bill Hawes , David Woodhouse for 2.1 dcache
*
*/
2014-04-09 03:04:14 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <linux/time.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/fcntl.h>
# include <linux/stat.h>
# include <linux/mm.h>
# include <linux/vmalloc.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2005-04-17 02:20:36 +04:00
2011-01-13 01:37:47 +03:00
# include "ncp_fs.h"
2005-04-17 02:20:36 +04:00
2011-07-17 04:44:56 +04:00
static int ncp_fsync ( struct file * file , loff_t start , loff_t end , int datasync )
2005-04-17 02:20:36 +04:00
{
2011-07-17 04:44:56 +04:00
return filemap_write_and_wait_range ( file - > f_mapping , start , end ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Open a file with the specified read / write mode .
*/
int ncp_make_open ( struct inode * inode , int right )
{
int error ;
int access ;
error = - EINVAL ;
if ( ! inode ) {
2014-04-09 03:04:14 +04:00
pr_err ( " %s: got NULL inode \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
2014-04-09 03:04:15 +04:00
ncp_dbg ( 1 , " opened=%d, volume # %u, dir entry # %u \n " ,
2005-04-17 02:20:36 +04:00
atomic_read ( & NCP_FINFO ( inode ) - > opened ) ,
NCP_FINFO ( inode ) - > volNumber ,
NCP_FINFO ( inode ) - > dirEntNum ) ;
error = - EACCES ;
2006-03-23 14:00:43 +03:00
mutex_lock ( & NCP_FINFO ( inode ) - > open_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( ! atomic_read ( & NCP_FINFO ( inode ) - > opened ) ) {
struct ncp_entry_info finfo ;
int result ;
/* tries max. rights */
finfo . access = O_RDWR ;
result = ncp_open_create_file_or_subdir ( NCP_SERVER ( inode ) ,
inode , NULL , OC_MODE_OPEN ,
0 , AR_READ | AR_WRITE , & finfo ) ;
if ( ! result )
goto update ;
/* RDWR did not succeeded, try readonly or writeonly as requested */
switch ( right ) {
case O_RDONLY :
finfo . access = O_RDONLY ;
result = ncp_open_create_file_or_subdir ( NCP_SERVER ( inode ) ,
inode , NULL , OC_MODE_OPEN ,
0 , AR_READ , & finfo ) ;
break ;
case O_WRONLY :
finfo . access = O_WRONLY ;
result = ncp_open_create_file_or_subdir ( NCP_SERVER ( inode ) ,
inode , NULL , OC_MODE_OPEN ,
0 , AR_WRITE , & finfo ) ;
break ;
}
if ( result ) {
PPRINTK ( " ncp_make_open: failed, result=%d \n " , result ) ;
goto out_unlock ;
}
/*
* Update the inode information .
*/
update :
ncp_update_inode ( inode , & finfo ) ;
atomic_set ( & NCP_FINFO ( inode ) - > opened , 1 ) ;
}
access = NCP_FINFO ( inode ) - > access ;
PPRINTK ( " ncp_make_open: file open, access=%x \n " , access ) ;
if ( access = = right | | access = = O_RDWR ) {
atomic_inc ( & NCP_FINFO ( inode ) - > opened ) ;
error = 0 ;
}
out_unlock :
2006-03-23 14:00:43 +03:00
mutex_unlock ( & NCP_FINFO ( inode ) - > open_mutex ) ;
2005-04-17 02:20:36 +04:00
out :
return error ;
}
static ssize_t
ncp_file_read ( struct file * file , char __user * buf , size_t count , loff_t * ppos )
{
2006-12-08 13:37:22 +03:00
struct dentry * dentry = file - > f_path . dentry ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
size_t already_read = 0 ;
off_t pos ;
size_t bufsize ;
int error ;
void * freepage ;
size_t freelen ;
2014-04-09 03:04:15 +04:00
ncp_dbg ( 1 , " enter %pd2 \n " , dentry ) ;
2005-04-17 02:20:36 +04:00
pos = * ppos ;
if ( ( ssize_t ) count < 0 ) {
return - EINVAL ;
}
if ( ! count )
return 0 ;
if ( pos > inode - > i_sb - > s_maxbytes )
return 0 ;
if ( pos + count > inode - > i_sb - > s_maxbytes ) {
count = inode - > i_sb - > s_maxbytes - pos ;
}
error = ncp_make_open ( inode , O_RDONLY ) ;
if ( error ) {
2014-04-09 03:04:15 +04:00
ncp_dbg ( 1 , " open failed, error=%d \n " , error ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
bufsize = NCP_SERVER ( inode ) - > buffer_size ;
error = - EIO ;
freelen = ncp_read_bounce_size ( bufsize ) ;
freepage = vmalloc ( freelen ) ;
if ( ! freepage )
goto outrel ;
error = 0 ;
/* First read in as much as possible for each bufsize. */
while ( already_read < count ) {
int read_this_time ;
size_t to_read = min_t ( unsigned int ,
bufsize - ( pos % bufsize ) ,
count - already_read ) ;
error = ncp_read_bounce ( NCP_SERVER ( inode ) ,
NCP_FINFO ( inode ) - > file_handle ,
pos , to_read , buf , & read_this_time ,
freepage , freelen ) ;
if ( error ) {
error = - EIO ; /* NW errno -> Linux errno */
break ;
}
pos + = read_this_time ;
buf + = read_this_time ;
already_read + = read_this_time ;
if ( read_this_time ! = to_read ) {
break ;
}
}
vfree ( freepage ) ;
* ppos = pos ;
file_accessed ( file ) ;
2014-04-09 03:04:15 +04:00
ncp_dbg ( 1 , " exit %pd2 \n " , dentry ) ;
2005-04-17 02:20:36 +04:00
outrel :
ncp_inode_close ( inode ) ;
return already_read ? already_read : error ;
}
static ssize_t
ncp_file_write ( struct file * file , const char __user * buf , size_t count , loff_t * ppos )
{
2006-12-08 13:37:22 +03:00
struct dentry * dentry = file - > f_path . dentry ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
size_t already_written = 0 ;
off_t pos ;
size_t bufsize ;
int errno ;
void * bouncebuffer ;
2014-04-09 03:04:15 +04:00
ncp_dbg ( 1 , " enter %pd2 \n " , dentry ) ;
2005-04-17 02:20:36 +04:00
if ( ( ssize_t ) count < 0 )
return - EINVAL ;
pos = * ppos ;
if ( file - > f_flags & O_APPEND ) {
2010-09-27 03:47:33 +04:00
pos = i_size_read ( inode ) ;
2005-04-17 02:20:36 +04:00
}
if ( pos + count > MAX_NON_LFS & & ! ( file - > f_flags & O_LARGEFILE ) ) {
if ( pos > = MAX_NON_LFS ) {
return - EFBIG ;
}
if ( count > MAX_NON_LFS - ( u32 ) pos ) {
count = MAX_NON_LFS - ( u32 ) pos ;
}
}
if ( pos > = inode - > i_sb - > s_maxbytes ) {
if ( count | | pos > inode - > i_sb - > s_maxbytes ) {
return - EFBIG ;
}
}
if ( pos + count > inode - > i_sb - > s_maxbytes ) {
count = inode - > i_sb - > s_maxbytes - pos ;
}
if ( ! count )
return 0 ;
errno = ncp_make_open ( inode , O_WRONLY ) ;
if ( errno ) {
2014-04-09 03:04:15 +04:00
ncp_dbg ( 1 , " open failed, error=%d \n " , errno ) ;
2005-04-17 02:20:36 +04:00
return errno ;
}
bufsize = NCP_SERVER ( inode ) - > buffer_size ;
already_written = 0 ;
2012-03-26 17:59:21 +04:00
errno = file_update_time ( file ) ;
if ( errno )
goto outrel ;
2005-04-17 02:20:36 +04:00
bouncebuffer = vmalloc ( bufsize ) ;
if ( ! bouncebuffer ) {
errno = - EIO ; /* -ENOMEM */
goto outrel ;
}
while ( already_written < count ) {
int written_this_time ;
size_t to_write = min_t ( unsigned int ,
bufsize - ( pos % bufsize ) ,
count - already_written ) ;
if ( copy_from_user ( bouncebuffer , buf , to_write ) ) {
errno = - EFAULT ;
break ;
}
if ( ncp_write_kernel ( NCP_SERVER ( inode ) ,
NCP_FINFO ( inode ) - > file_handle ,
pos , to_write , bouncebuffer , & written_this_time ) ! = 0 ) {
errno = - EIO ;
break ;
}
pos + = written_this_time ;
buf + = written_this_time ;
already_written + = written_this_time ;
if ( written_this_time ! = to_write ) {
break ;
}
}
vfree ( bouncebuffer ) ;
* ppos = pos ;
2010-09-27 03:47:33 +04:00
if ( pos > i_size_read ( inode ) ) {
mutex_lock ( & inode - > i_mutex ) ;
if ( pos > i_size_read ( inode ) )
i_size_write ( inode , pos ) ;
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
}
2014-04-09 03:04:15 +04:00
ncp_dbg ( 1 , " exit %pd2 \n " , dentry ) ;
2005-04-17 02:20:36 +04:00
outrel :
ncp_inode_close ( inode ) ;
return already_written ? already_written : errno ;
}
static int ncp_release ( struct inode * inode , struct file * file ) {
if ( ncp_make_closed ( inode ) ) {
2014-04-09 03:04:15 +04:00
ncp_dbg ( 1 , " failed to close \n " ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2006-03-28 13:56:42 +04:00
const struct file_operations ncp_file_operations =
2005-04-17 02:20:36 +04:00
{
2010-09-27 03:47:33 +04:00
. llseek = generic_file_llseek ,
2005-04-17 02:20:36 +04:00
. read = ncp_file_read ,
. write = ncp_file_write ,
2010-05-05 17:15:37 +04:00
. unlocked_ioctl = ncp_ioctl ,
2006-10-01 10:27:55 +04:00
# ifdef CONFIG_COMPAT
. compat_ioctl = ncp_compat_ioctl ,
# endif
2005-04-17 02:20:36 +04:00
. mmap = ncp_mmap ,
. release = ncp_release ,
. fsync = ncp_fsync ,
} ;
2007-02-12 11:55:39 +03:00
const struct inode_operations ncp_file_inode_operations =
2005-04-17 02:20:36 +04:00
{
. setattr = ncp_notify_change ,
} ;