Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12b9fa6a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 340b3a5b 5129fa48
Loading
Loading
Loading
Loading
+3 −28
Original line number Original line Diff line number Diff line
@@ -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 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
		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;
+15 −7
Original line number Original line Diff line number Diff line
@@ -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 @@ static int do_last(struct nameidata *nd,
		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 @@ static int do_last(struct nameidata *nd,
	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 @@ static int do_last(struct nameidata *nd,
		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 @@ static int do_last(struct nameidata *nd,
			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);
+4 −2
Original line number Original line Diff line number Diff line
@@ -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;