.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Overlayfs NFS export support. |
---|
3 | 4 | * |
---|
4 | 5 | * Amir Goldstein <amir73il@gmail.com> |
---|
5 | 6 | * |
---|
6 | 7 | * Copyright (C) 2017-2018 CTERA Networks. All Rights Reserved. |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify it |
---|
9 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
10 | | - * the Free Software Foundation. |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | 10 | #include <linux/fs.h> |
---|
.. | .. |
---|
33 | 30 | } |
---|
34 | 31 | |
---|
35 | 32 | if (err) { |
---|
36 | | - pr_warn_ratelimited("overlayfs: failed to copy up on encode (%pd2, err=%i)\n", |
---|
| 33 | + pr_warn_ratelimited("failed to copy up on encode (%pd2, err=%i)\n", |
---|
37 | 34 | dentry, err); |
---|
38 | 35 | } |
---|
39 | 36 | |
---|
.. | .. |
---|
207 | 204 | * ovl_connect_layer() will try to make origin's layer "connected" by |
---|
208 | 205 | * copying up a "connectable" ancestor. |
---|
209 | 206 | */ |
---|
210 | | - if (d_is_dir(dentry) && ofs->upper_mnt) |
---|
| 207 | + if (d_is_dir(dentry) && ovl_upper_mnt(ofs)) |
---|
211 | 208 | return ovl_connect_layer(dentry); |
---|
212 | 209 | |
---|
213 | 210 | /* Lower file handle for indexed and non-upper dir/non-dir */ |
---|
214 | 211 | return 1; |
---|
215 | 212 | } |
---|
216 | 213 | |
---|
217 | | -static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen) |
---|
| 214 | +static int ovl_dentry_to_fid(struct dentry *dentry, u32 *fid, int buflen) |
---|
218 | 215 | { |
---|
219 | 216 | struct ovl_fh *fh = NULL; |
---|
220 | 217 | int err, enc_lower; |
---|
| 218 | + int len; |
---|
221 | 219 | |
---|
222 | 220 | /* |
---|
223 | 221 | * Check if we should encode a lower or upper file handle and maybe |
---|
.. | .. |
---|
233 | 231 | if (IS_ERR(fh)) |
---|
234 | 232 | return PTR_ERR(fh); |
---|
235 | 233 | |
---|
236 | | - err = -EOVERFLOW; |
---|
237 | | - if (fh->len > buflen) |
---|
238 | | - goto fail; |
---|
239 | | - |
---|
240 | | - memcpy(buf, (char *)fh, fh->len); |
---|
241 | | - err = fh->len; |
---|
| 234 | + len = OVL_FH_LEN(fh); |
---|
| 235 | + if (len <= buflen) |
---|
| 236 | + memcpy(fid, fh, len); |
---|
| 237 | + err = len; |
---|
242 | 238 | |
---|
243 | 239 | out: |
---|
244 | 240 | kfree(fh); |
---|
245 | 241 | return err; |
---|
246 | 242 | |
---|
247 | 243 | fail: |
---|
248 | | - pr_warn_ratelimited("overlayfs: failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n", |
---|
249 | | - dentry, err, buflen, fh ? (int)fh->len : 0, |
---|
250 | | - fh ? fh->type : 0); |
---|
| 244 | + pr_warn_ratelimited("failed to encode file handle (%pd2, err=%i)\n", |
---|
| 245 | + dentry, err); |
---|
251 | 246 | goto out; |
---|
252 | | -} |
---|
253 | | - |
---|
254 | | -static int ovl_dentry_to_fh(struct dentry *dentry, u32 *fid, int *max_len) |
---|
255 | | -{ |
---|
256 | | - int res, len = *max_len << 2; |
---|
257 | | - |
---|
258 | | - res = ovl_d_to_fh(dentry, (char *)fid, len); |
---|
259 | | - if (res <= 0) |
---|
260 | | - return FILEID_INVALID; |
---|
261 | | - |
---|
262 | | - len = res; |
---|
263 | | - |
---|
264 | | - /* Round up to dwords */ |
---|
265 | | - *max_len = (len + 3) >> 2; |
---|
266 | | - return OVL_FILEID; |
---|
267 | 247 | } |
---|
268 | 248 | |
---|
269 | 249 | static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len, |
---|
270 | 250 | struct inode *parent) |
---|
271 | 251 | { |
---|
272 | 252 | struct dentry *dentry; |
---|
273 | | - int type; |
---|
| 253 | + int bytes, buflen = *max_len << 2; |
---|
274 | 254 | |
---|
275 | 255 | /* TODO: encode connectable file handles */ |
---|
276 | 256 | if (parent) |
---|
277 | 257 | return FILEID_INVALID; |
---|
278 | 258 | |
---|
279 | 259 | dentry = d_find_any_alias(inode); |
---|
280 | | - if (WARN_ON(!dentry)) |
---|
| 260 | + if (!dentry) |
---|
281 | 261 | return FILEID_INVALID; |
---|
282 | 262 | |
---|
283 | | - type = ovl_dentry_to_fh(dentry, fid, max_len); |
---|
284 | | - |
---|
| 263 | + bytes = ovl_dentry_to_fid(dentry, fid, buflen); |
---|
285 | 264 | dput(dentry); |
---|
286 | | - return type; |
---|
| 265 | + if (bytes <= 0) |
---|
| 266 | + return FILEID_INVALID; |
---|
| 267 | + |
---|
| 268 | + *max_len = bytes >> 2; |
---|
| 269 | + if (bytes > buflen) |
---|
| 270 | + return FILEID_INVALID; |
---|
| 271 | + |
---|
| 272 | + return OVL_FILEID_V1; |
---|
287 | 273 | } |
---|
288 | 274 | |
---|
289 | 275 | /* |
---|
.. | .. |
---|
320 | 306 | ovl_set_flag(OVL_UPPERDATA, inode); |
---|
321 | 307 | |
---|
322 | 308 | dentry = d_find_any_alias(inode); |
---|
323 | | - if (!dentry) { |
---|
324 | | - dentry = d_alloc_anon(inode->i_sb); |
---|
325 | | - if (!dentry) |
---|
326 | | - goto nomem; |
---|
327 | | - oe = ovl_alloc_entry(lower ? 1 : 0); |
---|
328 | | - if (!oe) |
---|
329 | | - goto nomem; |
---|
| 309 | + if (dentry) |
---|
| 310 | + goto out_iput; |
---|
330 | 311 | |
---|
331 | | - if (lower) { |
---|
332 | | - oe->lowerstack->dentry = dget(lower); |
---|
333 | | - oe->lowerstack->layer = lowerpath->layer; |
---|
334 | | - } |
---|
335 | | - dentry->d_fsdata = oe; |
---|
336 | | - if (upper_alias) |
---|
337 | | - ovl_dentry_set_upper_alias(dentry); |
---|
| 312 | + dentry = d_alloc_anon(inode->i_sb); |
---|
| 313 | + if (unlikely(!dentry)) |
---|
| 314 | + goto nomem; |
---|
| 315 | + oe = ovl_alloc_entry(lower ? 1 : 0); |
---|
| 316 | + if (!oe) |
---|
| 317 | + goto nomem; |
---|
| 318 | + |
---|
| 319 | + if (lower) { |
---|
| 320 | + oe->lowerstack->dentry = dget(lower); |
---|
| 321 | + oe->lowerstack->layer = lowerpath->layer; |
---|
338 | 322 | } |
---|
| 323 | + dentry->d_fsdata = oe; |
---|
| 324 | + if (upper_alias) |
---|
| 325 | + ovl_dentry_set_upper_alias(dentry); |
---|
| 326 | + |
---|
| 327 | + ovl_dentry_init_reval(dentry, upper); |
---|
339 | 328 | |
---|
340 | 329 | return d_instantiate_anon(dentry, inode); |
---|
341 | 330 | |
---|
342 | 331 | nomem: |
---|
343 | | - iput(inode); |
---|
344 | 332 | dput(dentry); |
---|
345 | | - return ERR_PTR(-ENOMEM); |
---|
| 333 | + dentry = ERR_PTR(-ENOMEM); |
---|
| 334 | +out_iput: |
---|
| 335 | + iput(inode); |
---|
| 336 | + return dentry; |
---|
346 | 337 | } |
---|
347 | 338 | |
---|
348 | 339 | /* Get the upper or lower dentry in stach whose on layer @idx */ |
---|
.. | .. |
---|
370 | 361 | */ |
---|
371 | 362 | static struct dentry *ovl_lookup_real_one(struct dentry *connected, |
---|
372 | 363 | struct dentry *real, |
---|
373 | | - struct ovl_layer *layer) |
---|
| 364 | + const struct ovl_layer *layer) |
---|
374 | 365 | { |
---|
375 | 366 | struct inode *dir = d_inode(connected); |
---|
376 | 367 | struct dentry *this, *parent = NULL; |
---|
.. | .. |
---|
397 | 388 | * pointer because we hold no lock on the real dentry. |
---|
398 | 389 | */ |
---|
399 | 390 | take_dentry_name_snapshot(&name, real); |
---|
400 | | - this = lookup_one_len(name.name, connected, strlen(name.name)); |
---|
| 391 | + this = lookup_one_len(name.name.name, connected, name.name.len); |
---|
| 392 | + release_dentry_name_snapshot(&name); |
---|
401 | 393 | err = PTR_ERR(this); |
---|
402 | 394 | if (IS_ERR(this)) { |
---|
403 | 395 | goto fail; |
---|
.. | .. |
---|
412 | 404 | } |
---|
413 | 405 | |
---|
414 | 406 | out: |
---|
415 | | - release_dentry_name_snapshot(&name); |
---|
416 | 407 | dput(parent); |
---|
417 | 408 | inode_unlock(dir); |
---|
418 | 409 | return this; |
---|
419 | 410 | |
---|
420 | 411 | fail: |
---|
421 | | - pr_warn_ratelimited("overlayfs: failed to lookup one by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", |
---|
| 412 | + pr_warn_ratelimited("failed to lookup one by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", |
---|
422 | 413 | real, layer->idx, connected, err); |
---|
423 | 414 | this = ERR_PTR(err); |
---|
424 | 415 | goto out; |
---|
.. | .. |
---|
426 | 417 | |
---|
427 | 418 | static struct dentry *ovl_lookup_real(struct super_block *sb, |
---|
428 | 419 | struct dentry *real, |
---|
429 | | - struct ovl_layer *layer); |
---|
| 420 | + const struct ovl_layer *layer); |
---|
430 | 421 | |
---|
431 | 422 | /* |
---|
432 | 423 | * Lookup an indexed or hashed overlay dentry by real inode. |
---|
433 | 424 | */ |
---|
434 | 425 | static struct dentry *ovl_lookup_real_inode(struct super_block *sb, |
---|
435 | 426 | struct dentry *real, |
---|
436 | | - struct ovl_layer *layer) |
---|
| 427 | + const struct ovl_layer *layer) |
---|
437 | 428 | { |
---|
438 | 429 | struct ovl_fs *ofs = sb->s_fs_info; |
---|
439 | | - struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; |
---|
440 | 430 | struct dentry *index = NULL; |
---|
441 | 431 | struct dentry *this = NULL; |
---|
442 | 432 | struct inode *inode; |
---|
.. | .. |
---|
478 | 468 | * recursive call walks back from indexed upper to the topmost |
---|
479 | 469 | * connected/hashed upper parent (or up to root). |
---|
480 | 470 | */ |
---|
481 | | - this = ovl_lookup_real(sb, upper, &upper_layer); |
---|
| 471 | + this = ovl_lookup_real(sb, upper, &ofs->layers[0]); |
---|
482 | 472 | dput(upper); |
---|
483 | 473 | } |
---|
484 | 474 | |
---|
.. | .. |
---|
499 | 489 | */ |
---|
500 | 490 | static struct dentry *ovl_lookup_real_ancestor(struct super_block *sb, |
---|
501 | 491 | struct dentry *real, |
---|
502 | | - struct ovl_layer *layer) |
---|
| 492 | + const struct ovl_layer *layer) |
---|
503 | 493 | { |
---|
504 | 494 | struct dentry *next, *parent = NULL; |
---|
505 | 495 | struct dentry *ancestor = ERR_PTR(-EIO); |
---|
.. | .. |
---|
552 | 542 | */ |
---|
553 | 543 | static struct dentry *ovl_lookup_real(struct super_block *sb, |
---|
554 | 544 | struct dentry *real, |
---|
555 | | - struct ovl_layer *layer) |
---|
| 545 | + const struct ovl_layer *layer) |
---|
556 | 546 | { |
---|
557 | 547 | struct dentry *connected; |
---|
558 | 548 | int err = 0; |
---|
.. | .. |
---|
643 | 633 | return connected; |
---|
644 | 634 | |
---|
645 | 635 | fail: |
---|
646 | | - pr_warn_ratelimited("overlayfs: failed to lookup by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", |
---|
| 636 | + pr_warn_ratelimited("failed to lookup by real (%pd2, layer=%d, connected=%pd2, err=%i)\n", |
---|
647 | 637 | real, layer->idx, connected, err); |
---|
648 | 638 | dput(connected); |
---|
649 | 639 | return ERR_PTR(err); |
---|
.. | .. |
---|
658 | 648 | struct dentry *index) |
---|
659 | 649 | { |
---|
660 | 650 | struct ovl_fs *ofs = sb->s_fs_info; |
---|
661 | | - struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; |
---|
662 | | - struct ovl_layer *layer = upper ? &upper_layer : lowerpath->layer; |
---|
| 651 | + const struct ovl_layer *layer = upper ? &ofs->layers[0] : lowerpath->layer; |
---|
663 | 652 | struct dentry *real = upper ?: (index ?: lowerpath->dentry); |
---|
664 | 653 | |
---|
665 | 654 | /* |
---|
.. | .. |
---|
687 | 676 | struct dentry *dentry; |
---|
688 | 677 | struct dentry *upper; |
---|
689 | 678 | |
---|
690 | | - if (!ofs->upper_mnt) |
---|
| 679 | + if (!ovl_upper_mnt(ofs)) |
---|
691 | 680 | return ERR_PTR(-EACCES); |
---|
692 | 681 | |
---|
693 | | - upper = ovl_decode_real_fh(fh, ofs->upper_mnt, true); |
---|
| 682 | + upper = ovl_decode_real_fh(fh, ovl_upper_mnt(ofs), true); |
---|
694 | 683 | if (IS_ERR_OR_NULL(upper)) |
---|
695 | 684 | return upper; |
---|
696 | 685 | |
---|
.. | .. |
---|
762 | 751 | goto out_err; |
---|
763 | 752 | } |
---|
764 | 753 | if (index) { |
---|
765 | | - err = ovl_verify_origin(index, origin.dentry, false); |
---|
| 754 | + err = ovl_verify_origin(ofs, index, origin.dentry, false); |
---|
766 | 755 | if (err) |
---|
767 | 756 | goto out_err; |
---|
768 | 757 | } |
---|
.. | .. |
---|
780 | 769 | goto out; |
---|
781 | 770 | } |
---|
782 | 771 | |
---|
| 772 | +static struct ovl_fh *ovl_fid_to_fh(struct fid *fid, int buflen, int fh_type) |
---|
| 773 | +{ |
---|
| 774 | + struct ovl_fh *fh; |
---|
| 775 | + |
---|
| 776 | + /* If on-wire inner fid is aligned - nothing to do */ |
---|
| 777 | + if (fh_type == OVL_FILEID_V1) |
---|
| 778 | + return (struct ovl_fh *)fid; |
---|
| 779 | + |
---|
| 780 | + if (fh_type != OVL_FILEID_V0) |
---|
| 781 | + return ERR_PTR(-EINVAL); |
---|
| 782 | + |
---|
| 783 | + if (buflen <= OVL_FH_WIRE_OFFSET) |
---|
| 784 | + return ERR_PTR(-EINVAL); |
---|
| 785 | + |
---|
| 786 | + fh = kzalloc(buflen, GFP_KERNEL); |
---|
| 787 | + if (!fh) |
---|
| 788 | + return ERR_PTR(-ENOMEM); |
---|
| 789 | + |
---|
| 790 | + /* Copy unaligned inner fh into aligned buffer */ |
---|
| 791 | + memcpy(&fh->fb, fid, buflen - OVL_FH_WIRE_OFFSET); |
---|
| 792 | + return fh; |
---|
| 793 | +} |
---|
| 794 | + |
---|
783 | 795 | static struct dentry *ovl_fh_to_dentry(struct super_block *sb, struct fid *fid, |
---|
784 | 796 | int fh_len, int fh_type) |
---|
785 | 797 | { |
---|
786 | 798 | struct dentry *dentry = NULL; |
---|
787 | | - struct ovl_fh *fh = (struct ovl_fh *) fid; |
---|
| 799 | + struct ovl_fh *fh = NULL; |
---|
788 | 800 | int len = fh_len << 2; |
---|
789 | 801 | unsigned int flags = 0; |
---|
790 | 802 | int err; |
---|
791 | 803 | |
---|
792 | | - err = -EINVAL; |
---|
793 | | - if (fh_type != OVL_FILEID) |
---|
| 804 | + fh = ovl_fid_to_fh(fid, len, fh_type); |
---|
| 805 | + err = PTR_ERR(fh); |
---|
| 806 | + if (IS_ERR(fh)) |
---|
794 | 807 | goto out_err; |
---|
795 | 808 | |
---|
796 | 809 | err = ovl_check_fh_len(fh, len); |
---|
797 | 810 | if (err) |
---|
798 | 811 | goto out_err; |
---|
799 | 812 | |
---|
800 | | - flags = fh->flags; |
---|
| 813 | + flags = fh->fb.flags; |
---|
801 | 814 | dentry = (flags & OVL_FH_FLAG_PATH_UPPER) ? |
---|
802 | 815 | ovl_upper_fh_to_d(sb, fh) : |
---|
803 | 816 | ovl_lower_fh_to_d(sb, fh); |
---|
.. | .. |
---|
805 | 818 | if (IS_ERR(dentry) && err != -ESTALE) |
---|
806 | 819 | goto out_err; |
---|
807 | 820 | |
---|
| 821 | +out: |
---|
| 822 | + /* We may have needed to re-align OVL_FILEID_V0 */ |
---|
| 823 | + if (!IS_ERR_OR_NULL(fh) && fh != (void *)fid) |
---|
| 824 | + kfree(fh); |
---|
| 825 | + |
---|
808 | 826 | return dentry; |
---|
809 | 827 | |
---|
810 | 828 | out_err: |
---|
811 | | - pr_warn_ratelimited("overlayfs: failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n", |
---|
812 | | - len, fh_type, flags, err); |
---|
813 | | - return ERR_PTR(err); |
---|
| 829 | + pr_warn_ratelimited("failed to decode file handle (len=%d, type=%d, flags=%x, err=%i)\n", |
---|
| 830 | + fh_len, fh_type, flags, err); |
---|
| 831 | + dentry = ERR_PTR(err); |
---|
| 832 | + goto out; |
---|
814 | 833 | } |
---|
815 | 834 | |
---|
816 | 835 | static struct dentry *ovl_fh_to_parent(struct super_block *sb, struct fid *fid, |
---|
817 | 836 | int fh_len, int fh_type) |
---|
818 | 837 | { |
---|
819 | | - pr_warn_ratelimited("overlayfs: connectable file handles not supported; use 'no_subtree_check' exportfs option.\n"); |
---|
| 838 | + pr_warn_ratelimited("connectable file handles not supported; use 'no_subtree_check' exportfs option.\n"); |
---|
820 | 839 | return ERR_PTR(-EACCES); |
---|
821 | 840 | } |
---|
822 | 841 | |
---|