7
7
#include <linux/fs.h>
8
8
#include <linux/dax.h>
9
9
#include <linux/pci.h>
10
+ #include <linux/interrupt.h>
11
+ #include <linux/group_cpus.h>
10
12
#include <linux/pfn_t.h>
11
13
#include <linux/memremap.h>
12
14
#include <linux/module.h>
@@ -67,6 +69,8 @@ struct virtio_fs {
67
69
unsigned int num_request_queues ; /* number of request queues */
68
70
struct dax_device * dax_dev ;
69
71
72
+ unsigned int * mq_map ; /* index = cpu id, value = request vq id */
73
+
70
74
/* DAX memory window where file contents are mapped */
71
75
void * window_kaddr ;
72
76
phys_addr_t window_phys_addr ;
@@ -185,6 +189,7 @@ static void virtio_fs_ktype_release(struct kobject *kobj)
185
189
{
186
190
struct virtio_fs * vfs = container_of (kobj , struct virtio_fs , kobj );
187
191
192
+ kfree (vfs -> mq_map );
188
193
kfree (vfs -> vqs );
189
194
kfree (vfs );
190
195
}
@@ -706,6 +711,44 @@ static void virtio_fs_requests_done_work(struct work_struct *work)
706
711
}
707
712
}
708
713
714
+ static void virtio_fs_map_queues (struct virtio_device * vdev , struct virtio_fs * fs )
715
+ {
716
+ const struct cpumask * mask , * masks ;
717
+ unsigned int q , cpu ;
718
+
719
+ /* First attempt to map using existing transport layer affinities
720
+ * e.g. PCIe MSI-X
721
+ */
722
+ if (!vdev -> config -> get_vq_affinity )
723
+ goto fallback ;
724
+
725
+ for (q = 0 ; q < fs -> num_request_queues ; q ++ ) {
726
+ mask = vdev -> config -> get_vq_affinity (vdev , VQ_REQUEST + q );
727
+ if (!mask )
728
+ goto fallback ;
729
+
730
+ for_each_cpu (cpu , mask )
731
+ fs -> mq_map [cpu ] = q ;
732
+ }
733
+
734
+ return ;
735
+ fallback :
736
+ /* Attempt to map evenly in groups over the CPUs */
737
+ masks = group_cpus_evenly (fs -> num_request_queues );
738
+ /* If even this fails we default to all CPUs use queue zero */
739
+ if (!masks ) {
740
+ for_each_possible_cpu (cpu )
741
+ fs -> mq_map [cpu ] = 0 ;
742
+ return ;
743
+ }
744
+
745
+ for (q = 0 ; q < fs -> num_request_queues ; q ++ ) {
746
+ for_each_cpu (cpu , & masks [q ])
747
+ fs -> mq_map [cpu ] = q ;
748
+ }
749
+ kfree (masks );
750
+ }
751
+
709
752
/* Virtqueue interrupt handler */
710
753
static void virtio_fs_vq_done (struct virtqueue * vq )
711
754
{
@@ -742,6 +785,11 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
742
785
{
743
786
struct virtqueue * * vqs ;
744
787
vq_callback_t * * callbacks ;
788
+ /* Specify pre_vectors to ensure that the queues before the
789
+ * request queues (e.g. hiprio) don't claim any of the CPUs in
790
+ * the multi-queue mapping and interrupt affinities
791
+ */
792
+ struct irq_affinity desc = { .pre_vectors = VQ_REQUEST };
745
793
const char * * names ;
746
794
unsigned int i ;
747
795
int ret = 0 ;
@@ -751,6 +799,9 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
751
799
if (fs -> num_request_queues == 0 )
752
800
return - EINVAL ;
753
801
802
+ /* Truncate nr of request queues to nr_cpu_id */
803
+ fs -> num_request_queues = min_t (unsigned int , fs -> num_request_queues ,
804
+ nr_cpu_ids );
754
805
fs -> nvqs = VQ_REQUEST + fs -> num_request_queues ;
755
806
fs -> vqs = kcalloc (fs -> nvqs , sizeof (fs -> vqs [VQ_HIPRIO ]), GFP_KERNEL );
756
807
if (!fs -> vqs )
@@ -760,7 +811,9 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
760
811
callbacks = kmalloc_array (fs -> nvqs , sizeof (callbacks [VQ_HIPRIO ]),
761
812
GFP_KERNEL );
762
813
names = kmalloc_array (fs -> nvqs , sizeof (names [VQ_HIPRIO ]), GFP_KERNEL );
763
- if (!vqs || !callbacks || !names ) {
814
+ fs -> mq_map = kcalloc_node (nr_cpu_ids , sizeof (* fs -> mq_map ), GFP_KERNEL ,
815
+ dev_to_node (& vdev -> dev ));
816
+ if (!vqs || !callbacks || !names || !fs -> mq_map ) {
764
817
ret = - ENOMEM ;
765
818
goto out ;
766
819
}
@@ -780,7 +833,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
780
833
names [i ] = fs -> vqs [i ].name ;
781
834
}
782
835
783
- ret = virtio_find_vqs (vdev , fs -> nvqs , vqs , callbacks , names , NULL );
836
+ ret = virtio_find_vqs (vdev , fs -> nvqs , vqs , callbacks , names , & desc );
784
837
if (ret < 0 )
785
838
goto out ;
786
839
@@ -792,8 +845,10 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
792
845
kfree (names );
793
846
kfree (callbacks );
794
847
kfree (vqs );
795
- if (ret )
848
+ if (ret ) {
796
849
kfree (fs -> vqs );
850
+ kfree (fs -> mq_map );
851
+ }
797
852
return ret ;
798
853
}
799
854
@@ -939,7 +994,7 @@ static int virtio_fs_probe(struct virtio_device *vdev)
939
994
if (ret < 0 )
940
995
goto out ;
941
996
942
- /* TODO vq affinity */
997
+ virtio_fs_map_queues ( vdev , fs );
943
998
944
999
ret = virtio_fs_setup_dax (vdev , fs );
945
1000
if (ret < 0 )
@@ -1288,7 +1343,7 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq,
1288
1343
static void virtio_fs_wake_pending_and_unlock (struct fuse_iqueue * fiq )
1289
1344
__releases (fiq - > lock )
1290
1345
{
1291
- unsigned int queue_id = VQ_REQUEST ; /* TODO multiqueue */
1346
+ unsigned int queue_id ;
1292
1347
struct virtio_fs * fs ;
1293
1348
struct fuse_req * req ;
1294
1349
struct virtio_fs_vq * fsvq ;
@@ -1302,11 +1357,13 @@ __releases(fiq->lock)
1302
1357
spin_unlock (& fiq -> lock );
1303
1358
1304
1359
fs = fiq -> priv ;
1360
+ queue_id = VQ_REQUEST + fs -> mq_map [raw_smp_processor_id ()];
1305
1361
1306
- pr_debug ("%s: opcode %u unique %#llx nodeid %#llx in.len %u out.len %u\n" ,
1307
- __func__ , req -> in .h .opcode , req -> in .h .unique ,
1362
+ pr_debug ("%s: opcode %u unique %#llx nodeid %#llx in.len %u out.len %u queue_id %u \n" ,
1363
+ __func__ , req -> in .h .opcode , req -> in .h .unique ,
1308
1364
req -> in .h .nodeid , req -> in .h .len ,
1309
- fuse_len_args (req -> args -> out_numargs , req -> args -> out_args ));
1365
+ fuse_len_args (req -> args -> out_numargs , req -> args -> out_args ),
1366
+ queue_id );
1310
1367
1311
1368
fsvq = & fs -> vqs [queue_id ];
1312
1369
ret = virtio_fs_enqueue_req (fsvq , req , false);
0 commit comments