aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLatchesar Ionkov <lucho@ionkov.net>2005-10-11 11:29:03 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-11 12:46:54 -0400
commit19cba8abd6ca09527c194864ae651db65cbacfe1 (patch)
tree3d59a1e147b2701d0957bef392e2fda441d5143f /fs
parentad6ce87e5bd4440a6ce9aa9f8cda795b9e902eff (diff)
[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>
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/vfs_file.c114
1 files changed, 33 insertions, 81 deletions
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index a4799e971d1c..bbc3cc63854f 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -175,16 +175,16 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
175} 175}
176 176
177/** 177/**
178 * v9fs_read - read from a file (internal) 178 * v9fs_file_read - read from a file
179 * @filep: file pointer to read 179 * @filep: file pointer to read
180 * @data: data buffer to read data into 180 * @data: data buffer to read data into
181 * @count: size of buffer 181 * @count: size of buffer
182 * @offset: offset at which to read data 182 * @offset: offset at which to read data
183 * 183 *
184 */ 184 */
185
186static ssize_t 185static ssize_t
187v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) 186v9fs_file_read(struct file *filp, char __user * data, size_t count,
187 loff_t * offset)
188{ 188{
189 struct inode *inode = filp->f_dentry->d_inode; 189 struct inode *inode = filp->f_dentry->d_inode;
190 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 190 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
@@ -194,6 +194,7 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset)
194 int rsize = 0; 194 int rsize = 0;
195 int result = 0; 195 int result = 0;
196 int total = 0; 196 int total = 0;
197 int n;
197 198
198 dprintk(DEBUG_VFS, "\n"); 199 dprintk(DEBUG_VFS, "\n");
199 200
@@ -216,10 +217,15 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset)
216 } else 217 } else
217 *offset += result; 218 *offset += result;
218 219
219 /* XXX - extra copy */ 220 n = copy_to_user(data, fcall->params.rread.data, result);
220 memcpy(buffer, 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 count -= result; 227 count -= result;
222 buffer += result; 228 data += result;
223 total += result; 229 total += result;
224 230
225 kfree(fcall); 231 kfree(fcall);
@@ -232,42 +238,7 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset)
232} 238}
233 239
234/** 240/**
235 * v9fs_file_read - read from a file 241 * v9fs_file_write - write to 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
243static ssize_t
244v9fs_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
271 * @filep: file pointer to write 242 * @filep: file pointer to write
272 * @data: data buffer to write data from 243 * @data: data buffer to write data from
273 * @count: size of buffer 244 * @count: size of buffer
@@ -276,7 +247,8 @@ v9fs_file_read(struct file *filp, char __user * data, size_t count,
276 */ 247 */
277 248
278static ssize_t 249static ssize_t
279v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) 250v9fs_file_write(struct file *filp, const char __user * data,
251 size_t count, loff_t * offset)
280{ 252{
281 struct inode *inode = filp->f_dentry->d_inode; 253 struct inode *inode = filp->f_dentry->d_inode;
282 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 254 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
@@ -286,30 +258,42 @@ v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset)
286 int result = -EIO; 258 int result = -EIO;
287 int rsize = 0; 259 int rsize = 0;
288 int total = 0; 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 (int)*offset); 264 (int)*offset);
292 rsize = v9ses->maxdata - V9FS_IOHDRSZ; 265 rsize = v9ses->maxdata - V9FS_IOHDRSZ;
293 if (v9fid->iounit != 0 && rsize > v9fid->iounit) 266 if (v9fid->iounit != 0 && rsize > v9fid->iounit)
294 rsize = v9fid->iounit; 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 do { 273 do {
299 if (count < rsize) 274 if (count < rsize)
300 rsize = count; 275 rsize = count;
301 276
302 result = 277 result = copy_from_user(buf, data, rsize);
303 v9fs_t_write(v9ses, fid, *offset, rsize, buffer, &fcall); 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 if (result < 0) { 286 if (result < 0) {
305 eprintk(KERN_ERR, "error while writing: %s(%d)\n", 287 eprintk(KERN_ERR, "error while writing: %s(%d)\n",
306 FCALL_ERROR(fcall), result); 288 FCALL_ERROR(fcall), result);
307 kfree(fcall); 289 kfree(fcall);
290 kfree(buf);
308 return result; 291 return result;
309 } else 292 } else
310 *offset += result; 293 *offset += result;
311 294
312 kfree(fcall); 295 kfree(fcall);
296 fcall = NULL;
313 297
314 if (result != rsize) { 298 if (result != rsize) {
315 eprintk(KERN_ERR, 299 eprintk(KERN_ERR,
@@ -319,46 +303,14 @@ v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset)
319 } 303 }
320 304
321 count -= result; 305 count -= result;
322 buffer += result; 306 data += result;
323 total += result; 307 total += result;
324 } while (count); 308 } while (count);
325 309
310 kfree(buf);
326 return total; 311 return total;
327} 312}
328 313
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
338static ssize_t
339v9fs_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}
361
362struct file_operations v9fs_file_operations = { 314struct file_operations v9fs_file_operations = {
363 .llseek = generic_file_llseek, 315 .llseek = generic_file_llseek,
364 .read = v9fs_file_read, 316 .read = v9fs_file_read,