diff options
author | Carsten Otte <cotte@de.ibm.com> | 2005-06-24 01:05:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:06:41 -0400 |
commit | eb6fe0c388e43b02e261f0fdee60e42f6298d7f7 (patch) | |
tree | 3924bfbbbb10afc19f3bcd4963af14121f2c0553 /mm/filemap_xip.c | |
parent | 6d79125bba55ee82701f1c7d4ebbc1aa20ecbe4e (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>
Diffstat (limited to 'mm/filemap_xip.c')
-rw-r--r-- | mm/filemap_xip.c | 246 |
1 files changed, 56 insertions, 190 deletions
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 | */ | ||
121 | static 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 | |||
173 | ssize_t | 117 | ssize_t |
174 | xip_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, | 118 | xip_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 | } | ||
182 | EXPORT_SYMBOL_GPL(xip_file_aio_read); | ||
183 | 124 | ||
184 | ssize_t | 125 | desc.written = 0; |
185 | xip_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 | } |
193 | EXPORT_SYMBOL_GPL(xip_file_readv); | 138 | EXPORT_SYMBOL_GPL(xip_file_read); |
194 | 139 | ||
195 | ssize_t | 140 | ssize_t |
196 | xip_file_sendfile(struct file *in_file, loff_t *ppos, | 141 | xip_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) | |||
326 | EXPORT_SYMBOL_GPL(xip_file_mmap); | 271 | EXPORT_SYMBOL_GPL(xip_file_mmap); |
327 | 272 | ||
328 | static ssize_t | 273 | static ssize_t |
329 | do_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 | ||
425 | static ssize_t | 355 | ssize_t |
426 | xip_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov, | 356 | xip_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 | |||
486 | static 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 | |||
496 | ssize_t | ||
497 | xip_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 | } |
514 | EXPORT_SYMBOL_GPL(xip_file_aio_write); | 400 | EXPORT_SYMBOL_GPL(xip_file_write); |
515 | |||
516 | ssize_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 | } | ||
528 | EXPORT_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; |
578 | out: | ||
579 | return err; | ||
580 | } | 446 | } |
581 | EXPORT_SYMBOL_GPL(xip_truncate_page); | 447 | EXPORT_SYMBOL_GPL(xip_truncate_page); |