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

Pull vfs fixes from Christian Brauner:

 - netfs:

    - fix the decision when to disallow write-streaming with fscache in
      use, handling of asynchronous cache object creation, a double fput
      in cachefiles, clearing S_KERNEL_FILE without the inode lock held,
      page extraction bugs in the iov_iter helpers (a potential
      underflow, a missing allocation failure check, a memory leak, and
      a folio offset miscalculation), writeback error and ENOMEM
      handling, DIO write retry for filesystems without a
      ->prepare_write() method, and the replacement of the wb_lock mutex
      with a bit lock plus writethrough collection offload so that
      multiple asynchronous writebacks don't interfere with each other.

    - Fix the barriering when walking the netfs subrequest list during
      retries as it was possible to see a subrequest that was just added
      by the application thread.

 - iomap:

    - Change iomap to submit read bios after each extent instead of
      building them up across extents. The old behavior was considered
      problematic for a while and now caused an actual erofs bug.

    - Guard the ioend io_size EOF trim in iomap against underflow when a
      concurrent truncate moves EOF below the start of the ioend,
      wrapping io_size to a huge value.

 - overlayfs

    - Fix a stale overlayfs comment about the locking order.

    - Store the linked-in upper dentry instead of the disconnected
      O_TMPFILE dentry during overlayfs tmpfile copy-up. With a FUSE or
      virtiofs upper layer ->d_revalidate() would try to look up "/" in
      the workdir and fail, causing persistent ESTALE errors that broke
      dpkg and apt.

 - vfs-bpf:

   Have the bpf_real_data_inode() kfunc take a struct file instead of a
   dentry so it is usable from the bprm_check_security, mmap_file, and
   file_mprotect hooks, and rename it from bpf_real_inode() to make the
   data-inode semantics explicit. The kfunc landed this cycle so the
   change is safe.

 - afs:

   NULL pointer dereferences in the callback service and in
   afs_get_tree(), several memory and refcount leaks, missing locking
   around the dynamic root inode numbers and premature cell exposure
   through /afs, a netns destruction hang caused by a misplaced
   increment of net->cells_outstanding, a bulk lookup malfunction caused
   by the dir_emit() API change, inode (re)initialisation issues, and
   assorted smaller fixes to error codes, seqlock handling, and debug
   output.

 - vfs:

   Refuse O_TMPFILE creation with an unmapped fsuid or fsgid and add a
   selftest for it.

 - vboxsf:

   Add Jori Koolstra as vboxsf maintainer, taking over from Hans de
   Goede.

 - dio:

   Release the pages attached to a short atomic dio bio; the REQ_ATOMIC
   size check error path leaked them.

 - procfs:

   Only bump the parent directory link count when registering
   directories in procfs. Registering regular files inflated the count
   and leaked a link on every create and remove cycle.

 - minix:

   Avoid an unsigned overflow in the minix bitmap block count
   calculation that let crafted images with huge inode or zone counts
   pass superblock validation and crash the kernel during mount.

 - cachefiles:

   Fix a double unlock in the cachefiles nomem_d_alloc error path left
   over from the start_creating() conversion.

 - fat:

   Stop fat from reading directory entries past the 0x00
   end-of-directory marker. If the trailing on-disk slots aren't
   zero-filled the driver surfaced arbitrary garbage as directory
   entries.

 - freexvfs:

   Don't BUG() on unknown typed-extent types in freevxfs, reachable via
   ioctl(FIBMAP) on a crafted image; fail with an I/O error instead.

 - orangefs:

   Keep the readdir entry size 64-bit in orangefs fill_from_part().
   Truncating it to __u32 bypassed the bounds check and led to
   out-of-bounds reads triggerable by the userspace client.

 - xfs:

   Fix the error unwind in xfs_open_devices() which released the rt
   device file twice and left dangling buftarg pointers behind that were
   freed again when the failed mount was torn down.

 - exec:

   Fix an off-by-one in the comment documenting the maximum binfmt
   rewrite depth in exec_binprm(). The code allows five rewrites, not
   four; restricting the code would break userspace so the comment is
   fixed instead.

 - file handles:

   Reject detached mounts in capable_wrt_mount(). A detached mount can
   be dissolved concurrently, leaving a NULL mount namespace that
   open_by_handle_at() would dereference.

* tag 'vfs-7.2-rc2.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (57 commits)
  netfs: Fix barriering when walking subrequest list
  iomap: submit read bio after each extent
  fuse: call fuse_send_readpages explicitly from fuse_readahead
  iomap: consolidate bio submission
  fhandle: reject detached mounts in capable_wrt_mount()
  netfs: Fix DIO write retry for filesystems without a ->prepare_write()
  netfs: Fix folio state after ENOMEM whilst under writeback iteration
  netfs: Fix writeback error handling
  netfs: Fix writethrough to use collection offload
  netfs: Replace wb_lock with a bit lock for asynchronicity
  netfs: Fix kdoc warning
  scatterlist: Fix offset in folio calc in extract_xarray_to_sg()
  iov_iter: Remove unused variable in kunit_iov_iter.c
  iov_iter: Fix a memory leak in iov_iter_extract_user_pages()
  iov_iter: Fix missing alloc fail check in iov_iter_extract_bvec_pages()
  iov_iter: Fix potential underflow in iov_iter_extract_xarray_pages()
  cachefiles: Fix file burial to take lock when unsetting S_KERNEL_FILE
  cachefiles: Fix double fput
  netfs: Fix netfs_create_write_req() to handle async cache object creation
  netfs: Fix decision whether to disallow write-streaming due to fscache use
  ...
This commit is contained in:
Linus Torvalds
2026-07-03 05:48:05 -10:00
52 changed files with 592 additions and 178 deletions
+1 -1
View File
@@ -28725,7 +28725,7 @@ F: include/linux/vbox_utils.h
F: include/uapi/linux/vbox*.h
VIRTUAL BOX SHARED FOLDER VFS DRIVER
M: Hans de Goede <hansg@kernel.org>
M: Jori Koolstra <jkoolstra@xs4all.nl>
L: linux-fsdevel@vger.kernel.org
S: Maintained
F: fs/vboxsf/*
+7 -10
View File
@@ -113,16 +113,12 @@ static struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell,
{
struct afs_volume *volume = NULL;
struct rb_node *p;
int seq = 1;
for (;;) {
scoped_seqlock_read(&cell->volume_lock, ss_lock) {
/* Unfortunately, rbtree walking doesn't give reliable results
* under just the RCU read lock, so we have to check for
* changes.
*/
seq++; /* 2 on the 1st/lockless path, otherwise odd */
read_seqbegin_or_lock(&cell->volume_lock, &seq);
p = rcu_dereference_raw(cell->volumes.rb_node);
while (p) {
volume = rb_entry(p, struct afs_volume, cell_node);
@@ -138,12 +134,9 @@ static struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell,
if (volume && afs_try_get_volume(volume, afs_volume_trace_get_callback))
break;
if (!need_seqretry(&cell->volume_lock, seq))
break;
seq |= 1; /* Want a lock next time */
volume = NULL;
}
done_seqretry(&cell->volume_lock, seq);
return volume;
}
@@ -221,7 +214,11 @@ static void afs_break_some_callbacks(struct afs_server *server,
rcu_read_lock();
volume = afs_lookup_volume_rcu(server->cell, vid);
if (cbb->fid.vnode == 0 && cbb->fid.unique == 0) {
if (!volume) {
/* Ignore breaks on unknown volumes. */
rcu_read_unlock();
*_count = 0;
} else if (cbb->fid.vnode == 0 && cbb->fid.unique == 0) {
afs_break_volume_callback(server, volume);
*_count -= 1;
if (*_count)
+21 -6
View File
@@ -206,11 +206,6 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
cell->dns_status = vllist->status;
smp_store_release(&cell->dns_lookup_count, 1); /* vs source/status */
atomic_inc(&net->cells_outstanding);
ret = idr_alloc_cyclic(&net->cells_dyn_ino, cell,
2, INT_MAX / 2, GFP_KERNEL);
if (ret < 0)
goto error;
cell->dynroot_ino = ret;
cell->debug_id = atomic_inc_return(&cell_debug_id);
trace_afs_cell(cell->debug_id, 1, 0, afs_cell_trace_alloc);
@@ -304,6 +299,13 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net,
goto cell_already_exists;
}
ret = idr_alloc_cyclic(&net->cells_dyn_ino, candidate,
2, INT_MAX / 2, GFP_KERNEL);
if (ret < 0)
goto cant_alloc_ino;
candidate->dynroot_ino = ret;
set_bit(AFS_CELL_FL_HAVE_INO, &candidate->flags);
cell = candidate;
candidate = NULL;
afs_use_cell(cell, trace);
@@ -378,6 +380,11 @@ no_wait:
_leave(" = %p [cell]", cell);
return cell;
cant_alloc_ino:
up_write(&net->cells_lock);
afs_put_cell(candidate, afs_cell_trace_put_candidate);
goto error_noput;
cell_already_exists:
_debug("cell exists");
cell = cursor;
@@ -547,6 +554,8 @@ static int afs_update_cell(struct afs_cell *cell)
rcu_assign_pointer(cell->vl_servers, vllist);
cell->dns_source = vllist->source;
old = p;
} else {
old = vllist;
}
write_unlock(&cell->vl_servers_lock);
afs_put_vlserverlist(cell->net, old);
@@ -577,7 +586,6 @@ static void afs_cell_destroy(struct rcu_head *rcu)
afs_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers));
afs_unuse_cell(cell->alias_of, afs_cell_trace_unuse_alias);
key_put(cell->anonymous_key);
idr_remove(&net->cells_dyn_ino, cell->dynroot_ino);
kfree(cell->name - 1);
kfree(cell);
@@ -592,6 +600,13 @@ static void afs_destroy_cell_work(struct work_struct *work)
afs_see_cell(cell, afs_cell_trace_destroy);
timer_delete_sync(&cell->management_timer);
cancel_work_sync(&cell->manager);
if (test_bit(AFS_CELL_FL_HAVE_INO, &cell->flags)) {
down_write(&cell->net->cells_lock);
idr_remove(&cell->net->cells_dyn_ino, cell->dynroot_ino);
up_write(&cell->net->cells_lock);
}
call_rcu(&cell->rcu, afs_cell_destroy);
}
+5 -2
View File
@@ -334,7 +334,6 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
ret = afs_extract_data(call, false);
switch (ret) {
case 0: break;
case -EAGAIN: return 0;
default: return ret;
}
@@ -364,6 +363,11 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING))
return afs_io_error(call, afs_io_error_cm_reply);
if (!call->server) {
trace_afs_cm_no_server_u(call, call->request);
return 0;
}
if (memcmp(call->request, &call->server->_uuid, sizeof(call->server->_uuid)) != 0) {
pr_notice("Callback UUID does not match fileserver UUID\n");
trace_afs_cm_no_server_u(call, call->request);
@@ -451,7 +455,6 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
ret = afs_extract_data(call, false);
switch (ret) {
case 0: break;
case -EAGAIN: return 0;
default: return ret;
}
+25 -15
View File
@@ -28,9 +28,11 @@ static int afs_d_revalidate(struct inode *dir, const struct qstr *name,
static int afs_d_delete(const struct dentry *dentry);
static void afs_d_iput(struct dentry *dentry, struct inode *inode);
static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen,
loff_t fpos, u64 ino, unsigned dtype);
u64 ino, u32 uniquifier);
#define AFS_LOOKUP_ONE ((filldir_t)0x123UL)
static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
loff_t fpos, u64 ino, unsigned dtype);
u64 ino, u32 uniquifier);
#define AFS_LOOKUP ((filldir_t)0x137UL)
static int afs_create(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, bool excl);
static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
@@ -421,11 +423,18 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode,
}
/* found the next entry */
if (!dir_emit(ctx, dire->u.name, nlen,
ntohl(dire->u.vnode),
(ctx->actor == afs_lookup_filldir ||
ctx->actor == afs_lookup_one_filldir)?
ntohl(dire->u.unique) : DT_UNKNOWN)) {
if (ctx->actor == AFS_LOOKUP) {
if (!afs_lookup_filldir(ctx, dire->u.name, nlen,
ntohl(dire->u.vnode),
ntohl(dire->u.unique)))
return 0;
} else if (ctx->actor == AFS_LOOKUP_ONE) {
if (!afs_lookup_one_filldir(ctx, dire->u.name, nlen,
ntohl(dire->u.vnode),
ntohl(dire->u.unique)))
return 0;
} else if (!dir_emit(ctx, dire->u.name, nlen,
ntohl(dire->u.vnode), DT_UNKNOWN)) {
_leave(" = 0 [full]");
return 0;
}
@@ -545,6 +554,7 @@ static int afs_readdir(struct file *file, struct dir_context *ctx)
{
afs_dataversion_t dir_version;
ctx->dt_flags_mask = UINT_MAX;
return afs_dir_iterate(file_inode(file), ctx, file, &dir_version);
}
@@ -554,14 +564,14 @@ static int afs_readdir(struct file *file, struct dir_context *ctx)
* uniquifier through dtype
*/
static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name,
int nlen, loff_t fpos, u64 ino, unsigned dtype)
int nlen, u64 ino, u32 uniquifier)
{
struct afs_lookup_one_cookie *cookie =
container_of(ctx, struct afs_lookup_one_cookie, ctx);
_enter("{%s,%u},%s,%u,,%llu,%u",
cookie->name.name, cookie->name.len, name, nlen,
(unsigned long long) ino, dtype);
(unsigned long long) ino, uniquifier);
/* insanity checks first */
BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048);
@@ -574,7 +584,7 @@ static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name,
}
cookie->fid.vnode = ino;
cookie->fid.unique = dtype;
cookie->fid.unique = uniquifier;
cookie->found = 1;
_leave(" = false [found]");
@@ -591,7 +601,7 @@ static int afs_do_lookup_one(struct inode *dir, const struct qstr *name,
{
struct afs_super_info *as = dir->i_sb->s_fs_info;
struct afs_lookup_one_cookie cookie = {
.ctx.actor = afs_lookup_one_filldir,
.ctx.actor = AFS_LOOKUP_ONE,
.name = *name,
.fid.vid = as->volume->vid
};
@@ -622,14 +632,14 @@ static int afs_do_lookup_one(struct inode *dir, const struct qstr *name,
* uniquifier through dtype
*/
static bool afs_lookup_filldir(struct dir_context *ctx, const char *name,
int nlen, loff_t fpos, u64 ino, unsigned dtype)
int nlen, u64 ino, u32 uniquifier)
{
struct afs_lookup_cookie *cookie =
container_of(ctx, struct afs_lookup_cookie, ctx);
_enter("{%s,%u},%s,%u,,%llu,%u",
cookie->name.name, cookie->name.len, name, nlen,
(unsigned long long) ino, dtype);
(unsigned long long) ino, uniquifier);
/* insanity checks first */
BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048);
@@ -637,7 +647,7 @@ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name,
if (cookie->nr_fids < 50) {
cookie->fids[cookie->nr_fids].vnode = ino;
cookie->fids[cookie->nr_fids].unique = dtype;
cookie->fids[cookie->nr_fids].unique = uniquifier;
cookie->nr_fids++;
}
@@ -778,7 +788,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry)
for (i = 0; i < ARRAY_SIZE(cookie->fids); i++)
cookie->fids[i].vid = dvnode->fid.vid;
cookie->ctx.actor = afs_lookup_filldir;
cookie->ctx.actor = AFS_LOOKUP;
cookie->name = dentry->d_name;
cookie->nr_fids = 2; /* slot 1 is saved for the fid we actually want
* and slot 0 for the directory */
+1 -1
View File
@@ -278,7 +278,7 @@ static struct dentry *afs_lookup_atcell(struct inode *dir, struct dentry *dentry
}
/*
* Transcribe the cell database into readdir content under the RCU read lock.
* Transcribe the cell database into readdir content under net->cells_lock.
* Each cell produces two entries, one prefixed with a dot and one not.
*/
static int afs_dynroot_readdir_cells(struct afs_net *net, struct dir_context *ctx)
+1 -1
View File
@@ -348,7 +348,7 @@ int afs_put_operation(struct afs_operation *op)
for (i = 0; i < op->nr_files - 2; i++)
if (op->more_files[i].put_vnode)
iput(&op->more_files[i].vnode->netfs.inode);
kfree(op->more_files);
kvfree(op->more_files);
}
if (op->estate) {
+7 -8
View File
@@ -52,9 +52,9 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren
/*
* Set parameters for the netfs library
*/
static void afs_set_netfs_context(struct afs_vnode *vnode)
static void afs_set_netfs_context(struct afs_vnode *vnode, bool is_file)
{
netfs_inode_init(&vnode->netfs, &afs_req_ops, true);
netfs_inode_init(&vnode->netfs, &afs_req_ops, is_file);
}
/*
@@ -93,6 +93,10 @@ static int afs_inode_init_from_status(struct afs_operation *op,
inode->i_gid = make_kgid(&init_user_ns, status->group);
set_nlink(&vnode->netfs.inode, status->nlink);
i_size_write(inode, status->size);
inode_set_bytes(inode, status->size);
afs_set_netfs_context(vnode, status->type == AFS_FTYPE_FILE);
switch (status->type) {
case AFS_FTYPE_FILE:
inode->i_mode = S_IFREG | (status->mode & S_IALLUGO);
@@ -126,7 +130,6 @@ static int afs_inode_init_from_status(struct afs_operation *op,
}
inode->i_mapping->a_ops = &afs_symlink_aops;
inode_nohighmem(inode);
mapping_set_release_always(inode->i_mapping);
break;
default:
dump_vnode(vnode, op->file[0].vnode != vnode ? op->file[0].vnode : NULL);
@@ -134,10 +137,6 @@ static int afs_inode_init_from_status(struct afs_operation *op,
return afs_protocol_error(NULL, afs_eproto_file_type);
}
i_size_write(inode, status->size);
inode_set_bytes(inode, status->size);
afs_set_netfs_context(vnode);
vnode->invalid_before = status->data_version;
trace_afs_set_dv(vnode, status->data_version);
inode_set_iversion_raw(&vnode->netfs.inode, status->data_version);
@@ -566,7 +565,6 @@ struct inode *afs_root_iget(struct super_block *sb, struct key *key)
vnode = AFS_FS_I(inode);
vnode->cb_v_check = atomic_read(&as->volume->cb_v_break);
afs_set_netfs_context(vnode);
op = afs_alloc_operation(key, as->volume);
if (IS_ERR(op)) {
@@ -682,6 +680,7 @@ void afs_evict_inode(struct inode *inode)
inode->i_mapping->a_ops->writepages(inode->i_mapping, &wbc);
}
flush_delayed_work(&vnode->lock_work);
netfs_wait_for_outstanding_io(inode);
truncate_inode_pages_final(&inode->i_data);
netfs_free_folioq_buffer(vnode->directory);
+1 -2
View File
@@ -388,6 +388,7 @@ struct afs_cell {
#define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */
#define AFS_CELL_FL_DO_LOOKUP 1 /* DNS lookup requested */
#define AFS_CELL_FL_CHECK_ALIAS 2 /* Need to check for aliases */
#define AFS_CELL_FL_HAVE_INO 3 /* Have dynroot_ino */
enum afs_cell_state state;
short error;
enum dns_record_source dns_source:8; /* Latest source of data from lookup */
@@ -750,8 +751,6 @@ static inline void afs_vnode_set_cache(struct afs_vnode *vnode,
{
#ifdef CONFIG_AFS_FSCACHE
vnode->netfs.cache = cookie;
if (cookie)
mapping_set_release_always(vnode->netfs.inode.i_mapping);
#endif
}
+3 -2
View File
@@ -587,7 +587,8 @@ static int afs_get_tree(struct fs_context *fc)
}
fc->root = dget(sb->s_root);
trace_afs_get_tree(as->cell, as->volume);
if (!ctx->dyn_root)
trace_afs_get_tree(as->cell, as->volume);
_leave(" = 0 [%p]", sb);
return 0;
@@ -659,7 +660,6 @@ static void afs_i_init_once(void *_vnode)
INIT_LIST_HEAD(&vnode->wb_keys);
INIT_LIST_HEAD(&vnode->pending_locks);
INIT_LIST_HEAD(&vnode->granted_locks);
INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
INIT_LIST_HEAD(&vnode->cb_mmap_link);
seqlock_init(&vnode->cb_lock);
}
@@ -693,6 +693,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
init_rwsem(&vnode->rmdir_lock);
INIT_WORK(&vnode->cb_work, afs_invalidate_mmap_work);
INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
_leave(" = %p", &vnode->netfs.inode);
return &vnode->netfs.inode;
+2 -2
View File
@@ -255,11 +255,11 @@ int afs_symlink_writepages(struct address_space *mapping,
}
if (ret == 0) {
mutex_lock(&vnode->netfs.wb_lock);
netfs_wb_begin(&vnode->netfs, false);
netfs_free_folioq_buffer(vnode->directory);
vnode->directory = NULL;
vnode->directory_size = 0;
mutex_unlock(&vnode->netfs.wb_lock);
netfs_wb_end(&vnode->netfs);
} else if (ret == 1) {
ret = 0; /* Skipped write due to lock conflict. */
}
+21 -3
View File
@@ -92,7 +92,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net,
{
struct afs_addr_list *alist;
const u8 *b = *_b;
int ret = -EINVAL;
int ret;
alist = afs_alloc_addrlist(nr_addrs);
if (!alist)
@@ -110,6 +110,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net,
case DNS_ADDRESS_IS_IPV4:
if (end - b < 4) {
_leave(" = -EINVAL [short inet]");
ret = -EINVAL;
goto error;
}
memcpy(x, b, 4);
@@ -122,6 +123,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net,
case DNS_ADDRESS_IS_IPV6:
if (end - b < 16) {
_leave(" = -EINVAL [short inet6]");
ret = -EINVAL;
goto error;
}
memcpy(x, b, 16);
@@ -198,6 +200,8 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
b += sizeof(*hdr);
while (end - b >= sizeof(bs)) {
int nlen;
bs.name_len = afs_extract_le16(&b);
bs.priority = afs_extract_le16(&b);
bs.weight = afs_extract_le16(&b);
@@ -207,10 +211,12 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
bs.protocol = *b++;
bs.nr_addrs = *b++;
nlen = min3(bs.name_len, end - b, 255);
_debug("extract %u %u %u %u %u %u %*.*s",
bs.name_len, bs.priority, bs.weight,
bs.port, bs.protocol, bs.nr_addrs,
bs.name_len, bs.name_len, b);
bs.name_len, nlen, b);
if (end - b < bs.name_len)
break;
@@ -287,8 +293,20 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
afs_put_addrlist(old, afs_alist_trace_put_vlserver_old);
}
/* Check for duplicates in the server list */
for (j = 0; j < vllist->nr_servers; j++) {
struct afs_vlserver *s = vllist->servers[j].server;
/* TODO: Might want to check for duplicates */
if (s->name_len == server->name_len &&
s->port == server->port &&
strncasecmp(s->name, server->name, server->name_len) == 0) {
afs_put_vlserver(cell->net, server);
server = NULL;
break;
}
}
if (!server)
continue;
/* Insertion-sort by priority and weight */
for (j = 0; j < vllist->nr_servers; j++) {
+1 -1
View File
@@ -40,7 +40,7 @@ static struct afs_volume *afs_insert_volume_into_cell(struct afs_cell *cell,
goto found;
}
set_bit(AFS_VOLUME_RM_TREE, &volume->flags);
set_bit(AFS_VOLUME_RM_TREE, &p->flags);
rb_replace_node_rcu(&p->cell_node, &volume->cell_node, &cell->volumes);
}
}
+14 -9
View File
@@ -360,18 +360,23 @@ __bpf_kfunc int bpf_cgroup_read_xattr(struct cgroup *cgroup, const char *name__s
#endif /* CONFIG_CGROUPS */
/**
* bpf_real_inode - get the real inode backing a dentry
* @dentry: dentry to resolve
* bpf_real_data_inode - get the real inode hosting a file's data
* @file: file to resolve
*
* If the dentry is on a union/overlay filesystem, return the underlying, real
* inode that hosts the data. Otherwise return the inode attached to the
* dentry itself.
* Resolve @file to the inode that hosts its data. For a regular file on a
* union/overlay filesystem this is the underlying (upper or lower) inode that
* stores the data, not the overlay inode.
*
* Return: The real inode backing the dentry, or NULL for a negative dentry.
* Data resolution only applies to regular files. For a non-regular file (e.g.
* a device node, fifo or socket) on a union/overlay filesystem the overlay
* inode itself is returned; for any file on a non-union filesystem the inode
* attached to @file is returned.
*
* Return: The inode hosting @file's data, or NULL.
*/
__bpf_kfunc struct inode *bpf_real_inode(struct dentry *dentry)
__bpf_kfunc struct inode *bpf_real_data_inode(struct file *file)
{
return d_real_inode(dentry);
return d_real_inode(file_dentry(file));
}
__bpf_kfunc_end_defs();
@@ -384,7 +389,7 @@ BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_remove_dentry_xattr, KF_SLEEPABLE)
BTF_ID_FLAGS(func, bpf_real_inode, KF_SLEEPABLE | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_real_data_inode, KF_SLEEPABLE | KF_RET_NULL)
BTF_KFUNCS_END(bpf_fs_kfunc_set_ids)
static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id)
+1 -3
View File
@@ -209,7 +209,6 @@ lookup_error:
return ERR_PTR(ret);
nomem_d_alloc:
inode_unlock(d_inode(dir));
_leave(" = -ENOMEM");
return ERR_PTR(-ENOMEM);
}
@@ -375,7 +374,7 @@ try_again:
"Rename failed with error %d", ret);
}
__cachefiles_unmark_inode_in_use(object, d_inode(rep));
cachefiles_do_unmark_inode_in_use(object, d_inode(rep));
end_renaming(&rd);
_leave(" = 0");
return 0;
@@ -467,7 +466,6 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)
ret = -EINVAL;
if (unlikely(!file->f_op->read_iter) ||
unlikely(!file->f_op->write_iter)) {
fput(file);
pr_notice("Cache does not support read_iter and write_iter\n");
goto err_unuse;
}
+1 -1
View File
@@ -1717,7 +1717,7 @@ static int exec_binprm(struct linux_binprm *bprm)
old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
rcu_read_unlock();
/* This allows 4 levels of binfmt rewrites before failing hard. */
/* This allows 5 levels of binfmt rewrites before failing hard. */
for (depth = 0;; depth++) {
struct file *exec;
if (depth > 5)
+1 -4
View File
@@ -253,10 +253,7 @@ static void exfat_iomap_read_end_io(struct bio *bio)
static void exfat_iomap_bio_submit_read(const struct iomap_iter *iter,
struct iomap_read_folio_ctx *ctx)
{
struct bio *bio = ctx->read_ctx;
bio->bi_end_io = exfat_iomap_read_end_io;
submit_bio(bio);
iomap_bio_submit_read_endio(iter, ctx, exfat_iomap_read_end_io);
}
const struct iomap_read_ops exfat_iomap_bio_read_ops = {
+40 -4
View File
@@ -130,6 +130,31 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos,
return fat__get_entry(dir, pos, bh, de);
}
/*
* Like fat_get_entry(), but honour the FAT end-of-directory marker:
* a dirent whose first name byte is NUL terminates iteration per the
* spec, which also guarantees that every following slot is zeroed.
* Skip straight to the end of the directory so the next call returns
* -1 from fat_bmap() without re-reading the trailing zero slots, and
* so callers that persist *pos across invocations (e.g. readdir's
* ctx->pos) keep reporting EOD. Release *bh and set it to NULL to
* match fat_get_entry()'s contract that *bh is NULL on the -1 return.
*/
static int fat_get_entry_eod(struct inode *dir, loff_t *pos,
struct buffer_head **bh,
struct msdos_dir_entry **de)
{
int err = fat_get_entry(dir, pos, bh, de);
if (err == 0 && (*de)->name[0] == 0) {
brelse(*bh);
*bh = NULL;
*pos = dir->i_size;
return -1;
}
return err;
}
/*
* Convert Unicode 16 to UTF-8, translated Unicode, or ASCII.
* If uni_xlate is enabled and we can't get a 1:1 conversion, use a
@@ -327,7 +352,7 @@ parse_long:
if (ds->id & 0x40)
(*unicode)[offset + 13] = 0;
if (fat_get_entry(dir, pos, bh, de) < 0)
if (fat_get_entry_eod(dir, pos, bh, de) < 0)
return PARSE_EOF;
if (slot == 0)
break;
@@ -489,7 +514,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
err = -ENOENT;
while (1) {
if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1)
goto end_of_dir;
parse_record:
nr_slots = 0;
@@ -601,7 +626,7 @@ static int __fat_readdir(struct inode *inode, struct file *file,
bh = NULL;
get_new:
if (fat_get_entry(inode, &cpos, &bh, &de) == -1)
if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1)
goto end_of_dir;
parse_record:
nr_slots = 0;
@@ -885,7 +910,7 @@ static int fat_get_short_entry(struct inode *dir, loff_t *pos,
struct buffer_head **bh,
struct msdos_dir_entry **de)
{
while (fat_get_entry(dir, pos, bh, de) >= 0) {
while (fat_get_entry_eod(dir, pos, bh, de) >= 0) {
/* free entry or long name entry or volume label */
if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME))
return 0;
@@ -1302,6 +1327,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
struct msdos_dir_entry *de;
int err, free_slots, i, nr_bhs;
loff_t pos;
bool saw_eod;
sinfo->nr_slots = nr_slots;
@@ -1310,12 +1336,15 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
bh = prev = NULL;
pos = 0;
err = -ENOSPC;
saw_eod = false;
while (fat_get_entry(dir, &pos, &bh, &de) > -1) {
/* check the maximum size of directory */
if (pos >= FAT_MAX_DIR_SIZE)
goto error;
if (IS_FREE(de->name)) {
if (de->name[0] == 0)
saw_eod = true;
if (prev != bh) {
get_bh(bh);
bhs[nr_bhs] = prev = bh;
@@ -1325,6 +1354,13 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
if (free_slots == nr_slots)
goto found;
} else {
if (saw_eod) {
fat_fs_error_ratelimit(sb,
"allocated dir entry found after end-of-directory marker (i_pos %lld)",
MSDOS_I(dir)->i_pos);
err = -EIO;
goto error;
}
for (i = 0; i < nr_bhs; i++)
brelse(bhs[i]);
prev = NULL;
+1 -1
View File
@@ -295,7 +295,7 @@ static bool capable_wrt_mount(struct mount *mount)
*/
guard(rcu)();
mnt_ns = READ_ONCE(mount->mnt_ns);
return ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN);
return mnt_ns && ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN);
}
static inline int may_decode_fh(struct handle_to_path_ctx *ctx,
+2 -1
View File
@@ -227,7 +227,8 @@ vxfs_bmap_typed(struct inode *ip, long iblock)
return 0;
}
default:
BUG();
WARN_ON_ONCE(1);
return 0;
}
}

Some files were not shown because too many files have changed in this diff Show More