.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2017 Red Hat, Inc. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify it |
---|
5 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
6 | | - * the Free Software Foundation. |
---|
7 | 4 | */ |
---|
8 | 5 | |
---|
9 | 6 | #include <linux/cred.h> |
---|
.. | .. |
---|
12 | 9 | #include <linux/xattr.h> |
---|
13 | 10 | #include <linux/uio.h> |
---|
14 | 11 | #include <linux/uaccess.h> |
---|
| 12 | +#include <linux/splice.h> |
---|
| 13 | +#include <linux/security.h> |
---|
| 14 | +#include <linux/mm.h> |
---|
| 15 | +#include <linux/fs.h> |
---|
15 | 16 | #include "overlayfs.h" |
---|
| 17 | + |
---|
| 18 | +#define OVL_IOCB_MASK (IOCB_DSYNC | IOCB_HIPRI | IOCB_NOWAIT | IOCB_SYNC) |
---|
| 19 | + |
---|
| 20 | +struct ovl_aio_req { |
---|
| 21 | + struct kiocb iocb; |
---|
| 22 | + refcount_t ref; |
---|
| 23 | + struct kiocb *orig_iocb; |
---|
| 24 | + struct fd fd; |
---|
| 25 | +}; |
---|
| 26 | + |
---|
| 27 | +static struct kmem_cache *ovl_aio_request_cachep; |
---|
16 | 28 | |
---|
17 | 29 | static char ovl_whatisit(struct inode *inode, struct inode *realinode) |
---|
18 | 30 | { |
---|
.. | .. |
---|
34 | 46 | struct file *realfile; |
---|
35 | 47 | const struct cred *old_cred; |
---|
36 | 48 | int flags = file->f_flags | OVL_OPEN_FLAGS; |
---|
| 49 | + int acc_mode = ACC_MODE(flags); |
---|
| 50 | + int err; |
---|
| 51 | + |
---|
| 52 | + if (flags & O_APPEND) |
---|
| 53 | + acc_mode |= MAY_APPEND; |
---|
37 | 54 | |
---|
38 | 55 | old_cred = ovl_override_creds(inode->i_sb); |
---|
39 | | - realfile = open_with_fake_path(&file->f_path, flags, realinode, |
---|
40 | | - current_cred()); |
---|
41 | | - ovl_revert_creds(old_cred); |
---|
| 56 | + err = inode_permission(realinode, MAY_OPEN | acc_mode); |
---|
| 57 | + if (err) { |
---|
| 58 | + realfile = ERR_PTR(err); |
---|
| 59 | + } else if (old_cred && !inode_owner_or_capable(realinode)) { |
---|
| 60 | + realfile = ERR_PTR(-EPERM); |
---|
| 61 | + } else { |
---|
| 62 | + realfile = open_with_fake_path(&file->f_path, flags, realinode, |
---|
| 63 | + current_cred()); |
---|
| 64 | + } |
---|
| 65 | + ovl_revert_creds(inode->i_sb, old_cred); |
---|
42 | 66 | |
---|
43 | 67 | pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n", |
---|
44 | 68 | file, file, ovl_whatisit(inode, realinode), file->f_flags, |
---|
.. | .. |
---|
115 | 139 | |
---|
116 | 140 | static int ovl_real_fdget(const struct file *file, struct fd *real) |
---|
117 | 141 | { |
---|
| 142 | + if (d_is_dir(file_dentry(file))) { |
---|
| 143 | + real->flags = 0; |
---|
| 144 | + real->file = ovl_dir_real_file(file, false); |
---|
| 145 | + |
---|
| 146 | + return PTR_ERR_OR_ZERO(real->file); |
---|
| 147 | + } |
---|
| 148 | + |
---|
118 | 149 | return ovl_real_fdget_meta(file, real, false); |
---|
119 | 150 | } |
---|
120 | 151 | |
---|
.. | .. |
---|
176 | 207 | * limitations that are more strict than ->s_maxbytes for specific |
---|
177 | 208 | * files, so we use the real file to perform seeks. |
---|
178 | 209 | */ |
---|
179 | | - inode_lock(inode); |
---|
| 210 | + ovl_inode_lock(inode); |
---|
180 | 211 | real.file->f_pos = file->f_pos; |
---|
181 | 212 | |
---|
182 | 213 | old_cred = ovl_override_creds(inode->i_sb); |
---|
183 | 214 | ret = vfs_llseek(real.file, offset, whence); |
---|
184 | | - ovl_revert_creds(old_cred); |
---|
| 215 | + ovl_revert_creds(inode->i_sb, old_cred); |
---|
185 | 216 | |
---|
186 | 217 | file->f_pos = real.file->f_pos; |
---|
187 | | - inode_unlock(inode); |
---|
| 218 | + ovl_inode_unlock(inode); |
---|
188 | 219 | |
---|
189 | 220 | fdput(real); |
---|
190 | 221 | |
---|
.. | .. |
---|
213 | 244 | touch_atime(&file->f_path); |
---|
214 | 245 | } |
---|
215 | 246 | |
---|
216 | | -static rwf_t ovl_iocb_to_rwf(struct kiocb *iocb) |
---|
| 247 | +static inline void ovl_aio_put(struct ovl_aio_req *aio_req) |
---|
217 | 248 | { |
---|
218 | | - int ifl = iocb->ki_flags; |
---|
219 | | - rwf_t flags = 0; |
---|
| 249 | + if (refcount_dec_and_test(&aio_req->ref)) { |
---|
| 250 | + fdput(aio_req->fd); |
---|
| 251 | + kmem_cache_free(ovl_aio_request_cachep, aio_req); |
---|
| 252 | + } |
---|
| 253 | +} |
---|
220 | 254 | |
---|
221 | | - if (ifl & IOCB_NOWAIT) |
---|
222 | | - flags |= RWF_NOWAIT; |
---|
223 | | - if (ifl & IOCB_HIPRI) |
---|
224 | | - flags |= RWF_HIPRI; |
---|
225 | | - if (ifl & IOCB_DSYNC) |
---|
226 | | - flags |= RWF_DSYNC; |
---|
227 | | - if (ifl & IOCB_SYNC) |
---|
228 | | - flags |= RWF_SYNC; |
---|
| 255 | +static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req) |
---|
| 256 | +{ |
---|
| 257 | + struct kiocb *iocb = &aio_req->iocb; |
---|
| 258 | + struct kiocb *orig_iocb = aio_req->orig_iocb; |
---|
229 | 259 | |
---|
230 | | - return flags; |
---|
| 260 | + if (iocb->ki_flags & IOCB_WRITE) { |
---|
| 261 | + struct inode *inode = file_inode(orig_iocb->ki_filp); |
---|
| 262 | + |
---|
| 263 | + /* Actually acquired in ovl_write_iter() */ |
---|
| 264 | + __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb, |
---|
| 265 | + SB_FREEZE_WRITE); |
---|
| 266 | + file_end_write(iocb->ki_filp); |
---|
| 267 | + ovl_copyattr(ovl_inode_real(inode), inode); |
---|
| 268 | + } |
---|
| 269 | + |
---|
| 270 | + orig_iocb->ki_pos = iocb->ki_pos; |
---|
| 271 | + ovl_aio_put(aio_req); |
---|
| 272 | +} |
---|
| 273 | + |
---|
| 274 | +static void ovl_aio_rw_complete(struct kiocb *iocb, long res, long res2) |
---|
| 275 | +{ |
---|
| 276 | + struct ovl_aio_req *aio_req = container_of(iocb, |
---|
| 277 | + struct ovl_aio_req, iocb); |
---|
| 278 | + struct kiocb *orig_iocb = aio_req->orig_iocb; |
---|
| 279 | + |
---|
| 280 | + ovl_aio_cleanup_handler(aio_req); |
---|
| 281 | + orig_iocb->ki_complete(orig_iocb, res, res2); |
---|
231 | 282 | } |
---|
232 | 283 | |
---|
233 | 284 | static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter) |
---|
.. | .. |
---|
244 | 295 | if (ret) |
---|
245 | 296 | return ret; |
---|
246 | 297 | |
---|
| 298 | + ret = -EINVAL; |
---|
| 299 | + if (iocb->ki_flags & IOCB_DIRECT && |
---|
| 300 | + (!real.file->f_mapping->a_ops || |
---|
| 301 | + !real.file->f_mapping->a_ops->direct_IO)) |
---|
| 302 | + goto out_fdput; |
---|
| 303 | + |
---|
247 | 304 | old_cred = ovl_override_creds(file_inode(file)->i_sb); |
---|
248 | | - ret = vfs_iter_read(real.file, iter, &iocb->ki_pos, |
---|
249 | | - ovl_iocb_to_rwf(iocb)); |
---|
250 | | - ovl_revert_creds(old_cred); |
---|
| 305 | + if (is_sync_kiocb(iocb)) { |
---|
| 306 | + ret = vfs_iter_read(real.file, iter, &iocb->ki_pos, |
---|
| 307 | + iocb_to_rw_flags(iocb->ki_flags, |
---|
| 308 | + OVL_IOCB_MASK)); |
---|
| 309 | + } else { |
---|
| 310 | + struct ovl_aio_req *aio_req; |
---|
| 311 | + |
---|
| 312 | + ret = -ENOMEM; |
---|
| 313 | + aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL); |
---|
| 314 | + if (!aio_req) |
---|
| 315 | + goto out; |
---|
| 316 | + |
---|
| 317 | + aio_req->fd = real; |
---|
| 318 | + real.flags = 0; |
---|
| 319 | + aio_req->orig_iocb = iocb; |
---|
| 320 | + kiocb_clone(&aio_req->iocb, iocb, real.file); |
---|
| 321 | + aio_req->iocb.ki_complete = ovl_aio_rw_complete; |
---|
| 322 | + refcount_set(&aio_req->ref, 2); |
---|
| 323 | + ret = vfs_iocb_iter_read(real.file, &aio_req->iocb, iter); |
---|
| 324 | + ovl_aio_put(aio_req); |
---|
| 325 | + if (ret != -EIOCBQUEUED) |
---|
| 326 | + ovl_aio_cleanup_handler(aio_req); |
---|
| 327 | + } |
---|
| 328 | +out: |
---|
| 329 | + ovl_revert_creds(file_inode(file)->i_sb, old_cred); |
---|
251 | 330 | |
---|
252 | 331 | ovl_file_accessed(file); |
---|
253 | | - |
---|
| 332 | +out_fdput: |
---|
254 | 333 | fdput(real); |
---|
255 | 334 | |
---|
256 | 335 | return ret; |
---|
.. | .. |
---|
263 | 342 | struct fd real; |
---|
264 | 343 | const struct cred *old_cred; |
---|
265 | 344 | ssize_t ret; |
---|
| 345 | + int ifl = iocb->ki_flags; |
---|
266 | 346 | |
---|
267 | 347 | if (!iov_iter_count(iter)) |
---|
268 | 348 | return 0; |
---|
.. | .. |
---|
278 | 358 | if (ret) |
---|
279 | 359 | goto out_unlock; |
---|
280 | 360 | |
---|
| 361 | + ret = -EINVAL; |
---|
| 362 | + if (iocb->ki_flags & IOCB_DIRECT && |
---|
| 363 | + (!real.file->f_mapping->a_ops || |
---|
| 364 | + !real.file->f_mapping->a_ops->direct_IO)) |
---|
| 365 | + goto out_fdput; |
---|
| 366 | + |
---|
| 367 | + if (!ovl_should_sync(OVL_FS(inode->i_sb))) |
---|
| 368 | + ifl &= ~(IOCB_DSYNC | IOCB_SYNC); |
---|
| 369 | + |
---|
281 | 370 | old_cred = ovl_override_creds(file_inode(file)->i_sb); |
---|
| 371 | + if (is_sync_kiocb(iocb)) { |
---|
| 372 | + file_start_write(real.file); |
---|
| 373 | + ret = vfs_iter_write(real.file, iter, &iocb->ki_pos, |
---|
| 374 | + iocb_to_rw_flags(ifl, OVL_IOCB_MASK)); |
---|
| 375 | + file_end_write(real.file); |
---|
| 376 | + /* Update size */ |
---|
| 377 | + ovl_copyattr(ovl_inode_real(inode), inode); |
---|
| 378 | + } else { |
---|
| 379 | + struct ovl_aio_req *aio_req; |
---|
| 380 | + |
---|
| 381 | + ret = -ENOMEM; |
---|
| 382 | + aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL); |
---|
| 383 | + if (!aio_req) |
---|
| 384 | + goto out; |
---|
| 385 | + |
---|
| 386 | + file_start_write(real.file); |
---|
| 387 | + /* Pacify lockdep, same trick as done in aio_write() */ |
---|
| 388 | + __sb_writers_release(file_inode(real.file)->i_sb, |
---|
| 389 | + SB_FREEZE_WRITE); |
---|
| 390 | + aio_req->fd = real; |
---|
| 391 | + real.flags = 0; |
---|
| 392 | + aio_req->orig_iocb = iocb; |
---|
| 393 | + kiocb_clone(&aio_req->iocb, iocb, real.file); |
---|
| 394 | + aio_req->iocb.ki_flags = ifl; |
---|
| 395 | + aio_req->iocb.ki_complete = ovl_aio_rw_complete; |
---|
| 396 | + refcount_set(&aio_req->ref, 2); |
---|
| 397 | + ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter); |
---|
| 398 | + ovl_aio_put(aio_req); |
---|
| 399 | + if (ret != -EIOCBQUEUED) |
---|
| 400 | + ovl_aio_cleanup_handler(aio_req); |
---|
| 401 | + } |
---|
| 402 | +out: |
---|
| 403 | + ovl_revert_creds(file_inode(file)->i_sb, old_cred); |
---|
| 404 | +out_fdput: |
---|
| 405 | + fdput(real); |
---|
| 406 | + |
---|
| 407 | +out_unlock: |
---|
| 408 | + inode_unlock(inode); |
---|
| 409 | + |
---|
| 410 | + return ret; |
---|
| 411 | +} |
---|
| 412 | + |
---|
| 413 | +/* |
---|
| 414 | + * Calling iter_file_splice_write() directly from overlay's f_op may deadlock |
---|
| 415 | + * due to lock order inversion between pipe->mutex in iter_file_splice_write() |
---|
| 416 | + * and file_start_write(real.file) in ovl_write_iter(). |
---|
| 417 | + * |
---|
| 418 | + * So do everything ovl_write_iter() does and call iter_file_splice_write() on |
---|
| 419 | + * the real file. |
---|
| 420 | + */ |
---|
| 421 | +static ssize_t ovl_splice_write(struct pipe_inode_info *pipe, struct file *out, |
---|
| 422 | + loff_t *ppos, size_t len, unsigned int flags) |
---|
| 423 | +{ |
---|
| 424 | + struct fd real; |
---|
| 425 | + const struct cred *old_cred; |
---|
| 426 | + struct inode *inode = file_inode(out); |
---|
| 427 | + struct inode *realinode = ovl_inode_real(inode); |
---|
| 428 | + ssize_t ret; |
---|
| 429 | + |
---|
| 430 | + inode_lock(inode); |
---|
| 431 | + /* Update mode */ |
---|
| 432 | + ovl_copyattr(realinode, inode); |
---|
| 433 | + ret = file_remove_privs(out); |
---|
| 434 | + if (ret) |
---|
| 435 | + goto out_unlock; |
---|
| 436 | + |
---|
| 437 | + ret = ovl_real_fdget(out, &real); |
---|
| 438 | + if (ret) |
---|
| 439 | + goto out_unlock; |
---|
| 440 | + |
---|
| 441 | + old_cred = ovl_override_creds(inode->i_sb); |
---|
282 | 442 | file_start_write(real.file); |
---|
283 | | - ret = vfs_iter_write(real.file, iter, &iocb->ki_pos, |
---|
284 | | - ovl_iocb_to_rwf(iocb)); |
---|
| 443 | + |
---|
| 444 | + ret = iter_file_splice_write(pipe, real.file, ppos, len, flags); |
---|
| 445 | + |
---|
285 | 446 | file_end_write(real.file); |
---|
286 | | - ovl_revert_creds(old_cred); |
---|
287 | | - |
---|
288 | 447 | /* Update size */ |
---|
289 | | - ovl_copyattr(ovl_inode_real(inode), inode); |
---|
290 | | - |
---|
| 448 | + ovl_copyattr(realinode, inode); |
---|
| 449 | + ovl_revert_creds(inode->i_sb, old_cred); |
---|
291 | 450 | fdput(real); |
---|
292 | 451 | |
---|
293 | 452 | out_unlock: |
---|
.. | .. |
---|
302 | 461 | const struct cred *old_cred; |
---|
303 | 462 | int ret; |
---|
304 | 463 | |
---|
| 464 | + ret = ovl_sync_status(OVL_FS(file_inode(file)->i_sb)); |
---|
| 465 | + if (ret <= 0) |
---|
| 466 | + return ret; |
---|
| 467 | + |
---|
305 | 468 | ret = ovl_real_fdget_meta(file, &real, !datasync); |
---|
306 | 469 | if (ret) |
---|
307 | 470 | return ret; |
---|
.. | .. |
---|
310 | 473 | if (file_inode(real.file) == ovl_inode_upper(file_inode(file))) { |
---|
311 | 474 | old_cred = ovl_override_creds(file_inode(file)->i_sb); |
---|
312 | 475 | ret = vfs_fsync_range(real.file, start, end, datasync); |
---|
313 | | - ovl_revert_creds(old_cred); |
---|
| 476 | + ovl_revert_creds(file_inode(file)->i_sb, old_cred); |
---|
314 | 477 | } |
---|
315 | 478 | |
---|
316 | 479 | fdput(real); |
---|
.. | .. |
---|
334 | 497 | |
---|
335 | 498 | old_cred = ovl_override_creds(file_inode(file)->i_sb); |
---|
336 | 499 | ret = call_mmap(vma->vm_file, vma); |
---|
337 | | - ovl_revert_creds(old_cred); |
---|
| 500 | + ovl_revert_creds(file_inode(file)->i_sb, old_cred); |
---|
338 | 501 | |
---|
339 | 502 | if (ret) { |
---|
340 | 503 | /* Drop reference count from new vm_file value */ |
---|
.. | .. |
---|
362 | 525 | |
---|
363 | 526 | old_cred = ovl_override_creds(file_inode(file)->i_sb); |
---|
364 | 527 | ret = vfs_fallocate(real.file, mode, offset, len); |
---|
365 | | - ovl_revert_creds(old_cred); |
---|
| 528 | + ovl_revert_creds(file_inode(file)->i_sb, old_cred); |
---|
366 | 529 | |
---|
367 | 530 | /* Update size */ |
---|
368 | 531 | ovl_copyattr(ovl_inode_real(inode), inode); |
---|
.. | .. |
---|
384 | 547 | |
---|
385 | 548 | old_cred = ovl_override_creds(file_inode(file)->i_sb); |
---|
386 | 549 | ret = vfs_fadvise(real.file, offset, len, advice); |
---|
387 | | - ovl_revert_creds(old_cred); |
---|
| 550 | + ovl_revert_creds(file_inode(file)->i_sb, old_cred); |
---|
388 | 551 | |
---|
389 | 552 | fdput(real); |
---|
390 | 553 | |
---|
.. | .. |
---|
395 | 558 | unsigned long arg) |
---|
396 | 559 | { |
---|
397 | 560 | struct fd real; |
---|
398 | | - const struct cred *old_cred; |
---|
399 | 561 | long ret; |
---|
400 | 562 | |
---|
401 | 563 | ret = ovl_real_fdget(file, &real); |
---|
402 | 564 | if (ret) |
---|
403 | 565 | return ret; |
---|
404 | 566 | |
---|
405 | | - old_cred = ovl_override_creds(file_inode(file)->i_sb); |
---|
406 | | - ret = vfs_ioctl(real.file, cmd, arg); |
---|
407 | | - ovl_revert_creds(old_cred); |
---|
| 567 | + ret = security_file_ioctl(real.file, cmd, arg); |
---|
| 568 | + if (!ret) { |
---|
| 569 | + /* |
---|
| 570 | + * Don't override creds, since we currently can't safely check |
---|
| 571 | + * permissions before doing so. |
---|
| 572 | + */ |
---|
| 573 | + ret = vfs_ioctl(real.file, cmd, arg); |
---|
| 574 | + } |
---|
408 | 575 | |
---|
409 | 576 | fdput(real); |
---|
410 | 577 | |
---|
.. | .. |
---|
412 | 579 | } |
---|
413 | 580 | |
---|
414 | 581 | static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, |
---|
415 | | - unsigned long arg, unsigned int iflags) |
---|
| 582 | + unsigned long arg) |
---|
416 | 583 | { |
---|
417 | 584 | long ret; |
---|
418 | 585 | struct inode *inode = file_inode(file); |
---|
419 | | - unsigned int old_iflags; |
---|
420 | 586 | |
---|
421 | 587 | if (!inode_owner_or_capable(inode)) |
---|
422 | 588 | return -EACCES; |
---|
.. | .. |
---|
427 | 593 | |
---|
428 | 594 | inode_lock(inode); |
---|
429 | 595 | |
---|
430 | | - /* Check the capability before cred override */ |
---|
| 596 | + /* |
---|
| 597 | + * Prevent copy up if immutable and has no CAP_LINUX_IMMUTABLE |
---|
| 598 | + * capability. |
---|
| 599 | + */ |
---|
431 | 600 | ret = -EPERM; |
---|
432 | | - old_iflags = READ_ONCE(inode->i_flags); |
---|
433 | | - if (((iflags ^ old_iflags) & (S_APPEND | S_IMMUTABLE)) && |
---|
| 601 | + if (!ovl_has_upperdata(inode) && IS_IMMUTABLE(inode) && |
---|
434 | 602 | !capable(CAP_LINUX_IMMUTABLE)) |
---|
435 | 603 | goto unlock; |
---|
436 | 604 | |
---|
.. | .. |
---|
450 | 618 | |
---|
451 | 619 | } |
---|
452 | 620 | |
---|
453 | | -static unsigned int ovl_fsflags_to_iflags(unsigned int flags) |
---|
454 | | -{ |
---|
455 | | - unsigned int iflags = 0; |
---|
456 | | - |
---|
457 | | - if (flags & FS_SYNC_FL) |
---|
458 | | - iflags |= S_SYNC; |
---|
459 | | - if (flags & FS_APPEND_FL) |
---|
460 | | - iflags |= S_APPEND; |
---|
461 | | - if (flags & FS_IMMUTABLE_FL) |
---|
462 | | - iflags |= S_IMMUTABLE; |
---|
463 | | - if (flags & FS_NOATIME_FL) |
---|
464 | | - iflags |= S_NOATIME; |
---|
465 | | - |
---|
466 | | - return iflags; |
---|
467 | | -} |
---|
468 | | - |
---|
469 | | -static long ovl_ioctl_set_fsflags(struct file *file, unsigned int cmd, |
---|
470 | | - unsigned long arg) |
---|
471 | | -{ |
---|
472 | | - unsigned int flags; |
---|
473 | | - |
---|
474 | | - if (get_user(flags, (int __user *) arg)) |
---|
475 | | - return -EFAULT; |
---|
476 | | - |
---|
477 | | - return ovl_ioctl_set_flags(file, cmd, arg, |
---|
478 | | - ovl_fsflags_to_iflags(flags)); |
---|
479 | | -} |
---|
480 | | - |
---|
481 | | -static unsigned int ovl_fsxflags_to_iflags(unsigned int xflags) |
---|
482 | | -{ |
---|
483 | | - unsigned int iflags = 0; |
---|
484 | | - |
---|
485 | | - if (xflags & FS_XFLAG_SYNC) |
---|
486 | | - iflags |= S_SYNC; |
---|
487 | | - if (xflags & FS_XFLAG_APPEND) |
---|
488 | | - iflags |= S_APPEND; |
---|
489 | | - if (xflags & FS_XFLAG_IMMUTABLE) |
---|
490 | | - iflags |= S_IMMUTABLE; |
---|
491 | | - if (xflags & FS_XFLAG_NOATIME) |
---|
492 | | - iflags |= S_NOATIME; |
---|
493 | | - |
---|
494 | | - return iflags; |
---|
495 | | -} |
---|
496 | | - |
---|
497 | | -static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd, |
---|
498 | | - unsigned long arg) |
---|
499 | | -{ |
---|
500 | | - struct fsxattr fa; |
---|
501 | | - |
---|
502 | | - memset(&fa, 0, sizeof(fa)); |
---|
503 | | - if (copy_from_user(&fa, (void __user *) arg, sizeof(fa))) |
---|
504 | | - return -EFAULT; |
---|
505 | | - |
---|
506 | | - return ovl_ioctl_set_flags(file, cmd, arg, |
---|
507 | | - ovl_fsxflags_to_iflags(fa.fsx_xflags)); |
---|
508 | | -} |
---|
509 | | - |
---|
510 | | -static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
---|
| 621 | +long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
---|
511 | 622 | { |
---|
512 | 623 | long ret; |
---|
513 | 624 | |
---|
.. | .. |
---|
517 | 628 | ret = ovl_real_ioctl(file, cmd, arg); |
---|
518 | 629 | break; |
---|
519 | 630 | |
---|
520 | | - case FS_IOC_SETFLAGS: |
---|
521 | | - ret = ovl_ioctl_set_fsflags(file, cmd, arg); |
---|
522 | | - break; |
---|
523 | | - |
---|
524 | 631 | case FS_IOC_FSSETXATTR: |
---|
525 | | - ret = ovl_ioctl_set_fsxflags(file, cmd, arg); |
---|
| 632 | + case FS_IOC_SETFLAGS: |
---|
| 633 | + ret = ovl_ioctl_set_flags(file, cmd, arg); |
---|
526 | 634 | break; |
---|
527 | 635 | |
---|
528 | 636 | default: |
---|
.. | .. |
---|
532 | 640 | return ret; |
---|
533 | 641 | } |
---|
534 | 642 | |
---|
535 | | -static long ovl_compat_ioctl(struct file *file, unsigned int cmd, |
---|
536 | | - unsigned long arg) |
---|
| 643 | +#ifdef CONFIG_COMPAT |
---|
| 644 | +long ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
---|
537 | 645 | { |
---|
538 | 646 | switch (cmd) { |
---|
539 | 647 | case FS_IOC32_GETFLAGS: |
---|
.. | .. |
---|
550 | 658 | |
---|
551 | 659 | return ovl_ioctl(file, cmd, arg); |
---|
552 | 660 | } |
---|
| 661 | +#endif |
---|
553 | 662 | |
---|
554 | 663 | enum ovl_copyop { |
---|
555 | 664 | OVL_COPY, |
---|
.. | .. |
---|
557 | 666 | OVL_DEDUPE, |
---|
558 | 667 | }; |
---|
559 | 668 | |
---|
560 | | -static ssize_t ovl_copyfile(struct file *file_in, loff_t pos_in, |
---|
| 669 | +static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in, |
---|
561 | 670 | struct file *file_out, loff_t pos_out, |
---|
562 | | - u64 len, unsigned int flags, enum ovl_copyop op) |
---|
| 671 | + loff_t len, unsigned int flags, enum ovl_copyop op) |
---|
563 | 672 | { |
---|
564 | 673 | struct inode *inode_out = file_inode(file_out); |
---|
565 | 674 | struct fd real_in, real_out; |
---|
566 | 675 | const struct cred *old_cred; |
---|
567 | | - ssize_t ret; |
---|
| 676 | + loff_t ret; |
---|
568 | 677 | |
---|
569 | 678 | ret = ovl_real_fdget(file_out, &real_out); |
---|
570 | 679 | if (ret) |
---|
.. | .. |
---|
585 | 694 | |
---|
586 | 695 | case OVL_CLONE: |
---|
587 | 696 | ret = vfs_clone_file_range(real_in.file, pos_in, |
---|
588 | | - real_out.file, pos_out, len); |
---|
| 697 | + real_out.file, pos_out, len, flags); |
---|
589 | 698 | break; |
---|
590 | 699 | |
---|
591 | 700 | case OVL_DEDUPE: |
---|
592 | 701 | ret = vfs_dedupe_file_range_one(real_in.file, pos_in, |
---|
593 | | - real_out.file, pos_out, len); |
---|
| 702 | + real_out.file, pos_out, len, |
---|
| 703 | + flags); |
---|
594 | 704 | break; |
---|
595 | 705 | } |
---|
596 | | - ovl_revert_creds(old_cred); |
---|
| 706 | + ovl_revert_creds(file_inode(file_out)->i_sb, old_cred); |
---|
597 | 707 | |
---|
598 | 708 | /* Update size */ |
---|
599 | 709 | ovl_copyattr(ovl_inode_real(inode_out), inode_out); |
---|
.. | .. |
---|
612 | 722 | OVL_COPY); |
---|
613 | 723 | } |
---|
614 | 724 | |
---|
615 | | -static int ovl_clone_file_range(struct file *file_in, loff_t pos_in, |
---|
616 | | - struct file *file_out, loff_t pos_out, u64 len) |
---|
| 725 | +static loff_t ovl_remap_file_range(struct file *file_in, loff_t pos_in, |
---|
| 726 | + struct file *file_out, loff_t pos_out, |
---|
| 727 | + loff_t len, unsigned int remap_flags) |
---|
617 | 728 | { |
---|
618 | | - return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 0, |
---|
619 | | - OVL_CLONE); |
---|
620 | | -} |
---|
| 729 | + enum ovl_copyop op; |
---|
621 | 730 | |
---|
622 | | -static int ovl_dedupe_file_range(struct file *file_in, loff_t pos_in, |
---|
623 | | - struct file *file_out, loff_t pos_out, u64 len) |
---|
624 | | -{ |
---|
| 731 | + if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) |
---|
| 732 | + return -EINVAL; |
---|
| 733 | + |
---|
| 734 | + if (remap_flags & REMAP_FILE_DEDUP) |
---|
| 735 | + op = OVL_DEDUPE; |
---|
| 736 | + else |
---|
| 737 | + op = OVL_CLONE; |
---|
| 738 | + |
---|
625 | 739 | /* |
---|
626 | 740 | * Don't copy up because of a dedupe request, this wouldn't make sense |
---|
627 | 741 | * most of the time (data would be duplicated instead of deduplicated). |
---|
628 | 742 | */ |
---|
629 | | - if (!ovl_inode_upper(file_inode(file_in)) || |
---|
630 | | - !ovl_inode_upper(file_inode(file_out))) |
---|
| 743 | + if (op == OVL_DEDUPE && |
---|
| 744 | + (!ovl_inode_upper(file_inode(file_in)) || |
---|
| 745 | + !ovl_inode_upper(file_inode(file_out)))) |
---|
631 | 746 | return -EPERM; |
---|
632 | 747 | |
---|
633 | | - return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, 0, |
---|
634 | | - OVL_DEDUPE); |
---|
| 748 | + return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, |
---|
| 749 | + remap_flags, op); |
---|
635 | 750 | } |
---|
636 | 751 | |
---|
637 | 752 | const struct file_operations ovl_file_operations = { |
---|
.. | .. |
---|
645 | 760 | .fallocate = ovl_fallocate, |
---|
646 | 761 | .fadvise = ovl_fadvise, |
---|
647 | 762 | .unlocked_ioctl = ovl_ioctl, |
---|
| 763 | +#ifdef CONFIG_COMPAT |
---|
648 | 764 | .compat_ioctl = ovl_compat_ioctl, |
---|
| 765 | +#endif |
---|
| 766 | + .splice_read = generic_file_splice_read, |
---|
| 767 | + .splice_write = ovl_splice_write, |
---|
649 | 768 | |
---|
650 | 769 | .copy_file_range = ovl_copy_file_range, |
---|
651 | | - .clone_file_range = ovl_clone_file_range, |
---|
652 | | - .dedupe_file_range = ovl_dedupe_file_range, |
---|
| 770 | + .remap_file_range = ovl_remap_file_range, |
---|
653 | 771 | }; |
---|
| 772 | + |
---|
| 773 | +int __init ovl_aio_request_cache_init(void) |
---|
| 774 | +{ |
---|
| 775 | + ovl_aio_request_cachep = kmem_cache_create("ovl_aio_req", |
---|
| 776 | + sizeof(struct ovl_aio_req), |
---|
| 777 | + 0, SLAB_HWCACHE_ALIGN, NULL); |
---|
| 778 | + if (!ovl_aio_request_cachep) |
---|
| 779 | + return -ENOMEM; |
---|
| 780 | + |
---|
| 781 | + return 0; |
---|
| 782 | +} |
---|
| 783 | + |
---|
| 784 | +void ovl_aio_request_cache_destroy(void) |
---|
| 785 | +{ |
---|
| 786 | + kmem_cache_destroy(ovl_aio_request_cachep); |
---|
| 787 | +} |
---|