diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-27 20:10:32 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-27 20:10:32 -0500 |
| commit | 12b9fa6a97b3150477ab182e321be512b59fa899 (patch) | |
| tree | 3ff6cf7f3b2d74f6c3e0ec81b75cb36c06332bfa | |
| parent | 340b3a5b35c0919e1535b355a9eafe1f81c4cae3 (diff) | |
| parent | 5129fa482b16615fd4464d2f5d23acb1b7056c66 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
do_last(): ELOOP failure exit should be done after leaving RCU mode
should_follow_link(): validate ->d_seq after having decided to follow
namei: ->d_inode of a pinned dentry is stable only for positives
do_last(): don't let a bogus return value from ->open() et.al. to confuse us
fs: return -EOPNOTSUPP if clone is not supported
hpfs: don't truncate the file when delete fails
| -rw-r--r-- | fs/hpfs/namei.c | 31 | ||||
| -rw-r--r-- | fs/namei.c | 22 | ||||
| -rw-r--r-- | fs/read_write.c | 6 |
3 files changed, 22 insertions, 37 deletions
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 506765afa1a3..bb8d67e2740a 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c | |||
| @@ -376,12 +376,11 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 376 | struct inode *inode = d_inode(dentry); | 376 | struct inode *inode = d_inode(dentry); |
| 377 | dnode_secno dno; | 377 | dnode_secno dno; |
| 378 | int r; | 378 | int r; |
| 379 | int rep = 0; | ||
| 380 | int err; | 379 | int err; |
| 381 | 380 | ||
| 382 | hpfs_lock(dir->i_sb); | 381 | hpfs_lock(dir->i_sb); |
| 383 | hpfs_adjust_length(name, &len); | 382 | hpfs_adjust_length(name, &len); |
| 384 | again: | 383 | |
| 385 | err = -ENOENT; | 384 | err = -ENOENT; |
| 386 | de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); | 385 | de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); |
| 387 | if (!de) | 386 | if (!de) |
| @@ -401,33 +400,9 @@ again: | |||
| 401 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | 400 | hpfs_error(dir->i_sb, "there was error when removing dirent"); |
| 402 | err = -EFSERROR; | 401 | err = -EFSERROR; |
| 403 | break; | 402 | break; |
| 404 | case 2: /* no space for deleting, try to truncate file */ | 403 | case 2: /* no space for deleting */ |
| 405 | |||
| 406 | err = -ENOSPC; | 404 | err = -ENOSPC; |
| 407 | if (rep++) | 405 | break; |
| 408 | break; | ||
| 409 | |||
| 410 | dentry_unhash(dentry); | ||
| 411 | if (!d_unhashed(dentry)) { | ||
| 412 | hpfs_unlock(dir->i_sb); | ||
| 413 | return -ENOSPC; | ||
| 414 | } | ||
| 415 | if (generic_permission(inode, MAY_WRITE) || | ||
| 416 | !S_ISREG(inode->i_mode) || | ||
| 417 | get_write_access(inode)) { | ||
| 418 | d_rehash(dentry); | ||
| 419 | } else { | ||
| 420 | struct iattr newattrs; | ||
| 421 | /*pr_info("truncating file before delete.\n");*/ | ||
| 422 | newattrs.ia_size = 0; | ||
| 423 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | ||
| 424 | err = notify_change(dentry, &newattrs, NULL); | ||
| 425 | put_write_access(inode); | ||
| 426 | if (!err) | ||
| 427 | goto again; | ||
| 428 | } | ||
| 429 | hpfs_unlock(dir->i_sb); | ||
| 430 | return -ENOSPC; | ||
| 431 | default: | 406 | default: |
| 432 | drop_nlink(inode); | 407 | drop_nlink(inode); |
| 433 | err = 0; | 408 | err = 0; |
diff --git a/fs/namei.c b/fs/namei.c index f624d132e01e..9c590e0f66e9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1712,6 +1712,11 @@ static inline int should_follow_link(struct nameidata *nd, struct path *link, | |||
| 1712 | return 0; | 1712 | return 0; |
| 1713 | if (!follow) | 1713 | if (!follow) |
| 1714 | return 0; | 1714 | return 0; |
| 1715 | /* make sure that d_is_symlink above matches inode */ | ||
| 1716 | if (nd->flags & LOOKUP_RCU) { | ||
| 1717 | if (read_seqcount_retry(&link->dentry->d_seq, seq)) | ||
| 1718 | return -ECHILD; | ||
| 1719 | } | ||
| 1715 | return pick_link(nd, link, inode, seq); | 1720 | return pick_link(nd, link, inode, seq); |
| 1716 | } | 1721 | } |
| 1717 | 1722 | ||
| @@ -1743,11 +1748,11 @@ static int walk_component(struct nameidata *nd, int flags) | |||
| 1743 | if (err < 0) | 1748 | if (err < 0) |
| 1744 | return err; | 1749 | return err; |
| 1745 | 1750 | ||
| 1746 | inode = d_backing_inode(path.dentry); | ||
| 1747 | seq = 0; /* we are already out of RCU mode */ | 1751 | seq = 0; /* we are already out of RCU mode */ |
| 1748 | err = -ENOENT; | 1752 | err = -ENOENT; |
| 1749 | if (d_is_negative(path.dentry)) | 1753 | if (d_is_negative(path.dentry)) |
| 1750 | goto out_path_put; | 1754 | goto out_path_put; |
| 1755 | inode = d_backing_inode(path.dentry); | ||
| 1751 | } | 1756 | } |
| 1752 | 1757 | ||
| 1753 | if (flags & WALK_PUT) | 1758 | if (flags & WALK_PUT) |
| @@ -3192,12 +3197,12 @@ retry_lookup: | |||
| 3192 | return error; | 3197 | return error; |
| 3193 | 3198 | ||
| 3194 | BUG_ON(nd->flags & LOOKUP_RCU); | 3199 | BUG_ON(nd->flags & LOOKUP_RCU); |
| 3195 | inode = d_backing_inode(path.dentry); | ||
| 3196 | seq = 0; /* out of RCU mode, so the value doesn't matter */ | 3200 | seq = 0; /* out of RCU mode, so the value doesn't matter */ |
| 3197 | if (unlikely(d_is_negative(path.dentry))) { | 3201 | if (unlikely(d_is_negative(path.dentry))) { |
| 3198 | path_to_nameidata(&path, nd); | 3202 | path_to_nameidata(&path, nd); |
| 3199 | return -ENOENT; | 3203 | return -ENOENT; |
| 3200 | } | 3204 | } |
| 3205 | inode = d_backing_inode(path.dentry); | ||
| 3201 | finish_lookup: | 3206 | finish_lookup: |
| 3202 | if (nd->depth) | 3207 | if (nd->depth) |
| 3203 | put_link(nd); | 3208 | put_link(nd); |
| @@ -3206,11 +3211,6 @@ finish_lookup: | |||
| 3206 | if (unlikely(error)) | 3211 | if (unlikely(error)) |
| 3207 | return error; | 3212 | return error; |
| 3208 | 3213 | ||
| 3209 | if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) { | ||
| 3210 | path_to_nameidata(&path, nd); | ||
| 3211 | return -ELOOP; | ||
| 3212 | } | ||
| 3213 | |||
| 3214 | if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) { | 3214 | if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) { |
| 3215 | path_to_nameidata(&path, nd); | 3215 | path_to_nameidata(&path, nd); |
| 3216 | } else { | 3216 | } else { |
| @@ -3229,6 +3229,10 @@ finish_open: | |||
| 3229 | return error; | 3229 | return error; |
| 3230 | } | 3230 | } |
| 3231 | audit_inode(nd->name, nd->path.dentry, 0); | 3231 | audit_inode(nd->name, nd->path.dentry, 0); |
| 3232 | if (unlikely(d_is_symlink(nd->path.dentry)) && !(open_flag & O_PATH)) { | ||
| 3233 | error = -ELOOP; | ||
| 3234 | goto out; | ||
| 3235 | } | ||
| 3232 | error = -EISDIR; | 3236 | error = -EISDIR; |
| 3233 | if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) | 3237 | if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) |
| 3234 | goto out; | 3238 | goto out; |
| @@ -3273,6 +3277,10 @@ opened: | |||
| 3273 | goto exit_fput; | 3277 | goto exit_fput; |
| 3274 | } | 3278 | } |
| 3275 | out: | 3279 | out: |
| 3280 | if (unlikely(error > 0)) { | ||
| 3281 | WARN_ON(1); | ||
| 3282 | error = -EINVAL; | ||
| 3283 | } | ||
| 3276 | if (got_write) | 3284 | if (got_write) |
| 3277 | mnt_drop_write(nd->path.mnt); | 3285 | mnt_drop_write(nd->path.mnt); |
| 3278 | path_put(&save_parent); | 3286 | path_put(&save_parent); |
diff --git a/fs/read_write.c b/fs/read_write.c index 0c8782aa3d71..dadf24e5c95b 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
| @@ -1533,10 +1533,12 @@ int vfs_clone_file_range(struct file *file_in, loff_t pos_in, | |||
| 1533 | 1533 | ||
| 1534 | if (!(file_in->f_mode & FMODE_READ) || | 1534 | if (!(file_in->f_mode & FMODE_READ) || |
| 1535 | !(file_out->f_mode & FMODE_WRITE) || | 1535 | !(file_out->f_mode & FMODE_WRITE) || |
| 1536 | (file_out->f_flags & O_APPEND) || | 1536 | (file_out->f_flags & O_APPEND)) |
| 1537 | !file_in->f_op->clone_file_range) | ||
| 1538 | return -EBADF; | 1537 | return -EBADF; |
| 1539 | 1538 | ||
| 1539 | if (!file_in->f_op->clone_file_range) | ||
| 1540 | return -EOPNOTSUPP; | ||
| 1541 | |||
| 1540 | ret = clone_verify_area(file_in, pos_in, len, false); | 1542 | ret = clone_verify_area(file_in, pos_in, len, false); |
| 1541 | if (ret) | 1543 | if (ret) |
| 1542 | return ret; | 1544 | return ret; |
