This is the 5.4.88 stable release
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAl/5pXIACgkQONu9yGCS aT5t7hAAqNuPKftShc3L/8QXk8m1K46Bx3J1s3o+P5vDFiAMVFNq+dKeN4XK9dnQ ePKTdLNW4woYp9laZREfImr4rJADG+AOQ0qVX06XQUkqgvqxBgIbCVWPngB6lUxV ojxjanoIAODo7IMZi2QfzaUVBlZaOpbKJa/Z9cju303k/vp+DJxhNpZ7RUfRiZIH nh3U6FnkTRAyPTi3H7iZteSTOQg4Av+zrDODqK1N9RL9qXwbMxQG9U9pl9XLD0Nb XaQ++ydGEB0dprix3WEe9pe1A1hIKlZ8lslSFYSt5DA3IY3YkKoAQPyhVcsG85YO 1HPiVa71kd4pLhJM3MlWAkunG8ZGf/Bx4Rvjac887HeyhQ8oxu3gFvNZDk2EFIv0 5GDfTOqZEv0Yp32GetM7hcMml3uH1dIG9Ib0iLkuNa6Kopus+Jor7YKrfy93iP2B nlB4LJorSRYNbOA/kEjToKEwA+v8ub4MHO8qBRJpkVtRVGHkR/jKLIyIYdXVXXFi C1emjB3qoRvbKed5mkkWpUhZG1mBDzmTK0Y/XqtbNlZktlolvRS/HTbOmke3G2C6 QWcbXtUZ+SlUM8uMYa0Z8lMMcl2rMHOj+ELg7D2XLOpViMIWbiRxYdLTlFAfKUUu kgwHOUuZa0iouvnmKE8tyypgiR+VAz+k74LOsHn3hHKV5U7203U= =/YH9 -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdQaENiSDAlGTDEbB7G51OISzHs0FAl/6HKYACgkQ7G51OISz Hs1fnA/5AaP6cas2PNb+8s4S2DYOxsLVSI1Oa6B0mgJfIf3OUBxoAEzMPAjevco7 6TgHk3zuhTzlS0HsQUKEg3ZLDLAoUysjjoo5hOuf1xDCBQ+1UAl3zZdebZEvXEIz 3vDqqkRiOnRH+dNjPwDM+5CIotZ8/8UbnoNMXe7E+WvSL823ucu1EdIeKkiCoa1d 7s4O4STZNg+k/6TS4mEDJ7aL0OioTppC0a+29uv+kH6DVUpSmCcUEeODOQN0KhnD 7CIUx0A3PtmLns8YndPRzj+V83p8rDuK48GRhdCWoV/zWlrmCXtvAHeUHMhBz0Z+ XTl3V+7PXtUtf6mljxdL37e4WCa6tLGIgLd6TPQTlffNQM/1ya057q0m04NWRb8C +4ue2bmb6upLLOtdKbb4e8T1kFuNaaA7eJr0hqYPYrcursuQ+6BDJrcEQBnxGlq4 LNDt2947yR31XnODRKhoL9n6lFGZErpFYQ8jedCy+orBnorum6nPfxaOAdEOJwUm Y1HtJjsfiqBx8euv7l1Pygf+01x8blb1ofx156SSNrCm1SbHI+9LXCWKpDsQaJ92 2ujyj1cUIw3ZrpPxkSHkVv2HjXdubOmYTy5+w82OswCtqKWVOr0B0vy9vHf//SRE ks7ElcT2iJixlRUt6MRkEUd6kDEEnuuTszhc7GaVEVBCM/Y500c= =uH8c -----END PGP SIGNATURE----- Merge tag 'v5.4.88' into 5.4-2.2.x-imx This is the 5.4.88 stable release Signed-off-by: Andrey Zhizhikin <andrey.zhizhikin@leica-geosystems.com>5.4-rM2-2.2.x-imx-squashed
commit
b8fcf77298
2
Makefile
2
Makefile
|
@ -1,7 +1,7 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
VERSION = 5
|
VERSION = 5
|
||||||
PATCHLEVEL = 4
|
PATCHLEVEL = 4
|
||||||
SUBLEVEL = 87
|
SUBLEVEL = 88
|
||||||
EXTRAVERSION =
|
EXTRAVERSION =
|
||||||
NAME = Kleptomaniac Octopus
|
NAME = Kleptomaniac Octopus
|
||||||
|
|
||||||
|
|
|
@ -1673,9 +1673,11 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
|
||||||
dma_cap_zero(mask);
|
dma_cap_zero(mask);
|
||||||
dma_cap_set(DMA_SLAVE, mask);
|
dma_cap_set(DMA_SLAVE, mask);
|
||||||
|
|
||||||
atslave = kzalloc(sizeof(*atslave), GFP_KERNEL);
|
atslave = kmalloc(sizeof(*atslave), GFP_KERNEL);
|
||||||
if (!atslave)
|
if (!atslave) {
|
||||||
|
put_device(&dmac_pdev->dev);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
atslave->cfg = ATC_DST_H2SEL_HW | ATC_SRC_H2SEL_HW;
|
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;
|
atslave->dma_dev = &dmac_pdev->dev;
|
||||||
|
|
||||||
chan = dma_request_channel(mask, at_dma_filter, atslave);
|
chan = dma_request_channel(mask, at_dma_filter, atslave);
|
||||||
if (!chan)
|
if (!chan) {
|
||||||
|
put_device(&dmac_pdev->dev);
|
||||||
|
kfree(atslave);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
atchan = to_at_dma_chan(chan);
|
atchan = to_at_dma_chan(chan);
|
||||||
atchan->per_if = dma_spec->args[0] & 0xff;
|
atchan->per_if = dma_spec->args[0] & 0xff;
|
||||||
|
|
|
@ -1434,8 +1434,7 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
|
||||||
|
|
||||||
drm_connector_update_edid_property(connector,
|
drm_connector_update_edid_property(connector,
|
||||||
aconnector->edid);
|
aconnector->edid);
|
||||||
aconnector->num_modes = drm_add_edid_modes(connector, aconnector->edid);
|
drm_add_edid_modes(connector, aconnector->edid);
|
||||||
drm_connector_list_update(connector);
|
|
||||||
|
|
||||||
if (aconnector->dc_link->aux_mode)
|
if (aconnector->dc_link->aux_mode)
|
||||||
drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
|
drm_dp_cec_set_edid(&aconnector->dm_dp_aux.aux,
|
||||||
|
|
|
@ -7,6 +7,13 @@
|
||||||
struct bmi160_data {
|
struct bmi160_data {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct iio_trigger *trig;
|
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;
|
extern const struct regmap_config bmi160_regmap_config;
|
||||||
|
|
|
@ -411,8 +411,6 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
|
||||||
struct iio_poll_func *pf = p;
|
struct iio_poll_func *pf = p;
|
||||||
struct iio_dev *indio_dev = pf->indio_dev;
|
struct iio_dev *indio_dev = pf->indio_dev;
|
||||||
struct bmi160_data *data = iio_priv(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;
|
int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L;
|
||||||
__le16 sample;
|
__le16 sample;
|
||||||
|
|
||||||
|
@ -422,10 +420,10 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p)
|
||||||
&sample, sizeof(sample));
|
&sample, sizeof(sample));
|
||||||
if (ret)
|
if (ret)
|
||||||
goto done;
|
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:
|
done:
|
||||||
iio_trigger_notify_done(indio_dev->trig);
|
iio_trigger_notify_done(indio_dev->trig);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
|
@ -317,10 +317,6 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
|
||||||
buf += ret;
|
buf += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->ooblen)
|
|
||||||
memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
|
|
||||||
req->ooblen);
|
|
||||||
|
|
||||||
return 0;
|
return 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);
|
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);
|
memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len);
|
||||||
|
|
||||||
mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n",
|
mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n",
|
||||||
|
|
12
fs/exec.c
12
fs/exec.c
|
@ -1009,8 +1009,8 @@ EXPORT_SYMBOL(read_code);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maps the mm_struct mm into the current task struct.
|
* Maps the mm_struct mm into the current task struct.
|
||||||
* On success, this function returns with the mutex
|
* On success, this function returns with exec_update_lock
|
||||||
* exec_update_mutex locked.
|
* held for writing.
|
||||||
*/
|
*/
|
||||||
static int exec_mmap(struct mm_struct *mm)
|
static int exec_mmap(struct mm_struct *mm)
|
||||||
{
|
{
|
||||||
|
@ -1023,7 +1023,7 @@ static int exec_mmap(struct mm_struct *mm)
|
||||||
old_mm = current->mm;
|
old_mm = current->mm;
|
||||||
exec_mm_release(tsk, old_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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -1038,7 +1038,7 @@ static int exec_mmap(struct mm_struct *mm)
|
||||||
down_read(&old_mm->mmap_sem);
|
down_read(&old_mm->mmap_sem);
|
||||||
if (unlikely(old_mm->core_state)) {
|
if (unlikely(old_mm->core_state)) {
|
||||||
up_read(&old_mm->mmap_sem);
|
up_read(&old_mm->mmap_sem);
|
||||||
mutex_unlock(&tsk->signal->exec_update_mutex);
|
up_write(&tsk->signal->exec_update_lock);
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1450,7 +1450,7 @@ static void free_bprm(struct linux_binprm *bprm)
|
||||||
free_arg_pages(bprm);
|
free_arg_pages(bprm);
|
||||||
if (bprm->cred) {
|
if (bprm->cred) {
|
||||||
if (bprm->called_exec_mmap)
|
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);
|
mutex_unlock(¤t->signal->cred_guard_mutex);
|
||||||
abort_creds(bprm->cred);
|
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.
|
* credentials; any time after this it may be unlocked.
|
||||||
*/
|
*/
|
||||||
security_bprm_committed_creds(bprm);
|
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);
|
mutex_unlock(¤t->signal->cred_guard_mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(install_exec_creds);
|
EXPORT_SYMBOL(install_exec_creds);
|
||||||
|
|
|
@ -19,6 +19,9 @@ struct posix_acl *fuse_get_acl(struct inode *inode, int type)
|
||||||
void *value = NULL;
|
void *value = NULL;
|
||||||
struct posix_acl *acl;
|
struct posix_acl *acl;
|
||||||
|
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return ERR_PTR(-EIO);
|
||||||
|
|
||||||
if (!fc->posix_acl || fc->no_getxattr)
|
if (!fc->posix_acl || fc->no_getxattr)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -53,6 +56,9 @@ int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type)
|
||||||
const char *name;
|
const char *name;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (!fc->posix_acl || fc->no_setxattr)
|
if (!fc->posix_acl || fc->no_setxattr)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
|
|
@ -201,7 +201,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
inode = d_inode_rcu(entry);
|
inode = d_inode_rcu(entry);
|
||||||
if (inode && is_bad_inode(inode))
|
if (inode && fuse_is_bad(inode))
|
||||||
goto invalid;
|
goto invalid;
|
||||||
else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
|
else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
|
||||||
(flags & LOOKUP_REVAL)) {
|
(flags & LOOKUP_REVAL)) {
|
||||||
|
@ -386,6 +386,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
|
||||||
bool outarg_valid = true;
|
bool outarg_valid = true;
|
||||||
bool locked;
|
bool locked;
|
||||||
|
|
||||||
|
if (fuse_is_bad(dir))
|
||||||
|
return ERR_PTR(-EIO);
|
||||||
|
|
||||||
locked = fuse_lock_inode(dir);
|
locked = fuse_lock_inode(dir);
|
||||||
err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
|
err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
|
||||||
&outarg, &inode);
|
&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 fuse_conn *fc = get_fuse_conn(dir);
|
||||||
struct dentry *res = NULL;
|
struct dentry *res = NULL;
|
||||||
|
|
||||||
|
if (fuse_is_bad(dir))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (d_in_lookup(entry)) {
|
if (d_in_lookup(entry)) {
|
||||||
res = fuse_lookup(dir, entry, 0);
|
res = fuse_lookup(dir, entry, 0);
|
||||||
if (IS_ERR(res))
|
if (IS_ERR(res))
|
||||||
|
@ -577,6 +583,9 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
|
||||||
int err;
|
int err;
|
||||||
struct fuse_forget_link *forget;
|
struct fuse_forget_link *forget;
|
||||||
|
|
||||||
|
if (fuse_is_bad(dir))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
forget = fuse_alloc_forget();
|
forget = fuse_alloc_forget();
|
||||||
if (!forget)
|
if (!forget)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -704,6 +713,9 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
|
||||||
struct fuse_conn *fc = get_fuse_conn(dir);
|
struct fuse_conn *fc = get_fuse_conn(dir);
|
||||||
FUSE_ARGS(args);
|
FUSE_ARGS(args);
|
||||||
|
|
||||||
|
if (fuse_is_bad(dir))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
args.opcode = FUSE_UNLINK;
|
args.opcode = FUSE_UNLINK;
|
||||||
args.nodeid = get_node_id(dir);
|
args.nodeid = get_node_id(dir);
|
||||||
args.in_numargs = 1;
|
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);
|
struct fuse_conn *fc = get_fuse_conn(dir);
|
||||||
FUSE_ARGS(args);
|
FUSE_ARGS(args);
|
||||||
|
|
||||||
|
if (fuse_is_bad(dir))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
args.opcode = FUSE_RMDIR;
|
args.opcode = FUSE_RMDIR;
|
||||||
args.nodeid = get_node_id(dir);
|
args.nodeid = get_node_id(dir);
|
||||||
args.in_numargs = 1;
|
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);
|
struct fuse_conn *fc = get_fuse_conn(olddir);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (fuse_is_bad(olddir))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
|
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -953,7 +971,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (fuse_invalid_attr(&outarg.attr) ||
|
if (fuse_invalid_attr(&outarg.attr) ||
|
||||||
(inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
|
(inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
|
||||||
make_bad_inode(inode);
|
fuse_make_bad(inode);
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
} else {
|
} else {
|
||||||
fuse_change_attributes(inode, &outarg.attr,
|
fuse_change_attributes(inode, &outarg.attr,
|
||||||
|
@ -1155,6 +1173,9 @@ static int fuse_permission(struct inode *inode, int mask)
|
||||||
bool refreshed = false;
|
bool refreshed = false;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (!fuse_allow_current_process(fc))
|
if (!fuse_allow_current_process(fc))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
@ -1250,7 +1271,7 @@ static const char *fuse_get_link(struct dentry *dentry, struct inode *inode,
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
if (fc->cache_symlinks)
|
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);
|
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (fc->no_fsyncdir)
|
if (fc->no_fsyncdir)
|
||||||
|
@ -1575,7 +1596,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
|
||||||
|
|
||||||
if (fuse_invalid_attr(&outarg.attr) ||
|
if (fuse_invalid_attr(&outarg.attr) ||
|
||||||
(inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
|
(inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
|
||||||
make_bad_inode(inode);
|
fuse_make_bad(inode);
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
goto error;
|
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;
|
struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (!fuse_allow_current_process(get_fuse_conn(inode)))
|
if (!fuse_allow_current_process(get_fuse_conn(inode)))
|
||||||
return -EACCES;
|
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 inode *inode = d_inode(path->dentry);
|
||||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||||
|
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (!fuse_allow_current_process(fc))
|
if (!fuse_allow_current_process(fc))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,9 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
|
||||||
fc->atomic_o_trunc &&
|
fc->atomic_o_trunc &&
|
||||||
fc->writeback_cache;
|
fc->writeback_cache;
|
||||||
|
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
err = generic_file_open(inode, file);
|
err = generic_file_open(inode, file);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
@ -443,7 +446,7 @@ static int fuse_flush(struct file *file, fl_owner_t id)
|
||||||
FUSE_ARGS(args);
|
FUSE_ARGS(args);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (fc->no_flush)
|
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);
|
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
inode_lock(inode);
|
inode_lock(inode);
|
||||||
|
@ -830,7 +833,7 @@ static int fuse_readpage(struct file *file, struct page *page)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err = fuse_do_readpage(file, page);
|
err = fuse_do_readpage(file, page);
|
||||||
|
@ -973,7 +976,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
data.file = file;
|
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 file *file = iocb->ki_filp;
|
||||||
struct fuse_file *ff = file->private_data;
|
struct fuse_file *ff = file->private_data;
|
||||||
|
|
||||||
if (is_bad_inode(file_inode(file)))
|
if (fuse_is_bad(file_inode(file)))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (!(ff->open_flags & FOPEN_DIRECT_IO))
|
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 file *file = iocb->ki_filp;
|
||||||
struct fuse_file *ff = file->private_data;
|
struct fuse_file *ff = file->private_data;
|
||||||
|
|
||||||
if (is_bad_inode(file_inode(file)))
|
if (fuse_is_bad(file_inode(file)))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (!(ff->open_flags & FOPEN_DIRECT_IO))
|
if (!(ff->open_flags & FOPEN_DIRECT_IO))
|
||||||
|
@ -2133,7 +2136,7 @@ static int fuse_writepages(struct address_space *mapping,
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
data.inode = inode;
|
data.inode = inode;
|
||||||
|
@ -2911,7 +2914,7 @@ long fuse_ioctl_common(struct file *file, unsigned int cmd,
|
||||||
if (!fuse_allow_current_process(fc))
|
if (!fuse_allow_current_process(fc))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
return fuse_do_ioctl(file, cmd, arg, flags);
|
return fuse_do_ioctl(file, cmd, arg, flags);
|
||||||
|
|
|
@ -158,6 +158,8 @@ enum {
|
||||||
FUSE_I_INIT_RDPLUS,
|
FUSE_I_INIT_RDPLUS,
|
||||||
/** An operation changing file size is in progress */
|
/** An operation changing file size is in progress */
|
||||||
FUSE_I_SIZE_UNSTABLE,
|
FUSE_I_SIZE_UNSTABLE,
|
||||||
|
/* Bad inode */
|
||||||
|
FUSE_I_BAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fuse_conn;
|
struct fuse_conn;
|
||||||
|
@ -787,6 +789,16 @@ static inline u64 fuse_get_attr_version(struct fuse_conn *fc)
|
||||||
return atomic64_read(&fc->attr_version);
|
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 */
|
/** Device operations */
|
||||||
extern const struct file_operations fuse_dev_operations;
|
extern const struct file_operations fuse_dev_operations;
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ static void fuse_evict_inode(struct inode *inode)
|
||||||
fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup);
|
fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup);
|
||||||
fi->forget = NULL;
|
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->write_files));
|
||||||
WARN_ON(!list_empty(&fi->queued_writes));
|
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);
|
unlock_new_inode(inode);
|
||||||
} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
|
} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
|
||||||
/* Inode has changed type, any I/O on the old should fail */
|
/* Inode has changed type, any I/O on the old should fail */
|
||||||
make_bad_inode(inode);
|
fuse_make_bad(inode);
|
||||||
iput(inode);
|
iput(inode);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@ retry:
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
if (is_bad_inode(inode)) {
|
if (fuse_is_bad(inode)) {
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
@ -568,7 +568,7 @@ int fuse_readdir(struct file *file, struct dir_context *ctx)
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (is_bad_inode(inode))
|
if (fuse_is_bad(inode))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
mutex_lock(&ff->readdir.lock);
|
mutex_lock(&ff->readdir.lock);
|
||||||
|
|
|
@ -113,6 +113,9 @@ ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
|
||||||
struct fuse_getxattr_out outarg;
|
struct fuse_getxattr_out outarg;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (!fuse_allow_current_process(fc))
|
if (!fuse_allow_current_process(fc))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
|
@ -178,6 +181,9 @@ static int fuse_xattr_get(const struct xattr_handler *handler,
|
||||||
struct dentry *dentry, struct inode *inode,
|
struct dentry *dentry, struct inode *inode,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
return fuse_getxattr(inode, name, value, size);
|
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,
|
const char *name, const void *value, size_t size,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
|
if (fuse_is_bad(inode))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
return fuse_removexattr(inode, name);
|
return fuse_removexattr(inode, name);
|
||||||
|
|
||||||
|
|
|
@ -403,11 +403,11 @@ print0:
|
||||||
|
|
||||||
static int lock_trace(struct task_struct *task)
|
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)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) {
|
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 -EPERM;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -415,7 +415,7 @@ static int lock_trace(struct task_struct *task)
|
||||||
|
|
||||||
static void unlock_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
|
#ifdef CONFIG_STACKTRACE
|
||||||
|
@ -2769,7 +2769,7 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int wh
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = mutex_lock_killable(&task->signal->exec_update_mutex);
|
result = down_read_killable(&task->signal->exec_update_lock);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
@ -2805,7 +2805,7 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int wh
|
||||||
result = 0;
|
result = 0;
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&task->signal->exec_update_mutex);
|
up_read(&task->signal->exec_update_lock);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,61 +21,61 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
/* acceptable for old filesystems */
|
/* 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;
|
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);
|
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);
|
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 major = MAJOR(dev);
|
||||||
unsigned minor = MINOR(dev);
|
unsigned minor = MINOR(dev);
|
||||||
return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
|
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 major = (dev & 0xfff00) >> 8;
|
||||||
unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
|
unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
|
||||||
return MKDEV(major, minor);
|
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);
|
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);
|
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);
|
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);
|
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;
|
return (dev >> 18) & 0x3fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned sysv_minor(u32 dev)
|
static __always_inline unsigned sysv_minor(u32 dev)
|
||||||
{
|
{
|
||||||
return dev & 0x3ffff;
|
return dev & 0x3ffff;
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,7 @@ static inline int rwsem_is_contended(struct rw_semaphore *sem)
|
||||||
* lock for reading
|
* lock for reading
|
||||||
*/
|
*/
|
||||||
extern void down_read(struct rw_semaphore *sem);
|
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);
|
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.)
|
* See Documentation/locking/lockdep-design.rst for more details.)
|
||||||
*/
|
*/
|
||||||
extern void down_read_nested(struct rw_semaphore *sem, int subclass);
|
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 void down_write_nested(struct rw_semaphore *sem, int subclass);
|
||||||
extern int down_write_killable_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);
|
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);
|
extern void up_read_non_owner(struct rw_semaphore *sem);
|
||||||
#else
|
#else
|
||||||
# define down_read_nested(sem, subclass) down_read(sem)
|
# 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_nest_lock(sem, nest_lock) down_write(sem)
|
||||||
# define down_write_nested(sem, subclass) down_write(sem)
|
# define down_write_nested(sem, subclass) down_write(sem)
|
||||||
# define down_write_killable_nested(sem, subclass) down_write_killable(sem)
|
# define down_write_killable_nested(sem, subclass) down_write_killable(sem)
|
||||||
|
|
|
@ -226,12 +226,13 @@ struct signal_struct {
|
||||||
* credential calculations
|
* credential calculations
|
||||||
* (notably. ptrace)
|
* (notably. ptrace)
|
||||||
* Deprecated do not use in new code.
|
* Deprecated do not use in new code.
|
||||||
* Use exec_update_mutex instead.
|
* Use exec_update_lock instead.
|
||||||
*/
|
|
||||||
struct mutex exec_update_mutex; /* Held while task_struct is being
|
|
||||||
* updated during exec, and may have
|
|
||||||
* inconsistent permissions.
|
|
||||||
*/
|
*/
|
||||||
|
struct rw_semaphore exec_update_lock; /* Held while task_struct is
|
||||||
|
* being updated during exec,
|
||||||
|
* and may have inconsistent
|
||||||
|
* permissions.
|
||||||
|
*/
|
||||||
} __randomize_layout;
|
} __randomize_layout;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -26,7 +26,7 @@ static struct signal_struct init_signals = {
|
||||||
.multiprocess = HLIST_HEAD_INIT,
|
.multiprocess = HLIST_HEAD_INIT,
|
||||||
.rlim = INIT_RLIMITS,
|
.rlim = INIT_RLIMITS,
|
||||||
.cred_guard_mutex = __MUTEX_INITIALIZER(init_signals.cred_guard_mutex),
|
.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
|
#ifdef CONFIG_POSIX_TIMERS
|
||||||
.posix_timers = LIST_HEAD_INIT(init_signals.posix_timers),
|
.posix_timers = LIST_HEAD_INIT(init_signals.posix_timers),
|
||||||
.cputimer = {
|
.cputimer = {
|
||||||
|
|
|
@ -1254,7 +1254,7 @@ static void put_ctx(struct perf_event_context *ctx)
|
||||||
* function.
|
* function.
|
||||||
*
|
*
|
||||||
* Lock order:
|
* Lock order:
|
||||||
* exec_update_mutex
|
* exec_update_lock
|
||||||
* task_struct::perf_event_mutex
|
* task_struct::perf_event_mutex
|
||||||
* perf_event_context::mutex
|
* perf_event_context::mutex
|
||||||
* perf_event::child_mutex;
|
* perf_event::child_mutex;
|
||||||
|
@ -11001,24 +11001,6 @@ SYSCALL_DEFINE5(perf_event_open,
|
||||||
goto err_task;
|
goto err_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (task) {
|
|
||||||
err = mutex_lock_interruptible(&task->signal->exec_update_mutex);
|
|
||||||
if (err)
|
|
||||||
goto err_task;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reuse ptrace permission checks for now.
|
|
||||||
*
|
|
||||||
* We must hold exec_update_mutex across this and any potential
|
|
||||||
* perf_install_in_context() call for this new event to
|
|
||||||
* serialize against exec() altering our credentials (and the
|
|
||||||
* perf_event_exit_task() that could imply).
|
|
||||||
*/
|
|
||||||
err = -EACCES;
|
|
||||||
if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS))
|
|
||||||
goto err_cred;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & PERF_FLAG_PID_CGROUP)
|
if (flags & PERF_FLAG_PID_CGROUP)
|
||||||
cgroup_fd = pid;
|
cgroup_fd = pid;
|
||||||
|
|
||||||
|
@ -11026,7 +11008,7 @@ SYSCALL_DEFINE5(perf_event_open,
|
||||||
NULL, NULL, cgroup_fd);
|
NULL, NULL, cgroup_fd);
|
||||||
if (IS_ERR(event)) {
|
if (IS_ERR(event)) {
|
||||||
err = PTR_ERR(event);
|
err = PTR_ERR(event);
|
||||||
goto err_cred;
|
goto err_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_sampling_event(event)) {
|
if (is_sampling_event(event)) {
|
||||||
|
@ -11145,6 +11127,24 @@ SYSCALL_DEFINE5(perf_event_open,
|
||||||
goto err_context;
|
goto err_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task) {
|
||||||
|
err = down_read_interruptible(&task->signal->exec_update_lock);
|
||||||
|
if (err)
|
||||||
|
goto err_file;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preserve ptrace permission check for backwards compatibility.
|
||||||
|
*
|
||||||
|
* We must hold exec_update_lock across this and any potential
|
||||||
|
* perf_install_in_context() call for this new event to
|
||||||
|
* serialize against exec() altering our credentials (and the
|
||||||
|
* perf_event_exit_task() that could imply).
|
||||||
|
*/
|
||||||
|
err = -EACCES;
|
||||||
|
if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS))
|
||||||
|
goto err_cred;
|
||||||
|
}
|
||||||
|
|
||||||
if (move_group) {
|
if (move_group) {
|
||||||
gctx = __perf_event_ctx_lock_double(group_leader, ctx);
|
gctx = __perf_event_ctx_lock_double(group_leader, ctx);
|
||||||
|
|
||||||
|
@ -11298,7 +11298,7 @@ SYSCALL_DEFINE5(perf_event_open,
|
||||||
mutex_unlock(&ctx->mutex);
|
mutex_unlock(&ctx->mutex);
|
||||||
|
|
||||||
if (task) {
|
if (task) {
|
||||||
mutex_unlock(&task->signal->exec_update_mutex);
|
up_read(&task->signal->exec_update_lock);
|
||||||
put_task_struct(task);
|
put_task_struct(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11320,7 +11320,10 @@ err_locked:
|
||||||
if (move_group)
|
if (move_group)
|
||||||
perf_event_ctx_unlock(group_leader, gctx);
|
perf_event_ctx_unlock(group_leader, gctx);
|
||||||
mutex_unlock(&ctx->mutex);
|
mutex_unlock(&ctx->mutex);
|
||||||
/* err_file: */
|
err_cred:
|
||||||
|
if (task)
|
||||||
|
up_read(&task->signal->exec_update_lock);
|
||||||
|
err_file:
|
||||||
fput(event_file);
|
fput(event_file);
|
||||||
err_context:
|
err_context:
|
||||||
perf_unpin_context(ctx);
|
perf_unpin_context(ctx);
|
||||||
|
@ -11332,9 +11335,6 @@ err_alloc:
|
||||||
*/
|
*/
|
||||||
if (!event_file)
|
if (!event_file)
|
||||||
free_event(event);
|
free_event(event);
|
||||||
err_cred:
|
|
||||||
if (task)
|
|
||||||
mutex_unlock(&task->signal->exec_update_mutex);
|
|
||||||
err_task:
|
err_task:
|
||||||
if (task)
|
if (task)
|
||||||
put_task_struct(task);
|
put_task_struct(task);
|
||||||
|
@ -11639,7 +11639,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
|
||||||
/*
|
/*
|
||||||
* When a child task exits, feed back event values to parent events.
|
* When a child task exits, feed back event values to parent events.
|
||||||
*
|
*
|
||||||
* Can be called with exec_update_mutex held when called from
|
* Can be called with exec_update_lock held when called from
|
||||||
* install_exec_creds().
|
* install_exec_creds().
|
||||||
*/
|
*/
|
||||||
void perf_event_exit_task(struct task_struct *child)
|
void perf_event_exit_task(struct task_struct *child)
|
||||||
|
|
|
@ -1221,7 +1221,7 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
|
||||||
struct mm_struct *mm;
|
struct mm_struct *mm;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = mutex_lock_killable(&task->signal->exec_update_mutex);
|
err = down_read_killable(&task->signal->exec_update_lock);
|
||||||
if (err)
|
if (err)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
|
@ -1231,7 +1231,7 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
|
||||||
mmput(mm);
|
mmput(mm);
|
||||||
mm = ERR_PTR(-EACCES);
|
mm = ERR_PTR(-EACCES);
|
||||||
}
|
}
|
||||||
mutex_unlock(&task->signal->exec_update_mutex);
|
up_read(&task->signal->exec_update_lock);
|
||||||
|
|
||||||
return mm;
|
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;
|
sig->oom_score_adj_min = current->signal->oom_score_adj_min;
|
||||||
|
|
||||||
mutex_init(&sig->cred_guard_mutex);
|
mutex_init(&sig->cred_guard_mutex);
|
||||||
mutex_init(&sig->exec_update_mutex);
|
init_rwsem(&sig->exec_update_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,25 +75,25 @@ get_file_raw_ptr(struct task_struct *task, unsigned int idx)
|
||||||
return file;
|
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))
|
if (likely(l2 != l1))
|
||||||
mutex_unlock(m2);
|
up_read(l2);
|
||||||
mutex_unlock(m1);
|
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;
|
int err;
|
||||||
|
|
||||||
if (m2 > m1)
|
if (l2 > l1)
|
||||||
swap(m1, m2);
|
swap(l1, l2);
|
||||||
|
|
||||||
err = mutex_lock_killable(m1);
|
err = down_read_killable(l1);
|
||||||
if (!err && likely(m1 != m2)) {
|
if (!err && likely(l1 != l2)) {
|
||||||
err = mutex_lock_killable_nested(m2, SINGLE_DEPTH_NESTING);
|
err = down_read_killable_nested(l2, SINGLE_DEPTH_NESTING);
|
||||||
if (err)
|
if (err)
|
||||||
mutex_unlock(m1);
|
up_read(l1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
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.
|
* One should have enough rights to inspect task details.
|
||||||
*/
|
*/
|
||||||
ret = kcmp_lock(&task1->signal->exec_update_mutex,
|
ret = kcmp_lock(&task1->signal->exec_update_lock,
|
||||||
&task2->signal->exec_update_mutex);
|
&task2->signal->exec_update_lock);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
if (!ptrace_may_access(task1, PTRACE_MODE_READ_REALCREDS) ||
|
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:
|
err_unlock:
|
||||||
kcmp_unlock(&task1->signal->exec_update_mutex,
|
kcmp_unlock(&task1->signal->exec_update_lock,
|
||||||
&task2->signal->exec_update_mutex);
|
&task2->signal->exec_update_lock);
|
||||||
err:
|
err:
|
||||||
put_task_struct(task1);
|
put_task_struct(task1);
|
||||||
put_task_struct(task2);
|
put_task_struct(task2);
|
||||||
|
|
|
@ -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)
|
static inline int __down_read_killable(struct rw_semaphore *sem)
|
||||||
{
|
{
|
||||||
if (!rwsem_read_trylock(sem)) {
|
if (!rwsem_read_trylock(sem)) {
|
||||||
|
@ -1498,6 +1510,20 @@ void __sched down_read(struct rw_semaphore *sem)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(down_read);
|
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)
|
int __sched down_read_killable(struct rw_semaphore *sem)
|
||||||
{
|
{
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
@ -1608,6 +1634,20 @@ void down_read_nested(struct rw_semaphore *sem, int subclass)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(down_read_nested);
|
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)
|
void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest)
|
||||||
{
|
{
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
|
Loading…
Reference in New Issue