@@ -96,21 +96,18 @@ struct mbox_cmd {
9696 * @dev: driver core device object
9797 * @cdev: char dev core object for ioctl operations
9898 * @cxlm: pointer to the parent device driver data
99- * @ops_active: active user of @cxlm in ops handlers
100- * @ops_dead: completion when all @cxlm ops users have exited
10199 * @id: id number of this memdev instance.
102100 */
103101struct cxl_memdev {
104102 struct device dev ;
105103 struct cdev cdev ;
106104 struct cxl_mem * cxlm ;
107- struct percpu_ref ops_active ;
108- struct completion ops_dead ;
109105 int id ;
110106};
111107
112108static int cxl_mem_major ;
113109static DEFINE_IDA (cxl_memdev_ida );
110+ static DECLARE_RWSEM (cxl_memdev_rwsem );
114111static struct dentry * cxl_debugfs ;
115112static bool cxl_raw_allow_all ;
116113
@@ -776,26 +773,43 @@ static long __cxl_memdev_ioctl(struct cxl_memdev *cxlmd, unsigned int cmd,
776773static long cxl_memdev_ioctl (struct file * file , unsigned int cmd ,
777774 unsigned long arg )
778775{
779- struct cxl_memdev * cxlmd ;
780- struct inode * inode ;
781- int rc = - ENOTTY ;
776+ struct cxl_memdev * cxlmd = file -> private_data ;
777+ int rc = - ENXIO ;
782778
783- inode = file_inode (file );
784- cxlmd = container_of (inode -> i_cdev , typeof (* cxlmd ), cdev );
779+ down_read (& cxl_memdev_rwsem );
780+ if (cxlmd -> cxlm )
781+ rc = __cxl_memdev_ioctl (cxlmd , cmd , arg );
782+ up_read (& cxl_memdev_rwsem );
785783
786- if (! percpu_ref_tryget_live ( & cxlmd -> ops_active ))
787- return - ENXIO ;
784+ return rc ;
785+ }
788786
789- rc = __cxl_memdev_ioctl (cxlmd , cmd , arg );
787+ static int cxl_memdev_open (struct inode * inode , struct file * file )
788+ {
789+ struct cxl_memdev * cxlmd =
790+ container_of (inode -> i_cdev , typeof (* cxlmd ), cdev );
790791
791- percpu_ref_put (& cxlmd -> ops_active );
792+ get_device (& cxlmd -> dev );
793+ file -> private_data = cxlmd ;
792794
793- return rc ;
795+ return 0 ;
796+ }
797+
798+ static int cxl_memdev_release_file (struct inode * inode , struct file * file )
799+ {
800+ struct cxl_memdev * cxlmd =
801+ container_of (inode -> i_cdev , typeof (* cxlmd ), cdev );
802+
803+ put_device (& cxlmd -> dev );
804+
805+ return 0 ;
794806}
795807
796808static const struct file_operations cxl_memdev_fops = {
797809 .owner = THIS_MODULE ,
798810 .unlocked_ioctl = cxl_memdev_ioctl ,
811+ .open = cxl_memdev_open ,
812+ .release = cxl_memdev_release_file ,
799813 .compat_ioctl = compat_ptr_ioctl ,
800814 .llseek = noop_llseek ,
801815};
@@ -1049,7 +1063,6 @@ static void cxl_memdev_release(struct device *dev)
10491063{
10501064 struct cxl_memdev * cxlmd = to_cxl_memdev (dev );
10511065
1052- percpu_ref_exit (& cxlmd -> ops_active );
10531066 ida_free (& cxl_memdev_ida , cxlmd -> id );
10541067 kfree (cxlmd );
10551068}
@@ -1150,24 +1163,21 @@ static const struct device_type cxl_memdev_type = {
11501163 .groups = cxl_memdev_attribute_groups ,
11511164};
11521165
1153- static void cxlmdev_unregister ( void * _cxlmd )
1166+ static void cxl_memdev_shutdown ( struct cxl_memdev * cxlmd )
11541167{
1155- struct cxl_memdev * cxlmd = _cxlmd ;
1156- struct device * dev = & cxlmd -> dev ;
1157-
1158- percpu_ref_kill (& cxlmd -> ops_active );
1159- cdev_device_del (& cxlmd -> cdev , dev );
1160- wait_for_completion (& cxlmd -> ops_dead );
1168+ down_write (& cxl_memdev_rwsem );
11611169 cxlmd -> cxlm = NULL ;
1162- put_device ( dev );
1170+ up_write ( & cxl_memdev_rwsem );
11631171}
11641172
1165- static void cxlmdev_ops_active_release ( struct percpu_ref * ref )
1173+ static void cxl_memdev_unregister ( void * _cxlmd )
11661174{
1167- struct cxl_memdev * cxlmd =
1168- container_of ( ref , typeof ( * cxlmd ), ops_active ) ;
1175+ struct cxl_memdev * cxlmd = _cxlmd ;
1176+ struct device * dev = & cxlmd -> dev ;
11691177
1170- complete (& cxlmd -> ops_dead );
1178+ cdev_device_del (& cxlmd -> cdev , dev );
1179+ cxl_memdev_shutdown (cxlmd );
1180+ put_device (dev );
11711181}
11721182
11731183static int cxl_mem_add_memdev (struct cxl_mem * cxlm )
@@ -1181,17 +1191,6 @@ static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
11811191 cxlmd = kzalloc (sizeof (* cxlmd ), GFP_KERNEL );
11821192 if (!cxlmd )
11831193 return - ENOMEM ;
1184- init_completion (& cxlmd -> ops_dead );
1185-
1186- /*
1187- * @cxlm is deallocated when the driver unbinds so operations
1188- * that are using it need to hold a live reference.
1189- */
1190- cxlmd -> cxlm = cxlm ;
1191- rc = percpu_ref_init (& cxlmd -> ops_active , cxlmdev_ops_active_release , 0 ,
1192- GFP_KERNEL );
1193- if (rc )
1194- goto err_ref ;
11951194
11961195 rc = ida_alloc_range (& cxl_memdev_ida , 0 , CXL_MEM_MAX_DEVS , GFP_KERNEL );
11971196 if (rc < 0 )
@@ -1209,23 +1208,27 @@ static int cxl_mem_add_memdev(struct cxl_mem *cxlm)
12091208 cdev = & cxlmd -> cdev ;
12101209 cdev_init (cdev , & cxl_memdev_fops );
12111210
1211+ /*
1212+ * Activate ioctl operations, no cxl_memdev_rwsem manipulation
1213+ * needed as this is ordered with cdev_add() publishing the device.
1214+ */
1215+ cxlmd -> cxlm = cxlm ;
1216+
12121217 rc = cdev_device_add (cdev , dev );
12131218 if (rc )
12141219 goto err_add ;
12151220
1216- return devm_add_action_or_reset (dev -> parent , cxlmdev_unregister , cxlmd );
1221+ return devm_add_action_or_reset (dev -> parent , cxl_memdev_unregister ,
1222+ cxlmd );
12171223
12181224err_add :
1219- ida_free (& cxl_memdev_ida , cxlmd -> id );
1220- err_id :
12211225 /*
1222- * Theoretically userspace could have already entered the fops,
1223- * so flush ops_active .
1226+ * The cdev was briefly live, shutdown any ioctl operations that
1227+ * saw that state .
12241228 */
1225- percpu_ref_kill (& cxlmd -> ops_active );
1226- wait_for_completion (& cxlmd -> ops_dead );
1227- percpu_ref_exit (& cxlmd -> ops_active );
1228- err_ref :
1229+ cxl_memdev_shutdown (cxlmd );
1230+ ida_free (& cxl_memdev_ida , cxlmd -> id );
1231+ err_id :
12291232 kfree (cxlmd );
12301233
12311234 return rc ;
0 commit comments