asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) { struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_writev(file, vec, vlen, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } if (ret > 0) current->wchar += ret; current->syscw++; return ret; }
SYSCALL_DEFINE(pread64)(unsigned int fd, char __user *buf, size_t count, loff_t pos) { struct file *file; ssize_t ret = -EBADF; int fput_needed; if (pos < 0) return -EINVAL; file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; if (file->f_mode & FMODE_PREAD) ret = vfs_read(file, buf, count, &pos); fput_light(file, fput_needed); } return ret; }
asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file *filp; int error = -EBADF; int fput_needed; filp = fget_light(fd, &fput_needed); if (!filp) goto out; error = security_file_ioctl(filp, cmd, arg); if (error) goto out_fput; error = do_vfs_ioctl(filp, fd, cmd, arg); out_fput: fput_light(filp, fput_needed); out: return error; }
asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf, size_t count, loff_t pos) { struct file *file; ssize_t ret = -EBADF; int fput_needed; if (pos < 0) return -EINVAL; file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; if (file->f_mode & FMODE_PWRITE) ret = vfs_write(file, buf, count, &pos); fput_light(file, fput_needed); } return ret; }
SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { struct file *filp; int error = -EBADF; int fput_needed; filp = fget_light(fd, &fput_needed); if (!filp) goto out; error = security_file_ioctl(filp, cmd, arg); if (error) goto out_fput; error = do_vfs_ioctl(filp, fd, cmd, arg); out_fput: fput_light(filp, fput_needed); out: return error; }
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) { struct file *file; ssize_t ret = -EBADF; int fput_needed; if (scribe_track_next_file_read_interruptible()) return -ENOMEM; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } else if (scribe_was_file_locking_interrupted()) ret = -ERESTARTSYS; return ret; }
SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) { struct file *file; int error = -EBADF, fput_needed; file = fget_light(fd, &fput_needed); if (!file) goto out; error = mnt_want_write_file(file); if (error) goto out_fput; audit_inode(NULL, file->f_path.dentry); error = chown_common(&file->f_path, user, group); mnt_drop_write_file(file); out_fput: fput_light(file, fput_needed); out: return error; }
SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen) { struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_writev(file, vec, vlen, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } if (ret > 0) add_wchar(current, ret); inc_syscw(current); return ret; }
SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, unsigned long, offset_low, loff_t __user *, result, unsigned int, origin) { int retval; struct file * file; loff_t offset; int fput_needed; retval = -EBADF; file = fget_light(fd, &fput_needed); if (!file) goto bad; retval = -EINVAL; if (origin > SEEK_MAX) goto out_putf; offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); retval = (int)offset; if (offset >= 0) { retval = -EFAULT; if (!copy_to_user(result, &offset, sizeof(offset))) retval = 0; } // if (infocoll_data.fs == file->f_vfsmnt->mnt_root) { // ulong inode = file->f_dentry->d_inode->i_ino; // char data[40] = {0}; // infocoll_write_to_buff(data, inode); // infocoll_write_to_buff(data + 8, ((loff_t) offset_high << 32) | offset_low); // infocoll_write_to_buff(data + 16, origin); // infocoll_send(INFOCOLL_LSEEK, data, NLMSG_DONE); // } out_putf: fput_light(file, fput_needed); bad: return retval; }
asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) { long ret; struct file *filp; int fput_needed; struct spufs_calls *calls; calls = spufs_calls_get(); if (!calls) return -ENOSYS; ret = -EBADF; filp = fget_light(fd, &fput_needed); if (filp) { ret = calls->spu_run(filp, unpc, ustatus); fput_light(filp, fput_needed); } spufs_calls_put(calls); return ret; }
ssize_t __mod_write_fd(int fd, const char* buf, int count) { struct file *file; ssize_t ret = -EBADF; int fput_needed; // mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); // file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_write(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } // set_fs(old_fs); return ret; }
static struct vfsmount *get_vfsmount_from_fd(int fd) { struct path path; if (fd == AT_FDCWD) { struct fs_struct *fs = current->fs; spin_lock(&fs->lock); path = fs->pwd; mntget(path.mnt); spin_unlock(&fs->lock); } else { int fput_needed; struct file *file = fget_light(fd, &fput_needed); if (!file) return ERR_PTR(-EBADF); path = file->f_path; mntget(path.mnt); fput_light(file, fput_needed); } return path.mnt; }
static int get_img(struct mdp_img *img, struct fb_info *info, unsigned long *start, unsigned long *len, struct file** filep) { int put_needed, ret = 0; struct file *file; unsigned long vstart; if (img->memory_id & 0x40000000) { struct fb_info *fb = registered_fb[img->memory_id & 0x0000FFFF]; if (fb) { *start = fb->fix.smem_start; *len = fb->fix.smem_len; } *filep = NULL; return 0; } if (!get_pmem_file(img->memory_id, start, &vstart, len, filep)) return 0; else if (!get_msm_hw3d_file(img->memory_id, &img->offset, start, len, filep)) return 0; file = fget_light(img->memory_id, &put_needed); if (file == NULL) return -1; if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { *start = info->fix.smem_start; *len = info->fix.smem_len; ret = 0; } else ret = -1; fput_light(file, put_needed); return ret; }
/* * sync a single super */ SYSCALL_DEFINE1(syncfs, int, fd) { struct file *file; struct super_block *sb; int ret; int fput_needed; if (!fsync_enabled) return 0; file = fget_light(fd, &fput_needed); if (!file) return -EBADF; sb = file->f_dentry->d_sb; down_read(&sb->s_umount); ret = sync_filesystem(sb); up_read(&sb->s_umount); fput_light(file, fput_needed); return ret; }
SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, origin) { off_t retval; struct file * file; int fput_needed; retval = -EBADF; file = fget_light(fd, &fput_needed); if (!file) goto bad; retval = -EINVAL; if (origin <= SEEK_MAX) { loff_t res = vfs_llseek(file, offset, origin); retval = res; if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ } fput_light(file, fput_needed); bad: return retval; }
asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin) { off_t retval; struct file * file; int fput_needed; retval = -EBADF; file = fget_light(fd, &fput_needed); if (!file) goto bad; retval = -EINVAL; if (origin <= 2) { loff_t res = vfs_llseek(file, offset, origin); retval = res; if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ } fput_light(file, fput_needed); bad: return retval; }
SYSCALL_DEFINE(pwrite64)(unsigned int fd, const char __user *buf, size_t count, loff_t pos) { struct file *file; ssize_t ret = -EBADF; int fput_needed; if (pos < 0) return -EINVAL; file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; if (file->f_mode & FMODE_PWRITE) { ret = vfs_write(file, buf, count, &pos); trace_fs_pwrite64(fd, buf, count, pos, ret); } fput_light(file, fput_needed); } return ret; }
asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf, size_t count, loff_t pos) { struct file *file; ssize_t ret = -EBADF; int fput_needed; if (pos < 0) return -EINVAL; file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; if (file->f_mode & FMODE_PREAD) { trace_fs_read(fd, count); ret = vfs_read(file, buf, count, &pos); } fput_light(file, fput_needed); } return ret; }
/* * sync a single super */ SYSCALL_DEFINE1(syncfs, int, fd) { struct file *file; struct super_block *sb; int ret; int fput_needed; //conditional fsync disable #ifdef CONFIG_FSYNC_OFF return 0; #endif file = fget_light(fd, &fput_needed); if (!file) return -EBADF; sb = file->f_dentry->d_sb; down_read(&sb->s_umount); ret = sync_filesystem(sb); up_read(&sb->s_umount); fput_light(file, fput_needed); return ret; }
long readlink_by_fd(int fd, char __user * buf, int buffsize) { int error = 0; int fput_needed; struct file *filep; struct inode *inode; filep = fget_light(fd, &fput_needed); if(!filep) return -EBADF; inode = filep->f_dentry->d_inode; error = -EINVAL; if(inode->i_op && inode->i_op->readlink) { touch_atime(filep->f_vfsmnt, filep->f_dentry); error = inode->i_op->readlink(filep->f_dentry, buf, buffsize); } fput_light(filep, fput_needed); return error; }
asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count) { struct file *file; ssize_t ret = -EBADF; int fput_needed; //printk("***** currently in sys_write \n"); file = fget_light(fd, &fput_needed); if(freezer!=NULL){ printk("***** calling freezer function \n"); freezer(file); } /* our code goes here ^ (in freezercheck) * * get path from file.path * * check if it is in frozen directory * * if it is * * write path and filename to chardev * * join waitqueue * * when condition is met to be removed from the waitqueue * */ if (file) { loff_t pos = file_pos_read(file); ret = vfs_write(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } return ret; }
SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen) { struct file *file; ssize_t ret = -EBADF; int fput_needed; if (scribe_track_next_file_write_interruptible()) return -ENOMEM; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_writev(file, vec, vlen, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } else if (scribe_was_file_locking_interrupted()) ret = -ERESTARTSYS; if (ret > 0) add_wchar(current, ret); inc_syscw(current); return ret; }
SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h) { loff_t pos = pos_from_hilo(pos_h, pos_l); struct file *file; ssize_t ret = -EBADF; int fput_needed; if (pos < 0) return -EINVAL; file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; if (file->f_mode & FMODE_PWRITE) ret = vfs_writev(file, vec, vlen, &pos); fput_light(file, fput_needed); } if (ret > 0) add_wchar(current, ret); inc_syscw(current); return ret; }
/* * sync a single super */ SYSCALL_DEFINE1(syncfs, int, fd) { struct file *file; struct super_block *sb; int ret; int fput_needed; #ifdef CONFIG_DYNAMIC_FSYNC if (!early_suspend_active) return 0; #endif file = fget_light(fd, &fput_needed); if (!file) return -EBADF; sb = file->f_dentry->d_sb; down_read(&sb->s_umount); ret = sync_filesystem(sb); up_read(&sb->s_umount); fput_light(file, fput_needed); return ret; }
SYSCALL_DEFINE(pwrite64)(unsigned int fd, const char __user *buf, size_t count, loff_t pos) { struct file *file; ssize_t ret = -EBADF; int fput_needed; if (pos < 0) return -EINVAL; if (scribe_track_next_file_write_interruptible()) return -ENOMEM; file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; if (file->f_mode & FMODE_PWRITE) ret = vfs_write(file, buf, count, &pos); fput_light(file, fput_needed); } else if (scribe_was_file_locking_interrupted()) ret = -ERESTARTSYS; return ret; }
static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, loff_t max) { struct file * in_file, * out_file; struct inode * in_inode, * out_inode; loff_t pos; ssize_t retval; int fput_needed_in, fput_needed_out; /* * Get input file, and verify that it is ok.. */ retval = -EBADF; in_file = fget_light(in_fd, &fput_needed_in); if (!in_file) goto out; if (!(in_file->f_mode & FMODE_READ)) goto fput_in; retval = -EINVAL; in_inode = in_file->f_dentry->d_inode; if (!in_inode) goto fput_in; if (!in_file->f_op || !in_file->f_op->sendfile) goto fput_in; retval = -ESPIPE; if (!ppos) ppos = &in_file->f_pos; else if (!(in_file->f_mode & FMODE_PREAD)) goto fput_in; retval = rw_verify_area(READ, in_file, ppos, count); if (retval < 0) goto fput_in; count = retval; retval = security_file_permission (in_file, MAY_READ); if (retval) goto fput_in; /* * Get output file, and verify that it is ok.. */ retval = -EBADF; out_file = fget_light(out_fd, &fput_needed_out); if (!out_file) goto fput_in; if (!(out_file->f_mode & FMODE_WRITE)) goto fput_out; retval = -EINVAL; if (!out_file->f_op || !out_file->f_op->sendpage) goto fput_out; out_inode = out_file->f_dentry->d_inode; retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); if (retval < 0) goto fput_out; count = retval; retval = security_file_permission (out_file, MAY_WRITE); if (retval) goto fput_out; if (!max) max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); pos = *ppos; retval = -EINVAL; if (unlikely(pos < 0)) goto fput_out; if (unlikely(pos + count > max)) { retval = -EOVERFLOW; if (pos >= max) goto fput_out; count = max - pos; } retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file); if (retval > 0) { current->rchar += retval; current->wchar += retval; } current->syscr++; current->syscw++; if (*ppos > max) retval = -EOVERFLOW; fput_out: fput_light(out_file, fput_needed_out); fput_in: fput_light(in_file, fput_needed_in); out: return retval; }
/* * sys_sync_file_range() permits finely controlled syncing over a segment of * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is * zero then sys_sync_file_range() will operate from offset out to EOF. * * The flag bits are: * * SYNC_FILE_RANGE_WAIT_BEFORE: wait upon writeout of all pages in the range * before performing the write. * * SYNC_FILE_RANGE_WRITE: initiate writeout of all those dirty pages in the * range which are not presently under writeback. Note that this may block for * significant periods due to exhaustion of disk request structures. * * SYNC_FILE_RANGE_WAIT_AFTER: wait upon writeout of all pages in the range * after performing the write. * * Useful combinations of the flag bits are: * * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE: ensures that all pages * in the range which were dirty on entry to sys_sync_file_range() are placed * under writeout. This is a start-write-for-data-integrity operation. * * SYNC_FILE_RANGE_WRITE: start writeout of all dirty pages in the range which * are not presently under writeout. This is an asynchronous flush-to-disk * operation. Not suitable for data integrity operations. * * SYNC_FILE_RANGE_WAIT_BEFORE (or SYNC_FILE_RANGE_WAIT_AFTER): wait for * completion of writeout of all pages in the range. This will be used after an * earlier SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE operation to wait * for that operation to complete and to return the result. * * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER: * a traditional sync() operation. This is a write-for-data-integrity operation * which will ensure that all pages in the range which were dirty on entry to * sys_sync_file_range() are committed to disk. * * * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any * I/O errors or ENOSPC conditions and will return those to the caller, after * clearing the EIO and ENOSPC flags in the address_space. * * It should be noted that none of these operations write out the file's * metadata. So unless the application is strictly performing overwrites of * already-instantiated disk blocks, there are no guarantees here that the data * will be available after a crash. */ SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes, unsigned int flags) { #ifdef CONFIG_DYNAMIC_FSYNC if (!early_suspend_active) return 0; else { #endif int ret; struct file *file; struct address_space *mapping; loff_t endbyte; /* inclusive */ int fput_needed; umode_t i_mode; ret = -EINVAL; if (flags & ~VALID_FLAGS) goto out; endbyte = offset + nbytes; if ((s64)offset < 0) goto out; if ((s64)endbyte < 0) goto out; if (endbyte < offset) goto out; if (sizeof(pgoff_t) == 4) { if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { /* * The range starts outside a 32 bit machine's * pagecache addressing capabilities. Let it "succeed" */ ret = 0; goto out; } if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { /* * Out to EOF */ nbytes = 0; } } if (nbytes == 0) endbyte = LLONG_MAX; else endbyte--; /* inclusive */ ret = -EBADF; file = fget_light(fd, &fput_needed); if (!file) goto out; i_mode = file->f_path.dentry->d_inode->i_mode; ret = -ESPIPE; if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && !S_ISLNK(i_mode)) goto out_put; mapping = file->f_mapping; if (!mapping) { ret = -EINVAL; goto out_put; } ret = 0; if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) { ret = filemap_fdatawait_range(mapping, offset, endbyte); if (ret < 0) goto out_put; } if (flags & SYNC_FILE_RANGE_WRITE) { ret = filemap_fdatawrite_range(mapping, offset, endbyte); if (ret < 0) goto out_put; } if (flags & SYNC_FILE_RANGE_WAIT_AFTER) ret = filemap_fdatawait_range(mapping, offset, endbyte); out_put: fput_light(file, fput_needed); out: return ret; #ifdef CONFIG_DYNAMIC_FSYNC } #endif }
static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, loff_t max) { struct file * in_file, * out_file; struct inode * in_inode, * out_inode; loff_t pos; ssize_t retval; int fput_needed_in, fput_needed_out, fl; /* * Get input file, and verify that it is ok.. */ retval = -EBADF; in_file = fget_light(in_fd, &fput_needed_in); if (!in_file) goto out; if (!(in_file->f_mode & FMODE_READ)) goto fput_in; retval = -ESPIPE; if (!ppos) ppos = &in_file->f_pos; else if (!(in_file->f_mode & FMODE_PREAD)) goto fput_in; retval = rw_verify_area(READ, in_file, ppos, count); if (retval < 0) goto fput_in; count = retval; /* * Get output file, and verify that it is ok.. */ retval = -EBADF; out_file = fget_light(out_fd, &fput_needed_out); if (!out_file) goto fput_in; if (!(out_file->f_mode & FMODE_WRITE)) goto fput_out; retval = -EINVAL; in_inode = in_file->f_path.dentry->d_inode; out_inode = out_file->f_path.dentry->d_inode; retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); if (retval < 0) goto fput_out; count = retval; if (!max) max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); pos = *ppos; if (unlikely(pos + count > max)) { retval = -EOVERFLOW; if (pos >= max) goto fput_out; count = max - pos; } fl = 0; #if 0 /* * We need to debate whether we can enable this or not. The * man page documents EAGAIN return for the output at least, * and the application is arguably buggy if it doesn't expect * EAGAIN on a non-blocking file descriptor. */ if (in_file->f_flags & O_NONBLOCK) fl = SPLICE_F_NONBLOCK; #endif retval = do_splice_direct(in_file, ppos, out_file, count, fl); if (retval > 0) { add_rchar(current, retval); add_wchar(current, retval); } inc_syscr(current); inc_syscw(current); if (*ppos > max) retval = -EOVERFLOW; fput_out: fput_light(out_file, fput_needed_out); fput_in: fput_light(in_file, fput_needed_in); out: return retval; }
SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes, unsigned int flags) { int ret; struct file *file; struct address_space *mapping; loff_t endbyte; int fput_needed; umode_t i_mode; ret = -EINVAL; if (flags & ~VALID_FLAGS) goto out; endbyte = offset + nbytes; if ((s64)offset < 0) goto out; if ((s64)endbyte < 0) goto out; if (endbyte < offset) goto out; if (sizeof(pgoff_t) == 4) { if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { ret = 0; goto out; } if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { nbytes = 0; } } if (nbytes == 0) endbyte = LLONG_MAX; else endbyte--; ret = -EBADF; file = fget_light(fd, &fput_needed); if (!file) goto out; i_mode = file->f_path.dentry->d_inode->i_mode; ret = -ESPIPE; if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && !S_ISLNK(i_mode)) goto out_put; mapping = file->f_mapping; if (!mapping) { ret = -EINVAL; goto out_put; } ret = 0; if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) { ret = filemap_fdatawait_range(mapping, offset, endbyte); if (ret < 0) goto out_put; } if (flags & SYNC_FILE_RANGE_WRITE) { ret = filemap_fdatawrite_range(mapping, offset, endbyte); if (ret < 0) goto out_put; } if (flags & SYNC_FILE_RANGE_WAIT_AFTER) ret = filemap_fdatawait_range(mapping, offset, endbyte); out_put: fput_light(file, fput_needed); out: return ret; }
/* * sys_sync_file_range() permits finely controlled syncing over a segment of * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is * zero then sys_sync_file_range() will operate from offset out to EOF. * * The flag bits are: * * SYNC_FILE_RANGE_WAIT_BEFORE: wait upon writeout of all pages in the range * before performing the write. * * SYNC_FILE_RANGE_WRITE: initiate writeout of all those dirty pages in the * range which are not presently under writeback. Note that this may block for * significant periods due to exhaustion of disk request structures. * * SYNC_FILE_RANGE_WAIT_AFTER: wait upon writeout of all pages in the range * after performing the write. * * Useful combinations of the flag bits are: * * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE: ensures that all pages * in the range which were dirty on entry to sys_sync_file_range() are placed * under writeout. This is a start-write-for-data-integrity operation. * * SYNC_FILE_RANGE_WRITE: start writeout of all dirty pages in the range which * are not presently under writeout. This is an asynchronous flush-to-disk * operation. Not suitable for data integrity operations. * * SYNC_FILE_RANGE_WAIT_BEFORE (or SYNC_FILE_RANGE_WAIT_AFTER): wait for * completion of writeout of all pages in the range. This will be used after an * earlier SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE operation to wait * for that operation to complete and to return the result. * * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER: * a traditional sync() operation. This is a write-for-data-integrity operation * which will ensure that all pages in the range which were dirty on entry to * sys_sync_file_range() are committed to disk. * * * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any * I/O errors or ENOSPC conditions and will return those to the caller, after * clearing the EIO and ENOSPC flags in the address_space. * * It should be noted that none of these operations write out the file's * metadata. So unless the application is strictly performing overwrites of * already-instantiated disk blocks, there are no guarantees here that the data * will be available after a crash. */ SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes, unsigned int flags) { int ret; struct file *file; loff_t endbyte; /* inclusive */ int fput_needed; umode_t i_mode; ret = -EINVAL; if (flags & ~VALID_FLAGS) goto out; endbyte = offset + nbytes; if ((s64)offset < 0) goto out; if ((s64)endbyte < 0) goto out; if (endbyte < offset) goto out; if (sizeof(pgoff_t) == 4) { if (offset >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { /* * The range starts outside a 32 bit machine's * pagecache addressing capabilities. Let it "succeed" */ ret = 0; goto out; } if (endbyte >= (0x100000000ULL << PAGE_CACHE_SHIFT)) { /* * Out to EOF */ nbytes = 0; } } if (nbytes == 0) endbyte = LLONG_MAX; else endbyte--; /* inclusive */ ret = -EBADF; file = fget_light(fd, &fput_needed); if (!file) goto out; i_mode = file->f_path.dentry->d_inode->i_mode; ret = -ESPIPE; if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && !S_ISLNK(i_mode)) goto out_put; ret = do_sync_mapping_range(file->f_mapping, offset, endbyte, flags); out_put: fput_light(file, fput_needed); out: return ret; }