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/writeback.h> 19 #include <linux/syscalls.h> 20 21 #include <asm/unistd.h> 22 23 /* 24 * POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could 25 * deactivate the pages and clear PG_Referenced. 26 * 27 * LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file 28 * offsets `offset' and `offset+len' inclusive. Any pages which are currently 29 * under writeout are skipped, whether or not they are dirty. 30 * 31 * LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file 32 * offsets `offset' and `offset+len'. 33 * 34 * By combining these two operations the application may do several things: 35 * 36 * LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk. 37 * 38 * LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently 39 * dirty pages at the disk. 40 * 41 * LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push 42 * all of the currently dirty pages at the disk, wait until they have been 43 * written. 44 * 45 * It should be noted that none of these operations write out the file's 46 * metadata. So unless the application is strictly performing overwrites of 47 * already-instantiated disk blocks, there are no guarantees here that the data 48 * will be available after a crash. 49 */ 50 asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice) 51 { 52 struct file *file = fget(fd); 53 struct address_space *mapping; 54 struct backing_dev_info *bdi; 55 loff_t endbyte; /* inclusive */ 56 pgoff_t start_index; 57 pgoff_t end_index; 58 unsigned long nrpages; 59 int ret = 0; 60 61 if (!file) 62 return -EBADF; 63 64 if (S_ISFIFO(file->f_dentry->d_inode->i_mode)) { 65 ret = -ESPIPE; 66 goto out; 67 } 68 69 mapping = file->f_mapping; 70 if (!mapping || len < 0) { 71 ret = -EINVAL; 72 goto out; 73 } 74 75 if (mapping->a_ops->get_xip_page) 76 /* no bad return value, but ignore advice */ 77 goto out; 78 79 /* Careful about overflows. Len == 0 means "as much as possible" */ 80 endbyte = offset + len; 81 if (!len || endbyte < len) 82 endbyte = -1; 83 else 84 endbyte--; /* inclusive */ 85 86 bdi = mapping->backing_dev_info; 87 88 switch (advice) { 89 case POSIX_FADV_NORMAL: 90 file->f_ra.ra_pages = bdi->ra_pages; 91 break; 92 case POSIX_FADV_RANDOM: 93 file->f_ra.ra_pages = 0; 94 break; 95 case POSIX_FADV_SEQUENTIAL: 96 file->f_ra.ra_pages = bdi->ra_pages * 2; 97 break; 98 case POSIX_FADV_WILLNEED: 99 case POSIX_FADV_NOREUSE: 100 if (!mapping->a_ops->readpage) { 101 ret = -EINVAL; 102 break; 103 } 104 105 /* First and last PARTIAL page! */ 106 start_index = offset >> PAGE_CACHE_SHIFT; 107 end_index = endbyte >> PAGE_CACHE_SHIFT; 108 109 /* Careful about overflow on the "+1" */ 110 nrpages = end_index - start_index + 1; 111 if (!nrpages) 112 nrpages = ~0UL; 113 114 ret = force_page_cache_readahead(mapping, file, 115 start_index, 116 max_sane_readahead(nrpages)); 117 if (ret > 0) 118 ret = 0; 119 break; 120 case POSIX_FADV_DONTNEED: 121 if (!bdi_write_congested(mapping->backing_dev_info)) 122 filemap_flush(mapping); 123 124 /* First and last FULL page! */ 125 start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT; 126 end_index = (endbyte >> PAGE_CACHE_SHIFT); 127 128 if (end_index >= start_index) 129 invalidate_mapping_pages(mapping, start_index, 130 end_index); 131 break; 132 case LINUX_FADV_ASYNC_WRITE: 133 ret = __filemap_fdatawrite_range(mapping, offset, endbyte, 134 WB_SYNC_NONE); 135 break; 136 case LINUX_FADV_WRITE_WAIT: 137 ret = wait_on_page_writeback_range(mapping, 138 offset >> PAGE_CACHE_SHIFT, 139 endbyte >> PAGE_CACHE_SHIFT); 140 break; 141 default: 142 ret = -EINVAL; 143 } 144 out: 145 fput(file); 146 return ret; 147 } 148 149 #ifdef __ARCH_WANT_SYS_FADVISE64 150 151 asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice) 152 { 153 return sys_fadvise64_64(fd, offset, len, advice); 154 } 155 156 #endif 157