mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] drm/amdgpu: Implement mmap of imported dma-bufs
@ 2023-03-03 11:09 Marek Maslanka
  2023-03-03 12:50 ` Christian König
  2023-03-03 14:18 ` kernel test robot
  0 siblings, 2 replies; 3+ messages in thread
From: Marek Maslanka @ 2023-03-03 11:09 UTC (permalink / raw)
  To: dri-devel
  Cc: Marek Maslanka, Dominik Behr, Alex Deucher, Christian König,
	Pan, Xinhui, David Airlie, Daniel Vetter, Lijo Lazar,
	Guchun Chen, Felix Kuehling, Marek Maslanka, Evan Quan,
	Hawking Zhang, Mario Limonciello, YiPeng Chai,
	Michel Dänzer, Kai-Heng Feng, Luben Tuikov,
	Arunpravin Paneer Selvam, Tong Liu01, Rajneesh Bhardwaj,
	Zack Rusin, amd-gfx, linux-kernel

Use dmabuf mmap from exporting driver to do the mapping.

Signed-off-by: Marek Maslanka <mmaslanka@chromium.org>
Signed-off-by: Dominik Behr <dbehr@chromium.org>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 46 +++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h |  2 +
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c     |  2 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c     |  9 ++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h     |  1 +
 5 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
index 0c001bb8fc2b..8f22d29ba077 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
@@ -37,6 +37,7 @@
 #include "amdgpu_dma_buf.h"
 #include "amdgpu_xgmi.h"
 #include <drm/amdgpu_drm.h>
+#include <drm/drm_drv.h>
 #include <drm/ttm/ttm_tt.h>
 #include <linux/dma-buf.h>
 #include <linux/dma-fence-array.h>
@@ -275,6 +276,51 @@ const struct dma_buf_ops amdgpu_dmabuf_ops = {
 	.vunmap = drm_gem_dmabuf_vunmap,
 };
 
+int amdgpu_try_dma_buf_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_file *priv = filp->private_data;
+	struct drm_device *dev = priv->minor->dev;
+	struct amdgpu_device *adev = drm_to_adev(dev);
+	struct ttm_device *bdev = &adev->mman.bdev;
+	struct ttm_buffer_object *tbo = NULL;
+	struct amdgpu_bo *bo = NULL;
+	struct drm_gem_object *obj = NULL;
+	struct drm_vma_offset_node *node;
+	int ret;
+
+	if (drm_dev_is_unplugged(dev))
+		return -ENODEV;
+
+	drm_vma_offset_lock_lookup(bdev->vma_manager);
+	node = drm_vma_offset_exact_lookup_locked(bdev->vma_manager,
+						  vma->vm_pgoff,
+						  vma_pages(vma));
+
+	if (likely(node)) {
+		tbo = container_of(node, struct ttm_buffer_object,
+				   base.vma_node);
+		tbo = ttm_bo_get_unless_zero(tbo);
+	}
+	drm_vma_offset_unlock_lookup(bdev->vma_manager);
+
+	if (!tbo)
+		return -EINVAL;
+
+	bo = ttm_to_amdgpu_bo(tbo);
+	obj = &tbo->base;
+
+	if (!obj->import_attach) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = dma_buf_mmap(obj->import_attach->dmabuf, vma, 0);
+
+done:
+	ttm_bo_put(tbo);
+	return ret;
+}
+
 /**
  * amdgpu_gem_prime_export - &drm_driver.gem_prime_export implementation
  * @gobj: GEM BO
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h
index 3e93b9b407a9..ecf1dc32eec4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h
@@ -25,6 +25,8 @@
 
 #include <drm/drm_gem.h>
 
+int amdgpu_try_dma_buf_mmap(struct file *filp, struct vm_area_struct *vma);
+
 struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj,
 					int flags);
 struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 86fbb4138285..91e94342d48e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -2737,7 +2737,7 @@ static const struct file_operations amdgpu_driver_kms_fops = {
 	.flush = amdgpu_flush,
 	.release = drm_release,
 	.unlocked_ioctl = amdgpu_drm_ioctl,
-	.mmap = drm_gem_mmap,
+	.mmap = amdgpu_mmap,
 	.poll = drm_poll,
 	.read = drm_read,
 #ifdef CONFIG_COMPAT
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index c5ef7f7bdc15..41944439cd6c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -61,6 +61,7 @@
 #include "amdgpu_hmm.h"
 #include "amdgpu_atomfirmware.h"
 #include "amdgpu_res_cursor.h"
+#include "amdgpu_dma_buf.h"
 #include "bif/bif_4_1_d.h"
 
 MODULE_IMPORT_NS(DMA_BUF);
@@ -1994,6 +1995,14 @@ static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev,
 						   DMA_RESV_USAGE_BOOKKEEP);
 }
 
+int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	if (amdgpu_try_dma_buf_mmap(filp, vma) == 0)
+		return 0;
+
+	return drm_gem_mmap(filp, vma);
+}
+
 int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
 		       uint64_t dst_offset, uint32_t byte_count,
 		       struct dma_resv *resv,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
index e2cd5894afc9..e4cd1bda7a2b 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
@@ -152,6 +152,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
 			struct dma_resv *resv,
 			struct dma_fence **fence);
 
+int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma);
 int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo);
 void amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo);
 uint64_t amdgpu_ttm_domain_start(struct amdgpu_device *adev, uint32_t type);
-- 
2.40.0.rc0.216.gc4246ad0f0-goog


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] drm/amdgpu: Implement mmap of imported dma-bufs
  2023-03-03 11:09 [PATCH] drm/amdgpu: Implement mmap of imported dma-bufs Marek Maslanka
@ 2023-03-03 12:50 ` Christian König
  2023-03-03 14:18 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: Christian König @ 2023-03-03 12:50 UTC (permalink / raw)
  To: Marek Maslanka, dri-devel, Daniel Vetter
  Cc: Dominik Behr, Alex Deucher, Pan, Xinhui, David Airlie,
	Lijo Lazar, Guchun Chen, Felix Kuehling, Marek Maslanka,
	Evan Quan, Hawking Zhang, Mario Limonciello, YiPeng Chai,
	Michel Dänzer, Kai-Heng Feng, Luben Tuikov,
	Arunpravin Paneer Selvam, Tong Liu01, Rajneesh Bhardwaj,
	Zack Rusin, amd-gfx, linux-kernel

Well big NAK to this!

We have discussed this extensively on the mailing list and absolutely 
don't want to allow that.

Only for some ARM drivers we failed to block that soon enough and will 
keep the functionality around to not break userspace.

Regards,
Christian.

Am 03.03.23 um 12:09 schrieb Marek Maslanka:
> Use dmabuf mmap from exporting driver to do the mapping.
>
> Signed-off-by: Marek Maslanka <mmaslanka@chromium.org>
> Signed-off-by: Dominik Behr <dbehr@chromium.org>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 46 +++++++++++++++++++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h |  2 +
>   drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c     |  2 +-
>   drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c     |  9 ++++
>   drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h     |  1 +
>   5 files changed, 59 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
> index 0c001bb8fc2b..8f22d29ba077 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
> @@ -37,6 +37,7 @@
>   #include "amdgpu_dma_buf.h"
>   #include "amdgpu_xgmi.h"
>   #include <drm/amdgpu_drm.h>
> +#include <drm/drm_drv.h>
>   #include <drm/ttm/ttm_tt.h>
>   #include <linux/dma-buf.h>
>   #include <linux/dma-fence-array.h>
> @@ -275,6 +276,51 @@ const struct dma_buf_ops amdgpu_dmabuf_ops = {
>   	.vunmap = drm_gem_dmabuf_vunmap,
>   };
>   
> +int amdgpu_try_dma_buf_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +	struct drm_file *priv = filp->private_data;
> +	struct drm_device *dev = priv->minor->dev;
> +	struct amdgpu_device *adev = drm_to_adev(dev);
> +	struct ttm_device *bdev = &adev->mman.bdev;
> +	struct ttm_buffer_object *tbo = NULL;
> +	struct amdgpu_bo *bo = NULL;
> +	struct drm_gem_object *obj = NULL;
> +	struct drm_vma_offset_node *node;
> +	int ret;
> +
> +	if (drm_dev_is_unplugged(dev))
> +		return -ENODEV;
> +
> +	drm_vma_offset_lock_lookup(bdev->vma_manager);
> +	node = drm_vma_offset_exact_lookup_locked(bdev->vma_manager,
> +						  vma->vm_pgoff,
> +						  vma_pages(vma));
> +
> +	if (likely(node)) {
> +		tbo = container_of(node, struct ttm_buffer_object,
> +				   base.vma_node);
> +		tbo = ttm_bo_get_unless_zero(tbo);
> +	}
> +	drm_vma_offset_unlock_lookup(bdev->vma_manager);
> +
> +	if (!tbo)
> +		return -EINVAL;
> +
> +	bo = ttm_to_amdgpu_bo(tbo);
> +	obj = &tbo->base;
> +
> +	if (!obj->import_attach) {
> +		ret = -EINVAL;
> +		goto done;
> +	}
> +
> +	ret = dma_buf_mmap(obj->import_attach->dmabuf, vma, 0);
> +
> +done:
> +	ttm_bo_put(tbo);
> +	return ret;
> +}
> +
>   /**
>    * amdgpu_gem_prime_export - &drm_driver.gem_prime_export implementation
>    * @gobj: GEM BO
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h
> index 3e93b9b407a9..ecf1dc32eec4 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.h
> @@ -25,6 +25,8 @@
>   
>   #include <drm/drm_gem.h>
>   
> +int amdgpu_try_dma_buf_mmap(struct file *filp, struct vm_area_struct *vma);
> +
>   struct dma_buf *amdgpu_gem_prime_export(struct drm_gem_object *gobj,
>   					int flags);
>   struct drm_gem_object *amdgpu_gem_prime_import(struct drm_device *dev,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 86fbb4138285..91e94342d48e 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -2737,7 +2737,7 @@ static const struct file_operations amdgpu_driver_kms_fops = {
>   	.flush = amdgpu_flush,
>   	.release = drm_release,
>   	.unlocked_ioctl = amdgpu_drm_ioctl,
> -	.mmap = drm_gem_mmap,
> +	.mmap = amdgpu_mmap,
>   	.poll = drm_poll,
>   	.read = drm_read,
>   #ifdef CONFIG_COMPAT
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> index c5ef7f7bdc15..41944439cd6c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> @@ -61,6 +61,7 @@
>   #include "amdgpu_hmm.h"
>   #include "amdgpu_atomfirmware.h"
>   #include "amdgpu_res_cursor.h"
> +#include "amdgpu_dma_buf.h"
>   #include "bif/bif_4_1_d.h"
>   
>   MODULE_IMPORT_NS(DMA_BUF);
> @@ -1994,6 +1995,14 @@ static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev,
>   						   DMA_RESV_USAGE_BOOKKEEP);
>   }
>   
> +int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +	if (amdgpu_try_dma_buf_mmap(filp, vma) == 0)
> +		return 0;
> +
> +	return drm_gem_mmap(filp, vma);
> +}
> +
>   int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
>   		       uint64_t dst_offset, uint32_t byte_count,
>   		       struct dma_resv *resv,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
> index e2cd5894afc9..e4cd1bda7a2b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
> @@ -152,6 +152,7 @@ int amdgpu_fill_buffer(struct amdgpu_bo *bo,
>   			struct dma_resv *resv,
>   			struct dma_fence **fence);
>   
> +int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma);
>   int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo);
>   void amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo);
>   uint64_t amdgpu_ttm_domain_start(struct amdgpu_device *adev, uint32_t type);


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] drm/amdgpu: Implement mmap of imported dma-bufs
  2023-03-03 11:09 [PATCH] drm/amdgpu: Implement mmap of imported dma-bufs Marek Maslanka
  2023-03-03 12:50 ` Christian König
@ 2023-03-03 14:18 ` kernel test robot
  1 sibling, 0 replies; 3+ messages in thread
From: kernel test robot @ 2023-03-03 14:18 UTC (permalink / raw)
  To: Marek Maslanka, dri-devel
  Cc: oe-kbuild-all, Lijo Lazar, linux-kernel, Michel Dänzer,
	Kai-Heng Feng, Mario Limonciello, Guchun Chen, amd-gfx,
	Marek Maslanka, Luben Tuikov, Arunpravin Paneer Selvam,
	Dominik Behr, Evan Quan, Tong Liu01, Felix Kuehling, Pan, Xinhui,
	Rajneesh Bhardwaj, YiPeng Chai, Alex Deucher,
	Christian König, Hawking Zhang

Hi Marek,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on drm/drm-next drm-intel/for-linux-next drm-tip/drm-tip linus/master next-20230303]
[cannot apply to drm-intel/for-linux-next-fixes v6.2]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Marek-Maslanka/drm-amdgpu-Implement-mmap-of-imported-dma-bufs/20230303-191145
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20230303110951.3777850-1-mmaslanka%40chromium.org
patch subject: [PATCH] drm/amdgpu: Implement mmap of imported dma-bufs
config: sparc-allyesconfig (https://download.01.org/0day-ci/archive/20230303/202303032218.9kvEePUv-lkp@intel.com/config)
compiler: sparc64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/2916257baab842afa387781faf1b595b73249767
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Marek-Maslanka/drm-amdgpu-Implement-mmap-of-imported-dma-bufs/20230303-191145
        git checkout 2916257baab842afa387781faf1b595b73249767
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sparc SHELL=/bin/bash drivers/gpu/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202303032218.9kvEePUv-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c: In function 'amdgpu_try_dma_buf_mmap':
>> drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:286:27: warning: variable 'bo' set but not used [-Wunused-but-set-variable]
     286 |         struct amdgpu_bo *bo = NULL;
         |                           ^~
   In file included from drivers/gpu/drm/amd/amdgpu/../display/dc/dc_types.h:36,
                    from drivers/gpu/drm/amd/amdgpu/../display/dc/dm_services_types.h:30,
                    from drivers/gpu/drm/amd/amdgpu/../include/dm_pp_interface.h:26,
                    from drivers/gpu/drm/amd/amdgpu/amdgpu.h:64,
                    from drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c:34:
   drivers/gpu/drm/amd/amdgpu/../display/dc/dc_hdmi_types.h: At top level:
   drivers/gpu/drm/amd/amdgpu/../display/dc/dc_hdmi_types.h:53:22: warning: 'dp_hdmi_dongle_signature_str' defined but not used [-Wunused-const-variable=]
      53 | static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR";
         |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/bo +286 drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c

   278	
   279	int amdgpu_try_dma_buf_mmap(struct file *filp, struct vm_area_struct *vma)
   280	{
   281		struct drm_file *priv = filp->private_data;
   282		struct drm_device *dev = priv->minor->dev;
   283		struct amdgpu_device *adev = drm_to_adev(dev);
   284		struct ttm_device *bdev = &adev->mman.bdev;
   285		struct ttm_buffer_object *tbo = NULL;
 > 286		struct amdgpu_bo *bo = NULL;
   287		struct drm_gem_object *obj = NULL;
   288		struct drm_vma_offset_node *node;
   289		int ret;
   290	
   291		if (drm_dev_is_unplugged(dev))
   292			return -ENODEV;
   293	
   294		drm_vma_offset_lock_lookup(bdev->vma_manager);
   295		node = drm_vma_offset_exact_lookup_locked(bdev->vma_manager,
   296							  vma->vm_pgoff,
   297							  vma_pages(vma));
   298	
   299		if (likely(node)) {
   300			tbo = container_of(node, struct ttm_buffer_object,
   301					   base.vma_node);
   302			tbo = ttm_bo_get_unless_zero(tbo);
   303		}
   304		drm_vma_offset_unlock_lookup(bdev->vma_manager);
   305	
   306		if (!tbo)
   307			return -EINVAL;
   308	
   309		bo = ttm_to_amdgpu_bo(tbo);
   310		obj = &tbo->base;
   311	
   312		if (!obj->import_attach) {
   313			ret = -EINVAL;
   314			goto done;
   315		}
   316	
   317		ret = dma_buf_mmap(obj->import_attach->dmabuf, vma, 0);
   318	
   319	done:
   320		ttm_bo_put(tbo);
   321		return ret;
   322	}
   323	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-03-03 14:19 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-03 11:09 [PATCH] drm/amdgpu: Implement mmap of imported dma-bufs Marek Maslanka
2023-03-03 12:50 ` Christian König
2023-03-03 14:18 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®