vfs-6.13.misc

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCZzcToAAKCRCRxhvAZXjc
 osL9AP948FFumJRC28gDJ4xp+X4eohNOfkgoEG8FTbF2zU6ulwD+O0pr26FqpFli
 pqlG+38UdATImpfqqWjPbb72sBYcfQg=
 =wLUh
 -----END PGP SIGNATURE-----

Merge tag 'vfs-6.13.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull misc vfs updates from Christian Brauner:
 "Features:

   - Fixup and improve NLM and kNFSD file lock callbacks

     Last year both GFS2 and OCFS2 had some work done to make their
     locking more robust when exported over NFS. Unfortunately, part of
     that work caused both NLM (for NFS v3 exports) and kNFSD (for
     NFSv4.1+ exports) to no longer send lock notifications to clients

     This in itself is not a huge problem because most NFS clients will
     still poll the server in order to acquire a conflicted lock

     It's important for NLM and kNFSD that they do not block their
     kernel threads inside filesystem's file_lock implementations
     because that can produce deadlocks. We used to make sure of this by
     only trusting that posix_lock_file() can correctly handle blocking
     lock calls asynchronously, so the lock managers would only setup
     their file_lock requests for async callbacks if the filesystem did
     not define its own lock() file operation

     However, when GFS2 and OCFS2 grew the capability to correctly
     handle blocking lock requests asynchronously, they started
     signalling this behavior with EXPORT_OP_ASYNC_LOCK, and the check
     for also trusting posix_lock_file() was inadvertently dropped, so
     now most filesystems no longer produce lock notifications when
     exported over NFS

     Fix this by using an fop_flag which greatly simplifies the problem
     and grooms the way for future uses by both filesystems and lock
     managers alike

   - Add a sysctl to delete the dentry when a file is removed instead of
     making it a negative dentry

     Commit 681ce86235 ("vfs: Delete the associated dentry when
     deleting a file") introduced an unconditional deletion of the
     associated dentry when a file is removed. However, this led to
     performance regressions in specific benchmarks, such as
     ilebench.sum_operations/s, prompting a revert in commit
     4a4be1ad3a ("Revert "vfs: Delete the associated dentry when
     deleting a file""). This reintroduces the concept conditionally
     through a sysctl

   - Expand the statmount() system call:

       * Report the filesystem subtype in a new fs_subtype field to
         e.g., report fuse filesystem subtypes

       * Report the superblock source in a new sb_source field

       * Add a new way to return filesystem specific mount options in an
         option array that returns filesystem specific mount options
         separated by zero bytes and unescaped. This allows caller's to
         retrieve filesystem specific mount options and immediately pass
         them to e.g., fsconfig() without having to unescape or split
         them

       * Report security (LSM) specific mount options in a separate
         security option array. We don't lump them together with
         filesystem specific mount options as security mount options are
         generic and most users aren't interested in them

         The format is the same as for the filesystem specific mount
         option array

   - Support relative paths in fsconfig()'s FSCONFIG_SET_STRING command

   - Optimize acl_permission_check() to avoid costly {g,u}id ownership
     checks if possible

   - Use smp_mb__after_spinlock() to avoid full smp_mb() in evict()

   - Add synchronous wakeup support for ep_poll_callback.

     Currently, epoll only uses wake_up() to wake up task. But sometimes
     there are epoll users which want to use the synchronous wakeup flag
     to give a hint to the scheduler, e.g., the Android binder driver.
     So add a wake_up_sync() define, and use wake_up_sync() when sync is
     true in ep_poll_callback()

  Fixes:

   - Fix kernel documentation for inode_insert5() and iget5_locked()

   - Annotate racy epoll check on file->f_ep

   - Make F_DUPFD_QUERY associative

   - Avoid filename buffer overrun in initramfs

   - Don't let statmount() return empty strings

   - Add a cond_resched() to dump_user_range() to avoid hogging the CPU

   - Don't query the device logical blocksize multiple times for hfsplus

   - Make filemap_read() check that the offset is positive or zero

  Cleanups:

   - Various typo fixes

   - Cleanup wbc_attach_fdatawrite_inode()

   - Add __releases annotation to wbc_attach_and_unlock_inode()

   - Add hugetlbfs tracepoints

   - Fix various vfs kernel doc parameters

   - Remove obsolete TODO comment from io_cancel()

   - Convert wbc_account_cgroup_owner() to take a folio

   - Fix comments for BANDWITH_INTERVAL and wb_domain_writeout_add()

   - Reorder struct posix_acl to save 8 bytes

   - Annotate struct posix_acl with __counted_by()

   - Replace one-element array with flexible array member in freevxfs

   - Use idiomatic atomic64_inc_return() in alloc_mnt_ns()"

* tag 'vfs-6.13.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (35 commits)
  statmount: retrieve security mount options
  vfs: make evict() use smp_mb__after_spinlock instead of smp_mb
  statmount: add flag to retrieve unescaped options
  fs: add the ability for statmount() to report the sb_source
  writeback: wbc_attach_fdatawrite_inode out of line
  writeback: add a __releases annoation to wbc_attach_and_unlock_inode
  fs: add the ability for statmount() to report the fs_subtype
  fs: don't let statmount return empty strings
  fs:aio: Remove TODO comment suggesting hash or array usage in io_cancel()
  hfsplus: don't query the device logical block size multiple times
  freevxfs: Replace one-element array with flexible array member
  fs: optimize acl_permission_check()
  initramfs: avoid filename buffer overrun
  fs/writeback: convert wbc_account_cgroup_owner to take a folio
  acl: Annotate struct posix_acl with __counted_by()
  acl: Realign struct posix_acl to save 8 bytes
  epoll: Add synchronous wakeup support for ep_poll_callback
  coredump: add cond_resched() to dump_user_range
  mm/page-writeback.c: Fix comment of wb_domain_writeout_add()
  mm/page-writeback.c: Update comment for BANDWIDTH_INTERVAL
  ...
This commit is contained in:
Linus Torvalds 2024-11-18 09:35:30 -08:00
commit 70e7730c2a
46 changed files with 531 additions and 141 deletions

View File

@ -2954,7 +2954,7 @@ following two functions.
a queue (device) has been associated with the bio and a queue (device) has been associated with the bio and
before submission. before submission.
wbc_account_cgroup_owner(@wbc, @page, @bytes) wbc_account_cgroup_owner(@wbc, @folio, @bytes)
Should be called for each data segment being written out. Should be called for each data segment being written out.
While this function doesn't care exactly when it's called While this function doesn't care exactly when it's called
during the writeback session, it's the easiest and most during the writeback session, it's the easiest and most

View File

@ -38,6 +38,11 @@ requests. ``aio-max-nr`` allows you to change the maximum value
``aio-max-nr`` does not result in the ``aio-max-nr`` does not result in the
pre-allocation or re-sizing of any kernel data structures. pre-allocation or re-sizing of any kernel data structures.
dentry-negative
----------------------------
Policy for negative dentries. Set to 1 to to always delete the dentry when a
file is removed, and 0 to disable it. By default, this behavior is disabled.
dentry-state dentry-state
------------ ------------

View File

@ -238,10 +238,3 @@ following flags are defined:
all of an inode's dirty data on last close. Exports that behave this all of an inode's dirty data on last close. Exports that behave this
way should set EXPORT_OP_FLUSH_ON_CLOSE so that NFSD knows to skip way should set EXPORT_OP_FLUSH_ON_CLOSE so that NFSD knows to skip
waiting for writeback when closing such files. waiting for writeback when closing such files.
EXPORT_OP_ASYNC_LOCK - Indicates a capable filesystem to do async lock
requests from lockd. Only set EXPORT_OP_ASYNC_LOCK if the filesystem has
it's own ->lock() functionality as core posix_lock_file() implementation
has no async lock request handling yet. For more information about how to
indicate an async lock request from a ->lock() file_operations struct, see
fs/locks.c and comment for the function vfs_lock_file().

View File

@ -10493,6 +10493,7 @@ F: Documentation/mm/hugetlbfs_reserv.rst
F: Documentation/mm/vmemmap_dedup.rst F: Documentation/mm/vmemmap_dedup.rst
F: fs/hugetlbfs/ F: fs/hugetlbfs/
F: include/linux/hugetlb.h F: include/linux/hugetlb.h
F: include/trace/events/hugetlbfs.h
F: mm/hugetlb.c F: mm/hugetlb.c
F: mm/hugetlb_vmemmap.c F: mm/hugetlb_vmemmap.c
F: mm/hugetlb_vmemmap.h F: mm/hugetlb_vmemmap.h

View File

@ -2191,7 +2191,6 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb,
return -EINVAL; return -EINVAL;
spin_lock_irq(&ctx->ctx_lock); spin_lock_irq(&ctx->ctx_lock);
/* TODO: use a hash or array, this sucks. */
list_for_each_entry(kiocb, &ctx->active_reqs, ki_list) { list_for_each_entry(kiocb, &ctx->active_reqs, ki_list) {
if (kiocb->ki_res.obj == obj) { if (kiocb->ki_res.obj == obj) {
ret = kiocb->ki_cancel(&kiocb->rw); ret = kiocb->ki_cancel(&kiocb->rw);

View File

@ -786,7 +786,7 @@ static void submit_extent_folio(struct btrfs_bio_ctrl *bio_ctrl,
} }
if (bio_ctrl->wbc) if (bio_ctrl->wbc)
wbc_account_cgroup_owner(bio_ctrl->wbc, &folio->page, wbc_account_cgroup_owner(bio_ctrl->wbc, folio,
len); len);
size -= len; size -= len;
@ -1708,7 +1708,7 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb,
ret = bio_add_folio(&bbio->bio, folio, eb->len, ret = bio_add_folio(&bbio->bio, folio, eb->len,
eb->start - folio_pos(folio)); eb->start - folio_pos(folio));
ASSERT(ret); ASSERT(ret);
wbc_account_cgroup_owner(wbc, folio_page(folio, 0), eb->len); wbc_account_cgroup_owner(wbc, folio, eb->len);
folio_unlock(folio); folio_unlock(folio);
} else { } else {
int num_folios = num_extent_folios(eb); int num_folios = num_extent_folios(eb);
@ -1722,8 +1722,7 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb,
folio_start_writeback(folio); folio_start_writeback(folio);
ret = bio_add_folio(&bbio->bio, folio, eb->folio_size, 0); ret = bio_add_folio(&bbio->bio, folio, eb->folio_size, 0);
ASSERT(ret); ASSERT(ret);
wbc_account_cgroup_owner(wbc, folio_page(folio, 0), wbc_account_cgroup_owner(wbc, folio, eb->folio_size);
eb->folio_size);
wbc->nr_to_write -= folio_nr_pages(folio); wbc->nr_to_write -= folio_nr_pages(folio);
folio_unlock(folio); folio_unlock(folio);
} }

View File

@ -1729,7 +1729,7 @@ static bool run_delalloc_compressed(struct btrfs_inode *inode,
* need full accuracy. Just account the whole thing * need full accuracy. Just account the whole thing
* against the first page. * against the first page.
*/ */
wbc_account_cgroup_owner(wbc, &locked_folio->page, wbc_account_cgroup_owner(wbc, locked_folio,
cur_end - start); cur_end - start);
async_chunk[i].locked_folio = locked_folio; async_chunk[i].locked_folio = locked_folio;
locked_folio = NULL; locked_folio = NULL;

View File

@ -2803,7 +2803,7 @@ static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
bio->bi_write_hint = write_hint; bio->bi_write_hint = write_hint;
__bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh)); bio_add_folio_nofail(bio, bh->b_folio, bh->b_size, bh_offset(bh));
bio->bi_end_io = end_bio_bh_io_sync; bio->bi_end_io = end_bio_bh_io_sync;
bio->bi_private = bh; bio->bi_private = bh;
@ -2813,7 +2813,7 @@ static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
if (wbc) { if (wbc) {
wbc_init_bio(wbc, bio); wbc_init_bio(wbc, bio);
wbc_account_cgroup_owner(wbc, bh->b_page, bh->b_size); wbc_account_cgroup_owner(wbc, bh->b_folio, bh->b_size);
} }
submit_bio(bio); submit_bio(bio);

View File

@ -562,8 +562,8 @@ int cdev_device_add(struct cdev *cdev, struct device *dev)
/** /**
* cdev_device_del() - inverse of cdev_device_add * cdev_device_del() - inverse of cdev_device_add
* @dev: the device structure
* @cdev: the cdev structure * @cdev: the cdev structure
* @dev: the device structure
* *
* cdev_device_del() is a helper function to call cdev_del and device_del. * cdev_device_del() is a helper function to call cdev_del and device_del.
* It should be used whenever cdev_device_add is used. * It should be used whenever cdev_device_add is used.

View File

@ -951,6 +951,7 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start,
} else { } else {
dump_skip(cprm, PAGE_SIZE); dump_skip(cprm, PAGE_SIZE);
} }
cond_resched();
} }
dump_page_free(dump_page); dump_page_free(dump_page);
return 1; return 1;

View File

@ -135,6 +135,7 @@ struct dentry_stat_t {
static DEFINE_PER_CPU(long, nr_dentry); static DEFINE_PER_CPU(long, nr_dentry);
static DEFINE_PER_CPU(long, nr_dentry_unused); static DEFINE_PER_CPU(long, nr_dentry_unused);
static DEFINE_PER_CPU(long, nr_dentry_negative); static DEFINE_PER_CPU(long, nr_dentry_negative);
static int dentry_negative_policy;
#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
/* Statistics gathering. */ /* Statistics gathering. */
@ -199,6 +200,15 @@ static struct ctl_table fs_dcache_sysctls[] = {
.mode = 0444, .mode = 0444,
.proc_handler = proc_nr_dentry, .proc_handler = proc_nr_dentry,
}, },
{
.procname = "dentry-negative",
.data = &dentry_negative_policy,
.maxlen = sizeof(dentry_negative_policy),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
}; };
static int __init init_fs_dcache_sysctls(void) static int __init init_fs_dcache_sysctls(void)
@ -2039,8 +2049,8 @@ EXPORT_SYMBOL(d_obtain_root);
/** /**
* d_add_ci - lookup or allocate new dentry with case-exact name * d_add_ci - lookup or allocate new dentry with case-exact name
* @inode: the inode case-insensitive lookup has found
* @dentry: the negative dentry that was passed to the parent's lookup func * @dentry: the negative dentry that was passed to the parent's lookup func
* @inode: the inode case-insensitive lookup has found
* @name: the case-exact name to be associated with the returned dentry * @name: the case-exact name to be associated with the returned dentry
* *
* This is to avoid filling the dcache with case-insensitive names to the * This is to avoid filling the dcache with case-insensitive names to the
@ -2093,8 +2103,8 @@ EXPORT_SYMBOL(d_add_ci);
/** /**
* d_same_name - compare dentry name with case-exact name * d_same_name - compare dentry name with case-exact name
* @parent: parent dentry
* @dentry: the negative dentry that was passed to the parent's lookup func * @dentry: the negative dentry that was passed to the parent's lookup func
* @parent: parent dentry
* @name: the case-exact name to be associated with the returned dentry * @name: the case-exact name to be associated with the returned dentry
* *
* Return: true if names are same, or false * Return: true if names are same, or false
@ -2401,6 +2411,8 @@ void d_delete(struct dentry * dentry)
* Are we the only user? * Are we the only user?
*/ */
if (dentry->d_lockref.count == 1) { if (dentry->d_lockref.count == 1) {
if (dentry_negative_policy)
__d_drop(dentry);
dentry->d_flags &= ~DCACHE_CANT_MOUNT; dentry->d_flags &= ~DCACHE_CANT_MOUNT;
dentry_unlink_inode(dentry); dentry_unlink_inode(dentry);
} else { } else {

View File

@ -823,7 +823,8 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
to_free = NULL; to_free = NULL;
head = file->f_ep; head = file->f_ep;
if (head->first == &epi->fllink && !epi->fllink.next) { if (head->first == &epi->fllink && !epi->fllink.next) {
file->f_ep = NULL; /* See eventpoll_release() for details. */
WRITE_ONCE(file->f_ep, NULL);
if (!is_file_epoll(file)) { if (!is_file_epoll(file)) {
struct epitems_head *v; struct epitems_head *v;
v = container_of(head, struct epitems_head, epitems); v = container_of(head, struct epitems_head, epitems);
@ -1372,6 +1373,9 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v
break; break;
} }
} }
if (sync)
wake_up_sync(&ep->wq);
else
wake_up(&ep->wq); wake_up(&ep->wq);
} }
if (waitqueue_active(&ep->poll_wait)) if (waitqueue_active(&ep->poll_wait))
@ -1603,7 +1607,8 @@ allocate:
spin_unlock(&file->f_lock); spin_unlock(&file->f_lock);
goto allocate; goto allocate;
} }
file->f_ep = head; /* See eventpoll_release() for details. */
WRITE_ONCE(file->f_ep, head);
to_free = NULL; to_free = NULL;
} }
hlist_add_head_rcu(&epi->fllink, file->f_ep); hlist_add_head_rcu(&epi->fllink, file->f_ep);

View File

@ -421,7 +421,7 @@ submit_and_retry:
io_submit_init_bio(io, bh); io_submit_init_bio(io, bh);
if (!bio_add_folio(io->io_bio, io_folio, bh->b_size, bh_offset(bh))) if (!bio_add_folio(io->io_bio, io_folio, bh->b_size, bh_offset(bh)))
goto submit_and_retry; goto submit_and_retry;
wbc_account_cgroup_owner(io->io_wbc, &folio->page, bh->b_size); wbc_account_cgroup_owner(io->io_wbc, folio, bh->b_size);
io->io_next_block++; io->io_next_block++;
} }

View File

@ -711,7 +711,8 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
} }
if (fio->io_wbc && !is_read_io(fio->op)) if (fio->io_wbc && !is_read_io(fio->op))
wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); wbc_account_cgroup_owner(fio->io_wbc, page_folio(fio->page),
PAGE_SIZE);
inc_page_count(fio->sbi, is_read_io(fio->op) ? inc_page_count(fio->sbi, is_read_io(fio->op) ?
__read_io_type(page) : WB_DATA_TYPE(fio->page, false)); __read_io_type(page) : WB_DATA_TYPE(fio->page, false));
@ -911,7 +912,8 @@ alloc_new:
} }
if (fio->io_wbc) if (fio->io_wbc)
wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); wbc_account_cgroup_owner(fio->io_wbc, page_folio(fio->page),
PAGE_SIZE);
inc_page_count(fio->sbi, WB_DATA_TYPE(page, false)); inc_page_count(fio->sbi, WB_DATA_TYPE(page, false));
@ -1011,7 +1013,8 @@ alloc_new:
} }
if (fio->io_wbc) if (fio->io_wbc)
wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); wbc_account_cgroup_owner(fio->io_wbc, page_folio(fio->page),
PAGE_SIZE);
io->last_block_in_bio = fio->new_blkaddr; io->last_block_in_bio = fio->new_blkaddr;

View File

@ -397,6 +397,9 @@ static long f_dupfd_query(int fd, struct file *filp)
{ {
CLASS(fd_raw, f)(fd); CLASS(fd_raw, f)(fd);
if (fd_empty(f))
return -EBADF;
/* /*
* We can do the 'fdput()' immediately, as the only thing that * We can do the 'fdput()' immediately, as the only thing that
* matters is the pointer value which isn't changed by the fdput. * matters is the pointer value which isn't changed by the fdput.

View File

@ -25,7 +25,7 @@
struct vxfs_dirblk { struct vxfs_dirblk {
__fs16 d_free; /* free space in dirblock */ __fs16 d_free; /* free space in dirblock */
__fs16 d_nhash; /* no of hash chains */ __fs16 d_nhash; /* no of hash chains */
__fs16 d_hash[1]; /* hash chain */ __fs16 d_hash[]; /* hash chain */
}; };
/* /*

View File

@ -290,7 +290,6 @@ void __inode_attach_wb(struct inode *inode, struct folio *folio)
if (unlikely(cmpxchg(&inode->i_wb, NULL, wb))) if (unlikely(cmpxchg(&inode->i_wb, NULL, wb)))
wb_put(wb); wb_put(wb);
} }
EXPORT_SYMBOL_GPL(__inode_attach_wb);
/** /**
* inode_cgwb_move_to_attached - put the inode onto wb->b_attached list * inode_cgwb_move_to_attached - put the inode onto wb->b_attached list
@ -731,8 +730,9 @@ bool cleanup_offline_cgwb(struct bdi_writeback *wb)
* writeback completion, wbc_detach_inode() should be called. This is used * writeback completion, wbc_detach_inode() should be called. This is used
* to track the cgroup writeback context. * to track the cgroup writeback context.
*/ */
void wbc_attach_and_unlock_inode(struct writeback_control *wbc, static void wbc_attach_and_unlock_inode(struct writeback_control *wbc,
struct inode *inode) struct inode *inode)
__releases(&inode->i_lock)
{ {
if (!inode_cgwb_enabled(inode)) { if (!inode_cgwb_enabled(inode)) {
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
@ -762,7 +762,24 @@ void wbc_attach_and_unlock_inode(struct writeback_control *wbc,
if (unlikely(wb_dying(wbc->wb) && !css_is_dying(wbc->wb->memcg_css))) if (unlikely(wb_dying(wbc->wb) && !css_is_dying(wbc->wb->memcg_css)))
inode_switch_wbs(inode, wbc->wb_id); inode_switch_wbs(inode, wbc->wb_id);
} }
EXPORT_SYMBOL_GPL(wbc_attach_and_unlock_inode);
/**
* wbc_attach_fdatawrite_inode - associate wbc and inode for fdatawrite
* @wbc: writeback_control of interest
* @inode: target inode
*
* This function is to be used by __filemap_fdatawrite_range(), which is an
* alternative entry point into writeback code, and first ensures @inode is
* associated with a bdi_writeback and attaches it to @wbc.
*/
void wbc_attach_fdatawrite_inode(struct writeback_control *wbc,
struct inode *inode)
{
spin_lock(&inode->i_lock);
inode_attach_wb(inode, NULL);
wbc_attach_and_unlock_inode(wbc, inode);
}
EXPORT_SYMBOL_GPL(wbc_attach_fdatawrite_inode);
/** /**
* wbc_detach_inode - disassociate wbc from inode and perform foreign detection * wbc_detach_inode - disassociate wbc from inode and perform foreign detection
@ -890,17 +907,16 @@ EXPORT_SYMBOL_GPL(wbc_detach_inode);
/** /**
* wbc_account_cgroup_owner - account writeback to update inode cgroup ownership * wbc_account_cgroup_owner - account writeback to update inode cgroup ownership
* @wbc: writeback_control of the writeback in progress * @wbc: writeback_control of the writeback in progress
* @page: page being written out * @folio: folio being written out
* @bytes: number of bytes being written out * @bytes: number of bytes being written out
* *
* @bytes from @page are about to written out during the writeback * @bytes from @folio are about to written out during the writeback
* controlled by @wbc. Keep the book for foreign inode detection. See * controlled by @wbc. Keep the book for foreign inode detection. See
* wbc_detach_inode(). * wbc_detach_inode().
*/ */
void wbc_account_cgroup_owner(struct writeback_control *wbc, struct page *page, void wbc_account_cgroup_owner(struct writeback_control *wbc, struct folio *folio,
size_t bytes) size_t bytes)
{ {
struct folio *folio;
struct cgroup_subsys_state *css; struct cgroup_subsys_state *css;
int id; int id;
@ -913,7 +929,6 @@ void wbc_account_cgroup_owner(struct writeback_control *wbc, struct page *page,
if (!wbc->wb || wbc->no_cgroup_owner) if (!wbc->wb || wbc->no_cgroup_owner)
return; return;
folio = page_folio(page);
css = mem_cgroup_css_from_folio(folio); css = mem_cgroup_css_from_folio(folio);
/* dead cgroups shouldn't contribute to inode ownership arbitration */ /* dead cgroups shouldn't contribute to inode ownership arbitration */
if (!(css->flags & CSS_ONLINE)) if (!(css->flags & CSS_ONLINE))
@ -1227,6 +1242,13 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
} }
} }
static inline void wbc_attach_and_unlock_inode(struct writeback_control *wbc,
struct inode *inode)
__releases(&inode->i_lock)
{
spin_unlock(&inode->i_lock);
}
#endif /* CONFIG_CGROUP_WRITEBACK */ #endif /* CONFIG_CGROUP_WRITEBACK */
/* /*

View File

@ -156,6 +156,7 @@ int fs_lookup_param(struct fs_context *fc,
f = getname_kernel(param->string); f = getname_kernel(param->string);
if (IS_ERR(f)) if (IS_ERR(f))
return PTR_ERR(f); return PTR_ERR(f);
param->dirfd = AT_FDCWD;
put_f = true; put_f = true;
break; break;
case fs_value_is_filename: case fs_value_is_filename:

View File

@ -190,6 +190,5 @@ const struct export_operations gfs2_export_ops = {
.fh_to_parent = gfs2_fh_to_parent, .fh_to_parent = gfs2_fh_to_parent,
.get_name = gfs2_get_name, .get_name = gfs2_get_name,
.get_parent = gfs2_get_parent, .get_parent = gfs2_get_parent,
.flags = EXPORT_OP_ASYNC_LOCK,
}; };

View File

@ -1586,6 +1586,7 @@ const struct file_operations gfs2_file_fops = {
.splice_write = gfs2_file_splice_write, .splice_write = gfs2_file_splice_write,
.setlease = simple_nosetlease, .setlease = simple_nosetlease,
.fallocate = gfs2_fallocate, .fallocate = gfs2_fallocate,
.fop_flags = FOP_ASYNC_LOCK,
}; };
const struct file_operations gfs2_dir_fops = { const struct file_operations gfs2_dir_fops = {
@ -1598,6 +1599,7 @@ const struct file_operations gfs2_dir_fops = {
.lock = gfs2_lock, .lock = gfs2_lock,
.flock = gfs2_flock, .flock = gfs2_flock,
.llseek = default_llseek, .llseek = default_llseek,
.fop_flags = FOP_ASYNC_LOCK,
}; };
#endif /* CONFIG_GFS2_FS_LOCKING_DLM */ #endif /* CONFIG_GFS2_FS_LOCKING_DLM */

View File

@ -157,6 +157,7 @@ struct hfsplus_sb_info {
/* Runtime variables */ /* Runtime variables */
u32 blockoffset; u32 blockoffset;
u32 min_io_size;
sector_t part_start; sector_t part_start;
sector_t sect_count; sector_t sect_count;
int fs_shift; int fs_shift;
@ -308,7 +309,7 @@ struct hfsplus_readdir_data {
*/ */
static inline unsigned short hfsplus_min_io_size(struct super_block *sb) static inline unsigned short hfsplus_min_io_size(struct super_block *sb)
{ {
return max_t(unsigned short, bdev_logical_block_size(sb->s_bdev), return max_t(unsigned short, HFSPLUS_SB(sb)->min_io_size,
HFSPLUS_SECTOR_SIZE); HFSPLUS_SECTOR_SIZE);
} }

View File

@ -172,6 +172,8 @@ int hfsplus_read_wrapper(struct super_block *sb)
if (!blocksize) if (!blocksize)
goto out; goto out;
sbi->min_io_size = blocksize;
if (hfsplus_get_last_session(sb, &part_start, &part_size)) if (hfsplus_get_last_session(sb, &part_start, &part_size))
goto out; goto out;

View File

@ -39,6 +39,9 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/sched/mm.h> #include <linux/sched/mm.h>
#define CREATE_TRACE_POINTS
#include <trace/events/hugetlbfs.h>
static const struct address_space_operations hugetlbfs_aops; static const struct address_space_operations hugetlbfs_aops;
static const struct file_operations hugetlbfs_file_operations; static const struct file_operations hugetlbfs_file_operations;
static const struct inode_operations hugetlbfs_dir_inode_operations; static const struct inode_operations hugetlbfs_dir_inode_operations;
@ -687,6 +690,7 @@ static void hugetlbfs_evict_inode(struct inode *inode)
{ {
struct resv_map *resv_map; struct resv_map *resv_map;
trace_hugetlbfs_evict_inode(inode);
remove_inode_hugepages(inode, 0, LLONG_MAX); remove_inode_hugepages(inode, 0, LLONG_MAX);
/* /*
@ -814,8 +818,10 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (mode & FALLOC_FL_PUNCH_HOLE) if (mode & FALLOC_FL_PUNCH_HOLE) {
return hugetlbfs_punch_hole(inode, offset, len); error = hugetlbfs_punch_hole(inode, offset, len);
goto out_nolock;
}
/* /*
* Default preallocate case. * Default preallocate case.
@ -919,6 +925,9 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
inode_set_ctime_current(inode); inode_set_ctime_current(inode);
out: out:
inode_unlock(inode); inode_unlock(inode);
out_nolock:
trace_hugetlbfs_fallocate(inode, mode, offset, len, error);
return error; return error;
} }
@ -935,6 +944,8 @@ static int hugetlbfs_setattr(struct mnt_idmap *idmap,
if (error) if (error)
return error; return error;
trace_hugetlbfs_setattr(inode, dentry, attr);
if (ia_valid & ATTR_SIZE) { if (ia_valid & ATTR_SIZE) {
loff_t oldsize = inode->i_size; loff_t oldsize = inode->i_size;
loff_t newsize = attr->ia_size; loff_t newsize = attr->ia_size;
@ -1033,6 +1044,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
break; break;
} }
lockdep_annotate_inode_mutex_key(inode); lockdep_annotate_inode_mutex_key(inode);
trace_hugetlbfs_alloc_inode(inode, dir, mode);
} else { } else {
if (resv_map) if (resv_map)
kref_put(&resv_map->refs, resv_map_release); kref_put(&resv_map->refs, resv_map_release);
@ -1272,6 +1284,7 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb)
static void hugetlbfs_free_inode(struct inode *inode) static void hugetlbfs_free_inode(struct inode *inode)
{ {
trace_hugetlbfs_free_inode(inode);
kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode)); kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode));
} }

View File

@ -819,7 +819,7 @@ static void evict(struct inode *inode)
* ___wait_var_event() either sees the bit cleared or * ___wait_var_event() either sees the bit cleared or
* waitqueue_active() check in wake_up_var() sees the waiter. * waitqueue_active() check in wake_up_var() sees the waiter.
*/ */
smp_mb(); smp_mb__after_spinlock();
inode_wake_up_bit(inode, __I_NEW); inode_wake_up_bit(inode, __I_NEW);
BUG_ON(inode->i_state != (I_FREEING | I_CLEAR)); BUG_ON(inode->i_state != (I_FREEING | I_CLEAR));
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
@ -1312,16 +1312,15 @@ EXPORT_SYMBOL(unlock_two_nondirectories);
* @data: opaque data pointer to pass to @test and @set * @data: opaque data pointer to pass to @test and @set
* *
* Search for the inode specified by @hashval and @data in the inode cache, * Search for the inode specified by @hashval and @data in the inode cache,
* and if present it is return it with an increased reference count. This is * and if present return it with an increased reference count. This is a
* a variant of iget5_locked() for callers that don't want to fail on memory * variant of iget5_locked() that doesn't allocate an inode.
* allocation of inode.
* *
* If the inode is not in cache, insert the pre-allocated inode to cache and * If the inode is not present in the cache, insert the pre-allocated inode and
* return it locked, hashed, and with the I_NEW flag set. The file system gets * return it locked, hashed, and with the I_NEW flag set. The file system gets
* to fill it in before unlocking it via unlock_new_inode(). * to fill it in before unlocking it via unlock_new_inode().
* *
* Note both @test and @set are called with the inode_hash_lock held, so can't * Note that both @test and @set are called with the inode_hash_lock held, so
* sleep. * they can't sleep.
*/ */
struct inode *inode_insert5(struct inode *inode, unsigned long hashval, struct inode *inode_insert5(struct inode *inode, unsigned long hashval,
int (*test)(struct inode *, void *), int (*test)(struct inode *, void *),
@ -1385,16 +1384,16 @@ EXPORT_SYMBOL(inode_insert5);
* @data: opaque data pointer to pass to @test and @set * @data: opaque data pointer to pass to @test and @set
* *
* Search for the inode specified by @hashval and @data in the inode cache, * Search for the inode specified by @hashval and @data in the inode cache,
* and if present it is return it with an increased reference count. This is * and if present return it with an increased reference count. This is a
* a generalized version of iget_locked() for file systems where the inode * generalized version of iget_locked() for file systems where the inode
* number is not sufficient for unique identification of an inode. * number is not sufficient for unique identification of an inode.
* *
* If the inode is not in cache, allocate a new inode and return it locked, * If the inode is not present in the cache, allocate and insert a new inode
* hashed, and with the I_NEW flag set. The file system gets to fill it in * and return it locked, hashed, and with the I_NEW flag set. The file system
* before unlocking it via unlock_new_inode(). * gets to fill it in before unlocking it via unlock_new_inode().
* *
* Note both @test and @set are called with the inode_hash_lock held, so can't * Note that both @test and @set are called with the inode_hash_lock held, so
* sleep. * they can't sleep.
*/ */
struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
int (*test)(struct inode *, void *), int (*test)(struct inode *, void *),
@ -2912,7 +2911,7 @@ EXPORT_SYMBOL(inode_set_ctime_deleg);
* @inode: inode to check * @inode: inode to check
* @vfsgid: the new/current vfsgid of @inode * @vfsgid: the new/current vfsgid of @inode
* *
* Check wether @vfsgid is in the caller's group list or if the caller is * Check whether @vfsgid is in the caller's group list or if the caller is
* privileged with CAP_FSETID over @inode. This can be used to determine * privileged with CAP_FSETID over @inode. This can be used to determine
* whether the setgid bit can be kept or must be dropped. * whether the setgid bit can be kept or must be dropped.
* *

View File

@ -1784,7 +1784,7 @@ new_ioend:
if (ifs) if (ifs)
atomic_add(len, &ifs->write_bytes_pending); atomic_add(len, &ifs->write_bytes_pending);
wpc->ioend->io_size += len; wpc->ioend->io_size += len;
wbc_account_cgroup_owner(wbc, &folio->page, len); wbc_account_cgroup_owner(wbc, folio, len);
return 0; return 0;
} }

View File

@ -30,7 +30,6 @@
#include <linux/sunrpc/svc_xprt.h> #include <linux/sunrpc/svc_xprt.h>
#include <linux/lockd/nlm.h> #include <linux/lockd/nlm.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/exportfs.h>
#define NLMDBG_FACILITY NLMDBG_SVCLOCK #define NLMDBG_FACILITY NLMDBG_SVCLOCK
@ -481,7 +480,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_host *host, struct nlm_lock *lock, int wait, struct nlm_host *host, struct nlm_lock *lock, int wait,
struct nlm_cookie *cookie, int reclaim) struct nlm_cookie *cookie, int reclaim)
{ {
struct inode *inode = nlmsvc_file_inode(file); struct inode *inode __maybe_unused = nlmsvc_file_inode(file);
struct nlm_block *block = NULL; struct nlm_block *block = NULL;
int error; int error;
int mode; int mode;
@ -496,7 +495,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
(long long)lock->fl.fl_end, (long long)lock->fl.fl_end,
wait); wait);
if (!exportfs_lock_op_is_async(inode->i_sb->s_export_op)) { if (!locks_can_async_lock(nlmsvc_file_file(file)->f_op)) {
async_block = wait; async_block = wait;
wait = 0; wait = 0;
} }
@ -550,7 +549,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
* requests on the underlaying ->lock() implementation but * requests on the underlaying ->lock() implementation but
* only one nlm_block to being granted by lm_grant(). * only one nlm_block to being granted by lm_grant().
*/ */
if (exportfs_lock_op_is_async(inode->i_sb->s_export_op) && if (locks_can_async_lock(nlmsvc_file_file(file)->f_op) &&
!list_empty(&block->b_list)) { !list_empty(&block->b_list)) {
spin_unlock(&nlm_blocked_lock); spin_unlock(&nlm_blocked_lock);
ret = nlm_lck_blocked; ret = nlm_lck_blocked;

View File

@ -606,7 +606,7 @@ alloc_new:
* the confused fail path above (OOM) will be very confused when * the confused fail path above (OOM) will be very confused when
* it finds all bh marked clean (i.e. it will not write anything) * it finds all bh marked clean (i.e. it will not write anything)
*/ */
wbc_account_cgroup_owner(wbc, &folio->page, folio_size(folio)); wbc_account_cgroup_owner(wbc, folio, folio_size(folio));
length = first_unmapped << blkbits; length = first_unmapped << blkbits;
if (!bio_add_folio(bio, folio, length, 0)) { if (!bio_add_folio(bio, folio, length, 0)) {
bio = mpage_bio_submit_write(bio); bio = mpage_bio_submit_write(bio);

View File

@ -326,6 +326,25 @@ static int check_acl(struct mnt_idmap *idmap,
return -EAGAIN; return -EAGAIN;
} }
/*
* Very quick optimistic "we know we have no ACL's" check.
*
* Note that this is purely for ACL_TYPE_ACCESS, and purely
* for the "we have cached that there are no ACLs" case.
*
* If this returns true, we know there are no ACLs. But if
* it returns false, we might still not have ACLs (it could
* be the is_uncached_acl() case).
*/
static inline bool no_acl_inode(struct inode *inode)
{
#ifdef CONFIG_FS_POSIX_ACL
return likely(!READ_ONCE(inode->i_acl));
#else
return true;
#endif
}
/** /**
* acl_permission_check - perform basic UNIX permission checking * acl_permission_check - perform basic UNIX permission checking
* @idmap: idmap of the mount the inode was found from * @idmap: idmap of the mount the inode was found from
@ -348,6 +367,28 @@ static int acl_permission_check(struct mnt_idmap *idmap,
unsigned int mode = inode->i_mode; unsigned int mode = inode->i_mode;
vfsuid_t vfsuid; vfsuid_t vfsuid;
/*
* Common cheap case: everybody has the requested
* rights, and there are no ACLs to check. No need
* to do any owner/group checks in that case.
*
* - 'mask&7' is the requested permission bit set
* - multiplying by 0111 spreads them out to all of ugo
* - '& ~mode' looks for missing inode permission bits
* - the '!' is for "no missing permissions"
*
* After that, we just need to check that there are no
* ACL's on the inode - do the 'IS_POSIXACL()' check last
* because it will dereference the ->i_sb pointer and we
* want to avoid that if at all possible.
*/
if (!((mask & 7) * 0111 & ~mode)) {
if (no_acl_inode(inode))
return 0;
if (!IS_POSIXACL(inode))
return 0;
}
/* Are we the owner? If so, ACL's don't matter */ /* Are we the owner? If so, ACL's don't matter */
vfsuid = i_uid_into_vfsuid(idmap, inode); vfsuid = i_uid_into_vfsuid(idmap, inode);
if (likely(vfsuid_eq_kuid(vfsuid, current_fsuid()))) { if (likely(vfsuid_eq_kuid(vfsuid, current_fsuid()))) {

View File

@ -3901,7 +3901,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, bool a
} }
new_ns->ns.ops = &mntns_operations; new_ns->ns.ops = &mntns_operations;
if (!anon) if (!anon)
new_ns->seq = atomic64_add_return(1, &mnt_ns_seq); new_ns->seq = atomic64_inc_return(&mnt_ns_seq);
refcount_set(&new_ns->ns.count, 1); refcount_set(&new_ns->ns.count, 1);
refcount_set(&new_ns->passive, 1); refcount_set(&new_ns->passive, 1);
new_ns->mounts = RB_ROOT; new_ns->mounts = RB_ROOT;
@ -5006,6 +5006,40 @@ static int statmount_fs_type(struct kstatmount *s, struct seq_file *seq)
return 0; return 0;
} }
static void statmount_fs_subtype(struct kstatmount *s, struct seq_file *seq)
{
struct super_block *sb = s->mnt->mnt_sb;
if (sb->s_subtype)
seq_puts(seq, sb->s_subtype);
}
static int statmount_sb_source(struct kstatmount *s, struct seq_file *seq)
{
struct super_block *sb = s->mnt->mnt_sb;
struct mount *r = real_mount(s->mnt);
if (sb->s_op->show_devname) {
size_t start = seq->count;
int ret;
ret = sb->s_op->show_devname(seq, s->mnt->mnt_root);
if (ret)
return ret;
if (unlikely(seq_has_overflowed(seq)))
return -EAGAIN;
/* Unescape the result */
seq->buf[seq->count] = '\0';
seq->count = start;
seq_commit(seq, string_unescape_inplace(seq->buf + start, UNESCAPE_OCTAL));
} else if (r->mnt_devname) {
seq_puts(seq, r->mnt_devname);
}
return 0;
}
static void statmount_mnt_ns_id(struct kstatmount *s, struct mnt_namespace *ns) static void statmount_mnt_ns_id(struct kstatmount *s, struct mnt_namespace *ns)
{ {
s->sm.mask |= STATMOUNT_MNT_NS_ID; s->sm.mask |= STATMOUNT_MNT_NS_ID;
@ -5040,35 +5074,134 @@ static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
return 0; return 0;
} }
static inline int statmount_opt_unescape(struct seq_file *seq, char *buf_start)
{
char *buf_end, *opt_start, *opt_end;
int count = 0;
buf_end = seq->buf + seq->count;
*buf_end = '\0';
for (opt_start = buf_start + 1; opt_start < buf_end; opt_start = opt_end + 1) {
opt_end = strchrnul(opt_start, ',');
*opt_end = '\0';
buf_start += string_unescape(opt_start, buf_start, 0, UNESCAPE_OCTAL) + 1;
if (WARN_ON_ONCE(++count == INT_MAX))
return -EOVERFLOW;
}
seq->count = buf_start - 1 - seq->buf;
return count;
}
static int statmount_opt_array(struct kstatmount *s, struct seq_file *seq)
{
struct vfsmount *mnt = s->mnt;
struct super_block *sb = mnt->mnt_sb;
size_t start = seq->count;
char *buf_start;
int err;
if (!sb->s_op->show_options)
return 0;
buf_start = seq->buf + start;
err = sb->s_op->show_options(seq, mnt->mnt_root);
if (err)
return err;
if (unlikely(seq_has_overflowed(seq)))
return -EAGAIN;
if (seq->count == start)
return 0;
err = statmount_opt_unescape(seq, buf_start);
if (err < 0)
return err;
s->sm.opt_num = err;
return 0;
}
static int statmount_opt_sec_array(struct kstatmount *s, struct seq_file *seq)
{
struct vfsmount *mnt = s->mnt;
struct super_block *sb = mnt->mnt_sb;
size_t start = seq->count;
char *buf_start;
int err;
buf_start = seq->buf + start;
err = security_sb_show_options(seq, sb);
if (!err)
return err;
if (unlikely(seq_has_overflowed(seq)))
return -EAGAIN;
if (seq->count == start)
return 0;
err = statmount_opt_unescape(seq, buf_start);
if (err < 0)
return err;
s->sm.opt_sec_num = err;
return 0;
}
static int statmount_string(struct kstatmount *s, u64 flag) static int statmount_string(struct kstatmount *s, u64 flag)
{ {
int ret; int ret = 0;
size_t kbufsize; size_t kbufsize;
struct seq_file *seq = &s->seq; struct seq_file *seq = &s->seq;
struct statmount *sm = &s->sm; struct statmount *sm = &s->sm;
u32 start = seq->count;
switch (flag) { switch (flag) {
case STATMOUNT_FS_TYPE: case STATMOUNT_FS_TYPE:
sm->fs_type = seq->count; sm->fs_type = start;
ret = statmount_fs_type(s, seq); ret = statmount_fs_type(s, seq);
break; break;
case STATMOUNT_MNT_ROOT: case STATMOUNT_MNT_ROOT:
sm->mnt_root = seq->count; sm->mnt_root = start;
ret = statmount_mnt_root(s, seq); ret = statmount_mnt_root(s, seq);
break; break;
case STATMOUNT_MNT_POINT: case STATMOUNT_MNT_POINT:
sm->mnt_point = seq->count; sm->mnt_point = start;
ret = statmount_mnt_point(s, seq); ret = statmount_mnt_point(s, seq);
break; break;
case STATMOUNT_MNT_OPTS: case STATMOUNT_MNT_OPTS:
sm->mnt_opts = seq->count; sm->mnt_opts = start;
ret = statmount_mnt_opts(s, seq); ret = statmount_mnt_opts(s, seq);
break; break;
case STATMOUNT_OPT_ARRAY:
sm->opt_array = start;
ret = statmount_opt_array(s, seq);
break;
case STATMOUNT_OPT_SEC_ARRAY:
sm->opt_sec_array = start;
ret = statmount_opt_sec_array(s, seq);
break;
case STATMOUNT_FS_SUBTYPE:
sm->fs_subtype = start;
statmount_fs_subtype(s, seq);
break;
case STATMOUNT_SB_SOURCE:
sm->sb_source = start;
ret = statmount_sb_source(s, seq);
break;
default: default:
WARN_ON_ONCE(true); WARN_ON_ONCE(true);
return -EINVAL; return -EINVAL;
} }
/*
* If nothing was emitted, return to avoid setting the flag
* and terminating the buffer.
*/
if (seq->count == start)
return ret;
if (unlikely(check_add_overflow(sizeof(*sm), seq->count, &kbufsize))) if (unlikely(check_add_overflow(sizeof(*sm), seq->count, &kbufsize)))
return -EOVERFLOW; return -EOVERFLOW;
if (kbufsize >= s->bufsize) if (kbufsize >= s->bufsize)
@ -5203,6 +5336,18 @@ static int do_statmount(struct kstatmount *s, u64 mnt_id, u64 mnt_ns_id,
if (!err && s->mask & STATMOUNT_MNT_OPTS) if (!err && s->mask & STATMOUNT_MNT_OPTS)
err = statmount_string(s, STATMOUNT_MNT_OPTS); err = statmount_string(s, STATMOUNT_MNT_OPTS);
if (!err && s->mask & STATMOUNT_OPT_ARRAY)
err = statmount_string(s, STATMOUNT_OPT_ARRAY);
if (!err && s->mask & STATMOUNT_OPT_SEC_ARRAY)
err = statmount_string(s, STATMOUNT_OPT_SEC_ARRAY);
if (!err && s->mask & STATMOUNT_FS_SUBTYPE)
err = statmount_string(s, STATMOUNT_FS_SUBTYPE);
if (!err && s->mask & STATMOUNT_SB_SOURCE)
err = statmount_string(s, STATMOUNT_SB_SOURCE);
if (!err && s->mask & STATMOUNT_MNT_NS_ID) if (!err && s->mask & STATMOUNT_MNT_NS_ID)
statmount_mnt_ns_id(s, ns); statmount_mnt_ns_id(s, ns);
@ -5224,7 +5369,9 @@ static inline bool retry_statmount(const long ret, size_t *seq_size)
} }
#define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \ #define STATMOUNT_STRING_REQ (STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT | \
STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS) STATMOUNT_FS_TYPE | STATMOUNT_MNT_OPTS | \
STATMOUNT_FS_SUBTYPE | STATMOUNT_SB_SOURCE | \
STATMOUNT_OPT_ARRAY | STATMOUNT_OPT_SEC_ARRAY)
static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq, static int prepare_kstatmount(struct kstatmount *ks, struct mnt_id_req *kreq,
struct statmount __user *buf, size_t bufsize, struct statmount __user *buf, size_t bufsize,

View File

@ -8001,9 +8001,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
fp = lock_stp->st_stid.sc_file; fp = lock_stp->st_stid.sc_file;
switch (lock->lk_type) { switch (lock->lk_type) {
case NFS4_READW_LT: case NFS4_READW_LT:
if (nfsd4_has_session(cstate) ||
exportfs_lock_op_is_async(sb->s_export_op))
flags |= FL_SLEEP;
fallthrough; fallthrough;
case NFS4_READ_LT: case NFS4_READ_LT:
spin_lock(&fp->fi_lock); spin_lock(&fp->fi_lock);
@ -8014,9 +8011,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
type = F_RDLCK; type = F_RDLCK;
break; break;
case NFS4_WRITEW_LT: case NFS4_WRITEW_LT:
if (nfsd4_has_session(cstate) ||
exportfs_lock_op_is_async(sb->s_export_op))
flags |= FL_SLEEP;
fallthrough; fallthrough;
case NFS4_WRITE_LT: case NFS4_WRITE_LT:
spin_lock(&fp->fi_lock); spin_lock(&fp->fi_lock);
@ -8036,15 +8030,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out; goto out;
} }
/* if (lock->lk_type & (NFS4_READW_LT | NFS4_WRITEW_LT) &&
* Most filesystems with their own ->lock operations will block nfsd4_has_session(cstate) &&
* the nfsd thread waiting to acquire the lock. That leads to locks_can_async_lock(nf->nf_file->f_op))
* deadlocks (we don't want every nfsd thread tied up waiting flags |= FL_SLEEP;
* for file locks), so don't attempt blocking lock notifications
* on those filesystems:
*/
if (!exportfs_lock_op_is_async(sb->s_export_op))
flags &= ~FL_SLEEP;
nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn);
if (!nbl) { if (!nbl) {

View File

@ -280,5 +280,4 @@ const struct export_operations ocfs2_export_ops = {
.fh_to_dentry = ocfs2_fh_to_dentry, .fh_to_dentry = ocfs2_fh_to_dentry,
.fh_to_parent = ocfs2_fh_to_parent, .fh_to_parent = ocfs2_fh_to_parent,
.get_parent = ocfs2_get_parent, .get_parent = ocfs2_get_parent,
.flags = EXPORT_OP_ASYNC_LOCK,
}; };

View File

@ -2812,6 +2812,7 @@ const struct file_operations ocfs2_fops = {
.splice_write = iter_file_splice_write, .splice_write = iter_file_splice_write,
.fallocate = ocfs2_fallocate, .fallocate = ocfs2_fallocate,
.remap_file_range = ocfs2_remap_file_range, .remap_file_range = ocfs2_remap_file_range,
.fop_flags = FOP_ASYNC_LOCK,
}; };
WRAP_DIR_ITER(ocfs2_readdir) // FIXME! WRAP_DIR_ITER(ocfs2_readdir) // FIXME!
@ -2828,6 +2829,7 @@ const struct file_operations ocfs2_dops = {
#endif #endif
.lock = ocfs2_lock, .lock = ocfs2_lock,
.flock = ocfs2_flock, .flock = ocfs2_flock,
.fop_flags = FOP_ASYNC_LOCK,
}; };
/* /*

View File

@ -200,11 +200,11 @@ EXPORT_SYMBOL(posix_acl_init);
* Allocate a new ACL with the specified number of entries. * Allocate a new ACL with the specified number of entries.
*/ */
struct posix_acl * struct posix_acl *
posix_acl_alloc(int count, gfp_t flags) posix_acl_alloc(unsigned int count, gfp_t flags)
{ {
const size_t size = sizeof(struct posix_acl) + struct posix_acl *acl;
count * sizeof(struct posix_acl_entry);
struct posix_acl *acl = kmalloc(size, flags); acl = kmalloc(struct_size(acl, a_entries, count), flags);
if (acl) if (acl)
posix_acl_init(acl, count); posix_acl_init(acl, count);
return acl; return acl;
@ -220,9 +220,8 @@ posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
struct posix_acl *clone = NULL; struct posix_acl *clone = NULL;
if (acl) { if (acl) {
int size = sizeof(struct posix_acl) + acl->a_count * clone = kmemdup(acl, struct_size(acl, a_entries, acl->a_count),
sizeof(struct posix_acl_entry); flags);
clone = kmemdup(acl, size, flags);
if (clone) if (clone)
refcount_set(&clone->a_refcount, 1); refcount_set(&clone->a_refcount, 1);
} }

View File

@ -343,8 +343,8 @@ EXPORT_SYMBOL(seq_lseek);
/** /**
* seq_release - free the structures associated with sequential file. * seq_release - free the structures associated with sequential file.
* @file: file in question
* @inode: its inode * @inode: its inode
* @file: file in question
* *
* Frees the structures associated with sequential file; can be used * Frees the structures associated with sequential file; can be used
* as ->f_op->release() if you don't have private data to destroy. * as ->f_op->release() if you don't have private data to destroy.

View File

@ -42,7 +42,7 @@ static inline void eventpoll_release(struct file *file)
* because the file in on the way to be removed and nobody ( but * because the file in on the way to be removed and nobody ( but
* eventpoll ) has still a reference to this file. * eventpoll ) has still a reference to this file.
*/ */
if (likely(!file->f_ep)) if (likely(!READ_ONCE(file->f_ep)))
return; return;
/* /*

View File

@ -250,19 +250,6 @@ struct export_operations {
unsigned long flags; unsigned long flags;
}; };
/**
* exportfs_lock_op_is_async() - export op supports async lock operation
* @export_ops: the nfs export operations to check
*
* Returns true if the nfs export_operations structure has
* EXPORT_OP_ASYNC_LOCK in their flags set
*/
static inline bool
exportfs_lock_op_is_async(const struct export_operations *export_ops)
{
return export_ops->flags & EXPORT_OP_ASYNC_LOCK;
}
extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid, extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
int *max_len, struct inode *parent, int *max_len, struct inode *parent,
int flags); int flags);

View File

@ -180,6 +180,11 @@ static inline void locks_wake_up(struct file_lock *fl)
wake_up(&fl->c.flc_wait); wake_up(&fl->c.flc_wait);
} }
static inline bool locks_can_async_lock(const struct file_operations *fops)
{
return !fops->lock || fops->fop_flags & FOP_ASYNC_LOCK;
}
/* fs/locks.c */ /* fs/locks.c */
void locks_free_lock_context(struct inode *inode); void locks_free_lock_context(struct inode *inode);
void locks_free_lock(struct file_lock *fl); void locks_free_lock(struct file_lock *fl);

View File

@ -2124,6 +2124,8 @@ struct file_operations {
#define FOP_HUGE_PAGES ((__force fop_flags_t)(1 << 4)) #define FOP_HUGE_PAGES ((__force fop_flags_t)(1 << 4))
/* Treat loff_t as unsigned (e.g., /dev/mem) */ /* Treat loff_t as unsigned (e.g., /dev/mem) */
#define FOP_UNSIGNED_OFFSET ((__force fop_flags_t)(1 << 5)) #define FOP_UNSIGNED_OFFSET ((__force fop_flags_t)(1 << 5))
/* Supports asynchronous lock callbacks */
#define FOP_ASYNC_LOCK ((__force fop_flags_t)(1 << 6))
/* Wrap a directory iterator that needs exclusive inode access */ /* Wrap a directory iterator that needs exclusive inode access */
int wrap_directory_iterator(struct file *, struct dir_context *, int wrap_directory_iterator(struct file *, struct dir_context *,

View File

@ -28,9 +28,9 @@ struct posix_acl_entry {
struct posix_acl { struct posix_acl {
refcount_t a_refcount; refcount_t a_refcount;
struct rcu_head a_rcu;
unsigned int a_count; unsigned int a_count;
struct posix_acl_entry a_entries[]; struct rcu_head a_rcu;
struct posix_acl_entry a_entries[] __counted_by(a_count);
}; };
#define FOREACH_ACL_ENTRY(pa, acl, pe) \ #define FOREACH_ACL_ENTRY(pa, acl, pe) \
@ -62,7 +62,7 @@ posix_acl_release(struct posix_acl *acl)
/* posix_acl.c */ /* posix_acl.c */
extern void posix_acl_init(struct posix_acl *, int); extern void posix_acl_init(struct posix_acl *, int);
extern struct posix_acl *posix_acl_alloc(int, gfp_t); extern struct posix_acl *posix_acl_alloc(unsigned int count, gfp_t flags);
extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t);
extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *);
extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *); extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *);

View File

@ -221,6 +221,7 @@ void __wake_up_pollfree(struct wait_queue_head *wq_head);
#define wake_up_all(x) __wake_up(x, TASK_NORMAL, 0, NULL) #define wake_up_all(x) __wake_up(x, TASK_NORMAL, 0, NULL)
#define wake_up_locked(x) __wake_up_locked((x), TASK_NORMAL, 1) #define wake_up_locked(x) __wake_up_locked((x), TASK_NORMAL, 1)
#define wake_up_all_locked(x) __wake_up_locked((x), TASK_NORMAL, 0) #define wake_up_all_locked(x) __wake_up_locked((x), TASK_NORMAL, 0)
#define wake_up_sync(x) __wake_up_sync(x, TASK_NORMAL)
#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL) #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
#define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL) #define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)

View File

@ -213,11 +213,8 @@ static inline void wait_on_inode(struct inode *inode)
#include <linux/bio.h> #include <linux/bio.h>
void __inode_attach_wb(struct inode *inode, struct folio *folio); void __inode_attach_wb(struct inode *inode, struct folio *folio);
void wbc_attach_and_unlock_inode(struct writeback_control *wbc,
struct inode *inode)
__releases(&inode->i_lock);
void wbc_detach_inode(struct writeback_control *wbc); void wbc_detach_inode(struct writeback_control *wbc);
void wbc_account_cgroup_owner(struct writeback_control *wbc, struct page *page, void wbc_account_cgroup_owner(struct writeback_control *wbc, struct folio *folio,
size_t bytes); size_t bytes);
int cgroup_writeback_by_id(u64 bdi_id, int memcg_id, int cgroup_writeback_by_id(u64 bdi_id, int memcg_id,
enum wb_reason reason, struct wb_completion *done); enum wb_reason reason, struct wb_completion *done);
@ -254,22 +251,8 @@ static inline void inode_detach_wb(struct inode *inode)
} }
} }
/** void wbc_attach_fdatawrite_inode(struct writeback_control *wbc,
* wbc_attach_fdatawrite_inode - associate wbc and inode for fdatawrite struct inode *inode);
* @wbc: writeback_control of interest
* @inode: target inode
*
* This function is to be used by __filemap_fdatawrite_range(), which is an
* alternative entry point into writeback code, and first ensures @inode is
* associated with a bdi_writeback and attaches it to @wbc.
*/
static inline void wbc_attach_fdatawrite_inode(struct writeback_control *wbc,
struct inode *inode)
{
spin_lock(&inode->i_lock);
inode_attach_wb(inode, NULL);
wbc_attach_and_unlock_inode(wbc, inode);
}
/** /**
* wbc_init_bio - writeback specific initializtion of bio * wbc_init_bio - writeback specific initializtion of bio
@ -303,13 +286,6 @@ static inline void inode_detach_wb(struct inode *inode)
{ {
} }
static inline void wbc_attach_and_unlock_inode(struct writeback_control *wbc,
struct inode *inode)
__releases(&inode->i_lock)
{
spin_unlock(&inode->i_lock);
}
static inline void wbc_attach_fdatawrite_inode(struct writeback_control *wbc, static inline void wbc_attach_fdatawrite_inode(struct writeback_control *wbc,
struct inode *inode) struct inode *inode)
{ {
@ -324,7 +300,7 @@ static inline void wbc_init_bio(struct writeback_control *wbc, struct bio *bio)
} }
static inline void wbc_account_cgroup_owner(struct writeback_control *wbc, static inline void wbc_account_cgroup_owner(struct writeback_control *wbc,
struct page *page, size_t bytes) struct folio *folio, size_t bytes)
{ {
} }

View File

@ -0,0 +1,156 @@
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM hugetlbfs
#if !defined(_TRACE_HUGETLBFS_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HUGETLBFS_H
#include <linux/tracepoint.h>
TRACE_EVENT(hugetlbfs_alloc_inode,
TP_PROTO(struct inode *inode, struct inode *dir, int mode),
TP_ARGS(inode, dir, mode),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(ino_t, dir)
__field(__u16, mode)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->dir = dir->i_ino;
__entry->mode = mode;
),
TP_printk("dev %d,%d ino %lu dir %lu mode 0%o",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long) __entry->ino,
(unsigned long) __entry->dir, __entry->mode)
);
DECLARE_EVENT_CLASS(hugetlbfs__inode,
TP_PROTO(struct inode *inode),
TP_ARGS(inode),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(__u16, mode)
__field(loff_t, size)
__field(unsigned int, nlink)
__field(unsigned int, seals)
__field(blkcnt_t, blocks)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
__entry->size = inode->i_size;
__entry->nlink = inode->i_nlink;
__entry->seals = HUGETLBFS_I(inode)->seals;
__entry->blocks = inode->i_blocks;
),
TP_printk("dev %d,%d ino %lu mode 0%o size %lld nlink %u seals %u blocks %llu",
MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long) __entry->ino,
__entry->mode, __entry->size, __entry->nlink, __entry->seals,
(unsigned long long)__entry->blocks)
);
DEFINE_EVENT(hugetlbfs__inode, hugetlbfs_evict_inode,
TP_PROTO(struct inode *inode),
TP_ARGS(inode)
);
DEFINE_EVENT(hugetlbfs__inode, hugetlbfs_free_inode,
TP_PROTO(struct inode *inode),
TP_ARGS(inode)
);
TRACE_EVENT(hugetlbfs_setattr,
TP_PROTO(struct inode *inode, struct dentry *dentry,
struct iattr *attr),
TP_ARGS(inode, dentry, attr),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(unsigned int, d_len)
__string(d_name, dentry->d_name.name)
__field(unsigned int, ia_valid)
__field(unsigned int, ia_mode)
__field(loff_t, old_size)
__field(loff_t, ia_size)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->d_len = dentry->d_name.len;
__assign_str(d_name);
__entry->ia_valid = attr->ia_valid;
__entry->ia_mode = attr->ia_mode;
__entry->old_size = inode->i_size;
__entry->ia_size = attr->ia_size;
),
TP_printk("dev %d,%d ino %lu name %.*s valid %#x mode 0%o old_size %lld size %lld",
MAJOR(__entry->dev), MINOR(__entry->dev), (unsigned long)__entry->ino,
__entry->d_len, __get_str(d_name), __entry->ia_valid, __entry->ia_mode,
__entry->old_size, __entry->ia_size)
);
TRACE_EVENT(hugetlbfs_fallocate,
TP_PROTO(struct inode *inode, int mode,
loff_t offset, loff_t len, int ret),
TP_ARGS(inode, mode, offset, len, ret),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(ino_t, ino)
__field(int, mode)
__field(loff_t, offset)
__field(loff_t, len)
__field(loff_t, size)
__field(int, ret)
),
TP_fast_assign(
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->mode = mode;
__entry->offset = offset;
__entry->len = len;
__entry->size = inode->i_size;
__entry->ret = ret;
),
TP_printk("dev %d,%d ino %lu mode 0%o offset %lld len %lld size %lld ret %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long)__entry->ino, __entry->mode,
(unsigned long long)__entry->offset,
(unsigned long long)__entry->len,
(unsigned long long)__entry->size,
__entry->ret)
);
#endif /* _TRACE_HUGETLBFS_H */
/* This part must be outside protection */
#include <trace/define_trace.h>

View File

@ -154,7 +154,7 @@ struct mount_attr {
*/ */
struct statmount { struct statmount {
__u32 size; /* Total size, including strings */ __u32 size; /* Total size, including strings */
__u32 mnt_opts; /* [str] Mount options of the mount */ __u32 mnt_opts; /* [str] Options (comma separated, escaped) */
__u64 mask; /* What results were written */ __u64 mask; /* What results were written */
__u32 sb_dev_major; /* Device ID */ __u32 sb_dev_major; /* Device ID */
__u32 sb_dev_minor; __u32 sb_dev_minor;
@ -173,7 +173,13 @@ struct statmount {
__u32 mnt_root; /* [str] Root of mount relative to root of fs */ __u32 mnt_root; /* [str] Root of mount relative to root of fs */
__u32 mnt_point; /* [str] Mountpoint relative to current root */ __u32 mnt_point; /* [str] Mountpoint relative to current root */
__u64 mnt_ns_id; /* ID of the mount namespace */ __u64 mnt_ns_id; /* ID of the mount namespace */
__u64 __spare2[49]; __u32 fs_subtype; /* [str] Subtype of fs_type (if any) */
__u32 sb_source; /* [str] Source string of the mount */
__u32 opt_num; /* Number of fs options */
__u32 opt_array; /* [str] Array of nul terminated fs options */
__u32 opt_sec_num; /* Number of security options */
__u32 opt_sec_array; /* [str] Array of nul terminated security options */
__u64 __spare2[46];
char str[]; /* Variable size part containing strings */ char str[]; /* Variable size part containing strings */
}; };
@ -207,6 +213,10 @@ struct mnt_id_req {
#define STATMOUNT_FS_TYPE 0x00000020U /* Want/got fs_type */ #define STATMOUNT_FS_TYPE 0x00000020U /* Want/got fs_type */
#define STATMOUNT_MNT_NS_ID 0x00000040U /* Want/got mnt_ns_id */ #define STATMOUNT_MNT_NS_ID 0x00000040U /* Want/got mnt_ns_id */
#define STATMOUNT_MNT_OPTS 0x00000080U /* Want/got mnt_opts */ #define STATMOUNT_MNT_OPTS 0x00000080U /* Want/got mnt_opts */
#define STATMOUNT_FS_SUBTYPE 0x00000100U /* Want/got fs_subtype */
#define STATMOUNT_SB_SOURCE 0x00000200U /* Want/got sb_source */
#define STATMOUNT_OPT_ARRAY 0x00000400U /* Want/got opt_... */
#define STATMOUNT_OPT_SEC_ARRAY 0x00000800U /* Want/got opt_sec... */
/* /*
* Special @mnt_id values that can be passed to listmount * Special @mnt_id values that can be passed to listmount

View File

@ -360,6 +360,15 @@ static int __init do_name(void)
{ {
state = SkipIt; state = SkipIt;
next_state = Reset; next_state = Reset;
/* name_len > 0 && name_len <= PATH_MAX checked in do_header */
if (collected[name_len - 1] != '\0') {
pr_err("initramfs name without nulterm: %.*s\n",
(int)name_len, collected);
error("malformed archive");
return 1;
}
if (strcmp(collected, "TRAILER!!!") == 0) { if (strcmp(collected, "TRAILER!!!") == 0) {
free_hash(); free_hash();
return 0; return 0;
@ -424,6 +433,12 @@ static int __init do_copy(void)
static int __init do_symlink(void) static int __init do_symlink(void)
{ {
if (collected[name_len - 1] != '\0') {
pr_err("initramfs symlink without nulterm: %.*s\n",
(int)name_len, collected);
error("malformed archive");
return 1;
}
collected[N_ALIGN(name_len) + body_len] = '\0'; collected[N_ALIGN(name_len) + body_len] = '\0';
clean_path(collected, 0); clean_path(collected, 0);
init_symlink(collected + N_ALIGN(name_len), collected); init_symlink(collected + N_ALIGN(name_len), collected);

View File

@ -2620,6 +2620,8 @@ ssize_t filemap_read(struct kiocb *iocb, struct iov_iter *iter,
loff_t isize, end_offset; loff_t isize, end_offset;
loff_t last_pos = ra->prev_pos; loff_t last_pos = ra->prev_pos;
if (unlikely(iocb->ki_pos < 0))
return -EINVAL;
if (unlikely(iocb->ki_pos >= inode->i_sb->s_maxbytes)) if (unlikely(iocb->ki_pos >= inode->i_sb->s_maxbytes))
return 0; return 0;
if (unlikely(!iov_iter_count(iter))) if (unlikely(!iov_iter_count(iter)))

View File

@ -54,7 +54,7 @@
#define DIRTY_POLL_THRESH (128 >> (PAGE_SHIFT - 10)) #define DIRTY_POLL_THRESH (128 >> (PAGE_SHIFT - 10))
/* /*
* Estimate write bandwidth at 200ms intervals. * Estimate write bandwidth or update dirty limit at 200ms intervals.
*/ */
#define BANDWIDTH_INTERVAL max(HZ/5, 1) #define BANDWIDTH_INTERVAL max(HZ/5, 1)
@ -586,7 +586,7 @@ static void wb_domain_writeout_add(struct wb_domain *dom,
/* First event after period switching was turned off? */ /* First event after period switching was turned off? */
if (unlikely(!dom->period_time)) { if (unlikely(!dom->period_time)) {
/* /*
* We can race with other __bdi_writeout_inc calls here but * We can race with other wb_domain_writeout_add calls here but
* it does not cause any harm since the resulting time when * it does not cause any harm since the resulting time when
* timer will fire and what is in writeout_period_time will be * timer will fire and what is in writeout_period_time will be
* roughly the same. * roughly the same.