This is file.c in view mode; [Download] [Up]
/*
* linux/fs/ufs/file.c
*
* Copyright (C) 1994 Yossi Gottlieb (yogo@math.tau.ac.il)
*
* Based on code and information:
* BSD code, Copyright (c) 1982, 1986 Regents of the University of California.
* All rights reserved.
* linux/fs/minix Copyright (C) 1991, 1992, 1993 Linus Torvalds
*
*/
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>
#include <linux/ufs_fs.h>
#include "ufs.h"
#define NBUF 32
int ufs_file_read(struct inode *, struct file *, char *, int);
int ufs_bmap(struct inode *, int block);
struct file_operations ufs_file_operations = {
NULL, /* lseek - none */
ufs_file_read, /* read - none */
NULL, /* write - none */
NULL,
NULL, /* select - none */
NULL, /* ioctl - none */
generic_mmap, /* mmap - none */
NULL, /* open - none */
NULL, /* release - none */
file_fsync, /* fsync - none */
NULL, /* fasync - none */
NULL,
NULL
};
struct inode_operations ufs_file_inode_operations = {
&ufs_file_operations,
NULL, /* create - none */
NULL, /* lookup - none */
NULL, /* link - none */
NULL, /* unlink - none */
NULL, /* symlink - none */
NULL, /* mkdir - none */
NULL, /* rmdir - none */
NULL, /* mknod - none */
NULL, /* rename - none */
NULL, /* readlink - none */
NULL, /* follow_link - none */
ufs_bmap, /* bmap - wrapper for ufs_blknum */
NULL, /* truncate - none */
NULL, /* permission - none */
NULL /* smap - none */
};
int ufs_bmap(struct inode *inode, int block)
{
return fsbtodb(&inode->i_sb->u.ufs_sb, ufs_blknum(inode, block));
}
int ufs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int read,left,chars;
int block, blocks, offset, blk, bfrag, bmaxfrag;
int bhrequest, uptodate;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * bhreq[NBUF];
struct buffer_head * buflist[NBUF];
struct ufs_sb_info *sb = &inode->i_sb->u.ufs_sb;
unsigned int size;
if (!inode) {
printk("ufs_file_read: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
printk("ufs_file_read: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
offset = filp->f_pos;
size = inode->i_size;
if (offset > size)
left = 0;
else
left = size - offset;
if (left > count)
left = count;
if (left <= 0)
return 0;
read = 0;
block = lblkno(sb, offset);
bfrag = numfrags(sb, offset & (sb->fs_bsize-1));
offset &= sb->fs_fsize-1;
size = blkroundup(sb, size);
blocks = lblkno(sb, blkroundup(sb, left));
bhb = bhe = buflist;
if (filp->f_reada) {
if (blocks < read_ahead[MAJOR(inode->i_dev)] / BLOCK_SIZE >> 9)
blocks = read_ahead[MAJOR(inode->i_dev)] / BLOCK_SIZE >> 9;
if (block + blocks > size)
blocks = size - block;
}
bmaxfrag = sb->fs_frag;
#ifdef UFS_DEBUG
printk("ufs_file_read: block=%d,blocks=%d,size=%d,offset=%d,bmaxfrag=%d,left=%d\n",
block,blocks,size,offset,bmaxfrag,left);
#endif
do {
bhrequest = 0;
uptodate = 1;
while (blocks) {
if (!--blocks)
bmaxfrag = bfrag + numfrags(sb, fragroundup(sb, left));
else
bmaxfrag = sb->fs_frag - bfrag;
blk = ufs_blknum(inode, blkstofrags(sb, block));
if (blk > 0) {
blk = fsbtodb(sb, blk);
blk += fsbtodb(sb, bfrag);
}
#ifdef UFS_DEBUG
printk("ufs_file_read: blk=%d, bfrag=%d, bmaxfrag=%d\n", blk, bfrag, bmaxfrag);
#endif
while (bfrag < bmaxfrag) {
if (blk == -1)
*bhb = NULL;
else
*bhb = getblk(inode->i_sb->s_dev, sb->fs_block_base + blk++, BLOCK_SIZE);
if (*bhb && !(*bhb)->b_uptodate) {
uptodate = 0;
bhreq[bhrequest++] = *bhb;
}
bfrag += dbtofsb(sb, 1);
if (++bhb == &buflist[NBUF])
bhb = buflist;
if (*bhb == *bhe)
break;
}
if (bfrag >= bmaxfrag) {
bfrag = 0;
block++;
#ifdef UFS_DEBUG
printk("ufs_file_read: finished block %d\n", block);
#endif
} else {
blocks++;
#ifdef UFS_DEBUG
printk("ufs_file_read: unfinished block %d, frag %d\n", block, bfrag);
#endif
}
/* If the block we have on hand is uptodate, go ahead
and complete processing. */
if (uptodate)
break;
if (bhb == bhe)
break;
}
/* Now request them all */
if (bhrequest)
ll_rw_block(READ, bhrequest, bhreq);
do { /* Finish off all I/O that has actually completed */
if (*bhe) {
wait_on_buffer(*bhe);
if (!(*bhe)->b_uptodate) { /* read error? */
brelse(*bhe);
if (++bhe == &buflist[NBUF])
bhe = buflist;
left = 0;
break;
}
}
if (left < BLOCK_SIZE - offset)
chars = left;
else
chars = BLOCK_SIZE - offset;
filp->f_pos += chars;
left -= chars;
read += chars;
if (*bhe) {
memcpy_tofs(buf,offset+(*bhe)->b_data,chars);
brelse(*bhe);
buf += chars;
} else {
while (chars-->0)
put_fs_byte(0,buf++);
}
offset = 0;
if (++bhe == &buflist[NBUF])
bhe = buflist;
} while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
} while (left > 0);
/* Release the read-ahead blocks */
while (bhe != bhb) {
brelse(*bhe);
if (++bhe == &buflist[NBUF])
bhe = buflist;
};
if (!read)
return -EIO;
filp->f_reada = 1;
if (!IS_RDONLY(inode))
inode->i_atime = CURRENT_TIME;
return read;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.