aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ntfs/file.c21
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c22
-rw-r--r--include/linux/fs.h2
-rw-r--r--mm/filemap.c82
4 files changed, 53 insertions, 74 deletions
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index dbbac5593106..621de369e6f8 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -2129,28 +2129,13 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb,
2129 struct address_space *mapping = file->f_mapping; 2129 struct address_space *mapping = file->f_mapping;
2130 struct inode *inode = mapping->host; 2130 struct inode *inode = mapping->host;
2131 loff_t pos; 2131 loff_t pos;
2132 unsigned long seg;
2133 size_t count; /* after file limit checks */ 2132 size_t count; /* after file limit checks */
2134 ssize_t written, err; 2133 ssize_t written, err;
2135 2134
2136 count = 0; 2135 count = 0;
2137 for (seg = 0; seg < nr_segs; seg++) { 2136 err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
2138 const struct iovec *iv = &iov[seg]; 2137 if (err)
2139 /* 2138 return err;
2140 * If any segment has a negative length, or the cumulative
2141 * length ever wraps negative then return -EINVAL.
2142 */
2143 count += iv->iov_len;
2144 if (unlikely((ssize_t)(count|iv->iov_len) < 0))
2145 return -EINVAL;
2146 if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
2147 continue;
2148 if (!seg)
2149 return -EFAULT;
2150 nr_segs = seg;
2151 count -= iv->iov_len; /* This segment is no good */
2152 break;
2153 }
2154 pos = *ppos; 2139 pos = *ppos;
2155 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); 2140 vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
2156 /* We can write back this queue in page reclaim. */ 2141 /* We can write back this queue in page reclaim. */
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index ff8d64eba9f8..558076dd0752 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -639,7 +639,6 @@ xfs_write(
639 xfs_fsize_t isize, new_size; 639 xfs_fsize_t isize, new_size;
640 xfs_iocore_t *io; 640 xfs_iocore_t *io;
641 bhv_vnode_t *vp; 641 bhv_vnode_t *vp;
642 unsigned long seg;
643 int iolock; 642 int iolock;
644 int eventsent = 0; 643 int eventsent = 0;
645 bhv_vrwlock_t locktype; 644 bhv_vrwlock_t locktype;
@@ -652,24 +651,9 @@ xfs_write(
652 vp = BHV_TO_VNODE(bdp); 651 vp = BHV_TO_VNODE(bdp);
653 xip = XFS_BHVTOI(bdp); 652 xip = XFS_BHVTOI(bdp);
654 653
655 for (seg = 0; seg < segs; seg++) { 654 error = generic_segment_checks(iovp, &segs, &ocount, VERIFY_READ);
656 const struct iovec *iv = &iovp[seg]; 655 if (error)
657 656 return error;
658 /*
659 * If any segment has a negative length, or the cumulative
660 * length ever wraps negative then return -EINVAL.
661 */
662 ocount += iv->iov_len;
663 if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
664 return -EINVAL;
665 if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
666 continue;
667 if (seg == 0)
668 return -EFAULT;
669 segs = seg;
670 ocount -= iv->iov_len; /* This segment is no good */
671 break;
672 }
673 657
674 count = ocount; 658 count = ocount;
675 pos = *offset; 659 pos = *offset;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index bc6d27cecaac..020a8426e10a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1735,6 +1735,8 @@ extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor
1735extern void do_generic_mapping_read(struct address_space *mapping, 1735extern void do_generic_mapping_read(struct address_space *mapping,
1736 struct file_ra_state *, struct file *, 1736 struct file_ra_state *, struct file *,
1737 loff_t *, read_descriptor_t *, read_actor_t); 1737 loff_t *, read_descriptor_t *, read_actor_t);
1738extern int generic_segment_checks(const struct iovec *iov,
1739 unsigned long *nr_segs, size_t *count, int access_flags);
1738 1740
1739/* fs/splice.c */ 1741/* fs/splice.c */
1740extern ssize_t generic_file_splice_read(struct file *, loff_t *, 1742extern ssize_t generic_file_splice_read(struct file *, loff_t *,
diff --git a/mm/filemap.c b/mm/filemap.c
index 5631d6b2a62d..3e49fe13d6ac 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1110,6 +1110,45 @@ success:
1110 return size; 1110 return size;
1111} 1111}
1112 1112
1113/*
1114 * Performs necessary checks before doing a write
1115 * @iov: io vector request
1116 * @nr_segs: number of segments in the iovec
1117 * @count: number of bytes to write
1118 * @access_flags: type of access: %VERIFY_READ or %VERIFY_WRITE
1119 *
1120 * Adjust number of segments and amount of bytes to write (nr_segs should be
1121 * properly initialized first). Returns appropriate error code that caller
1122 * should return or zero in case that write should be allowed.
1123 */
1124int generic_segment_checks(const struct iovec *iov,
1125 unsigned long *nr_segs, size_t *count, int access_flags)
1126{
1127 unsigned long seg;
1128 size_t cnt = 0;
1129 for (seg = 0; seg < *nr_segs; seg++) {
1130 const struct iovec *iv = &iov[seg];
1131
1132 /*
1133 * If any segment has a negative length, or the cumulative
1134 * length ever wraps negative then return -EINVAL.
1135 */
1136 cnt += iv->iov_len;
1137 if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
1138 return -EINVAL;
1139 if (access_ok(access_flags, iv->iov_base, iv->iov_len))
1140 continue;
1141 if (seg == 0)
1142 return -EFAULT;
1143 *nr_segs = seg;
1144 cnt -= iv->iov_len; /* This segment is no good */
1145 break;
1146 }
1147 *count = cnt;
1148 return 0;
1149}
1150EXPORT_SYMBOL(generic_segment_checks);
1151
1113/** 1152/**
1114 * generic_file_aio_read - generic filesystem read routine 1153 * generic_file_aio_read - generic filesystem read routine
1115 * @iocb: kernel I/O control block 1154 * @iocb: kernel I/O control block
@@ -1131,24 +1170,9 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
1131 loff_t *ppos = &iocb->ki_pos; 1170 loff_t *ppos = &iocb->ki_pos;
1132 1171
1133 count = 0; 1172 count = 0;
1134 for (seg = 0; seg < nr_segs; seg++) { 1173 retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
1135 const struct iovec *iv = &iov[seg]; 1174 if (retval)
1136 1175 return retval;
1137 /*
1138 * If any segment has a negative length, or the cumulative
1139 * length ever wraps negative then return -EINVAL.
1140 */
1141 count += iv->iov_len;
1142 if (unlikely((ssize_t)(count|iv->iov_len) < 0))
1143 return -EINVAL;
1144 if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
1145 continue;
1146 if (seg == 0)
1147 return -EFAULT;
1148 nr_segs = seg;
1149 count -= iv->iov_len; /* This segment is no good */
1150 break;
1151 }
1152 1176
1153 /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ 1177 /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
1154 if (filp->f_flags & O_DIRECT) { 1178 if (filp->f_flags & O_DIRECT) {
@@ -2218,30 +2242,14 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
2218 size_t ocount; /* original count */ 2242 size_t ocount; /* original count */
2219 size_t count; /* after file limit checks */ 2243 size_t count; /* after file limit checks */
2220 struct inode *inode = mapping->host; 2244 struct inode *inode = mapping->host;
2221 unsigned long seg;
2222 loff_t pos; 2245 loff_t pos;
2223 ssize_t written; 2246 ssize_t written;
2224 ssize_t err; 2247 ssize_t err;
2225 2248
2226 ocount = 0; 2249 ocount = 0;
2227 for (seg = 0; seg < nr_segs; seg++) { 2250 err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
2228 const struct iovec *iv = &iov[seg]; 2251 if (err)
2229 2252 return err;
2230 /*
2231 * If any segment has a negative length, or the cumulative
2232 * length ever wraps negative then return -EINVAL.
2233 */
2234 ocount += iv->iov_len;
2235 if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
2236 return -EINVAL;
2237 if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
2238 continue;
2239 if (seg == 0)
2240 return -EFAULT;
2241 nr_segs = seg;
2242 ocount -= iv->iov_len; /* This segment is no good */
2243 break;
2244 }
2245 2253
2246 count = ocount; 2254 count = ocount;
2247 pos = *ppos; 2255 pos = *ppos;