diff options
Diffstat (limited to 'fs/9p/vfs_file.c')
-rw-r--r-- | fs/9p/vfs_file.c | 93 |
1 files changed, 82 insertions, 11 deletions
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 52944d2249a4..041c52692284 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -120,23 +120,72 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
120 | } | 120 | } |
121 | 121 | ||
122 | /** | 122 | /** |
123 | * v9fs_file_read - read from a file | 123 | * v9fs_file_readn - read from a file |
124 | * @filp: file pointer to read | 124 | * @filp: file pointer to read |
125 | * @data: data buffer to read data into | 125 | * @data: data buffer to read data into |
126 | * @udata: user data buffer to read data into | ||
126 | * @count: size of buffer | 127 | * @count: size of buffer |
127 | * @offset: offset at which to read data | 128 | * @offset: offset at which to read data |
128 | * | 129 | * |
129 | */ | 130 | */ |
131 | |||
132 | ssize_t | ||
133 | v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, | ||
134 | u64 offset) | ||
135 | { | ||
136 | int n, total; | ||
137 | struct p9_fid *fid = filp->private_data; | ||
138 | |||
139 | P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid, | ||
140 | (long long unsigned) offset, count); | ||
141 | |||
142 | n = 0; | ||
143 | total = 0; | ||
144 | do { | ||
145 | n = p9_client_read(fid, data, udata, offset, count); | ||
146 | if (n <= 0) | ||
147 | break; | ||
148 | |||
149 | if (data) | ||
150 | data += n; | ||
151 | if (udata) | ||
152 | udata += n; | ||
153 | |||
154 | offset += n; | ||
155 | count -= n; | ||
156 | total += n; | ||
157 | } while (count > 0 && n == (fid->clnt->msize - P9_IOHDRSZ)); | ||
158 | |||
159 | if (n < 0) | ||
160 | total = n; | ||
161 | |||
162 | return total; | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * v9fs_file_read - read from a file | ||
167 | * @filp: file pointer to read | ||
168 | * @udata: user data buffer to read data into | ||
169 | * @count: size of buffer | ||
170 | * @offset: offset at which to read data | ||
171 | * | ||
172 | */ | ||
173 | |||
130 | static ssize_t | 174 | static ssize_t |
131 | v9fs_file_read(struct file *filp, char __user * data, size_t count, | 175 | v9fs_file_read(struct file *filp, char __user *udata, size_t count, |
132 | loff_t * offset) | 176 | loff_t * offset) |
133 | { | 177 | { |
134 | int ret; | 178 | int ret; |
135 | struct p9_fid *fid; | 179 | struct p9_fid *fid; |
136 | 180 | ||
137 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); | 181 | P9_DPRINTK(P9_DEBUG_VFS, "count %d offset %lld\n", count, *offset); |
138 | fid = filp->private_data; | 182 | fid = filp->private_data; |
139 | ret = p9_client_uread(fid, data, *offset, count); | 183 | |
184 | if (count > (fid->clnt->msize - P9_IOHDRSZ)) | ||
185 | ret = v9fs_file_readn(filp, NULL, udata, count, *offset); | ||
186 | else | ||
187 | ret = p9_client_read(fid, NULL, udata, *offset, count); | ||
188 | |||
140 | if (ret > 0) | 189 | if (ret > 0) |
141 | *offset += ret; | 190 | *offset += ret; |
142 | 191 | ||
@@ -156,19 +205,38 @@ static ssize_t | |||
156 | v9fs_file_write(struct file *filp, const char __user * data, | 205 | v9fs_file_write(struct file *filp, const char __user * data, |
157 | size_t count, loff_t * offset) | 206 | size_t count, loff_t * offset) |
158 | { | 207 | { |
159 | int ret; | 208 | int n, rsize, total = 0; |
160 | struct p9_fid *fid; | 209 | struct p9_fid *fid; |
210 | struct p9_client *clnt; | ||
161 | struct inode *inode = filp->f_path.dentry->d_inode; | 211 | struct inode *inode = filp->f_path.dentry->d_inode; |
212 | int origin = *offset; | ||
162 | 213 | ||
163 | P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, | 214 | P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, |
164 | (int)count, (int)*offset); | 215 | (int)count, (int)*offset); |
165 | 216 | ||
166 | fid = filp->private_data; | 217 | fid = filp->private_data; |
167 | ret = p9_client_uwrite(fid, data, *offset, count); | 218 | clnt = fid->clnt; |
168 | if (ret > 0) { | 219 | |
169 | invalidate_inode_pages2_range(inode->i_mapping, *offset, | 220 | rsize = fid->iounit; |
170 | *offset+ret); | 221 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
171 | *offset += ret; | 222 | rsize = clnt->msize - P9_IOHDRSZ; |
223 | |||
224 | do { | ||
225 | if (count < rsize) | ||
226 | rsize = count; | ||
227 | |||
228 | n = p9_client_write(fid, NULL, data+total, *offset+total, | ||
229 | rsize); | ||
230 | if (n <= 0) | ||
231 | break; | ||
232 | count -= n; | ||
233 | total += n; | ||
234 | } while (count > 0); | ||
235 | |||
236 | if (total > 0) { | ||
237 | invalidate_inode_pages2_range(inode->i_mapping, origin, | ||
238 | origin+total); | ||
239 | *offset += total; | ||
172 | } | 240 | } |
173 | 241 | ||
174 | if (*offset > inode->i_size) { | 242 | if (*offset > inode->i_size) { |
@@ -176,7 +244,10 @@ v9fs_file_write(struct file *filp, const char __user * data, | |||
176 | inode->i_blocks = (inode->i_size + 512 - 1) >> 9; | 244 | inode->i_blocks = (inode->i_size + 512 - 1) >> 9; |
177 | } | 245 | } |
178 | 246 | ||
179 | return ret; | 247 | if (n < 0) |
248 | return n; | ||
249 | |||
250 | return total; | ||
180 | } | 251 | } |
181 | 252 | ||
182 | static const struct file_operations v9fs_cached_file_operations = { | 253 | static const struct file_operations v9fs_cached_file_operations = { |