aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarsten Otte <cotte@de.ibm.com>2005-06-24 01:05:28 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:06:41 -0400
commiteb6fe0c388e43b02e261f0fdee60e42f6298d7f7 (patch)
tree3924bfbbbb10afc19f3bcd4963af14121f2c0553
parent6d79125bba55ee82701f1c7d4ebbc1aa20ecbe4e (diff)
[PATCH] xip: reduce code duplication
This patch reworks filemap_xip.c with the goal to reduce code duplication from mm/filemap.c. It applies agains 2.6.12-rc6-mm1. Instead of implementing the aio functions, this one implements the synchronous read/write functions only. For readv and writev, the generic fallback is used. For aio, we rely on the application doing the fallback. Since our "synchronous" function does memcpy immediately anyway, there is no performance difference between using the fallbacks or implementing each operation. Signed-off-by: Carsten Otte <cotte@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/ext2/file.c8
-rw-r--r--include/linux/fs.h12
-rw-r--r--mm/filemap.h2
-rw-r--r--mm/filemap_xip.c246
4 files changed, 63 insertions, 205 deletions
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 2b3d572365af..a484412fc782 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -58,17 +58,13 @@ struct file_operations ext2_file_operations = {
58#ifdef CONFIG_EXT2_FS_XIP 58#ifdef CONFIG_EXT2_FS_XIP
59struct file_operations ext2_xip_file_operations = { 59struct file_operations ext2_xip_file_operations = {
60 .llseek = generic_file_llseek, 60 .llseek = generic_file_llseek,
61 .read = do_sync_read, 61 .read = xip_file_read,
62 .write = do_sync_write, 62 .write = xip_file_write,
63 .aio_read = xip_file_aio_read,
64 .aio_write = xip_file_aio_write,
65 .ioctl = ext2_ioctl, 63 .ioctl = ext2_ioctl,
66 .mmap = xip_file_mmap, 64 .mmap = xip_file_mmap,
67 .open = generic_file_open, 65 .open = generic_file_open,
68 .release = ext2_release_file, 66 .release = ext2_release_file,
69 .fsync = ext2_sync_file, 67 .fsync = ext2_sync_file,
70 .readv = xip_file_readv,
71 .writev = xip_file_writev,
72 .sendfile = xip_file_sendfile, 68 .sendfile = xip_file_sendfile,
73}; 69};
74#endif 70#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 7e0501895f35..3ae8e37bdfc8 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1500,18 +1500,14 @@ extern int generic_file_open(struct inode * inode, struct file * filp);
1500extern int nonseekable_open(struct inode * inode, struct file * filp); 1500extern int nonseekable_open(struct inode * inode, struct file * filp);
1501 1501
1502#ifdef CONFIG_FS_XIP 1502#ifdef CONFIG_FS_XIP
1503extern ssize_t xip_file_aio_read(struct kiocb *iocb, char __user *buf, 1503extern ssize_t xip_file_read(struct file *filp, char __user *buf, size_t len,
1504 size_t count, loff_t pos); 1504 loff_t *ppos);
1505extern ssize_t xip_file_readv(struct file *filp, const struct iovec *iov,
1506 unsigned long nr_segs, loff_t *ppos);
1507extern ssize_t xip_file_sendfile(struct file *in_file, loff_t *ppos, 1505extern ssize_t xip_file_sendfile(struct file *in_file, loff_t *ppos,
1508 size_t count, read_actor_t actor, 1506 size_t count, read_actor_t actor,
1509 void *target); 1507 void *target);
1510extern int xip_file_mmap(struct file * file, struct vm_area_struct * vma); 1508extern int xip_file_mmap(struct file * file, struct vm_area_struct * vma);
1511extern ssize_t xip_file_aio_write(struct kiocb *iocb, const char __user *buf, 1509extern ssize_t xip_file_write(struct file *filp, const char __user *buf,
1512 size_t count, loff_t pos); 1510 size_t len, loff_t *ppos);
1513extern ssize_t xip_file_writev(struct file *file, const struct iovec *iov,
1514 unsigned long nr_segs, loff_t *ppos);
1515extern int xip_truncate_page(struct address_space *mapping, loff_t from); 1511extern int xip_truncate_page(struct address_space *mapping, loff_t from);
1516#else 1512#else
1517static inline int xip_truncate_page(struct address_space *mapping, loff_t from) 1513static inline int xip_truncate_page(struct address_space *mapping, loff_t from)
diff --git a/mm/filemap.h b/mm/filemap.h
index c2d0546a57eb..13793ba0ce17 100644
--- a/mm/filemap.h
+++ b/mm/filemap.h
@@ -15,7 +15,7 @@
15#include <linux/config.h> 15#include <linux/config.h>
16#include <asm/uaccess.h> 16#include <asm/uaccess.h>
17 17
18extern size_t 18size_t
19__filemap_copy_from_user_iovec(char *vaddr, 19__filemap_copy_from_user_iovec(char *vaddr,
20 const struct iovec *iov, 20 const struct iovec *iov,
21 size_t base, 21 size_t base,
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index 7d63acd48817..3b6e384b98a6 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -114,83 +114,28 @@ out:
114 file_accessed(filp); 114 file_accessed(filp);
115} 115}
116 116
117/*
118 * This is the "read()" routine for all filesystems
119 * that uses the get_xip_page address space operation.
120 */
121static ssize_t
122__xip_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
123 unsigned long nr_segs, loff_t *ppos)
124{
125 struct file *filp = iocb->ki_filp;
126 ssize_t retval;
127 unsigned long seg;
128 size_t count;
129
130 count = 0;
131 for (seg = 0; seg < nr_segs; seg++) {
132 const struct iovec *iv = &iov[seg];
133
134 /*
135 * If any segment has a negative length, or the cumulative
136 * length ever wraps negative then return -EINVAL.
137 */
138 count += iv->iov_len;
139 if (unlikely((ssize_t)(count|iv->iov_len) < 0))
140 return -EINVAL;
141 if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
142 continue;
143 if (seg == 0)
144 return -EFAULT;
145 nr_segs = seg;
146 count -= iv->iov_len; /* This segment is no good */
147 break;
148 }
149
150 retval = 0;
151 if (count) {
152 for (seg = 0; seg < nr_segs; seg++) {
153 read_descriptor_t desc;
154
155 desc.written = 0;
156 desc.arg.buf = iov[seg].iov_base;
157 desc.count = iov[seg].iov_len;
158 if (desc.count == 0)
159 continue;
160 desc.error = 0;
161 do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp,
162 ppos, &desc, file_read_actor);
163 retval += desc.written;
164 if (!retval) {
165 retval = desc.error;
166 break;
167 }
168 }
169 }
170 return retval;
171}
172
173ssize_t 117ssize_t
174xip_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, 118xip_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
175 loff_t pos)
176{ 119{
177 struct iovec local_iov = { .iov_base = buf, .iov_len = count }; 120 read_descriptor_t desc;
178 121
179 BUG_ON(iocb->ki_pos != pos); 122 if (!access_ok(VERIFY_WRITE, buf, len))
180 return __xip_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos); 123 return -EFAULT;
181}
182EXPORT_SYMBOL_GPL(xip_file_aio_read);
183 124
184ssize_t 125 desc.written = 0;
185xip_file_readv(struct file *filp, const struct iovec *iov, 126 desc.arg.buf = buf;
186 unsigned long nr_segs, loff_t *ppos) 127 desc.count = len;
187{ 128 desc.error = 0;
188 struct kiocb kiocb;
189 129
190 init_sync_kiocb(&kiocb, filp); 130 do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp,
191 return __xip_file_aio_read(&kiocb, iov, nr_segs, ppos); 131 ppos, &desc, file_read_actor);
132
133 if (desc.written)
134 return desc.written;
135 else
136 return desc.error;
192} 137}
193EXPORT_SYMBOL_GPL(xip_file_readv); 138EXPORT_SYMBOL_GPL(xip_file_read);
194 139
195ssize_t 140ssize_t
196xip_file_sendfile(struct file *in_file, loff_t *ppos, 141xip_file_sendfile(struct file *in_file, loff_t *ppos,
@@ -326,25 +271,19 @@ int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
326EXPORT_SYMBOL_GPL(xip_file_mmap); 271EXPORT_SYMBOL_GPL(xip_file_mmap);
327 272
328static ssize_t 273static ssize_t
329do_xip_file_write(struct kiocb *iocb, const struct iovec *iov, 274__xip_file_write(struct file *filp, const char __user *buf,
330 unsigned long nr_segs, loff_t pos, loff_t *ppos, 275 size_t count, loff_t pos, loff_t *ppos)
331 size_t count)
332{ 276{
333 struct file *file = iocb->ki_filp; 277 struct address_space * mapping = filp->f_mapping;
334 struct address_space * mapping = file->f_mapping;
335 struct address_space_operations *a_ops = mapping->a_ops; 278 struct address_space_operations *a_ops = mapping->a_ops;
336 struct inode *inode = mapping->host; 279 struct inode *inode = mapping->host;
337 long status = 0; 280 long status = 0;
338 struct page *page; 281 struct page *page;
339 size_t bytes; 282 size_t bytes;
340 const struct iovec *cur_iov = iov; /* current iovec */
341 size_t iov_base = 0; /* offset in the current iovec */
342 char __user *buf;
343 ssize_t written = 0; 283 ssize_t written = 0;
344 284
345 BUG_ON(!mapping->a_ops->get_xip_page); 285 BUG_ON(!mapping->a_ops->get_xip_page);
346 286
347 buf = iov->iov_base;
348 do { 287 do {
349 unsigned long index; 288 unsigned long index;
350 unsigned long offset; 289 unsigned long offset;
@@ -365,15 +304,14 @@ do_xip_file_write(struct kiocb *iocb, const struct iovec *iov,
365 fault_in_pages_readable(buf, bytes); 304 fault_in_pages_readable(buf, bytes);
366 305
367 page = a_ops->get_xip_page(mapping, 306 page = a_ops->get_xip_page(mapping,
368 index*(PAGE_SIZE/512), 0); 307 index*(PAGE_SIZE/512), 0);
369 if (IS_ERR(page) && (PTR_ERR(page) == -ENODATA)) { 308 if (IS_ERR(page) && (PTR_ERR(page) == -ENODATA)) {
370 /* we allocate a new page unmap it */ 309 /* we allocate a new page unmap it */
371 page = a_ops->get_xip_page(mapping, 310 page = a_ops->get_xip_page(mapping,
372 index*(PAGE_SIZE/512), 1); 311 index*(PAGE_SIZE/512), 1);
373 if (!IS_ERR(page)) 312 if (!IS_ERR(page))
374 /* unmap page at pgoff from all other vmas */ 313 /* unmap page at pgoff from all other vmas */
375 __xip_unmap(mapping, index); 314 __xip_unmap(mapping, index);
376
377 } 315 }
378 316
379 if (IS_ERR(page)) { 317 if (IS_ERR(page)) {
@@ -383,12 +321,7 @@ do_xip_file_write(struct kiocb *iocb, const struct iovec *iov,
383 321
384 BUG_ON(!PageUptodate(page)); 322 BUG_ON(!PageUptodate(page));
385 323
386 if (likely(nr_segs == 1)) 324 copied = filemap_copy_from_user(page, offset, buf, bytes);
387 copied = filemap_copy_from_user(page, offset,
388 buf, bytes);
389 else
390 copied = filemap_copy_from_user_iovec(page, offset,
391 cur_iov, iov_base, bytes);
392 flush_dcache_page(page); 325 flush_dcache_page(page);
393 if (likely(copied > 0)) { 326 if (likely(copied > 0)) {
394 status = copied; 327 status = copied;
@@ -398,9 +331,6 @@ do_xip_file_write(struct kiocb *iocb, const struct iovec *iov,
398 count -= status; 331 count -= status;
399 pos += status; 332 pos += status;
400 buf += status; 333 buf += status;
401 if (unlikely(nr_segs > 1))
402 filemap_set_next_iovec(&cur_iov,
403 &iov_base, status);
404 } 334 }
405 } 335 }
406 if (unlikely(copied != bytes)) 336 if (unlikely(copied != bytes))
@@ -422,110 +352,52 @@ do_xip_file_write(struct kiocb *iocb, const struct iovec *iov,
422 return written ? written : status; 352 return written ? written : status;
423} 353}
424 354
425static ssize_t 355ssize_t
426xip_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, 356xip_file_write(struct file *filp, const char __user *buf, size_t len,
427 unsigned long nr_segs, loff_t *ppos) 357 loff_t *ppos)
428{ 358{
429 struct file *file = iocb->ki_filp; 359 struct address_space *mapping = filp->f_mapping;
430 struct address_space * mapping = file->f_mapping; 360 struct inode *inode = mapping->host;
431 size_t ocount; /* original count */ 361 size_t count;
432 size_t count; /* after file limit checks */ 362 loff_t pos;
433 struct inode *inode = mapping->host; 363 ssize_t ret;
434 unsigned long seg;
435 loff_t pos;
436 ssize_t written;
437 ssize_t err;
438 364
439 ocount = 0; 365 down(&inode->i_sem);
440 for (seg = 0; seg < nr_segs; seg++) {
441 const struct iovec *iv = &iov[seg];
442 366
443 /* 367 if (!access_ok(VERIFY_READ, buf, len)) {
444 * If any segment has a negative length, or the cumulative 368 ret=-EFAULT;
445 * length ever wraps negative then return -EINVAL. 369 goto out_up;
446 */
447 ocount += iv->iov_len;
448 if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
449 return -EINVAL;
450 if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
451 continue;
452 if (seg == 0)
453 return -EFAULT;
454 nr_segs = seg;
455 ocount -= iv->iov_len; /* This segment is no good */
456 break;
457 } 370 }
458 371
459 count = ocount;
460 pos = *ppos; 372 pos = *ppos;
373 count = len;
461 374
462 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); 375 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
463 376
464 written = 0; 377 /* We can write back this queue in page reclaim */
465 378 current->backing_dev_info = mapping->backing_dev_info;
466 err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
467 if (err)
468 goto out;
469 379
380 ret = generic_write_checks(filp, &pos, &count, S_ISBLK(inode->i_mode));
381 if (ret)
382 goto out_backing;
470 if (count == 0) 383 if (count == 0)
471 goto out; 384 goto out_backing;
472 385
473 err = remove_suid(file->f_dentry); 386 ret = remove_suid(filp->f_dentry);
474 if (err) 387 if (ret)
475 goto out; 388 goto out_backing;
476 389
477 inode_update_time(inode, 1); 390 inode_update_time(inode, 1);
478 391
479 /* use execute in place to copy directly to disk */ 392 ret = __xip_file_write (filp, buf, count, pos, ppos);
480 written = do_xip_file_write (iocb, iov,
481 nr_segs, pos, ppos, count);
482 out:
483 return written ? written : err;
484}
485
486static ssize_t
487__xip_file_write_nolock(struct file *file, const struct iovec *iov,
488 unsigned long nr_segs, loff_t *ppos)
489{
490 struct kiocb kiocb;
491
492 init_sync_kiocb(&kiocb, file);
493 return xip_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
494}
495
496ssize_t
497xip_file_aio_write(struct kiocb *iocb, const char __user *buf,
498 size_t count, loff_t pos)
499{
500 struct file *file = iocb->ki_filp;
501 struct address_space *mapping = file->f_mapping;
502 struct inode *inode = mapping->host;
503 ssize_t ret;
504 struct iovec local_iov = { .iov_base = (void __user *)buf,
505 .iov_len = count };
506 393
507 BUG_ON(iocb->ki_pos != pos); 394 out_backing:
508 395 current->backing_dev_info = NULL;
509 down(&inode->i_sem); 396 out_up:
510 ret = xip_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
511 up(&inode->i_sem); 397 up(&inode->i_sem);
512 return ret; 398 return ret;
513} 399}
514EXPORT_SYMBOL_GPL(xip_file_aio_write); 400EXPORT_SYMBOL_GPL(xip_file_write);
515
516ssize_t xip_file_writev(struct file *file, const struct iovec *iov,
517 unsigned long nr_segs, loff_t *ppos)
518{
519 struct address_space *mapping = file->f_mapping;
520 struct inode *inode = mapping->host;
521 ssize_t ret;
522
523 down(&inode->i_sem);
524 ret = __xip_file_write_nolock(file, iov, nr_segs, ppos);
525 up(&inode->i_sem);
526 return ret;
527}
528EXPORT_SYMBOL_GPL(xip_file_writev);
529 401
530/* 402/*
531 * truncate a page used for execute in place 403 * truncate a page used for execute in place
@@ -541,7 +413,6 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
541 unsigned length; 413 unsigned length;
542 struct page *page; 414 struct page *page;
543 void *kaddr; 415 void *kaddr;
544 int err;
545 416
546 BUG_ON(!mapping->a_ops->get_xip_page); 417 BUG_ON(!mapping->a_ops->get_xip_page);
547 418
@@ -556,17 +427,14 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
556 427
557 page = mapping->a_ops->get_xip_page(mapping, 428 page = mapping->a_ops->get_xip_page(mapping,
558 index*(PAGE_SIZE/512), 0); 429 index*(PAGE_SIZE/512), 0);
559 err = -ENOMEM;
560 if (!page) 430 if (!page)
561 goto out; 431 return -ENOMEM;
562 if (unlikely(IS_ERR(page))) { 432 if (unlikely(IS_ERR(page))) {
563 if (PTR_ERR(page) == -ENODATA) { 433 if (PTR_ERR(page) == -ENODATA)
564 /* Hole? No need to truncate */ 434 /* Hole? No need to truncate */
565 return 0; 435 return 0;
566 } else { 436 else
567 err = PTR_ERR(page); 437 return PTR_ERR(page);
568 goto out;
569 }
570 } else 438 } else
571 BUG_ON(!PageUptodate(page)); 439 BUG_ON(!PageUptodate(page));
572 kaddr = kmap_atomic(page, KM_USER0); 440 kaddr = kmap_atomic(page, KM_USER0);
@@ -574,8 +442,6 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
574 kunmap_atomic(kaddr, KM_USER0); 442 kunmap_atomic(kaddr, KM_USER0);
575 443
576 flush_dcache_page(page); 444 flush_dcache_page(page);
577 err = 0; 445 return 0;
578out:
579 return err;
580} 446}
581EXPORT_SYMBOL_GPL(xip_truncate_page); 447EXPORT_SYMBOL_GPL(xip_truncate_page);