v6.6-vfs.misc
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCZOXTxQAKCRCRxhvAZXjc okaVAP94WAlItvDRt/z2Wtzf0+RqPZeTXEdGTxua8+RxqCyYIQD+OO5nRfKQPHlV AqqGJMKItQMSMIYgB5ftqVhNWZfnHgM= =pSEW -----END PGP SIGNATURE----- Merge tag 'v6.6-vfs.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull misc vfs updates from Christian Brauner: "This contains the usual miscellaneous features, cleanups, and fixes for vfs and individual filesystems. Features: - Block mode changes on symlinks and rectify our broken semantics - Report file modifications via fsnotify() for splice - Allow specifying an explicit timeout for the "rootwait" kernel command line option. This allows to timeout and reboot instead of always waiting indefinitely for the root device to show up - Use synchronous fput for the close system call Cleanups: - Get rid of open-coded lockdep workarounds for async io submitters and replace it all with a single consolidated helper - Simplify epoll allocation helper - Convert simple_write_begin and simple_write_end to use a folio - Convert page_cache_pipe_buf_confirm() to use a folio - Simplify __range_close to avoid pointless locking - Disable per-cpu buffer head cache for isolated cpus - Port ecryptfs to kmap_local_page() api - Remove redundant initialization of pointer buf in pipe code - Unexport the d_genocide() function which is only used within core vfs - Replace printk(KERN_ERR) and WARN_ON() with WARN() Fixes: - Fix various kernel-doc issues - Fix refcount underflow for eventfds when used as EFD_SEMAPHORE - Fix a mainly theoretical issue in devpts - Check the return value of __getblk() in reiserfs - Fix a racy assert in i_readcount_dec - Fix integer conversion issues in various functions - Fix LSM security context handling during automounts that prevented NFS superblock sharing" * tag 'v6.6-vfs.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (39 commits) cachefiles: use kiocb_{start,end}_write() helpers ovl: use kiocb_{start,end}_write() helpers aio: use kiocb_{start,end}_write() helpers io_uring: use kiocb_{start,end}_write() helpers fs: create kiocb_{start,end}_write() helpers fs: add kerneldoc to file_{start,end}_write() helpers io_uring: rename kiocb_end_write() local helper splice: Convert page_cache_pipe_buf_confirm() to use a folio libfs: Convert simple_write_begin and simple_write_end to use a folio fs/dcache: Replace printk and WARN_ON by WARN fs/pipe: remove redundant initialization of pointer buf fs: Fix kernel-doc warnings devpts: Fix kernel-doc warnings doc: idmappings: fix an error and rephrase a paragraph init: Add support for rootwait timeout parameter vfs: fix up the assert in i_readcount_dec fs: Fix one kernel-doc comment docs: filesystems: idmappings: clarify from where idmappings are taken fs/buffer.c: disable per-CPU buffer_head cache for isolated CPUs vfs, security: Fix automount superblock LSM init problem, preventing NFS sb sharing ...
This commit is contained in:
commit
de16588a77
@ -5522,6 +5522,10 @@
|
||||
Useful for devices that are detected asynchronously
|
||||
(e.g. USB and MMC devices).
|
||||
|
||||
rootwait= [KNL] Maximum time (in seconds) to wait for root device
|
||||
to show up before attempting to mount the root
|
||||
filesystem.
|
||||
|
||||
rproc_mem=nn[KMG][@address]
|
||||
[KNL,ARM,CMA] Remoteproc physical memory block.
|
||||
Memory area to be used by remote processor image,
|
||||
|
@ -146,9 +146,10 @@ For the rest of this document we will prefix all userspace ids with ``u`` and
|
||||
all kernel ids with ``k``. Ranges of idmappings will be prefixed with ``r``. So
|
||||
an idmapping will be written as ``u0:k10000:r10000``.
|
||||
|
||||
For example, the id ``u1000`` is an id in the upper idmapset or "userspace
|
||||
idmapset" starting with ``u1000``. And it is mapped to ``k11000`` which is a
|
||||
kernel id in the lower idmapset or "kernel idmapset" starting with ``k10000``.
|
||||
For example, within this idmapping, the id ``u1000`` is an id in the upper
|
||||
idmapset or "userspace idmapset" starting with ``u0``. And it is mapped to
|
||||
``k11000`` which is a kernel id in the lower idmapset or "kernel idmapset"
|
||||
starting with ``k10000``.
|
||||
|
||||
A kernel id is always created by an idmapping. Such idmappings are associated
|
||||
with user namespaces. Since we mainly care about how idmappings work we're not
|
||||
@ -373,6 +374,13 @@ kernel maps the caller's userspace id down into a kernel id according to the
|
||||
caller's idmapping and then maps that kernel id up according to the
|
||||
filesystem's idmapping.
|
||||
|
||||
From the implementation point it's worth mentioning how idmappings are represented.
|
||||
All idmappings are taken from the corresponding user namespace.
|
||||
|
||||
- caller's idmapping (usually taken from ``current_user_ns()``)
|
||||
- filesystem's idmapping (``sb->s_user_ns``)
|
||||
- mount's idmapping (``mnt_idmap(vfsmnt)``)
|
||||
|
||||
Let's see some examples with caller/filesystem idmapping but without mount
|
||||
idmappings. This will exhibit some problems we can hit. After that we will
|
||||
revisit/reconsider these examples, this time using mount idmappings, to see how
|
||||
|
20
fs/aio.c
20
fs/aio.c
@ -1447,13 +1447,8 @@ static void aio_complete_rw(struct kiocb *kiocb, long res)
|
||||
if (kiocb->ki_flags & IOCB_WRITE) {
|
||||
struct inode *inode = file_inode(kiocb->ki_filp);
|
||||
|
||||
/*
|
||||
* Tell lockdep we inherited freeze protection from submission
|
||||
* thread.
|
||||
*/
|
||||
if (S_ISREG(inode->i_mode))
|
||||
__sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE);
|
||||
file_end_write(kiocb->ki_filp);
|
||||
kiocb_end_write(kiocb);
|
||||
}
|
||||
|
||||
iocb->ki_res.res = res;
|
||||
@ -1581,17 +1576,8 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb,
|
||||
return ret;
|
||||
ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
|
||||
if (!ret) {
|
||||
/*
|
||||
* Open-code file_start_write here to grab freeze protection,
|
||||
* which will be released by another thread in
|
||||
* aio_complete_rw(). Fool lockdep by telling it the lock got
|
||||
* released so that it doesn't complain about the held lock when
|
||||
* we return to userspace.
|
||||
*/
|
||||
if (S_ISREG(file_inode(file)->i_mode)) {
|
||||
sb_start_write(file_inode(file)->i_sb);
|
||||
__sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
|
||||
}
|
||||
if (S_ISREG(file_inode(file)->i_mode))
|
||||
kiocb_start_write(req);
|
||||
req->ki_flags |= IOCB_WRITE;
|
||||
aio_rw_done(req, call_write_iter(file, req, &iter));
|
||||
}
|
||||
|
20
fs/attr.c
20
fs/attr.c
@ -394,9 +394,25 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
return error;
|
||||
|
||||
if ((ia_valid & ATTR_MODE)) {
|
||||
umode_t amode = attr->ia_mode;
|
||||
/*
|
||||
* Don't allow changing the mode of symlinks:
|
||||
*
|
||||
* (1) The vfs doesn't take the mode of symlinks into account
|
||||
* during permission checking.
|
||||
* (2) This has never worked correctly. Most major filesystems
|
||||
* did return EOPNOTSUPP due to interactions with POSIX ACLs
|
||||
* but did still updated the mode of the symlink.
|
||||
* This inconsistency led system call wrapper providers such
|
||||
* as libc to block changing the mode of symlinks with
|
||||
* EOPNOTSUPP already.
|
||||
* (3) To even do this in the first place one would have to use
|
||||
* specific file descriptors and quite some effort.
|
||||
*/
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Flag setting protected by i_mutex */
|
||||
if (is_sxid(amode))
|
||||
if (is_sxid(attr->ia_mode))
|
||||
inode->i_flags &= ~S_NOSEC;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include <trace/events/block.h>
|
||||
#include <linux/fscrypt.h>
|
||||
#include <linux/fsverity.h>
|
||||
#include <linux/sched/isolation.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@ -1352,7 +1353,7 @@ static void bh_lru_install(struct buffer_head *bh)
|
||||
* failing page migration.
|
||||
* Skip putting upcoming bh into bh_lru until migration is done.
|
||||
*/
|
||||
if (lru_cache_disabled()) {
|
||||
if (lru_cache_disabled() || cpu_is_isolated(smp_processor_id())) {
|
||||
bh_lru_unlock();
|
||||
return;
|
||||
}
|
||||
@ -1382,6 +1383,10 @@ lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size)
|
||||
|
||||
check_irqs_on();
|
||||
bh_lru_lock();
|
||||
if (cpu_is_isolated(smp_processor_id())) {
|
||||
bh_lru_unlock();
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < BH_LRU_SIZE; i++) {
|
||||
struct buffer_head *bh = __this_cpu_read(bh_lrus.bhs[i]);
|
||||
|
||||
|
@ -259,9 +259,7 @@ static void cachefiles_write_complete(struct kiocb *iocb, long ret)
|
||||
|
||||
_enter("%ld", ret);
|
||||
|
||||
/* Tell lockdep we inherited freeze protection from submission thread */
|
||||
__sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE);
|
||||
__sb_end_write(inode->i_sb, SB_FREEZE_WRITE);
|
||||
kiocb_end_write(iocb);
|
||||
|
||||
if (ret < 0)
|
||||
trace_cachefiles_io_error(object, inode, ret,
|
||||
@ -286,7 +284,6 @@ int __cachefiles_write(struct cachefiles_object *object,
|
||||
{
|
||||
struct cachefiles_cache *cache;
|
||||
struct cachefiles_kiocb *ki;
|
||||
struct inode *inode;
|
||||
unsigned int old_nofs;
|
||||
ssize_t ret;
|
||||
size_t len = iov_iter_count(iter);
|
||||
@ -322,19 +319,12 @@ int __cachefiles_write(struct cachefiles_object *object,
|
||||
ki->iocb.ki_complete = cachefiles_write_complete;
|
||||
atomic_long_add(ki->b_writing, &cache->b_writing);
|
||||
|
||||
/* Open-code file_start_write here to grab freeze protection, which
|
||||
* will be released by another thread in aio_complete_rw(). Fool
|
||||
* lockdep by telling it the lock got released so that it doesn't
|
||||
* complain about the held lock when we return to userspace.
|
||||
*/
|
||||
inode = file_inode(file);
|
||||
__sb_start_write(inode->i_sb, SB_FREEZE_WRITE);
|
||||
__sb_writers_release(inode->i_sb, SB_FREEZE_WRITE);
|
||||
kiocb_start_write(&ki->iocb);
|
||||
|
||||
get_file(ki->iocb.ki_filp);
|
||||
cachefiles_grab_object(object, cachefiles_obj_get_ioreq);
|
||||
|
||||
trace_cachefiles_write(object, inode, ki->iocb.ki_pos, len);
|
||||
trace_cachefiles_write(object, file_inode(file), ki->iocb.ki_pos, len);
|
||||
old_nofs = memalloc_nofs_save();
|
||||
ret = cachefiles_inject_write_error();
|
||||
if (ret == 0)
|
||||
|
@ -1664,7 +1664,7 @@ static enum d_walk_ret umount_check(void *_data, struct dentry *dentry)
|
||||
if (dentry == _data && dentry->d_lockref.count == 1)
|
||||
return D_WALK_CONTINUE;
|
||||
|
||||
printk(KERN_ERR "BUG: Dentry %p{i=%lx,n=%pd} "
|
||||
WARN(1, "BUG: Dentry %p{i=%lx,n=%pd} "
|
||||
" still in use (%d) [unmount of %s %s]\n",
|
||||
dentry,
|
||||
dentry->d_inode ?
|
||||
@ -1673,7 +1673,6 @@ static enum d_walk_ret umount_check(void *_data, struct dentry *dentry)
|
||||
dentry->d_lockref.count,
|
||||
dentry->d_sb->s_type->name,
|
||||
dentry->d_sb->s_id);
|
||||
WARN_ON(1);
|
||||
return D_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
@ -3247,8 +3246,6 @@ void d_genocide(struct dentry *parent)
|
||||
d_walk(parent, parent, d_genocide_kill);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(d_genocide);
|
||||
|
||||
void d_tmpfile(struct file *file, struct inode *inode)
|
||||
{
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
|
@ -534,12 +534,12 @@ void devpts_kill_index(struct pts_fs_info *fsi, int idx)
|
||||
|
||||
/**
|
||||
* devpts_pty_new -- create a new inode in /dev/pts/
|
||||
* @ptmx_inode: inode of the master
|
||||
* @device: major+minor of the node to be created
|
||||
* @fsi: Filesystem info for this instance.
|
||||
* @index: used as a name of the node
|
||||
* @priv: what's given back by devpts_get_priv
|
||||
*
|
||||
* The created inode is returned. Remove it from /dev/pts/ by devpts_pty_kill.
|
||||
* The dentry for the created inode is returned.
|
||||
* Remove it from /dev/pts/ with devpts_pty_kill().
|
||||
*/
|
||||
struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv)
|
||||
{
|
||||
@ -580,7 +580,7 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv)
|
||||
|
||||
/**
|
||||
* devpts_get_priv -- get private data for a slave
|
||||
* @pts_inode: inode of the slave
|
||||
* @dentry: dentry of the slave
|
||||
*
|
||||
* Returns whatever was passed as priv in devpts_pty_new for a given inode.
|
||||
*/
|
||||
@ -593,7 +593,7 @@ void *devpts_get_priv(struct dentry *dentry)
|
||||
|
||||
/**
|
||||
* devpts_pty_kill -- remove inode form /dev/pts/
|
||||
* @inode: inode of the slave to be removed
|
||||
* @dentry: dentry of the slave to be removed
|
||||
*
|
||||
* This is an inverse operation of devpts_pty_new.
|
||||
*/
|
||||
|
@ -441,10 +441,10 @@ int ecryptfs_encrypt_page(struct page *page)
|
||||
}
|
||||
|
||||
lower_offset = lower_offset_for_page(crypt_stat, page);
|
||||
enc_extent_virt = kmap(enc_extent_page);
|
||||
enc_extent_virt = kmap_local_page(enc_extent_page);
|
||||
rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt, lower_offset,
|
||||
PAGE_SIZE);
|
||||
kunmap(enc_extent_page);
|
||||
kunmap_local(enc_extent_virt);
|
||||
if (rc < 0) {
|
||||
ecryptfs_printk(KERN_ERR,
|
||||
"Error attempting to write lower page; rc = [%d]\n",
|
||||
@ -490,10 +490,10 @@ int ecryptfs_decrypt_page(struct page *page)
|
||||
BUG_ON(!(crypt_stat->flags & ECRYPTFS_ENCRYPTED));
|
||||
|
||||
lower_offset = lower_offset_for_page(crypt_stat, page);
|
||||
page_virt = kmap(page);
|
||||
page_virt = kmap_local_page(page);
|
||||
rc = ecryptfs_read_lower(page_virt, lower_offset, PAGE_SIZE,
|
||||
ecryptfs_inode);
|
||||
kunmap(page);
|
||||
kunmap_local(page_virt);
|
||||
if (rc < 0) {
|
||||
ecryptfs_printk(KERN_ERR,
|
||||
"Error attempting to read lower page; rc = [%d]\n",
|
||||
|
@ -125,7 +125,7 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
|
||||
/* This is a header extent */
|
||||
char *page_virt;
|
||||
|
||||
page_virt = kmap_atomic(page);
|
||||
page_virt = kmap_local_page(page);
|
||||
memset(page_virt, 0, PAGE_SIZE);
|
||||
/* TODO: Support more than one header extent */
|
||||
if (view_extent_num == 0) {
|
||||
@ -138,7 +138,7 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
|
||||
crypt_stat,
|
||||
&written);
|
||||
}
|
||||
kunmap_atomic(page_virt);
|
||||
kunmap_local(page_virt);
|
||||
flush_dcache_page(page);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "%s: Error reading xattr "
|
||||
@ -255,7 +255,6 @@ out:
|
||||
* @mapping: The eCryptfs object
|
||||
* @pos: The file offset at which to start writing
|
||||
* @len: Length of the write
|
||||
* @flags: Various flags
|
||||
* @pagep: Pointer to return the page
|
||||
* @fsdata: Pointer to return fs data (unused)
|
||||
*
|
||||
|
@ -64,11 +64,11 @@ int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
|
||||
|
||||
offset = ((((loff_t)page_for_lower->index) << PAGE_SHIFT)
|
||||
+ offset_in_page);
|
||||
virt = kmap(page_for_lower);
|
||||
virt = kmap_local_page(page_for_lower);
|
||||
rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
|
||||
if (rc > 0)
|
||||
rc = 0;
|
||||
kunmap(page_for_lower);
|
||||
kunmap_local(virt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset,
|
||||
ecryptfs_page_idx, rc);
|
||||
goto out;
|
||||
}
|
||||
ecryptfs_page_virt = kmap_atomic(ecryptfs_page);
|
||||
ecryptfs_page_virt = kmap_local_page(ecryptfs_page);
|
||||
|
||||
/*
|
||||
* pos: where we're now writing, offset: where the request was
|
||||
@ -163,7 +163,7 @@ int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset,
|
||||
(data + data_offset), num_bytes);
|
||||
data_offset += num_bytes;
|
||||
}
|
||||
kunmap_atomic(ecryptfs_page_virt);
|
||||
kunmap_local(ecryptfs_page_virt);
|
||||
flush_dcache_page(ecryptfs_page);
|
||||
SetPageUptodate(ecryptfs_page);
|
||||
unlock_page(ecryptfs_page);
|
||||
@ -253,11 +253,11 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
|
||||
int rc;
|
||||
|
||||
offset = ((((loff_t)page_index) << PAGE_SHIFT) + offset_in_page);
|
||||
virt = kmap(page_for_ecryptfs);
|
||||
virt = kmap_local_page(page_for_ecryptfs);
|
||||
rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);
|
||||
if (rc > 0)
|
||||
rc = 0;
|
||||
kunmap(page_for_ecryptfs);
|
||||
kunmap_local(virt);
|
||||
flush_dcache_page(page_for_ecryptfs);
|
||||
return rc;
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt)
|
||||
{
|
||||
lockdep_assert_held(&ctx->wqh.lock);
|
||||
|
||||
*cnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count;
|
||||
*cnt = ((ctx->flags & EFD_SEMAPHORE) && ctx->count) ? 1 : ctx->count;
|
||||
ctx->count -= *cnt;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(eventfd_ctx_do_read);
|
||||
|
@ -975,15 +975,11 @@ again:
|
||||
|
||||
static int ep_alloc(struct eventpoll **pep)
|
||||
{
|
||||
int error;
|
||||
struct user_struct *user;
|
||||
struct eventpoll *ep;
|
||||
|
||||
user = get_current_user();
|
||||
error = -ENOMEM;
|
||||
ep = kzalloc(sizeof(*ep), GFP_KERNEL);
|
||||
if (unlikely(!ep))
|
||||
goto free_uid;
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ep->mtx);
|
||||
rwlock_init(&ep->lock);
|
||||
@ -992,16 +988,12 @@ static int ep_alloc(struct eventpoll **pep)
|
||||
INIT_LIST_HEAD(&ep->rdllist);
|
||||
ep->rbr = RB_ROOT_CACHED;
|
||||
ep->ovflist = EP_UNACTIVE_PTR;
|
||||
ep->user = user;
|
||||
ep->user = get_current_user();
|
||||
refcount_set(&ep->refcount, 1);
|
||||
|
||||
*pep = ep;
|
||||
|
||||
return 0;
|
||||
|
||||
free_uid:
|
||||
free_uid(user);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
29
fs/fcntl.c
29
fs/fcntl.c
@ -34,7 +34,7 @@
|
||||
|
||||
#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
|
||||
|
||||
static int setfl(int fd, struct file * filp, unsigned long arg)
|
||||
static int setfl(int fd, struct file * filp, unsigned int arg)
|
||||
{
|
||||
struct inode * inode = file_inode(filp);
|
||||
int error = 0;
|
||||
@ -112,11 +112,11 @@ void __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
|
||||
}
|
||||
EXPORT_SYMBOL(__f_setown);
|
||||
|
||||
int f_setown(struct file *filp, unsigned long arg, int force)
|
||||
int f_setown(struct file *filp, int who, int force)
|
||||
{
|
||||
enum pid_type type;
|
||||
struct pid *pid = NULL;
|
||||
int who = arg, ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
type = PIDTYPE_TGID;
|
||||
if (who < 0) {
|
||||
@ -317,28 +317,29 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
||||
struct file *filp)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
int argi = (int)arg;
|
||||
struct flock flock;
|
||||
long err = -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case F_DUPFD:
|
||||
err = f_dupfd(arg, filp, 0);
|
||||
err = f_dupfd(argi, filp, 0);
|
||||
break;
|
||||
case F_DUPFD_CLOEXEC:
|
||||
err = f_dupfd(arg, filp, O_CLOEXEC);
|
||||
err = f_dupfd(argi, filp, O_CLOEXEC);
|
||||
break;
|
||||
case F_GETFD:
|
||||
err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
|
||||
break;
|
||||
case F_SETFD:
|
||||
err = 0;
|
||||
set_close_on_exec(fd, arg & FD_CLOEXEC);
|
||||
set_close_on_exec(fd, argi & FD_CLOEXEC);
|
||||
break;
|
||||
case F_GETFL:
|
||||
err = filp->f_flags;
|
||||
break;
|
||||
case F_SETFL:
|
||||
err = setfl(fd, filp, arg);
|
||||
err = setfl(fd, filp, argi);
|
||||
break;
|
||||
#if BITS_PER_LONG != 32
|
||||
/* 32-bit arches must use fcntl64() */
|
||||
@ -375,7 +376,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
||||
force_successful_syscall_return();
|
||||
break;
|
||||
case F_SETOWN:
|
||||
err = f_setown(filp, arg, 1);
|
||||
err = f_setown(filp, argi, 1);
|
||||
break;
|
||||
case F_GETOWN_EX:
|
||||
err = f_getown_ex(filp, arg);
|
||||
@ -391,28 +392,28 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
||||
break;
|
||||
case F_SETSIG:
|
||||
/* arg == 0 restores default behaviour. */
|
||||
if (!valid_signal(arg)) {
|
||||
if (!valid_signal(argi)) {
|
||||
break;
|
||||
}
|
||||
err = 0;
|
||||
filp->f_owner.signum = arg;
|
||||
filp->f_owner.signum = argi;
|
||||
break;
|
||||
case F_GETLEASE:
|
||||
err = fcntl_getlease(filp);
|
||||
break;
|
||||
case F_SETLEASE:
|
||||
err = fcntl_setlease(fd, filp, arg);
|
||||
err = fcntl_setlease(fd, filp, argi);
|
||||
break;
|
||||
case F_NOTIFY:
|
||||
err = fcntl_dirnotify(fd, filp, arg);
|
||||
err = fcntl_dirnotify(fd, filp, argi);
|
||||
break;
|
||||
case F_SETPIPE_SZ:
|
||||
case F_GETPIPE_SZ:
|
||||
err = pipe_fcntl(filp, cmd, arg);
|
||||
err = pipe_fcntl(filp, cmd, argi);
|
||||
break;
|
||||
case F_ADD_SEALS:
|
||||
case F_GET_SEALS:
|
||||
err = memfd_fcntl(filp, cmd, arg);
|
||||
err = memfd_fcntl(filp, cmd, argi);
|
||||
break;
|
||||
case F_GET_RW_HINT:
|
||||
case F_SET_RW_HINT:
|
||||
|
30
fs/file.c
30
fs/file.c
@ -668,7 +668,7 @@ EXPORT_SYMBOL(close_fd); /* for ksys_close() */
|
||||
|
||||
/**
|
||||
* last_fd - return last valid index into fd table
|
||||
* @cur_fds: files struct
|
||||
* @fdt: File descriptor table.
|
||||
*
|
||||
* Context: Either rcu read lock or files_lock must be held.
|
||||
*
|
||||
@ -693,29 +693,30 @@ static inline void __range_cloexec(struct files_struct *cur_fds,
|
||||
spin_unlock(&cur_fds->file_lock);
|
||||
}
|
||||
|
||||
static inline void __range_close(struct files_struct *cur_fds, unsigned int fd,
|
||||
static inline void __range_close(struct files_struct *files, unsigned int fd,
|
||||
unsigned int max_fd)
|
||||
{
|
||||
struct file *file;
|
||||
unsigned n;
|
||||
|
||||
rcu_read_lock();
|
||||
n = last_fd(files_fdtable(cur_fds));
|
||||
rcu_read_unlock();
|
||||
spin_lock(&files->file_lock);
|
||||
n = last_fd(files_fdtable(files));
|
||||
max_fd = min(max_fd, n);
|
||||
|
||||
while (fd <= max_fd) {
|
||||
struct file *file;
|
||||
|
||||
spin_lock(&cur_fds->file_lock);
|
||||
file = pick_file(cur_fds, fd++);
|
||||
spin_unlock(&cur_fds->file_lock);
|
||||
|
||||
for (; fd <= max_fd; fd++) {
|
||||
file = pick_file(files, fd);
|
||||
if (file) {
|
||||
/* found a valid file to close */
|
||||
filp_close(file, cur_fds);
|
||||
spin_unlock(&files->file_lock);
|
||||
filp_close(file, files);
|
||||
cond_resched();
|
||||
spin_lock(&files->file_lock);
|
||||
} else if (need_resched()) {
|
||||
spin_unlock(&files->file_lock);
|
||||
cond_resched();
|
||||
spin_lock(&files->file_lock);
|
||||
}
|
||||
}
|
||||
spin_unlock(&files->file_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -723,6 +724,7 @@ static inline void __range_close(struct files_struct *cur_fds, unsigned int fd,
|
||||
*
|
||||
* @fd: starting file descriptor to close
|
||||
* @max_fd: last file descriptor to close
|
||||
* @flags: CLOSE_RANGE flags.
|
||||
*
|
||||
* This closes a range of file descriptors. All file descriptors
|
||||
* from @fd up to and including @max_fd are closed.
|
||||
|
@ -461,11 +461,8 @@ void fput(struct file *file)
|
||||
*/
|
||||
void __fput_sync(struct file *file)
|
||||
{
|
||||
if (atomic_long_dec_and_test(&file->f_count)) {
|
||||
struct task_struct *task = current;
|
||||
BUG_ON(!(task->flags & PF_KTHREAD));
|
||||
if (atomic_long_dec_and_test(&file->f_count))
|
||||
__fput(file);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(fput);
|
||||
|
@ -162,6 +162,10 @@ EXPORT_SYMBOL(vfs_parse_fs_param);
|
||||
|
||||
/**
|
||||
* vfs_parse_fs_string - Convenience function to just parse a string.
|
||||
* @fc: Filesystem context.
|
||||
* @key: Parameter name.
|
||||
* @value: Default value.
|
||||
* @v_size: Maximum number of bytes in the value.
|
||||
*/
|
||||
int vfs_parse_fs_string(struct fs_context *fc, const char *key,
|
||||
const char *value, size_t v_size)
|
||||
@ -189,7 +193,7 @@ EXPORT_SYMBOL(vfs_parse_fs_string);
|
||||
|
||||
/**
|
||||
* generic_parse_monolithic - Parse key[=val][,key[=val]]* mount data
|
||||
* @ctx: The superblock configuration to fill in.
|
||||
* @fc: The superblock configuration to fill in.
|
||||
* @data: The data to parse
|
||||
*
|
||||
* Parse a blob of data that's in key[=val][,key[=val]]* form. This can be
|
||||
@ -315,10 +319,31 @@ struct fs_context *fs_context_for_reconfigure(struct dentry *dentry,
|
||||
}
|
||||
EXPORT_SYMBOL(fs_context_for_reconfigure);
|
||||
|
||||
/**
|
||||
* fs_context_for_submount: allocate a new fs_context for a submount
|
||||
* @type: file_system_type of the new context
|
||||
* @reference: reference dentry from which to copy relevant info
|
||||
*
|
||||
* Allocate a new fs_context suitable for a submount. This also ensures that
|
||||
* the fc->security object is inherited from @reference (if needed).
|
||||
*/
|
||||
struct fs_context *fs_context_for_submount(struct file_system_type *type,
|
||||
struct dentry *reference)
|
||||
{
|
||||
return alloc_fs_context(type, reference, 0, 0, FS_CONTEXT_FOR_SUBMOUNT);
|
||||
struct fs_context *fc;
|
||||
int ret;
|
||||
|
||||
fc = alloc_fs_context(type, reference, 0, 0, FS_CONTEXT_FOR_SUBMOUNT);
|
||||
if (IS_ERR(fc))
|
||||
return fc;
|
||||
|
||||
ret = security_fs_context_submount(fc, reference->d_sb);
|
||||
if (ret) {
|
||||
put_fs_context(fc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return fc;
|
||||
}
|
||||
EXPORT_SYMBOL(fs_context_for_submount);
|
||||
|
||||
@ -333,7 +358,7 @@ void fc_drop_locked(struct fs_context *fc)
|
||||
static void legacy_fs_context_free(struct fs_context *fc);
|
||||
|
||||
/**
|
||||
* vfs_dup_fc_config: Duplicate a filesystem context.
|
||||
* vfs_dup_fs_context - Duplicate a filesystem context.
|
||||
* @src_fc: The context to copy.
|
||||
*/
|
||||
struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
|
||||
@ -379,7 +404,9 @@ EXPORT_SYMBOL(vfs_dup_fs_context);
|
||||
|
||||
/**
|
||||
* logfc - Log a message to a filesystem context
|
||||
* @fc: The filesystem context to log to.
|
||||
* @log: The filesystem context to log to, or NULL to use printk.
|
||||
* @prefix: A string to prefix the output with, or NULL.
|
||||
* @level: 'w' for a warning, 'e' for an error. Anything else is a notice.
|
||||
* @fmt: The format of the buffer.
|
||||
*/
|
||||
void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, ...)
|
||||
|
10
fs/ioctl.c
10
fs/ioctl.c
@ -109,9 +109,6 @@ static int ioctl_fibmap(struct file *filp, int __user *p)
|
||||
* Returns 0 on success, -errno on error, 1 if this was the last
|
||||
* extent that will fit in user array.
|
||||
*/
|
||||
#define SET_UNKNOWN_FLAGS (FIEMAP_EXTENT_DELALLOC)
|
||||
#define SET_NO_UNMOUNTED_IO_FLAGS (FIEMAP_EXTENT_DATA_ENCRYPTED)
|
||||
#define SET_NOT_ALIGNED_FLAGS (FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE)
|
||||
int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
|
||||
u64 phys, u64 len, u32 flags)
|
||||
{
|
||||
@ -127,6 +124,10 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
|
||||
if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max)
|
||||
return 1;
|
||||
|
||||
#define SET_UNKNOWN_FLAGS (FIEMAP_EXTENT_DELALLOC)
|
||||
#define SET_NO_UNMOUNTED_IO_FLAGS (FIEMAP_EXTENT_DATA_ENCRYPTED)
|
||||
#define SET_NOT_ALIGNED_FLAGS (FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE)
|
||||
|
||||
if (flags & SET_UNKNOWN_FLAGS)
|
||||
flags |= FIEMAP_EXTENT_UNKNOWN;
|
||||
if (flags & SET_NO_UNMOUNTED_IO_FLAGS)
|
||||
@ -877,6 +878,9 @@ out:
|
||||
#ifdef CONFIG_COMPAT
|
||||
/**
|
||||
* compat_ptr_ioctl - generic implementation of .compat_ioctl file operation
|
||||
* @file: The file to operate on.
|
||||
* @cmd: The ioctl command number.
|
||||
* @arg: The argument to the ioctl.
|
||||
*
|
||||
* This is not normally called as a function, but instead set in struct
|
||||
* file_operations as
|
||||
|
@ -8,16 +8,16 @@
|
||||
/**
|
||||
* kernel_read_file() - read file contents into a kernel buffer
|
||||
*
|
||||
* @file file to read from
|
||||
* @offset where to start reading from (see below).
|
||||
* @buf pointer to a "void *" buffer for reading into (if
|
||||
* @file: file to read from
|
||||
* @offset: where to start reading from (see below).
|
||||
* @buf: pointer to a "void *" buffer for reading into (if
|
||||
* *@buf is NULL, a buffer will be allocated, and
|
||||
* @buf_size will be ignored)
|
||||
* @buf_size size of buf, if already allocated. If @buf not
|
||||
* @buf_size: size of buf, if already allocated. If @buf not
|
||||
* allocated, this is the largest size to allocate.
|
||||
* @file_size if non-NULL, the full size of @file will be
|
||||
* @file_size: if non-NULL, the full size of @file will be
|
||||
* written here.
|
||||
* @id the kernel_read_file_id identifying the type of
|
||||
* @id: the kernel_read_file_id identifying the type of
|
||||
* file contents being read (for LSMs to examine)
|
||||
*
|
||||
* @offset must be 0 unless both @buf and @file_size are non-NULL
|
||||
|
42
fs/libfs.c
42
fs/libfs.c
@ -815,21 +815,20 @@ int simple_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
struct page *page;
|
||||
pgoff_t index;
|
||||
struct folio *folio;
|
||||
|
||||
index = pos >> PAGE_SHIFT;
|
||||
folio = __filemap_get_folio(mapping, pos / PAGE_SIZE, FGP_WRITEBEGIN,
|
||||
mapping_gfp_mask(mapping));
|
||||
if (IS_ERR(folio))
|
||||
return PTR_ERR(folio);
|
||||
|
||||
page = grab_cache_page_write_begin(mapping, index);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
*pagep = &folio->page;
|
||||
|
||||
*pagep = page;
|
||||
if (!folio_test_uptodate(folio) && (len != folio_size(folio))) {
|
||||
size_t from = offset_in_folio(folio, pos);
|
||||
|
||||
if (!PageUptodate(page) && (len != PAGE_SIZE)) {
|
||||
unsigned from = pos & (PAGE_SIZE - 1);
|
||||
|
||||
zero_user_segments(page, 0, from, from + len, PAGE_SIZE);
|
||||
folio_zero_segments(folio, 0, from,
|
||||
from + len, folio_size(folio));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -861,17 +860,18 @@ static int simple_write_end(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned copied,
|
||||
struct page *page, void *fsdata)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct folio *folio = page_folio(page);
|
||||
struct inode *inode = folio->mapping->host;
|
||||
loff_t last_pos = pos + copied;
|
||||
|
||||
/* zero the stale part of the page if we did a short copy */
|
||||
if (!PageUptodate(page)) {
|
||||
/* zero the stale part of the folio if we did a short copy */
|
||||
if (!folio_test_uptodate(folio)) {
|
||||
if (copied < len) {
|
||||
unsigned from = pos & (PAGE_SIZE - 1);
|
||||
size_t from = offset_in_folio(folio, pos);
|
||||
|
||||
zero_user(page, from + copied, len - copied);
|
||||
folio_zero_range(folio, from + copied, len - copied);
|
||||
}
|
||||
SetPageUptodate(page);
|
||||
folio_mark_uptodate(folio);
|
||||
}
|
||||
/*
|
||||
* No need to use i_size_read() here, the i_size
|
||||
@ -880,9 +880,9 @@ static int simple_write_end(struct file *file, struct address_space *mapping,
|
||||
if (last_pos > inode->i_size)
|
||||
i_size_write(inode, last_pos);
|
||||
|
||||
set_page_dirty(page);
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
folio_mark_dirty(folio);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
|
||||
return copied;
|
||||
}
|
||||
@ -1536,7 +1536,7 @@ EXPORT_SYMBOL(alloc_anon_inode);
|
||||
* All arguments are ignored and it just returns -EINVAL.
|
||||
*/
|
||||
int
|
||||
simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
|
||||
simple_nosetlease(struct file *filp, int arg, struct file_lock **flp,
|
||||
void **priv)
|
||||
{
|
||||
return -EINVAL;
|
||||
|
20
fs/locks.c
20
fs/locks.c
@ -438,7 +438,7 @@ static void flock_make_lock(struct file *filp, struct file_lock *fl, int type)
|
||||
fl->fl_end = OFFSET_MAX;
|
||||
}
|
||||
|
||||
static int assign_type(struct file_lock *fl, long type)
|
||||
static int assign_type(struct file_lock *fl, int type)
|
||||
{
|
||||
switch (type) {
|
||||
case F_RDLCK:
|
||||
@ -549,7 +549,7 @@ static const struct lock_manager_operations lease_manager_ops = {
|
||||
/*
|
||||
* Initialize a lease, use the default lock manager operations
|
||||
*/
|
||||
static int lease_init(struct file *filp, long type, struct file_lock *fl)
|
||||
static int lease_init(struct file *filp, int type, struct file_lock *fl)
|
||||
{
|
||||
if (assign_type(fl, type) != 0)
|
||||
return -EINVAL;
|
||||
@ -567,7 +567,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl)
|
||||
}
|
||||
|
||||
/* Allocate a file_lock initialised to this type of lease */
|
||||
static struct file_lock *lease_alloc(struct file *filp, long type)
|
||||
static struct file_lock *lease_alloc(struct file *filp, int type)
|
||||
{
|
||||
struct file_lock *fl = locks_alloc_lock();
|
||||
int error = -ENOMEM;
|
||||
@ -1666,7 +1666,7 @@ int fcntl_getlease(struct file *filp)
|
||||
* conflict with the lease we're trying to set.
|
||||
*/
|
||||
static int
|
||||
check_conflicting_open(struct file *filp, const long arg, int flags)
|
||||
check_conflicting_open(struct file *filp, const int arg, int flags)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
int self_wcount = 0, self_rcount = 0;
|
||||
@ -1701,7 +1701,7 @@ check_conflicting_open(struct file *filp, const long arg, int flags)
|
||||
}
|
||||
|
||||
static int
|
||||
generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **priv)
|
||||
generic_add_lease(struct file *filp, int arg, struct file_lock **flp, void **priv)
|
||||
{
|
||||
struct file_lock *fl, *my_fl = NULL, *lease;
|
||||
struct inode *inode = file_inode(filp);
|
||||
@ -1859,7 +1859,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
|
||||
* The (input) flp->fl_lmops->lm_break function is required
|
||||
* by break_lease().
|
||||
*/
|
||||
int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
|
||||
int generic_setlease(struct file *filp, int arg, struct file_lock **flp,
|
||||
void **priv)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
@ -1906,7 +1906,7 @@ lease_notifier_chain_init(void)
|
||||
}
|
||||
|
||||
static inline void
|
||||
setlease_notifier(long arg, struct file_lock *lease)
|
||||
setlease_notifier(int arg, struct file_lock *lease)
|
||||
{
|
||||
if (arg != F_UNLCK)
|
||||
srcu_notifier_call_chain(&lease_notifier_chain, arg, lease);
|
||||
@ -1942,7 +1942,7 @@ EXPORT_SYMBOL_GPL(lease_unregister_notifier);
|
||||
* may be NULL if the lm_setup operation doesn't require it.
|
||||
*/
|
||||
int
|
||||
vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
|
||||
vfs_setlease(struct file *filp, int arg, struct file_lock **lease, void **priv)
|
||||
{
|
||||
if (lease)
|
||||
setlease_notifier(arg, *lease);
|
||||
@ -1953,7 +1953,7 @@ vfs_setlease(struct file *filp, long arg, struct file_lock **lease, void **priv)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vfs_setlease);
|
||||
|
||||
static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
|
||||
static int do_fcntl_add_lease(unsigned int fd, struct file *filp, int arg)
|
||||
{
|
||||
struct file_lock *fl;
|
||||
struct fasync_struct *new;
|
||||
@ -1988,7 +1988,7 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
|
||||
* Note that you also need to call %F_SETSIG to
|
||||
* receive a signal when the lease is broken.
|
||||
*/
|
||||
int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
|
||||
int fcntl_setlease(unsigned int fd, struct file *filp, int arg)
|
||||
{
|
||||
if (arg == F_UNLCK)
|
||||
return vfs_setlease(filp, F_UNLCK, NULL, (void **)&filp);
|
||||
|
@ -643,6 +643,8 @@ static bool nd_alloc_stack(struct nameidata *nd)
|
||||
|
||||
/**
|
||||
* path_connected - Verify that a dentry is below mnt.mnt_root
|
||||
* @mnt: The mountpoint to check.
|
||||
* @dentry: The dentry to check.
|
||||
*
|
||||
* Rename can sometimes move a file or directory outside of a bind
|
||||
* mount, path_connected allows those cases to be detected.
|
||||
@ -1083,6 +1085,7 @@ fs_initcall(init_fs_namei_sysctls);
|
||||
/**
|
||||
* may_follow_link - Check symlink following for unsafe situations
|
||||
* @nd: nameidata pathwalk data
|
||||
* @inode: Used for idmapping.
|
||||
*
|
||||
* In the case of the sysctl_protected_symlinks sysctl being enabled,
|
||||
* CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is
|
||||
@ -2890,7 +2893,7 @@ int path_pts(struct path *path)
|
||||
dput(path->dentry);
|
||||
path->dentry = parent;
|
||||
child = d_hash_and_lookup(parent, &this);
|
||||
if (!child)
|
||||
if (IS_ERR_OR_NULL(child))
|
||||
return -ENOENT;
|
||||
|
||||
path->dentry = child;
|
||||
|
@ -328,7 +328,7 @@ extern int update_open_stateid(struct nfs4_state *state,
|
||||
const nfs4_stateid *open_stateid,
|
||||
const nfs4_stateid *deleg_stateid,
|
||||
fmode_t fmode);
|
||||
extern int nfs4_proc_setlease(struct file *file, long arg,
|
||||
extern int nfs4_proc_setlease(struct file *file, int arg,
|
||||
struct file_lock **lease, void **priv);
|
||||
extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
|
||||
struct nfs_fsinfo *fsinfo);
|
||||
|
@ -438,7 +438,7 @@ void nfs42_ssc_unregister_ops(void)
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
||||
static int nfs4_setlease(struct file *file, long arg, struct file_lock **lease,
|
||||
static int nfs4_setlease(struct file *file, int arg, struct file_lock **lease,
|
||||
void **priv)
|
||||
{
|
||||
return nfs4_proc_setlease(file, arg, lease, priv);
|
||||
|
@ -7579,7 +7579,7 @@ static int nfs4_delete_lease(struct file *file, void **priv)
|
||||
return generic_setlease(file, F_UNLCK, NULL, priv);
|
||||
}
|
||||
|
||||
static int nfs4_add_lease(struct file *file, long arg, struct file_lock **lease,
|
||||
static int nfs4_add_lease(struct file *file, int arg, struct file_lock **lease,
|
||||
void **priv)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
@ -7597,7 +7597,7 @@ static int nfs4_add_lease(struct file *file, long arg, struct file_lock **lease,
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
int nfs4_proc_setlease(struct file *file, long arg, struct file_lock **lease,
|
||||
int nfs4_proc_setlease(struct file *file, int arg, struct file_lock **lease,
|
||||
void **priv)
|
||||
{
|
||||
switch (arg) {
|
||||
|
@ -199,7 +199,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
|
||||
}
|
||||
|
||||
/* this conversion is done only at watch creation */
|
||||
static __u32 convert_arg(unsigned long arg)
|
||||
static __u32 convert_arg(unsigned int arg)
|
||||
{
|
||||
__u32 new_mask = FS_EVENT_ON_CHILD;
|
||||
|
||||
@ -258,7 +258,7 @@ static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark *dn_mark,
|
||||
* up here. Allocate both a mark for fsnotify to add and a dnotify_struct to be
|
||||
* attached to the fsnotify_mark.
|
||||
*/
|
||||
int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
|
||||
int fcntl_dirnotify(int fd, struct file *filp, unsigned int arg)
|
||||
{
|
||||
struct dnotify_mark *new_dn_mark, *dn_mark;
|
||||
struct fsnotify_mark *new_fsn_mark, *fsn_mark;
|
||||
|
31
fs/open.c
31
fs/open.c
@ -1150,7 +1150,7 @@ EXPORT_SYMBOL_GPL(kernel_file_open);
|
||||
* backing_file_open - open a backing file for kernel internal use
|
||||
* @path: path of the file to open
|
||||
* @flags: open flags
|
||||
* @path: path of the backing file
|
||||
* @real_path: path of the backing file
|
||||
* @cred: credentials for open
|
||||
*
|
||||
* Open a backing file for a stackable filesystem (e.g., overlayfs).
|
||||
@ -1503,7 +1503,7 @@ SYSCALL_DEFINE2(creat, const char __user *, pathname, umode_t, mode)
|
||||
* "id" is the POSIX thread ID. We use the
|
||||
* files pointer for this..
|
||||
*/
|
||||
int filp_close(struct file *filp, fl_owner_t id)
|
||||
static int filp_flush(struct file *filp, fl_owner_t id)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
@ -1520,10 +1520,18 @@ int filp_close(struct file *filp, fl_owner_t id)
|
||||
dnotify_flush(filp, id);
|
||||
locks_remove_posix(filp, id);
|
||||
}
|
||||
fput(filp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int filp_close(struct file *filp, fl_owner_t id)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = filp_flush(filp, id);
|
||||
fput(filp);
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(filp_close);
|
||||
|
||||
/*
|
||||
@ -1533,7 +1541,20 @@ EXPORT_SYMBOL(filp_close);
|
||||
*/
|
||||
SYSCALL_DEFINE1(close, unsigned int, fd)
|
||||
{
|
||||
int retval = close_fd(fd);
|
||||
int retval;
|
||||
struct file *file;
|
||||
|
||||
file = close_fd_get_file(fd);
|
||||
if (!file)
|
||||
return -EBADF;
|
||||
|
||||
retval = filp_flush(file, current->files);
|
||||
|
||||
/*
|
||||
* We're returning to user space. Don't bother
|
||||
* with any delayed fput() cases.
|
||||
*/
|
||||
__fput_sync(file);
|
||||
|
||||
/* can't restart close syscall because file table entry was cleared */
|
||||
if (unlikely(retval == -ERESTARTSYS ||
|
||||
@ -1546,7 +1567,7 @@ SYSCALL_DEFINE1(close, unsigned int, fd)
|
||||
}
|
||||
|
||||
/**
|
||||
* close_range() - Close all file descriptors in a given range.
|
||||
* sys_close_range() - Close all file descriptors in a given range.
|
||||
*
|
||||
* @fd: starting file descriptor to close
|
||||
* @max_fd: last file descriptor to close
|
||||
|
@ -293,10 +293,7 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
|
||||
if (iocb->ki_flags & IOCB_WRITE) {
|
||||
struct inode *inode = file_inode(orig_iocb->ki_filp);
|
||||
|
||||
/* Actually acquired in ovl_write_iter() */
|
||||
__sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb,
|
||||
SB_FREEZE_WRITE);
|
||||
file_end_write(iocb->ki_filp);
|
||||
kiocb_end_write(iocb);
|
||||
ovl_copyattr(inode);
|
||||
}
|
||||
|
||||
@ -412,10 +409,6 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
if (!aio_req)
|
||||
goto out;
|
||||
|
||||
file_start_write(real.file);
|
||||
/* Pacify lockdep, same trick as done in aio_write() */
|
||||
__sb_writers_release(file_inode(real.file)->i_sb,
|
||||
SB_FREEZE_WRITE);
|
||||
aio_req->fd = real;
|
||||
real.flags = 0;
|
||||
aio_req->orig_iocb = iocb;
|
||||
@ -423,6 +416,7 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
aio_req->iocb.ki_flags = ifl;
|
||||
aio_req->iocb.ki_complete = ovl_aio_rw_complete;
|
||||
refcount_set(&aio_req->ref, 2);
|
||||
kiocb_start_write(&aio_req->iocb);
|
||||
ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);
|
||||
ovl_aio_put(aio_req);
|
||||
if (ret != -EIOCBQUEUED)
|
||||
|
@ -489,7 +489,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
head = pipe->head;
|
||||
if (!pipe_full(head, pipe->tail, pipe->max_usage)) {
|
||||
unsigned int mask = pipe->ring_size - 1;
|
||||
struct pipe_buffer *buf = &pipe->bufs[head & mask];
|
||||
struct pipe_buffer *buf;
|
||||
struct page *page = pipe->tmp_page;
|
||||
int copied;
|
||||
|
||||
@ -1236,7 +1236,7 @@ const struct file_operations pipefifo_fops = {
|
||||
* Currently we rely on the pipe array holding a power-of-2 number
|
||||
* of pages. Returns 0 on error.
|
||||
*/
|
||||
unsigned int round_pipe_size(unsigned long size)
|
||||
unsigned int round_pipe_size(unsigned int size)
|
||||
{
|
||||
if (size > (1U << 31))
|
||||
return 0;
|
||||
@ -1319,7 +1319,7 @@ int pipe_resize_ring(struct pipe_inode_info *pipe, unsigned int nr_slots)
|
||||
* Allocate a new array of pipe buffers and copy the info over. Returns the
|
||||
* pipe size if successful, or return -ERROR on error.
|
||||
*/
|
||||
static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
|
||||
static long pipe_set_size(struct pipe_inode_info *pipe, unsigned int arg)
|
||||
{
|
||||
unsigned long user_bufs;
|
||||
unsigned int nr_slots, size;
|
||||
@ -1387,7 +1387,7 @@ struct pipe_inode_info *get_pipe_info(struct file *file, bool for_splice)
|
||||
return pipe;
|
||||
}
|
||||
|
||||
long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
long pipe_fcntl(struct file *file, unsigned int cmd, unsigned int arg)
|
||||
{
|
||||
struct pipe_inode_info *pipe;
|
||||
long ret;
|
||||
|
@ -71,7 +71,7 @@ EXPORT_SYMBOL(vfs_setpos);
|
||||
* @file: file structure to seek on
|
||||
* @offset: file offset to seek to
|
||||
* @whence: type of seek
|
||||
* @size: max size of this file in file system
|
||||
* @maxsize: max size of this file in file system
|
||||
* @eof: offset used for SEEK_END position
|
||||
*
|
||||
* This is a variant of generic_file_llseek that allows passing in a custom
|
||||
|
@ -2326,7 +2326,7 @@ static struct buffer_head *reiserfs_breada(struct block_device *dev,
|
||||
int i, j;
|
||||
|
||||
bh = __getblk(dev, block, bufsize);
|
||||
if (buffer_uptodate(bh))
|
||||
if (!bh || buffer_uptodate(bh))
|
||||
return (bh);
|
||||
|
||||
if (block + BUFNR > max_block) {
|
||||
@ -2336,6 +2336,8 @@ static struct buffer_head *reiserfs_breada(struct block_device *dev,
|
||||
j = 1;
|
||||
for (i = 1; i < blocks; i++) {
|
||||
bh = __getblk(dev, block + i, bufsize);
|
||||
if (!bh)
|
||||
break;
|
||||
if (buffer_uptodate(bh)) {
|
||||
brelse(bh);
|
||||
break;
|
||||
|
@ -1077,7 +1077,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_setlease(struct file *file, long arg, struct file_lock **lease, void **priv)
|
||||
cifs_setlease(struct file *file, int arg, struct file_lock **lease, void **priv)
|
||||
{
|
||||
/*
|
||||
* Note that this is called by vfs setlease with i_lock held to
|
||||
|
66
fs/splice.c
66
fs/splice.c
@ -120,17 +120,17 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe,
|
||||
static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe,
|
||||
struct pipe_buffer *buf)
|
||||
{
|
||||
struct page *page = buf->page;
|
||||
struct folio *folio = page_folio(buf->page);
|
||||
int err;
|
||||
|
||||
if (!PageUptodate(page)) {
|
||||
lock_page(page);
|
||||
if (!folio_test_uptodate(folio)) {
|
||||
folio_lock(folio);
|
||||
|
||||
/*
|
||||
* Page got truncated/unhashed. This will cause a 0-byte
|
||||
* Folio got truncated/unhashed. This will cause a 0-byte
|
||||
* splice, if this is the first page.
|
||||
*/
|
||||
if (!page->mapping) {
|
||||
if (!folio->mapping) {
|
||||
err = -ENODATA;
|
||||
goto error;
|
||||
}
|
||||
@ -138,20 +138,18 @@ static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe,
|
||||
/*
|
||||
* Uh oh, read-error from disk.
|
||||
*/
|
||||
if (!PageUptodate(page)) {
|
||||
if (!folio_test_uptodate(folio)) {
|
||||
err = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Page is ok afterall, we are done.
|
||||
*/
|
||||
unlock_page(page);
|
||||
/* Folio is ok after all, we are done */
|
||||
folio_unlock(folio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
unlock_page(page);
|
||||
folio_unlock(folio);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1269,10 +1267,8 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out,
|
||||
if ((in->f_flags | out->f_flags) & O_NONBLOCK)
|
||||
flags |= SPLICE_F_NONBLOCK;
|
||||
|
||||
return splice_pipe_to_pipe(ipipe, opipe, len, flags);
|
||||
}
|
||||
|
||||
if (ipipe) {
|
||||
ret = splice_pipe_to_pipe(ipipe, opipe, len, flags);
|
||||
} else if (ipipe) {
|
||||
if (off_in)
|
||||
return -ESPIPE;
|
||||
if (off_out) {
|
||||
@ -1297,18 +1293,11 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out,
|
||||
ret = do_splice_from(ipipe, out, &offset, len, flags);
|
||||
file_end_write(out);
|
||||
|
||||
if (ret > 0)
|
||||
fsnotify_modify(out);
|
||||
|
||||
if (!off_out)
|
||||
out->f_pos = offset;
|
||||
else
|
||||
*off_out = offset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (opipe) {
|
||||
} else if (opipe) {
|
||||
if (off_out)
|
||||
return -ESPIPE;
|
||||
if (off_in) {
|
||||
@ -1324,18 +1313,25 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out,
|
||||
|
||||
ret = splice_file_to_pipe(in, opipe, &offset, len, flags);
|
||||
|
||||
if (ret > 0)
|
||||
fsnotify_access(in);
|
||||
|
||||
if (!off_in)
|
||||
in->f_pos = offset;
|
||||
else
|
||||
*off_in = offset;
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
if (ret > 0) {
|
||||
/*
|
||||
* Generate modify out before access in:
|
||||
* do_splice_from() may've already sent modify out,
|
||||
* and this ensures the events get merged.
|
||||
*/
|
||||
fsnotify_modify(out);
|
||||
fsnotify_access(in);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long __do_splice(struct file *in, loff_t __user *off_in,
|
||||
@ -1464,6 +1460,9 @@ static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
|
||||
pipe_unlock(pipe);
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
fsnotify_access(file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1493,8 +1492,10 @@ static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
|
||||
if (!ret)
|
||||
ret = iter_to_pipe(iter, pipe, buf_flag);
|
||||
pipe_unlock(pipe);
|
||||
if (ret > 0)
|
||||
if (ret > 0) {
|
||||
wakeup_pipe_readers(pipe);
|
||||
fsnotify_modify(file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1928,6 +1929,11 @@ long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags)
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
fsnotify_access(in);
|
||||
fsnotify_modify(out);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ struct dnotify_struct {
|
||||
FS_MOVED_FROM | FS_MOVED_TO)
|
||||
|
||||
extern void dnotify_flush(struct file *, fl_owner_t);
|
||||
extern int fcntl_dirnotify(int, struct file *, unsigned long);
|
||||
extern int fcntl_dirnotify(int, struct file *, unsigned int);
|
||||
|
||||
#else
|
||||
|
||||
@ -38,7 +38,7 @@ static inline void dnotify_flush(struct file *filp, fl_owner_t id)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
|
||||
static inline int fcntl_dirnotify(int fd, struct file *filp, unsigned int arg)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ int fcntl_setlk64(unsigned int, struct file *, unsigned int,
|
||||
struct flock64 *);
|
||||
#endif
|
||||
|
||||
int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
|
||||
int fcntl_setlease(unsigned int fd, struct file *filp, int arg);
|
||||
int fcntl_getlease(struct file *filp);
|
||||
|
||||
/* fs/locks.c */
|
||||
@ -167,8 +167,8 @@ bool vfs_inode_has_locks(struct inode *inode);
|
||||
int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl);
|
||||
int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
|
||||
void lease_get_mtime(struct inode *, struct timespec64 *time);
|
||||
int generic_setlease(struct file *, long, struct file_lock **, void **priv);
|
||||
int vfs_setlease(struct file *, long, struct file_lock **, void **);
|
||||
int generic_setlease(struct file *, int, struct file_lock **, void **priv);
|
||||
int vfs_setlease(struct file *, int, struct file_lock **, void **);
|
||||
int lease_modify(struct file_lock *, int, struct list_head *);
|
||||
|
||||
struct notifier_block;
|
||||
@ -213,7 +213,7 @@ static inline int fcntl_setlk64(unsigned int fd, struct file *file,
|
||||
return -EACCES;
|
||||
}
|
||||
#endif
|
||||
static inline int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
|
||||
static inline int fcntl_setlease(unsigned int fd, struct file *filp, int arg)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -306,13 +306,13 @@ static inline void lease_get_mtime(struct inode *inode,
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int generic_setlease(struct file *filp, long arg,
|
||||
static inline int generic_setlease(struct file *filp, int arg,
|
||||
struct file_lock **flp, void **priv)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int vfs_setlease(struct file *filp, long arg,
|
||||
static inline int vfs_setlease(struct file *filp, int arg,
|
||||
struct file_lock **lease, void **priv)
|
||||
{
|
||||
return -EINVAL;
|
||||
|
@ -1069,7 +1069,7 @@ extern void fasync_free(struct fasync_struct *);
|
||||
extern void kill_fasync(struct fasync_struct **, int, int);
|
||||
|
||||
extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
|
||||
extern int f_setown(struct file *filp, unsigned long arg, int force);
|
||||
extern int f_setown(struct file *filp, int who, int force);
|
||||
extern void f_delown(struct file *filp);
|
||||
extern pid_t f_getown(struct file *filp);
|
||||
extern int send_sigurg(struct fown_struct *fown);
|
||||
@ -1871,7 +1871,7 @@ struct file_operations {
|
||||
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
|
||||
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
|
||||
void (*splice_eof)(struct file *file);
|
||||
int (*setlease)(struct file *, long, struct file_lock **, void **);
|
||||
int (*setlease)(struct file *, int, struct file_lock **, void **);
|
||||
long (*fallocate)(struct file *file, int mode, loff_t offset,
|
||||
loff_t len);
|
||||
void (*show_fdinfo)(struct seq_file *m, struct file *f);
|
||||
@ -2632,6 +2632,13 @@ static inline bool inode_wrong_type(const struct inode *inode, umode_t mode)
|
||||
return (inode->i_mode ^ mode) & S_IFMT;
|
||||
}
|
||||
|
||||
/**
|
||||
* file_start_write - get write access to a superblock for regular file io
|
||||
* @file: the file we want to write to
|
||||
*
|
||||
* This is a variant of sb_start_write() which is a noop on non-regualr file.
|
||||
* Should be matched with a call to file_end_write().
|
||||
*/
|
||||
static inline void file_start_write(struct file *file)
|
||||
{
|
||||
if (!S_ISREG(file_inode(file)->i_mode))
|
||||
@ -2646,11 +2653,53 @@ static inline bool file_start_write_trylock(struct file *file)
|
||||
return sb_start_write_trylock(file_inode(file)->i_sb);
|
||||
}
|
||||
|
||||
/**
|
||||
* file_end_write - drop write access to a superblock of a regular file
|
||||
* @file: the file we wrote to
|
||||
*
|
||||
* Should be matched with a call to file_start_write().
|
||||
*/
|
||||
static inline void file_end_write(struct file *file)
|
||||
{
|
||||
if (!S_ISREG(file_inode(file)->i_mode))
|
||||
return;
|
||||
__sb_end_write(file_inode(file)->i_sb, SB_FREEZE_WRITE);
|
||||
sb_end_write(file_inode(file)->i_sb);
|
||||
}
|
||||
|
||||
/**
|
||||
* kiocb_start_write - get write access to a superblock for async file io
|
||||
* @iocb: the io context we want to submit the write with
|
||||
*
|
||||
* This is a variant of sb_start_write() for async io submission.
|
||||
* Should be matched with a call to kiocb_end_write().
|
||||
*/
|
||||
static inline void kiocb_start_write(struct kiocb *iocb)
|
||||
{
|
||||
struct inode *inode = file_inode(iocb->ki_filp);
|
||||
|
||||
sb_start_write(inode->i_sb);
|
||||
/*
|
||||
* Fool lockdep by telling it the lock got released so that it
|
||||
* doesn't complain about the held lock when we return to userspace.
|
||||
*/
|
||||
__sb_writers_release(inode->i_sb, SB_FREEZE_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* kiocb_end_write - drop write access to a superblock after async file io
|
||||
* @iocb: the io context we sumbitted the write with
|
||||
*
|
||||
* Should be matched with a call to kiocb_start_write().
|
||||
*/
|
||||
static inline void kiocb_end_write(struct kiocb *iocb)
|
||||
{
|
||||
struct inode *inode = file_inode(iocb->ki_filp);
|
||||
|
||||
/*
|
||||
* Tell lockdep we inherited freeze protection from submission thread.
|
||||
*/
|
||||
__sb_writers_acquired(inode->i_sb, SB_FREEZE_WRITE);
|
||||
sb_end_write(inode->i_sb);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2700,8 +2749,7 @@ static inline bool inode_is_open_for_write(const struct inode *inode)
|
||||
#if defined(CONFIG_IMA) || defined(CONFIG_FILE_LOCKING)
|
||||
static inline void i_readcount_dec(struct inode *inode)
|
||||
{
|
||||
BUG_ON(!atomic_read(&inode->i_readcount));
|
||||
atomic_dec(&inode->i_readcount);
|
||||
BUG_ON(atomic_dec_return(&inode->i_readcount) < 0);
|
||||
}
|
||||
static inline void i_readcount_inc(struct inode *inode)
|
||||
{
|
||||
@ -3046,7 +3094,7 @@ extern int simple_write_begin(struct file *file, struct address_space *mapping,
|
||||
extern const struct address_space_operations ram_aops;
|
||||
extern int always_delete_dentry(const struct dentry *);
|
||||
extern struct inode *alloc_anon_inode(struct super_block *);
|
||||
extern int simple_nosetlease(struct file *, long, struct file_lock **, void **);
|
||||
extern int simple_nosetlease(struct file *, int, struct file_lock **, void **);
|
||||
extern const struct dentry_operations simple_dentry_operations;
|
||||
|
||||
extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
|
||||
|
@ -54,6 +54,7 @@ LSM_HOOK(int, 0, bprm_creds_from_file, struct linux_binprm *bprm, struct file *f
|
||||
LSM_HOOK(int, 0, bprm_check_security, struct linux_binprm *bprm)
|
||||
LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm)
|
||||
LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, struct linux_binprm *bprm)
|
||||
LSM_HOOK(int, 0, fs_context_submount, struct fs_context *fc, struct super_block *reference)
|
||||
LSM_HOOK(int, 0, fs_context_dup, struct fs_context *fc,
|
||||
struct fs_context *src_sc)
|
||||
LSM_HOOK(int, -ENOPARAM, fs_context_parse_param, struct fs_context *fc,
|
||||
|
@ -269,10 +269,10 @@ bool pipe_is_unprivileged_user(void);
|
||||
|
||||
/* for F_SETPIPE_SZ and F_GETPIPE_SZ */
|
||||
int pipe_resize_ring(struct pipe_inode_info *pipe, unsigned int nr_slots);
|
||||
long pipe_fcntl(struct file *, unsigned int, unsigned long arg);
|
||||
long pipe_fcntl(struct file *, unsigned int, unsigned int arg);
|
||||
struct pipe_inode_info *get_pipe_info(struct file *file, bool for_splice);
|
||||
|
||||
int create_pipe_files(struct file **, int);
|
||||
unsigned int round_pipe_size(unsigned long size);
|
||||
unsigned int round_pipe_size(unsigned int size);
|
||||
|
||||
#endif
|
||||
|
@ -293,6 +293,7 @@ int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file);
|
||||
int security_bprm_check(struct linux_binprm *bprm);
|
||||
void security_bprm_committing_creds(struct linux_binprm *bprm);
|
||||
void security_bprm_committed_creds(struct linux_binprm *bprm);
|
||||
int security_fs_context_submount(struct fs_context *fc, struct super_block *reference);
|
||||
int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc);
|
||||
int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param);
|
||||
int security_sb_alloc(struct super_block *sb);
|
||||
@ -629,6 +630,11 @@ static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int security_fs_context_submount(struct fs_context *fc,
|
||||
struct super_block *reference)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int security_fs_context_dup(struct fs_context *fc,
|
||||
struct fs_context *src_fc)
|
||||
{
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ramfs.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfs_fs_sb.h>
|
||||
@ -71,12 +72,37 @@ static int __init rootwait_setup(char *str)
|
||||
{
|
||||
if (*str)
|
||||
return 0;
|
||||
root_wait = 1;
|
||||
root_wait = -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("rootwait", rootwait_setup);
|
||||
|
||||
static int __init rootwait_timeout_setup(char *str)
|
||||
{
|
||||
int sec;
|
||||
|
||||
if (kstrtoint(str, 0, &sec) || sec < 0) {
|
||||
pr_warn("ignoring invalid rootwait value\n");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
if (check_mul_overflow(sec, MSEC_PER_SEC, &root_wait)) {
|
||||
pr_warn("ignoring excessive rootwait value\n");
|
||||
goto ignore;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
ignore:
|
||||
/* Fallback to indefinite wait */
|
||||
root_wait = -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("rootwait=", rootwait_timeout_setup);
|
||||
|
||||
static char * __initdata root_mount_data;
|
||||
static int __init root_data_setup(char *str)
|
||||
{
|
||||
@ -384,14 +410,22 @@ void __init mount_root(char *root_device_name)
|
||||
/* wait for any asynchronous scanning to complete */
|
||||
static void __init wait_for_root(char *root_device_name)
|
||||
{
|
||||
ktime_t end;
|
||||
|
||||
if (ROOT_DEV != 0)
|
||||
return;
|
||||
|
||||
pr_info("Waiting for root device %s...\n", root_device_name);
|
||||
|
||||
end = ktime_add_ms(ktime_get_raw(), root_wait);
|
||||
|
||||
while (!driver_probe_done() ||
|
||||
early_lookup_bdev(root_device_name, &ROOT_DEV) < 0)
|
||||
early_lookup_bdev(root_device_name, &ROOT_DEV) < 0) {
|
||||
msleep(5);
|
||||
if (root_wait > 0 && ktime_after(ktime_get_raw(), end))
|
||||
break;
|
||||
}
|
||||
|
||||
async_synchronize_full();
|
||||
|
||||
}
|
||||
|
@ -220,17 +220,12 @@ static bool io_rw_should_reissue(struct io_kiocb *req)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void kiocb_end_write(struct io_kiocb *req)
|
||||
static void io_req_end_write(struct io_kiocb *req)
|
||||
{
|
||||
/*
|
||||
* Tell lockdep we inherited freeze protection from submission
|
||||
* thread.
|
||||
*/
|
||||
if (req->flags & REQ_F_ISREG) {
|
||||
struct super_block *sb = file_inode(req->file)->i_sb;
|
||||
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
||||
|
||||
__sb_writers_acquired(sb, SB_FREEZE_WRITE);
|
||||
sb_end_write(sb);
|
||||
kiocb_end_write(&rw->kiocb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +238,7 @@ static void io_req_io_end(struct io_kiocb *req)
|
||||
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
||||
|
||||
if (rw->kiocb.ki_flags & IOCB_WRITE) {
|
||||
kiocb_end_write(req);
|
||||
io_req_end_write(req);
|
||||
fsnotify_modify(req->file);
|
||||
} else {
|
||||
fsnotify_access(req->file);
|
||||
@ -313,7 +308,7 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(rw);
|
||||
|
||||
if (kiocb->ki_flags & IOCB_WRITE)
|
||||
kiocb_end_write(req);
|
||||
io_req_end_write(req);
|
||||
if (unlikely(res != req->cqe.res)) {
|
||||
if (res == -EAGAIN && io_rw_should_reissue(req)) {
|
||||
req->flags |= REQ_F_REISSUE | REQ_F_PARTIAL_IO;
|
||||
@ -902,18 +897,8 @@ int io_write(struct io_kiocb *req, unsigned int issue_flags)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open-code file_start_write here to grab freeze protection,
|
||||
* which will be released by another thread in
|
||||
* io_complete_rw(). Fool lockdep by telling it the lock got
|
||||
* released so that it doesn't complain about the held lock when
|
||||
* we return to userspace.
|
||||
*/
|
||||
if (req->flags & REQ_F_ISREG) {
|
||||
sb_start_write(file_inode(req->file)->i_sb);
|
||||
__sb_writers_release(file_inode(req->file)->i_sb,
|
||||
SB_FREEZE_WRITE);
|
||||
}
|
||||
if (req->flags & REQ_F_ISREG)
|
||||
kiocb_start_write(kiocb);
|
||||
kiocb->ki_flags |= IOCB_WRITE;
|
||||
|
||||
if (likely(req->file->f_op->write_iter))
|
||||
@ -961,7 +946,7 @@ int io_write(struct io_kiocb *req, unsigned int issue_flags)
|
||||
io->bytes_done += ret2;
|
||||
|
||||
if (kiocb->ki_flags & IOCB_WRITE)
|
||||
kiocb_end_write(req);
|
||||
io_req_end_write(req);
|
||||
return ret ? ret : -EAGAIN;
|
||||
}
|
||||
done:
|
||||
@ -972,7 +957,7 @@ copy_iov:
|
||||
ret = io_setup_async_rw(req, iovec, s, false);
|
||||
if (!ret) {
|
||||
if (kiocb->ki_flags & IOCB_WRITE)
|
||||
kiocb_end_write(req);
|
||||
io_req_end_write(req);
|
||||
return -EAGAIN;
|
||||
}
|
||||
return ret;
|
||||
|
@ -1138,6 +1138,20 @@ void security_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
call_void_hook(bprm_committed_creds, bprm);
|
||||
}
|
||||
|
||||
/**
|
||||
* security_fs_context_submount() - Initialise fc->security
|
||||
* @fc: new filesystem context
|
||||
* @reference: dentry reference for submount/remount
|
||||
*
|
||||
* Fill out the ->security field for a new fs_context.
|
||||
*
|
||||
* Return: Returns 0 on success or negative error code on failure.
|
||||
*/
|
||||
int security_fs_context_submount(struct fs_context *fc, struct super_block *reference)
|
||||
{
|
||||
return call_int_hook(fs_context_submount, 0, fc, reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* security_fs_context_dup() - Duplicate a fs_context LSM blob
|
||||
* @fc: destination filesystem context
|
||||
|
@ -2745,6 +2745,27 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
|
||||
FILESYSTEM__UNMOUNT, NULL);
|
||||
}
|
||||
|
||||
static int selinux_fs_context_submount(struct fs_context *fc,
|
||||
struct super_block *reference)
|
||||
{
|
||||
const struct superblock_security_struct *sbsec;
|
||||
struct selinux_mnt_opts *opts;
|
||||
|
||||
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
|
||||
if (!opts)
|
||||
return -ENOMEM;
|
||||
|
||||
sbsec = selinux_superblock(reference);
|
||||
if (sbsec->flags & FSCONTEXT_MNT)
|
||||
opts->fscontext_sid = sbsec->sid;
|
||||
if (sbsec->flags & CONTEXT_MNT)
|
||||
opts->context_sid = sbsec->mntpoint_sid;
|
||||
if (sbsec->flags & DEFCONTEXT_MNT)
|
||||
opts->defcontext_sid = sbsec->def_sid;
|
||||
fc->security = opts;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int selinux_fs_context_dup(struct fs_context *fc,
|
||||
struct fs_context *src_fc)
|
||||
{
|
||||
@ -7182,6 +7203,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
|
||||
/*
|
||||
* PUT "CLONING" (ACCESSING + ALLOCATING) HOOKS HERE
|
||||
*/
|
||||
LSM_HOOK_INIT(fs_context_submount, selinux_fs_context_submount),
|
||||
LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
|
||||
LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
|
||||
LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
|
||||
|
@ -614,6 +614,56 @@ out_opt_err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_fs_context_submount - Initialise security data for a filesystem context
|
||||
* @fc: The filesystem context.
|
||||
* @reference: reference superblock
|
||||
*
|
||||
* Returns 0 on success or -ENOMEM on error.
|
||||
*/
|
||||
static int smack_fs_context_submount(struct fs_context *fc,
|
||||
struct super_block *reference)
|
||||
{
|
||||
struct superblock_smack *sbsp;
|
||||
struct smack_mnt_opts *ctx;
|
||||
struct inode_smack *isp;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
fc->security = ctx;
|
||||
|
||||
sbsp = smack_superblock(reference);
|
||||
isp = smack_inode(reference->s_root->d_inode);
|
||||
|
||||
if (sbsp->smk_default) {
|
||||
ctx->fsdefault = kstrdup(sbsp->smk_default->smk_known, GFP_KERNEL);
|
||||
if (!ctx->fsdefault)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (sbsp->smk_floor) {
|
||||
ctx->fsfloor = kstrdup(sbsp->smk_floor->smk_known, GFP_KERNEL);
|
||||
if (!ctx->fsfloor)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (sbsp->smk_hat) {
|
||||
ctx->fshat = kstrdup(sbsp->smk_hat->smk_known, GFP_KERNEL);
|
||||
if (!ctx->fshat)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
|
||||
if (sbsp->smk_root) {
|
||||
ctx->fstransmute = kstrdup(sbsp->smk_root->smk_known, GFP_KERNEL);
|
||||
if (!ctx->fstransmute)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_fs_context_dup - Duplicate the security data on fs_context duplication
|
||||
* @fc: The new filesystem context.
|
||||
@ -4876,6 +4926,7 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
|
||||
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
|
||||
LSM_HOOK_INIT(syslog, smack_syslog),
|
||||
|
||||
LSM_HOOK_INIT(fs_context_submount, smack_fs_context_submount),
|
||||
LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup),
|
||||
LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user