diff options
author | Maxim Patlasov <mpatlasov@parallels.com> | 2012-10-26 11:50:15 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2013-01-24 10:21:27 -0500 |
commit | b98d023a24496bf7d538c549e5426b1173c6f55d (patch) | |
tree | c465a190fe9997021c09367b22bca5915bd99b25 /fs/fuse/file.c | |
parent | d28574e043e8b7cb35482de6e9a553118a32803d (diff) |
fuse: pass iov[] to fuse_get_user_pages()
The patch makes preliminary work for the next patch optimizing scatter-gather
direct IO. The idea is to allow fuse_get_user_pages() to pack as many iov-s
to each fuse request as possible. So, here we only rework all related
call-paths to carry iov[] from fuse_direct_IO() to fuse_get_user_pages().
Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r-- | fs/fuse/file.c | 103 |
1 files changed, 49 insertions, 54 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 3384a200b3ee..542ad97b103a 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -1056,14 +1056,18 @@ static inline void fuse_page_descs_length_init(struct fuse_req *req) | |||
1056 | req->page_descs[i].offset; | 1056 | req->page_descs[i].offset; |
1057 | } | 1057 | } |
1058 | 1058 | ||
1059 | static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | 1059 | static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, |
1060 | size_t *nbytesp, int write) | 1060 | size_t *nbytesp, int write) |
1061 | { | 1061 | { |
1062 | size_t nbytes = *nbytesp; | 1062 | size_t nbytes = *nbytesp; |
1063 | unsigned long user_addr = (unsigned long) buf; | 1063 | size_t frag_size = min(iov_iter_single_seg_count(ii), nbytes); |
1064 | unsigned offset = user_addr & ~PAGE_MASK; | 1064 | unsigned long user_addr; |
1065 | unsigned offset; | ||
1065 | int npages; | 1066 | int npages; |
1066 | 1067 | ||
1068 | user_addr = (unsigned long)ii->iov->iov_base + ii->iov_offset; | ||
1069 | offset = user_addr & ~PAGE_MASK; | ||
1070 | |||
1067 | /* Special case for kernel I/O: can copy directly into the buffer */ | 1071 | /* Special case for kernel I/O: can copy directly into the buffer */ |
1068 | if (segment_eq(get_fs(), KERNEL_DS)) { | 1072 | if (segment_eq(get_fs(), KERNEL_DS)) { |
1069 | if (write) | 1073 | if (write) |
@@ -1071,10 +1075,12 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | |||
1071 | else | 1075 | else |
1072 | req->out.args[0].value = (void *) user_addr; | 1076 | req->out.args[0].value = (void *) user_addr; |
1073 | 1077 | ||
1078 | iov_iter_advance(ii, frag_size); | ||
1079 | *nbytesp = frag_size; | ||
1074 | return 0; | 1080 | return 0; |
1075 | } | 1081 | } |
1076 | 1082 | ||
1077 | nbytes = min_t(size_t, nbytes, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); | 1083 | nbytes = min_t(size_t, frag_size, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); |
1078 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; | 1084 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; |
1079 | npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); | 1085 | npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); |
1080 | npages = get_user_pages_fast(user_addr, npages, !write, req->pages); | 1086 | npages = get_user_pages_fast(user_addr, npages, !write, req->pages); |
@@ -1092,17 +1098,19 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | |||
1092 | 1098 | ||
1093 | nbytes = (req->num_pages << PAGE_SHIFT) - req->page_descs[0].offset; | 1099 | nbytes = (req->num_pages << PAGE_SHIFT) - req->page_descs[0].offset; |
1094 | 1100 | ||
1095 | if (*nbytesp < nbytes) | 1101 | if (frag_size < nbytes) |
1096 | req->page_descs[req->num_pages - 1].length -= | 1102 | req->page_descs[req->num_pages - 1].length -= |
1097 | nbytes - *nbytesp; | 1103 | nbytes - frag_size; |
1098 | 1104 | ||
1099 | *nbytesp = min(*nbytesp, nbytes); | 1105 | *nbytesp = min(frag_size, nbytes); |
1106 | iov_iter_advance(ii, *nbytesp); | ||
1100 | 1107 | ||
1101 | return 0; | 1108 | return 0; |
1102 | } | 1109 | } |
1103 | 1110 | ||
1104 | ssize_t fuse_direct_io(struct file *file, const char __user *buf, | 1111 | static ssize_t __fuse_direct_io(struct file *file, const struct iovec *iov, |
1105 | size_t count, loff_t *ppos, int write) | 1112 | unsigned long nr_segs, size_t count, |
1113 | loff_t *ppos, int write) | ||
1106 | { | 1114 | { |
1107 | struct fuse_file *ff = file->private_data; | 1115 | struct fuse_file *ff = file->private_data; |
1108 | struct fuse_conn *fc = ff->fc; | 1116 | struct fuse_conn *fc = ff->fc; |
@@ -1110,6 +1118,9 @@ ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
1110 | loff_t pos = *ppos; | 1118 | loff_t pos = *ppos; |
1111 | ssize_t res = 0; | 1119 | ssize_t res = 0; |
1112 | struct fuse_req *req; | 1120 | struct fuse_req *req; |
1121 | struct iov_iter ii; | ||
1122 | |||
1123 | iov_iter_init(&ii, iov, nr_segs, count, 0); | ||
1113 | 1124 | ||
1114 | req = fuse_get_req(fc, FUSE_MAX_PAGES_PER_REQ); | 1125 | req = fuse_get_req(fc, FUSE_MAX_PAGES_PER_REQ); |
1115 | if (IS_ERR(req)) | 1126 | if (IS_ERR(req)) |
@@ -1119,7 +1130,7 @@ ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
1119 | size_t nres; | 1130 | size_t nres; |
1120 | fl_owner_t owner = current->files; | 1131 | fl_owner_t owner = current->files; |
1121 | size_t nbytes = min(count, nmax); | 1132 | size_t nbytes = min(count, nmax); |
1122 | int err = fuse_get_user_pages(req, buf, &nbytes, write); | 1133 | int err = fuse_get_user_pages(req, &ii, &nbytes, write); |
1123 | if (err) { | 1134 | if (err) { |
1124 | res = err; | 1135 | res = err; |
1125 | break; | 1136 | break; |
@@ -1142,7 +1153,6 @@ ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
1142 | count -= nres; | 1153 | count -= nres; |
1143 | res += nres; | 1154 | res += nres; |
1144 | pos += nres; | 1155 | pos += nres; |
1145 | buf += nres; | ||
1146 | if (nres != nbytes) | 1156 | if (nres != nbytes) |
1147 | break; | 1157 | break; |
1148 | if (count) { | 1158 | if (count) { |
@@ -1159,10 +1169,17 @@ ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
1159 | 1169 | ||
1160 | return res; | 1170 | return res; |
1161 | } | 1171 | } |
1172 | |||
1173 | ssize_t fuse_direct_io(struct file *file, const char __user *buf, | ||
1174 | size_t count, loff_t *ppos, int write) | ||
1175 | { | ||
1176 | struct iovec iov = { .iov_base = (void *)buf, .iov_len = count }; | ||
1177 | return __fuse_direct_io(file, &iov, 1, count, ppos, write); | ||
1178 | } | ||
1162 | EXPORT_SYMBOL_GPL(fuse_direct_io); | 1179 | EXPORT_SYMBOL_GPL(fuse_direct_io); |
1163 | 1180 | ||
1164 | static ssize_t fuse_direct_read(struct file *file, char __user *buf, | 1181 | static ssize_t __fuse_direct_read(struct file *file, const struct iovec *iov, |
1165 | size_t count, loff_t *ppos) | 1182 | unsigned long nr_segs, loff_t *ppos) |
1166 | { | 1183 | { |
1167 | ssize_t res; | 1184 | ssize_t res; |
1168 | struct inode *inode = file->f_path.dentry->d_inode; | 1185 | struct inode *inode = file->f_path.dentry->d_inode; |
@@ -1170,22 +1187,31 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf, | |||
1170 | if (is_bad_inode(inode)) | 1187 | if (is_bad_inode(inode)) |
1171 | return -EIO; | 1188 | return -EIO; |
1172 | 1189 | ||
1173 | res = fuse_direct_io(file, buf, count, ppos, 0); | 1190 | res = __fuse_direct_io(file, iov, nr_segs, iov_length(iov, nr_segs), |
1191 | ppos, 0); | ||
1174 | 1192 | ||
1175 | fuse_invalidate_attr(inode); | 1193 | fuse_invalidate_attr(inode); |
1176 | 1194 | ||
1177 | return res; | 1195 | return res; |
1178 | } | 1196 | } |
1179 | 1197 | ||
1180 | static ssize_t __fuse_direct_write(struct file *file, const char __user *buf, | 1198 | static ssize_t fuse_direct_read(struct file *file, char __user *buf, |
1181 | size_t count, loff_t *ppos) | 1199 | size_t count, loff_t *ppos) |
1200 | { | ||
1201 | struct iovec iov = { .iov_base = (void *)buf, .iov_len = count }; | ||
1202 | return __fuse_direct_read(file, &iov, 1, ppos); | ||
1203 | } | ||
1204 | |||
1205 | static ssize_t __fuse_direct_write(struct file *file, const struct iovec *iov, | ||
1206 | unsigned long nr_segs, loff_t *ppos) | ||
1182 | { | 1207 | { |
1183 | struct inode *inode = file->f_path.dentry->d_inode; | 1208 | struct inode *inode = file->f_path.dentry->d_inode; |
1209 | size_t count = iov_length(iov, nr_segs); | ||
1184 | ssize_t res; | 1210 | ssize_t res; |
1185 | 1211 | ||
1186 | res = generic_write_checks(file, ppos, &count, 0); | 1212 | res = generic_write_checks(file, ppos, &count, 0); |
1187 | if (!res) { | 1213 | if (!res) { |
1188 | res = fuse_direct_io(file, buf, count, ppos, 1); | 1214 | res = __fuse_direct_io(file, iov, nr_segs, count, ppos, 1); |
1189 | if (res > 0) | 1215 | if (res > 0) |
1190 | fuse_write_update_size(inode, *ppos); | 1216 | fuse_write_update_size(inode, *ppos); |
1191 | } | 1217 | } |
@@ -1198,6 +1224,7 @@ static ssize_t __fuse_direct_write(struct file *file, const char __user *buf, | |||
1198 | static ssize_t fuse_direct_write(struct file *file, const char __user *buf, | 1224 | static ssize_t fuse_direct_write(struct file *file, const char __user *buf, |
1199 | size_t count, loff_t *ppos) | 1225 | size_t count, loff_t *ppos) |
1200 | { | 1226 | { |
1227 | struct iovec iov = { .iov_base = (void *)buf, .iov_len = count }; | ||
1201 | struct inode *inode = file->f_path.dentry->d_inode; | 1228 | struct inode *inode = file->f_path.dentry->d_inode; |
1202 | ssize_t res; | 1229 | ssize_t res; |
1203 | 1230 | ||
@@ -1206,7 +1233,7 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf, | |||
1206 | 1233 | ||
1207 | /* Don't allow parallel writes to the same file */ | 1234 | /* Don't allow parallel writes to the same file */ |
1208 | mutex_lock(&inode->i_mutex); | 1235 | mutex_lock(&inode->i_mutex); |
1209 | res = __fuse_direct_write(file, buf, count, ppos); | 1236 | res = __fuse_direct_write(file, &iov, 1, ppos); |
1210 | mutex_unlock(&inode->i_mutex); | 1237 | mutex_unlock(&inode->i_mutex); |
1211 | 1238 | ||
1212 | return res; | 1239 | return res; |
@@ -2167,41 +2194,6 @@ int fuse_notify_poll_wakeup(struct fuse_conn *fc, | |||
2167 | return 0; | 2194 | return 0; |
2168 | } | 2195 | } |
2169 | 2196 | ||
2170 | static ssize_t fuse_loop_dio(struct file *filp, const struct iovec *iov, | ||
2171 | unsigned long nr_segs, loff_t *ppos, int rw) | ||
2172 | { | ||
2173 | const struct iovec *vector = iov; | ||
2174 | ssize_t ret = 0; | ||
2175 | |||
2176 | while (nr_segs > 0) { | ||
2177 | void __user *base; | ||
2178 | size_t len; | ||
2179 | ssize_t nr; | ||
2180 | |||
2181 | base = vector->iov_base; | ||
2182 | len = vector->iov_len; | ||
2183 | vector++; | ||
2184 | nr_segs--; | ||
2185 | |||
2186 | if (rw == WRITE) | ||
2187 | nr = __fuse_direct_write(filp, base, len, ppos); | ||
2188 | else | ||
2189 | nr = fuse_direct_read(filp, base, len, ppos); | ||
2190 | |||
2191 | if (nr < 0) { | ||
2192 | if (!ret) | ||
2193 | ret = nr; | ||
2194 | break; | ||
2195 | } | ||
2196 | ret += nr; | ||
2197 | if (nr != len) | ||
2198 | break; | ||
2199 | } | ||
2200 | |||
2201 | return ret; | ||
2202 | } | ||
2203 | |||
2204 | |||
2205 | static ssize_t | 2197 | static ssize_t |
2206 | fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | 2198 | fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, |
2207 | loff_t offset, unsigned long nr_segs) | 2199 | loff_t offset, unsigned long nr_segs) |
@@ -2213,7 +2205,10 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
2213 | file = iocb->ki_filp; | 2205 | file = iocb->ki_filp; |
2214 | pos = offset; | 2206 | pos = offset; |
2215 | 2207 | ||
2216 | ret = fuse_loop_dio(file, iov, nr_segs, &pos, rw); | 2208 | if (rw == WRITE) |
2209 | ret = __fuse_direct_write(file, iov, nr_segs, &pos); | ||
2210 | else | ||
2211 | ret = __fuse_direct_read(file, iov, nr_segs, &pos); | ||
2217 | 2212 | ||
2218 | return ret; | 2213 | return ret; |
2219 | } | 2214 | } |