diff options
| -rw-r--r-- | drivers/base/devtmpfs.c | 4 | ||||
| -rw-r--r-- | fs/attr.c | 25 | ||||
| -rw-r--r-- | fs/cachefiles/interface.c | 4 | ||||
| -rw-r--r-- | fs/ecryptfs/inode.c | 4 | ||||
| -rw-r--r-- | fs/hpfs/namei.c | 2 | ||||
| -rw-r--r-- | fs/inode.c | 6 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 8 | ||||
| -rw-r--r-- | fs/open.c | 22 | ||||
| -rw-r--r-- | fs/utimes.c | 9 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 |
10 files changed, 69 insertions, 17 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 1b8490e2fbde..0f3820121e02 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c | |||
| @@ -216,7 +216,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid, | |||
| 216 | newattrs.ia_gid = gid; | 216 | newattrs.ia_gid = gid; |
| 217 | newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID; | 217 | newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID; |
| 218 | mutex_lock(&dentry->d_inode->i_mutex); | 218 | mutex_lock(&dentry->d_inode->i_mutex); |
| 219 | notify_change(dentry, &newattrs); | 219 | notify_change(dentry, &newattrs, NULL); |
| 220 | mutex_unlock(&dentry->d_inode->i_mutex); | 220 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 221 | 221 | ||
| 222 | /* mark as kernel-created inode */ | 222 | /* mark as kernel-created inode */ |
| @@ -322,7 +322,7 @@ static int handle_remove(const char *nodename, struct device *dev) | |||
| 322 | newattrs.ia_valid = | 322 | newattrs.ia_valid = |
| 323 | ATTR_UID|ATTR_GID|ATTR_MODE; | 323 | ATTR_UID|ATTR_GID|ATTR_MODE; |
| 324 | mutex_lock(&dentry->d_inode->i_mutex); | 324 | mutex_lock(&dentry->d_inode->i_mutex); |
| 325 | notify_change(dentry, &newattrs); | 325 | notify_change(dentry, &newattrs, NULL); |
| 326 | mutex_unlock(&dentry->d_inode->i_mutex); | 326 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 327 | err = vfs_unlink(parent.dentry->d_inode, dentry, NULL); | 327 | err = vfs_unlink(parent.dentry->d_inode, dentry, NULL); |
| 328 | if (!err || err == -ENOENT) | 328 | if (!err || err == -ENOENT) |
| @@ -167,7 +167,27 @@ void setattr_copy(struct inode *inode, const struct iattr *attr) | |||
| 167 | } | 167 | } |
| 168 | EXPORT_SYMBOL(setattr_copy); | 168 | EXPORT_SYMBOL(setattr_copy); |
| 169 | 169 | ||
| 170 | int notify_change(struct dentry * dentry, struct iattr * attr) | 170 | /** |
| 171 | * notify_change - modify attributes of a filesytem object | ||
| 172 | * @dentry: object affected | ||
| 173 | * @iattr: new attributes | ||
| 174 | * @delegated_inode: returns inode, if the inode is delegated | ||
| 175 | * | ||
| 176 | * The caller must hold the i_mutex on the affected object. | ||
| 177 | * | ||
| 178 | * If notify_change discovers a delegation in need of breaking, | ||
| 179 | * it will return -EWOULDBLOCK and return a reference to the inode in | ||
| 180 | * delegated_inode. The caller should then break the delegation and | ||
| 181 | * retry. Because breaking a delegation may take a long time, the | ||
| 182 | * caller should drop the i_mutex before doing so. | ||
| 183 | * | ||
| 184 | * Alternatively, a caller may pass NULL for delegated_inode. This may | ||
| 185 | * be appropriate for callers that expect the underlying filesystem not | ||
| 186 | * to be NFS exported. Also, passing NULL is fine for callers holding | ||
| 187 | * the file open for write, as there can be no conflicting delegation in | ||
| 188 | * that case. | ||
| 189 | */ | ||
| 190 | int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode) | ||
| 171 | { | 191 | { |
| 172 | struct inode *inode = dentry->d_inode; | 192 | struct inode *inode = dentry->d_inode; |
| 173 | umode_t mode = inode->i_mode; | 193 | umode_t mode = inode->i_mode; |
| @@ -243,6 +263,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr) | |||
| 243 | error = security_inode_setattr(dentry, attr); | 263 | error = security_inode_setattr(dentry, attr); |
| 244 | if (error) | 264 | if (error) |
| 245 | return error; | 265 | return error; |
| 266 | error = try_break_deleg(inode, delegated_inode); | ||
| 267 | if (error) | ||
| 268 | return error; | ||
| 246 | 269 | ||
| 247 | if (inode->i_op->setattr) | 270 | if (inode->i_op->setattr) |
| 248 | error = inode->i_op->setattr(dentry, attr); | 271 | error = inode->i_op->setattr(dentry, attr); |
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 43eb5592cdea..5088a418ac4d 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
| @@ -449,14 +449,14 @@ static int cachefiles_attr_changed(struct fscache_object *_object) | |||
| 449 | _debug("discard tail %llx", oi_size); | 449 | _debug("discard tail %llx", oi_size); |
| 450 | newattrs.ia_valid = ATTR_SIZE; | 450 | newattrs.ia_valid = ATTR_SIZE; |
| 451 | newattrs.ia_size = oi_size & PAGE_MASK; | 451 | newattrs.ia_size = oi_size & PAGE_MASK; |
| 452 | ret = notify_change(object->backer, &newattrs); | 452 | ret = notify_change(object->backer, &newattrs, NULL); |
| 453 | if (ret < 0) | 453 | if (ret < 0) |
| 454 | goto truncate_failed; | 454 | goto truncate_failed; |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | newattrs.ia_valid = ATTR_SIZE; | 457 | newattrs.ia_valid = ATTR_SIZE; |
| 458 | newattrs.ia_size = ni_size; | 458 | newattrs.ia_size = ni_size; |
| 459 | ret = notify_change(object->backer, &newattrs); | 459 | ret = notify_change(object->backer, &newattrs, NULL); |
| 460 | 460 | ||
| 461 | truncate_failed: | 461 | truncate_failed: |
| 462 | mutex_unlock(&object->backer->d_inode->i_mutex); | 462 | mutex_unlock(&object->backer->d_inode->i_mutex); |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 1c628f023041..c36c44824471 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -882,7 +882,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
| 882 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); | 882 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); |
| 883 | 883 | ||
| 884 | mutex_lock(&lower_dentry->d_inode->i_mutex); | 884 | mutex_lock(&lower_dentry->d_inode->i_mutex); |
| 885 | rc = notify_change(lower_dentry, &lower_ia); | 885 | rc = notify_change(lower_dentry, &lower_ia, NULL); |
| 886 | mutex_unlock(&lower_dentry->d_inode->i_mutex); | 886 | mutex_unlock(&lower_dentry->d_inode->i_mutex); |
| 887 | } | 887 | } |
| 888 | return rc; | 888 | return rc; |
| @@ -983,7 +983,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) | |||
| 983 | lower_ia.ia_valid &= ~ATTR_MODE; | 983 | lower_ia.ia_valid &= ~ATTR_MODE; |
| 984 | 984 | ||
| 985 | mutex_lock(&lower_dentry->d_inode->i_mutex); | 985 | mutex_lock(&lower_dentry->d_inode->i_mutex); |
| 986 | rc = notify_change(lower_dentry, &lower_ia); | 986 | rc = notify_change(lower_dentry, &lower_ia, NULL); |
| 987 | mutex_unlock(&lower_dentry->d_inode->i_mutex); | 987 | mutex_unlock(&lower_dentry->d_inode->i_mutex); |
| 988 | out: | 988 | out: |
| 989 | fsstack_copy_attr_all(inode, lower_inode); | 989 | fsstack_copy_attr_all(inode, lower_inode); |
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 345713d2f8f3..1b39afdd86fd 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c | |||
| @@ -407,7 +407,7 @@ again: | |||
| 407 | /*printk("HPFS: truncating file before delete.\n");*/ | 407 | /*printk("HPFS: truncating file before delete.\n");*/ |
| 408 | newattrs.ia_size = 0; | 408 | newattrs.ia_size = 0; |
| 409 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | 409 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; |
| 410 | err = notify_change(dentry, &newattrs); | 410 | err = notify_change(dentry, &newattrs, NULL); |
| 411 | put_write_access(inode); | 411 | put_write_access(inode); |
| 412 | if (!err) | 412 | if (!err) |
| 413 | goto again; | 413 | goto again; |
diff --git a/fs/inode.c b/fs/inode.c index ce48c359ce9e..4bcdad3c9361 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -1603,7 +1603,11 @@ static int __remove_suid(struct dentry *dentry, int kill) | |||
| 1603 | struct iattr newattrs; | 1603 | struct iattr newattrs; |
| 1604 | 1604 | ||
| 1605 | newattrs.ia_valid = ATTR_FORCE | kill; | 1605 | newattrs.ia_valid = ATTR_FORCE | kill; |
| 1606 | return notify_change(dentry, &newattrs); | 1606 | /* |
| 1607 | * Note we call this on write, so notify_change will not | ||
| 1608 | * encounter any conflicting delegations: | ||
| 1609 | */ | ||
| 1610 | return notify_change(dentry, &newattrs, NULL); | ||
| 1607 | } | 1611 | } |
| 1608 | 1612 | ||
| 1609 | int file_remove_suid(struct file *file) | 1613 | int file_remove_suid(struct file *file) |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 27ba21b5f383..94b5f5d2bfed 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -427,7 +427,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
| 427 | goto out_nfserr; | 427 | goto out_nfserr; |
| 428 | fh_lock(fhp); | 428 | fh_lock(fhp); |
| 429 | 429 | ||
| 430 | host_err = notify_change(dentry, iap); | 430 | host_err = notify_change(dentry, iap, NULL); |
| 431 | err = nfserrno(host_err); | 431 | err = nfserrno(host_err); |
| 432 | fh_unlock(fhp); | 432 | fh_unlock(fhp); |
| 433 | } | 433 | } |
| @@ -988,7 +988,11 @@ static void kill_suid(struct dentry *dentry) | |||
| 988 | ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; | 988 | ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; |
| 989 | 989 | ||
| 990 | mutex_lock(&dentry->d_inode->i_mutex); | 990 | mutex_lock(&dentry->d_inode->i_mutex); |
| 991 | notify_change(dentry, &ia); | 991 | /* |
| 992 | * Note we call this on write, so notify_change will not | ||
| 993 | * encounter any conflicting delegations: | ||
| 994 | */ | ||
| 995 | notify_change(dentry, &ia, NULL); | ||
| 992 | mutex_unlock(&dentry->d_inode->i_mutex); | 996 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 993 | } | 997 | } |
| 994 | 998 | ||
| @@ -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); | ||
