aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:24 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:24 -0400
commit51f7e52dc943468c6929fa0a82d4afac3c8e9636 (patch)
treef5eb45b46ae8b7103ef9b77bb1b711472b400c19
parent39b681f8026c170a73972517269efc830db0d7ce (diff)
ovl: share inode for hard link
Inode attributes are copied up to overlay inode (uid, gid, mode, atime, mtime, ctime) so generic code using these fields works correcty. If a hard link is created in overlayfs separate inodes are allocated for each link. If chmod/chown/etc. is performed on one of the links then the inode belonging to the other ones won't be updated. This patch attempts to fix this by sharing inodes for hard links. Use inode hash (with real inode pointer as a key) to make sure overlay inodes are shared for hard links on upper. Hard links on lower are still split (which is not user observable until the copy-up happens, see Documentation/filesystems/overlayfs.txt under "Non-standard behavior"). The inode is only inserted in the hash if it is non-directoy and upper. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/dir.c84
-rw-r--r--fs/overlayfs/inode.c51
-rw-r--r--fs/overlayfs/overlayfs.h1
-rw-r--r--fs/overlayfs/super.c12
4 files changed, 100 insertions, 48 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 96b1bdcf3674..d456e9fb012a 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -163,12 +163,17 @@ static int ovl_dir_getattr(struct vfsmount *mnt, struct dentry *dentry,
163 163
164/* Common operations required to be done after creation of file on upper */ 164/* Common operations required to be done after creation of file on upper */
165static void ovl_instantiate(struct dentry *dentry, struct inode *inode, 165static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
166 struct dentry *newdentry) 166 struct dentry *newdentry, bool hardlink)
167{ 167{
168 ovl_dentry_version_inc(dentry->d_parent); 168 ovl_dentry_version_inc(dentry->d_parent);
169 ovl_dentry_update(dentry, newdentry); 169 ovl_dentry_update(dentry, newdentry);
170 ovl_inode_update(inode, d_inode(newdentry)); 170 if (!hardlink) {
171 ovl_copyattr(newdentry->d_inode, inode); 171 ovl_inode_update(inode, d_inode(newdentry));
172 ovl_copyattr(newdentry->d_inode, inode);
173 } else {
174 WARN_ON(ovl_inode_real(inode, NULL) != d_inode(newdentry));
175 inc_nlink(inode);
176 }
172 d_instantiate(dentry, inode); 177 d_instantiate(dentry, inode);
173} 178}
174 179
@@ -191,7 +196,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
191 if (err) 196 if (err)
192 goto out_dput; 197 goto out_dput;
193 198
194 ovl_instantiate(dentry, inode, newdentry); 199 ovl_instantiate(dentry, inode, newdentry, !!hardlink);
195 newdentry = NULL; 200 newdentry = NULL;
196out_dput: 201out_dput:
197 dput(newdentry); 202 dput(newdentry);
@@ -361,7 +366,8 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
361 /* 366 /*
362 * mode could have been mutilated due to umask (e.g. sgid directory) 367 * mode could have been mutilated due to umask (e.g. sgid directory)
363 */ 368 */
364 if (!S_ISLNK(stat->mode) && newdentry->d_inode->i_mode != stat->mode) { 369 if (!hardlink &&
370 !S_ISLNK(stat->mode) && newdentry->d_inode->i_mode != stat->mode) {
365 struct iattr attr = { 371 struct iattr attr = {
366 .ia_valid = ATTR_MODE, 372 .ia_valid = ATTR_MODE,
367 .ia_mode = stat->mode, 373 .ia_mode = stat->mode,
@@ -373,7 +379,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
373 goto out_cleanup; 379 goto out_cleanup;
374 } 380 }
375 381
376 if (S_ISDIR(stat->mode)) { 382 if (!hardlink && S_ISDIR(stat->mode)) {
377 err = ovl_set_opaque(newdentry); 383 err = ovl_set_opaque(newdentry);
378 if (err) 384 if (err)
379 goto out_cleanup; 385 goto out_cleanup;
@@ -389,7 +395,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
389 if (err) 395 if (err)
390 goto out_cleanup; 396 goto out_cleanup;
391 } 397 }
392 ovl_instantiate(dentry, inode, newdentry); 398 ovl_instantiate(dentry, inode, newdentry, !!hardlink);
393 newdentry = NULL; 399 newdentry = NULL;
394out_dput2: 400out_dput2:
395 dput(upper); 401 dput(upper);
@@ -405,28 +411,17 @@ out_cleanup:
405 goto out_dput2; 411 goto out_dput2;
406} 412}
407 413
408static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev, 414static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
409 const char *link, struct dentry *hardlink) 415 struct kstat *stat, const char *link,
416 struct dentry *hardlink)
410{ 417{
411 int err; 418 int err;
412 struct inode *inode;
413 const struct cred *old_cred; 419 const struct cred *old_cred;
414 struct cred *override_cred; 420 struct cred *override_cred;
415 struct kstat stat = {
416 .rdev = rdev,
417 };
418
419 err = -ENOMEM;
420 inode = ovl_new_inode(dentry->d_sb, mode);
421 if (!inode)
422 goto out;
423 421
424 err = ovl_copy_up(dentry->d_parent); 422 err = ovl_copy_up(dentry->d_parent);
425 if (err) 423 if (err)
426 goto out_iput; 424 return err;
427
428 inode_init_owner(inode, dentry->d_parent->d_inode, mode);
429 stat.mode = inode->i_mode;
430 425
431 old_cred = ovl_override_creds(dentry->d_sb); 426 old_cred = ovl_override_creds(dentry->d_sb);
432 err = -ENOMEM; 427 err = -ENOMEM;
@@ -438,10 +433,10 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
438 put_cred(override_cred); 433 put_cred(override_cred);
439 434
440 if (!ovl_dentry_is_opaque(dentry)) 435 if (!ovl_dentry_is_opaque(dentry))
441 err = ovl_create_upper(dentry, inode, &stat, link, 436 err = ovl_create_upper(dentry, inode, stat, link,
442 hardlink); 437 hardlink);
443 else 438 else
444 err = ovl_create_over_whiteout(dentry, inode, &stat, 439 err = ovl_create_over_whiteout(dentry, inode, stat,
445 link, hardlink); 440 link, hardlink);
446 } 441 }
447 revert_creds(old_cred); 442 revert_creds(old_cred);
@@ -451,11 +446,7 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
451 WARN_ON(inode->i_mode != realinode->i_mode); 446 WARN_ON(inode->i_mode != realinode->i_mode);
452 WARN_ON(!uid_eq(inode->i_uid, realinode->i_uid)); 447 WARN_ON(!uid_eq(inode->i_uid, realinode->i_uid));
453 WARN_ON(!gid_eq(inode->i_gid, realinode->i_gid)); 448 WARN_ON(!gid_eq(inode->i_gid, realinode->i_gid));
454 inode = NULL;
455 } 449 }
456out_iput:
457 iput(inode);
458out:
459 return err; 450 return err;
460} 451}
461 452
@@ -463,13 +454,30 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
463 const char *link) 454 const char *link)
464{ 455{
465 int err; 456 int err;
457 struct inode *inode;
458 struct kstat stat = {
459 .rdev = rdev,
460 };
466 461
467 err = ovl_want_write(dentry); 462 err = ovl_want_write(dentry);
468 if (!err) { 463 if (err)
469 err = ovl_create_or_link(dentry, mode, rdev, link, NULL); 464 goto out;
470 ovl_drop_write(dentry); 465
471 } 466 err = -ENOMEM;
467 inode = ovl_new_inode(dentry->d_sb, mode);
468 if (!inode)
469 goto out_drop_write;
470
471 inode_init_owner(inode, dentry->d_parent->d_inode, mode);
472 stat.mode = inode->i_mode;
473
474 err = ovl_create_or_link(dentry, inode, &stat, link, NULL);
475 if (err)
476 iput(inode);
472 477
478out_drop_write:
479 ovl_drop_write(dentry);
480out:
473 return err; 481 return err;
474} 482}
475 483
@@ -504,7 +512,7 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
504 struct dentry *new) 512 struct dentry *new)
505{ 513{
506 int err; 514 int err;
507 struct dentry *upper; 515 struct inode *inode;
508 516
509 err = ovl_want_write(old); 517 err = ovl_want_write(old);
510 if (err) 518 if (err)
@@ -514,8 +522,12 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
514 if (err) 522 if (err)
515 goto out_drop_write; 523 goto out_drop_write;
516 524
517 upper = ovl_dentry_upper(old); 525 inode = d_inode(old);
518 err = ovl_create_or_link(new, upper->d_inode->i_mode, 0, NULL, upper); 526 ihold(inode);
527
528 err = ovl_create_or_link(new, inode, NULL, NULL, ovl_dentry_upper(old));
529 if (err)
530 iput(inode);
519 531
520out_drop_write: 532out_drop_write:
521 ovl_drop_write(old); 533 ovl_drop_write(old);
@@ -684,6 +696,8 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
684 else 696 else
685 err = ovl_remove_and_whiteout(dentry, is_dir); 697 err = ovl_remove_and_whiteout(dentry, is_dir);
686 revert_creds(old_cred); 698 revert_creds(old_cred);
699 if (!err && !is_dir)
700 drop_nlink(dentry->d_inode);
687out_drop_write: 701out_drop_write:
688 ovl_drop_write(dentry); 702 ovl_drop_write(dentry);
689out: 703out:
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 2bdd3cae0f71..6be0d276fd05 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -409,14 +409,8 @@ static const struct inode_operations ovl_symlink_inode_operations = {
409 .update_time = ovl_update_time, 409 .update_time = ovl_update_time,
410}; 410};
411 411
412struct inode *ovl_new_inode(struct super_block *sb, umode_t mode) 412static void ovl_fill_inode(struct inode *inode, umode_t mode)
413{ 413{
414 struct inode *inode;
415
416 inode = new_inode(sb);
417 if (!inode)
418 return NULL;
419
420 inode->i_ino = get_next_ino(); 414 inode->i_ino = get_next_ino();
421 inode->i_mode = mode; 415 inode->i_mode = mode;
422 inode->i_flags |= S_NOCMTIME; 416 inode->i_flags |= S_NOCMTIME;
@@ -432,6 +426,10 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode)
432 inode->i_op = &ovl_symlink_inode_operations; 426 inode->i_op = &ovl_symlink_inode_operations;
433 break; 427 break;
434 428
429 default:
430 WARN(1, "illegal file type: %i\n", mode);
431 /* Fall through */
432
435 case S_IFREG: 433 case S_IFREG:
436 case S_IFSOCK: 434 case S_IFSOCK:
437 case S_IFBLK: 435 case S_IFBLK:
@@ -439,11 +437,42 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode)
439 case S_IFIFO: 437 case S_IFIFO:
440 inode->i_op = &ovl_file_inode_operations; 438 inode->i_op = &ovl_file_inode_operations;
441 break; 439 break;
440 }
441}
442 442
443 default: 443struct inode *ovl_new_inode(struct super_block *sb, umode_t mode)
444 WARN(1, "illegal file type: %i\n", mode); 444{
445 iput(inode); 445 struct inode *inode;
446 inode = NULL; 446
447 inode = new_inode(sb);
448 if (inode)
449 ovl_fill_inode(inode, mode);
450
451 return inode;
452}
453
454static int ovl_inode_test(struct inode *inode, void *data)
455{
456 return ovl_inode_real(inode, NULL) == data;
457}
458
459static int ovl_inode_set(struct inode *inode, void *data)
460{
461 inode->i_private = (void *) (((unsigned long) data) | OVL_ISUPPER_MASK);
462 return 0;
463}
464
465struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode)
466
467{
468 struct inode *inode;
469
470 inode = iget5_locked(sb, (unsigned long) realinode,
471 ovl_inode_test, ovl_inode_set, realinode);
472 if (inode && inode->i_state & I_NEW) {
473 ovl_fill_inode(inode, realinode->i_mode);
474 set_nlink(inode, realinode->i_nlink);
475 unlock_new_inode(inode);
447 } 476 }
448 477
449 return inode; 478 return inode;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 6410209ea616..abeef1e6db56 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -195,6 +195,7 @@ int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
195int ovl_update_time(struct inode *inode, struct timespec *ts, int flags); 195int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
196 196
197struct inode *ovl_new_inode(struct super_block *sb, umode_t mode); 197struct inode *ovl_new_inode(struct super_block *sb, umode_t mode);
198struct inode *ovl_get_inode(struct super_block *sb, struct inode *realinode);
198static inline void ovl_copyattr(struct inode *from, struct inode *to) 199static inline void ovl_copyattr(struct inode *from, struct inode *to)
199{ 200{
200 to->i_uid = from->i_uid; 201 to->i_uid = from->i_uid;
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 313f773652ff..44c4510f5adf 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -232,8 +232,11 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry)
232void ovl_inode_update(struct inode *inode, struct inode *upperinode) 232void ovl_inode_update(struct inode *inode, struct inode *upperinode)
233{ 233{
234 WARN_ON(!upperinode); 234 WARN_ON(!upperinode);
235 WARN_ON(!inode_unhashed(inode));
235 WRITE_ONCE(inode->i_private, 236 WRITE_ONCE(inode->i_private,
236 (unsigned long) upperinode | OVL_ISUPPER_MASK); 237 (unsigned long) upperinode | OVL_ISUPPER_MASK);
238 if (!S_ISDIR(upperinode->i_mode))
239 __insert_inode_hash(inode, (unsigned long) upperinode);
237} 240}
238 241
239void ovl_dentry_version_inc(struct dentry *dentry) 242void ovl_dentry_version_inc(struct dentry *dentry)
@@ -572,10 +575,15 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
572 realinode = d_inode(realdentry); 575 realinode = d_inode(realdentry);
573 576
574 err = -ENOMEM; 577 err = -ENOMEM;
575 inode = ovl_new_inode(dentry->d_sb, realinode->i_mode); 578 if (upperdentry && !d_is_dir(upperdentry)) {
579 inode = ovl_get_inode(dentry->d_sb, realinode);
580 } else {
581 inode = ovl_new_inode(dentry->d_sb, realinode->i_mode);
582 if (inode)
583 ovl_inode_init(inode, realinode, !!upperdentry);
584 }
576 if (!inode) 585 if (!inode)
577 goto out_free_oe; 586 goto out_free_oe;
578 ovl_inode_init(inode, realinode, !!upperdentry);
579 ovl_copyattr(realdentry->d_inode, inode); 587 ovl_copyattr(realdentry->d_inode, inode);
580 } 588 }
581 589