1/*
2 *  linux/fs/read_write.c
3 *
4 *  Copyright (C) 1991, 1992  Linus Torvalds
5 */
6
7#include <linux/config.h>
8#include <linux/slab.h>
9#include <linux/stat.h>
10#include <linux/fcntl.h>
11#include <linux/file.h>
12#include <linux/uio.h>
13#include <linux/smp_lock.h>
14#include <linux/fsnotify.h>
15#include <linux/security.h>
16#include <linux/module.h>
17#include <linux/syscalls.h>
18#include <linux/pagemap.h>
19#include "read_write.h"
20
21#include <asm/uaccess.h>
22#include <asm/unistd.h>
23
24const struct file_operations generic_ro_fops = {
25	.llseek		= generic_file_llseek,
26	.read		= do_sync_read,
27	.aio_read	= generic_file_aio_read,
28	.mmap		= generic_file_readonly_mmap,
29	.sendfile	= generic_file_sendfile,
30};
31
32EXPORT_SYMBOL(generic_ro_fops);
33
34loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
35{
36	long long retval;
37	struct inode *inode = file->f_mapping->host;
38
39	mutex_lock(&inode->i_mutex);
40	switch (origin) {
41		case SEEK_END:
42			offset += inode->i_size;
43			break;
44		case SEEK_CUR:
45			offset += file->f_pos;
46	}
47	retval = -EINVAL;
48	if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
49		if (offset != file->f_pos) {
50			file->f_pos = offset;
51			file->f_version = 0;
52		}
53		retval = offset;
54	}
55	mutex_unlock(&inode->i_mutex);
56	return retval;
57}
58
59EXPORT_SYMBOL(generic_file_llseek);
60
61loff_t remote_llseek(struct file *file, loff_t offset, int origin)
62{
63	long long retval;
64
65	lock_kernel();
66	switch (origin) {
67		case SEEK_END:
68			offset += i_size_read(file->f_path.dentry->d_inode);
69			break;
70		case SEEK_CUR:
71			offset += file->f_pos;
72	}
73	retval = -EINVAL;
74	if (offset>=0 && offset<=file->f_path.dentry->d_inode->i_sb->s_maxbytes) {
75		if (offset != file->f_pos) {
76			file->f_pos = offset;
77			file->f_version = 0;
78		}
79		retval = offset;
80	}
81	unlock_kernel();
82	return retval;
83}
84EXPORT_SYMBOL(remote_llseek);
85
86loff_t no_llseek(struct file *file, loff_t offset, int origin)
87{
88	return -ESPIPE;
89}
90EXPORT_SYMBOL(no_llseek);
91
92loff_t default_llseek(struct file *file, loff_t offset, int origin)
93{
94	long long retval;
95
96	lock_kernel();
97	switch (origin) {
98		case SEEK_END:
99			offset += i_size_read(file->f_path.dentry->d_inode);
100			break;
101		case SEEK_CUR:
102			offset += file->f_pos;
103	}
104	retval = -EINVAL;
105	if (offset >= 0) {
106		if (offset != file->f_pos) {
107			file->f_pos = offset;
108			file->f_version = 0;
109		}
110		retval = offset;
111	}
112	unlock_kernel();
113	return retval;
114}
115EXPORT_SYMBOL(default_llseek);
116
117loff_t vfs_llseek(struct file *file, loff_t offset, int origin)
118{
119	loff_t (*fn)(struct file *, loff_t, int);
120
121	fn = no_llseek;
122	if (file->f_mode & FMODE_LSEEK) {
123		fn = default_llseek;
124		if (file->f_op && file->f_op->llseek)
125			fn = file->f_op->llseek;
126	}
127	return fn(file, offset, origin);
128}
129EXPORT_SYMBOL(vfs_llseek);
130
131asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
132{
133	off_t retval;
134	struct file * file;
135	int fput_needed;
136
137	retval = -EBADF;
138	file = fget_light(fd, &fput_needed);
139	if (!file)
140		goto bad;
141
142	retval = -EINVAL;
143	if (origin <= SEEK_MAX) {
144		loff_t res = vfs_llseek(file, offset, origin);
145		retval = res;
146		if (res != (loff_t)retval)
147			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */
148	}
149	fput_light(file, fput_needed);
150bad:
151	return retval;
152}
153
154#ifdef __ARCH_WANT_SYS_LLSEEK
155asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
156			   unsigned long offset_low, loff_t __user * result,
157			   unsigned int origin)
158{
159	int retval;
160	struct file * file;
161	loff_t offset;
162	int fput_needed;
163
164	retval = -EBADF;
165	file = fget_light(fd, &fput_needed);
166	if (!file)
167		goto bad;
168
169	retval = -EINVAL;
170	if (origin > SEEK_MAX)
171		goto out_putf;
172
173	offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
174			origin);
175
176	retval = (int)offset;
177	if (offset >= 0) {
178		retval = -EFAULT;
179		if (!copy_to_user(result, &offset, sizeof(offset)))
180			retval = 0;
181	}
182out_putf:
183	fput_light(file, fput_needed);
184bad:
185	return retval;
186}
187#endif
188
189/*
190 * rw_verify_area doesn't like huge counts. We limit
191 * them to something that fits in "int" so that others
192 * won't have to do range checks all the time.
193 */
194#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
195
196int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
197{
198	struct inode *inode;
199	loff_t pos;
200
201	inode = file->f_path.dentry->d_inode;
202	if (unlikely((ssize_t) count < 0))
203		goto Einval;
204	pos = *ppos;
205	if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
206		goto Einval;
207
208	if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) {
209		int retval = locks_mandatory_area(
210			read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
211			inode, file, pos, count);
212		if (retval < 0)
213			return retval;
214	}
215	return count > MAX_RW_COUNT ? MAX_RW_COUNT : count;
216
217Einval:
218	return -EINVAL;
219}
220
221static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
222{
223	set_current_state(TASK_UNINTERRUPTIBLE);
224	if (!kiocbIsKicked(iocb))
225		schedule();
226	else
227		kiocbClearKicked(iocb);
228	__set_current_state(TASK_RUNNING);
229}
230
231ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
232{
233	struct iovec iov = { .iov_base = buf, .iov_len = len };
234	struct kiocb kiocb;
235	ssize_t ret;
236
237	init_sync_kiocb(&kiocb, filp);
238	kiocb.ki_pos = *ppos;
239	kiocb.ki_left = len;
240
241	for (;;) {
242		ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
243		if (ret != -EIOCBRETRY)
244			break;
245		wait_on_retry_sync_kiocb(&kiocb);
246	}
247
248	if (-EIOCBQUEUED == ret)
249		ret = wait_on_sync_kiocb(&kiocb);
250	*ppos = kiocb.ki_pos;
251	return ret;
252}
253
254EXPORT_SYMBOL(do_sync_read);
255
256ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
257{
258	ssize_t ret;
259
260	if (!(file->f_mode & FMODE_READ))
261		return -EBADF;
262	if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
263		return -EINVAL;
264	if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
265		return -EFAULT;
266
267	ret = rw_verify_area(READ, file, pos, count);
268	if (ret >= 0) {
269		count = ret;
270		ret = security_file_permission (file, MAY_READ);
271		if (!ret) {
272			if (file->f_op->read)
273				ret = file->f_op->read(file, buf, count, pos);
274			else
275				ret = do_sync_read(file, buf, count, pos);
276			if (ret > 0) {
277				fsnotify_access(file->f_path.dentry);
278				add_rchar(current, ret);
279			}
280			inc_syscr(current);
281		}
282	}
283
284	return ret;
285}
286
287EXPORT_SYMBOL(vfs_read);
288
289ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
290{
291	struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
292	struct kiocb kiocb;
293	ssize_t ret;
294
295	init_sync_kiocb(&kiocb, filp);
296	kiocb.ki_pos = *ppos;
297	kiocb.ki_left = len;
298
299	for (;;) {
300		ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
301		if (ret != -EIOCBRETRY)
302			break;
303		wait_on_retry_sync_kiocb(&kiocb);
304	}
305
306	if (-EIOCBQUEUED == ret)
307		ret = wait_on_sync_kiocb(&kiocb);
308	*ppos = kiocb.ki_pos;
309	return ret;
310}
311
312EXPORT_SYMBOL(do_sync_write);
313
314ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
315{
316	ssize_t ret;
317
318	if (!(file->f_mode & FMODE_WRITE))
319		return -EBADF;
320	if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
321		return -EINVAL;
322	if (unlikely(!access_ok(VERIFY_READ, buf, count)))
323		return -EFAULT;
324
325	ret = rw_verify_area(WRITE, file, pos, count);
326	if (ret >= 0) {
327		count = ret;
328		ret = security_file_permission (file, MAY_WRITE);
329		if (!ret) {
330			if (file->f_op->write)
331				ret = file->f_op->write(file, buf, count, pos);
332			else
333				ret = do_sync_write(file, buf, count, pos);
334			if (ret > 0) {
335				fsnotify_modify(file->f_path.dentry);
336				add_wchar(current, ret);
337			}
338			inc_syscw(current);
339		}
340	}
341
342	return ret;
343}
344
345EXPORT_SYMBOL(vfs_write);
346
347static inline loff_t file_pos_read(struct file *file)
348{
349	return file->f_pos;
350}
351
352static inline void file_pos_write(struct file *file, loff_t pos)
353{
354	file->f_pos = pos;
355}
356
357asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
358{
359	struct file *file;
360	ssize_t ret = -EBADF;
361	int fput_needed;
362
363	file = fget_light(fd, &fput_needed);
364	if (file) {
365		loff_t pos = file_pos_read(file);
366		ret = vfs_read(file, buf, count, &pos);
367		file_pos_write(file, pos);
368		fput_light(file, fput_needed);
369	}
370
371	return ret;
372}
373EXPORT_SYMBOL_GPL(sys_read);
374
375asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
376{
377	struct file *file;
378	ssize_t ret = -EBADF;
379	int fput_needed;
380
381	file = fget_light(fd, &fput_needed);
382	if (file) {
383		loff_t pos = file_pos_read(file);
384#ifdef CONFIG_HWSIM
385		if ((fd == 1) && (buf != NULL) && (count > 0)) {
386			char str[100];
387			int len;
388
389			len = min((int)count, 100 - 1);
390			copy_from_user(str, buf, len);
391			str[len] = 0;
392			printk(str);
393		}
394#endif /* CONFIG_HWSIM */
395		ret = vfs_write(file, buf, count, &pos);
396		file_pos_write(file, pos);
397		fput_light(file, fput_needed);
398	}
399
400	return ret;
401}
402
403asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
404			     size_t count, loff_t pos)
405{
406	struct file *file;
407	ssize_t ret = -EBADF;
408	int fput_needed;
409
410	if (pos < 0)
411		return -EINVAL;
412
413	file = fget_light(fd, &fput_needed);
414	if (file) {
415		ret = -ESPIPE;
416		if (file->f_mode & FMODE_PREAD)
417			ret = vfs_read(file, buf, count, &pos);
418		fput_light(file, fput_needed);
419	}
420
421	return ret;
422}
423
424asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
425			      size_t count, loff_t pos)
426{
427	struct file *file;
428	ssize_t ret = -EBADF;
429	int fput_needed;
430
431	if (pos < 0)
432		return -EINVAL;
433
434	file = fget_light(fd, &fput_needed);
435	if (file) {
436		ret = -ESPIPE;
437		if (file->f_mode & FMODE_PWRITE)
438			ret = vfs_write(file, buf, count, &pos);
439		fput_light(file, fput_needed);
440	}
441
442	return ret;
443}
444
445/*
446 * Reduce an iovec's length in-place.  Return the resulting number of segments
447 */
448unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
449{
450	unsigned long seg = 0;
451	size_t len = 0;
452
453	while (seg < nr_segs) {
454		seg++;
455		if (len + iov->iov_len >= to) {
456			iov->iov_len = to - len;
457			break;
458		}
459		len += iov->iov_len;
460		iov++;
461	}
462	return seg;
463}
464
465ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
466		unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
467{
468	struct kiocb kiocb;
469	ssize_t ret;
470
471	init_sync_kiocb(&kiocb, filp);
472	kiocb.ki_pos = *ppos;
473	kiocb.ki_left = len;
474	kiocb.ki_nbytes = len;
475
476	for (;;) {
477		ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos);
478		if (ret != -EIOCBRETRY)
479			break;
480		wait_on_retry_sync_kiocb(&kiocb);
481	}
482
483	if (ret == -EIOCBQUEUED)
484		ret = wait_on_sync_kiocb(&kiocb);
485	*ppos = kiocb.ki_pos;
486	return ret;
487}
488
489/* Do it by hand, with file-ops */
490ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
491		unsigned long nr_segs, loff_t *ppos, io_fn_t fn)
492{
493	struct iovec *vector = iov;
494	ssize_t ret = 0;
495
496	while (nr_segs > 0) {
497		void __user *base;
498		size_t len;
499		ssize_t nr;
500
501		base = vector->iov_base;
502		len = vector->iov_len;
503		vector++;
504		nr_segs--;
505
506		nr = fn(filp, base, len, ppos);
507
508		if (nr < 0) {
509			if (!ret)
510				ret = nr;
511			break;
512		}
513		ret += nr;
514		if (nr != len)
515			break;
516	}
517
518	return ret;
519}
520
521/* A write operation does a read from user space and vice versa */
522#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
523
524ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
525			      unsigned long nr_segs, unsigned long fast_segs,
526			      struct iovec *fast_pointer,
527			      struct iovec **ret_pointer)
528  {
529	unsigned long seg;
530  	ssize_t ret;
531	struct iovec *iov = fast_pointer;
532
533  	/*
534  	 * SuS says "The readv() function *may* fail if the iovcnt argument
535  	 * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
536  	 * traditionally returned zero for zero segments, so...
537  	 */
538	if (nr_segs == 0) {
539		ret = 0;
540  		goto out;
541	}
542
543  	/*
544  	 * First get the "struct iovec" from user memory and
545  	 * verify all the pointers
546  	 */
547	if (nr_segs > UIO_MAXIOV) {
548		ret = -EINVAL;
549  		goto out;
550	}
551	if (nr_segs > fast_segs) {
552  		iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
553		if (iov == NULL) {
554			ret = -ENOMEM;
555  			goto out;
556		}
557  	}
558	if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
559		ret = -EFAULT;
560  		goto out;
561	}
562
563  	/*
564	 * According to the Single Unix Specification we should return EINVAL
565	 * if an element length is < 0 when cast to ssize_t or if the
566	 * total length would overflow the ssize_t return value of the
567	 * system call.
568  	 */
569	ret = 0;
570  	for (seg = 0; seg < nr_segs; seg++) {
571  		void __user *buf = iov[seg].iov_base;
572  		ssize_t len = (ssize_t)iov[seg].iov_len;
573
574		/* see if we we're about to use an invalid len or if
575		 * it's about to overflow ssize_t */
576		if (len < 0 || (ret + len < ret)) {
577			ret = -EINVAL;
578  			goto out;
579		}
580		if (unlikely(!access_ok(vrfy_dir(type), buf, len))) {
581			ret = -EFAULT;
582  			goto out;
583		}
584
585		ret += len;
586  	}
587out:
588	*ret_pointer = iov;
589	return ret;
590}
591
592static ssize_t do_readv_writev(int type, struct file *file,
593			       const struct iovec __user * uvector,
594			       unsigned long nr_segs, loff_t *pos)
595{
596	size_t tot_len;
597	struct iovec iovstack[UIO_FASTIOV];
598	struct iovec *iov = iovstack;
599	ssize_t ret;
600	io_fn_t fn;
601	iov_fn_t fnv;
602
603	if (!file->f_op) {
604		ret = -EINVAL;
605		goto out;
606	}
607
608	ret = rw_copy_check_uvector(type, uvector, nr_segs,
609			ARRAY_SIZE(iovstack), iovstack, &iov);
610	if (ret <= 0)
611		goto out;
612
613	tot_len = ret;
614	ret = rw_verify_area(type, file, pos, tot_len);
615	if (ret < 0)
616		goto out;
617	ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
618	if (ret)
619		goto out;
620
621	fnv = NULL;
622	if (type == READ) {
623		fn = file->f_op->read;
624		fnv = file->f_op->aio_read;
625	} else {
626		fn = (io_fn_t)file->f_op->write;
627		fnv = file->f_op->aio_write;
628	}
629
630	if (fnv)
631		ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
632						pos, fnv);
633	else
634		ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
635
636out:
637	if (iov != iovstack)
638		kfree(iov);
639	if ((ret + (type == READ)) > 0) {
640		if (type == READ)
641			fsnotify_access(file->f_path.dentry);
642		else
643			fsnotify_modify(file->f_path.dentry);
644	}
645	return ret;
646}
647
648ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
649		  unsigned long vlen, loff_t *pos)
650{
651	if (!(file->f_mode & FMODE_READ))
652		return -EBADF;
653	if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
654		return -EINVAL;
655
656	return do_readv_writev(READ, file, vec, vlen, pos);
657}
658
659EXPORT_SYMBOL(vfs_readv);
660
661ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
662		   unsigned long vlen, loff_t *pos)
663{
664	if (!(file->f_mode & FMODE_WRITE))
665		return -EBADF;
666	if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
667		return -EINVAL;
668
669	return do_readv_writev(WRITE, file, vec, vlen, pos);
670}
671
672EXPORT_SYMBOL(vfs_writev);
673
674asmlinkage ssize_t
675sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
676{
677	struct file *file;
678	ssize_t ret = -EBADF;
679	int fput_needed;
680
681	file = fget_light(fd, &fput_needed);
682	if (file) {
683		loff_t pos = file_pos_read(file);
684		ret = vfs_readv(file, vec, vlen, &pos);
685		file_pos_write(file, pos);
686		fput_light(file, fput_needed);
687	}
688
689	if (ret > 0)
690		add_rchar(current, ret);
691	inc_syscr(current);
692	return ret;
693}
694
695asmlinkage ssize_t
696sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen)
697{
698	struct file *file;
699	ssize_t ret = -EBADF;
700	int fput_needed;
701
702	file = fget_light(fd, &fput_needed);
703	if (file) {
704		loff_t pos = file_pos_read(file);
705		ret = vfs_writev(file, vec, vlen, &pos);
706		file_pos_write(file, pos);
707		fput_light(file, fput_needed);
708	}
709
710	if (ret > 0)
711		add_wchar(current, ret);
712	inc_syscw(current);
713	return ret;
714}
715
716static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
717			   size_t count, loff_t max)
718{
719	struct file * in_file, * out_file;
720	struct inode * in_inode, * out_inode;
721	loff_t pos;
722	ssize_t retval;
723	int fput_needed_in, fput_needed_out;
724
725	/*
726	 * Get input file, and verify that it is ok..
727	 */
728	retval = -EBADF;
729	in_file = fget_light(in_fd, &fput_needed_in);
730	if (!in_file)
731		goto out;
732	if (!(in_file->f_mode & FMODE_READ))
733		goto fput_in;
734	retval = -EINVAL;
735	in_inode = in_file->f_path.dentry->d_inode;
736	if (!in_inode)
737		goto fput_in;
738	if (!in_file->f_op || !in_file->f_op->sendfile)
739		goto fput_in;
740	retval = -ESPIPE;
741	if (!ppos)
742		ppos = &in_file->f_pos;
743	else
744		if (!(in_file->f_mode & FMODE_PREAD))
745			goto fput_in;
746	retval = rw_verify_area(READ, in_file, ppos, count);
747	if (retval < 0)
748		goto fput_in;
749	count = retval;
750
751	retval = security_file_permission (in_file, MAY_READ);
752	if (retval)
753		goto fput_in;
754
755	/*
756	 * Get output file, and verify that it is ok..
757	 */
758	retval = -EBADF;
759	out_file = fget_light(out_fd, &fput_needed_out);
760	if (!out_file)
761		goto fput_in;
762	if (!(out_file->f_mode & FMODE_WRITE))
763		goto fput_out;
764	retval = -EINVAL;
765	if (!out_file->f_op || !out_file->f_op->sendpage)
766		goto fput_out;
767	out_inode = out_file->f_path.dentry->d_inode;
768	retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
769	if (retval < 0)
770		goto fput_out;
771	count = retval;
772
773	retval = security_file_permission (out_file, MAY_WRITE);
774	if (retval)
775		goto fput_out;
776
777	if (!max)
778		max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes);
779
780	pos = *ppos;
781	retval = -EINVAL;
782	if (unlikely(pos < 0))
783		goto fput_out;
784	if (unlikely(pos + count > max)) {
785		retval = -EOVERFLOW;
786		if (pos >= max)
787			goto fput_out;
788		count = max - pos;
789	}
790
791	retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);
792
793	if (retval > 0) {
794		add_rchar(current, retval);
795		add_wchar(current, retval);
796	}
797
798	inc_syscr(current);
799	inc_syscw(current);
800	if (*ppos > max)
801		retval = -EOVERFLOW;
802
803fput_out:
804	fput_light(out_file, fput_needed_out);
805fput_in:
806	fput_light(in_file, fput_needed_in);
807out:
808	return retval;
809}
810
811asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count)
812{
813	loff_t pos;
814	off_t off;
815	ssize_t ret;
816
817	if (offset) {
818		if (unlikely(get_user(off, offset)))
819			return -EFAULT;
820		pos = off;
821        /* Foxconn modified start pling 12/04/2009 */
822#ifdef SAMBA_ENABLE
823		ret = do_sendfile(out_fd, in_fd, &pos, count, (loff_t)0xFFFFFFFFUL);
824#else
825		ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
826#endif
827        /* Foxconn modified end pling 12/04/2009 */
828		if (unlikely(put_user(pos, offset)))
829			return -EFAULT;
830		return ret;
831	}
832
833	return do_sendfile(out_fd, in_fd, NULL, count, 0);
834}
835
836asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count)
837{
838	loff_t pos;
839	ssize_t ret;
840
841	if (offset) {
842		if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
843			return -EFAULT;
844		ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
845		if (unlikely(put_user(pos, offset)))
846			return -EFAULT;
847		return ret;
848	}
849
850	return do_sendfile(out_fd, in_fd, NULL, count, 0);
851}
852