diff options
Diffstat (limited to 'fs/sync.c')
| -rw-r--r-- | fs/sync.c | 113 |
1 files changed, 113 insertions, 0 deletions
| @@ -10,11 +10,124 @@ | |||
| 10 | #include <linux/syscalls.h> | 10 | #include <linux/syscalls.h> |
| 11 | #include <linux/linkage.h> | 11 | #include <linux/linkage.h> |
| 12 | #include <linux/pagemap.h> | 12 | #include <linux/pagemap.h> |
| 13 | #include <linux/quotaops.h> | ||
| 14 | #include <linux/buffer_head.h> | ||
| 13 | 15 | ||
| 14 | #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ | 16 | #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ |
| 15 | SYNC_FILE_RANGE_WAIT_AFTER) | 17 | SYNC_FILE_RANGE_WAIT_AFTER) |
| 16 | 18 | ||
| 17 | /* | 19 | /* |
| 20 | * sync everything. Start out by waking pdflush, because that writes back | ||
| 21 | * all queues in parallel. | ||
| 22 | */ | ||
| 23 | static void do_sync(unsigned long wait) | ||
| 24 | { | ||
| 25 | wakeup_pdflush(0); | ||
| 26 | sync_inodes(0); /* All mappings, inodes and their blockdevs */ | ||
| 27 | DQUOT_SYNC(NULL); | ||
| 28 | sync_supers(); /* Write the superblocks */ | ||
| 29 | sync_filesystems(0); /* Start syncing the filesystems */ | ||
| 30 | sync_filesystems(wait); /* Waitingly sync the filesystems */ | ||
| 31 | sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ | ||
| 32 | if (!wait) | ||
| 33 | printk("Emergency Sync complete\n"); | ||
| 34 | if (unlikely(laptop_mode)) | ||
| 35 | laptop_sync_completion(); | ||
| 36 | } | ||
| 37 | |||
| 38 | asmlinkage long sys_sync(void) | ||
| 39 | { | ||
| 40 | do_sync(1); | ||
| 41 | return 0; | ||
| 42 | } | ||
| 43 | |||
| 44 | void emergency_sync(void) | ||
| 45 | { | ||
| 46 | pdflush_operation(do_sync, 0); | ||
| 47 | } | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Generic function to fsync a file. | ||
| 51 | * | ||
| 52 | * filp may be NULL if called via the msync of a vma. | ||
| 53 | */ | ||
| 54 | int file_fsync(struct file *filp, struct dentry *dentry, int datasync) | ||
| 55 | { | ||
| 56 | struct inode * inode = dentry->d_inode; | ||
| 57 | struct super_block * sb; | ||
| 58 | int ret, err; | ||
| 59 | |||
| 60 | /* sync the inode to buffers */ | ||
| 61 | ret = write_inode_now(inode, 0); | ||
| 62 | |||
| 63 | /* sync the superblock to buffers */ | ||
| 64 | sb = inode->i_sb; | ||
| 65 | lock_super(sb); | ||
| 66 | if (sb->s_op->write_super) | ||
| 67 | sb->s_op->write_super(sb); | ||
| 68 | unlock_super(sb); | ||
| 69 | |||
| 70 | /* .. finally sync the buffers to disk */ | ||
| 71 | err = sync_blockdev(sb->s_bdev); | ||
| 72 | if (!ret) | ||
| 73 | ret = err; | ||
| 74 | return ret; | ||
| 75 | } | ||
| 76 | |||
| 77 | long do_fsync(struct file *file, int datasync) | ||
| 78 | { | ||
| 79 | int ret; | ||
| 80 | int err; | ||
| 81 | struct address_space *mapping = file->f_mapping; | ||
| 82 | |||
| 83 | if (!file->f_op || !file->f_op->fsync) { | ||
| 84 | /* Why? We can still call filemap_fdatawrite */ | ||
| 85 | ret = -EINVAL; | ||
| 86 | goto out; | ||
| 87 | } | ||
| 88 | |||
| 89 | ret = filemap_fdatawrite(mapping); | ||
| 90 | |||
| 91 | /* | ||
| 92 | * We need to protect against concurrent writers, which could cause | ||
| 93 | * livelocks in fsync_buffers_list(). | ||
| 94 | */ | ||
| 95 | mutex_lock(&mapping->host->i_mutex); | ||
| 96 | err = file->f_op->fsync(file, file->f_dentry, datasync); | ||
| 97 | if (!ret) | ||
| 98 | ret = err; | ||
| 99 | mutex_unlock(&mapping->host->i_mutex); | ||
| 100 | err = filemap_fdatawait(mapping); | ||
| 101 | if (!ret) | ||
| 102 | ret = err; | ||
| 103 | out: | ||
| 104 | return ret; | ||
| 105 | } | ||
| 106 | |||
| 107 | static long __do_fsync(unsigned int fd, int datasync) | ||
| 108 | { | ||
| 109 | struct file *file; | ||
| 110 | int ret = -EBADF; | ||
| 111 | |||
| 112 | file = fget(fd); | ||
| 113 | if (file) { | ||
| 114 | ret = do_fsync(file, datasync); | ||
| 115 | fput(file); | ||
| 116 | } | ||
| 117 | return ret; | ||
| 118 | } | ||
| 119 | |||
| 120 | asmlinkage long sys_fsync(unsigned int fd) | ||
| 121 | { | ||
| 122 | return __do_fsync(fd, 0); | ||
| 123 | } | ||
| 124 | |||
| 125 | asmlinkage long sys_fdatasync(unsigned int fd) | ||
| 126 | { | ||
| 127 | return __do_fsync(fd, 1); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 18 | * sys_sync_file_range() permits finely controlled syncing over a segment of | 131 | * sys_sync_file_range() permits finely controlled syncing over a segment of |
| 19 | * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is | 132 | * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is |
| 20 | * zero then sys_sync_file_range() will operate from offset out to EOF. | 133 | * zero then sys_sync_file_range() will operate from offset out to EOF. |
