Commit 3e9bff3b authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfs-6.11-rc6.fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:
 "VFS:

   - Ensure that backing files uses file->f_ops->splice_write() for
     splice

  netfs:

   - Revert the removal of PG_private_2 from netfs_release_folio() as
     cephfs still relies on this

   - When AS_RELEASE_ALWAYS is set on a mapping the folio needs to
     always be invalidated during truncation

   - Fix losing untruncated data in a folio by making letting
     netfs_release_folio() return false if the folio is dirty

   - Fix trimming of streaming-write folios in netfs_inval_folio()

   - Reset iterator before retrying a short read

   - Fix interaction of streaming writes with zero-point tracker

  afs:

   - During truncation afs currently calls truncate_setsize() which sets
     i_size, expands the pagecache and truncates it. The first two
     operations aren't needed because they will have already been done.
     So call truncate_pagecache() instead and skip the redundant parts

  overlayfs:

   - Fix checking of the number of allowed lower layers so 500 layers
     can actually be used instead of just 499

   - Add missing '\n' to pr_err() output

   - Pass string to ovl_parse_layer() and thus allow it to be used for
     Opt_lowerdir as well

  pidfd:

   - Revert blocking the creation of pidfds for kthread as apparently
     userspace relies on this. Specifically, it breaks systemd during
     shutdown

  romfs:

   - Fix romfs_read_folio() to use the correct offset with
     folio_zero_tail()"

* tag 'vfs-6.11-rc6.fixes' of gitolite.kernel.org:pub/scm/linux/kernel/git/vfs/vfs:
  netfs: Fix interaction of streaming writes with zero-point tracker
  netfs: Fix missing iterator reset on retry of short read
  netfs: Fix trimming of streaming-write folios in netfs_inval_folio()
  netfs: Fix netfs_release_folio() to say no if folio dirty
  afs: Fix post-setattr file edit to do truncation correctly
  mm: Fix missing folio invalidation calls during truncation
  ovl: ovl_parse_param_lowerdir: Add missed '\n' for pr_err
  ovl: fix wrong lowerdir number check for parameter Opt_lowerdir
  ovl: pass string to ovl_parse_layer()
  backing-file: convert to using fops->splice_write
  Revert "pidfd: prevent creation of pidfds for kthreads"
  romfs: fix romfs_read_folio()
  netfs, ceph: Partially revert "netfs: Replace PG_fscache by setting folio->private and marking dirty"
parents 5be63fc1 e00e99ba
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -695,13 +695,18 @@ static void afs_setattr_edit_file(struct afs_operation *op)
{
	struct afs_vnode_param *vp = &op->file[0];
	struct afs_vnode *vnode = vp->vnode;
	struct inode *inode = &vnode->netfs.inode;

	if (op->setattr.attr->ia_valid & ATTR_SIZE) {
		loff_t size = op->setattr.attr->ia_size;
		loff_t i_size = op->setattr.old_i_size;
		loff_t old = op->setattr.old_i_size;

		/* Note: inode->i_size was updated by afs_apply_status() inside
		 * the I/O and callback locks.
		 */

		if (size != i_size) {
			truncate_setsize(&vnode->netfs.inode, size);
		if (size != old) {
			truncate_pagecache(inode, size);
			netfs_resize_file(&vnode->netfs, size, true);
			fscache_resize_cookie(afs_vnode_cache(vnode), size);
		}
+4 −1
Original line number Diff line number Diff line
@@ -303,13 +303,16 @@ ssize_t backing_file_splice_write(struct pipe_inode_info *pipe,
	if (WARN_ON_ONCE(!(out->f_mode & FMODE_BACKING)))
		return -EIO;

	if (!out->f_op->splice_write)
		return -EINVAL;

	ret = file_remove_privs(ctx->user_file);
	if (ret)
		return ret;

	old_cred = override_creds(ctx->cred);
	file_start_write(out);
	ret = iter_file_splice_write(pipe, out, ppos, len, flags);
	ret = out->f_op->splice_write(pipe, out, ppos, len, flags);
	file_end_write(out);
	revert_creds(old_cred);

+1 −0
Original line number Diff line number Diff line
@@ -695,6 +695,7 @@ void ceph_evict_inode(struct inode *inode)

	percpu_counter_dec(&mdsc->metric.total_inodes);

	netfs_wait_for_outstanding_io(inode);
	truncate_inode_pages_final(&inode->i_data);
	if (inode->i_state & I_PINNING_NETFS_WB)
		ceph_fscache_unuse_cookie(inode, true);
+1 −0
Original line number Diff line number Diff line
@@ -313,6 +313,7 @@ static bool netfs_rreq_perform_resubmissions(struct netfs_io_request *rreq)
			netfs_reset_subreq_iter(rreq, subreq);
			netfs_read_from_server(rreq, subreq);
		} else if (test_bit(NETFS_SREQ_SHORT_IO, &subreq->flags)) {
			netfs_reset_subreq_iter(rreq, subreq);
			netfs_rreq_short_read(rreq, subreq);
		}
	}
+45 −15
Original line number Diff line number Diff line
@@ -97,10 +97,22 @@ EXPORT_SYMBOL(netfs_clear_inode_writeback);
void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length)
{
	struct netfs_folio *finfo;
	struct netfs_inode *ctx = netfs_inode(folio_inode(folio));
	size_t flen = folio_size(folio);

	_enter("{%lx},%zx,%zx", folio->index, offset, length);

	if (offset == 0 && length == flen) {
		unsigned long long i_size = i_size_read(&ctx->inode);
		unsigned long long fpos = folio_pos(folio), end;

		end = umin(fpos + flen, i_size);
		if (fpos < i_size && end > ctx->zero_point)
			ctx->zero_point = end;
	}

	folio_wait_private_2(folio); /* [DEPRECATED] */

	if (!folio_test_private(folio))
		return;

@@ -113,18 +125,34 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length)
		/* We have a partially uptodate page from a streaming write. */
		unsigned int fstart = finfo->dirty_offset;
		unsigned int fend = fstart + finfo->dirty_len;
		unsigned int end = offset + length;
		unsigned int iend = offset + length;

		if (offset >= fend)
			return;
		if (end <= fstart)
		if (iend <= fstart)
			return;
		if (offset <= fstart && end >= fend)

		/* The invalidation region overlaps the data.  If the region
		 * covers the start of the data, we either move along the start
		 * or just erase the data entirely.
		 */
		if (offset <= fstart) {
			if (iend >= fend)
				goto erase_completely;
		if (offset <= fstart && end > fstart)
			goto reduce_len;
		if (offset > fstart && end >= fend)
			goto move_start;
			/* Move the start of the data. */
			finfo->dirty_len = fend - iend;
			finfo->dirty_offset = offset;
			return;
		}

		/* Reduce the length of the data if the invalidation region
		 * covers the tail part.
		 */
		if (iend >= fend) {
			finfo->dirty_len = offset - fstart;
			return;
		}

		/* A partial write was split.  The caller has already zeroed
		 * it, so just absorb the hole.
		 */
@@ -137,12 +165,6 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length)
	folio_clear_uptodate(folio);
	kfree(finfo);
	return;
reduce_len:
	finfo->dirty_len = offset + length - finfo->dirty_offset;
	return;
move_start:
	finfo->dirty_len -= offset - finfo->dirty_offset;
	finfo->dirty_offset = offset;
}
EXPORT_SYMBOL(netfs_invalidate_folio);

@@ -159,12 +181,20 @@ bool netfs_release_folio(struct folio *folio, gfp_t gfp)
	struct netfs_inode *ctx = netfs_inode(folio_inode(folio));
	unsigned long long end;

	end = folio_pos(folio) + folio_size(folio);
	if (folio_test_dirty(folio))
		return false;

	end = umin(folio_pos(folio) + folio_size(folio), i_size_read(&ctx->inode));
	if (end > ctx->zero_point)
		ctx->zero_point = end;

	if (folio_test_private(folio))
		return false;
	if (unlikely(folio_test_private_2(folio))) { /* [DEPRECATED] */
		if (current_is_kswapd() || !(gfp & __GFP_FS))
			return false;
		folio_wait_private_2(folio);
	}
	fscache_note_page_release(netfs_i_cookie(ctx));
	return true;
}
Loading