1f79e2abbSAndrew Morton /* 2f79e2abbSAndrew Morton * High-level sync()-related operations 3f79e2abbSAndrew Morton */ 4f79e2abbSAndrew Morton 5f79e2abbSAndrew Morton #include <linux/kernel.h> 6f79e2abbSAndrew Morton #include <linux/file.h> 7f79e2abbSAndrew Morton #include <linux/fs.h> 8f79e2abbSAndrew Morton #include <linux/module.h> 9f79e2abbSAndrew Morton #include <linux/writeback.h> 10f79e2abbSAndrew Morton #include <linux/syscalls.h> 11f79e2abbSAndrew Morton #include <linux/linkage.h> 12f79e2abbSAndrew Morton #include <linux/pagemap.h> 13f79e2abbSAndrew Morton 14f79e2abbSAndrew Morton #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ 15f79e2abbSAndrew Morton SYNC_FILE_RANGE_WAIT_AFTER) 16f79e2abbSAndrew Morton 17f79e2abbSAndrew Morton /* 18f79e2abbSAndrew Morton * sys_sync_file_range() permits finely controlled syncing over a segment of 19f79e2abbSAndrew Morton * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is 20f79e2abbSAndrew Morton * zero then sys_sync_file_range() will operate from offset out to EOF. 21f79e2abbSAndrew Morton * 22f79e2abbSAndrew Morton * The flag bits are: 23f79e2abbSAndrew Morton * 24f79e2abbSAndrew Morton * SYNC_FILE_RANGE_WAIT_BEFORE: wait upon writeout of all pages in the range 25f79e2abbSAndrew Morton * before performing the write. 26f79e2abbSAndrew Morton * 27f79e2abbSAndrew Morton * SYNC_FILE_RANGE_WRITE: initiate writeout of all those dirty pages in the 28f79e2abbSAndrew Morton * range which are not presently under writeback. 29f79e2abbSAndrew Morton * 30f79e2abbSAndrew Morton * SYNC_FILE_RANGE_WAIT_AFTER: wait upon writeout of all pages in the range 31f79e2abbSAndrew Morton * after performing the write. 32f79e2abbSAndrew Morton * 33f79e2abbSAndrew Morton * Useful combinations of the flag bits are: 34f79e2abbSAndrew Morton * 35f79e2abbSAndrew Morton * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE: ensures that all pages 36f79e2abbSAndrew Morton * in the range which were dirty on entry to sys_sync_file_range() are placed 37f79e2abbSAndrew Morton * under writeout. This is a start-write-for-data-integrity operation. 38f79e2abbSAndrew Morton * 39f79e2abbSAndrew Morton * SYNC_FILE_RANGE_WRITE: start writeout of all dirty pages in the range which 40f79e2abbSAndrew Morton * are not presently under writeout. This is an asynchronous flush-to-disk 41f79e2abbSAndrew Morton * operation. Not suitable for data integrity operations. 42f79e2abbSAndrew Morton * 43f79e2abbSAndrew Morton * SYNC_FILE_RANGE_WAIT_BEFORE (or SYNC_FILE_RANGE_WAIT_AFTER): wait for 44f79e2abbSAndrew Morton * completion of writeout of all pages in the range. This will be used after an 45f79e2abbSAndrew Morton * earlier SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE operation to wait 46f79e2abbSAndrew Morton * for that operation to complete and to return the result. 47f79e2abbSAndrew Morton * 48f79e2abbSAndrew Morton * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER: 49f79e2abbSAndrew Morton * a traditional sync() operation. This is a write-for-data-integrity operation 50f79e2abbSAndrew Morton * which will ensure that all pages in the range which were dirty on entry to 51f79e2abbSAndrew Morton * sys_sync_file_range() are committed to disk. 52f79e2abbSAndrew Morton * 53f79e2abbSAndrew Morton * 54f79e2abbSAndrew Morton * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any 55f79e2abbSAndrew Morton * I/O errors or ENOSPC conditions and will return those to the caller, after 56f79e2abbSAndrew Morton * clearing the EIO and ENOSPC flags in the address_space. 57f79e2abbSAndrew Morton * 58f79e2abbSAndrew Morton * It should be noted that none of these operations write out the file's 59f79e2abbSAndrew Morton * metadata. So unless the application is strictly performing overwrites of 60f79e2abbSAndrew Morton * already-instantiated disk blocks, there are no guarantees here that the data 61f79e2abbSAndrew Morton * will be available after a crash. 62f79e2abbSAndrew Morton */ 63f79e2abbSAndrew Morton asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, 645246d050SAndrew Morton unsigned int flags) 65f79e2abbSAndrew Morton { 66f79e2abbSAndrew Morton int ret; 67f79e2abbSAndrew Morton struct file *file; 68f79e2abbSAndrew Morton loff_t endbyte; /* inclusive */ 69f79e2abbSAndrew Morton int fput_needed; 70f79e2abbSAndrew Morton umode_t i_mode; 71f79e2abbSAndrew Morton 72f79e2abbSAndrew Morton ret = -EINVAL; 73f79e2abbSAndrew Morton if (flags & ~VALID_FLAGS) 74f79e2abbSAndrew Morton goto out; 75f79e2abbSAndrew Morton 76f79e2abbSAndrew Morton endbyte = offset + nbytes; 77f79e2abbSAndrew Morton 78f79e2abbSAndrew Morton if ((s64)offset < 0) 79f79e2abbSAndrew Morton goto out; 80f79e2abbSAndrew Morton if ((s64)endbyte < 0) 81f79e2abbSAndrew Morton goto out; 82f79e2abbSAndrew Morton if (endbyte < offset) 83f79e2abbSAndrew Morton goto out; 84f79e2abbSAndrew Morton 85f79e2abbSAndrew Morton if (sizeof(pgoff_t) == 4) { 86f79e2abbSAndrew Morton if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { 87f79e2abbSAndrew Morton /* 88f79e2abbSAndrew Morton * The range starts outside a 32 bit machine's 89f79e2abbSAndrew Morton * pagecache addressing capabilities. Let it "succeed" 90f79e2abbSAndrew Morton */ 91f79e2abbSAndrew Morton ret = 0; 92f79e2abbSAndrew Morton goto out; 93f79e2abbSAndrew Morton } 94f79e2abbSAndrew Morton if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { 95f79e2abbSAndrew Morton /* 96f79e2abbSAndrew Morton * Out to EOF 97f79e2abbSAndrew Morton */ 98f79e2abbSAndrew Morton nbytes = 0; 99f79e2abbSAndrew Morton } 100f79e2abbSAndrew Morton } 101f79e2abbSAndrew Morton 102f79e2abbSAndrew Morton if (nbytes == 0) 103*111ebb6eSOGAWA Hirofumi endbyte = LLONG_MAX; 104f79e2abbSAndrew Morton else 105f79e2abbSAndrew Morton endbyte--; /* inclusive */ 106f79e2abbSAndrew Morton 107f79e2abbSAndrew Morton ret = -EBADF; 108f79e2abbSAndrew Morton file = fget_light(fd, &fput_needed); 109f79e2abbSAndrew Morton if (!file) 110f79e2abbSAndrew Morton goto out; 111f79e2abbSAndrew Morton 112f79e2abbSAndrew Morton i_mode = file->f_dentry->d_inode->i_mode; 113f79e2abbSAndrew Morton ret = -ESPIPE; 114f79e2abbSAndrew Morton if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && 115f79e2abbSAndrew Morton !S_ISLNK(i_mode)) 116f79e2abbSAndrew Morton goto out_put; 117f79e2abbSAndrew Morton 118f79e2abbSAndrew Morton ret = do_sync_file_range(file, offset, endbyte, flags); 119f79e2abbSAndrew Morton out_put: 120f79e2abbSAndrew Morton fput_light(file, fput_needed); 121f79e2abbSAndrew Morton out: 122f79e2abbSAndrew Morton return ret; 123f79e2abbSAndrew Morton } 124f79e2abbSAndrew Morton 125f79e2abbSAndrew Morton /* 126f79e2abbSAndrew Morton * `endbyte' is inclusive 127f79e2abbSAndrew Morton */ 128f79e2abbSAndrew Morton int do_sync_file_range(struct file *file, loff_t offset, loff_t endbyte, 1295246d050SAndrew Morton unsigned int flags) 130f79e2abbSAndrew Morton { 131f79e2abbSAndrew Morton int ret; 132f79e2abbSAndrew Morton struct address_space *mapping; 133f79e2abbSAndrew Morton 134f79e2abbSAndrew Morton mapping = file->f_mapping; 135f79e2abbSAndrew Morton if (!mapping) { 136f79e2abbSAndrew Morton ret = -EINVAL; 137f79e2abbSAndrew Morton goto out; 138f79e2abbSAndrew Morton } 139f79e2abbSAndrew Morton 140f79e2abbSAndrew Morton ret = 0; 141f79e2abbSAndrew Morton if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) { 142f79e2abbSAndrew Morton ret = wait_on_page_writeback_range(mapping, 143f79e2abbSAndrew Morton offset >> PAGE_CACHE_SHIFT, 144f79e2abbSAndrew Morton endbyte >> PAGE_CACHE_SHIFT); 145f79e2abbSAndrew Morton if (ret < 0) 146f79e2abbSAndrew Morton goto out; 147f79e2abbSAndrew Morton } 148f79e2abbSAndrew Morton 149f79e2abbSAndrew Morton if (flags & SYNC_FILE_RANGE_WRITE) { 150f79e2abbSAndrew Morton ret = __filemap_fdatawrite_range(mapping, offset, endbyte, 151f79e2abbSAndrew Morton WB_SYNC_NONE); 152f79e2abbSAndrew Morton if (ret < 0) 153f79e2abbSAndrew Morton goto out; 154f79e2abbSAndrew Morton } 155f79e2abbSAndrew Morton 156f79e2abbSAndrew Morton if (flags & SYNC_FILE_RANGE_WAIT_AFTER) { 157f79e2abbSAndrew Morton ret = wait_on_page_writeback_range(mapping, 158f79e2abbSAndrew Morton offset >> PAGE_CACHE_SHIFT, 159f79e2abbSAndrew Morton endbyte >> PAGE_CACHE_SHIFT); 160f79e2abbSAndrew Morton } 161f79e2abbSAndrew Morton out: 162f79e2abbSAndrew Morton return ret; 163f79e2abbSAndrew Morton } 164f79e2abbSAndrew Morton EXPORT_SYMBOL_GPL(do_sync_file_range); 165