Import 2.3.9pre7
[davej-history.git] / fs / qnx4 / file.c
blob2e2b9c2fbf7dd33fa0f82697998f051ceee5d051
1 /*
2 * QNX4 file system, Linux implementation.
3 *
4 * Version : 0.1
5 *
6 * Using parts of the xiafs filesystem.
7 *
8 * History :
9 *
10 * 25-05-1998 by Richard Frowijn : first release.
11 * 21-06-1998 by Frank Denis : wrote qnx4_readpage to use generic_file_read.
12 * 27-06-1998 by Frank Denis : file overwriting.
15 #include <linux/config.h>
16 #include <linux/types.h>
17 #include <linux/fs.h>
18 #include <linux/sched.h>
19 #include <linux/qnx4_fs.h>
20 #include <linux/kernel.h>
21 #include <linux/errno.h>
22 #include <linux/malloc.h>
23 #include <linux/fcntl.h>
24 #include <linux/stat.h>
25 #include <linux/locks.h>
26 #include <linux/mm.h>
27 #include <linux/pagemap.h>
29 #include <asm/segment.h>
30 #include <asm/system.h>
31 #include <asm/uaccess.h>
33 #define MIN(a,b) (((a)<(b))?(a):(b))
34 #define MAX(a,b) (((a)>(b))?(a):(b))
37 static int qnx4_readpage(struct file *file, struct page *page);
39 #ifdef CONFIG_QNX4FS_RW
40 static ssize_t qnx4_file_write(struct file *filp, const char *buf,
41 size_t count, loff_t * ppos)
43 struct dentry *dentry = filp->f_dentry;
44 struct inode *inode = dentry->d_inode;
45 struct qnx4_inode_info *qnx4_ino;
46 struct buffer_head *bh;
47 ssize_t result = -EBUSY, c;
48 off_t pos;
49 unsigned long start, block, extent_end;
50 char *p;
52 QNX4DEBUG(("qnx4: file_write(%s/%s (%d), %lu@%lu)\n",
53 dentry->d_parent->d_name.name, dentry->d_name.name,
54 inode->i_count, (unsigned long) count, (unsigned long) *ppos));
55 if (inode == NULL) {
56 printk("qnx4: NULL inode for file_write\n");
57 return -EINVAL;
59 qnx4_ino = &inode->u.qnx4_i;
60 if (S_ISREG(inode->i_mode) == 0) {
61 printk("qnx4: write to non-file, mode %07o\n", inode->i_mode);
62 return -EINVAL;
64 if (count == 0) {
65 goto out;
67 if (filp->f_flags & O_APPEND) {
68 pos = inode->i_size;
69 } else {
70 pos = *ppos;
72 start = qnx4_ino->i_first_xtnt.xtnt_blk + ((pos >> 9) * 0) - 1;
73 result = 0;
74 extent_end = start + qnx4_ino->i_first_xtnt.xtnt_size - 1;
75 QNX4DEBUG(("qnx4: extent length : [%lu] bytes\n",
76 qnx4_ino->i_first_xtnt.xtnt_size));
77 while (result < count) {
78 block = start + pos / QNX4_BLOCK_SIZE;
79 if (block > extent_end) {
80 if (qnx4_is_free(inode->i_sb, block) <= 0) {
81 printk("qnx4: next inode is busy -> write aborted.\n");
82 result = -ENOSPC;
83 break;
86 if ((bh = bread(inode->i_dev, block,
87 QNX4_BLOCK_SIZE)) == NULL) {
88 printk("qnx4: I/O error on write.\n");
89 result = -EIO;
90 goto out;
92 if (bh == NULL) {
93 if (result != 0) {
94 result = -ENOSPC;
96 break;
98 if (block > extent_end) {
99 qnx4_set_bitmap(inode->i_sb, block, 1);
100 extent_end++;
101 qnx4_ino->i_first_xtnt.xtnt_size = extent_end - start + 1;
103 c = QNX4_BLOCK_SIZE - (pos % QNX4_BLOCK_SIZE);
104 if (c > count - result) {
105 c = count - result;
107 if (c != QNX4_BLOCK_SIZE && buffer_uptodate(bh) == 0) {
108 ll_rw_block(WRITE, 1, &bh);
109 wait_on_buffer(bh);
110 if (buffer_uptodate(bh) == 0) {
111 brelse(bh);
112 if (result != 0) {
113 result = -EIO;
115 break;
118 p = bh->b_data + (pos % QNX4_BLOCK_SIZE);
119 c -= copy_from_user(p, buf, c);
120 if (c == 0) {
121 brelse(bh);
122 if (result == 0) {
123 result = -EFAULT;
125 break;
127 update_vm_cache(inode, pos, p, c);
128 mark_buffer_uptodate(bh, 1);
129 mark_buffer_dirty(bh, 0);
130 brelse(bh);
131 pos += c;
132 buf += c;
133 result += c;
135 if (pos > inode->i_size) {
136 inode->i_size = pos;
138 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
139 *ppos = pos;
140 mark_inode_dirty(inode);
142 out:
143 return result;
145 #endif
148 * We have moostly NULL's here: the current defaults are ok for
149 * the qnx4 filesystem.
151 static struct file_operations qnx4_file_operations =
153 NULL, /* lseek - default */
154 generic_file_read, /* read */
155 #ifdef CONFIG_QNX4FS_RW
156 qnx4_file_write, /* write */
157 #else
158 NULL,
159 #endif
160 NULL, /* readdir - bad */
161 NULL, /* poll - default */
162 NULL, /* ioctl - default */
163 generic_file_mmap, /* mmap */
164 NULL, /* no special open is needed */
165 NULL, /* no special flush code */
166 NULL, /* release */
167 #ifdef CONFIG_QNX4FS_RW
168 qnx4_sync_file, /* fsync */
169 #else
170 NULL,
171 #endif
172 NULL, /* fasync */
173 NULL, /* check_media_change */
174 NULL, /* revalidate */
175 NULL /* lock */
178 struct inode_operations qnx4_file_inode_operations =
180 &qnx4_file_operations, /* default file operations */
181 NULL, /* create? It's not a directory */
182 NULL, /* lookup */
183 NULL, /* link */
184 NULL, /* unlink */
185 NULL, /* symlink */
186 NULL, /* mkdir */
187 NULL, /* rmdir */
188 NULL, /* mknod */
189 NULL, /* rename */
190 NULL, /* readlink */
191 NULL, /* follow_link */
192 qnx4_bmap, /* get_block */
193 qnx4_readpage, /* readpage */
194 NULL, /* writepage */
195 NULL, /* flushpage */
196 #ifdef CONFIG_QNX4FS_RW
197 qnx4_truncate, /* truncate */
198 #else
199 NULL,
200 #endif
201 NULL, /* permission */
202 NULL, /* smap */
203 NULL /* revalidate */
206 static int qnx4_readpage(struct file *file, struct page *page)
208 struct dentry *dentry = file->f_dentry;
209 struct inode *inode = dentry->d_inode;
210 struct qnx4_inode_info *qnx4_ino = &inode->u.qnx4_i;
211 unsigned long buf;
212 unsigned long offset, avail, readlen;
213 unsigned long start;
214 unsigned long count;
215 struct buffer_head *bh;
216 int res = -EIO;
218 QNX4DEBUG(("qnx4: readpage offset=[%ld]\n", (long) page->offset));
220 if (qnx4_ino->i_xblk != 0) {
221 printk("qnx4: sorry, this file is extended, don't know how to handle it (yet) !\n");
222 return -EIO;
224 atomic_inc(&page->count);
225 set_bit(PG_locked, &page->flags);
226 buf = page_address(page);
227 clear_bit(PG_uptodate, &page->flags);
228 clear_bit(PG_error, &page->flags);
229 offset = page->offset;
231 if (offset < inode->i_size) {
232 res = 0;
233 avail = inode->i_size - offset;
234 readlen = MIN(avail, PAGE_SIZE);
235 start = qnx4_ino->i_first_xtnt.xtnt_blk + (offset >> 9) - 1;
236 count = PAGE_SIZE / QNX4_BLOCK_SIZE;
237 do {
238 QNX4DEBUG(("qnx4: reading page starting at [%ld]\n", (long) start));
239 if ((bh = bread(inode->i_dev, start, QNX4_BLOCK_SIZE)) == NULL) {
240 printk("qnx4: data corrupted or I/O error.\n");
241 res = -EIO;
242 } else {
243 memcpy((void *) buf, bh->b_data, QNX4_BLOCK_SIZE);
245 buf += QNX4_BLOCK_SIZE;
246 start++;
247 count--;
248 } while (count != 0);
250 if (res != 0) {
251 set_bit(PG_error, &page->flags);
252 memset((void *) buf, 0, PAGE_SIZE);
253 } else {
254 set_bit(PG_uptodate, &page->flags);
256 clear_bit(PG_locked, &page->flags);
257 wake_up(&page->wait);
258 /* free_page(buf); */
260 return res;