Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: "Ghimiray, Himal Prasad" <himal.prasad.ghimiray@intel.com>
To: Tejas Upadhyay <tejas.upadhyay@intel.com>,
	<intel-xe@lists.freedesktop.org>
Subject: Re: [PATCH V15 11/14] drm/xe/vram: Use RCU for lock-free sysfs reads of bad page lists
Date: Wed, 12 Aug 2026 17:44:47 +0530	[thread overview]
Message-ID: <e768c091-fa7a-4ce5-b8d1-4f9d45ac2916@intel.com> (raw)
In-Reply-To: <20260811124016.3614699-27-tejas.upadhyay@intel.com>



On 11-08-2026 18:10, Tejas Upadhyay wrote:
> The sysfs vram_bad_pages reader previously held mgr->lock while
> formatting the entire output, blocking normal VRAM alloc/free
> operations for the duration of the read.
> 
> Switch to RCU-protected list traversal for the sysfs read path:
> 
> Writer side (page offline, under mgr->lock):
>    - list_add()  -> list_add_rcu()
>    - list_del()  -> list_del_rcu()
>    - kfree()     -> kfree_rcu()
> 
> Reader side (sysfs serialize_bad_pages):
>    - Drop mgr->lock entirely
>    - Use rcu_read_lock() + list_for_each_entry_rcu()
>    - Use READ_ONCE() for entry counters
> 
> The writer-side xe_ttm_vram_page_already_processed() keeps
> lockdep_assert_held(&mgr->lock) since it requires serialization
> against concurrent page offline operations.

The patch is doing much more than its meant to do.

Better handle >    - list_add()  -> list_add_rcu()
 >    - list_del()  -> list_del_rcu()
 >    - kfree()     -> kfree_rcu()

in original patch [8]

Sysfs handling should move to next patch.

> 
> Signed-off-by: Tejas Upadhyay <tejas.upadhyay@intel.com>
> ---
>   drivers/gpu/drm/xe/xe_ttm_vram_mgr.c       | 161 +++++++++++++++++++--
>   drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h |   4 +
>   2 files changed, 155 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
> index 6280886e2ebb..c22669955147 100644
> --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
> +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c
> @@ -312,15 +312,15 @@ static void xe_ttm_vram_free_bad_pages(struct drm_device *dev, struct xe_ttm_vra
>   
>   	list_for_each_entry_safe(pos, n, &mgr->offlined_pages, offlined_link) {
>   		xe_ttm_vram_buddy_free(mgr, &pos->blocks, pos->used_visible_size);
> -		list_del(&pos->offlined_link);
> +		list_del_rcu(&pos->offlined_link);
>   		--mgr->n_offlined_pages;
> -		kfree(pos);
> +		kfree_rcu(pos, rcu);
>   	}
>   	list_for_each_entry_safe(pos, n, &mgr->queued_pages, queued_link) {
>   		xe_ttm_vram_buddy_free(mgr, &pos->blocks, 0);
> -		list_del(&pos->queued_link);
> +		list_del_rcu(&pos->queued_link);
>   		--mgr->n_queued_pages;
> -		kfree(pos);
> +		kfree_rcu(pos, rcu);
>   	}
>   }
>   
> @@ -657,7 +657,7 @@ static int xe_ttm_vram_reserve_page_at_addr(struct xe_device *xe, u64 addr,
>   				break;
>   			}
>   			++vram_mgr->n_queued_pages;
> -			list_add(&nentry->queued_link, &vram_mgr->queued_pages);
> +			list_add_rcu(&nentry->queued_link, &vram_mgr->queued_pages);
>   		}
>   	}
>   
> @@ -702,11 +702,11 @@ static int xe_ttm_vram_reserve_page_at_addr(struct xe_device *xe, u64 addr,
>   			list_for_each_entry_safe(pos, n, &vram_mgr->queued_pages, queued_link) {
>   				if (pos->addr == nentry->addr) {
>   					--vram_mgr->n_queued_pages;
> -					list_del(&pos->queued_link);
> +					list_del_rcu(&pos->queued_link);
>   					break;
>   				}
>   			}
> -			list_add(&nentry->offlined_link, &vram_mgr->offlined_pages);
> +			list_add_rcu(&nentry->offlined_link, &vram_mgr->offlined_pages);
>   			/* RAS will send command to FW for offlining page based on ret value */
>   			++vram_mgr->n_offlined_pages;
>   			return ret;
> @@ -716,7 +716,7 @@ static int xe_ttm_vram_reserve_page_at_addr(struct xe_device *xe, u64 addr,
>   
>   		scoped_guard(mutex, &vram_mgr->lock) {
>   			++vram_mgr->n_queued_pages;
> -			list_add(&nentry->queued_link, &vram_mgr->queued_pages);
> +			list_add_rcu(&nentry->queued_link, &vram_mgr->queued_pages);
>   			ret = xe_ttm_vram_buddy_alloc(vram_mgr, addr, addr + size,
>   						      size, size, &nentry->blocks,
>   						      GPU_BUDDY_RANGE_ALLOCATION,
> @@ -732,12 +732,12 @@ static int xe_ttm_vram_reserve_page_at_addr(struct xe_device *xe, u64 addr,
>   			list_for_each_entry_safe(pos, n, &vram_mgr->queued_pages, queued_link) {
>   				if (pos->addr == nentry->addr) {
>   					--vram_mgr->n_queued_pages;
> -					list_del(&pos->queued_link);
> +					list_del_rcu(&pos->queued_link);
>   					break;
>   				}
>   			}
>   			++vram_mgr->n_offlined_pages;
> -			list_add(&nentry->offlined_link, &vram_mgr->offlined_pages);
> +			list_add_rcu(&nentry->offlined_link, &vram_mgr->offlined_pages);
>   			/* RAS will send command to FW for offlining page based on ret value */
>   		}
>   	}
> @@ -825,3 +825,144 @@ int xe_ttm_vram_handle_addr_fault(struct xe_device *xe, u64 addr)
>   	return xe_ttm_vram_reserve_page_at_addr(xe, addr, vram_mgr, mm);
>   }
>   EXPORT_SYMBOL(xe_ttm_vram_handle_addr_fault);
> +
> +static size_t serialize_bad_pages(struct xe_ttm_vram_mgr *mgr, char *buf, size_t max_len)
> +{
> +	struct xe_ttm_vram_offline_resource *pos;
> +	struct gpu_buddy_block *block;
> +	size_t s = 0;
> +	int printed;
> +	int count = 0;
> +
> +	rcu_read_lock();
> +
> +	printed = scnprintf(buf + s, max_len - s, "max_pages: %d\n", mgr->max_pages);
> +	s += printed;
> +
> +	list_for_each_entry_rcu(pos, &mgr->offlined_pages, offlined_link) {
> +		if (count >= 10000 || s >= max_len)
> +			break;
> +
> +		block = list_first_entry_or_null(&pos->blocks, struct gpu_buddy_block, link);
> +		if (!block)
> +			continue;
> +
> +		printed = scnprintf(buf + s, max_len - s, "0x%016llx : 0x%016llx : %c\n",
> +				    gpu_buddy_block_offset(block) >> PAGE_SHIFT,
> +				    gpu_buddy_block_size(&mgr->mm, block), 'R');
> +		s += printed;
> +		count++;
> +	}
> +	list_for_each_entry_rcu(pos, &mgr->queued_pages, queued_link) {
> +		u64 pfn, blk_size;
> +
> +		if (count >= 10000 || s >= max_len)
> +			break;
> +
> +		block = list_first_entry_or_null(&pos->blocks, struct gpu_buddy_block, link);
> +		if (block) {
> +			pfn = gpu_buddy_block_offset(block) >> PAGE_SHIFT;
> +			blk_size = gpu_buddy_block_size(&mgr->mm, block);
> +		} else {
> +			pfn = pos->addr >> PAGE_SHIFT;
> +			blk_size = PAGE_SIZE;
> +		}
> +
> +		printed = scnprintf(buf + s, max_len - s, "0x%016llx : 0x%016llx : %c\n",
> +				    pfn, blk_size, pos->status ? 'F' : 'P');
> +		s += printed;
> +		count++;
> +	}
> +
> +	rcu_read_unlock();
> +	return s;
> +}
> +
> +static ssize_t vram_bad_pages_bin_read(struct file *filp, struct kobject *kobj,
> +				       const struct bin_attribute *attr, char *buf,
> +				       loff_t off, size_t count)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct ttm_resource_manager *man;
> +	struct xe_ttm_vram_mgr *mgr;
> +	size_t allocation_size;
> +	struct xe_device *xe;
> +	size_t full_data_len;
> +	int active_entries;
> +	char *temp_buf;
> +
> +	xe = pdev_to_xe_device(pdev);
> +	man = ttm_manager_type(&xe->ttm, XE_PL_VRAM0);
> +	if (!man)
> +		return -ENODEV;
> +	mgr = to_xe_ttm_vram_mgr(man);
> +
> +	active_entries = READ_ONCE(mgr->n_offlined_pages) + READ_ONCE(mgr->n_queued_pages);
> +
> +	if (active_entries > 10000)
> +		active_entries = 10000;
> +
> +	allocation_size = 64 + (active_entries * 48);
> +
> +	temp_buf = kvmalloc(allocation_size, GFP_KERNEL);
> +	if (!temp_buf)
> +		return -ENOMEM;
> +
> +	/* serialize_bad_pages uses rcu_read_lock internally */
> +	full_data_len = serialize_bad_pages(mgr, temp_buf, allocation_size);
> +
> +	if (off >= full_data_len) {
> +		kvfree(temp_buf);
> +		return 0;
> +	}
> +
> +	if (off + count > full_data_len)
> +		count = full_data_len - off;
> +
> +	memcpy(buf, temp_buf + off, count);
> +
> +	kvfree(temp_buf);
> +	return count;
> +}
> +
> +static const struct bin_attribute bin_attr_vram_bad_pages = {
> +	.attr = { .name = "vram_bad_pages", .mode = 0444 },
> +	.read = vram_bad_pages_bin_read,
> +	.size = 0,
> +};
> +
> +static void xe_ttm_vram_sysfs_fini(void *arg)
> +{
> +	struct xe_device *xe = arg;
> +	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
> +
> +	sysfs_remove_bin_file(&pdev->dev.kobj, &bin_attr_vram_bad_pages);
> +}
> +
> +/**
> + * xe_ttm_vram_sysfs_init - Initialize vram bad pages sysfs binary file
> + * @xe: Xe Device object
> + *
> + * Creates a binary sysfs file under the PCI device for reading
> + * offlined and queued VRAM pages. Supports large entry counts
> + * via offset/count pagination.
> + *
> + * Returns: 0 on success, negative error code on error.
> + */
> +int xe_ttm_vram_sysfs_init(struct xe_device *xe)
> +{
> +	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
> +	int err;
> +
> +	err = sysfs_create_bin_file(&pdev->dev.kobj, &bin_attr_vram_bad_pages);
> +	if (err) {
> +		dev_err(&pdev->dev,
> +			"Failed to create vram_bad_pages sysfs: %d\n",
> +			err);
> +		return err;
> +	}
> +
> +	return devm_add_action_or_reset(&pdev->dev, xe_ttm_vram_sysfs_fini, xe);
> +}
> +EXPORT_SYMBOL(xe_ttm_vram_sysfs_init);
> diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h
> index bdfdf6ec1218..003d3a7cb1dd 100644
> --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h
> +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h
> @@ -37,6 +37,8 @@ struct xe_ttm_vram_mgr {
>   	struct mutex lock;
>   	/** @mem_type: The TTM memory type */
>   	u32 mem_type;
> +	/** @max_pages: max pages that can be in offline queue retrieved from FW */
> +	u16 max_pages;
>   };
>   
>   /**
> @@ -69,6 +71,8 @@ struct xe_ttm_vram_offline_resource {
>   	u64 addr;
>   	/** @status: Reservation status (0=pending, 1=fail) */
>   	bool status;
> +	/** @rcu: RCU head for deferred freeing */
> +	struct rcu_head rcu;
>   };
>   
>   #endif


  reply	other threads:[~2026-08-12 12:15 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-11 12:40 [PATCH V15 00/14] Add memory page offlining support Tejas Upadhyay
2026-08-11 12:40 ` [PATCH V15 01/14] drm/xe: Link VRAM object with gpu buddy Tejas Upadhyay
2026-08-11 12:40 ` [PATCH V15 02/14] [DO_NOT_MERGE]drm/gpu: Add gpu_buddy_allocated_addr_to_block helper Tejas Upadhyay
2026-08-11 12:40 ` [PATCH V15 03/14] drm/xe: Link LRC BO and its execution Queue Tejas Upadhyay
2026-08-11 12:40 ` [PATCH V15 04/14] drm/xe: Extend BO purge to handle vram pages as well Tejas Upadhyay
2026-08-11 12:40 ` [PATCH V15 05/14] drm/xe/bo: Make xe_bo_is_user() public Tejas Upadhyay
2026-08-11 15:38   ` Ghimiray, Himal Prasad
2026-08-11 12:40 ` [PATCH V15 06/14] drm/xe: Guard teardown paths against purged BOs Tejas Upadhyay
2026-08-12  3:24   ` Ghimiray, Himal Prasad
2026-08-12  9:40     ` Upadhyay, Tejas
2026-08-11 12:40 ` [PATCH V15 07/14] drm/xe/vram: Extract buddy alloc and free helpers Tejas Upadhyay
2026-08-12  3:25   ` Ghimiray, Himal Prasad
2026-08-11 12:40 ` [PATCH V15 08/14] drm/xe/vram: Add page offline data structures and lifecycle Tejas Upadhyay
2026-08-12 12:01   ` Ghimiray, Himal Prasad
2026-08-14  6:38     ` Upadhyay, Tejas
2026-08-11 12:40 ` [PATCH V15 09/14] drm/xe/vram: Add VRAM page offline fault handler Tejas Upadhyay
2026-08-13 12:44   ` Ghimiray, Himal Prasad
2026-08-14  5:19     ` Upadhyay, Tejas
2026-08-14 10:16       ` Upadhyay, Tejas
2026-08-11 12:40 ` [PATCH V15 10/14] drm/xe/configfs: Add vram bad page reservation policy Tejas Upadhyay
2026-08-12 12:21   ` Ghimiray, Himal Prasad
2026-08-11 12:40 ` [PATCH V15 11/14] drm/xe/vram: Use RCU for lock-free sysfs reads of bad page lists Tejas Upadhyay
2026-08-12 12:14   ` Ghimiray, Himal Prasad [this message]
2026-08-11 12:40 ` [PATCH V15 12/14] drm/xe: Add sysfs interface for bad gpu vram pages Tejas Upadhyay
2026-08-12 12:27   ` Ghimiray, Himal Prasad
2026-08-11 12:40 ` [PATCH V15 13/14] drm/xe/uapi: Expose ban reason in EXEC_QUEUE_GET_PROPERTY_BAN Tejas Upadhyay
2026-08-11 20:08   ` Rodrigo Vivi
2026-08-12 12:24   ` Ghimiray, Himal Prasad
2026-08-11 12:40 ` [PATCH V15 14/14] drm/xe: Add fault-inject based VRAM page offline injection Tejas Upadhyay
2026-08-16 14:35   ` Ghimiray, Himal Prasad

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e768c091-fa7a-4ce5-b8d1-4f9d45ac2916@intel.com \
    --to=himal.prasad.ghimiray@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=tejas.upadhyay@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox