Merge tag 'vfs-7.1-rc5.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs fixes from Christian Brauner:
 "This contains a fixes for the current development cycle. Note that AI
  related review sometimes delays fixes a bit because we find more fixes
  for the fixes. I might try and send smaller but more fixes PRs if this
  trend keeps up.

   - Fix various netfslib bugs

   - Fix an out-of-bounds write when listing idmappings

   - Fix the return values in jfs_mkdir() and orangefs_mkdir()

   - Fix a writeback writeback array overflow in fuse

   - Fix a forced iversion increment on lazytime timestamp updates

   - Reject a negative timeval component in kern_select()

   - Fix error return when vfs_mkdir() fails in the cachefiles code

   - Fix wrong error code returned for pidns ioctls"

* tag 'vfs-7.1-rc5.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (31 commits)
  cachefiles: Fix error return when vfs_mkdir() fails
  afs: Fix the locking used by afs_get_link()
  netfs, afs: Fix write skipping in dir/link writepages
  netfs: Fix netfs_read_folio() to wait on writeback
  netfs: Fix folio->private handling in netfs_perform_write()
  netfs: Fix partial invalidation of streaming-write folio
  netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages()
  netfs: Fix leak of request in netfs_write_begin() error handling
  netfs: Fix early put of sink folio in netfs_read_gaps()
  netfs: Fix write streaming disablement if fd open O_RDWR
  netfs: Fix read-gaps to remove netfs_folio from filled folio
  netfs: Fix potential deadlock in write-through mode
  netfs: Fix streaming write being overwritten
  netfs: Defer the emission of trace_netfs_folio()
  netfs: Fix netfs_invalidate_folio() to clear dirty bit if all changes gone
  netfs: Fix overrun check in netfs_extract_user_iter()
  netfs: fix error handling in netfs_extract_user_iter()
  netfs: Fix potential uninitialised var in netfs_extract_user_iter()
  netfs: fix VM_BUG_ON_FOLIO() issue in netfs_write_begin() call
  netfs: Fix zeropoint update where i_size > remote_i_size
  ...
This commit is contained in:
Linus Torvalds
2026-05-18 07:30:31 -07:00
44 changed files with 1172 additions and 438 deletions

View File

@@ -191,6 +191,29 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head)
__list_add(new, head->prev, head);
}
/**
* list_add_tail_release - add a new entry with release barrier
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head, using a release barrier to set
* the ->next pointer that points to it. This is useful for implementing
* queues, in particular one that the elements will be walked through forwards
* locklessly.
*/
static inline void list_add_tail_release(struct list_head *new,
struct list_head *head)
{
struct list_head *prev = head->prev;
if (__list_add_valid(new, prev, head)) {
new->next = head;
new->prev = prev;
head->prev = new;
smp_store_release(&prev->next, new);
}
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
@@ -644,6 +667,20 @@ static inline void list_splice_tail_init(struct list_head *list,
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
})
/**
* list_first_entry_or_null_acquire - get the first element from a list with barrier
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note that if the list is empty, it returns NULL.
*/
#define list_first_entry_or_null_acquire(ptr, type, member) ({ \
struct list_head *head__ = (ptr); \
struct list_head *pos__ = smp_load_acquire(&head__->next); \
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
})
/**
* list_last_entry_or_null - get the last element from a list
* @ptr: the list head to take the element from.

View File

@@ -62,8 +62,8 @@ struct netfs_inode {
struct fscache_cookie *cache;
#endif
struct mutex wb_lock; /* Writeback serialisation */
loff_t remote_i_size; /* Size of the remote file */
loff_t zero_point; /* Size after which we assume there's no data
loff_t _remote_i_size; /* Size of the remote file */
loff_t _zero_point; /* Size after which we assume there's no data
* on the server */
atomic_t io_count; /* Number of outstanding reqs */
unsigned long flags;
@@ -252,7 +252,7 @@ struct netfs_io_request {
unsigned long long collected_to; /* Point we've collected to */
unsigned long long cleaned_to; /* Position we've cleaned folios to */
unsigned long long abandon_to; /* Position to abandon folios to */
pgoff_t no_unlock_folio; /* Don't unlock this folio after read */
const struct folio *no_unlock_folio; /* Don't unlock this folio after read */
unsigned int direct_bv_count; /* Number of elements in direct_bv[] */
unsigned int debug_id;
unsigned int rsize; /* Maximum read size (0 for none) */
@@ -474,6 +474,254 @@ static inline struct netfs_inode *netfs_inode(struct inode *inode)
return container_of(inode, struct netfs_inode, inode);
}
/**
* netfs_read_remote_i_size - Read remote_i_size safely
* @inode: The inode to access
*
* Read remote_i_size safely without the potential for tearing on 32-bit
* arches.
*
* NOTE: in a 32bit arch with a preemptable kernel and an UP compile the
* i_size_read/write must be atomic with respect to the local cpu (unlike with
* preempt disabled), but they don't need to be atomic with respect to other
* cpus like in true SMP (so they need either to either locally disable irq
* around the read or for example on x86 they can be still implemented as a
* cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit
* archs it makes no difference if preempt is enabled or not.
*/
static inline unsigned long long netfs_read_remote_i_size(const struct inode *inode)
{
const struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode);
unsigned long long remote_i_size;
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
unsigned int seq;
do {
seq = read_seqcount_begin(&inode->i_size_seqcount);
remote_i_size = ictx->_remote_i_size;
} while (read_seqcount_retry(&inode->i_size_seqcount, seq));
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
preempt_disable();
remote_i_size = ictx->_remote_i_size;
preempt_enable();
#else
/* Pairs with smp_store_release() in netfs_write_remote_i_size() */
remote_i_size = smp_load_acquire(&ictx->_remote_i_size);
#endif
return remote_i_size;
}
/*
* netfs_write_remote_i_size - Set remote_i_size safely
* @inode: The inode to access
* @remote_i_size: The new value for the size of the file on the server
*
* Set remote_i_size safely without the potential for tearing on 32-bit arches.
*
* Context: The caller must hold inode->i_lock.
*
* NOTE: unlike netfs_read_remote_i_size(), netfs_write_remote_i_size() does
* need locking around it (normally i_rwsem), otherwise on 32bit/SMP an update
* of i_size_seqcount can be lost, resulting in subsequent i_size_read() calls
* spinning forever.
*/
static inline void netfs_write_remote_i_size(struct inode *inode,
unsigned long long remote_i_size)
{
struct netfs_inode *ictx = netfs_inode(inode);
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
write_seqcount_begin(&inode->i_size_seqcount);
ictx->_remote_i_size = remote_i_size;
write_seqcount_end(&inode->i_size_seqcount);
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
preempt_disable();
ictx->_remote_i_size = remote_i_size;
preempt_enable();
#else
/*
* Pairs with smp_load_acquire() in netfs_read_remote_i_size() to
* ensure changes related to inode size (such as page contents) are
* visible before we see the changed inode size.
*/
smp_store_release(&ictx->_remote_i_size, remote_i_size);
#endif
}
/**
* netfs_read_zero_point - Read zero_point safely
* @inode: The inode to access
*
* Read zero_point safely without the potential for tearing on 32-bit
* arches.
*
* NOTE: in a 32bit arch with a preemptable kernel and an UP compile the
* i_size_read/write must be atomic with respect to the local cpu (unlike with
* preempt disabled), but they don't need to be atomic with respect to other
* cpus like in true SMP (so they need either to either locally disable irq
* around the read or for example on x86 they can be still implemented as a
* cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit
* archs it makes no difference if preempt is enabled or not.
*/
static inline unsigned long long netfs_read_zero_point(const struct inode *inode)
{
struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode);
unsigned long long zero_point;
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
unsigned int seq;
do {
seq = read_seqcount_begin(&inode->i_size_seqcount);
zero_point = ictx->_zero_point;
} while (read_seqcount_retry(&inode->i_size_seqcount, seq));
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
preempt_disable();
zero_point = ictx->_zero_point;
preempt_enable();
#else
/* Pairs with smp_store_release() in netfs_write_zero_point() */
zero_point = smp_load_acquire(&ictx->_zero_point);
#endif
return zero_point;
}
/*
* netfs_write_zero_point - Set zero_point safely
* @inode: The inode to access
* @zero_point: The new value for the point beyond which the server has no data
*
* Set zero_point safely without the potential for tearing on 32-bit arches.
*
* Context: The caller must hold inode->i_lock.
*
* NOTE: unlike netfs_read_zero_point(), netfs_write_zero_point() does need
* locking around it (normally i_rwsem), otherwise on 32bit/SMP an update of
* i_size_seqcount can be lost, resulting in subsequent read calls spinning
* forever.
*/
static inline void netfs_write_zero_point(struct inode *inode,
unsigned long long zero_point)
{
struct netfs_inode *ictx = netfs_inode(inode);
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
write_seqcount_begin(&inode->i_size_seqcount);
ictx->_zero_point = zero_point;
write_seqcount_end(&inode->i_size_seqcount);
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
preempt_disable();
ictx->_zero_point = zero_point;
preempt_enable();
#else
/*
* Pairs with smp_load_acquire() in netfs_read_zero_point() to
* ensure changes related to inode size (such as page contents) are
* visible before we see the changed inode size.
*/
smp_store_release(&ictx->_zero_point, zero_point);
#endif
}
/**
* netfs_read_sizes - Read remote_i_size and zero_point safely
* @inode: The inode to access
* @i_size: Where to return the local file size.
* @remote_i_size: Where to return the size of the file on the server
* @zero_point: Where to return the the point beyond which the server has no data
*
* Read remote_i_size and zero_point safely without the potential for tearing
* on 32-bit arches.
*
* NOTE: in a 32bit arch with a preemptable kernel and an UP compile the
* i_size_read/write must be atomic with respect to the local cpu (unlike with
* preempt disabled), but they don't need to be atomic with respect to other
* cpus like in true SMP (so they need either to either locally disable irq
* around the read or for example on x86 they can be still implemented as a
* cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit
* archs it makes no difference if preempt is enabled or not.
*/
static inline void netfs_read_sizes(const struct inode *inode,
unsigned long long *i_size,
unsigned long long *remote_i_size,
unsigned long long *zero_point)
{
const struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode);
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
unsigned int seq;
do {
seq = read_seqcount_begin(&inode->i_size_seqcount);
*i_size = inode->i_size;
*remote_i_size = ictx->_remote_i_size;
*zero_point = ictx->_zero_point;
} while (read_seqcount_retry(&inode->i_size_seqcount, seq));
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
preempt_disable();
*i_size = inode->i_size;
*remote_i_size = ictx->_remote_i_size;
*zero_point = ictx->_zero_point;
preempt_enable();
#else
/* Pairs with smp_store_release() in i_size_write() */
*i_size = smp_load_acquire(&inode->i_size);
/* Pairs with smp_store_release() in netfs_write_remote_i_size() */
*remote_i_size = smp_load_acquire(&ictx->_remote_i_size);
/* Pairs with smp_store_release() in netfs_write_zero_point() */
*zero_point = smp_load_acquire(&ictx->_zero_point);
#endif
}
/*
* netfs_write_sizes - Set i_size, remote_i_size and zero_point safely
* @inode: The inode to access
* @i_size: The new value for the local size of the file
* @remote_i_size: The new value for the size of the file on the server
* @zero_point: The new value for the point beyond which the server has no data
*
* Set both remote_i_size and zero_point safely without the potential for
* tearing on 32-bit arches.
*
* Context: The caller must hold inode->i_lock.
*
* NOTE: unlike netfs_read_zero_point(), netfs_write_zero_point() does need
* locking around it (normally i_rwsem), otherwise on 32bit/SMP an update of
* i_size_seqcount can be lost, resulting in subsequent read calls spinning
* forever.
*/
static inline void netfs_write_sizes(struct inode *inode,
unsigned long long i_size,
unsigned long long remote_i_size,
unsigned long long zero_point)
{
struct netfs_inode *ictx = netfs_inode(inode);
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
write_seqcount_begin(&inode->i_size_seqcount);
inode->i_size = i_size;
ictx->_remote_i_size = remote_i_size;
ictx->_zero_point = zero_point;
write_seqcount_end(&inode->i_size_seqcount);
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
preempt_disable();
inode->i_size = i_size;
ictx->_remote_i_size = remote_i_size;
ictx->_zero_point = zero_point;
preempt_enable();
#else
/*
* Pairs with smp_load_acquire() in i_size_read(),
* netfs_read_remote_i_size() and netfs_read_zero_point() to ensure
* changes related to inode size (such as page contents) are visible
* before we see the changed inode size.
*/
smp_store_release(&inode->i_size, i_size);
smp_store_release(&ictx->_remote_i_size, remote_i_size);
smp_store_release(&ictx->_zero_point, zero_point);
#endif
}
/**
* netfs_inode_init - Initialise a netfslib inode context
* @ctx: The netfs inode to initialise
@@ -488,8 +736,8 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,
bool use_zero_point)
{
ctx->ops = ops;
ctx->remote_i_size = i_size_read(&ctx->inode);
ctx->zero_point = LLONG_MAX;
ctx->_remote_i_size = i_size_read(&ctx->inode);
ctx->_zero_point = LLONG_MAX;
ctx->flags = 0;
atomic_set(&ctx->io_count, 0);
#if IS_ENABLED(CONFIG_FSCACHE)
@@ -498,7 +746,7 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,
mutex_init(&ctx->wb_lock);
/* ->releasepage() drives zero_point */
if (use_zero_point) {
ctx->zero_point = ctx->remote_i_size;
ctx->_zero_point = ctx->_remote_i_size;
mapping_set_release_always(ctx->inode.i_mapping);
}
}
@@ -511,13 +759,40 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,
*
* Inform the netfs lib that a file got resized so that it can adjust its state.
*/
static inline void netfs_resize_file(struct netfs_inode *ctx, loff_t new_i_size,
static inline void netfs_resize_file(struct netfs_inode *ictx,
unsigned long long new_i_size,
bool changed_on_server)
{
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
struct inode *inode = &ictx->inode;
preempt_disable();
write_seqcount_begin(&inode->i_size_seqcount);
if (changed_on_server)
ctx->remote_i_size = new_i_size;
if (new_i_size < ctx->zero_point)
ctx->zero_point = new_i_size;
ictx->_remote_i_size = new_i_size;
if (new_i_size < ictx->_zero_point)
ictx->_zero_point = new_i_size;
write_seqcount_end(&inode->i_size_seqcount);
preempt_enable();
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
preempt_disable();
if (changed_on_server)
ictx->_remote_i_size = new_i_size;
if (new_i_size < ictx->_zero_point)
ictx->_zero_point = new_i_size;
preempt_enable();
#else
/*
* Pairs with smp_load_acquire() in netfs_read_remote_i_size and
* netfs_read_zero_point() to ensure changes related to inode size
* (such as page contents) are visible before we see the changed inode
* size.
*/
if (changed_on_server)
smp_store_release(&ictx->_remote_i_size, new_i_size);
if (new_i_size < ictx->_zero_point)
smp_store_release(&ictx->_zero_point, new_i_size);
#endif
}
/**