diff options
Diffstat (limited to 'fs/ufs/file.c')
-rw-r--r-- | fs/ufs/file.c | 258 |
1 files changed, 83 insertions, 175 deletions
diff --git a/fs/ufs/file.c b/fs/ufs/file.c index 7e94bfd1c..9e027cfc3 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c @@ -41,52 +41,6 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) -static long long ufs_file_lseek(struct file *, long long, int); -static ssize_t ufs_file_write (struct file *, const char *, size_t, loff_t *); -static int ufs_release_file (struct inode *, struct file *); - -/* - * We have mostly NULL's here: the current defaults are ok for - * the ufs filesystem. - */ -static struct file_operations ufs_file_operations = { - ufs_file_lseek, /* lseek */ - generic_file_read, /* read */ - ufs_file_write, /* write */ - NULL, /* readdir - bad */ - NULL, /* poll - default */ - NULL, /* ioctl */ - generic_file_mmap, /* mmap */ - NULL, /* no special open is needed */ - NULL, /* flush */ - ufs_release_file, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL /* revalidate */ -}; - -struct inode_operations ufs_file_inode_operations = { - &ufs_file_operations,/* default file operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - generic_readpage, /* readpage */ - NULL, /* writepage */ - ufs_bmap, /* bmap */ - ufs_truncate, /* truncate */ - NULL, /* permission */ - NULL /* smap */ -}; - /* * Make sure the offset never goes beyond the 32-bit mark.. */ @@ -133,139 +87,49 @@ static inline void remove_suid(struct inode *inode) } } -static ssize_t ufs_file_write ( - struct file * filp, - const char * buf, - size_t count, - loff_t *ppos ) +static int ufs_writepage (struct file *file, struct page *page) { - struct inode * inode = filp->f_dentry->d_inode; - __u32 pos; - long block; - int offset; - int written, c; - struct buffer_head * bh, *bufferlist[NBUF]; - struct super_block * sb; - int err; - int i,buffercount,write_error; - - /* POSIX: mtime/ctime may not change for 0 count */ - if (!count) - return 0; - write_error = buffercount = 0; - if (!inode) - return -EINVAL; - sb = inode->i_sb; - if (sb->s_flags & MS_RDONLY) - /* - * This fs has been automatically remounted ro because of errors - */ - return -ENOSPC; - - if (!S_ISREG(inode->i_mode)) { - ufs_warning (sb, "ufs_file_write", "mode = %07o", - inode->i_mode); - return -EINVAL; - } - remove_suid(inode); - - if (filp->f_flags & O_APPEND) - pos = inode->i_size; - else { - pos = *ppos; - if (pos != *ppos) - return -EINVAL; - } - - /* Check for overflow.. */ - if (pos > (__u32) (pos + count)) { - count = ~pos; /* == 0xFFFFFFFF - pos */ - if (!count) - return -EFBIG; - } - - /* - * If a file has been opened in synchronous mode, we have to ensure - * that meta-data will also be written synchronously. Thus, we - * set the i_osync field. This field is tested by the allocation - * routines. - */ - if (filp->f_flags & O_SYNC) - inode->u.ufs_i.i_osync++; - block = pos >> sb->s_blocksize_bits; - offset = pos & (sb->s_blocksize - 1); - c = sb->s_blocksize - offset; - written = 0; + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + unsigned long block; + int *p, nr[PAGE_SIZE/512]; + int i, err, created; + struct buffer_head *bh; + + i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits; + block = page->offset >> inode->i_sb->s_blocksize_bits; + p = nr; + bh = page->buffers; do { - bh = ufs_getfrag (inode, block, 1, &err); - if (!bh) { - if (!written) - written = err; - break; - } - if (c > count) - c = count; - if (c != sb->s_blocksize && !buffer_uptodate(bh)) { - ll_rw_block (READ, 1, &bh); - wait_on_buffer (bh); - if (!buffer_uptodate(bh)) { - brelse (bh); - if (!written) - written = -EIO; - break; - } - } - c -= copy_from_user (bh->b_data + offset, buf, c); - if (!c) { - brelse(bh); - if (!written) - written = -EFAULT; - break; - } - update_vm_cache(inode, pos, bh->b_data + offset, c); - pos += c; - written += c; - buf += c; - count -= c; - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh, 0); - if (filp->f_flags & O_SYNC) - bufferlist[buffercount++] = bh; + if (bh && bh->b_blocknr) + *p = bh->b_blocknr; else - brelse(bh); - if (buffercount == NBUF){ - ll_rw_block(WRITE, buffercount, bufferlist); - for(i=0; i<buffercount; i++){ - wait_on_buffer(bufferlist[i]); - if (!buffer_uptodate(bufferlist[i])) - write_error=1; - brelse(bufferlist[i]); - } - buffercount=0; - } - if (write_error) - break; + *p = ufs_getfrag_block(inode, block, 1, &err, &created); + if (!*p) + return -EIO; + i--; block++; - offset = 0; - c = sb->s_blocksize; - } while (count); - if (buffercount){ - ll_rw_block(WRITE, buffercount, bufferlist); - for (i=0; i<buffercount; i++){ - wait_on_buffer(bufferlist[i]); - if (!buffer_uptodate(bufferlist[i])) - write_error=1; - brelse(bufferlist[i]); - } - } - if (pos > inode->i_size) - inode->i_size = pos; - if (filp->f_flags & O_SYNC) - inode->u.ufs_i.i_osync--; - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - *ppos = pos; - mark_inode_dirty(inode); - return written; + p++; + if (bh) + bh = bh->b_this_page; + } while (i > 0); + + brw_page(WRITE, page, inode->i_dev, nr, inode->i_sb->s_blocksize, 1); + return 0; +} + +static long ufs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char *buf) +{ + return block_write_one_page(file, page, offset, bytes, buf, ufs_getfrag_block); +} + +/* + * Write to a file (through the page cache). + */ +static ssize_t +ufs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + return generic_file_write(file, buf, count, ppos, ufs_write_one_page); } /* @@ -277,3 +141,47 @@ static int ufs_release_file (struct inode * inode, struct file * filp) { return 0; } + +/* + * We have mostly NULL's here: the current defaults are ok for + * the ufs filesystem. + */ +static struct file_operations ufs_file_operations = { + ufs_file_lseek, /* lseek */ + generic_file_read, /* read */ + ufs_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* poll - default */ + NULL, /* ioctl */ + generic_file_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* flush */ + ufs_release_file, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ +}; + +struct inode_operations ufs_file_inode_operations = { + &ufs_file_operations,/* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + generic_readpage, /* readpage */ + ufs_writepage, /* writepage */ + ufs_bmap, /* bmap */ + ufs_truncate, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* revalidate */ + block_flushpage, /* flushpage */ +}; |