Commit 19cba8abd6ca09527c194864ae651db65cbacfe1
Committed by
Linus Torvalds
1 parent
ad6ce87e5b
Exists in
master
and in
7 other branches
[PATCH] v9fs: remove additional buffer allocation from v9fs_file_read and v9fs_file_write
v9fs_file_read and v9fs_file_write use kmalloc to allocate buffers as big as the data buffer received as parameter. kmalloc cannot be used to allocate buffers bigger than 128K, so reading/writing data in chunks bigger than 128k fails. This patch reorganizes v9fs_file_read and v9fs_file_write to allocate only buffers as big as the maximum data that can be sent in one 9P message. Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Cc: Eric Van Hensbergen <ericvh@gmail.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 1 changed file with 33 additions and 81 deletions Side-by-side Diff
fs/9p/vfs_file.c
... | ... | @@ -175,16 +175,16 @@ |
175 | 175 | } |
176 | 176 | |
177 | 177 | /** |
178 | - * v9fs_read - read from a file (internal) | |
178 | + * v9fs_file_read - read from a file | |
179 | 179 | * @filep: file pointer to read |
180 | 180 | * @data: data buffer to read data into |
181 | 181 | * @count: size of buffer |
182 | 182 | * @offset: offset at which to read data |
183 | 183 | * |
184 | 184 | */ |
185 | - | |
186 | 185 | static ssize_t |
187 | -v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | |
186 | +v9fs_file_read(struct file *filp, char __user * data, size_t count, | |
187 | + loff_t * offset) | |
188 | 188 | { |
189 | 189 | struct inode *inode = filp->f_dentry->d_inode; |
190 | 190 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
... | ... | @@ -194,6 +194,7 @@ |
194 | 194 | int rsize = 0; |
195 | 195 | int result = 0; |
196 | 196 | int total = 0; |
197 | + int n; | |
197 | 198 | |
198 | 199 | dprintk(DEBUG_VFS, "\n"); |
199 | 200 | |
200 | 201 | |
... | ... | @@ -216,10 +217,15 @@ |
216 | 217 | } else |
217 | 218 | *offset += result; |
218 | 219 | |
219 | - /* XXX - extra copy */ | |
220 | - memcpy(buffer, fcall->params.rread.data, result); | |
220 | + n = copy_to_user(data, fcall->params.rread.data, result); | |
221 | + if (n) { | |
222 | + dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n); | |
223 | + kfree(fcall); | |
224 | + return -EFAULT; | |
225 | + } | |
226 | + | |
221 | 227 | count -= result; |
222 | - buffer += result; | |
228 | + data += result; | |
223 | 229 | total += result; |
224 | 230 | |
225 | 231 | kfree(fcall); |
... | ... | @@ -232,42 +238,7 @@ |
232 | 238 | } |
233 | 239 | |
234 | 240 | /** |
235 | - * v9fs_file_read - read from a file | |
236 | - * @filep: file pointer to read | |
237 | - * @data: data buffer to read data into | |
238 | - * @count: size of buffer | |
239 | - * @offset: offset at which to read data | |
240 | - * | |
241 | - */ | |
242 | - | |
243 | -static ssize_t | |
244 | -v9fs_file_read(struct file *filp, char __user * data, size_t count, | |
245 | - loff_t * offset) | |
246 | -{ | |
247 | - int retval = -1; | |
248 | - int ret = 0; | |
249 | - char *buffer; | |
250 | - | |
251 | - buffer = kmalloc(count, GFP_KERNEL); | |
252 | - if (!buffer) | |
253 | - return -ENOMEM; | |
254 | - | |
255 | - retval = v9fs_read(filp, buffer, count, offset); | |
256 | - if (retval > 0) { | |
257 | - if ((ret = copy_to_user(data, buffer, retval)) != 0) { | |
258 | - dprintk(DEBUG_ERROR, "Problem copying to user %d\n", | |
259 | - ret); | |
260 | - retval = ret; | |
261 | - } | |
262 | - } | |
263 | - | |
264 | - kfree(buffer); | |
265 | - | |
266 | - return retval; | |
267 | -} | |
268 | - | |
269 | -/** | |
270 | - * v9fs_write - write to a file | |
241 | + * v9fs_file_write - write to a file | |
271 | 242 | * @filep: file pointer to write |
272 | 243 | * @data: data buffer to write data from |
273 | 244 | * @count: size of buffer |
... | ... | @@ -276,7 +247,8 @@ |
276 | 247 | */ |
277 | 248 | |
278 | 249 | static ssize_t |
279 | -v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) | |
250 | +v9fs_file_write(struct file *filp, const char __user * data, | |
251 | + size_t count, loff_t * offset) | |
280 | 252 | { |
281 | 253 | struct inode *inode = filp->f_dentry->d_inode; |
282 | 254 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
283 | 255 | |
284 | 256 | |
285 | 257 | |
286 | 258 | |
287 | 259 | |
... | ... | @@ -286,30 +258,42 @@ |
286 | 258 | int result = -EIO; |
287 | 259 | int rsize = 0; |
288 | 260 | int total = 0; |
261 | + char *buf; | |
289 | 262 | |
290 | - dprintk(DEBUG_VFS, "data %p count %d offset %x\n", buffer, (int)count, | |
263 | + dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, | |
291 | 264 | (int)*offset); |
292 | 265 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; |
293 | 266 | if (v9fid->iounit != 0 && rsize > v9fid->iounit) |
294 | 267 | rsize = v9fid->iounit; |
295 | 268 | |
296 | - dump_data(buffer, count); | |
269 | + buf = kmalloc(v9ses->maxdata - V9FS_IOHDRSZ, GFP_KERNEL); | |
270 | + if (!buf) | |
271 | + return -ENOMEM; | |
297 | 272 | |
298 | 273 | do { |
299 | 274 | if (count < rsize) |
300 | 275 | rsize = count; |
301 | 276 | |
302 | - result = | |
303 | - v9fs_t_write(v9ses, fid, *offset, rsize, buffer, &fcall); | |
277 | + result = copy_from_user(buf, data, rsize); | |
278 | + if (result) { | |
279 | + dprintk(DEBUG_ERROR, "Problem copying from user\n"); | |
280 | + kfree(buf); | |
281 | + return -EFAULT; | |
282 | + } | |
283 | + | |
284 | + dump_data(buf, rsize); | |
285 | + result = v9fs_t_write(v9ses, fid, *offset, rsize, buf, &fcall); | |
304 | 286 | if (result < 0) { |
305 | 287 | eprintk(KERN_ERR, "error while writing: %s(%d)\n", |
306 | 288 | FCALL_ERROR(fcall), result); |
307 | 289 | kfree(fcall); |
290 | + kfree(buf); | |
308 | 291 | return result; |
309 | 292 | } else |
310 | 293 | *offset += result; |
311 | 294 | |
312 | 295 | kfree(fcall); |
296 | + fcall = NULL; | |
313 | 297 | |
314 | 298 | if (result != rsize) { |
315 | 299 | eprintk(KERN_ERR, |
316 | 300 | |
317 | 301 | |
... | ... | @@ -319,44 +303,12 @@ |
319 | 303 | } |
320 | 304 | |
321 | 305 | count -= result; |
322 | - buffer += result; | |
306 | + data += result; | |
323 | 307 | total += result; |
324 | 308 | } while (count); |
325 | 309 | |
310 | + kfree(buf); | |
326 | 311 | return total; |
327 | -} | |
328 | - | |
329 | -/** | |
330 | - * v9fs_file_write - write to a file | |
331 | - * @filep: file pointer to write | |
332 | - * @data: data buffer to write data from | |
333 | - * @count: size of buffer | |
334 | - * @offset: offset at which to write data | |
335 | - * | |
336 | - */ | |
337 | - | |
338 | -static ssize_t | |
339 | -v9fs_file_write(struct file *filp, const char __user * data, | |
340 | - size_t count, loff_t * offset) | |
341 | -{ | |
342 | - int ret = -1; | |
343 | - char *buffer; | |
344 | - | |
345 | - buffer = kmalloc(count, GFP_KERNEL); | |
346 | - if (buffer == NULL) | |
347 | - return -ENOMEM; | |
348 | - | |
349 | - ret = copy_from_user(buffer, data, count); | |
350 | - if (ret) { | |
351 | - dprintk(DEBUG_ERROR, "Problem copying from user\n"); | |
352 | - ret = -EFAULT; | |
353 | - } else { | |
354 | - ret = v9fs_write(filp, buffer, count, offset); | |
355 | - } | |
356 | - | |
357 | - kfree(buffer); | |
358 | - | |
359 | - return ret; | |
360 | 312 | } |
361 | 313 | |
362 | 314 | struct file_operations v9fs_file_operations = { |