Linux 5.4.88
Greg Kroah-Hartman
maintainerI'm announcing the release of the 5.4.88 kernel.
All users of the 5.4 kernel series must upgrade.
The updated 5.4.y git tree can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-5.4.y
and can be browsed at the normal kernel.org git web browser:
https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary
thanks,
greg k-h
------------
Makefile | 2 drivers/dma/at_hdmac.c | 11 +++- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 - drivers/iio/imu/bmi160/bmi160.h | 7 ++ drivers/iio/imu/bmi160/bmi160_core.c | 6 -- drivers/mtd/nand/spi/core.c | 4 - drivers/net/wireless/marvell/mwifiex/join.c | 2 fs/exec.c | 12 ++--- fs/fuse/acl.c | 6 ++ fs/fuse/dir.c | 37 +++++++++++++-- fs/fuse/file.c | 19 ++++---- fs/fuse/fuse_i.h | 12 +++++ fs/fuse/inode.c | 4 - fs/fuse/readdir.c | 4 - fs/fuse/xattr.c | 9 +++ fs/proc/base.c | 10 ++-- include/linux/kdev_t.h | 22 ++++----- include/linux/rwsem.h | 3 + include/linux/sched/signal.h | 11 ++-- init/init_task.c | 2 kernel/events/core.c | 52 +++++++++++----------- kernel/fork.c | 6 +- kernel/kcmp.c | 30 ++++++------ kernel/locking/rwsem.c | 40 ++++++++++++++++ 24 files changed, 211 insertions(+), 103 deletions(-)
Alex Deucher (1):
Revert "drm/amd/display: Fix memory leaks in S3 resume"
Eric W. Biederman (3):
rwsem: Implement down_read_killable_nested
rwsem: Implement down_read_interruptible
exec: Transform exec_update_mutex into a rw_semaphore
Felix Fietkau (1):
Revert "mtd: spinand: Fix OOB read"
Greg Kroah-Hartman (1):
Linux 5.4.88
Jonathan Cameron (1):
iio:imu:bmi160: Fix alignment and data leak issues
Josh Poimboeuf (1):
kdev_t: always inline major/minor helper functions
Miklos Szeredi (1):
fuse: fix bad inode
Tudor Ambarus (1):
dmaengine: at_hdmac: Substitute kzalloc with kmalloc
Yu Kuai (2):
dmaengine: at_hdmac: add missing put_device() call in at_dma_xlate()
dmaengine: at_hdmac: add missing kfree() call in at_dma_xlate()
Zhang Xiaohui (1):
mwifiex: Fix possible buffer overflows in mwifiex_cmd_802_11_ad_hoc_start
[email protected] (1):
perf: Break deadlock involving exec_update_mutex
Greg Kroah-Hartman
maintainerMakefile +1 -1
@@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 5 PATCHLEVEL = 4 -SUBLEVEL = 87 +SUBLEVEL = 88 EXTRAVERSION = NAME = Kleptomaniac Octopus
drivers/dma/at_hdmac.c +8 -3
@@ -1673,9 +1673,11 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,dma_cap_zero (mask);dma_cap_set (DMA_SLAVE , mask); - atslave =kzalloc (sizeof (*atslave),GFP_KERNEL ); -if (!atslave) + atslave =kmalloc (sizeof (*atslave),GFP_KERNEL ); +if (!atslave) { +put_device (&dmac_pdev->dev);return NULL ; + } atslave->cfg =ATC_DST_H2SEL_HW |ATC_SRC_H2SEL_HW ;/*
@@ -1704,8 +1706,11 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec, atslave->dma_dev = &dmac_pdev->dev; chan =dma_request_channel (mask, at_dma_filter, atslave); -if (!chan) +if (!chan) { +put_device (&dmac_pdev->dev); +kfree (atslave);return NULL ; + } atchan =to_at_dma_chan (chan); atchan->per_if = dma_spec->args[0 ] &0xff ;
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +1 -2
@@ -1434,8 +1434,7 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)drm_connector_update_edid_property (connector, aconnector->edid); - aconnector->num_modes =drm_add_edid_modes (connector, aconnector->edid); -drm_connector_list_update (connector); +drm_add_edid_modes (connector, aconnector->edid);if (aconnector->dc_link->aux_mode) drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
drivers/iio/imu/bmi160/bmi160.h +7 -0
@@ -7,6 +7,13 @@struct bmi160_data {struct regmap *regmap;struct iio_trigger *trig; +/* +* Ensure natural alignment for timestamp if present. +* Max length needed: 2 * 3 channels + 4 bytes padding + 8 byte ts. +* If fewer channels are enabled, less space may be needed, as +* long as the timestamp is still aligned to 8 bytes. +*/ +__le16 buf[12 ]__aligned(8) ; };extern const struct regmap_config bmi160_regmap_config;
drivers/iio/imu/bmi160/bmi160_core.c +2 -4
@@ -411,8 +411,6 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)struct iio_poll_func *pf = p;struct iio_dev *indio_dev = pf->indio_dev;struct bmi160_data *data =iio_priv (indio_dev); -__le16 buf[12 ]; -/* 2 sens x 3 axis x __le16 + 2 x __le16 pad + 4 x __le16 tstamp */ int i, ret, j =0 , base =BMI160_REG_DATA_MAGN_XOUT_L ;__le16 sample;
@@ -422,10 +420,10 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p) &sample, sizeof(sample));if (ret) goto done; - buf[j++] = sample; + data->buf[j++] = sample; } -iio_push_to_buffers_with_timestamp (indio_dev, buf, pf->timestamp); +iio_push_to_buffers_with_timestamp (indio_dev, data->buf, pf->timestamp); done:iio_trigger_notify_done (indio_dev->trig);return IRQ_HANDLED ;
drivers/mtd/nand/spi/core.c +0 -4
@@ -317,10 +317,6 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, buf += ret; } -if (req->ooblen) -memcpy (req->oobbuf.in, spinand->oobbuf + req->ooboffs, - req->ooblen); -return 0 ; }
drivers/net/wireless/marvell/mwifiex/join.c +2 -0
@@ -877,6 +877,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,memset (adhoc_start->ssid,0 ,IEEE80211_MAX_SSID_LEN ); +if (req_ssid->ssid_len >IEEE80211_MAX_SSID_LEN ) + req_ssid->ssid_len =IEEE80211_MAX_SSID_LEN ;memcpy (adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len); mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n",
fs/exec.c +6 -6
@@ -1009,8 +1009,8 @@ EXPORT_SYMBOL(read_code);/* * Maps the mm_struct mm into the current task struct. -* On success, this function returns with the mutex -* exec_update_mutex locked. +* On success, this function returns with exec_update_lock +* held for writing. */ static int exec_mmap (struct mm_struct *mm) {
@@ -1023,7 +1023,7 @@ static int exec_mmap(struct mm_struct *mm) old_mm = current->mm;exec_mm_release (tsk, old_mm); - ret =mutex_lock_killable (&tsk->signal->exec_update_mutex); + ret =down_write_killable (&tsk->signal->exec_update_lock);if (ret)return ret;
@@ -1038,7 +1038,7 @@ static int exec_mmap(struct mm_struct *mm)down_read (&old_mm->mmap_sem);if (unlikely (old_mm->core_state)) {up_read (&old_mm->mmap_sem); -mutex_unlock (&tsk->signal->exec_update_mutex); +up_write (&tsk->signal->exec_update_lock);return -EINTR ; } }
@@ -1450,7 +1450,7 @@ static void free_bprm(struct linux_binprm *bprm)free_arg_pages (bprm);if (bprm->cred) {if (bprm->called_exec_mmap) -mutex_unlock (¤t->signal->exec_update_mutex); +up_write (¤t->signal->exec_update_lock);mutex_unlock (¤t->signal->cred_guard_mutex);abort_creds (bprm->cred); }
@@ -1500,7 +1500,7 @@ void install_exec_creds(struct linux_binprm *bprm)* credentials; any time after this it may be unlocked. */ security_bprm_committed_creds (bprm); -mutex_unlock (¤t->signal->exec_update_mutex); +up_write (¤t->signal->exec_update_lock);mutex_unlock (¤t->signal->cred_guard_mutex); }EXPORT_SYMBOL (install_exec_creds);
fs/fuse/acl.c +6 -0
@@ -19,6 +19,9 @@ struct posix_acl *fuse_get_acl(struct inode *inode, int type)void *value =NULL ;struct posix_acl *acl; +if (fuse_is_bad (inode)) +return ERR_PTR (-EIO ); +if (!fc->posix_acl || fc->no_getxattr)return NULL ;
@@ -53,6 +56,9 @@ int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type)const char *name;int ret; +if (fuse_is_bad (inode)) +return -EIO ; +if (!fc->posix_acl || fc->no_setxattr)return -EOPNOTSUPP ;
fs/fuse/dir.c +32 -5
@@ -201,7 +201,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)int ret; inode =d_inode_rcu (entry); -if (inode &&is_bad_inode (inode)) +if (inode &&fuse_is_bad (inode)) goto invalid;else if (time_before64 (fuse_dentry_time (entry),get_jiffies_64 ()) || (flags &LOOKUP_REVAL )) {
@@ -386,6 +386,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,bool outarg_valid = true;bool locked; +if (fuse_is_bad (dir)) +return ERR_PTR (-EIO ); + locked =fuse_lock_inode (dir); err =fuse_lookup_name (dir->i_sb,get_node_id (dir), &entry->d_name, &outarg, &inode);
@@ -529,6 +532,9 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,struct fuse_conn *fc =get_fuse_conn (dir);struct dentry *res =NULL ; +if (fuse_is_bad (dir)) +return -EIO ; +if (d_in_lookup (entry)) { res =fuse_lookup (dir, entry,0 );if (IS_ERR (res))
@@ -577,6 +583,9 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,int err;struct fuse_forget_link *forget; +if (fuse_is_bad (dir)) +return -EIO ; + forget =fuse_alloc_forget ();if (!forget)return -ENOMEM ;
@@ -704,6 +713,9 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)struct fuse_conn *fc =get_fuse_conn (dir);FUSE_ARGS (args); +if (fuse_is_bad (dir)) +return -EIO ; + args.opcode =FUSE_UNLINK ; args.nodeid =get_node_id (dir); args.in_numargs =1 ;
@@ -740,6 +752,9 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)struct fuse_conn *fc =get_fuse_conn (dir);FUSE_ARGS (args); +if (fuse_is_bad (dir)) +return -EIO ; + args.opcode =FUSE_RMDIR ; args.nodeid =get_node_id (dir); args.in_numargs =1 ;
@@ -818,6 +833,9 @@ static int fuse_rename2(struct inode *olddir, struct dentry *oldent,struct fuse_conn *fc =get_fuse_conn (olddir);int err; +if (fuse_is_bad (olddir)) +return -EIO ; +if (flags & ~(RENAME_NOREPLACE |RENAME_EXCHANGE ))return -EINVAL ;
@@ -953,7 +971,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,if (!err) {if (fuse_invalid_attr (&outarg.attr) || (inode->i_mode ^ outarg.attr.mode) &S_IFMT ) { -make_bad_inode (inode); +fuse_make_bad (inode); err = -EIO ; }else { fuse_change_attributes(inode, &outarg.attr,
@@ -1155,6 +1173,9 @@ static int fuse_permission(struct inode *inode, int mask)bool refreshed = false;int err =0 ; +if (fuse_is_bad (inode)) +return -EIO ; +if (!fuse_allow_current_process (fc))return -EACCES ;
@@ -1250,7 +1271,7 @@ static const char *fuse_get_link(struct dentry *dentry, struct inode *inode,int err; err = -EIO ; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode)) goto out_err;if (fc->cache_symlinks)
@@ -1298,7 +1319,7 @@ static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end,struct fuse_conn *fc =get_fuse_conn (inode);int err; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode))return -EIO ;if (fc->no_fsyncdir)
@@ -1575,7 +1596,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,if (fuse_invalid_attr (&outarg.attr) || (inode->i_mode ^ outarg.attr.mode) &S_IFMT ) { -make_bad_inode (inode); +fuse_make_bad (inode); err = -EIO ; goto error; }
@@ -1631,6 +1652,9 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)struct file *file = (attr->ia_valid &ATTR_FILE ) ? attr->ia_file :NULL ;int ret; +if (fuse_is_bad (inode)) +return -EIO ; +if (!fuse_allow_current_process (get_fuse_conn (inode)))return -EACCES ;
@@ -1689,6 +1713,9 @@ static int fuse_getattr(const struct path *path, struct kstat *stat,struct inode *inode =d_inode (path->dentry);struct fuse_conn *fc =get_fuse_conn (inode); +if (fuse_is_bad (inode)) +return -EIO ; +if (!fuse_allow_current_process (fc))return -EACCES ;
fs/fuse/file.c +11 -8
@@ -222,6 +222,9 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) fc->atomic_o_trunc && fc->writeback_cache; +if (fuse_is_bad (inode)) +return -EIO ; + err =generic_file_open (inode, file);if (err)return err;
@@ -443,7 +446,7 @@ static int fuse_flush(struct file *file, fl_owner_t id)FUSE_ARGS (args);int err; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode))return -EIO ;if (fc->no_flush)
@@ -506,7 +509,7 @@ static int fuse_fsync(struct file *file, loff_t start, loff_t end,struct fuse_conn *fc =get_fuse_conn (inode);int err; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode))return -EIO ;inode_lock (inode);
@@ -830,7 +833,7 @@ static int fuse_readpage(struct file *file, struct page *page)int err; err = -EIO ; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode)) goto out; err =fuse_do_readpage (file, page);
@@ -973,7 +976,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,int err; err = -EIO ; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode)) goto out; data.file = file;
@@ -1569,7 +1572,7 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)struct file *file = iocb->ki_filp;struct fuse_file *ff = file->private_data; -if (is_bad_inode (file_inode (file))) +if (fuse_is_bad (file_inode (file)))return -EIO ;if (!(ff->open_flags &FOPEN_DIRECT_IO ))
@@ -1583,7 +1586,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)struct file *file = iocb->ki_filp;struct fuse_file *ff = file->private_data; -if (is_bad_inode (file_inode (file))) +if (fuse_is_bad (file_inode (file)))return -EIO ;if (!(ff->open_flags &FOPEN_DIRECT_IO ))
@@ -2133,7 +2136,7 @@ static int fuse_writepages(struct address_space *mapping,int err; err = -EIO ; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode)) goto out; data.inode = inode;
@@ -2911,7 +2914,7 @@ long fuse_ioctl_common(struct file *file, unsigned int cmd,if (!fuse_allow_current_process (fc))return -EACCES ; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode))return -EIO ;return fuse_do_ioctl (file, cmd, arg, flags);
fs/fuse/fuse_i.h +12 -0
@@ -158,6 +158,8 @@ enum {FUSE_I_INIT_RDPLUS ,/** An operation changing file size is in progress */ FUSE_I_SIZE_UNSTABLE , +/* Bad inode */ + FUSE_I_BAD, };struct fuse_conn ;
@@ -787,6 +789,16 @@ static inline u64 fuse_get_attr_version(struct fuse_conn *fc)return atomic64_read (&fc->attr_version); } +static inline void fuse_make_bad (struct inode *inode) +{ +set_bit (FUSE_I_BAD , &get_fuse_inode (inode)->state); +} + +static inline bool fuse_is_bad (struct inode *inode) +{ +return unlikely (test_bit (FUSE_I_BAD , &get_fuse_inode (inode)->state)); +} +/** Device operations */ extern const struct file_operations fuse_dev_operations;
fs/fuse/inode.c +2 -2
@@ -115,7 +115,7 @@ static void fuse_evict_inode(struct inode *inode)fuse_queue_forget (fc, fi->forget, fi->nodeid, fi->nlookup); fi->forget =NULL ; } -if (S_ISREG (inode->i_mode) && !is_bad_inode (inode)) { +if (S_ISREG (inode->i_mode) && !fuse_is_bad (inode)) {WARN_ON (!list_empty (&fi->write_files));WARN_ON (!list_empty (&fi->queued_writes)); }
@@ -306,7 +306,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,unlock_new_inode (inode); }else if ((inode->i_mode ^ attr->mode) &S_IFMT ) {/* Inode has changed type, any I/O on the old should fail */ -make_bad_inode (inode); +fuse_make_bad (inode);iput (inode); goto retry; }
fs/fuse/readdir.c +2 -2
@@ -207,7 +207,7 @@ static int fuse_direntplus_link(struct file *file,dput (dentry); goto retry; } -if (is_bad_inode (inode)) { +if (fuse_is_bad (inode)) {dput (dentry);return -EIO ; }
@@ -568,7 +568,7 @@ int fuse_readdir(struct file *file, struct dir_context *ctx)struct inode *inode =file_inode (file);int err; -if (is_bad_inode (inode)) +if (fuse_is_bad (inode))return -EIO ;mutex_lock (&ff->readdir.lock);
fs/fuse/xattr.c +9 -0
@@ -113,6 +113,9 @@ ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)struct fuse_getxattr_out outarg;ssize_t ret; +if (fuse_is_bad (inode)) +return -EIO ; +if (!fuse_allow_current_process (fc))return -EACCES ;
@@ -178,6 +181,9 @@ static int fuse_xattr_get(const struct xattr_handler *handler, struct dentry *dentry, struct inode *inode, const char *name, void *value, size_t size) { + if (fuse_is_bad(inode)) + return -EIO; +return fuse_getxattr (inode, name, value, size); }
@@ -186,6 +192,9 @@ static int fuse_xattr_set(const struct xattr_handler *handler, const char *name, const void *value, size_t size, int flags) { + if (fuse_is_bad(inode)) + return -EIO; +if (!value)return fuse_removexattr (inode, name);
fs/proc/base.c +5 -5
@@ -403,11 +403,11 @@ static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,static int lock_trace (struct task_struct *task) { -int err =mutex_lock_killable (&task->signal->exec_update_mutex); +int err =down_read_killable (&task->signal->exec_update_lock);if (err)return err;if (!ptrace_may_access (task,PTRACE_MODE_ATTACH_FSCREDS )) { -mutex_unlock (&task->signal->exec_update_mutex); +up_read (&task->signal->exec_update_lock);return -EPERM ; }return 0 ;
@@ -415,7 +415,7 @@ static int lock_trace(struct task_struct *task)static void unlock_trace (struct task_struct *task) { -mutex_unlock (&task->signal->exec_update_mutex); +up_read (&task->signal->exec_update_lock); }#ifdef CONFIG_STACKTRACE
@@ -2769,7 +2769,7 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int whunsigned long flags;int result; - result =mutex_lock_killable (&task->signal->exec_update_mutex); + result =down_read_killable (&task->signal->exec_update_lock);if (result)return result;
@@ -2805,7 +2805,7 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int wh result =0 ; out_unlock: -mutex_unlock (&task->signal->exec_update_mutex); +up_read (&task->signal->exec_update_lock);return result; }
include/linux/kdev_t.h +11 -11
@@ -21,61 +21,61 @@ })/* acceptable for old filesystems */ -static inline bool old_valid_dev (dev_t dev) +static __always_inline bool old_valid_dev(dev_t dev) {return MAJOR (dev) <256 &&MINOR (dev) <256 ; } -static inline u16 old_encode_dev (dev_t dev) +static __always_inline u16 old_encode_dev(dev_t dev) {return (MAJOR (dev) <<8 ) |MINOR (dev); } -static inline dev_t old_decode_dev (u16 val) +static __always_inline dev_t old_decode_dev(u16 val) {return MKDEV ((val >>8 ) &255 , val &255 ); } -static inline u32 new_encode_dev (dev_t dev) +static __always_inline u32 new_encode_dev(dev_t dev) {unsigned major =MAJOR (dev);unsigned minor =MINOR (dev);return (minor &0xff ) | (major <<8 ) | ((minor & ~0xff ) <<12 ); } -static inline dev_t new_decode_dev (u32 dev) +static __always_inline dev_t new_decode_dev(u32 dev) {unsigned major = (dev &0xfff00 ) >>8 ;unsigned minor = (dev &0xff ) | ((dev >>12 ) &0xfff00 );return MKDEV (major, minor); } -static inline u64 huge_encode_dev (dev_t dev) +static __always_inline u64 huge_encode_dev(dev_t dev) {return new_encode_dev (dev); } -static inline dev_t huge_decode_dev (u64 dev) +static __always_inline dev_t huge_decode_dev(u64 dev) {return new_decode_dev (dev); } -static inline int sysv_valid_dev (dev_t dev) +static __always_inline int sysv_valid_dev(dev_t dev) {return MAJOR (dev) < (1 <<14 ) &&MINOR (dev) < (1 <<18 ); } -static inline u32 sysv_encode_dev (dev_t dev) +static __always_inline u32 sysv_encode_dev(dev_t dev) {return MINOR (dev) | (MAJOR (dev) <<18 ); } -static inline unsigned sysv_major (u32 dev) +static __always_inline unsigned sysv_major (u32 dev) {return (dev >>18 ) &0x3fff ; } -static inline unsigned sysv_minor (u32 dev) +static __always_inline unsigned sysv_minor (u32 dev) {return dev &0x3ffff ; }
include/linux/rwsem.h +3 -0
@@ -125,6 +125,7 @@ static inline int rwsem_is_contended(struct rw_semaphore *sem)* lock for reading */ extern void down_read (struct rw_semaphore *sem); +extern int __must_check down_read_interruptible (struct rw_semaphore *sem);extern int __must_check down_read_killable (struct rw_semaphore *sem);/*
@@ -173,6 +174,7 @@ extern void downgrade_write(struct rw_semaphore *sem);* See Documentation/locking/lockdep-design.rst for more details.) */ extern void down_read_nested (struct rw_semaphore *sem,int subclass); +extern int __must_check down_read_killable_nested (struct rw_semaphore *sem,int subclass);extern void down_write_nested (struct rw_semaphore *sem,int subclass);extern int down_write_killable_nested (struct rw_semaphore *sem,int subclass);extern void _down_write_nest_lock (struct rw_semaphore *sem,struct lockdep_map *nest_lock);
@@ -193,6 +195,7 @@ extern void down_read_non_owner(struct rw_semaphore *sem);extern void up_read_non_owner (struct rw_semaphore *sem);#else # define down_read_nested (sem, subclass) down_read(sem) +# define down_read_killable_nested (sem, subclass) down_read_killable(sem)# define down_write_nest_lock (sem, nest_lock) down_write(sem)# define down_write_nested (sem, subclass) down_write(sem)# define down_write_killable_nested (sem, subclass) down_write_killable(sem)
include/linux/sched/signal.h +6 -5
@@ -226,12 +226,13 @@ struct signal_struct {* credential calculations * (notably. ptrace) * Deprecated do not use in new code. -* Use exec_update_mutex instead. -*/ -struct mutex exec_update_mutex;/* Held while task_struct is being -* updated during exec, and may have -* inconsistent permissions. +* Use exec_update_lock instead. */ +struct rw_semaphore exec_update_lock;/* Held while task_struct is +* being updated during exec, +* and may have inconsistent +* permissions. +*/ } __randomize_layout;/*
init/init_task.c +1 -1
@@ -26,7 +26,7 @@ static struct signal_struct init_signals = { .multiprocess = HLIST_HEAD_INIT, .rlim = INIT_RLIMITS, .cred_guard_mutex = __MUTEX_INITIALIZER(init_signals.cred_guard_mutex), - .exec_update_mutex =__MUTEX_INITIALIZER (init_signals.exec_update_mutex), + .exec_update_lock =__RWSEM_INITIALIZER (init_signals.exec_update_lock), #ifdef CONFIG_POSIX_TIMERS .posix_timers =LIST_HEAD_INIT (init_signals.posix_timers), .cputimer = {
kernel/events/core.c +26 -26
100 lines not on this page · raw message
kernel/fork.c +3 -3
@@ -1221,7 +1221,7 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)struct mm_struct *mm;int err; - err =mutex_lock_killable (&task->signal->exec_update_mutex); + err =down_read_killable (&task->signal->exec_update_lock);if (err)return ERR_PTR (err);
@@ -1231,7 +1231,7 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)mmput (mm); mm =ERR_PTR (-EACCES ); } -mutex_unlock (&task->signal->exec_update_mutex); +up_read (&task->signal->exec_update_lock);return mm; }
@@ -1586,7 +1586,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) sig->oom_score_adj_min = current->signal->oom_score_adj_min;mutex_init (&sig->cred_guard_mutex); -mutex_init (&sig->exec_update_mutex); +init_rwsem (&sig->exec_update_lock);return 0 ; }
kernel/kcmp.c +15 -15
@@ -75,25 +75,25 @@ get_file_raw_ptr(struct task_struct *task, unsigned int idx)return file; } -static void kcmp_unlock (struct mutex *m1,struct mutex *m2) +static void kcmp_unlock (struct rw_semaphore *l1,struct rw_semaphore *l2) { -if (likely (m2 != m1)) -mutex_unlock (m2); -mutex_unlock (m1); +if (likely (l2 != l1)) +up_read (l2); +up_read (l1); } -static int kcmp_lock (struct mutex *m1,struct mutex *m2) +static int kcmp_lock (struct rw_semaphore *l1,struct rw_semaphore *l2) {int err; -if (m2 > m1) -swap (m1, m2); +if (l2 > l1) +swap (l1, l2); - err =mutex_lock_killable (m1); -if (!err &&likely (m1 != m2)) { - err =mutex_lock_killable_nested (m2,SINGLE_DEPTH_NESTING ); + err =down_read_killable (l1); +if (!err &&likely (l1 != l2)) { + err =down_read_killable_nested (l2,SINGLE_DEPTH_NESTING );if (err) -mutex_unlock (m1); +up_read (l1); }return err;
@@ -173,8 +173,8 @@ SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type,/* * One should have enough rights to inspect task details. */ - ret =kcmp_lock (&task1->signal->exec_update_mutex, - &task2->signal->exec_update_mutex); + ret =kcmp_lock (&task1->signal->exec_update_lock, + &task2->signal->exec_update_lock);if (ret) goto err; if (!ptrace_may_access(task1, PTRACE_MODE_READ_REALCREDS) ||
@@ -229,8 +229,8 @@ SYSCALL_DEFINE5(kcmp, pid_t, pid1, pid_t, pid2, int, type, } err_unlock: -kcmp_unlock (&task1->signal->exec_update_mutex, - &task2->signal->exec_update_mutex); +kcmp_unlock (&task1->signal->exec_update_lock, + &task2->signal->exec_update_lock); err:put_task_struct (task1);put_task_struct (task2);
kernel/locking/rwsem.c +40 -0
@@ -1348,6 +1348,18 @@ inline void __down_read(struct rw_semaphore *sem) } } +static inline int __down_read_interruptible (struct rw_semaphore *sem) +{ +if (!rwsem_read_trylock (sem)) { +if (IS_ERR (rwsem_down_read_slowpath (sem,TASK_INTERRUPTIBLE ))) +return -EINTR ; +DEBUG_RWSEMS_WARN_ON (!is_rwsem_reader_owned (sem), sem); + }else { +rwsem_set_reader_owned (sem); + } +return 0 ; +} +static inline int __down_read_killable (struct rw_semaphore *sem) {if (!rwsem_read_trylock (sem)) {
@@ -1498,6 +1510,20 @@ void __sched down_read(struct rw_semaphore *sem) }EXPORT_SYMBOL (down_read); +int __sched down_read_interruptible(struct rw_semaphore *sem) +{ +might_sleep (); +rwsem_acquire_read (&sem->dep_map,0 ,0 , _RET_IP_); + +if (LOCK_CONTENDED_RETURN (sem, __down_read_trylock, __down_read_interruptible)) { +rwsem_release (&sem->dep_map,1 , _RET_IP_); +return -EINTR ; + } + +return 0 ; +} +EXPORT_SYMBOL (down_read_interruptible); + int __sched down_read_killable(struct rw_semaphore *sem) {might_sleep ();
@@ -1608,6 +1634,20 @@ void down_read_nested(struct rw_semaphore *sem, int subclass) }EXPORT_SYMBOL (down_read_nested); +int down_read_killable_nested (struct rw_semaphore *sem,int subclass) +{ +might_sleep (); +rwsem_acquire_read (&sem->dep_map, subclass,0 , _RET_IP_); + +if (LOCK_CONTENDED_RETURN (sem, __down_read_trylock, __down_read_killable)) { +rwsem_release (&sem->dep_map,1 , _RET_IP_); +return -EINTR ; + } + +return 0 ; +} +EXPORT_SYMBOL (down_read_killable_nested); +void _down_write_nest_lock (struct rw_semaphore *sem,struct lockdep_map *nest) {might_sleep ();