ubifs: make ubifs_[get|set]xattr atomic
This commit make the ubifs_[get|set]xattr protected by ui_mutex. Originally, there is a possibility that ubifs_getxattr to get a wrong value. P1 P2 ---------- ---------- ubifs_getxattr ubifs_setxattr - kfree() - memcpy() - kmemdup() Then ubifs_getxattr() would get a non-sense data. To solve this problem, this commit make the xattr of ubifs_inode updated in atomic. Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
54bcfdf19e
commit
ab92a20bce
@ -200,6 +200,7 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
|
|||||||
int err;
|
int err;
|
||||||
struct ubifs_inode *host_ui = ubifs_inode(host);
|
struct ubifs_inode *host_ui = ubifs_inode(host);
|
||||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||||
|
void *buf = NULL;
|
||||||
struct ubifs_budget_req req = { .dirtied_ino = 2,
|
struct ubifs_budget_req req = { .dirtied_ino = 2,
|
||||||
.dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
|
.dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
|
||||||
|
|
||||||
@ -208,14 +209,17 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
kfree(ui->data);
|
buf = kmemdup(value, size, GFP_NOFS);
|
||||||
ui->data = kmemdup(value, size, GFP_NOFS);
|
if (!buf) {
|
||||||
if (!ui->data) {
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
mutex_lock(&ui->ui_mutex);
|
||||||
|
kfree(ui->data);
|
||||||
|
ui->data = buf;
|
||||||
inode->i_size = ui->ui_size = size;
|
inode->i_size = ui->ui_size = size;
|
||||||
ui->data_len = size;
|
ui->data_len = size;
|
||||||
|
mutex_unlock(&ui->ui_mutex);
|
||||||
|
|
||||||
mutex_lock(&host_ui->ui_mutex);
|
mutex_lock(&host_ui->ui_mutex);
|
||||||
host->i_ctime = ubifs_current_time(host);
|
host->i_ctime = ubifs_current_time(host);
|
||||||
@ -409,6 +413,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
|
|||||||
ubifs_assert(inode->i_size == ui->data_len);
|
ubifs_assert(inode->i_size == ui->data_len);
|
||||||
ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len);
|
ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len);
|
||||||
|
|
||||||
|
mutex_lock(&ui->ui_mutex);
|
||||||
if (buf) {
|
if (buf) {
|
||||||
/* If @buf is %NULL we are supposed to return the length */
|
/* If @buf is %NULL we are supposed to return the length */
|
||||||
if (ui->data_len > size) {
|
if (ui->data_len > size) {
|
||||||
@ -423,6 +428,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
|
|||||||
err = ui->data_len;
|
err = ui->data_len;
|
||||||
|
|
||||||
out_iput:
|
out_iput:
|
||||||
|
mutex_unlock(&ui->ui_mutex);
|
||||||
iput(inode);
|
iput(inode);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
kfree(xent);
|
kfree(xent);
|
||||||
|
Loading…
Reference in New Issue
Block a user