1 /* 2 * mm/fadvise.c 3 * 4 * Copyright (C) 2002, Linus Torvalds 5 * 6 * 11Jan2003 akpm@digeo.com 7 * Initial version. 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/file.h> 12 #include <linux/fs.h> 13 #include <linux/mm.h> 14 #include <linux/pagemap.h> 15 #include <linux/backing-dev.h> 16 #include <linux/pagevec.h> 17 #include <linux/fadvise.h> 18 #include <linux/syscalls.h> 19 20 #include <asm/unistd.h> 21 22 /* 23 * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could 24 * deactivate the pages and clear PG_Referenced. 25 */ 26 asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) 27 { 28 struct file *file = fget(fd); 29 struct address_space *mapping; 30 struct backing_dev_info *bdi; 31 loff_t endbyte; 32 pgoff_t start_index; 33 pgoff_t end_index; 34 unsigned long nrpages; 35 int ret = 0; 36 37 if (!file) 38 return -EBADF; 39 40 if (S_ISFIFO(file->f_dentry->d_inode->i_mode)) { 41 ret = -ESPIPE; 42 goto out; 43 } 44 45 mapping = file->f_mapping; 46 if (!mapping || len < 0) { 47 ret = -EINVAL; 48 goto out; 49 } 50 51 if (mapping->a_ops->get_xip_page) 52 /* no bad return value, but ignore advice */ 53 goto out; 54 55 /* Careful about overflows. Len == 0 means "as much as possible" */ 56 endbyte = offset + len; 57 if (!len || endbyte < len) 58 endbyte = -1; 59 60 bdi = mapping->backing_dev_info; 61 62 switch (advice) { 63 case POSIX_FADV_NORMAL: 64 file->f_ra.ra_pages = bdi->ra_pages; 65 break; 66 case POSIX_FADV_RANDOM: 67 file->f_ra.ra_pages = 0; 68 break; 69 case POSIX_FADV_SEQUENTIAL: 70 file->f_ra.ra_pages = bdi->ra_pages * 2; 71 break; 72 case POSIX_FADV_WILLNEED: 73 case POSIX_FADV_NOREUSE: 74 if (!mapping->a_ops->readpage) { 75 ret = -EINVAL; 76 break; 77 } 78 79 /* First and last PARTIAL page! */ 80 start_index = offset >> PAGE_CACHE_SHIFT; 81 end_index = (endbyte-1) >> PAGE_CACHE_SHIFT; 82 83 /* Careful about overflow on the "+1" */ 84 nrpages = end_index - start_index + 1; 85 if (!nrpages) 86 nrpages = ~0UL; 87 88 ret = force_page_cache_readahead(mapping, file, 89 start_index, 90 max_sane_readahead(nrpages)); 91 if (ret > 0) 92 ret = 0; 93 break; 94 case POSIX_FADV_DONTNEED: 95 if (!bdi_write_congested(mapping->backing_dev_info)) 96 filemap_flush(mapping); 97 98 /* First and last FULL page! */ 99 start_index = (offset + (PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT; 100 end_index = (endbyte >> PAGE_CACHE_SHIFT); 101 102 if (end_index > start_index) 103 invalidate_mapping_pages(mapping, start_index, end_index-1); 104 break; 105 default: 106 ret = -EINVAL; 107 } 108 out: 109 fput(file); 110 return ret; 111 } 112 113 #ifdef __ARCH_WANT_SYS_FADVISE64 114 115 asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice) 116 { 117 return sys_fadvise64_64(fd, offset, len, advice); 118 } 119 120 #endif 121