diff options
-rw-r--r-- | block/blk-map.c | 47 | ||||
-rw-r--r-- | fs/ecryptfs/file.c | 71 | ||||
-rw-r--r-- | fs/isofs/rock.c | 13 | ||||
-rw-r--r-- | fs/namei.c | 59 | ||||
-rw-r--r-- | fs/open.c | 12 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 4 | ||||
-rw-r--r-- | fs/splice.c | 3 | ||||
-rw-r--r-- | include/linux/dcache.h | 12 | ||||
-rw-r--r-- | include/linux/namei.h | 2 | ||||
-rw-r--r-- | include/linux/uio.h | 1 | ||||
-rw-r--r-- | lib/iov_iter.c | 19 |
11 files changed, 152 insertions, 91 deletions
diff --git a/block/blk-map.c b/block/blk-map.c index a54f0543b956..b9f88b7751fb 100644 --- a/block/blk-map.c +++ b/block/blk-map.c | |||
@@ -9,24 +9,6 @@ | |||
9 | 9 | ||
10 | #include "blk.h" | 10 | #include "blk.h" |
11 | 11 | ||
12 | static bool iovec_gap_to_prv(struct request_queue *q, | ||
13 | struct iovec *prv, struct iovec *cur) | ||
14 | { | ||
15 | unsigned long prev_end; | ||
16 | |||
17 | if (!queue_virt_boundary(q)) | ||
18 | return false; | ||
19 | |||
20 | if (prv->iov_base == NULL && prv->iov_len == 0) | ||
21 | /* prv is not set - don't check */ | ||
22 | return false; | ||
23 | |||
24 | prev_end = (unsigned long)(prv->iov_base + prv->iov_len); | ||
25 | |||
26 | return (((unsigned long)cur->iov_base & queue_virt_boundary(q)) || | ||
27 | prev_end & queue_virt_boundary(q)); | ||
28 | } | ||
29 | |||
30 | int blk_rq_append_bio(struct request_queue *q, struct request *rq, | 12 | int blk_rq_append_bio(struct request_queue *q, struct request *rq, |
31 | struct bio *bio) | 13 | struct bio *bio) |
32 | { | 14 | { |
@@ -125,31 +107,18 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, | |||
125 | struct rq_map_data *map_data, | 107 | struct rq_map_data *map_data, |
126 | const struct iov_iter *iter, gfp_t gfp_mask) | 108 | const struct iov_iter *iter, gfp_t gfp_mask) |
127 | { | 109 | { |
128 | struct iovec iov, prv = {.iov_base = NULL, .iov_len = 0}; | 110 | bool copy = false; |
129 | bool copy = (q->dma_pad_mask & iter->count) || map_data; | 111 | unsigned long align = q->dma_pad_mask | queue_dma_alignment(q); |
130 | struct bio *bio = NULL; | 112 | struct bio *bio = NULL; |
131 | struct iov_iter i; | 113 | struct iov_iter i; |
132 | int ret; | 114 | int ret; |
133 | 115 | ||
134 | if (!iter || !iter->count) | 116 | if (map_data) |
135 | return -EINVAL; | 117 | copy = true; |
136 | 118 | else if (iov_iter_alignment(iter) & align) | |
137 | iov_for_each(iov, i, *iter) { | 119 | copy = true; |
138 | unsigned long uaddr = (unsigned long) iov.iov_base; | 120 | else if (queue_virt_boundary(q)) |
139 | 121 | copy = queue_virt_boundary(q) & iov_iter_gap_alignment(iter); | |
140 | if (!iov.iov_len) | ||
141 | return -EINVAL; | ||
142 | |||
143 | /* | ||
144 | * Keep going so we check length of all segments | ||
145 | */ | ||
146 | if ((uaddr & queue_dma_alignment(q)) || | ||
147 | iovec_gap_to_prv(q, &prv, &iov)) | ||
148 | copy = true; | ||
149 | |||
150 | prv.iov_base = iov.iov_base; | ||
151 | prv.iov_len = iov.iov_len; | ||
152 | } | ||
153 | 122 | ||
154 | i = *iter; | 123 | i = *iter; |
155 | do { | 124 | do { |
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index feef8a9c4de7..f02404052b7b 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c | |||
@@ -112,7 +112,6 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx) | |||
112 | .sb = inode->i_sb, | 112 | .sb = inode->i_sb, |
113 | }; | 113 | }; |
114 | lower_file = ecryptfs_file_to_lower(file); | 114 | lower_file = ecryptfs_file_to_lower(file); |
115 | lower_file->f_pos = ctx->pos; | ||
116 | rc = iterate_dir(lower_file, &buf.ctx); | 115 | rc = iterate_dir(lower_file, &buf.ctx); |
117 | ctx->pos = buf.ctx.pos; | 116 | ctx->pos = buf.ctx.pos; |
118 | if (rc < 0) | 117 | if (rc < 0) |
@@ -223,14 +222,6 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
223 | } | 222 | } |
224 | ecryptfs_set_file_lower( | 223 | ecryptfs_set_file_lower( |
225 | file, ecryptfs_inode_to_private(inode)->lower_file); | 224 | file, ecryptfs_inode_to_private(inode)->lower_file); |
226 | if (d_is_dir(ecryptfs_dentry)) { | ||
227 | ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); | ||
228 | mutex_lock(&crypt_stat->cs_mutex); | ||
229 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); | ||
230 | mutex_unlock(&crypt_stat->cs_mutex); | ||
231 | rc = 0; | ||
232 | goto out; | ||
233 | } | ||
234 | rc = read_or_initialize_metadata(ecryptfs_dentry); | 225 | rc = read_or_initialize_metadata(ecryptfs_dentry); |
235 | if (rc) | 226 | if (rc) |
236 | goto out_put; | 227 | goto out_put; |
@@ -247,6 +238,45 @@ out: | |||
247 | return rc; | 238 | return rc; |
248 | } | 239 | } |
249 | 240 | ||
241 | /** | ||
242 | * ecryptfs_dir_open | ||
243 | * @inode: inode speciying file to open | ||
244 | * @file: Structure to return filled in | ||
245 | * | ||
246 | * Opens the file specified by inode. | ||
247 | * | ||
248 | * Returns zero on success; non-zero otherwise | ||
249 | */ | ||
250 | static int ecryptfs_dir_open(struct inode *inode, struct file *file) | ||
251 | { | ||
252 | struct dentry *ecryptfs_dentry = file->f_path.dentry; | ||
253 | /* Private value of ecryptfs_dentry allocated in | ||
254 | * ecryptfs_lookup() */ | ||
255 | struct ecryptfs_file_info *file_info; | ||
256 | struct file *lower_file; | ||
257 | |||
258 | /* Released in ecryptfs_release or end of function if failure */ | ||
259 | file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); | ||
260 | ecryptfs_set_file_private(file, file_info); | ||
261 | if (unlikely(!file_info)) { | ||
262 | ecryptfs_printk(KERN_ERR, | ||
263 | "Error attempting to allocate memory\n"); | ||
264 | return -ENOMEM; | ||
265 | } | ||
266 | lower_file = dentry_open(ecryptfs_dentry_to_lower_path(ecryptfs_dentry), | ||
267 | file->f_flags, current_cred()); | ||
268 | if (IS_ERR(lower_file)) { | ||
269 | printk(KERN_ERR "%s: Error attempting to initialize " | ||
270 | "the lower file for the dentry with name " | ||
271 | "[%pd]; rc = [%ld]\n", __func__, | ||
272 | ecryptfs_dentry, PTR_ERR(lower_file)); | ||
273 | kmem_cache_free(ecryptfs_file_info_cache, file_info); | ||
274 | return PTR_ERR(lower_file); | ||
275 | } | ||
276 | ecryptfs_set_file_lower(file, lower_file); | ||
277 | return 0; | ||
278 | } | ||
279 | |||
250 | static int ecryptfs_flush(struct file *file, fl_owner_t td) | 280 | static int ecryptfs_flush(struct file *file, fl_owner_t td) |
251 | { | 281 | { |
252 | struct file *lower_file = ecryptfs_file_to_lower(file); | 282 | struct file *lower_file = ecryptfs_file_to_lower(file); |
@@ -267,6 +297,19 @@ static int ecryptfs_release(struct inode *inode, struct file *file) | |||
267 | return 0; | 297 | return 0; |
268 | } | 298 | } |
269 | 299 | ||
300 | static int ecryptfs_dir_release(struct inode *inode, struct file *file) | ||
301 | { | ||
302 | fput(ecryptfs_file_to_lower(file)); | ||
303 | kmem_cache_free(ecryptfs_file_info_cache, | ||
304 | ecryptfs_file_to_private(file)); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static loff_t ecryptfs_dir_llseek(struct file *file, loff_t offset, int whence) | ||
309 | { | ||
310 | return vfs_llseek(ecryptfs_file_to_lower(file), offset, whence); | ||
311 | } | ||
312 | |||
270 | static int | 313 | static int |
271 | ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) | 314 | ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
272 | { | 315 | { |
@@ -346,20 +389,16 @@ const struct file_operations ecryptfs_dir_fops = { | |||
346 | #ifdef CONFIG_COMPAT | 389 | #ifdef CONFIG_COMPAT |
347 | .compat_ioctl = ecryptfs_compat_ioctl, | 390 | .compat_ioctl = ecryptfs_compat_ioctl, |
348 | #endif | 391 | #endif |
349 | .open = ecryptfs_open, | 392 | .open = ecryptfs_dir_open, |
350 | .flush = ecryptfs_flush, | 393 | .release = ecryptfs_dir_release, |
351 | .release = ecryptfs_release, | ||
352 | .fsync = ecryptfs_fsync, | 394 | .fsync = ecryptfs_fsync, |
353 | .fasync = ecryptfs_fasync, | 395 | .llseek = ecryptfs_dir_llseek, |
354 | .splice_read = generic_file_splice_read, | ||
355 | .llseek = default_llseek, | ||
356 | }; | 396 | }; |
357 | 397 | ||
358 | const struct file_operations ecryptfs_main_fops = { | 398 | const struct file_operations ecryptfs_main_fops = { |
359 | .llseek = generic_file_llseek, | 399 | .llseek = generic_file_llseek, |
360 | .read_iter = ecryptfs_read_update_atime, | 400 | .read_iter = ecryptfs_read_update_atime, |
361 | .write_iter = generic_file_write_iter, | 401 | .write_iter = generic_file_write_iter, |
362 | .iterate = ecryptfs_readdir, | ||
363 | .unlocked_ioctl = ecryptfs_unlocked_ioctl, | 402 | .unlocked_ioctl = ecryptfs_unlocked_ioctl, |
364 | #ifdef CONFIG_COMPAT | 403 | #ifdef CONFIG_COMPAT |
365 | .compat_ioctl = ecryptfs_compat_ioctl, | 404 | .compat_ioctl = ecryptfs_compat_ioctl, |
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 5384ceb35b1c..98b3eb7d8eaf 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c | |||
@@ -203,6 +203,8 @@ int get_rock_ridge_filename(struct iso_directory_record *de, | |||
203 | int retnamlen = 0; | 203 | int retnamlen = 0; |
204 | int truncate = 0; | 204 | int truncate = 0; |
205 | int ret = 0; | 205 | int ret = 0; |
206 | char *p; | ||
207 | int len; | ||
206 | 208 | ||
207 | if (!ISOFS_SB(inode->i_sb)->s_rock) | 209 | if (!ISOFS_SB(inode->i_sb)->s_rock) |
208 | return 0; | 210 | return 0; |
@@ -267,12 +269,17 @@ repeat: | |||
267 | rr->u.NM.flags); | 269 | rr->u.NM.flags); |
268 | break; | 270 | break; |
269 | } | 271 | } |
270 | if ((strlen(retname) + rr->len - 5) >= 254) { | 272 | len = rr->len - 5; |
273 | if (retnamlen + len >= 254) { | ||
271 | truncate = 1; | 274 | truncate = 1; |
272 | break; | 275 | break; |
273 | } | 276 | } |
274 | strncat(retname, rr->u.NM.name, rr->len - 5); | 277 | p = memchr(rr->u.NM.name, '\0', len); |
275 | retnamlen += rr->len - 5; | 278 | if (unlikely(p)) |
279 | len = p - rr->u.NM.name; | ||
280 | memcpy(retname + retnamlen, rr->u.NM.name, len); | ||
281 | retnamlen += len; | ||
282 | retname[retnamlen] = '\0'; | ||
276 | break; | 283 | break; |
277 | case SIG('R', 'E'): | 284 | case SIG('R', 'E'): |
278 | kfree(rs.buffer); | 285 | kfree(rs.buffer); |
diff --git a/fs/namei.c b/fs/namei.c index 1d9ca2d5dff6..30145f8f21ed 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2267,6 +2267,33 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
2267 | EXPORT_SYMBOL(vfs_path_lookup); | 2267 | EXPORT_SYMBOL(vfs_path_lookup); |
2268 | 2268 | ||
2269 | /** | 2269 | /** |
2270 | * lookup_hash - lookup single pathname component on already hashed name | ||
2271 | * @name: name and hash to lookup | ||
2272 | * @base: base directory to lookup from | ||
2273 | * | ||
2274 | * The name must have been verified and hashed (see lookup_one_len()). Using | ||
2275 | * this after just full_name_hash() is unsafe. | ||
2276 | * | ||
2277 | * This function also doesn't check for search permission on base directory. | ||
2278 | * | ||
2279 | * Use lookup_one_len_unlocked() instead, unless you really know what you are | ||
2280 | * doing. | ||
2281 | * | ||
2282 | * Do not hold i_mutex; this helper takes i_mutex if necessary. | ||
2283 | */ | ||
2284 | struct dentry *lookup_hash(const struct qstr *name, struct dentry *base) | ||
2285 | { | ||
2286 | struct dentry *ret; | ||
2287 | |||
2288 | ret = lookup_dcache(name, base, 0); | ||
2289 | if (!ret) | ||
2290 | ret = lookup_slow(name, base, 0); | ||
2291 | |||
2292 | return ret; | ||
2293 | } | ||
2294 | EXPORT_SYMBOL(lookup_hash); | ||
2295 | |||
2296 | /** | ||
2270 | * lookup_one_len - filesystem helper to lookup single pathname component | 2297 | * lookup_one_len - filesystem helper to lookup single pathname component |
2271 | * @name: pathname component to lookup | 2298 | * @name: pathname component to lookup |
2272 | * @base: base directory to lookup from | 2299 | * @base: base directory to lookup from |
@@ -2337,7 +2364,6 @@ struct dentry *lookup_one_len_unlocked(const char *name, | |||
2337 | struct qstr this; | 2364 | struct qstr this; |
2338 | unsigned int c; | 2365 | unsigned int c; |
2339 | int err; | 2366 | int err; |
2340 | struct dentry *ret; | ||
2341 | 2367 | ||
2342 | this.name = name; | 2368 | this.name = name; |
2343 | this.len = len; | 2369 | this.len = len; |
@@ -2369,10 +2395,7 @@ struct dentry *lookup_one_len_unlocked(const char *name, | |||
2369 | if (err) | 2395 | if (err) |
2370 | return ERR_PTR(err); | 2396 | return ERR_PTR(err); |
2371 | 2397 | ||
2372 | ret = lookup_dcache(&this, base, 0); | 2398 | return lookup_hash(&this, base); |
2373 | if (!ret) | ||
2374 | ret = lookup_slow(&this, base, 0); | ||
2375 | return ret; | ||
2376 | } | 2399 | } |
2377 | EXPORT_SYMBOL(lookup_one_len_unlocked); | 2400 | EXPORT_SYMBOL(lookup_one_len_unlocked); |
2378 | 2401 | ||
@@ -2942,22 +2965,10 @@ no_open: | |||
2942 | dentry = lookup_real(dir, dentry, nd->flags); | 2965 | dentry = lookup_real(dir, dentry, nd->flags); |
2943 | if (IS_ERR(dentry)) | 2966 | if (IS_ERR(dentry)) |
2944 | return PTR_ERR(dentry); | 2967 | return PTR_ERR(dentry); |
2945 | 2968 | } | |
2946 | if (create_error) { | 2969 | if (create_error && !dentry->d_inode) { |
2947 | int open_flag = op->open_flag; | 2970 | error = create_error; |
2948 | 2971 | goto out; | |
2949 | error = create_error; | ||
2950 | if ((open_flag & O_EXCL)) { | ||
2951 | if (!dentry->d_inode) | ||
2952 | goto out; | ||
2953 | } else if (!dentry->d_inode) { | ||
2954 | goto out; | ||
2955 | } else if ((open_flag & O_TRUNC) && | ||
2956 | d_is_reg(dentry)) { | ||
2957 | goto out; | ||
2958 | } | ||
2959 | /* will fail later, go on to get the right error */ | ||
2960 | } | ||
2961 | } | 2972 | } |
2962 | looked_up: | 2973 | looked_up: |
2963 | path->dentry = dentry; | 2974 | path->dentry = dentry; |
@@ -4213,7 +4224,11 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
4213 | bool new_is_dir = false; | 4224 | bool new_is_dir = false; |
4214 | unsigned max_links = new_dir->i_sb->s_max_links; | 4225 | unsigned max_links = new_dir->i_sb->s_max_links; |
4215 | 4226 | ||
4216 | if (source == target) | 4227 | /* |
4228 | * Check source == target. | ||
4229 | * On overlayfs need to look at underlying inodes. | ||
4230 | */ | ||
4231 | if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0)) | ||
4217 | return 0; | 4232 | return 0; |
4218 | 4233 | ||
4219 | error = may_delete(old_dir, old_dentry, is_dir); | 4234 | error = may_delete(old_dir, old_dentry, is_dir); |
@@ -840,16 +840,12 @@ EXPORT_SYMBOL(file_path); | |||
840 | int vfs_open(const struct path *path, struct file *file, | 840 | int vfs_open(const struct path *path, struct file *file, |
841 | const struct cred *cred) | 841 | const struct cred *cred) |
842 | { | 842 | { |
843 | struct dentry *dentry = path->dentry; | 843 | struct inode *inode = vfs_select_inode(path->dentry, file->f_flags); |
844 | struct inode *inode = dentry->d_inode; | ||
845 | 844 | ||
846 | file->f_path = *path; | 845 | if (IS_ERR(inode)) |
847 | if (dentry->d_flags & DCACHE_OP_SELECT_INODE) { | 846 | return PTR_ERR(inode); |
848 | inode = dentry->d_op->d_select_inode(dentry, file->f_flags); | ||
849 | if (IS_ERR(inode)) | ||
850 | return PTR_ERR(inode); | ||
851 | } | ||
852 | 847 | ||
848 | file->f_path = *path; | ||
853 | return do_dentry_open(file, inode, NULL, cred); | 849 | return do_dentry_open(file, inode, NULL, cred); |
854 | } | 850 | } |
855 | 851 | ||
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 5d972e6cd3fe..791235e03d17 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -411,9 +411,7 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir, | |||
411 | { | 411 | { |
412 | struct dentry *dentry; | 412 | struct dentry *dentry; |
413 | 413 | ||
414 | inode_lock(dir->d_inode); | 414 | dentry = lookup_hash(name, dir); |
415 | dentry = lookup_one_len(name->name, dir, name->len); | ||
416 | inode_unlock(dir->d_inode); | ||
417 | 415 | ||
418 | if (IS_ERR(dentry)) { | 416 | if (IS_ERR(dentry)) { |
419 | if (PTR_ERR(dentry) == -ENOENT) | 417 | if (PTR_ERR(dentry) == -ENOENT) |
diff --git a/fs/splice.c b/fs/splice.c index b018eb485019..dd9bf7e410d2 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -1143,6 +1143,9 @@ static long do_splice_to(struct file *in, loff_t *ppos, | |||
1143 | if (unlikely(ret < 0)) | 1143 | if (unlikely(ret < 0)) |
1144 | return ret; | 1144 | return ret; |
1145 | 1145 | ||
1146 | if (unlikely(len > MAX_RW_COUNT)) | ||
1147 | len = MAX_RW_COUNT; | ||
1148 | |||
1146 | if (in->f_op->splice_read) | 1149 | if (in->f_op->splice_read) |
1147 | splice_read = in->f_op->splice_read; | 1150 | splice_read = in->f_op->splice_read; |
1148 | else | 1151 | else |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 4bb4de8d95ea..7e9422cb5989 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -565,4 +565,16 @@ static inline struct dentry *d_real(struct dentry *dentry) | |||
565 | return dentry; | 565 | return dentry; |
566 | } | 566 | } |
567 | 567 | ||
568 | static inline struct inode *vfs_select_inode(struct dentry *dentry, | ||
569 | unsigned open_flags) | ||
570 | { | ||
571 | struct inode *inode = d_inode(dentry); | ||
572 | |||
573 | if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE)) | ||
574 | inode = dentry->d_op->d_select_inode(dentry, open_flags); | ||
575 | |||
576 | return inode; | ||
577 | } | ||
578 | |||
579 | |||
568 | #endif /* __LINUX_DCACHE_H */ | 580 | #endif /* __LINUX_DCACHE_H */ |
diff --git a/include/linux/namei.h b/include/linux/namei.h index 77d01700daf7..ec5ec2818a28 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
@@ -79,6 +79,8 @@ extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int); | |||
79 | 79 | ||
80 | extern struct dentry *lookup_one_len(const char *, struct dentry *, int); | 80 | extern struct dentry *lookup_one_len(const char *, struct dentry *, int); |
81 | extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int); | 81 | extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int); |
82 | struct qstr; | ||
83 | extern struct dentry *lookup_hash(const struct qstr *, struct dentry *); | ||
82 | 84 | ||
83 | extern int follow_down_one(struct path *); | 85 | extern int follow_down_one(struct path *); |
84 | extern int follow_down(struct path *); | 86 | extern int follow_down(struct path *); |
diff --git a/include/linux/uio.h b/include/linux/uio.h index fd9bcfedad42..1b5d1cd796e2 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h | |||
@@ -87,6 +87,7 @@ size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i); | |||
87 | size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); | 87 | size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); |
88 | size_t iov_iter_zero(size_t bytes, struct iov_iter *); | 88 | size_t iov_iter_zero(size_t bytes, struct iov_iter *); |
89 | unsigned long iov_iter_alignment(const struct iov_iter *i); | 89 | unsigned long iov_iter_alignment(const struct iov_iter *i); |
90 | unsigned long iov_iter_gap_alignment(const struct iov_iter *i); | ||
90 | void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, | 91 | void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, |
91 | unsigned long nr_segs, size_t count); | 92 | unsigned long nr_segs, size_t count); |
92 | void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec, | 93 | void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec, |
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 5fecddc32b1b..ca5316e0087b 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
@@ -569,6 +569,25 @@ unsigned long iov_iter_alignment(const struct iov_iter *i) | |||
569 | } | 569 | } |
570 | EXPORT_SYMBOL(iov_iter_alignment); | 570 | EXPORT_SYMBOL(iov_iter_alignment); |
571 | 571 | ||
572 | unsigned long iov_iter_gap_alignment(const struct iov_iter *i) | ||
573 | { | ||
574 | unsigned long res = 0; | ||
575 | size_t size = i->count; | ||
576 | if (!size) | ||
577 | return 0; | ||
578 | |||
579 | iterate_all_kinds(i, size, v, | ||
580 | (res |= (!res ? 0 : (unsigned long)v.iov_base) | | ||
581 | (size != v.iov_len ? size : 0), 0), | ||
582 | (res |= (!res ? 0 : (unsigned long)v.bv_offset) | | ||
583 | (size != v.bv_len ? size : 0)), | ||
584 | (res |= (!res ? 0 : (unsigned long)v.iov_base) | | ||
585 | (size != v.iov_len ? size : 0)) | ||
586 | ); | ||
587 | return res; | ||
588 | } | ||
589 | EXPORT_SYMBOL(iov_iter_gap_alignment); | ||
590 | |||
572 | ssize_t iov_iter_get_pages(struct iov_iter *i, | 591 | ssize_t iov_iter_get_pages(struct iov_iter *i, |
573 | struct page **pages, size_t maxsize, unsigned maxpages, | 592 | struct page **pages, size_t maxsize, unsigned maxpages, |
574 | size_t *start) | 593 | size_t *start) |