diff options
author | J. Bruce Fields <bfields@redhat.com> | 2011-09-20 17:19:26 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-11-09 00:16:44 -0500 |
commit | 27ac0ffeac80ba6b9580529568d06144df044366 (patch) | |
tree | a2e523716039784271250387d6e94ec4f01daec5 /fs/open.c | |
parent | 146a8595c6399ee6ab4b5cc34c0d28aa4835fdc5 (diff) |
locks: break delegations on any attribute modification
NFSv4 uses leases to guarantee that clients can cache metadata as well
as data.
Cc: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Cc: David Howells <dhowells@redhat.com>
Cc: Tyler Hicks <tyhicks@canonical.com>
Cc: Dustin Kirkland <dustin.kirkland@gazzang.com>
Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 22 |
1 files changed, 18 insertions, 4 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 | ||