| @@ -35,7 +35,8 @@ struct ovl_config { · 34 unmodified lines |
| 35 | 35 | /* private information held for overlayfs's superblock */ |
| 36 | 36 | struct ovl_fs { |
| 37 | 37 | struct vfsmount *upper_mnt; |
| 38 | | − struct vfsmount *lower_mnt; |
| 38 | + unsigned numlower; |
| 39 | + struct vfsmount **lower_mnt; |
| 39 | 40 | struct dentry *workdir; |
| 40 | 41 | long lower_namelen; |
| 41 | 42 | /* pathnames of lower and upper dirs, for show_options */ |
| @@ -47,7 +48,6 @@ struct ovl_dir_cache; · 5 unmodified lines |
| 47 | 48 | /* private information held for every overlayfs dentry */ |
| 48 | 49 | struct ovl_entry { |
| 49 | 50 | struct dentry *__upperdentry; |
| 50 | | − struct dentry *lowerdentry; |
| 51 | 51 | struct ovl_dir_cache *cache; |
| 52 | 52 | union { |
| 53 | 53 | struct { |
| @@ -56,30 +56,36 @@ struct ovl_entry { · 2 unmodified lines |
| 56 | 56 | }; |
| 57 | 57 | struct rcu_head rcu; |
| 58 | 58 | }; |
| 59 | + unsigned numlower; |
| 60 | + struct path lowerstack[]; |
| 59 | 61 | }; |
| 60 | 62 | |
| 61 | | −const char *ovl_opaque_xattr = "trusted.overlay.opaque"; |
| 63 | +#define OVL_MAX_STACK 500 |
| 62 | 64 | |
| 65 | +static struct dentry *__ovl_dentry_lower(struct ovl_entry *oe) |
| 66 | +{ |
| 67 | + return oe->numlower ? oe->lowerstack[0].dentry : NULL; |
| 68 | +} |
| 63 | 69 | |
| 64 | 70 | enum ovl_path_type ovl_path_type(struct dentry *dentry) |
| 65 | 71 | { |
| 66 | 72 | struct ovl_entry *oe = dentry->d_fsdata; |
| 73 | + enum ovl_path_type type = 0; |
| 67 | 74 | |
| 68 | 75 | if (oe->__upperdentry) { |
| 69 | | − if (oe->lowerdentry) { |
| 76 | + type = __OVL_PATH_UPPER; |
| 77 | + |
| 78 | + if (oe->numlower) { |
| 70 | 79 | if (S_ISDIR(dentry->d_inode->i_mode)) |
| 71 | | − return OVL_PATH_MERGE; |
| 72 | | − else |
| 73 | | − return OVL_PATH_UPPER; |
| 74 | | − } else { |
| 75 | | − if (oe->opaque) |
| 76 | | − return OVL_PATH_UPPER; |
| 77 | | − else |
| 78 | | − return OVL_PATH_PURE_UPPER; |
| 80 | + type |= __OVL_PATH_MERGE; |
| 81 | + } else if (!oe->opaque) { |
| 82 | + type |= __OVL_PATH_PURE; |
| 79 | 83 | } |
| 80 | 84 | } else { |
| 81 | | − return OVL_PATH_LOWER; |
| 85 | + if (oe->numlower > 1) |
| 86 | + type |= __OVL_PATH_MERGE; |
| 82 | 87 | } |
| 88 | + return type; |
| 83 | 89 | } |
| 84 | 90 | |
| 85 | 91 | static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe) |
| @@ -98,10 +104,9 @@ void ovl_path_upper(struct dentry *dentry, struct path *path) · 12 unmodified lines |
| 98 | 104 | |
| 99 | 105 | enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path) |
| 100 | 106 | { |
| 101 | | − |
| 102 | 107 | enum ovl_path_type type = ovl_path_type(dentry); |
| 103 | 108 | |
| 104 | | − if (type == OVL_PATH_LOWER) |
| 109 | + if (!OVL_TYPE_UPPER(type)) |
| 105 | 110 | ovl_path_lower(dentry, path); |
| 106 | 111 | else |
| 107 | 112 | ovl_path_upper(dentry, path); |
| @@ -120,7 +125,7 @@ struct dentry *ovl_dentry_lower(struct dentry *dentry) · 12 unmodified lines |
| 120 | 125 | { |
| 121 | 126 | struct ovl_entry *oe = dentry->d_fsdata; |
| 122 | 127 | |
| 123 | | − return oe->lowerdentry; |
| 128 | + return __ovl_dentry_lower(oe); |
| 124 | 129 | } |
| 125 | 130 | |
| 126 | 131 | struct dentry *ovl_dentry_real(struct dentry *dentry) |
| @@ -130,7 +135,7 @@ struct dentry *ovl_dentry_real(struct dentry *dentry) · 3 unmodified lines |
| 130 | 135 | |
| 131 | 136 | realdentry = ovl_upperdentry_dereference(oe); |
| 132 | 137 | if (!realdentry) |
| 133 | | − realdentry = oe->lowerdentry; |
| 138 | + realdentry = __ovl_dentry_lower(oe); |
| 134 | 139 | |
| 135 | 140 | return realdentry; |
| 136 | 141 | } |
| @@ -143,7 +148,7 @@ struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper) · 6 unmodified lines |
| 143 | 148 | if (realdentry) { |
| 144 | 149 | *is_upper = true; |
| 145 | 150 | } else { |
| 146 | | − realdentry = oe->lowerdentry; |
| 151 | + realdentry = __ovl_dentry_lower(oe); |
| 147 | 152 | *is_upper = false; |
| 148 | 153 | } |
| 149 | 154 | return realdentry; |
| @@ -165,11 +170,9 @@ void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache) · 15 unmodified lines |
| 165 | 170 | |
| 166 | 171 | void ovl_path_lower(struct dentry *dentry, struct path *path) |
| 167 | 172 | { |
| 168 | | − struct ovl_fs *ofs = dentry->d_sb->s_fs_info; |
| 169 | 173 | struct ovl_entry *oe = dentry->d_fsdata; |
| 170 | 174 | |
| 171 | | − path->mnt = ofs->lower_mnt; |
| 172 | | − path->dentry = oe->lowerdentry; |
| 175 | + *path = oe->numlower ? oe->lowerstack[0] : (struct path) { NULL, NULL }; |
| 173 | 176 | } |
| 174 | 177 | |
| 175 | 178 | int ovl_want_write(struct dentry *dentry) |
| @@ -249,7 +252,7 @@ static bool ovl_is_opaquedir(struct dentry *dentry) · 73 unmodified lines |
| 249 | 252 | if (!S_ISDIR(inode->i_mode) || !inode->i_op->getxattr) |
| 250 | 253 | return false; |
| 251 | 254 | |
| 252 | | − res = inode->i_op->getxattr(dentry, ovl_opaque_xattr, &val, 1); |
| 255 | + res = inode->i_op->getxattr(dentry, OVL_XATTR_OPAQUE, &val, 1); |
| 253 | 256 | if (res == 1 && val == 'y') |
| 254 | 257 | return true; |
| 255 | 258 | |
| @@ -261,8 +264,11 @@ static void ovl_dentry_release(struct dentry *dentry) · 5 unmodified lines |
| 261 | 264 | struct ovl_entry *oe = dentry->d_fsdata; |
| 262 | 265 | |
| 263 | 266 | if (oe) { |
| 267 | + unsigned int i; |
| 268 | + |
| 264 | 269 | dput(oe->__upperdentry); |
| 265 | | − dput(oe->lowerdentry); |
| 270 | + for (i = 0; i < oe->numlower; i++) |
| 271 | + dput(oe->lowerstack[i].dentry); |
| 266 | 272 | kfree_rcu(oe, rcu); |
| 267 | 273 | } |
| 268 | 274 | } |
| @@ -271,9 +277,15 @@ static const struct dentry_operations ovl_dentry_operations = { · 2 unmodified lines |
| 271 | 277 | .d_release = ovl_dentry_release, |
| 272 | 278 | }; |
| 273 | 279 | |
| 274 | | −static struct ovl_entry *ovl_alloc_entry(void) |
| 280 | +static struct ovl_entry *ovl_alloc_entry(unsigned int numlower) |
| 275 | 281 | { |
| 276 | | − return kzalloc(sizeof(struct ovl_entry), GFP_KERNEL); |
| 282 | + size_t size = offsetof(struct ovl_entry, lowerstack[numlower]); |
| 283 | + struct ovl_entry *oe = kzalloc(size, GFP_KERNEL); |
| 284 | + |
| 285 | + if (oe) |
| 286 | + oe->numlower = numlower; |
| 287 | + |
| 288 | + return oe; |
| 277 | 289 | } |
| 278 | 290 | |
| 279 | 291 | static inline struct dentry *ovl_lookup_real(struct dentry *dir, |
| @@ -295,82 +307,154 @@ static inline struct dentry *ovl_lookup_real(struct dentry *dir, · 15 unmodified lines |
| 295 | 307 | return dentry; |
| 296 | 308 | } |
| 297 | 309 | |
| 310 | +/* |
| 311 | + * Returns next layer in stack starting from top. |
| 312 | + * Returns -1 if this is the last layer. |
| 313 | + */ |
| 314 | +int ovl_path_next(int idx, struct dentry *dentry, struct path *path) |
| 315 | +{ |
| 316 | + struct ovl_entry *oe = dentry->d_fsdata; |
| 317 | + |
| 318 | + BUG_ON(idx < 0); |
| 319 | + if (idx == 0) { |
| 320 | + ovl_path_upper(dentry, path); |
| 321 | + if (path->dentry) |
| 322 | + return oe->numlower ? 1 : -1; |
| 323 | + idx++; |
| 324 | + } |
| 325 | + BUG_ON(idx > oe->numlower); |
| 326 | + *path = oe->lowerstack[idx - 1]; |
| 327 | + |
| 328 | + return (idx < oe->numlower) ? idx + 1 : -1; |
| 329 | +} |
| 330 | + |
| 298 | 331 | struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, |
| 299 | 332 | unsigned int flags) |
| 300 | 333 | { |
| 301 | 334 | struct ovl_entry *oe; |
| 302 | | − struct dentry *upperdir; |
| 303 | | − struct dentry *lowerdir; |
| 304 | | − struct dentry *upperdentry = NULL; |
| 305 | | − struct dentry *lowerdentry = NULL; |
| 335 | + struct ovl_entry *poe = dentry->d_parent->d_fsdata; |
| 336 | + struct path *stack = NULL; |
| 337 | + struct dentry *upperdir, *upperdentry = NULL; |
| 338 | + unsigned int ctr = 0; |
| 306 | 339 | struct inode *inode = NULL; |
| 340 | + bool upperopaque = false; |
| 341 | + struct dentry *this, *prev = NULL; |
| 342 | + unsigned int i; |
| 307 | 343 | int err; |
| 308 | 344 | |
| 309 | | − err = -ENOMEM; |
| 310 | | − oe = ovl_alloc_entry(); |
| 311 | | − if (!oe) |
| 312 | | − goto out; |
| 313 | | − |
| 314 | | − upperdir = ovl_dentry_upper(dentry->d_parent); |
| 315 | | − lowerdir = ovl_dentry_lower(dentry->d_parent); |
| 316 | | − |
| 345 | + upperdir = ovl_upperdentry_dereference(poe); |
| 317 | 346 | if (upperdir) { |
| 318 | | − upperdentry = ovl_lookup_real(upperdir, &dentry->d_name); |
| 319 | | − err = PTR_ERR(upperdentry); |
| 320 | | − if (IS_ERR(upperdentry)) |
| 321 | | − goto out_put_dir; |
| 322 | | − |
| 323 | | − if (lowerdir && upperdentry) { |
| 324 | | − if (ovl_is_whiteout(upperdentry)) { |
| 325 | | − dput(upperdentry); |
| 326 | | − upperdentry = NULL; |
| 327 | | − oe->opaque = true; |
| 328 | | − } else if (ovl_is_opaquedir(upperdentry)) { |
| 329 | | − oe->opaque = true; |
| 347 | + this = ovl_lookup_real(upperdir, &dentry->d_name); |
| 348 | + err = PTR_ERR(this); |
| 349 | + if (IS_ERR(this)) |
| 350 | + goto out; |
| 351 | + |
| 352 | + if (this) { |
| 353 | + if (ovl_is_whiteout(this)) { |
| 354 | + dput(this); |
| 355 | + this = NULL; |
| 356 | + upperopaque = true; |
| 357 | + } else if (poe->numlower && ovl_is_opaquedir(this)) { |
| 358 | + upperopaque = true; |
| 330 | 359 | } |
| 331 | 360 | } |
| 361 | + upperdentry = prev = this; |
| 332 | 362 | } |
| 333 | | − if (lowerdir && !oe->opaque) { |
| 334 | | − lowerdentry = ovl_lookup_real(lowerdir, &dentry->d_name); |
| 335 | | − err = PTR_ERR(lowerdentry); |
| 336 | | − if (IS_ERR(lowerdentry)) |
| 337 | | − goto out_dput_upper; |
| 363 | + |
| 364 | + if (!upperopaque && poe->numlower) { |
| 365 | + err = -ENOMEM; |
| 366 | + stack = kcalloc(poe->numlower, sizeof(struct path), GFP_KERNEL); |
| 367 | + if (!stack) |
| 368 | + goto out_put_upper; |
| 338 | 369 | } |
| 339 | 370 | |
| 340 | | − if (lowerdentry && upperdentry && |
| 341 | | − (!S_ISDIR(upperdentry->d_inode->i_mode) || |
| 342 | | − !S_ISDIR(lowerdentry->d_inode->i_mode))) { |
| 343 | | − dput(lowerdentry); |
| 344 | | − lowerdentry = NULL; |
| 345 | | − oe->opaque = true; |
| 371 | + for (i = 0; !upperopaque && i < poe->numlower; i++) { |
| 372 | + bool opaque = false; |
| 373 | + struct path lowerpath = poe->lowerstack[i]; |
| 374 | + |
| 375 | + this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name); |
| 376 | + err = PTR_ERR(this); |
| 377 | + if (IS_ERR(this)) { |
| 378 | + /* |
| 379 | + * If it's positive, then treat ENAMETOOLONG as ENOENT. |
| 380 | + */ |
| 381 | + if (err == -ENAMETOOLONG && (upperdentry || ctr)) |
| 382 | + continue; |
| 383 | + goto out_put; |
| 384 | + } |
| 385 | + if (!this) |
| 386 | + continue; |
| 387 | + if (ovl_is_whiteout(this)) { |
| 388 | + dput(this); |
| 389 | + break; |
| 390 | + } |
| 391 | + /* |
| 392 | + * Only makes sense to check opaque dir if this is not the |
| 393 | + * lowermost layer. |
| 394 | + */ |
| 395 | + if (i < poe->numlower - 1 && ovl_is_opaquedir(this)) |
| 396 | + opaque = true; |
| 397 | + |
| 398 | + if (prev && (!S_ISDIR(prev->d_inode->i_mode) || |
| 399 | + !S_ISDIR(this->d_inode->i_mode))) { |
| 400 | + /* |
| 401 | + * FIXME: check for upper-opaqueness maybe better done |
| 402 | + * in remove code. |
| 403 | + */ |
| 404 | + if (prev == upperdentry) |
| 405 | + upperopaque = true; |
| 406 | + dput(this); |
| 407 | + break; |
| 408 | + } |
| 409 | + /* |
| 410 | + * If this is a non-directory then stop here. |
| 411 | + */ |
| 412 | + if (!S_ISDIR(this->d_inode->i_mode)) |
| 413 | + opaque = true; |
| 414 | + |
| 415 | + stack[ctr].dentry = this; |
| 416 | + stack[ctr].mnt = lowerpath.mnt; |
| 417 | + ctr++; |
| 418 | + prev = this; |
| 419 | + if (opaque) |
| 420 | + break; |
| 346 | 421 | } |
| 347 | 422 | |
| 348 | | − if (lowerdentry || upperdentry) { |
| 423 | + oe = ovl_alloc_entry(ctr); |
| 424 | + err = -ENOMEM; |
| 425 | + if (!oe) |
| 426 | + goto out_put; |
| 427 | + |
| 428 | + if (upperdentry || ctr) { |
| 349 | 429 | struct dentry *realdentry; |
| 350 | 430 | |
| 351 | | − realdentry = upperdentry ? upperdentry : lowerdentry; |
| 431 | + realdentry = upperdentry ? upperdentry : stack[0].dentry; |
| 432 | + |
| 352 | 433 | err = -ENOMEM; |
| 353 | 434 | inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, |
| 354 | 435 | oe); |
| 355 | 436 | if (!inode) |
| 356 | | − goto out_dput; |
| 437 | + goto out_free_oe; |
| 357 | 438 | ovl_copyattr(realdentry->d_inode, inode); |
| 358 | 439 | } |
| 359 | 440 | |
| 441 | + oe->opaque = upperopaque; |
| 360 | 442 | oe->__upperdentry = upperdentry; |
| 361 | | − oe->lowerdentry = lowerdentry; |
| 362 | | − |
| 443 | + memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr); |
| 444 | + kfree(stack); |
| 363 | 445 | dentry->d_fsdata = oe; |
| 364 | 446 | d_add(dentry, inode); |
| 365 | 447 | |
| 366 | 448 | return NULL; |
| 367 | 449 | |
| 368 | | −out_dput: |
| 369 | | − dput(lowerdentry); |
| 370 | | −out_dput_upper: |
| 371 | | − dput(upperdentry); |
| 372 | | −out_put_dir: |
| 450 | +out_free_oe: |
| 373 | 451 | kfree(oe); |
| 452 | +out_put: |
| 453 | + for (i = 0; i < ctr; i++) |
| 454 | + dput(stack[i].dentry); |
| 455 | + kfree(stack); |
| 456 | +out_put_upper: |
| 457 | + dput(upperdentry); |
| 374 | 458 | out: |
| 375 | 459 | return ERR_PTR(err); |
| 376 | 460 | } |
| @@ -383,10 +467,12 @@ struct file *ovl_path_open(struct path *path, int flags) · 6 unmodified lines |
| 383 | 467 | static void ovl_put_super(struct super_block *sb) |
| 384 | 468 | { |
| 385 | 469 | struct ovl_fs *ufs = sb->s_fs_info; |
| 470 | + unsigned i; |
| 386 | 471 | |
| 387 | 472 | dput(ufs->workdir); |
| 388 | 473 | mntput(ufs->upper_mnt); |
| 389 | | − mntput(ufs->lower_mnt); |
| 474 | + for (i = 0; i < ufs->numlower; i++) |
| 475 | + mntput(ufs->lower_mnt[i]); |
| 390 | 476 | |
| 391 | 477 | kfree(ufs->config.lowerdir); |
| 392 | 478 | kfree(ufs->config.upperdir); |
| @@ -400,7 +486,7 @@ static void ovl_put_super(struct super_block *sb) · 7 unmodified lines |
| 400 | 486 | * @buf: The struct kstatfs to fill in with stats |
| 401 | 487 | * |
| 402 | 488 | * Get the filesystem statistics. As writes always target the upper layer |
| 403 | | − * filesystem pass the statfs to the same filesystem. |
| 489 | + * filesystem pass the statfs to the upper filesystem (if it exists) |
| 404 | 490 | */ |
| 405 | 491 | static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) |
| 406 | 492 | { |
| @@ -409,7 +495,7 @@ static int ovl_statfs(struct dentry *dentry, struct kstatfs *buf) · 2 unmodified lines |
| 409 | 495 | struct path path; |
| 410 | 496 | int err; |
| 411 | 497 | |
| 412 | | − ovl_path_upper(root_dentry, &path); |
| 498 | + ovl_path_real(root_dentry, &path); |
| 413 | 499 | |
| 414 | 500 | err = vfs_statfs(&path, buf); |
| 415 | 501 | if (!err) { |
| @@ -432,8 +518,21 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry) · 16 unmodified lines |
| 432 | 518 | struct ovl_fs *ufs = sb->s_fs_info; |
| 433 | 519 | |
| 434 | 520 | seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); |
| 435 | | − seq_printf(m, ",upperdir=%s", ufs->config.upperdir); |
| 436 | | − seq_printf(m, ",workdir=%s", ufs->config.workdir); |
| 521 | + if (ufs->config.upperdir) { |
| 522 | + seq_printf(m, ",upperdir=%s", ufs->config.upperdir); |
| 523 | + seq_printf(m, ",workdir=%s", ufs->config.workdir); |
| 524 | + } |
| 525 | + return 0; |
| 526 | +} |
| 527 | + |
| 528 | +static int ovl_remount(struct super_block *sb, int *flags, char *data) |
| 529 | +{ |
| 530 | + struct ovl_fs *ufs = sb->s_fs_info; |
| 531 | + |
| 532 | + if (!(*flags & MS_RDONLY) && |
| 533 | + (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY))) |
| 534 | + return -EROFS; |
| 535 | + |
| 437 | 536 | return 0; |
| 438 | 537 | } |
| 439 | 538 | |
| @@ -441,6 +540,7 @@ static const struct super_operations ovl_super_operations = { · 1 unmodified line |
| 441 | 540 | .put_super = ovl_put_super, |
| 442 | 541 | .statfs = ovl_statfs, |
| 443 | 542 | .show_options = ovl_show_options, |
| 543 | + .remount_fs = ovl_remount, |
| 444 | 544 | }; |
| 445 | 545 | |
| 446 | 546 | enum { |
| @@ -585,24 +685,6 @@ static void ovl_unescape(char *s) · 138 unmodified lines |
| 585 | 685 | } |
| 586 | 686 | } |
| 587 | 687 | |
| 588 | | −static int ovl_mount_dir(const char *name, struct path *path) |
| 589 | | −{ |
| 590 | | − int err; |
| 591 | | − char *tmp = kstrdup(name, GFP_KERNEL); |
| 592 | | − |
| 593 | | − if (!tmp) |
| 594 | | − return -ENOMEM; |
| 595 | | − |
| 596 | | − ovl_unescape(tmp); |
| 597 | | − err = kern_path(tmp, LOOKUP_FOLLOW, path); |
| 598 | | − if (err) { |
| 599 | | − pr_err("overlayfs: failed to resolve '%s': %i\n", tmp, err); |
| 600 | | − err = -EINVAL; |
| 601 | | − } |
| 602 | | − kfree(tmp); |
| 603 | | − return err; |
| 604 | | −} |
| 605 | | − |
| 606 | 688 | static bool ovl_is_allowed_fs_type(struct dentry *root) |
| 607 | 689 | { |
| 608 | 690 | const struct dentry_operations *dop = root->d_op; |
| @@ -622,6 +704,75 @@ static bool ovl_is_allowed_fs_type(struct dentry *root) · 13 unmodified lines |
| 622 | 704 | return true; |
| 623 | 705 | } |
| 624 | 706 | |
| 707 | +static int ovl_mount_dir_noesc(const char *name, struct path *path) |
| 708 | +{ |
| 709 | + int err = -EINVAL; |
| 710 | + |
| 711 | + if (!*name) { |
| 712 | + pr_err("overlayfs: empty lowerdir\n"); |
| 713 | + goto out; |
| 714 | + } |
| 715 | + err = kern_path(name, LOOKUP_FOLLOW, path); |
| 716 | + if (err) { |
| 717 | + pr_err("overlayfs: failed to resolve '%s': %i\n", name, err); |
| 718 | + goto out; |
| 719 | + } |
| 720 | + err = -EINVAL; |
| 721 | + if (!ovl_is_allowed_fs_type(path->dentry)) { |
| 722 | + pr_err("overlayfs: filesystem on '%s' not supported\n", name); |
| 723 | + goto out_put; |
| 724 | + } |
| 725 | + if (!S_ISDIR(path->dentry->d_inode->i_mode)) { |
| 726 | + pr_err("overlayfs: '%s' not a directory\n", name); |
| 727 | + goto out_put; |
| 728 | + } |
| 729 | + return 0; |
| 730 | + |
| 731 | +out_put: |
| 732 | + path_put(path); |
| 733 | +out: |
| 734 | + return err; |
| 735 | +} |
| 736 | + |
| 737 | +static int ovl_mount_dir(const char *name, struct path *path) |
| 738 | +{ |
| 739 | + int err = -ENOMEM; |
| 740 | + char *tmp = kstrdup(name, GFP_KERNEL); |
| 741 | + |
| 742 | + if (tmp) { |
| 743 | + ovl_unescape(tmp); |
| 744 | + err = ovl_mount_dir_noesc(tmp, path); |
| 745 | + kfree(tmp); |
| 746 | + } |
| 747 | + return err; |
| 748 | +} |
| 749 | + |
| 750 | +static int ovl_lower_dir(const char *name, struct path *path, long *namelen, |
| 751 | + int *stack_depth) |
| 752 | +{ |
| 753 | + int err; |
| 754 | + struct kstatfs statfs; |
| 755 | + |
| 756 | + err = ovl_mount_dir_noesc(name, path); |
| 757 | + if (err) |
| 758 | + goto out; |
| 759 | + |
| 760 | + err = vfs_statfs(path, &statfs); |
| 761 | + if (err) { |
| 762 | + pr_err("overlayfs: statfs failed on '%s'\n", name); |
| 763 | + goto out_put; |
| 764 | + } |
| 765 | + *namelen = max(*namelen, statfs.f_namelen); |
| 766 | + *stack_depth = max(*stack_depth, path->mnt->mnt_sb->s_stack_depth); |
| 767 | + |
| 768 | + return 0; |
| 769 | + |
| 770 | +out_put: |
| 771 | + path_put(path); |
| 772 | +out: |
| 773 | + return err; |
| 774 | +} |
| 775 | + |
| 625 | 776 | /* Workdir should not be subdir of upperdir and vice versa */ |
| 626 | 777 | static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir) |
| 627 | 778 | { |
| @@ -634,16 +785,39 @@ static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir) · 6 unmodified lines |
| 634 | 785 | return ok; |
| 635 | 786 | } |
| 636 | 787 | |
| 788 | +static unsigned int ovl_split_lowerdirs(char *str) |
| 789 | +{ |
| 790 | + unsigned int ctr = 1; |
| 791 | + char *s, *d; |
| 792 | + |
| 793 | + for (s = d = str;; s++, d++) { |
| 794 | + if (*s == '\\') { |
| 795 | + s++; |
| 796 | + } else if (*s == ':') { |
| 797 | + *d = '\0'; |
| 798 | + ctr++; |
| 799 | + continue; |
| 800 | + } |
| 801 | + *d = *s; |
| 802 | + if (!*s) |
| 803 | + break; |
| 804 | + } |
| 805 | + return ctr; |
| 806 | +} |
| 807 | + |
| 637 | 808 | static int ovl_fill_super(struct super_block *sb, void *data, int silent) |
| 638 | 809 | { |
| 639 | | − struct path lowerpath; |
| 640 | | − struct path upperpath; |
| 641 | | − struct path workpath; |
| 642 | | − struct inode *root_inode; |
| 810 | + struct path upperpath = { NULL, NULL }; |
| 811 | + struct path workpath = { NULL, NULL }; |
| 643 | 812 | struct dentry *root_dentry; |
| 644 | 813 | struct ovl_entry *oe; |
| 645 | 814 | struct ovl_fs *ufs; |
| 646 | | − struct kstatfs statfs; |
| 815 | + struct path *stack = NULL; |
| 816 | + char *lowertmp; |
| 817 | + char *lower; |
| 818 | + unsigned int numlower; |
| 819 | + unsigned int stacklen = 0; |
| 820 | + unsigned int i; |
| 647 | 821 | int err; |
| 648 | 822 | |
| 649 | 823 | err = -ENOMEM; |
| @@ -655,123 +829,135 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) · 5 unmodified lines |
| 655 | 829 | if (err) |
| 656 | 830 | goto out_free_config; |
| 657 | 831 | |
| 658 | | − /* FIXME: workdir is not needed for a R/O mount */ |
| 659 | 832 | err = -EINVAL; |
| 660 | | − if (!ufs->config.upperdir || !ufs->config.lowerdir || |
| 661 | | − !ufs->config.workdir) { |
| 662 | | − pr_err("overlayfs: missing upperdir or lowerdir or workdir\n"); |
| 833 | + if (!ufs->config.lowerdir) { |
| 834 | + pr_err("overlayfs: missing 'lowerdir'\n"); |
| 663 | 835 | goto out_free_config; |
| 664 | 836 | } |
| 665 | 837 | |
| 666 | | − err = -ENOMEM; |
| 667 | | − oe = ovl_alloc_entry(); |
| 668 | | − if (oe == NULL) |
| 669 | | − goto out_free_config; |
| 670 | | − |
| 671 | | − err = ovl_mount_dir(ufs->config.upperdir, &upperpath); |
| 672 | | − if (err) |
| 673 | | − goto out_free_oe; |
| 674 | | − |
| 675 | | − err = ovl_mount_dir(ufs->config.lowerdir, &lowerpath); |
| 676 | | − if (err) |
| 677 | | − goto out_put_upperpath; |
| 838 | + sb->s_stack_depth = 0; |
| 839 | + if (ufs->config.upperdir) { |
| 840 | + /* FIXME: workdir is not needed for a R/O mount */ |
| 841 | + if (!ufs->config.workdir) { |
| 842 | + pr_err("overlayfs: missing 'workdir'\n"); |
| 843 | + goto out_free_config; |
| 844 | + } |
| 678 | 845 | |
| 679 | | − err = ovl_mount_dir(ufs->config.workdir, &workpath); |
| 680 | | − if (err) |
| 681 | | − goto out_put_lowerpath; |
| 846 | + err = ovl_mount_dir(ufs->config.upperdir, &upperpath); |
| 847 | + if (err) |
| 848 | + goto out_free_config; |
| 682 | 849 | |
| 683 | | − err = -EINVAL; |
| 684 | | − if (!S_ISDIR(upperpath.dentry->d_inode->i_mode) || |
| 685 | | − !S_ISDIR(lowerpath.dentry->d_inode->i_mode) || |
| 686 | | − !S_ISDIR(workpath.dentry->d_inode->i_mode)) { |
| 687 | | − pr_err("overlayfs: upperdir or lowerdir or workdir not a directory\n"); |
| 688 | | − goto out_put_workpath; |
| 689 | | − } |
| 850 | + err = ovl_mount_dir(ufs->config.workdir, &workpath); |
| 851 | + if (err) |
| 852 | + goto out_put_upperpath; |
| 690 | 853 | |
| 691 | | − if (upperpath.mnt != workpath.mnt) { |
| 692 | | − pr_err("overlayfs: workdir and upperdir must reside under the same mount\n"); |
| 693 | | − goto out_put_workpath; |
| 694 | | − } |
| 695 | | − if (!ovl_workdir_ok(workpath.dentry, upperpath.dentry)) { |
| 696 | | − pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); |
| 697 | | − goto out_put_workpath; |
| 854 | + err = -EINVAL; |
| 855 | + if (upperpath.mnt != workpath.mnt) { |
| 856 | + pr_err("overlayfs: workdir and upperdir must reside under the same mount\n"); |
| 857 | + goto out_put_workpath; |
| 858 | + } |
| 859 | + if (!ovl_workdir_ok(workpath.dentry, upperpath.dentry)) { |
| 860 | + pr_err("overlayfs: workdir and upperdir must be separate subtrees\n"); |
| 861 | + goto out_put_workpath; |
| 862 | + } |
| 863 | + sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth; |
| 698 | 864 | } |
| 699 | | − |
| 700 | | − if (!ovl_is_allowed_fs_type(upperpath.dentry)) { |
| 701 | | − pr_err("overlayfs: filesystem of upperdir is not supported\n"); |
| 865 | + err = -ENOMEM; |
| 866 | + lowertmp = kstrdup(ufs->config.lowerdir, GFP_KERNEL); |
| 867 | + if (!lowertmp) |
| 702 | 868 | goto out_put_workpath; |
| 703 | | − } |
| 704 | 869 | |
| 705 | | − if (!ovl_is_allowed_fs_type(lowerpath.dentry)) { |
| 706 | | − pr_err("overlayfs: filesystem of lowerdir is not supported\n"); |
| 707 | | − goto out_put_workpath; |
| 708 | | − } |
| 870 | + err = -EINVAL; |
| 871 | + stacklen = ovl_split_lowerdirs(lowertmp); |
| 872 | + if (stacklen > OVL_MAX_STACK) |
| 873 | + goto out_free_lowertmp; |
| 874 | + |
| 875 | + stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL); |
| 876 | + if (!stack) |
| 877 | + goto out_free_lowertmp; |
| 878 | + |
| 879 | + lower = lowertmp; |
| 880 | + for (numlower = 0; numlower < stacklen; numlower++) { |
| 881 | + err = ovl_lower_dir(lower, &stack[numlower], |
| 882 | + &ufs->lower_namelen, &sb->s_stack_depth); |
| 883 | + if (err) |
| 884 | + goto out_put_lowerpath; |
| 709 | 885 | |
| 710 | | − err = vfs_statfs(&lowerpath, &statfs); |
| 711 | | − if (err) { |
| 712 | | − pr_err("overlayfs: statfs failed on lowerpath\n"); |
| 713 | | − goto out_put_workpath; |
| 886 | + lower = strchr(lower, '\0') + 1; |
| 714 | 887 | } |
| 715 | | − ufs->lower_namelen = statfs.f_namelen; |
| 716 | | − |
| 717 | | − sb->s_stack_depth = max(upperpath.mnt->mnt_sb->s_stack_depth, |
| 718 | | − lowerpath.mnt->mnt_sb->s_stack_depth) + 1; |
| 719 | 888 | |
| 720 | 889 | err = -EINVAL; |
| 890 | + sb->s_stack_depth++; |
| 721 | 891 | if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { |
| 722 | 892 | pr_err("overlayfs: maximum fs stacking depth exceeded\n"); |
| 723 | | − goto out_put_workpath; |
| 893 | + goto out_put_lowerpath; |
| 724 | 894 | } |
| 725 | 895 | |
| 726 | | − ufs->upper_mnt = clone_private_mount(&upperpath); |
| 727 | | − err = PTR_ERR(ufs->upper_mnt); |
| 728 | | − if (IS_ERR(ufs->upper_mnt)) { |
| 729 | | − pr_err("overlayfs: failed to clone upperpath\n"); |
| 730 | | − goto out_put_workpath; |
| 731 | | − } |
| 896 | + if (ufs->config.upperdir) { |
| 897 | + ufs->upper_mnt = clone_private_mount(&upperpath); |
| 898 | + err = PTR_ERR(ufs->upper_mnt); |
| 899 | + if (IS_ERR(ufs->upper_mnt)) { |
| 900 | + pr_err("overlayfs: failed to clone upperpath\n"); |
| 901 | + goto out_put_lowerpath; |
| 902 | + } |
| 732 | 903 | |
| 733 | | − ufs->lower_mnt = clone_private_mount(&lowerpath); |
| 734 | | − err = PTR_ERR(ufs->lower_mnt); |
| 735 | | − if (IS_ERR(ufs->lower_mnt)) { |
| 736 | | − pr_err("overlayfs: failed to clone lowerpath\n"); |
| 737 | | − goto out_put_upper_mnt; |
| 904 | + ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); |
| 905 | + err = PTR_ERR(ufs->workdir); |
| 906 | + if (IS_ERR(ufs->workdir)) { |
| 907 | + pr_err("overlayfs: failed to create directory %s/%s\n", |
| 908 | + ufs->config.workdir, OVL_WORKDIR_NAME); |
| 909 | + goto out_put_upper_mnt; |
| 910 | + } |
| 738 | 911 | } |
| 739 | 912 | |
| 740 | | − ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); |
| 741 | | − err = PTR_ERR(ufs->workdir); |
| 742 | | − if (IS_ERR(ufs->workdir)) { |
| 743 | | − pr_err("overlayfs: failed to create directory %s/%s\n", |
| 744 | | − ufs->config.workdir, OVL_WORKDIR_NAME); |
| 745 | | − goto out_put_lower_mnt; |
| 746 | | − } |
| 913 | + err = -ENOMEM; |
| 914 | + ufs->lower_mnt = kcalloc(numlower, sizeof(struct vfsmount *), GFP_KERNEL); |
| 915 | + if (ufs->lower_mnt == NULL) |
| 916 | + goto out_put_workdir; |
| 917 | + for (i = 0; i < numlower; i++) { |
| 918 | + struct vfsmount *mnt = clone_private_mount(&stack[i]); |
| 747 | 919 | |
| 748 | | − /* |
| 749 | | − * Make lower_mnt R/O. That way fchmod/fchown on lower file |
| 750 | | − * will fail instead of modifying lower fs. |
| 751 | | − */ |
| 752 | | − ufs->lower_mnt->mnt_flags |= MNT_READONLY; |
| 920 | + err = PTR_ERR(mnt); |
| 921 | + if (IS_ERR(mnt)) { |
| 922 | + pr_err("overlayfs: failed to clone lowerpath\n"); |
| 923 | + goto out_put_lower_mnt; |
| 924 | + } |
| 925 | + /* |
| 926 | + * Make lower_mnt R/O. That way fchmod/fchown on lower file |
| 927 | + * will fail instead of modifying lower fs. |
| 928 | + */ |
| 929 | + mnt->mnt_flags |= MNT_READONLY; |
| 930 | + |
| 931 | + ufs->lower_mnt[ufs->numlower] = mnt; |
| 932 | + ufs->numlower++; |
| 933 | + } |
| 753 | 934 | |
| 754 | | − /* If the upper fs is r/o, we mark overlayfs r/o too */ |
| 755 | | − if (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY) |
| 935 | + /* If the upper fs is r/o or nonexistent, we mark overlayfs r/o too */ |
| 936 | + if (!ufs->upper_mnt || (ufs->upper_mnt->mnt_sb->s_flags & MS_RDONLY)) |
| 756 | 937 | sb->s_flags |= MS_RDONLY; |
| 757 | 938 | |
| 758 | 939 | sb->s_d_op = &ovl_dentry_operations; |
| 759 | 940 | |
| 760 | 941 | err = -ENOMEM; |
| 761 | | − root_inode = ovl_new_inode(sb, S_IFDIR, oe); |
| 762 | | − if (!root_inode) |
| 763 | | − goto out_put_workdir; |
| 942 | + oe = ovl_alloc_entry(numlower); |
| 943 | + if (!oe) |
| 944 | + goto out_put_lower_mnt; |
| 764 | 945 | |
| 765 | | − root_dentry = d_make_root(root_inode); |
| 946 | + root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe)); |
| 766 | 947 | if (!root_dentry) |
| 767 | | − goto out_put_workdir; |
| 948 | + goto out_free_oe; |
| 768 | 949 | |
| 769 | 950 | mntput(upperpath.mnt); |
| 770 | | − mntput(lowerpath.mnt); |
| 951 | + for (i = 0; i < numlower; i++) |
| 952 | + mntput(stack[i].mnt); |
| 771 | 953 | path_put(&workpath); |
| 954 | + kfree(lowertmp); |
| 772 | 955 | |
| 773 | 956 | oe->__upperdentry = upperpath.dentry; |
| 774 | | − oe->lowerdentry = lowerpath.dentry; |
| 957 | + for (i = 0; i < numlower; i++) { |
| 958 | + oe->lowerstack[i].dentry = stack[i].dentry; |
| 959 | + oe->lowerstack[i].mnt = ufs->lower_mnt[i]; |
| 960 | + } |
| 775 | 961 | |
| 776 | 962 | root_dentry->d_fsdata = oe; |
| 777 | 963 | |
| @@ -782,20 +968,26 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) · 4 unmodified lines |
| 782 | 968 | |
| 783 | 969 | return 0; |
| 784 | 970 | |
| 971 | +out_free_oe: |
| 972 | + kfree(oe); |
| 973 | +out_put_lower_mnt: |
| 974 | + for (i = 0; i < ufs->numlower; i++) |
| 975 | + mntput(ufs->lower_mnt[i]); |
| 976 | + kfree(ufs->lower_mnt); |
| 785 | 977 | out_put_workdir: |
| 786 | 978 | dput(ufs->workdir); |
| 787 | | −out_put_lower_mnt: |
| 788 | | − mntput(ufs->lower_mnt); |
| 789 | 979 | out_put_upper_mnt: |
| 790 | 980 | mntput(ufs->upper_mnt); |
| 981 | +out_put_lowerpath: |
| 982 | + for (i = 0; i < numlower; i++) |
| 983 | + path_put(&stack[i]); |
| 984 | + kfree(stack); |
| 985 | +out_free_lowertmp: |
| 986 | + kfree(lowertmp); |
| 791 | 987 | out_put_workpath: |
| 792 | 988 | path_put(&workpath); |
| 793 | | −out_put_lowerpath: |
| 794 | | − path_put(&lowerpath); |
| 795 | 989 | out_put_upperpath: |
| 796 | 990 | path_put(&upperpath); |
| 797 | | −out_free_oe: |
| 798 | | − kfree(oe); |
| 799 | 991 | out_free_config: |
| 800 | 992 | kfree(ufs->config.lowerdir); |
| 801 | 993 | kfree(ufs->config.upperdir); |