mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
This pull request contains the following changes for UBIFS:
- Fix for a race xattr list and modification - Various minor fixes (spelling, return codes, ...) -----BEGIN PGP SIGNATURE----- iQJKBAABCAA0FiEEdgfidid8lnn52cLTZvlZhesYu8EFAmDnaSYWHHJpY2hhcmRA c2lnbWEtc3Rhci5hdAAKCRBm+VmF6xi7wd36D/9ZJDHP1D1ZTTN6eFbAy55fDV+U 6nx36Ot+DA5BqaPYX1YRBNxshBIdd620W4n07US20SL14k7dzky/y+oJt+ZZY44k 1ev6zqbmWTKdZhITwoaeVWRGYkEUVTvGW4MoOERZSfLhodrRVCfqs9/1a8ol/x1g AhZFxBRBUWLWlHYNplqdZdIuCo0qGQBWITv/A8of0pXH9cGxRTvYV5V6CbeXrnuD LgvckvwCZHPtRHgil3R1l/oGo109QNKhEycFBBLf1ydqIyIjOBcpI2ETZmifyv9D v2dgyu9u1SM2mzMEZmdTfWVBjqhKH2vYiv1otF2BD7DCJ48Y4yb/YQby3MOrZfDI rI3B8FlfNeXkqzoKjuLjiHe21KXrifPNsuTcunNd8Thnw+0mqsY3OimY4pYpQO2O JhDlnt8V4QLcUeg2NYGrQHx1qfLSMgc5pYd0ntOWWhJKXtreFYtX2WeorMroIHZQ B4li4VasaLvg+HSwJsgJ4qrPHl0fMT8eu0yb4KjsJi/d9Zl4FhmRe/QVs43GayAT zczxywAAN81sP2q/TQPtDgHzI90QTA0E89JkQVa0cGA2/VznM9RmAhrxGIjwGKZE 4owC5RMA8w7eb60aLZ4HEooLwNXbKRd3ayR9Hatbp+Cq3+GBUG77em+2sLtwyqiD mDWJo6AWRZxBDpG4jg== =2Wk7 -----END PGP SIGNATURE----- Merge tag 'for-linus-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs Pull UBIFS updates from Richard Weinberger: - Fix for a race xattr list and modification - Various minor fixes (spelling, return codes, ...) * tag 'for-linus-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs: ubifs: Set/Clear I_LINKABLE under i_lock for whiteout inode ubifs: Fix spelling mistakes ubifs: Remove ui_mutex in ubifs_xattr_get and change_xattr ubifs: Fix races between xattr_{set|get} and listxattr operations ubifs: fix snprintf() checking ubifs: journal: Fix error return code in ubifs_jnl_write_inode()
This commit is contained in:
commit
7a400bf283
@ -511,7 +511,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
|
||||
|
||||
n = snprintf(d->dfs_dir_name, UBI_DFS_DIR_LEN + 1, UBI_DFS_DIR_NAME,
|
||||
ubi->ubi_num);
|
||||
if (n == UBI_DFS_DIR_LEN) {
|
||||
if (n > UBI_DFS_DIR_LEN) {
|
||||
/* The array size is too small */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -2824,7 +2824,7 @@ void dbg_debugfs_init_fs(struct ubifs_info *c)
|
||||
|
||||
n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
|
||||
c->vi.ubi_num, c->vi.vol_id);
|
||||
if (n == UBIFS_DFS_DIR_LEN) {
|
||||
if (n > UBIFS_DFS_DIR_LEN) {
|
||||
/* The array size is too small */
|
||||
return;
|
||||
}
|
||||
|
@ -1337,7 +1337,10 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
spin_lock(&whiteout->i_lock);
|
||||
whiteout->i_state |= I_LINKABLE;
|
||||
spin_unlock(&whiteout->i_lock);
|
||||
|
||||
whiteout_ui = ubifs_inode(whiteout);
|
||||
whiteout_ui->data = dev;
|
||||
whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0));
|
||||
@ -1430,7 +1433,11 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
|
||||
inc_nlink(whiteout);
|
||||
mark_inode_dirty(whiteout);
|
||||
|
||||
spin_lock(&whiteout->i_lock);
|
||||
whiteout->i_state &= ~I_LINKABLE;
|
||||
spin_unlock(&whiteout->i_lock);
|
||||
|
||||
iput(whiteout);
|
||||
}
|
||||
|
||||
|
@ -882,6 +882,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
struct ubifs_dent_node *xent, *pxent = NULL;
|
||||
|
||||
if (ui->xattr_cnt > ubifs_xattr_max_cnt(c)) {
|
||||
err = -EPERM;
|
||||
ubifs_err(c, "Cannot delete inode, it has too much xattrs!");
|
||||
goto out_release;
|
||||
}
|
||||
@ -1431,7 +1432,7 @@ out_free:
|
||||
/**
|
||||
* truncate_data_node - re-compress/encrypt a truncated data node.
|
||||
* @c: UBIFS file-system description object
|
||||
* @inode: inode which referes to the data node
|
||||
* @inode: inode which refers to the data node
|
||||
* @block: data block number
|
||||
* @dn: data node to re-compress
|
||||
* @new_len: new length
|
||||
|
@ -37,7 +37,7 @@ int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Do not compare the embedded HMAC aswell which also must be different
|
||||
* Do not compare the embedded HMAC as well which also must be different
|
||||
* due to the different common node header.
|
||||
*/
|
||||
behind = hmac_offs + UBIFS_MAX_HMAC_LEN;
|
||||
|
@ -296,7 +296,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
|
||||
* @b: second replay entry
|
||||
*
|
||||
* This is a comparios function for 'list_sort()' which compares 2 replay
|
||||
* entries @a and @b by comparing their sequence numer. Returns %1 if @a has
|
||||
* entries @a and @b by comparing their sequence number. Returns %1 if @a has
|
||||
* greater sequence number and %-1 otherwise.
|
||||
*/
|
||||
static int replay_entries_cmp(void *priv, const struct list_head *a,
|
||||
|
@ -275,6 +275,7 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb)
|
||||
memset((void *)ui + sizeof(struct inode), 0,
|
||||
sizeof(struct ubifs_inode) - sizeof(struct inode));
|
||||
mutex_init(&ui->ui_mutex);
|
||||
init_rwsem(&ui->xattr_sem);
|
||||
spin_lock_init(&ui->ui_lock);
|
||||
return &ui->vfs_inode;
|
||||
};
|
||||
@ -2060,7 +2061,7 @@ const struct super_operations ubifs_super_operations = {
|
||||
* @mode: UBI volume open mode
|
||||
*
|
||||
* The primary method of mounting UBIFS is by specifying the UBI volume
|
||||
* character device node path. However, UBIFS may also be mounted withoug any
|
||||
* character device node path. However, UBIFS may also be mounted without any
|
||||
* character device node using one of the following methods:
|
||||
*
|
||||
* o ubiX_Y - mount UBI device number X, volume Y;
|
||||
|
@ -930,7 +930,7 @@ static int write_index(struct ubifs_info *c)
|
||||
* flag cleared before %COW_ZNODE. Specifically, it matters in
|
||||
* the 'dirty_cow_znode()' function. This is the reason for the
|
||||
* first barrier. Also, we want the bit changes to be seen to
|
||||
* other threads ASAP, to avoid unnecesarry copying, which is
|
||||
* other threads ASAP, to avoid unnecessary copying, which is
|
||||
* the reason for the second barrier.
|
||||
*/
|
||||
clear_bit(DIRTY_ZNODE, &znode->flags);
|
||||
|
@ -356,6 +356,7 @@ struct ubifs_gced_idx_leb {
|
||||
* @ui_mutex: serializes inode write-back with the rest of VFS operations,
|
||||
* serializes "clean <-> dirty" state changes, serializes bulk-read,
|
||||
* protects @dirty, @bulk_read, @ui_size, and @xattr_size
|
||||
* @xattr_sem: serilizes write operations (remove|set|create) on xattr
|
||||
* @ui_lock: protects @synced_i_size
|
||||
* @synced_i_size: synchronized size of inode, i.e. the value of inode size
|
||||
* currently stored on the flash; used only for regular file
|
||||
@ -409,6 +410,7 @@ struct ubifs_inode {
|
||||
unsigned int bulk_read:1;
|
||||
unsigned int compr_type:2;
|
||||
struct mutex ui_mutex;
|
||||
struct rw_semaphore xattr_sem;
|
||||
spinlock_t ui_lock;
|
||||
loff_t synced_i_size;
|
||||
loff_t ui_size;
|
||||
@ -912,7 +914,7 @@ struct ubifs_budget_req {
|
||||
* @rb: rb-tree node of rb-tree of orphans sorted by inode number
|
||||
* @list: list head of list of orphans in order added
|
||||
* @new_list: list head of list of orphans added since the last commit
|
||||
* @child_list: list of xattr childs if this orphan hosts xattrs, list head
|
||||
* @child_list: list of xattr children if this orphan hosts xattrs, list head
|
||||
* if this orphan is a xattr, not used otherwise.
|
||||
* @cnext: next orphan to commit
|
||||
* @dnext: next orphan to delete
|
||||
|
@ -208,13 +208,11 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
|
||||
err = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
mutex_lock(&ui->ui_mutex);
|
||||
kfree(ui->data);
|
||||
ui->data = buf;
|
||||
inode->i_size = ui->ui_size = size;
|
||||
old_size = ui->data_len;
|
||||
ui->data_len = size;
|
||||
mutex_unlock(&ui->ui_mutex);
|
||||
|
||||
mutex_lock(&host_ui->ui_mutex);
|
||||
host->i_ctime = current_time(host);
|
||||
@ -285,6 +283,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
|
||||
if (!xent)
|
||||
return -ENOMEM;
|
||||
|
||||
down_write(&ubifs_inode(host)->xattr_sem);
|
||||
/*
|
||||
* The extended attribute entries are stored in LNC, so multiple
|
||||
* look-ups do not involve reading the flash.
|
||||
@ -319,6 +318,7 @@ int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
|
||||
iput(inode);
|
||||
|
||||
out_free:
|
||||
up_write(&ubifs_inode(host)->xattr_sem);
|
||||
kfree(xent);
|
||||
return err;
|
||||
}
|
||||
@ -341,25 +341,25 @@ ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
|
||||
if (!xent)
|
||||
return -ENOMEM;
|
||||
|
||||
down_read(&ubifs_inode(host)->xattr_sem);
|
||||
xent_key_init(c, &key, host->i_ino, &nm);
|
||||
err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
|
||||
if (err) {
|
||||
if (err == -ENOENT)
|
||||
err = -ENODATA;
|
||||
goto out_unlock;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
inode = iget_xattr(c, le64_to_cpu(xent->inum));
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out_unlock;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
ui = ubifs_inode(inode);
|
||||
ubifs_assert(c, inode->i_size == ui->data_len);
|
||||
ubifs_assert(c, ubifs_inode(host)->xattr_size > ui->data_len);
|
||||
|
||||
mutex_lock(&ui->ui_mutex);
|
||||
if (buf) {
|
||||
/* If @buf is %NULL we are supposed to return the length */
|
||||
if (ui->data_len > size) {
|
||||
@ -372,9 +372,9 @@ ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
|
||||
err = ui->data_len;
|
||||
|
||||
out_iput:
|
||||
mutex_unlock(&ui->ui_mutex);
|
||||
iput(inode);
|
||||
out_unlock:
|
||||
out_cleanup:
|
||||
up_read(&ubifs_inode(host)->xattr_sem);
|
||||
kfree(xent);
|
||||
return err;
|
||||
}
|
||||
@ -406,16 +406,21 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino,
|
||||
dentry, size);
|
||||
|
||||
down_read(&host_ui->xattr_sem);
|
||||
len = host_ui->xattr_names + host_ui->xattr_cnt;
|
||||
if (!buffer)
|
||||
if (!buffer) {
|
||||
/*
|
||||
* We should return the minimum buffer size which will fit a
|
||||
* null-terminated list of all the extended attribute names.
|
||||
*/
|
||||
return len;
|
||||
err = len;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (len > size)
|
||||
return -ERANGE;
|
||||
if (len > size) {
|
||||
err = -ERANGE;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
lowest_xent_key(c, &key, host->i_ino);
|
||||
while (1) {
|
||||
@ -437,8 +442,9 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
pxent = xent;
|
||||
key_read(c, &xent->key, &key);
|
||||
}
|
||||
|
||||
kfree(pxent);
|
||||
up_read(&host_ui->xattr_sem);
|
||||
|
||||
if (err != -ENOENT) {
|
||||
ubifs_err(c, "cannot find next direntry, error %d", err);
|
||||
return err;
|
||||
@ -446,6 +452,10 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
|
||||
ubifs_assert(c, written <= size);
|
||||
return written;
|
||||
|
||||
out_err:
|
||||
up_read(&host_ui->xattr_sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int remove_xattr(struct ubifs_info *c, struct inode *host,
|
||||
@ -504,6 +514,7 @@ int ubifs_purge_xattrs(struct inode *host)
|
||||
ubifs_warn(c, "inode %lu has too many xattrs, doing a non-atomic deletion",
|
||||
host->i_ino);
|
||||
|
||||
down_write(&ubifs_inode(host)->xattr_sem);
|
||||
lowest_xent_key(c, &key, host->i_ino);
|
||||
while (1) {
|
||||
xent = ubifs_tnc_next_ent(c, &key, &nm);
|
||||
@ -523,7 +534,7 @@ int ubifs_purge_xattrs(struct inode *host)
|
||||
ubifs_ro_mode(c, err);
|
||||
kfree(pxent);
|
||||
kfree(xent);
|
||||
return err;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
ubifs_assert(c, ubifs_inode(xino)->xattr);
|
||||
@ -535,7 +546,7 @@ int ubifs_purge_xattrs(struct inode *host)
|
||||
kfree(xent);
|
||||
iput(xino);
|
||||
ubifs_err(c, "cannot remove xattr, error %d", err);
|
||||
return err;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
iput(xino);
|
||||
@ -544,14 +555,19 @@ int ubifs_purge_xattrs(struct inode *host)
|
||||
pxent = xent;
|
||||
key_read(c, &xent->key, &key);
|
||||
}
|
||||
|
||||
kfree(pxent);
|
||||
up_write(&ubifs_inode(host)->xattr_sem);
|
||||
|
||||
if (err != -ENOENT) {
|
||||
ubifs_err(c, "cannot find next direntry, error %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
up_write(&ubifs_inode(host)->xattr_sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -594,6 +610,7 @@ static int ubifs_xattr_remove(struct inode *host, const char *name)
|
||||
if (!xent)
|
||||
return -ENOMEM;
|
||||
|
||||
down_write(&ubifs_inode(host)->xattr_sem);
|
||||
xent_key_init(c, &key, host->i_ino, &nm);
|
||||
err = ubifs_tnc_lookup_nm(c, &key, xent, &nm);
|
||||
if (err) {
|
||||
@ -618,6 +635,7 @@ static int ubifs_xattr_remove(struct inode *host, const char *name)
|
||||
iput(inode);
|
||||
|
||||
out_free:
|
||||
up_write(&ubifs_inode(host)->xattr_sem);
|
||||
kfree(xent);
|
||||
return err;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user