diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 32 |
1 files changed, 24 insertions, 8 deletions
@@ -57,7 +57,8 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | |||
57 | newattrs.ia_valid |= ret | ATTR_FORCE; | 57 | newattrs.ia_valid |= ret | ATTR_FORCE; |
58 | 58 | ||
59 | mutex_lock(&dentry->d_inode->i_mutex); | 59 | mutex_lock(&dentry->d_inode->i_mutex); |
60 | ret = notify_change(dentry, &newattrs); | 60 | /* Note any delegations or leases have already been broken: */ |
61 | ret = notify_change(dentry, &newattrs, NULL); | ||
61 | mutex_unlock(&dentry->d_inode->i_mutex); | 62 | mutex_unlock(&dentry->d_inode->i_mutex); |
62 | return ret; | 63 | return ret; |
63 | } | 64 | } |
@@ -464,21 +465,28 @@ out: | |||
464 | static int chmod_common(struct path *path, umode_t mode) | 465 | static int chmod_common(struct path *path, umode_t mode) |
465 | { | 466 | { |
466 | struct inode *inode = path->dentry->d_inode; | 467 | struct inode *inode = path->dentry->d_inode; |
468 | struct inode *delegated_inode = NULL; | ||
467 | struct iattr newattrs; | 469 | struct iattr newattrs; |
468 | int error; | 470 | int error; |
469 | 471 | ||
470 | error = mnt_want_write(path->mnt); | 472 | error = mnt_want_write(path->mnt); |
471 | if (error) | 473 | if (error) |
472 | return error; | 474 | return error; |
475 | retry_deleg: | ||
473 | mutex_lock(&inode->i_mutex); | 476 | mutex_lock(&inode->i_mutex); |
474 | error = security_path_chmod(path, mode); | 477 | error = security_path_chmod(path, mode); |
475 | if (error) | 478 | if (error) |
476 | goto out_unlock; | 479 | goto out_unlock; |
477 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 480 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); |
478 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 481 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
479 | error = notify_change(path->dentry, &newattrs); | 482 | error = notify_change(path->dentry, &newattrs, &delegated_inode); |
480 | out_unlock: | 483 | out_unlock: |
481 | mutex_unlock(&inode->i_mutex); | 484 | mutex_unlock(&inode->i_mutex); |
485 | if (delegated_inode) { | ||
486 | error = break_deleg_wait(&delegated_inode); | ||
487 | if (!error) | ||
488 | goto retry_deleg; | ||
489 | } | ||
482 | mnt_drop_write(path->mnt); | 490 | mnt_drop_write(path->mnt); |
483 | return error; | 491 | return error; |
484 | } | 492 | } |
@@ -522,6 +530,7 @@ SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode) | |||
522 | static int chown_common(struct path *path, uid_t user, gid_t group) | 530 | static int chown_common(struct path *path, uid_t user, gid_t group) |
523 | { | 531 | { |
524 | struct inode *inode = path->dentry->d_inode; | 532 | struct inode *inode = path->dentry->d_inode; |
533 | struct inode *delegated_inode = NULL; | ||
525 | int error; | 534 | int error; |
526 | struct iattr newattrs; | 535 | struct iattr newattrs; |
527 | kuid_t uid; | 536 | kuid_t uid; |
@@ -546,12 +555,17 @@ static int chown_common(struct path *path, uid_t user, gid_t group) | |||
546 | if (!S_ISDIR(inode->i_mode)) | 555 | if (!S_ISDIR(inode->i_mode)) |
547 | newattrs.ia_valid |= | 556 | newattrs.ia_valid |= |
548 | ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; | 557 | ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; |
558 | retry_deleg: | ||
549 | mutex_lock(&inode->i_mutex); | 559 | mutex_lock(&inode->i_mutex); |
550 | error = security_path_chown(path, uid, gid); | 560 | error = security_path_chown(path, uid, gid); |
551 | if (!error) | 561 | if (!error) |
552 | error = notify_change(path->dentry, &newattrs); | 562 | error = notify_change(path->dentry, &newattrs, &delegated_inode); |
553 | mutex_unlock(&inode->i_mutex); | 563 | mutex_unlock(&inode->i_mutex); |
554 | 564 | if (delegated_inode) { | |
565 | error = break_deleg_wait(&delegated_inode); | ||
566 | if (!error) | ||
567 | goto retry_deleg; | ||
568 | } | ||
555 | return error; | 569 | return error; |
556 | } | 570 | } |
557 | 571 | ||
@@ -685,7 +699,6 @@ static int do_dentry_open(struct file *f, | |||
685 | } | 699 | } |
686 | 700 | ||
687 | f->f_mapping = inode->i_mapping; | 701 | f->f_mapping = inode->i_mapping; |
688 | file_sb_list_add(f, inode->i_sb); | ||
689 | 702 | ||
690 | if (unlikely(f->f_mode & FMODE_PATH)) { | 703 | if (unlikely(f->f_mode & FMODE_PATH)) { |
691 | f->f_op = &empty_fops; | 704 | f->f_op = &empty_fops; |
@@ -693,6 +706,10 @@ static int do_dentry_open(struct file *f, | |||
693 | } | 706 | } |
694 | 707 | ||
695 | f->f_op = fops_get(inode->i_fop); | 708 | f->f_op = fops_get(inode->i_fop); |
709 | if (unlikely(WARN_ON(!f->f_op))) { | ||
710 | error = -ENODEV; | ||
711 | goto cleanup_all; | ||
712 | } | ||
696 | 713 | ||
697 | error = security_file_open(f, cred); | 714 | error = security_file_open(f, cred); |
698 | if (error) | 715 | if (error) |
@@ -702,7 +719,7 @@ static int do_dentry_open(struct file *f, | |||
702 | if (error) | 719 | if (error) |
703 | goto cleanup_all; | 720 | goto cleanup_all; |
704 | 721 | ||
705 | if (!open && f->f_op) | 722 | if (!open) |
706 | open = f->f_op->open; | 723 | open = f->f_op->open; |
707 | if (open) { | 724 | if (open) { |
708 | error = open(inode, f); | 725 | error = open(inode, f); |
@@ -720,7 +737,6 @@ static int do_dentry_open(struct file *f, | |||
720 | 737 | ||
721 | cleanup_all: | 738 | cleanup_all: |
722 | fops_put(f->f_op); | 739 | fops_put(f->f_op); |
723 | file_sb_list_del(f); | ||
724 | if (f->f_mode & FMODE_WRITE) { | 740 | if (f->f_mode & FMODE_WRITE) { |
725 | put_write_access(inode); | 741 | put_write_access(inode); |
726 | if (!special_file(inode->i_mode)) { | 742 | if (!special_file(inode->i_mode)) { |
@@ -1023,7 +1039,7 @@ int filp_close(struct file *filp, fl_owner_t id) | |||
1023 | return 0; | 1039 | return 0; |
1024 | } | 1040 | } |
1025 | 1041 | ||
1026 | if (filp->f_op && filp->f_op->flush) | 1042 | if (filp->f_op->flush) |
1027 | retval = filp->f_op->flush(filp, id); | 1043 | retval = filp->f_op->flush(filp, id); |
1028 | 1044 | ||
1029 | if (likely(!(filp->f_mode & FMODE_PATH))) { | 1045 | if (likely(!(filp->f_mode & FMODE_PATH))) { |