ia64/xen-unstable

changeset 2418:51f753d105f7

bitkeeper revision 1.1159.69.2 (41385e204Qryz7kXFra9nLruJLGcgw)

Merge ssh://xenbk@gandalf.hpl.hp.com//var/bk/xeno-unstable.bk
into labyrinth.cl.cam.ac.uk:/auto/anfs/scratch/labyrinth/iap10/xeno-clone/xeno.bk
author iap10@labyrinth.cl.cam.ac.uk
date Fri Sep 03 12:05:52 2004 +0000 (2004-09-03)
parents ccdb04941d97 f67e97f4012f
children 5d7a7c656fa3
files linux-2.6.8.1-xen-sparse/drivers/xen/blkfront/blkfront.c linux-2.6.8.1-xen-sparse/drivers/xen/netfront/netfront.c tools/python/xen/xend/XendClient.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/blkif.py tools/python/xen/xend/server/messages.py tools/python/xen/xend/server/netif.py tools/python/xen/xm/main.py tools/xfrd/xen_domain.c xen/include/hypervisor-ifs/io/domain_controller.h
line diff
     1.1 --- a/linux-2.6.8.1-xen-sparse/drivers/xen/blkfront/blkfront.c	Fri Sep 03 11:21:04 2004 +0000
     1.2 +++ b/linux-2.6.8.1-xen-sparse/drivers/xen/blkfront/blkfront.c	Fri Sep 03 12:05:52 2004 +0000
     1.3 @@ -1148,6 +1148,12 @@ static void blkif_status_change(blkif_fe
     1.4  
     1.5          break;
     1.6  
     1.7 +    case BLKIF_INTERFACE_STATUS_CHANGED:
     1.8 +        /* The domain controller is notifying us that a device has been
     1.9 +        * added or removed.
    1.10 +        */
    1.11 +        break;
    1.12 +
    1.13      default:
    1.14          printk(KERN_WARNING "Status change to unknown value %d\n", 
    1.15                 status->status);
     2.1 --- a/linux-2.6.8.1-xen-sparse/drivers/xen/netfront/netfront.c	Fri Sep 03 11:21:04 2004 +0000
     2.2 +++ b/linux-2.6.8.1-xen-sparse/drivers/xen/netfront/netfront.c	Fri Sep 03 12:05:52 2004 +0000
     2.3 @@ -26,6 +26,9 @@
     2.4  #include <asm-xen/hypervisor-ifs/io/netif.h>
     2.5  #include <asm/page.h>
     2.6  
     2.7 +#include <net/arp.h>
     2.8 +#include <net/route.h>
     2.9 +
    2.10  #if 0
    2.11  #define DPRINTK(fmt, args...) \
    2.12      printk(KERN_INFO "[XEN] %s" fmt, __FUNCTION__, ##args)
    2.13 @@ -171,6 +174,32 @@ static int netctrl_connected_count(void)
    2.14      return connected;
    2.15  }
    2.16  
    2.17 +/** Send a packet on a net device to encourage switches to learn the
    2.18 + * MAC. We send a fake ARP request.
    2.19 + *
    2.20 + * @param dev device
    2.21 + * @return 0 on success, error code otherwise
    2.22 + */
    2.23 +static int vif_wake(struct net_device *dev){
    2.24 +    int err = 0;
    2.25 +    struct sk_buff *skb;
    2.26 +    u32 src_ip;
    2.27 +    u32 dst_ip = INADDR_BROADCAST;
    2.28 +    unsigned char dst_hw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
    2.29 +
    2.30 +    src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK);
    2.31 +    skb = arp_create(ARPOP_REQUEST, ETH_P_ARP,
    2.32 +                     dst_ip, dev, src_ip,
    2.33 +                     dst_hw, dev->dev_addr, NULL);
    2.34 +    if(skb == NULL){
    2.35 +        err = -ENOMEM;
    2.36 +        goto exit;
    2.37 +    }
    2.38 +    err = dev_queue_xmit(skb);
    2.39 +  exit:
    2.40 +    return err;
    2.41 +}
    2.42 +
    2.43  static inline struct sk_buff *alloc_skb_page(void)
    2.44  {
    2.45      struct sk_buff *skb;
    2.46 @@ -739,6 +768,13 @@ static void netif_status_change(netif_fe
    2.47          (void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM, 
    2.48                            dev->name, dev);
    2.49          netctrl_connected_count();
    2.50 +        vif_wake(dev);
    2.51 +        break;
    2.52 +
    2.53 +    case NETIF_INTERFACE_STATUS_CHANGED:
    2.54 +        /* The domain controller is notifying us that a device has been
    2.55 +        * added or removed.
    2.56 +        */
    2.57          break;
    2.58  
    2.59      default:
     3.1 --- a/tools/python/xen/xend/XendClient.py	Fri Sep 03 11:21:04 2004 +0000
     3.2 +++ b/tools/python/xen/xend/XendClient.py	Fri Sep 03 12:05:52 2004 +0000
     3.3 @@ -548,7 +548,7 @@ class Xend:
     3.4          return self.xendPost(self.domainurl(id),
     3.5                               {'op'      : 'device_destroy',
     3.6                                'type'    : type,
     3.7 -                              'index'   : idx })
     3.8 +                              'idx'     : idx })
     3.9  
    3.10      def xend_consoles(self):
    3.11          return self.xendGet(self.consoleurl())
     4.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Fri Sep 03 11:21:04 2004 +0000
     4.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Sep 03 12:05:52 2004 +0000
     4.3 @@ -576,6 +576,16 @@ class XendDomainInfo:
     4.4          dl.append(dev)
     4.5          self.devices[type] = dl
     4.6  
     4.7 +    def remove_device(self, type, dev):
     4.8 +        """Remove a device from a virtual machine.
     4.9 +
    4.10 +        @param type: device type
    4.11 +        @param dev:  device
    4.12 +        """
    4.13 +        dl = self.devices.get(type, [])
    4.14 +        if dev in dl:
    4.15 +            dl.remove(dev)
    4.16 +
    4.17      def get_devices(self, type):
    4.18          """Get a list of the devices of a given type.
    4.19  
    4.20 @@ -812,7 +822,7 @@ class XendDomainInfo:
    4.21          devs = self.get_devices(dev_name)
    4.22          dev_index = len(devs)
    4.23          self.config.append(['device', dev_config])
    4.24 -        d = dev_handler(self, dev_config, dev_index)
    4.25 +        d = dev_handler(self, dev_config, dev_index, change=1)
    4.26          return d
    4.27  
    4.28      def device_destroy(self, type, idx):
    4.29 @@ -829,7 +839,8 @@ class XendDomainInfo:
    4.30          dev_config = self.config_device(type, index)
    4.31          if dev_config:
    4.32              self.config.remove(['device', dev_config])
    4.33 -        dev.destroy()
    4.34 +        dev.destroy(change=1)
    4.35 +        self.remove_device(type, dev)
    4.36  
    4.37      def configure_memory(self):
    4.38          """Configure vm memory limit.
    4.39 @@ -1053,7 +1064,7 @@ def vm_image_netbsd(vm, image):
    4.40      return vm
    4.41  
    4.42  
    4.43 -def vm_dev_vif(vm, val, index):
    4.44 +def vm_dev_vif(vm, val, index, change=0):
    4.45      """Create a virtual network interface (vif).
    4.46  
    4.47      @param vm:        virtual machine
    4.48 @@ -1069,11 +1080,13 @@ def vm_dev_vif(vm, val, index):
    4.49      def cbok(dev):
    4.50          dev.vifctl('up', vmname=vm.name)
    4.51          vm.add_device('vif', dev)
    4.52 +        if change:
    4.53 +            dev.interfaceChanged()
    4.54          return dev
    4.55      defer.addCallback(cbok)
    4.56      return defer
    4.57  
    4.58 -def vm_dev_vbd(vm, val, index):
    4.59 +def vm_dev_vbd(vm, val, index, change=0):
    4.60      """Create a virtual block device (vbd).
    4.61  
    4.62      @param vm:        virtual machine
    4.63 @@ -1094,6 +1107,8 @@ def vm_dev_vbd(vm, val, index):
    4.64          vbd.dev = dev
    4.65          vbd.uname = uname
    4.66          vm.add_device('vbd', vbd)
    4.67 +        if change:
    4.68 +            vbd.interfaceChanged()
    4.69          return vbd
    4.70      defer.addCallback(fn)
    4.71      return defer
    4.72 @@ -1110,7 +1125,7 @@ def parse_pci(val):
    4.73          v = val
    4.74      return v
    4.75  
    4.76 -def vm_dev_pci(vm, val, index):
    4.77 +def vm_dev_pci(vm, val, index, change=0):
    4.78      """Add a pci device.
    4.79  
    4.80      @param vm: virtual machine
     5.1 --- a/tools/python/xen/xend/server/blkif.py	Fri Sep 03 11:21:04 2004 +0000
     5.2 +++ b/tools/python/xen/xend/server/blkif.py	Fri Sep 03 12:05:52 2004 +0000
     5.3 @@ -3,7 +3,6 @@
     5.4  """
     5.5  
     5.6  from twisted.internet import defer
     5.7 -#defer.Deferred.debug = 1
     5.8  
     5.9  from xen.xend import sxp
    5.10  from xen.xend.XendLogging import log
    5.11 @@ -88,14 +87,12 @@ class BlkifBackendInterface(controller.B
    5.12          self.send_be_disconnect(response=d)
    5.13          
    5.14      def send_be_disconnect(self, response=None):
    5.15 -        log.debug('>BlkifBackendController>send_be_disconnect> %s', str(self))
    5.16          msg = packMsg('blkif_be_disconnect_t',
    5.17                        { 'domid'        : self.controller.dom,
    5.18                          'blkif_handle' : self.handle })
    5.19          self.writeRequest(msg, response=response)
    5.20  
    5.21      def send_be_destroy(self, response=None):
    5.22 -        log.debug('>BlkifBackendController>send_be_destroy> %s', str(self))
    5.23          msg = packMsg('blkif_be_destroy_t',
    5.24                        { 'domid'        : self.controller.dom,
    5.25                          'blkif_handle' : self.handle })
    5.26 @@ -127,9 +124,28 @@ class BlkifBackendInterface(controller.B
    5.27          msg = packMsg('blkif_fe_interface_status_changed_t',
    5.28                        { 'handle' : self.handle,
    5.29                          'status' : BLKIF_INTERFACE_STATUS_CONNECTED,
    5.30 -                        'domid'  : 0, ## FIXME: should be domid of backend
    5.31 +                        'domid'  : self.dom,
    5.32                          'evtchn' : self.evtchn['port2'] })
    5.33          self.controller.writeRequest(msg, response=response)
    5.34 +
    5.35 +    def interfaceDisconnected(self):
    5.36 +        msg = packMsg('blkif_fe_interface_status_changed_t',
    5.37 +                      { 'handle' : self.handle,
    5.38 +                        'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED,
    5.39 +                        'domid'  : self.dom,
    5.40 +                        'evtchn' : 0 })
    5.41 +        self.controller.writeRequest(msg)
    5.42 +        
    5.43 +    def interfaceChanged(self):
    5.44 +        """Notify the front-end that devices have been added or removed.
    5.45 +        The front-end should then probe for devices.
    5.46 +        """
    5.47 +        msg = packMsg('blkif_fe_interface_status_changed_t',
    5.48 +                      { 'handle' : self.handle,
    5.49 +                        'status' : BLKIF_INTERFACE_STATUS_CHANGED,
    5.50 +                        'domid'  : self.dom,
    5.51 +                        'evtchn' : 0 })
    5.52 +        self.controller.writeRequest(msg)
    5.53          
    5.54  class BlkifControllerFactory(controller.SplitControllerFactory):
    5.55      """Factory for creating block device interface controllers.
    5.56 @@ -230,9 +246,21 @@ class BlkDev(controller.SplitDev):
    5.57              val.append(['uname', self.uname])
    5.58          return val
    5.59  
    5.60 -    def destroy(self):
    5.61 +    def destroy(self, change=0):
    5.62 +        """Destroy the device. If 'change' is true notify the front-end interface.
    5.63 +
    5.64 +        @param change: change flag
    5.65 +        """
    5.66          log.debug("Destroying vbd domain=%d vdev=%d", self.controller.dom, self.vdev)
    5.67 -        self.send_be_vbd_destroy()
    5.68 +        d = self.send_be_vbd_destroy()
    5.69 +        if change:
    5.70 +            d.addCallback(lambda val: self.interfaceChanged())
    5.71 +
    5.72 +    def interfaceChanged(self):
    5.73 +        """Tell the back-end to notify the front-end that a device has been
    5.74 +        added or removed.
    5.75 +        """
    5.76 +        self.getBackendInterface().interfaceChanged()
    5.77  
    5.78      def attach(self):
    5.79          """Attach the device to its controller.
    5.80 @@ -295,16 +323,16 @@ class BlkDev(controller.SplitDev):
    5.81                              % (self.vdev, status))
    5.82          return self
    5.83  
    5.84 -    def send_be_vbd_destroy(self, response=None):
    5.85 -        log.debug('>BlkDev>send_be_vbd_destroy> dom=%d vdev=%d',
    5.86 -                  self.controller.dom, self.vdev)
    5.87 +    def send_be_vbd_destroy(self):
    5.88 +        d = defer.Deferred()
    5.89          backend = self.getBackendInterface()
    5.90          msg = packMsg('blkif_be_vbd_destroy_t',
    5.91                        { 'domid'                : self.controller.dom,
    5.92                          'blkif_handle'         : backend.handle,
    5.93                          'vdevice'              : self.vdev })
    5.94          self.controller.delDevice(self.vdev)
    5.95 -        backend.writeRequest(msg, response=response)
    5.96 +        backend.writeRequest(msg, response=d)
    5.97 +        return d
    5.98          
    5.99          
   5.100  class BlkifController(controller.SplitController):
   5.101 @@ -399,13 +427,8 @@ class BlkifController(controller.SplitCo
   5.102  
   5.103      def recv_fe_driver_status_changed(self, msg, req):
   5.104          val = unpackMsg('blkif_fe_driver_status_changed_t', msg)
   5.105 -        # For each backend?
   5.106 -        msg = packMsg('blkif_fe_interface_status_changed_t',
   5.107 -                      { 'handle' : 0,
   5.108 -                        'status' : BLKIF_INTERFACE_STATUS_DISCONNECTED,
   5.109 -                        'domid'  : 0, ## FIXME: should be domid of backend
   5.110 -                        'evtchn' : 0 })
   5.111 -        self.writeRequest(msg)
   5.112 +        for backend in self.getBackendInterfaces():
   5.113 +            backend.interfaceDisconnected()
   5.114  
   5.115      def recv_fe_interface_connect(self, msg, req):
   5.116          val = unpackMsg('blkif_fe_interface_connect_t', msg)
     6.1 --- a/tools/python/xen/xend/server/messages.py	Fri Sep 03 11:21:04 2004 +0000
     6.2 +++ b/tools/python/xen/xend/server/messages.py	Fri Sep 03 12:05:52 2004 +0000
     6.3 @@ -50,6 +50,7 @@ BLKIF_DRIVER_STATUS_UP    = 1
     6.4  BLKIF_INTERFACE_STATUS_DESTROYED    = 0 #/* Interface doesn't exist.    */
     6.5  BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
     6.6  BLKIF_INTERFACE_STATUS_CONNECTED    = 2 #/* Exists and is connected.    */
     6.7 +BLKIF_INTERFACE_STATUS_CHANGED      = 3 #/* A device has been added or removed. */
     6.8  
     6.9  BLKIF_BE_STATUS_OKAY                = 0
    6.10  BLKIF_BE_STATUS_ERROR               = 1
    6.11 @@ -117,6 +118,7 @@ CMSG_NETIF_BE_DRIVER_STATUS_CHANGED    =
    6.12  NETIF_INTERFACE_STATUS_DESTROYED    = 0 #/* Interface doesn't exist.    */
    6.13  NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
    6.14  NETIF_INTERFACE_STATUS_CONNECTED    = 2 #/* Exists and is connected.    */
    6.15 +NETIF_INTERFACE_STATUS_CHANGED      = 3 #/* A device has been added or removed. */
    6.16  
    6.17  NETIF_DRIVER_STATUS_DOWN   = 0
    6.18  NETIF_DRIVER_STATUS_UP     = 1
     7.1 --- a/tools/python/xen/xend/server/netif.py	Fri Sep 03 11:21:04 2004 +0000
     7.2 +++ b/tools/python/xen/xend/server/netif.py	Fri Sep 03 12:05:52 2004 +0000
     7.3 @@ -5,7 +5,6 @@
     7.4  import random
     7.5  
     7.6  from twisted.internet import defer
     7.7 -#defer.Deferred.debug = 1
     7.8  
     7.9  from xen.xend import sxp
    7.10  from xen.xend import Vifctl
    7.11 @@ -208,13 +207,17 @@ class NetDev(controller.SplitDev):
    7.12          val = unpackMsg('netif_be_create_t', msg)
    7.13          return self
    7.14  
    7.15 -    def destroy(self):
    7.16 +    def destroy(self, change=0):
    7.17          """Destroy the device's resources and disconnect from the back-end
    7.18 -        device controller.
    7.19 +        device controller. If 'change' is true notify the front-end interface.
    7.20 +
    7.21 +        @param change: change flag
    7.22          """
    7.23          def cb_destroy(val):
    7.24              self.send_be_destroy()
    7.25              self.getBackendInterface().close()
    7.26 +            if change:
    7.27 +                self.interfaceChanged()
    7.28          log.debug("Destroying vif domain=%d vif=%d", self.controller.dom, self.vif)
    7.29          self.vifctl('down')
    7.30          d = self.send_be_disconnect()
    7.31 @@ -256,7 +259,7 @@ class NetDev(controller.SplitDev):
    7.32                        { 'handle' : self.vif,
    7.33                          'status' : NETIF_INTERFACE_STATUS_CONNECTED,
    7.34                          'evtchn' : self.evtchn['port2'],
    7.35 -                        'domid'  : 0, ## FIXME: should be domid of backend
    7.36 +                        'domid'  : self.backendDomain,
    7.37                          'mac'    : self.mac })
    7.38          self.controller.writeRequest(msg)
    7.39  
    7.40 @@ -265,7 +268,19 @@ class NetDev(controller.SplitDev):
    7.41                        { 'handle' : self.vif,
    7.42                          'status' : NETIF_INTERFACE_STATUS_DISCONNECTED,
    7.43                          'evtchn' : 0,
    7.44 -                        'domid'  : 0, ## FIXME: should be domid of backend
    7.45 +                        'domid'  : self.backendDomain,
    7.46 +                        'mac'    : self.mac })
    7.47 +        self.controller.writeRequest(msg)
    7.48 +
    7.49 +    def interfaceChanged(self):
    7.50 +        """Notify the font-end that a device has been added or removed.
    7.51 +        The front-end should then probe the devices.
    7.52 +        """
    7.53 +        msg = packMsg('netif_fe_interface_status_changed_t',
    7.54 +                      { 'handle' : self.vif,
    7.55 +                        'status' : NETIF_INTERFACE_STATUS_CHANGED,
    7.56 +                        'evtchn' : 0,
    7.57 +                        'domid'  : self.backendDomain,
    7.58                          'mac'    : self.mac })
    7.59          self.controller.writeRequest(msg)
    7.60          
     8.1 --- a/tools/python/xen/xm/main.py	Fri Sep 03 11:21:04 2004 +0000
     8.2 +++ b/tools/python/xen/xm/main.py	Fri Sep 03 12:05:52 2004 +0000
     8.3 @@ -737,22 +737,26 @@ class ProgVbdCreate(Prog):
     8.4      info = """Create a new virtual block device for a domain"""
     8.5  
     8.6      def help(self, args):
     8.7 -        print args[0], "DOM UNAME DEV MODE"
     8.8 +        print args[0], "DOM UNAME DEV MODE [BACKEND]"
     8.9          print """
    8.10  Create a virtual block device for a domain.
    8.11  
    8.12 -  UNAME - device to export, e.g. phys:hda2
    8.13 -  DEV   - device name in the domain, e.g. xda1
    8.14 -  MODE  - access mode: r for read, w for read-write
    8.15 +  UNAME   - device to export, e.g. phy:hda2
    8.16 +  DEV     - device name in the domain, e.g. xda1
    8.17 +  MODE    - access mode: r for read, w for read-write
    8.18 +  BACKEND - backend driver domain
    8.19  """
    8.20  
    8.21      def main(self, args):
    8.22 -        if len(args) != 5: self.err("%s: Invalid argument(s)" % args[0])
    8.23 +        n = len(args)
    8.24 +        if n < 5 or n > 6: self.err("%s: Invalid argument(s)" % args[0])
    8.25          dom = args[1]
    8.26          vbd = ['vbd',
    8.27                 ['uname', args[2]],
    8.28                 ['dev',   args[3]],
    8.29                 ['mode',  args[4]]]
    8.30 +        if n == 6:
    8.31 +            vbd.append(['backend', args[5]])
    8.32          server.xend_domain_device_create(dom, vbd)
    8.33  
    8.34  xm.prog(ProgVbdCreate)
    8.35 @@ -766,13 +770,15 @@ class ProgVbdDestroy(Prog):
    8.36          print args[0], "DOM DEV"
    8.37          print """
    8.38  Destroy vbd DEV attached to domain DOM. Detaches the device
    8.39 -from the domain, but does not destroy the device contents."""
    8.40 +from the domain, but does not destroy the device contents.
    8.41 +The device indentifier DEV is the idx field in the device
    8.42 +information. This is visible in 'xm vbd-list'."""
    8.43  
    8.44      def main(self, args):
    8.45 -        if len(args!=3): self.err("%s: Invalid argument(s)" % args[0])
    8.46 +        if len(args) != 3: self.err("%s: Invalid argument(s)" % args[0])
    8.47          dom = args[1]
    8.48          dev = args[2]
    8.49 -        sever.xend_domain_device_destroy(dom, "vbd", dev)
    8.50 +        server.xend_domain_device_destroy(dom, "vbd", dev)
    8.51  
    8.52  xm.prog(ProgVbdDestroy)
    8.53  
     9.1 --- a/tools/xfrd/xen_domain.c	Fri Sep 03 11:21:04 2004 +0000
     9.2 +++ b/tools/xfrd/xen_domain.c	Fri Sep 03 12:05:52 2004 +0000
     9.3 @@ -16,6 +16,7 @@ typedef unsigned long u32;
     9.4  
     9.5  #define MODULE_NAME "XFRD"
     9.6  #define DEBUG 1
     9.7 +#undef DEBUG
     9.8  #include "debug.h"
     9.9  
    9.10  
    10.1 --- a/xen/include/hypervisor-ifs/io/domain_controller.h	Fri Sep 03 11:21:04 2004 +0000
    10.2 +++ b/xen/include/hypervisor-ifs/io/domain_controller.h	Fri Sep 03 12:05:52 2004 +0000
    10.3 @@ -93,6 +93,7 @@ typedef struct {
    10.4  #define BLKIF_INTERFACE_STATUS_DESTROYED    0 /* Interface doesn't exist.    */
    10.5  #define BLKIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
    10.6  #define BLKIF_INTERFACE_STATUS_CONNECTED    2 /* Exists and is connected.    */
    10.7 +#define BLKIF_INTERFACE_STATUS_CHANGED      3 /* A device has been added or removed. */
    10.8  typedef struct {
    10.9      u32 handle; /*  0 */
   10.10      u32 status; /*  4 */
   10.11 @@ -357,6 +358,7 @@ typedef struct {
   10.12  #define NETIF_INTERFACE_STATUS_DESTROYED    0 /* Interface doesn't exist.    */
   10.13  #define NETIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
   10.14  #define NETIF_INTERFACE_STATUS_CONNECTED    2 /* Exists and is connected.    */
   10.15 +#define NETIF_INTERFACE_STATUS_CHANGED      3 /* A device has been added or removed. */
   10.16  typedef struct {
   10.17      u32        handle; /*  0 */
   10.18      u32        status; /*  4 */