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
This commit is contained in:
commit
12b9fa6a97
|
@ -376,12 +376,11 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
struct inode *inode = d_inode(dentry);
|
struct inode *inode = d_inode(dentry);
|
||||||
dnode_secno dno;
|
dnode_secno dno;
|
||||||
int r;
|
int r;
|
||||||
int rep = 0;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
hpfs_lock(dir->i_sb);
|
hpfs_lock(dir->i_sb);
|
||||||
hpfs_adjust_length(name, &len);
|
hpfs_adjust_length(name, &len);
|
||||||
again:
|
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
|
de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
|
||||||
if (!de)
|
if (!de)
|
||||||
|
@ -401,33 +400,9 @@ again:
|
||||||
hpfs_error(dir->i_sb, "there was error when removing dirent");
|
hpfs_error(dir->i_sb, "there was error when removing dirent");
|
||||||
err = -EFSERROR;
|
err = -EFSERROR;
|
||||||
break;
|
break;
|
||||||
case 2: /* no space for deleting, try to truncate file */
|
case 2: /* no space for deleting */
|
||||||
|
|
||||||
err = -ENOSPC;
|
err = -ENOSPC;
|
||||||
if (rep++)
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
dentry_unhash(dentry);
|
|
||||||
if (!d_unhashed(dentry)) {
|
|
||||||
hpfs_unlock(dir->i_sb);
|
|
||||||
return -ENOSPC;
|
|
||||||
}
|
|
||||||
if (generic_permission(inode, MAY_WRITE) ||
|
|
||||||
!S_ISREG(inode->i_mode) ||
|
|
||||||
get_write_access(inode)) {
|
|
||||||
d_rehash(dentry);
|
|
||||||
} else {
|
|
||||||
struct iattr newattrs;
|
|
||||||
/*pr_info("truncating file before delete.\n");*/
|
|
||||||
newattrs.ia_size = 0;
|
|
||||||
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
|
|
||||||
err = notify_change(dentry, &newattrs, NULL);
|
|
||||||
put_write_access(inode);
|
|
||||||
if (!err)
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
hpfs_unlock(dir->i_sb);
|
|
||||||
return -ENOSPC;
|
|
||||||
default:
|
default:
|
||||||
drop_nlink(inode);
|
drop_nlink(inode);
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
22
fs/namei.c
22
fs/namei.c
|
@ -1712,6 +1712,11 @@ static inline int should_follow_link(struct nameidata *nd, struct path *link,
|
||||||
return 0;
|
return 0;
|
||||||
if (!follow)
|
if (!follow)
|
||||||
return 0;
|
return 0;
|
||||||
|
/* make sure that d_is_symlink above matches inode */
|
||||||
|
if (nd->flags & LOOKUP_RCU) {
|
||||||
|
if (read_seqcount_retry(&link->dentry->d_seq, seq))
|
||||||
|
return -ECHILD;
|
||||||
|
}
|
||||||
return pick_link(nd, link, inode, seq);
|
return pick_link(nd, link, inode, seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1743,11 +1748,11 @@ static int walk_component(struct nameidata *nd, int flags)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
inode = d_backing_inode(path.dentry);
|
|
||||||
seq = 0; /* we are already out of RCU mode */
|
seq = 0; /* we are already out of RCU mode */
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
if (d_is_negative(path.dentry))
|
if (d_is_negative(path.dentry))
|
||||||
goto out_path_put;
|
goto out_path_put;
|
||||||
|
inode = d_backing_inode(path.dentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & WALK_PUT)
|
if (flags & WALK_PUT)
|
||||||
|
@ -3192,12 +3197,12 @@ retry_lookup:
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
BUG_ON(nd->flags & LOOKUP_RCU);
|
BUG_ON(nd->flags & LOOKUP_RCU);
|
||||||
inode = d_backing_inode(path.dentry);
|
|
||||||
seq = 0; /* out of RCU mode, so the value doesn't matter */
|
seq = 0; /* out of RCU mode, so the value doesn't matter */
|
||||||
if (unlikely(d_is_negative(path.dentry))) {
|
if (unlikely(d_is_negative(path.dentry))) {
|
||||||
path_to_nameidata(&path, nd);
|
path_to_nameidata(&path, nd);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
inode = d_backing_inode(path.dentry);
|
||||||
finish_lookup:
|
finish_lookup:
|
||||||
if (nd->depth)
|
if (nd->depth)
|
||||||
put_link(nd);
|
put_link(nd);
|
||||||
|
@ -3206,11 +3211,6 @@ finish_lookup:
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) {
|
|
||||||
path_to_nameidata(&path, nd);
|
|
||||||
return -ELOOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) {
|
if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) {
|
||||||
path_to_nameidata(&path, nd);
|
path_to_nameidata(&path, nd);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3229,6 +3229,10 @@ finish_open:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
audit_inode(nd->name, nd->path.dentry, 0);
|
audit_inode(nd->name, nd->path.dentry, 0);
|
||||||
|
if (unlikely(d_is_symlink(nd->path.dentry)) && !(open_flag & O_PATH)) {
|
||||||
|
error = -ELOOP;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
error = -EISDIR;
|
error = -EISDIR;
|
||||||
if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
|
if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -3273,6 +3277,10 @@ opened:
|
||||||
goto exit_fput;
|
goto exit_fput;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
if (unlikely(error > 0)) {
|
||||||
|
WARN_ON(1);
|
||||||
|
error = -EINVAL;
|
||||||
|
}
|
||||||
if (got_write)
|
if (got_write)
|
||||||
mnt_drop_write(nd->path.mnt);
|
mnt_drop_write(nd->path.mnt);
|
||||||
path_put(&save_parent);
|
path_put(&save_parent);
|
||||||
|
|
|
@ -1533,10 +1533,12 @@ int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
|
||||||
|
|
||||||
if (!(file_in->f_mode & FMODE_READ) ||
|
if (!(file_in->f_mode & FMODE_READ) ||
|
||||||
!(file_out->f_mode & FMODE_WRITE) ||
|
!(file_out->f_mode & FMODE_WRITE) ||
|
||||||
(file_out->f_flags & O_APPEND) ||
|
(file_out->f_flags & O_APPEND))
|
||||||
!file_in->f_op->clone_file_range)
|
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
|
if (!file_in->f_op->clone_file_range)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
ret = clone_verify_area(file_in, pos_in, len, false);
|
ret = clone_verify_area(file_in, pos_in, len, false);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue