Skip to content

Commit f728a5e

Browse files
dma-buf: fix dma_buf_export init order v2
The init order and resulting error handling in dma_buf_export was pretty messy. Subordinate objects like the file and the sysfs kernel objects were initializing and wiring itself up with the object in the wrong order resulting not only in complicating and partially incorrect error handling, but also in publishing only halve initialized DMA-buf objects. Clean this up thoughtfully by allocating the file independent of the DMA-buf object. Then allocate and initialize the DMA-buf object itself, before publishing it through sysfs. If everything works as expected the file is then connected with the DMA-buf object and publish it through debugfs. Also adds the missing dma_resv_fini() into the error handling. v2: add some missing changes to dma_bug_getfile() and a missing NULL check in dma_buf_file_release() Signed-off-by: Christian König <[email protected]> Reviewed-by: Michael J. Ruhl <[email protected]> Reviewed-by: T.J. Mercier <[email protected]> Acked-by: Sumit Semwal <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent c425265 commit f728a5e

File tree

3 files changed

+43
-52
lines changed

3 files changed

+43
-52
lines changed

drivers/dma-buf/dma-buf-sysfs-stats.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,11 @@ void dma_buf_uninit_sysfs_statistics(void)
168168
kset_unregister(dma_buf_stats_kset);
169169
}
170170

171-
int dma_buf_stats_setup(struct dma_buf *dmabuf)
171+
int dma_buf_stats_setup(struct dma_buf *dmabuf, struct file *file)
172172
{
173173
struct dma_buf_sysfs_entry *sysfs_entry;
174174
int ret;
175175

176-
if (!dmabuf || !dmabuf->file)
177-
return -EINVAL;
178-
179176
if (!dmabuf->exp_name) {
180177
pr_err("exporter name must not be empty if stats needed\n");
181178
return -EINVAL;
@@ -192,7 +189,7 @@ int dma_buf_stats_setup(struct dma_buf *dmabuf)
192189

193190
/* create the directory for buffer stats */
194191
ret = kobject_init_and_add(&sysfs_entry->kobj, &dma_buf_ktype, NULL,
195-
"%lu", file_inode(dmabuf->file)->i_ino);
192+
"%lu", file_inode(file)->i_ino);
196193
if (ret)
197194
goto err_sysfs_dmabuf;
198195

drivers/dma-buf/dma-buf-sysfs-stats.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
int dma_buf_init_sysfs_statistics(void);
1414
void dma_buf_uninit_sysfs_statistics(void);
1515

16-
int dma_buf_stats_setup(struct dma_buf *dmabuf);
16+
int dma_buf_stats_setup(struct dma_buf *dmabuf, struct file *file);
1717

1818
void dma_buf_stats_teardown(struct dma_buf *dmabuf);
1919
#else
@@ -25,7 +25,7 @@ static inline int dma_buf_init_sysfs_statistics(void)
2525

2626
static inline void dma_buf_uninit_sysfs_statistics(void) {}
2727

28-
static inline int dma_buf_stats_setup(struct dma_buf *dmabuf)
28+
static inline int dma_buf_stats_setup(struct dma_buf *dmabuf, struct file *file)
2929
{
3030
return 0;
3131
}

drivers/dma-buf/dma-buf.c

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,11 @@ static int dma_buf_file_release(struct inode *inode, struct file *file)
9595
return -EINVAL;
9696

9797
dmabuf = file->private_data;
98-
99-
mutex_lock(&db_list.lock);
100-
list_del(&dmabuf->list_node);
101-
mutex_unlock(&db_list.lock);
98+
if (dmabuf) {
99+
mutex_lock(&db_list.lock);
100+
list_del(&dmabuf->list_node);
101+
mutex_unlock(&db_list.lock);
102+
}
102103

103104
return 0;
104105
}
@@ -523,17 +524,17 @@ static inline int is_dma_buf_file(struct file *file)
523524
return file->f_op == &dma_buf_fops;
524525
}
525526

526-
static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
527+
static struct file *dma_buf_getfile(size_t size, int flags)
527528
{
528529
static atomic64_t dmabuf_inode = ATOMIC64_INIT(0);
529-
struct file *file;
530530
struct inode *inode = alloc_anon_inode(dma_buf_mnt->mnt_sb);
531+
struct file *file;
531532

532533
if (IS_ERR(inode))
533534
return ERR_CAST(inode);
534535

535-
inode->i_size = dmabuf->size;
536-
inode_set_bytes(inode, dmabuf->size);
536+
inode->i_size = size;
537+
inode_set_bytes(inode, size);
537538

538539
/*
539540
* The ->i_ino acquired from get_next_ino() is not unique thus
@@ -547,8 +548,6 @@ static struct file *dma_buf_getfile(struct dma_buf *dmabuf, int flags)
547548
flags, &dma_buf_fops);
548549
if (IS_ERR(file))
549550
goto err_alloc_file;
550-
file->private_data = dmabuf;
551-
file->f_path.dentry->d_fsdata = dmabuf;
552551

553552
return file;
554553

@@ -614,19 +613,11 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
614613
size_t alloc_size = sizeof(struct dma_buf);
615614
int ret;
616615

617-
if (!exp_info->resv)
618-
alloc_size += sizeof(struct dma_resv);
619-
else
620-
/* prevent &dma_buf[1] == dma_buf->resv */
621-
alloc_size += 1;
622-
623-
if (WARN_ON(!exp_info->priv
624-
|| !exp_info->ops
625-
|| !exp_info->ops->map_dma_buf
626-
|| !exp_info->ops->unmap_dma_buf
627-
|| !exp_info->ops->release)) {
616+
if (WARN_ON(!exp_info->priv || !exp_info->ops
617+
|| !exp_info->ops->map_dma_buf
618+
|| !exp_info->ops->unmap_dma_buf
619+
|| !exp_info->ops->release))
628620
return ERR_PTR(-EINVAL);
629-
}
630621

631622
if (WARN_ON(exp_info->ops->cache_sgt_mapping &&
632623
(exp_info->ops->pin || exp_info->ops->unpin)))
@@ -638,10 +629,21 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
638629
if (!try_module_get(exp_info->owner))
639630
return ERR_PTR(-ENOENT);
640631

632+
file = dma_buf_getfile(exp_info->size, exp_info->flags);
633+
if (IS_ERR(file)) {
634+
ret = PTR_ERR(file);
635+
goto err_module;
636+
}
637+
638+
if (!exp_info->resv)
639+
alloc_size += sizeof(struct dma_resv);
640+
else
641+
/* prevent &dma_buf[1] == dma_buf->resv */
642+
alloc_size += 1;
641643
dmabuf = kzalloc(alloc_size, GFP_KERNEL);
642644
if (!dmabuf) {
643645
ret = -ENOMEM;
644-
goto err_module;
646+
goto err_file;
645647
}
646648

647649
dmabuf->priv = exp_info->priv;
@@ -653,44 +655,36 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
653655
init_waitqueue_head(&dmabuf->poll);
654656
dmabuf->cb_in.poll = dmabuf->cb_out.poll = &dmabuf->poll;
655657
dmabuf->cb_in.active = dmabuf->cb_out.active = 0;
658+
mutex_init(&dmabuf->lock);
659+
INIT_LIST_HEAD(&dmabuf->attachments);
656660

657661
if (!resv) {
658-
resv = (struct dma_resv *)&dmabuf[1];
659-
dma_resv_init(resv);
662+
dmabuf->resv = (struct dma_resv *)&dmabuf[1];
663+
dma_resv_init(dmabuf->resv);
664+
} else {
665+
dmabuf->resv = resv;
660666
}
661-
dmabuf->resv = resv;
662667

663-
file = dma_buf_getfile(dmabuf, exp_info->flags);
664-
if (IS_ERR(file)) {
665-
ret = PTR_ERR(file);
668+
ret = dma_buf_stats_setup(dmabuf, file);
669+
if (ret)
666670
goto err_dmabuf;
667-
}
668671

672+
file->private_data = dmabuf;
673+
file->f_path.dentry->d_fsdata = dmabuf;
669674
dmabuf->file = file;
670675

671-
mutex_init(&dmabuf->lock);
672-
INIT_LIST_HEAD(&dmabuf->attachments);
673-
674676
mutex_lock(&db_list.lock);
675677
list_add(&dmabuf->list_node, &db_list.head);
676678
mutex_unlock(&db_list.lock);
677679

678-
ret = dma_buf_stats_setup(dmabuf);
679-
if (ret)
680-
goto err_sysfs;
681-
682680
return dmabuf;
683681

684-
err_sysfs:
685-
/*
686-
* Set file->f_path.dentry->d_fsdata to NULL so that when
687-
* dma_buf_release() gets invoked by dentry_ops, it exits
688-
* early before calling the release() dma_buf op.
689-
*/
690-
file->f_path.dentry->d_fsdata = NULL;
691-
fput(file);
692682
err_dmabuf:
683+
if (!resv)
684+
dma_resv_fini(dmabuf->resv);
693685
kfree(dmabuf);
686+
err_file:
687+
fput(file);
694688
err_module:
695689
module_put(exp_info->owner);
696690
return ERR_PTR(ret);

0 commit comments

Comments
 (0)