]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Jul 2015 23:02:25 +0000 (16:02 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Jul 2015 23:02:25 +0000 (16:02 -0700)
Pull virtio/vhost cross endian support from Michael Tsirkin:
 "I have just queued some more bugfix patches today but none fix
  regressions and none are related to these ones, so it looks like a
  good time for a merge for -rc1.

  The motivation for this is support for legacy BE guests on the new LE
  hosts.  There are two redeeming properties that made me merge this:

   - It's a trivial amount of code: since we wrap host/guest accesses
     anyway, almost all of it is well hidden from drivers.

   - Sane platforms would never set flags like VHOST_CROSS_ENDIAN_LEGACY,
     and when it's clear, there's zero overhead (as some point it was
     tested by compiling with and without the patches, got the same
     stripped binary).

  Maybe we could create a Kconfig symbol to enforce the second point:
  prevent people from enabling it eg on x86.  I will look into this"

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost:
  virtio-pci: alloc only resources actually used.
  macvtap/tun: cross-endian support for little-endian hosts
  vhost: cross-endian support for legacy devices
  virtio: add explicit big-endian support to memory accessors
  vhost: introduce vhost_is_little_endian() helper
  vringh: introduce vringh_is_little_endian() helper
  macvtap: introduce macvtap_is_little_endian() helper
  tun: add tun_is_little_endian() helper
  virtio: introduce virtio_is_little_endian() helper

1  2 
drivers/net/Kconfig
drivers/net/macvtap.c
drivers/net/tun.c
drivers/virtio/virtio_pci_common.c

diff --combined drivers/net/Kconfig
index 019fceffc9e52980d1f3837b01a299b97782dfca,71ac0ece2d750555554ab709d3809a49e61bedeb..b7f31150753d8998d317d483300004f1463de301
@@@ -179,20 -179,6 +179,20 @@@ config VXLA
          To compile this driver as a module, choose M here: the module
          will be called vxlan.
  
 +config GENEVE
 +       tristate "Generic Network Virtualization Encapsulation netdev"
 +       depends on INET && GENEVE_CORE
 +       select NET_IP_TUNNEL
 +       ---help---
 +        This allows one to create geneve virtual interfaces that provide
 +        Layer 2 Networks over Layer 3 Networks. GENEVE is often used
 +        to tunnel virtual network infrastructure in virtualized environments.
 +        For more information see:
 +          http://tools.ietf.org/html/draft-gross-geneve-02
 +
 +        To compile this driver as a module, choose M here: the module
 +        will be called geneve.
 +
  config NETCONSOLE
        tristate "Network console logging support"
        ---help---
@@@ -258,6 -244,20 +258,20 @@@ config TU
  
          If you don't know what to use this for, you don't need it.
  
+ config TUN_VNET_CROSS_LE
+       bool "Support for cross-endian vnet headers on little-endian kernels"
+       default n
+       ---help---
+         This option allows TUN/TAP and MACVTAP device drivers in a
+         little-endian kernel to parse vnet headers that come from a
+         big-endian legacy virtio device.
+         Userspace programs can control the feature using the TUNSETVNETBE
+         and TUNGETVNETBE ioctls.
+         Unless you have a little-endian system hosting a big-endian virtual
+         machine with a legacy virtio NIC, you should say N.
  config VETH
        tristate "Virtual ethernet pair device"
        ---help---
diff --combined drivers/net/macvtap.c
index 6a64197f5bcef6fa4fce9e714bee6fa664e46fb7,928f3f4db62908379c772aba91420ee2272a99b4..f8370808a018f77503de49503985f3d5c55985f6
@@@ -48,15 -48,70 +48,70 @@@ struct macvtap_queue 
  #define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE)
  
  #define MACVTAP_VNET_LE 0x80000000
+ #define MACVTAP_VNET_BE 0x40000000
+ #ifdef CONFIG_TUN_VNET_CROSS_LE
+ static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q)
+ {
+       return q->flags & MACVTAP_VNET_BE ? false :
+               virtio_legacy_is_little_endian();
+ }
+ static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *sp)
+ {
+       int s = !!(q->flags & MACVTAP_VNET_BE);
+       if (put_user(s, sp))
+               return -EFAULT;
+       return 0;
+ }
+ static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *sp)
+ {
+       int s;
+       if (get_user(s, sp))
+               return -EFAULT;
+       if (s)
+               q->flags |= MACVTAP_VNET_BE;
+       else
+               q->flags &= ~MACVTAP_VNET_BE;
+       return 0;
+ }
+ #else
+ static inline bool macvtap_legacy_is_little_endian(struct macvtap_queue *q)
+ {
+       return virtio_legacy_is_little_endian();
+ }
+ static long macvtap_get_vnet_be(struct macvtap_queue *q, int __user *argp)
+ {
+       return -EINVAL;
+ }
+ static long macvtap_set_vnet_be(struct macvtap_queue *q, int __user *argp)
+ {
+       return -EINVAL;
+ }
+ #endif /* CONFIG_TUN_VNET_CROSS_LE */
+ static inline bool macvtap_is_little_endian(struct macvtap_queue *q)
+ {
+       return q->flags & MACVTAP_VNET_LE ||
+               macvtap_legacy_is_little_endian(q);
+ }
  
  static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val)
  {
-       return __virtio16_to_cpu(q->flags & MACVTAP_VNET_LE, val);
+       return __virtio16_to_cpu(macvtap_is_little_endian(q), val);
  }
  
  static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val)
  {
-       return __cpu_to_virtio16(q->flags & MACVTAP_VNET_LE, val);
+       return __cpu_to_virtio16(macvtap_is_little_endian(q), val);
  }
  
  static struct proto macvtap_proto = {
@@@ -263,21 -318,27 +318,21 @@@ out
  static void macvtap_del_queues(struct net_device *dev)
  {
        struct macvlan_dev *vlan = netdev_priv(dev);
 -      struct macvtap_queue *q, *tmp, *qlist[MAX_MACVTAP_QUEUES];
 -      int i, j = 0;
 +      struct macvtap_queue *q, *tmp;
  
        ASSERT_RTNL();
        list_for_each_entry_safe(q, tmp, &vlan->queue_list, next) {
                list_del_init(&q->next);
 -              qlist[j++] = q;
                RCU_INIT_POINTER(q->vlan, NULL);
                if (q->enabled)
                        vlan->numvtaps--;
                vlan->numqueues--;
 +              sock_put(&q->sk);
        }
 -      for (i = 0; i < vlan->numvtaps; i++)
 -              RCU_INIT_POINTER(vlan->taps[i], NULL);
        BUG_ON(vlan->numvtaps);
        BUG_ON(vlan->numqueues);
        /* guarantee that any future macvtap_set_queue will fail */
        vlan->numvtaps = MAX_MACVTAP_QUEUES;
 -
 -      for (--j; j >= 0; j--)
 -              sock_put(&qlist[j]->sk);
  }
  
  static rx_handler_result_t macvtap_handle_frame(struct sk_buff **pskb)
@@@ -470,7 -531,7 +525,7 @@@ static int macvtap_open(struct inode *i
  
        err = -ENOMEM;
        q = (struct macvtap_queue *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
 -                                           &macvtap_proto);
 +                                           &macvtap_proto, 0);
        if (!q)
                goto out;
  
@@@ -1000,7 -1061,6 +1055,7 @@@ static long macvtap_ioctl(struct file *
        unsigned int __user *up = argp;
        unsigned short u;
        int __user *sp = argp;
 +      struct sockaddr sa;
        int s;
        int ret;
  
                        q->flags &= ~MACVTAP_VNET_LE;
                return 0;
  
+       case TUNGETVNETBE:
+               return macvtap_get_vnet_be(q, sp);
+       case TUNSETVNETBE:
+               return macvtap_set_vnet_be(q, sp);
        case TUNSETOFFLOAD:
                /* let the user check for future flags */
                if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
                rtnl_unlock();
                return ret;
  
 +      case SIOCGIFHWADDR:
 +              rtnl_lock();
 +              vlan = macvtap_get_vlan(q);
 +              if (!vlan) {
 +                      rtnl_unlock();
 +                      return -ENOLINK;
 +              }
 +              ret = 0;
 +              u = vlan->dev->type;
 +              if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) ||
 +                  copy_to_user(&ifr->ifr_hwaddr.sa_data, vlan->dev->dev_addr, ETH_ALEN) ||
 +                  put_user(u, &ifr->ifr_hwaddr.sa_family))
 +                      ret = -EFAULT;
 +              macvtap_put_vlan(vlan);
 +              rtnl_unlock();
 +              return ret;
 +
 +      case SIOCSIFHWADDR:
 +              if (copy_from_user(&sa, &ifr->ifr_hwaddr, sizeof(sa)))
 +                      return -EFAULT;
 +              rtnl_lock();
 +              vlan = macvtap_get_vlan(q);
 +              if (!vlan) {
 +                      rtnl_unlock();
 +                      return -ENOLINK;
 +              }
 +              ret = dev_set_mac_address(vlan->dev, &sa);
 +              macvtap_put_vlan(vlan);
 +              rtnl_unlock();
 +              return ret;
 +
        default:
                return -EINVAL;
        }
diff --combined drivers/net/tun.c
index 1a1c4f7b3ec53d884c0ea3aed996d08d203ce6aa,cb376b2d548a1e448f40bf573f819e82dbfc1b43..06a039414628de9a9d91c73e9f8790c23fce71a3
@@@ -111,6 -111,7 +111,7 @@@ do {                                                               
  #define TUN_FASYNC    IFF_ATTACH_QUEUE
  /* High bits in flags field are unused. */
  #define TUN_VNET_LE     0x80000000
+ #define TUN_VNET_BE     0x40000000
  
  #define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \
                      IFF_MULTI_QUEUE)
@@@ -146,6 -147,7 +147,6 @@@ struct tun_file 
        struct socket socket;
        struct socket_wq wq;
        struct tun_struct __rcu *tun;
 -      struct net *net;
        struct fasync_struct *fasync;
        /* only used for fasnyc */
        unsigned int flags;
@@@ -205,14 -207,68 +206,68 @@@ struct tun_struct 
        u32 flow_count;
  };
  
+ #ifdef CONFIG_TUN_VNET_CROSS_LE
+ static inline bool tun_legacy_is_little_endian(struct tun_struct *tun)
+ {
+       return tun->flags & TUN_VNET_BE ? false :
+               virtio_legacy_is_little_endian();
+ }
+ static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp)
+ {
+       int be = !!(tun->flags & TUN_VNET_BE);
+       if (put_user(be, argp))
+               return -EFAULT;
+       return 0;
+ }
+ static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp)
+ {
+       int be;
+       if (get_user(be, argp))
+               return -EFAULT;
+       if (be)
+               tun->flags |= TUN_VNET_BE;
+       else
+               tun->flags &= ~TUN_VNET_BE;
+       return 0;
+ }
+ #else
+ static inline bool tun_legacy_is_little_endian(struct tun_struct *tun)
+ {
+       return virtio_legacy_is_little_endian();
+ }
+ static long tun_get_vnet_be(struct tun_struct *tun, int __user *argp)
+ {
+       return -EINVAL;
+ }
+ static long tun_set_vnet_be(struct tun_struct *tun, int __user *argp)
+ {
+       return -EINVAL;
+ }
+ #endif /* CONFIG_TUN_VNET_CROSS_LE */
+ static inline bool tun_is_little_endian(struct tun_struct *tun)
+ {
+       return tun->flags & TUN_VNET_LE ||
+               tun_legacy_is_little_endian(tun);
+ }
  static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val)
  {
-       return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val);
+       return __virtio16_to_cpu(tun_is_little_endian(tun), val);
  }
  
  static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val)
  {
-       return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val);
+       return __cpu_to_virtio16(tun_is_little_endian(tun), val);
  }
  
  static inline u32 tun_hashfn(u32 rxhash)
@@@ -492,7 -548,10 +547,7 @@@ static void __tun_detach(struct tun_fil
                            tun->dev->reg_state == NETREG_REGISTERED)
                                unregister_netdevice(tun->dev);
                }
 -
 -              BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED,
 -                               &tfile->socket.flags));
 -              sk_release_kernel(&tfile->sk);
 +              sock_put(&tfile->sk);
        }
  }
  
        return ret;
  }
  
 -static int tun_release(struct socket *sock)
 -{
 -      if (sock->sk)
 -              sock_put(sock->sk);
 -      return 0;
 -}
 -
  /* Ops structure to mimic raw sockets with tun */
  static const struct proto_ops tun_socket_ops = {
        .sendmsg = tun_sendmsg,
        .recvmsg = tun_recvmsg,
 -      .release = tun_release,
  };
  
  static struct proto tun_proto = {
@@@ -1853,7 -1920,7 +1908,7 @@@ static long __tun_chr_ioctl(struct fil
        if (cmd == TUNSETIFF && !tun) {
                ifr.ifr_name[IFNAMSIZ-1] = '\0';
  
 -              ret = tun_set_iff(tfile->net, file, &ifr);
 +              ret = tun_set_iff(sock_net(&tfile->sk), file, &ifr);
  
                if (ret)
                        goto unlock;
                        tun->flags &= ~TUN_VNET_LE;
                break;
  
+       case TUNGETVNETBE:
+               ret = tun_get_vnet_be(tun, argp);
+               break;
+       case TUNSETVNETBE:
+               ret = tun_set_vnet_be(tun, argp);
+               break;
        case TUNATTACHFILTER:
                /* Can be set only for TAPs */
                ret = -EINVAL;
  
  static int tun_chr_open(struct inode *inode, struct file * file)
  {
 +      struct net *net = current->nsproxy->net_ns;
        struct tun_file *tfile;
  
        DBG1(KERN_INFO, "tunX: tun_chr_open\n");
  
 -      tfile = (struct tun_file *)sk_alloc(&init_net, AF_UNSPEC, GFP_KERNEL,
 -                                          &tun_proto);
 +      tfile = (struct tun_file *)sk_alloc(net, AF_UNSPEC, GFP_KERNEL,
 +                                          &tun_proto, 0);
        if (!tfile)
                return -ENOMEM;
        RCU_INIT_POINTER(tfile->tun, NULL);
 -      tfile->net = get_net(current->nsproxy->net_ns);
        tfile->flags = 0;
        tfile->ifindex = 0;
  
        tfile->socket.ops = &tun_socket_ops;
  
        sock_init_data(&tfile->socket, &tfile->sk);
 -      sk_change_net(&tfile->sk, tfile->net);
  
        tfile->sk.sk_write_space = tun_sock_write_space;
        tfile->sk.sk_sndbuf = INT_MAX;
  
        file->private_data = tfile;
 -      set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags);
        INIT_LIST_HEAD(&tfile->next);
  
        sock_set_flag(&tfile->sk, SOCK_ZEROCOPY);
  static int tun_chr_close(struct inode *inode, struct file *file)
  {
        struct tun_file *tfile = file->private_data;
 -      struct net *net = tfile->net;
  
        tun_detach(tfile, true);
 -      put_net(net);
  
        return 0;
  }
index 5447b818633232937d7cb87ddb21424da1281010,4fd036c3468f264bbef2a019fb12f26ebb3426f7..78f804af6c2020a9b927286e3496f6a2d8541953
@@@ -423,7 -423,6 +423,7 @@@ int vp_set_vq_affinity(struct virtqueu
                if (cpu == -1)
                        irq_set_affinity_hint(irq, NULL);
                else {
 +                      cpumask_clear(mask);
                        cpumask_set_cpu(cpu, mask);
                        irq_set_affinity_hint(irq, mask);
                }
@@@ -502,15 -501,14 +502,11 @@@ static int virtio_pci_probe(struct pci_
        INIT_LIST_HEAD(&vp_dev->virtqueues);
        spin_lock_init(&vp_dev->lock);
  
 -      /* Disable MSI/MSIX to bring device to a known good state. */
 -      pci_msi_off(pci_dev);
 -
        /* enable the device */
        rc = pci_enable_device(pci_dev);
        if (rc)
                goto err_enable_device;
  
-       rc = pci_request_regions(pci_dev, "virtio-pci");
-       if (rc)
-               goto err_request_regions;
        if (force_legacy) {
                rc = virtio_pci_legacy_probe(vp_dev);
                /* Also try modern mode if we can't map BAR0 (no IO space). */
@@@ -540,8 -538,6 +536,6 @@@ err_register
        else
             virtio_pci_modern_remove(vp_dev);
  err_probe:
-       pci_release_regions(pci_dev);
- err_request_regions:
        pci_disable_device(pci_dev);
  err_enable_device:
        kfree(vp_dev);
@@@ -559,7 -555,6 +553,6 @@@ static void virtio_pci_remove(struct pc
        else
                virtio_pci_modern_remove(vp_dev);
  
-       pci_release_regions(pci_dev);
        pci_disable_device(pci_dev);
  }