Commit 19cba8abd6ca09527c194864ae651db65cbacfe1

Authored by Latchesar Ionkov
Committed by Linus Torvalds
1 parent ad6ce87e5b

[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

... ... @@ -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 = {