Commit eb4d32c1 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.1.108pre1

parent d4f630d9
A Brief Overview of the Virtual File System
===========================================
by Benjamin LaHaise (blah@dot.superaje.com)
No one else seems to be writing this, so here's a quick description of what
I've learned while writing lofs.
The VFS is relatively simple, but it is nice not to have to browse through
pages of code to determine what is expected when writing a filesystem.
This document is meant to help anyone attempting such a feat, and to clarify
a few important points and dependencies.
register_filesystem (struct file_system_type *fstype)
=====================================================
All filesystems are created equal, or at least they start out that way.
A filesystem, whether in module form or linked into the kernel, needs to add
itself to the table of filesystems by calling register_filesystem with an
initialized file_system_type structure. Any further functions of the
filesystem are accessed through the following function tables:
struct file_system_type
=======================
struct super_block *(*read_super) (struct super_block *sb, void *options, int silent);
This is the entry point of all filesystems. If the filesystem succeeds
in mounting itself, sb should be returned, otherwise NULL. options is
a pointer to a maximum of PAGE_SIZE-1 bytes of options, typically a zero
terminated string passed from mount. This page is freed after read_super
returns, so do not use any pointers into it.
This routine _must_ set the s_op member of sb to point to a valid
super_operations structure.
const char *name;
Name points to a string that the system will know the filesystem by.
int requires_dev;
Set this flag to 1 if the filesystem requires a block device to be mounted
on.
struct file_system_type * next;
This field points to the next file_system_type that is present in the system,
and should be initialized to NULL.
struct super_operations
=======================
The super_operations structure is found through the s_op member of the
super_block structure.
void (*read_inode) (struct inode *inode);
[optional - doesn't quite make sense]
read_inode is called by the VFS when iget is called requesting an inode
not already present in the inode table. i_ino is set to the number of the
inode requested.
The i_op member of inode should be set to a valid inode_operations
structure. Typically filesystems have separate inode_operations for
directories, files and symlinks. i_op can be NULL.
int (*notify_change) (struct inode *, struct iattr *);
[optional]
void (*write_inode) (struct inode *);
[optional]
int (*put_inode) (struct inode *inode);
[optional]
put_inode is called by the VFS when the last instance of inode is released
with a call to iput. The only special consideration that should be made
is that iget may reuse inode without calling read_inode unless clear_inode
is called. put_inode MUST return 1 if it called clear_inode on the inode,
otherwise zero.
void (*put_super) (struct super_block *);
[optional]
void (*write_super) (struct super_block *);
[optional]
void (*statfs) (struct super_block *, struct statfs *, int);
[optional]
int (*remount_fs) (struct super_block *, int *, char *);
[optional]
struct inode_operations
=======================
struct file_operations * default_file_ops;
[mandatory]
All inode_operations structures must have default_file_ops pointing to
a valid file_operations structure.
int (*create) (struct inode *,const char *,int,int,struct inode **);
[optional]
int (*lookup) (struct inode *dir, const char *name, int len, struct inode **result);
[optional]
lookup is called when the VFS wishes to have the filesystem resolve a name
into an inode. Dir is a directory on the filesystem that--we hope--contains
the zero-terminated string name (length len). A return value of zero indicates
that there is a valid inode stored in *result.
*** Note: lofs assumes that any filesystem returns an inode within the filesystem
for all directory inodes. Therefore, __iget(sb,ino,0) should be used to fetch
the inode in a filesystem's lookup routine.
int (*link) (struct inode *,struct inode *,const char *,int);
[optional]
int (*unlink) (struct inode *,const char *,int);
[optional]
int (*symlink) (struct inode *,const char *,int,const char *);
[optional]
int (*mkdir) (struct inode *,const char *,int,int);
[optional]
int (*rmdir) (struct inode *,const char *,int);
[optional]
int (*mknod) (struct inode *,const char *,int,int,int);
[optional]
int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int);
[optional]
int (*readlink) (struct inode *inode, char *buf, int len);
[optional]
readlink is called by the VFS to read the contents of a symbolic link.
inode is an inode that meets the S_ISLNK test, and buf points to a buffer
of len bytes.
int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
[optional]
follow_link must be implemented if readlink is implemented.
Note that follow_link can return a different inode than a
lookup_dentry() on the result of readlink() would return.
The proc filesystem, in particular, uses this feature heavily.
For most user filesystems, however, follow_link() and readlink()
should return consistent results.
int (*readpage) (struct inode *, struct page *); [optional]
int (*writepage) (struct inode *, struct page *); [mandatory with readpage]
In order for files to be mmap'd, readpage and writepage are required.
A filesystem can use generic_readpage/writepage if it supports the bmap
function. Otherwise, a custom version must be written.
int (*bmap) (struct inode *,int);
[optional]
void (*truncate) (struct inode *);
[optional]
int (*permission) (struct inode *, int);
[optional]
int (*smap) (struct inode *,int);
[optional]
struct file_operations
======================
int (*lseek) (struct inode *, struct file *, off_t, int);
int (*read) (struct inode *, struct file *, char *, int);
int (*write) (struct inode *, struct file *, const char *, int);
int (*readdir) (struct inode *, struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, poll_table *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct inode *, struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
void (*release) (struct inode *, struct file *);
int (*fsync) (struct inode *, struct file *);
int (*fasync) (struct inode *, struct file *, int);
int (*check_media_change) (kdev_t dev);
int (*revalidate) (kdev_t dev);
VERSION = 2
PATCHLEVEL = 1
SUBLEVEL = 107
SUBLEVEL = 108
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
......
......@@ -547,7 +547,8 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_capget)
.long SYMBOL_NAME(sys_capset) /* 185 */
.long SYMBOL_NAME(sys_sigaltstack)
.long SYMBOL_NAME(sys_sendfile)
.rept NR_syscalls-186
.rept NR_syscalls-187
.long SYMBOL_NAME(sys_ni_syscall)
.endr
......@@ -466,7 +466,7 @@ int get_cpuinfo(char * buffer)
continue;
#endif
p += sprintf(p, "processor\t: %d\n"
"CPU family\t: %c\n"
"cpu family\t: %c\n"
"model\t\t: %s\n"
"vendor_id\t: %s\n",
n,
......@@ -512,9 +512,9 @@ int get_cpuinfo(char * buffer)
"hlt_bug\t\t: %s\n"
"sep_bug\t\t: %s\n"
"f00f_bug\t: %s\n"
"FPU\t\t: %s\n"
"FPU_exception\t: %s\n"
"CPUID level\t: %d\n"
"fpu\t\t: %s\n"
"fpu_exception\t: %s\n"
"cpuid level\t: %d\n"
"wp\t\t: %s\n"
"flags\t\t:",
c->fdiv_bug ? "yes" : "no",
......
......@@ -8,7 +8,6 @@
* moment everything difficult is handled by the generic code.
*/
#include <linux/config.h>
#include <asm/ptrace.h>
#include <linux/types.h>
#include <linux/init.h>
......
......@@ -6,7 +6,6 @@
* This file contains the HP300-specific time handling code.
*/
#include <linux/config.h>
#include <asm/ptrace.h>
#include <linux/types.h>
#include <linux/init.h>
......
#include <linux/config.h>
#include <linux/module.h>
#include <linux/linkage.h>
#include <linux/sched.h>
......
......@@ -69,6 +69,7 @@
* -
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
......
......@@ -5,7 +5,6 @@
* via them as are assorted bits and bobs - eg rtc, adb.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
......
......@@ -21,7 +21,7 @@ CONFIG_MACH_SPECIFIC=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
CONFIG_KERNELD=y
CONFIG_KMOD=y
CONFIG_PCI=y
CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
......
......@@ -20,7 +20,7 @@ CONFIG_ALL_PPC=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
CONFIG_KERNELD=y
CONFIG_KMOD=y
CONFIG_PCI=y
CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
......
......@@ -21,7 +21,7 @@ CONFIG_MACH_SPECIFIC=y
CONFIG_EXPERIMENTAL=y
CONFIG_MODULES=y
CONFIG_MODVERSIONS=y
CONFIG_KERNELD=y
CONFIG_KMOD=y
CONFIG_PCI=y
# CONFIG_PCI_OPTIMIZE is not set
CONFIG_PCI_OLD_PROC=y
......
......@@ -52,7 +52,6 @@ int unicount[MAX_FONTLEN];
void addpair(int fp, int un)
{
int i;
unicode hu;
if ( un <= 0xfffe )
{
......
......@@ -23,8 +23,8 @@
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#endif
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
#ifdef __mc68000__
......@@ -262,7 +262,7 @@ static void set_con2fb_map(int unit, int newidx)
}
}
#ifdef CONFIG_KERNELD
#ifdef CONFIG_KMOD
static void try_to_load(int fb)
{
char modname[16];
......@@ -337,7 +337,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EINVAL;
if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
return -EINVAL;
#ifdef CONFIG_KERNELD
#ifdef CONFIG_KMOD
if (!registered_fb[con2fb.framebuffer])
try_to_load(con2fb.framebuffer);
#endif
......@@ -419,7 +419,7 @@ fb_open(struct inode *inode, struct file *file)
int fbidx = GET_FB_IDX(inode->i_rdev);
struct fb_info *info;
#ifdef CONFIG_KERNELD
#ifdef CONFIG_KMOD
if (!(info = registered_fb[fbidx]))
try_to_load(fbidx);
#endif
......
......@@ -20,8 +20,6 @@
* - making it shorter - scr_readw are macros which expand in PRETTY long code
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
......
......@@ -8,7 +8,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
......
......@@ -12,9 +12,7 @@
* most of a2025 and sunlance with the aim of merging them, so the
* common code was pretty obvious.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
......
......@@ -35,6 +35,7 @@
/*****************************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
......
......@@ -438,7 +438,7 @@ static void gentbl_hapn4800(FILE *f)
{
int i, j, k, l;
float s;
float c[40];
float c[44];
float min, max;
fprintf(f, "\n/*\n * hapn4800 specific tables\n */\n\n");
......
......@@ -5,9 +5,7 @@
* Uses the generic 7990.c LANCE code.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
......
......@@ -42,7 +42,6 @@
static const char *version = "sktr.c: v1.01 08/29/97 by Christoph Goos\n";
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
......
......@@ -11,6 +11,8 @@
#ifndef NCR53C9X_H
#define NCR53C9X_H
#include <linux/config.h>
/* Macros for debugging messages */
/* #define DEBUG_ESP */
......
......@@ -14,8 +14,8 @@
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/config.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
#include <asm/irq.h>
......@@ -104,7 +104,7 @@ __initfunc(int pluto_detect(Scsi_Host_Template *tpnt))
fcscount++;
PLND(("%d channels online\n", fcscount))
if (!fcscount) {
#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KERNELD)
#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD)
request_module("soc");
for_each_online_fc_channel(fc)
......
......@@ -24,7 +24,6 @@
*
********************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
......
......@@ -24,7 +24,6 @@
*
********************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/types.h>
......
......@@ -30,6 +30,8 @@
#ifndef __MSND_CLASSIC_H
#define __MSND_CLASSIC_H
#include <linux/config.h>
#define DSP_NUMIO 0x10
#define HP_MEMM 0x08
......
......@@ -24,7 +24,6 @@
*
********************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/types.h>
......
......@@ -30,6 +30,8 @@
#ifndef __MSND_PINNACLE_H
#define __MSND_PINNACLE_H
#include <linux/config.h>
#define DSP_NUMIO 0x08
#define HP_DSPR 0x04
......
......@@ -34,7 +34,6 @@
* locking at some point in 2.3.x.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/types.h>
......
......@@ -23,6 +23,7 @@
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
......
......@@ -201,7 +201,7 @@ void fbcon_ilbm_putcs(struct vc_data *conp, struct display *p, const char *s,
#if defined(__BIG_ENDIAN)
d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++;
#elif defined(__LITTLE_ENDIAN)
d = *cdat1++ | *cdat2++<<8 | *cdat3++<<16 | *cdat4++<<32);
d = *cdat1++ | *cdat2++<<8 | *cdat3++<<16 | *cdat4++<<24;
#else
#error FIXME: No endianness??
#endif
......
......@@ -10,6 +10,7 @@
* more details.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/console.h>
......
......@@ -10,6 +10,7 @@
* more details.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/console.h>
......
......@@ -10,6 +10,7 @@
* more details.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/console.h>
......
......@@ -6,7 +6,6 @@
* No! -- Jes
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
......
......@@ -7,7 +7,6 @@
*
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
......
......@@ -232,7 +232,7 @@ static int get_kstat(char * buffer)
#ifdef __SMP__
len = sprintf(buffer,
"CPU %u %u %u %lu\n",
"cpu %u %u %u %lu\n",
kstat.cpu_user,
kstat.cpu_nice,
kstat.cpu_system,
......
......@@ -297,12 +297,15 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
current->state = TASK_INTERRUPTIBLE;
for (fdpnt = fds, j = 0; j < nfds; j++, fdpnt++) {
int fd;
unsigned int mask;
struct file * file;
mask = POLLNVAL;
mask = 0;
fd = fdpnt->fd;
if (fd >= 0) {
/* poll_wait increments f_count if needed */
file = fcheck(fdpnt->fd);
struct file * file = fcheck(fd);
mask = POLLNVAL;
if (file != NULL) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll)
......@@ -313,6 +316,7 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
wait = NULL;
count++;
}
}
fdpnt->revents = mask;
}
......
......@@ -3,7 +3,7 @@ Mon Dec 15 1997 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
Fri Jan 23 1998 Krzysztof G. Baranowski <kgb@manjak.knm.org.pl>
* inode.c: corrected 1 track offset setting (in sb->sv_block_base).
Originally it was overriden (by setting to zero)
Originally it was overridden (by setting to zero)
in detected_[xenix,sysv4,sysv2,coherent]. Thanks
to Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
for identifying the problem.
......
#
# Makefile for the Linux SystemV/Coherent-filesystem routines.
# Makefile for the Linux SystemV/Coherent filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
# unless it's something special (not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
# Note 2! The CFLAGS definitions are now in the main makefile.
O_TARGET := sysv.o
O_OBJS := ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \
......
......@@ -36,7 +36,7 @@
static ssize_t sysv_file_write(struct file *, const char *, size_t, loff_t *);
/*
* We have mostly NULL's here: the current defaults are ok for
* We have mostly NULLs here: the current defaults are OK for
* the coh filesystem.
*/
static struct file_operations sysv_file_operations = {
......@@ -220,7 +220,7 @@ static ssize_t sysv_file_write(struct file * filp, const char * buf,
return -EINVAL;
}
/*
* ok, append may not work when many processes are writing at the same time
* OK, append may not work when many processes are writing at the same time
* but so what. That way leads to madness anyway.
* But we need to protect against simultaneous truncate as we may end up
* writing our data into blocks that have meanwhile been incorporated into
......
......@@ -24,7 +24,7 @@
/*
* Truncate has the most races in the whole filesystem: coding it is
* a pain in the a**. Especially as I don't do any locking...
* a pain in the a**, especially as I don't do any locking.
*
* The code may look a bit weird, but that's just because I've tried to
* handle things like file-size changes in a somewhat graceful manner.
......
......@@ -192,6 +192,7 @@
#define __NR_capget 184
#define __NR_capset 185
#define __NR_sigaltstack 186
#define __NR_sendfile 187
/* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */
......
#ifndef _M68K_PGTABLE_H
#define _M68K_PGTABLE_H
#include <linux/config.h>
#include <asm/setup.h>
#ifndef __ASSEMBLY__
......
......@@ -11,6 +11,8 @@
#ifndef _LINUX_CONSOLE_COMPAT_H_
#define _LINUX_CONSOLE_COMPAT_H_
#include <linux/config.h>
#undef video_num_columns
#undef video_num_lines
#undef video_size_row
......
......@@ -10,8 +10,6 @@
*/
#define CUR_DEFAULT CUR_UNDERLINE
#include <linux/config.h>
#define NPAR 16
struct vc_data {
......
......@@ -4,8 +4,6 @@
* Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c
*/
#include <linux/config.h>
extern int sel_cons;
extern void clear_selection(void);
......@@ -60,8 +58,6 @@ extern void putconsxy(int currcons, char *p);
/* how to access screen memory */
#include <linux/config.h>
static inline void scr_writew(unsigned short val, unsigned short *addr)
{
/* simply store the value in the "shadow screen" memory */
......
......@@ -567,6 +567,23 @@ static inline unsigned long generic_file_readahead(int reada_ok,
return page_cache;
}
/*
* "descriptor" for what we're up to with a read.
* This allows us to use the same read code yet
* have multiple different users of the data that
* we read from a file.
*
* The simplest case just copies the data to user
* mode.
*/
typedef struct {
size_t written;
size_t count;
char * buf;
int error;
} read_descriptor_t;
typedef int (*read_actor_t)(read_descriptor_t *, const char *, unsigned long);
/*
* This is a generic file read routine, and uses the
......@@ -576,23 +593,14 @@ static inline unsigned long generic_file_readahead(int reada_ok,
* This is really ugly. But the goto's actually try to clarify some
* of the logic when it comes to error handling etc.
*/
ssize_t generic_file_read(struct file * filp, char * buf,
size_t count, loff_t *ppos)
static void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, read_actor_t actor)
{
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
ssize_t error, read;
size_t pos, pgpos, page_cache;
int reada_ok;
int max_readahead = get_max_readahead(inode);
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
if (!count)
return 0;
error = 0;
read = 0;
page_cache = 0;
pos = *ppos;
......@@ -620,12 +628,12 @@ ssize_t generic_file_read(struct file * filp, char * buf,
* Then, at least MIN_READAHEAD if read ahead is ok,
* and at most MAX_READAHEAD in all cases.
*/
if (pos + count <= (PAGE_SIZE >> 1)) {
if (pos + desc->count <= (PAGE_SIZE >> 1)) {
filp->f_ramax = 0;
} else {
unsigned long needed;
needed = ((pos + count) & PAGE_MASK) - pgpos;
needed = ((pos + desc->count) & PAGE_MASK) - pgpos;
if (filp->f_ramax < needed)
filp->f_ramax = needed;
......@@ -678,20 +686,20 @@ ssize_t generic_file_read(struct file * filp, char * buf,
offset = pos & ~PAGE_MASK;
nr = PAGE_SIZE - offset;
if (nr > count)
nr = count;
if (nr > inode->i_size - pos)
nr = inode->i_size - pos;
nr -= copy_to_user(buf, (void *) (page_address(page) + offset), nr);
release_page(page);
error = -EFAULT;
if (!nr)
break;
buf += nr;
/*
* The actor routine returns how many bytes were actually used..
* NOTE! This may not be the same as how much of a user buffer
* we filled up (we may be padding etc), so we can only update
* "pos" here (the actor routine has to update the user buffer
* pointers and the remaining count).
*/
nr = actor(desc, (const char *) (page_address(page) + offset), nr);
pos += nr;
read += nr;
count -= nr;
if (count)
release_page(page);
if (nr && desc->count)
continue;
break;
}
......@@ -709,7 +717,7 @@ ssize_t generic_file_read(struct file * filp, char * buf,
*/
if (page_cache)
continue;
error = -ENOMEM;
desc->error = -ENOMEM;
break;
}
......@@ -738,11 +746,14 @@ ssize_t generic_file_read(struct file * filp, char * buf,
if (reada_ok && filp->f_ramax > MIN_READAHEAD)
filp->f_ramax = MIN_READAHEAD;
error = inode->i_op->readpage(filp, page);
{
int error = inode->i_op->readpage(filp, page);
if (!error)
goto found_page;
desc->error = error;
release_page(page);
break;
}
page_read_error:
/*
......@@ -750,25 +761,165 @@ ssize_t generic_file_read(struct file * filp, char * buf,
* Try to re-read it _once_. We do this synchronously,
* because this happens only if there were errors.
*/
error = inode->i_op->readpage(filp, page);
{
int error = inode->i_op->readpage(filp, page);
if (!error) {
wait_on_page(page);
if (PageUptodate(page) && !PageError(page))
goto success;
error = -EIO; /* Some unspecified error occurred.. */
}
desc->error = error;
release_page(page);
break;
}
}
*ppos = pos;
filp->f_reada = 1;
if (page_cache)
free_page(page_cache);
UPDATE_ATIME(inode);
if (!read)
read = error;
return read;
}
static int file_read_actor(read_descriptor_t * desc, const char *area, unsigned long size)
{
unsigned long left;
unsigned long count = desc->count;
if (size > count)
size = count;
left = __copy_to_user(desc->buf, area, size);
if (left) {
size -= left;
desc->error = -EFAULT;
}
desc->count = count - size;
desc->written += size;
desc->buf += size;
return size;
}
/*
* This is the "read()" routine for all filesystems
* that can use the page cache directly.
*/
ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
{
ssize_t retval;
retval = -EFAULT;
if (access_ok(VERIFY_WRITE, buf, count)) {
retval = 0;
if (count) {
read_descriptor_t desc;
desc.written = 0;
desc.count = count;
desc.buf = buf;
desc.error = 0;
do_generic_file_read(filp, ppos, &desc, file_read_actor);
retval = desc.written;
if (!retval)
retval = desc.error;
}
}
return retval;
}
static int file_send_actor(read_descriptor_t * desc, const char *area, unsigned long size)
{
ssize_t written;
unsigned long count = desc->count;
struct file *file = (struct file *) desc->buf;
struct inode *inode = file->f_dentry->d_inode;
if (size > count)
size = count;
down(&inode->i_sem);
set_fs(KERNEL_DS);
written = file->f_op->write(file, area, size, &file->f_pos);
set_fs(USER_DS);
up(&inode->i_sem);
if (written < 0) {
desc->error = written;
written = 0;
}
desc->count = count - written;
desc->written += written;
return written;
}
asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, size_t count)
{
ssize_t retval;
struct file * in_file, * out_file;
struct inode * in_inode, * out_inode;
lock_kernel();
/*
* Get input file, and verify that it is ok..
*/
retval = -EBADF;
in_file = fget(in_fd);
if (!in_file)
goto out;
if (!(in_file->f_mode & FMODE_READ))
goto fput_in;
retval = -EINVAL;
in_inode = in_file->f_dentry->d_inode;
if (!in_inode)
goto fput_in;
if (!in_inode->i_op || !in_inode->i_op->readpage)
goto fput_in;
retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count);
if (retval)
goto fput_in;
/*
* Get output file, and verify that it is ok..
*/
retval = -EBADF;
out_file = fget(out_fd);
if (!out_file)
goto fput_in;
if (!(out_file->f_mode & FMODE_WRITE))
goto fput_out;
retval = -EINVAL;
if (!out_file->f_op || !out_file->f_op->write)
goto fput_out;
out_inode = out_file->f_dentry->d_inode;
if (!out_inode)
goto fput_out;
retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
if (retval)
goto fput_out;
retval = 0;
if (count) {
read_descriptor_t desc;
desc.written = 0;
desc.count = count;
desc.buf = (char *) out_file;
desc.error = 0;
do_generic_file_read(in_file, &in_file->f_pos, &desc, file_send_actor);
retval = desc.written;
if (!retval)
retval = desc.error;
}
fput_out:
fput(out_file);
fput_in:
fput(in_file);
out:
unlock_kernel();
return retval;
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment