strace: Remove the ability to write to Qstrace
[akaros.git] / kern / drivers / net / udrvr / compat.c
1 /*
2  * Copyright (c) 2016 Google Inc
3  * Author: Kanoj Sarcar <kanoj@google.com>
4  * See LICENSE for details.
5  */
6
7 #include <err.h>
8 #include <kmalloc.h>
9 #include <kref.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <assert.h>
13 #include <error.h>
14 #include <pmap.h>
15 #include <smp.h>
16 #include <devfs.h>
17 #include <linux/rdma/ib_user_verbs.h>
18 #include "uverbs.h"
19 #include <ros/procinfo.h>
20
21 static unsigned long pgprot_val(int vmprot)
22 {
23         unsigned long   prot = PTE_P | PTE_U | PTE_A;
24
25         if (vmprot & PROT_WRITE)
26                 prot |= PTE_W | PTE_D;
27         return prot;
28 }
29
30 unsigned long pgprot_noncached(int vmprot)
31 {
32         return pgprot_val(vmprot) | PTE_NOCACHE;
33 }
34
35 unsigned long pgprot_writecombine(int vmprot)
36 {
37         return pgprot_val(vmprot) | PTE_WRITECOMB;
38 }
39
40 /*
41  * Our version knocked off from kern/src/mm.c version + uncaching logic from
42  * vmap_pmem_nocache(). This routine is expected to be invoked as part of mmap()
43  * handler.
44  */
45 int map_upage_at_addr(struct proc *p, physaddr_t paddr, uintptr_t addr, int pteprot, int dolock)
46 {
47         pte_t           pte;
48         int             rv = -1;
49         struct page     *pp;
50
51         /* __vmr_free_pgs() assumes mapped pte is backed by "struct page" */
52         if (paddr > max_paddr) {
53                 printk("[akaros]: map_upage_at_addr(): paddr=0x%llx "
54                     "max_paddr=0x%llx\n", paddr, max_paddr);
55                 return -1;
56         }
57
58         pp = pa2page(paddr);
59
60         /* __vmr_free_pgs() refcnt's pagemap pages differently */
61         if (atomic_read(&pp->pg_flags) & PG_PAGEMAP) {
62                 printk("[akaros]: map_upage_at_addr(): mapPA=0x%llx\n",
63                     paddr);
64                 return -1;
65         }
66
67         spin_lock(&p->pte_lock);
68
69         /*
70          * Free any existing page backing uva, drop in this page, and
71          * acquire refcnt on page on behalf of user. Note though that we
72          * do not expect an existing page, since we are invoked in mmap
73          * path (page_insert() does not handle PG_PAGEMAP refcnt's).
74          */
75         rv = page_insert(p->env_pgdir, pp, (void *)addr, pteprot);
76         spin_unlock(&p->pte_lock);
77         return rv;
78 }
79
80 void set_page_dirty_lock(struct page *pagep)
81 {
82         atomic_or(&pagep->pg_flags, PG_DIRTY);
83 }
84
85 void put_page(struct page *pagep)
86 {
87         if (atomic_read(&pagep->pg_flags) & PG_PAGEMAP)
88                 printk("[akaros]: put_page() on pagemap page!!!\n");
89         page_decref(pagep);
90 }
91
92 int get_user_page(struct proc *p, unsigned long uvastart, int write, int force,
93     struct page **plist)
94 {
95         pte_t           pte;
96         int             ret = -1;
97         struct page     *pp;
98
99         spin_lock(&p->pte_lock);
100
101         pte = pgdir_walk(p->env_pgdir, (void*)uvastart, TRUE);
102
103         if (!pte_walk_okay(pte))
104                 goto err1;
105
106         if (!pte_is_present(pte)) {
107                 unsigned long prot = PTE_P | PTE_U | PTE_A | PTE_W | PTE_D;
108 #if 0
109                 printk("[akaros]: get_user_page() uva=0x%llx pte absent\n",
110                     uvastart);
111 #endif
112                 /*
113                  * TODO: ok to allocate with pte_lock? "prot" needs to be
114                  * based on VMR writability, refer to pgprot_noncached().
115                  */
116                 if (upage_alloc(p, &pp, 0))
117                         goto err1;
118                 pte_write(pte, page2pa(pp), prot);
119         } else {
120                 pp = pa2page(pte_get_paddr(pte));
121
122                 /* __vmr_free_pgs() refcnt's pagemap pages differently */
123                 if (atomic_read(&pp->pg_flags) & PG_PAGEMAP) {
124                         printk("[akaros]: get_user_page(): uva=0x%llx\n",
125                             uvastart);
126                         goto err1;
127                 }
128         }
129
130         if (write && (!pte_has_perm_urw(pte))) {
131                 /* TODO: How is Linux using the "force" parameter */
132                 printk("[akaros]: get_user_page() uva=0x%llx pte ro\n",
133                     uvastart);
134                 goto err1;
135         }
136
137         /* TODO (GUP): change the interface such that devices provide the memory and
138          * the user mmaps it, instead of trying to pin arbitrary user memory. */
139         warn_once("Extremely unsafe, unpinned memory mapped!  If your process dies, you might scribble on RAM!");
140
141         plist[0] = pp;
142         ret = 1;
143 err1:
144         spin_unlock(&p->pte_lock);
145         return ret;
146 }
147
148 int sg_alloc_table(struct sg_table *ptr, unsigned int npages, gfp_t mask)
149 {
150         ptr->sgl = kmalloc((sizeof(struct scatterlist) * npages), mask);
151         ptr->nents = ptr->orig_nents = npages;
152         sg_init_table(ptr->sgl, npages);
153         return 0;
154 }
155
156 void sg_free_table(struct sg_table *ptr)
157 {
158         kfree(ptr->sgl);
159 }
160
161 void idr_remove(struct idr *idp, int id)
162 {
163         BUG_ON((id < 0) || (id >= MAXITEMS));
164         idp->values[id] = NULL;
165 }
166
167 void *idr_find(struct idr *idp, int id)
168 {
169         BUG_ON((id < 0) || (id >= MAXITEMS));
170         BUG_ON(idp->values[id] == NULL);
171         return idp->values[id];
172 }
173
174 int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask)
175 {
176         int     i;
177
178         /* We use values[] == NULL as an indicator that slot is free */
179         BUG_ON(ptr == NULL);
180
181         spin_lock_irqsave(&idp->lock, f);
182
183         for (i = 0; i < MAXITEMS; i++) {
184                 if (idp->values[i] == NULL) {
185                         idp->values[i] = ptr;
186                         goto done;
187                 }
188         }
189
190         i = -1;                 /* error return */
191
192 done:
193         spin_unlock_irqsave(&idp->lock);
194         return i;
195 }
196
197 /* START: Linux /sys support for lib/apps */
198
199 /* Callers must pass in null terminated strings */
200 static ssize_t sysfs_read(char __user *buf, size_t ucount, loff_t *pos,
201     char *src)
202 {
203         int             slen = strlen(src) + 1; /* + 1 for terminating null */
204         unsigned long   off = *pos, nb = slen - off;
205
206         if (off >= slen)
207                 return 0;
208
209         if (copy_to_user(buf, (src + off), nb))
210                 return -EFAULT;
211
212         *pos += nb;
213         return nb;
214 }
215
216 static ssize_t ib_api_ver_read(struct file *filp, char __user *buf,
217     size_t count, loff_t *pos)
218 {
219         char            src[4] = { 0, 0, 0, 0};
220
221         src[0] = '0' + IB_USER_VERBS_ABI_VERSION;
222
223         return sysfs_read(buf, count, pos, src);
224 }
225
226 static const struct file_operations ib_api_ver = {
227         .read   = ib_api_ver_read,
228         .open   = kfs_open,
229         .release= kfs_release,
230 };
231
232 static ssize_t mlx4_mgm_read(struct file *filp, char __user *buf,
233     size_t count, loff_t *pos)
234 {
235 #if CONFIG_MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE == -1
236         char            src[4] = { '-', '1', 0, 0 };
237 #else
238         char            src[4] = { '1', '0', 0, 0 };
239 #endif
240
241         return sysfs_read(buf, count, pos, src);
242 }
243
244 static const struct file_operations mlx4_mgm = {
245         .read   = mlx4_mgm_read,
246         .open   = kfs_open,
247         .release= kfs_release,
248 };
249
250 #if 0
251 static void stradd(char *dest, int val, int num)
252 {
253         int     tval = val, i = 0, fac = 1;
254
255         while (tval) {
256                 tval /= 10;
257                 fac *= 10;
258                 i++;
259         }
260         fac /= 10;
261         tval = val;
262         while (tval && num) {
263                 int dig = tval / fac;
264                 *dest++ = dig + '0';
265                 tval -= (dig * fac);
266                 fac /= 10;
267                 num--;
268         }
269 }
270
271 static ssize_t cpu_read(struct file *filp, char __user *buf,
272     size_t count, loff_t *pos)
273 {
274         char cpu_info_str[128];
275         long freq = __proc_global_info.tsc_freq, idx;
276
277         strncpy(cpu_info_str, "cpu MHz\t\t: ", 16);
278         idx = strlen(cpu_info_str);
279
280         stradd(cpu_info_str + idx, freq / 1000000, 4);
281         idx += 4;
282
283         strncpy(cpu_info_str + idx, ".", 1);
284         idx++;
285
286         stradd(cpu_info_str + idx, freq % 1000000, 3);
287         idx += 3;
288
289         cpu_info_str[idx] = 0;
290
291         return sysfs_read(buf, count, pos, cpu_info_str);
292 }
293
294 static const struct file_operations cpuinfo = {
295         .read   = cpu_read,
296         .open   = kfs_open,
297         .release= kfs_release,
298 };
299 #endif
300
301 void sysfs_init(void)
302 {
303         do_mkdir("/dev_vfs/infiniband", S_IRWXU | S_IRWXG | S_IRWXO);
304         do_mkdir("/sys", S_IRWXU | S_IRWXG | S_IRWXO);
305         do_mkdir("/sys/class", S_IRWXU | S_IRWXG | S_IRWXO);
306         do_mkdir("/sys/class/infiniband_verbs", S_IRWXU | S_IRWXG | S_IRWXO);
307         do_mkdir("/sys/class/infiniband", S_IRWXU | S_IRWXG | S_IRWXO);
308
309         make_device("/sys/class/infiniband_verbs/abi_version",
310                     S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
311                     __S_IFCHR, (struct file_operations *)&ib_api_ver);
312
313         do_mkdir("/sys/module", S_IRWXU | S_IRWXG | S_IRWXO);
314         do_mkdir("/sys/module/mlx4_core", S_IRWXU | S_IRWXG | S_IRWXO);
315         do_mkdir("/sys/module/mlx4_core/parameters", S_IRWXU | S_IRWXG |
316             S_IRWXO);
317         make_device("/sys/module/mlx4_core/parameters/log_num_mgm_entry_size",
318                     S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
319                     __S_IFCHR, (struct file_operations *)&mlx4_mgm);
320
321 #if 0
322         /* Do this thru init scripts */
323         do_mkdir("/proc", S_IRWXU | S_IRWXG | S_IRWXO);
324         make_device("/proc/cpuinfo", S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR |
325             S_IRGRP | S_IROTH, __S_IFCHR, (struct file_operations *)&cpuinfo);
326 #endif
327 }
328
329 static ssize_t dver_read(struct file *filp, char __user *buf,
330     size_t count, loff_t *pos)
331 {
332         struct ib_uverbs_device *uvp;
333         char            src[4] = { 0, 0, 0, 0};
334
335         uvp = (struct ib_uverbs_device *)get_fs_info(filp);
336         src[0] = '0' + uvp->ib_dev->uverbs_abi_ver;
337
338         return sysfs_read(buf, count, pos, src);
339 }
340
341 static ssize_t dname_read(struct file *filp, char __user *buf,
342     size_t count, loff_t *pos)
343 {
344         struct ib_uverbs_device *uvp;
345
346         uvp = (struct ib_uverbs_device *)get_fs_info(filp);
347         return sysfs_read(buf, count, pos, uvp->ib_dev->name);
348 }
349
350 static ssize_t ntype_read(struct file *filp, char __user *buf,
351     size_t count, loff_t *pos)
352 {
353         char    src[] = "1";
354
355         return sysfs_read(buf, count, pos, src);
356 }
357
358 static ssize_t ddev_read(struct file *filp, char __user *buf,
359     size_t count, loff_t *pos)
360 {
361         char    src[] = "0x1003";
362
363         return sysfs_read(buf, count, pos, src);
364 }
365
366 static ssize_t dven_read(struct file *filp, char __user *buf,
367     size_t count, loff_t *pos)
368 {
369         char    src[] = "0x15b3";
370
371         return sysfs_read(buf, count, pos, src);
372 }
373
374 static ssize_t vsd_read(struct file *filp, char __user *buf,
375     size_t count, loff_t *pos)
376 {
377         char    *src = "puma20_A1-10.2.3.0";
378
379         return sysfs_read(buf, count, pos, src);
380 }
381
382 static const struct file_operations dver_fops = {
383         .read   = dver_read,
384         .open   = kfs_open,
385         .release= kfs_release,
386 };
387
388 static const struct file_operations dname_fops = {
389         .read   = dname_read,
390         .open   = kfs_open,
391         .release= kfs_release,
392 };
393
394 static const struct file_operations ddev_fops = {
395         .read   = ddev_read,
396         .open   = kfs_open,
397         .release= kfs_release,
398 };
399
400 static const struct file_operations dven_fops = {
401         .read   = dven_read,
402         .open   = kfs_open,
403         .release= kfs_release,
404 };
405
406 static const struct file_operations ntype_fops = {
407         .read   = ntype_read,
408         .open   = kfs_open,
409         .release= kfs_release,
410 };
411
412 static const struct file_operations vsd_fops = {
413         .read   = vsd_read,
414         .open   = kfs_open,
415         .release= kfs_release,
416 };
417
418 void sysfs_create(int devnum, const struct file_operations *verb_fops,
419     void *ptr)
420 {
421         char            sysname[256] = "/sys/class/infiniband_verbs/uverbs0";
422         char            devname[] = "/dev_vfs/infiniband/uverbs0";
423         char            drvname[64] = "/sys/class/infiniband/";
424         int             sysnameidx = strlen(sysname), drvidx;
425         struct file     *fp;
426         struct ib_uverbs_device *uvp = (struct ib_uverbs_device *)ptr;
427
428         /* Create correct name */
429         if (devnum > 9)
430                 panic("Too many devs");
431         devname[strlen(devname) - 1] = '0' + devnum;
432         sysname[sysnameidx - 1] = '0' + devnum;
433
434         /* Foll fops need to come from caller */
435         fp = make_device(devname,
436             S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
437             __S_IFCHR, (struct file_operations *)verb_fops);
438         set_fs_info(fp, ptr);
439
440         /* /sys/class/infiniband/mlx4_0 */
441         strncpy((drvname + strlen(drvname)), uvp->ib_dev->name, 12);
442         do_mkdir(drvname, S_IRWXU | S_IRWXG | S_IRWXO);
443         drvidx = strlen(drvname);
444
445         /* /sys/class/infiniband/mlx4_0/node_type */
446         strncpy(drvname + drvidx, "/node_type", 11);
447         make_device(drvname,
448             S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
449             __S_IFCHR, (struct file_operations *)&ntype_fops);
450
451         /* /sys/class/infiniband/mlx4_0/vsd */
452         strncpy(drvname + drvidx, "/vsd", 5);
453         fp = make_device(drvname,
454             S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
455             __S_IFCHR, (struct file_operations *)&vsd_fops);
456         set_fs_info(fp, ptr);
457
458         /* /sys/class/infiniband_verbs/uverbs0 */
459         do_mkdir(sysname, S_IRWXU | S_IRWXG | S_IRWXO);
460
461         /* /sys/class/infiniband_verbs/uverbs0/device */
462         strncpy(sysname + sysnameidx, "/device", 16);
463         do_mkdir(sysname, S_IRWXU | S_IRWXG | S_IRWXO);
464
465         /* /sys/class/infiniband_verbs/uverbs0/device/device */
466         strncpy(sysname + sysnameidx, "/device/device", 16);
467         fp = make_device(sysname,
468             S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
469             __S_IFCHR, (struct file_operations *)&ddev_fops);
470         set_fs_info(fp, ptr);
471
472         /* /sys/class/infiniband_verbs/uverbs0/device/vendor */
473         strncpy(sysname + sysnameidx, "/device/vendor", 16);
474         fp = make_device(sysname,
475             S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
476             __S_IFCHR, (struct file_operations *)&dven_fops);
477         set_fs_info(fp, ptr);
478
479         /* /sys/class/infiniband_verbs/uverbs0/ibdev */
480         strncpy(sysname + sysnameidx, "/ibdev", 16);
481         fp = make_device(sysname,
482             S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
483             __S_IFCHR, (struct file_operations *)&dname_fops);
484         set_fs_info(fp, ptr);
485
486         /* /sys/class/infiniband_verbs/uverbs0/abi_version */
487         strncpy(sysname + sysnameidx, "/abi_version", 16);
488         fp = make_device(sysname,
489             S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR | S_IRGRP | S_IROTH,
490             __S_IFCHR, (struct file_operations *)&dver_fops);
491         set_fs_info(fp, ptr);
492 }
493
494 /* END: Linux /sys support for lib/apps */
495
496 /* START: Support older version of libibverbs */
497
498 /* in_words and provider_in_words are in terms of 4-byte words, not 8-byte */
499 struct ib_uverbs_ex_cmd_hdr_compat {
500         __u16 provider_in_words;
501         __u16 provider_out_words;
502         __u32 cmd_hdr_reserved;
503         __u32 comp_mask;
504         /* __u32 dummy; */
505         __u64 response;
506         __u32 qp_handle;
507 };
508
509 static ssize_t compat_ex(struct ib_uverbs_file *file, size_t count,
510     const char __user *buf)
511 {
512         struct ib_uverbs_cmd_hdr hdr;
513         struct ib_uverbs_ex_cmd_hdr_compat ex_hdr;
514         struct ib_udata ucore;
515         struct ib_udata uhw;
516         __u32 command;
517         int err;
518         unsigned long   tmpbuf[16];
519         struct ib_uverbs_create_flow *ptr;
520
521         if (copy_from_user(&hdr, buf, sizeof hdr))
522                 return -EFAULT;
523
524         command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK;
525         command -= 2;
526
527         if (command == IB_USER_VERBS_EX_CMD_DESTROY_FLOW) {
528                 INIT_UDATA_BUF_OR_NULL(&ucore, buf + 8, 0, 8, 0);
529                 err = ib_uverbs_ex_destroy_flow(file, &ucore, &uhw);
530                 goto next;
531         }
532
533         /*
534          * "struct ibv_create_flow" is 56 bytes, "struct ibv_kern_spec" is
535          * 48 bytes, so at a minimum we expect 56 + (n x 48), n >= 1.
536          */
537         if (count < 104)
538                 return -EINVAL;
539
540         if (copy_from_user(&ex_hdr, buf + sizeof(hdr), sizeof(ex_hdr)))
541                 return -EFAULT;
542
543         if ((hdr.in_words + ex_hdr.provider_in_words) * 4 != count)
544                 return -EINVAL;
545
546         if (ex_hdr.cmd_hdr_reserved)
547                 return -EINVAL;
548
549         if (ex_hdr.comp_mask)
550                 return -EINVAL;
551
552         if (ex_hdr.response) {
553                 if (!hdr.out_words && !ex_hdr.provider_out_words)
554                         return -EINVAL;
555
556                 if (!access_ok(VERIFY_WRITE,
557                                (void __user *) (unsigned long) ex_hdr.response,
558                                (hdr.out_words + ex_hdr.provider_out_words) * 4))
559                         return -EFAULT;
560         } else {
561                 if (hdr.out_words || ex_hdr.provider_out_words)
562                         return -EINVAL;
563         }
564
565         ptr = (struct ib_uverbs_create_flow *)tmpbuf;
566         ptr->comp_mask = 0;     /* user input already validated above */
567         ptr->qp_handle = ex_hdr.qp_handle;
568
569         if ((count-36) > 120)
570                 BUG();
571
572         /* Copy 16 bytes worth "struct ibv_kern_flow_attr" */
573         copy_from_user(&tmpbuf[1], buf+36, sizeof(struct ib_uverbs_flow_attr));
574
575         ptr->flow_attr.size -= 56;              /* Comes in as 96 = 56 + 40 */
576
577         /* Copy "struct ibv_kern_spec"s */
578         copy_from_user(&tmpbuf[3], buf+56, count-56);
579
580         /*
581          * Copy : count-56 "struct ibv_kern_spec"s,
582          * 16 bytes "struct ibv_kern_flow_attr", 16 bytes comp_mask/qp_handle.
583          */
584         copy_to_user((char __user *)buf, tmpbuf, count-24);
585
586         INIT_UDATA_BUF_OR_NULL(&ucore, buf,
587             (unsigned long) ex_hdr.response, count - 24,
588             hdr.out_words * 4);
589
590         err = ib_uverbs_ex_create_flow(file, &ucore, &uhw);
591
592 next:
593         if (err)
594                 return err;
595
596         return count;
597 }
598
599 static ssize_t compat(struct ib_uverbs_file *file, size_t count,
600     const char __user *buf)
601 {
602         unsigned long                   tmpbuf[17];
603         struct ib_uverbs_cmd_hdr        *p = (struct ib_uverbs_cmd_hdr *)tmpbuf;
604         char __user                     *dst = (char __user *)buf;
605         int                             insz, outsz;
606
607         /*
608          * User "struct ibv_qp_dest" is 40 bytes, passes in 136 bytes.
609          * Kernel "struct ib_uverbs_qp_dest" is 32 bytes, expects 120.
610          * Last 8 bytes of user "struct ibv_qp_dest" not used by kernel.
611          * Kernel expects this layout:
612          *      struct ib_uverbs_cmd_hdr (8)
613          *      struct ib_uverbs_qp_dest (32 <- 40)
614          *      struct ib_uverbs_qp_dest (32 <- 40)
615          *      Rest of qp_mod inputs    (48)
616          */
617
618         if (count > 136)
619                 BUG();
620
621         if (copy_from_user(tmpbuf, buf, count))
622                 return -EFAULT;
623         insz = p->in_words * 4;
624         outsz = p->out_words * 4;
625
626         copy_to_user(dst, &tmpbuf[1], sizeof(struct ib_uverbs_qp_dest));
627         dst += sizeof(struct ib_uverbs_qp_dest);
628         copy_to_user(dst, &tmpbuf[6], sizeof(struct ib_uverbs_qp_dest));
629         dst += sizeof(struct ib_uverbs_qp_dest);
630         copy_to_user(dst, &tmpbuf[11], 48);
631
632
633         return ib_uverbs_modify_qp(file, buf, insz, outsz);
634 }
635
636 /*
637  * Request structure is:
638  * ib_uverbs_cmd_hdr :: (almost) ib_uverbs_ex_cmd_hdr_compat.
639  * Response structure is:
640  * 8B comp_mask :: ib_uverbs_query_device_resp :: 8B timestamp_mask ::
641  * 8B hca_core_clock
642  */
643 static ssize_t compat_query(struct ib_uverbs_file *file, size_t count,
644     const char __user *buf)
645 {
646         unsigned long                   tmpbuf[17], tval = 0;
647         struct ib_uverbs_cmd_hdr        *p = (struct ib_uverbs_cmd_hdr *)tmpbuf;
648         char __user                     *dst = (char __user *)buf;
649         int                             insz, outsz;
650
651         if (copy_from_user(tmpbuf, buf, count))
652                 return -EFAULT;
653         insz = p->in_words * 4;
654         outsz = p->out_words * 4;
655
656         /* Zero out expected comp_mask field in response */
657         copy_to_user((void *)tmpbuf[3], &tval, 8);
658         /* Kernel writes out after expected comp_mask field */
659         tmpbuf[3] += 8;
660         /* Move "response" upwards to "buf" */
661         copy_to_user(dst, &tmpbuf[3], sizeof(struct ib_uverbs_query_device));
662
663         return ib_uverbs_query_device(file, buf, insz, outsz);
664 }
665
666 /*
667  * Compat hack for applications/libraries we care about. Retrofit Linux 3.12
668  * style APIs.
669  */
670 ssize_t check_old_abi(struct file *filp, const char __user *buf, size_t count)
671 {
672         struct ib_uverbs_cmd_hdr hdr;
673         int                      tmp;
674         struct ib_uverbs_file *file = filp->private_data;
675
676         if (copy_from_user(&hdr, buf, sizeof hdr))
677                 return -EFAULT;
678
679         tmp = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK;
680         if ((tmp >= 52) && (tmp <= 53)) {
681                 return compat_ex(file, count, buf);
682         } else if (tmp == IB_USER_VERBS_CMD_MODIFY_QP) {
683                 return compat(file, count, buf);
684         } else if (tmp == 56) {
685                 return compat_query(file, count, buf);
686         } else if (tmp == IB_USER_VERBS_CMD_QUERY_QP) {
687                 panic("query_qp API difference not handled\n");
688         }
689
690         /* Continue with processing this command */
691         return 0;
692 }
693
694 /* END: Support older version of libibverbs */