diff options
Diffstat (limited to 'fs/fuse/file.c')
| -rw-r--r-- | fs/fuse/file.c | 129 |
1 files changed, 112 insertions, 17 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a841868bf9ce..504e61b7fd75 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -194,10 +194,6 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) | |||
| 194 | struct fuse_conn *fc = get_fuse_conn(inode); | 194 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 195 | int err; | 195 | int err; |
| 196 | 196 | ||
| 197 | /* VFS checks this, but only _after_ ->open() */ | ||
| 198 | if (file->f_flags & O_DIRECT) | ||
| 199 | return -EINVAL; | ||
| 200 | |||
| 201 | err = generic_file_open(inode, file); | 197 | err = generic_file_open(inode, file); |
| 202 | if (err) | 198 | if (err) |
| 203 | return err; | 199 | return err; |
| @@ -932,17 +928,23 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 932 | struct file *file = iocb->ki_filp; | 928 | struct file *file = iocb->ki_filp; |
| 933 | struct address_space *mapping = file->f_mapping; | 929 | struct address_space *mapping = file->f_mapping; |
| 934 | size_t count = 0; | 930 | size_t count = 0; |
| 931 | size_t ocount = 0; | ||
| 935 | ssize_t written = 0; | 932 | ssize_t written = 0; |
| 933 | ssize_t written_buffered = 0; | ||
| 936 | struct inode *inode = mapping->host; | 934 | struct inode *inode = mapping->host; |
| 937 | ssize_t err; | 935 | ssize_t err; |
| 938 | struct iov_iter i; | 936 | struct iov_iter i; |
| 937 | loff_t endbyte = 0; | ||
| 939 | 938 | ||
| 940 | WARN_ON(iocb->ki_pos != pos); | 939 | WARN_ON(iocb->ki_pos != pos); |
| 941 | 940 | ||
| 942 | err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ); | 941 | ocount = 0; |
| 942 | err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ); | ||
| 943 | if (err) | 943 | if (err) |
| 944 | return err; | 944 | return err; |
| 945 | 945 | ||
| 946 | count = ocount; | ||
| 947 | |||
| 946 | mutex_lock(&inode->i_mutex); | 948 | mutex_lock(&inode->i_mutex); |
| 947 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | 949 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); |
| 948 | 950 | ||
| @@ -962,11 +964,41 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 962 | 964 | ||
| 963 | file_update_time(file); | 965 | file_update_time(file); |
| 964 | 966 | ||
| 965 | iov_iter_init(&i, iov, nr_segs, count, 0); | 967 | if (file->f_flags & O_DIRECT) { |
| 966 | written = fuse_perform_write(file, mapping, &i, pos); | 968 | written = generic_file_direct_write(iocb, iov, &nr_segs, |
| 967 | if (written >= 0) | 969 | pos, &iocb->ki_pos, |
| 968 | iocb->ki_pos = pos + written; | 970 | count, ocount); |
| 971 | if (written < 0 || written == count) | ||
| 972 | goto out; | ||
| 973 | |||
| 974 | pos += written; | ||
| 975 | count -= written; | ||
| 969 | 976 | ||
| 977 | iov_iter_init(&i, iov, nr_segs, count, written); | ||
| 978 | written_buffered = fuse_perform_write(file, mapping, &i, pos); | ||
| 979 | if (written_buffered < 0) { | ||
| 980 | err = written_buffered; | ||
| 981 | goto out; | ||
| 982 | } | ||
| 983 | endbyte = pos + written_buffered - 1; | ||
| 984 | |||
| 985 | err = filemap_write_and_wait_range(file->f_mapping, pos, | ||
| 986 | endbyte); | ||
| 987 | if (err) | ||
| 988 | goto out; | ||
| 989 | |||
| 990 | invalidate_mapping_pages(file->f_mapping, | ||
| 991 | pos >> PAGE_CACHE_SHIFT, | ||
| 992 | endbyte >> PAGE_CACHE_SHIFT); | ||
| 993 | |||
| 994 | written += written_buffered; | ||
| 995 | iocb->ki_pos = pos + written_buffered; | ||
| 996 | } else { | ||
| 997 | iov_iter_init(&i, iov, nr_segs, count, 0); | ||
| 998 | written = fuse_perform_write(file, mapping, &i, pos); | ||
| 999 | if (written >= 0) | ||
| 1000 | iocb->ki_pos = pos + written; | ||
| 1001 | } | ||
| 970 | out: | 1002 | out: |
| 971 | current->backing_dev_info = NULL; | 1003 | current->backing_dev_info = NULL; |
| 972 | mutex_unlock(&inode->i_mutex); | 1004 | mutex_unlock(&inode->i_mutex); |
| @@ -1101,30 +1133,41 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf, | |||
| 1101 | return res; | 1133 | return res; |
| 1102 | } | 1134 | } |
| 1103 | 1135 | ||
| 1104 | static ssize_t fuse_direct_write(struct file *file, const char __user *buf, | 1136 | static ssize_t __fuse_direct_write(struct file *file, const char __user *buf, |
| 1105 | size_t count, loff_t *ppos) | 1137 | size_t count, loff_t *ppos) |
| 1106 | { | 1138 | { |
| 1107 | struct inode *inode = file->f_path.dentry->d_inode; | 1139 | struct inode *inode = file->f_path.dentry->d_inode; |
| 1108 | ssize_t res; | 1140 | ssize_t res; |
| 1109 | 1141 | ||
| 1110 | if (is_bad_inode(inode)) | ||
| 1111 | return -EIO; | ||
| 1112 | |||
| 1113 | /* Don't allow parallel writes to the same file */ | ||
| 1114 | mutex_lock(&inode->i_mutex); | ||
| 1115 | res = generic_write_checks(file, ppos, &count, 0); | 1142 | res = generic_write_checks(file, ppos, &count, 0); |
| 1116 | if (!res) { | 1143 | if (!res) { |
| 1117 | res = fuse_direct_io(file, buf, count, ppos, 1); | 1144 | res = fuse_direct_io(file, buf, count, ppos, 1); |
| 1118 | if (res > 0) | 1145 | if (res > 0) |
| 1119 | fuse_write_update_size(inode, *ppos); | 1146 | fuse_write_update_size(inode, *ppos); |
| 1120 | } | 1147 | } |
| 1121 | mutex_unlock(&inode->i_mutex); | ||
| 1122 | 1148 | ||
| 1123 | fuse_invalidate_attr(inode); | 1149 | fuse_invalidate_attr(inode); |
| 1124 | 1150 | ||
| 1125 | return res; | 1151 | return res; |
| 1126 | } | 1152 | } |
| 1127 | 1153 | ||
| 1154 | static ssize_t fuse_direct_write(struct file *file, const char __user *buf, | ||
| 1155 | size_t count, loff_t *ppos) | ||
| 1156 | { | ||
| 1157 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 1158 | ssize_t res; | ||
| 1159 | |||
| 1160 | if (is_bad_inode(inode)) | ||
| 1161 | return -EIO; | ||
| 1162 | |||
| 1163 | /* Don't allow parallel writes to the same file */ | ||
| 1164 | mutex_lock(&inode->i_mutex); | ||
| 1165 | res = __fuse_direct_write(file, buf, count, ppos); | ||
| 1166 | mutex_unlock(&inode->i_mutex); | ||
| 1167 | |||
| 1168 | return res; | ||
| 1169 | } | ||
| 1170 | |||
| 1128 | static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req) | 1171 | static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req) |
| 1129 | { | 1172 | { |
| 1130 | __free_page(req->pages[0]); | 1173 | __free_page(req->pages[0]); |
| @@ -2077,6 +2120,57 @@ int fuse_notify_poll_wakeup(struct fuse_conn *fc, | |||
| 2077 | return 0; | 2120 | return 0; |
| 2078 | } | 2121 | } |
| 2079 | 2122 | ||
| 2123 | static ssize_t fuse_loop_dio(struct file *filp, const struct iovec *iov, | ||
| 2124 | unsigned long nr_segs, loff_t *ppos, int rw) | ||
| 2125 | { | ||
| 2126 | const struct iovec *vector = iov; | ||
| 2127 | ssize_t ret = 0; | ||
| 2128 | |||
| 2129 | while (nr_segs > 0) { | ||
| 2130 | void __user *base; | ||
| 2131 | size_t len; | ||
| 2132 | ssize_t nr; | ||
| 2133 | |||
| 2134 | base = vector->iov_base; | ||
| 2135 | len = vector->iov_len; | ||
| 2136 | vector++; | ||
| 2137 | nr_segs--; | ||
| 2138 | |||
| 2139 | if (rw == WRITE) | ||
| 2140 | nr = __fuse_direct_write(filp, base, len, ppos); | ||
| 2141 | else | ||
| 2142 | nr = fuse_direct_read(filp, base, len, ppos); | ||
| 2143 | |||
| 2144 | if (nr < 0) { | ||
| 2145 | if (!ret) | ||
| 2146 | ret = nr; | ||
| 2147 | break; | ||
| 2148 | } | ||
| 2149 | ret += nr; | ||
| 2150 | if (nr != len) | ||
| 2151 | break; | ||
| 2152 | } | ||
| 2153 | |||
| 2154 | return ret; | ||
| 2155 | } | ||
| 2156 | |||
| 2157 | |||
| 2158 | static ssize_t | ||
| 2159 | fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | ||
| 2160 | loff_t offset, unsigned long nr_segs) | ||
| 2161 | { | ||
| 2162 | ssize_t ret = 0; | ||
| 2163 | struct file *file = NULL; | ||
| 2164 | loff_t pos = 0; | ||
| 2165 | |||
| 2166 | file = iocb->ki_filp; | ||
| 2167 | pos = offset; | ||
| 2168 | |||
| 2169 | ret = fuse_loop_dio(file, iov, nr_segs, &pos, rw); | ||
| 2170 | |||
| 2171 | return ret; | ||
| 2172 | } | ||
| 2173 | |||
| 2080 | static const struct file_operations fuse_file_operations = { | 2174 | static const struct file_operations fuse_file_operations = { |
| 2081 | .llseek = fuse_file_llseek, | 2175 | .llseek = fuse_file_llseek, |
| 2082 | .read = do_sync_read, | 2176 | .read = do_sync_read, |
| @@ -2120,6 +2214,7 @@ static const struct address_space_operations fuse_file_aops = { | |||
| 2120 | .readpages = fuse_readpages, | 2214 | .readpages = fuse_readpages, |
| 2121 | .set_page_dirty = __set_page_dirty_nobuffers, | 2215 | .set_page_dirty = __set_page_dirty_nobuffers, |
| 2122 | .bmap = fuse_bmap, | 2216 | .bmap = fuse_bmap, |
| 2217 | .direct_IO = fuse_direct_IO, | ||
| 2123 | }; | 2218 | }; |
| 2124 | 2219 | ||
| 2125 | void fuse_init_file_inode(struct inode *inode) | 2220 | void fuse_init_file_inode(struct inode *inode) |
