summaryrefslogtreecommitdiffstats
path: root/fs/qnx4/file.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-09-19 19:15:08 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-09-19 19:15:08 +0000
commit03ba4131783cc9e872f8bb26a03f15bc11f27564 (patch)
tree88db8dba75ae06ba3bad08e42c5e52efc162535c /fs/qnx4/file.c
parent257730f99381dd26e10b832fce4c94cae7ac1176 (diff)
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'fs/qnx4/file.c')
-rw-r--r--fs/qnx4/file.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
new file mode 100644
index 000000000..f26733d9a
--- /dev/null
+++ b/fs/qnx4/file.c
@@ -0,0 +1,265 @@
+/*
+ * QNX4 file system, Linux implementation.
+ *
+ * Version : 0.1
+ *
+ * Using parts of the xiafs filesystem.
+ *
+ * History :
+ *
+ * 25-05-1998 by Richard Frowijn : first release.
+ * 21-06-1998 by Frank Denis : wrote qnx4_readpage to use generic_file_read.
+ * 27-06-1998 by Frank Denis : file overwriting.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/qnx4_fs.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+#include <linux/fs.h>
+#include <linux/qnx4_fs.h>
+
+static int qnx4_readpage(struct file *file, struct page *page);
+
+#ifdef CONFIG_QNX4FS_RW
+static ssize_t qnx4_file_write(struct file *filp, const char *buf,
+ size_t count, loff_t * ppos)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct qnx4_inode_info *qnx4_ino;
+ struct buffer_head *bh;
+ ssize_t result = -EBUSY, c;
+ off_t pos;
+ unsigned long start, block, extent_end;
+ char *p;
+
+ QNX4DEBUG(("qnx4: file_write(%s/%s (%d), %lu@%lu)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ inode->i_count, (unsigned long) count, (unsigned long) *ppos));
+ if (inode == NULL) {
+ printk("qnx4: NULL inode for file_write\n");
+ return -EINVAL;
+ }
+ qnx4_ino = &inode->u.qnx4_i;
+ if (S_ISREG(inode->i_mode) == 0) {
+ printk("qnx4: write to non-file, mode %07o\n", inode->i_mode);
+ return -EINVAL;
+ }
+ if (count == 0) {
+ goto out;
+ }
+ if (filp->f_flags & O_APPEND) {
+ pos = inode->i_size;
+ } else {
+ pos = *ppos;
+ }
+ start = qnx4_ino->i_first_xtnt.xtnt_blk + ((pos >> 9) * 0) - 1;
+ result = 0;
+ extent_end = start + qnx4_ino->i_first_xtnt.xtnt_size - 1;
+ QNX4DEBUG(("qnx4: extent length : [%lu] bytes\n",
+ qnx4_ino->i_first_xtnt.xtnt_size));
+ while (result < count) {
+ block = start + pos / QNX4_BLOCK_SIZE;
+ if (block > extent_end) {
+ if (qnx4_is_free(inode->i_sb, block) <= 0) {
+ printk("qnx4: next inode is busy -> write aborted.\n");
+ result = -ENOSPC;
+ break;
+ }
+ }
+ if ((bh = bread(inode->i_dev, block,
+ QNX4_BLOCK_SIZE)) == NULL) {
+ printk("qnx4: I/O error on write.\n");
+ result = -EIO;
+ goto out;
+ }
+ if (bh == NULL) {
+ if (result != 0) {
+ result = -ENOSPC;
+ }
+ break;
+ }
+ if (block > extent_end) {
+ qnx4_set_bitmap(inode->i_sb, block, 1);
+ extent_end++;
+ qnx4_ino->i_first_xtnt.xtnt_size = extent_end - start + 1;
+ }
+ c = QNX4_BLOCK_SIZE - (pos % QNX4_BLOCK_SIZE);
+ if (c > count - result) {
+ c = count - result;
+ }
+ if (c != QNX4_BLOCK_SIZE && buffer_uptodate(bh) == 0) {
+ ll_rw_block(WRITE, 1, &bh);
+ wait_on_buffer(bh);
+ if (buffer_uptodate(bh) == 0) {
+ brelse(bh);
+ if (result != 0) {
+ result = -EIO;
+ }
+ break;
+ }
+ }
+ p = bh->b_data + (pos % QNX4_BLOCK_SIZE);
+ c -= copy_from_user(p, buf, c);
+ if (c == 0) {
+ brelse(bh);
+ if (result == 0) {
+ result = -EFAULT;
+ }
+ break;
+ }
+ update_vm_cache(inode, pos, p, c);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 0);
+ brelse(bh);
+ pos += c;
+ buf += c;
+ result += c;
+ }
+ if (pos > inode->i_size) {
+ inode->i_size = pos;
+ }
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ *ppos = pos;
+ mark_inode_dirty(inode);
+
+ out:
+ return result;
+}
+#endif
+
+/*
+ * We have moostly NULL's here: the current defaults are ok for
+ * the qnx4 filesystem.
+ */
+static struct file_operations qnx4_file_operations =
+{
+ NULL, /* lseek - default */
+ generic_file_read, /* read */
+#ifdef CONFIG_QNX4FS_RW
+ qnx4_file_write, /* write */
+#else
+ NULL,
+#endif
+ NULL, /* readdir - bad */
+ NULL, /* poll - default */
+ NULL, /* ioctl - default */
+ generic_file_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* no special flush code */
+ NULL, /* release */
+#ifdef CONFIG_QNX4FS_RW
+ qnx4_sync_file, /* fsync */
+#else
+ NULL,
+#endif
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
+};
+
+struct inode_operations qnx4_file_inode_operations =
+{
+ &qnx4_file_operations, /* default file operations */
+#ifdef CONFIG_QNX4FS_RW
+ qnx4_create, /* create */
+#else
+ NULL,
+#endif
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ qnx4_readpage, /* readpage */
+ NULL, /* writepage */
+ qnx4_bmap, /* bmap */
+#ifdef CONFIG_QNX4FS_RW
+ qnx4_truncate, /* truncate */
+#else
+ NULL,
+#endif
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+static int qnx4_readpage(struct file *file, struct page *page)
+{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct qnx4_inode_info *qnx4_ino = &inode->u.qnx4_i;
+ unsigned long buf;
+ unsigned long offset, avail, readlen;
+ unsigned long start;
+ unsigned long count;
+ struct buffer_head *bh;
+ int res = -EIO;
+
+ QNX4DEBUG(("qnx4: readpage offset=[%ld]\n", (long) page->offset));
+
+ if (qnx4_ino->i_xblk != 0) {
+ printk("qnx4: sorry, this file is extended, don't know how to handle it (yet) !\n");
+ return -EIO;
+ }
+ atomic_inc(&page->count);
+ set_bit(PG_locked, &page->flags);
+ buf = page_address(page);
+ clear_bit(PG_uptodate, &page->flags);
+ clear_bit(PG_error, &page->flags);
+ offset = page->offset;
+
+ if (offset < inode->i_size) {
+ res = 0;
+ avail = inode->i_size - offset;
+ readlen = MIN(avail, PAGE_SIZE);
+ start = qnx4_ino->i_first_xtnt.xtnt_blk + (offset >> 9) - 1;
+ count = PAGE_SIZE / QNX4_BLOCK_SIZE;
+ do {
+ QNX4DEBUG(("qnx4: reading page starting at [%ld]\n", (long) start));
+ if ((bh = bread(inode->i_dev, start, QNX4_BLOCK_SIZE)) == NULL) {
+ printk("qnx4: data corrupted or I/O error.\n");
+ res = -EIO;
+ } else {
+ memcpy((void *) buf, bh->b_data, QNX4_BLOCK_SIZE);
+ }
+ buf += QNX4_BLOCK_SIZE;
+ start++;
+ count--;
+ } while (count != 0);
+ }
+ if (res != 0) {
+ set_bit(PG_error, &page->flags);
+ memset((void *) buf, 0, PAGE_SIZE);
+ } else {
+ set_bit(PG_uptodate, &page->flags);
+ }
+ clear_bit(PG_locked, &page->flags);
+ wake_up(&page->wait);
+/* free_page(buf); */
+
+ return res;
+}