aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
authorMaxim Patlasov <mpatlasov@parallels.com>2012-10-26 11:50:15 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2013-01-24 10:21:27 -0500
commitb98d023a24496bf7d538c549e5426b1173c6f55d (patch)
treec465a190fe9997021c09367b22bca5915bd99b25 /fs/fuse/file.c
parentd28574e043e8b7cb35482de6e9a553118a32803d (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.c103
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
1059static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, 1059static 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
1104ssize_t fuse_direct_io(struct file *file, const char __user *buf, 1111static 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
1173ssize_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}
1162EXPORT_SYMBOL_GPL(fuse_direct_io); 1179EXPORT_SYMBOL_GPL(fuse_direct_io);
1163 1180
1164static ssize_t fuse_direct_read(struct file *file, char __user *buf, 1181static 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
1180static ssize_t __fuse_direct_write(struct file *file, const char __user *buf, 1198static 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
1205static 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,
1198static ssize_t fuse_direct_write(struct file *file, const char __user *buf, 1224static 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
2170static 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
2205static ssize_t 2197static ssize_t
2206fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, 2198fuse_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}