ia64/xen-unstable

changeset 7570:b50eb7619dd4

Change the grant table interface so that gnttab_end_foreign_access_ref returns
an error code if the page is still in use, and gnttab_end_foreign_access takes
a page to free. This allows us to cope with frontends wanting to end access
while backends are still using pages by, eventually, placing the page and
grant table entry on a list, for freeing later. At the moment, the page and
grant table entry are leaked, with a diagnostic.

Tidied up netfront.c's clean-up code.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Sun Oct 30 16:33:05 2005 +0100 (2005-10-30)
parents ecae9e6c7331
children 1ce76b214ce2
files linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c linux-2.6-xen-sparse/include/asm-xen/gnttab.h
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c	Sun Oct 30 16:25:52 2005 +0100
     1.2 +++ b/linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c	Sun Oct 30 16:33:05 2005 +0100
     1.3 @@ -165,25 +165,39 @@ gnttab_query_foreign_access(grant_ref_t 
     1.4  	return (nflags & (GTF_reading|GTF_writing));
     1.5  }
     1.6  
     1.7 -void
     1.8 +int
     1.9  gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
    1.10  {
    1.11  	u16 flags, nflags;
    1.12  
    1.13  	nflags = shared[ref].flags;
    1.14  	do {
    1.15 -		if ( (flags = nflags) & (GTF_reading|GTF_writing) )
    1.16 +		if ( (flags = nflags) & (GTF_reading|GTF_writing) ) {
    1.17  			printk(KERN_ALERT "WARNING: g.e. still in use!\n");
    1.18 +			return 0;
    1.19 +		}
    1.20  	}
    1.21  	while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) !=
    1.22  	       flags);
    1.23 +
    1.24 +	return 1;
    1.25  }
    1.26  
    1.27  void
    1.28 -gnttab_end_foreign_access(grant_ref_t ref, int readonly)
    1.29 +gnttab_end_foreign_access(grant_ref_t ref, int readonly, unsigned long page)
    1.30  {
    1.31 -	gnttab_end_foreign_access_ref(ref, readonly);
    1.32 -	put_free_entry(ref);
    1.33 +	if (gnttab_end_foreign_access_ref(ref, readonly)) {
    1.34 +		put_free_entry(ref);
    1.35 +		if (page != 0) {
    1.36 +			free_page(page);
    1.37 +		}
    1.38 +	}
    1.39 +	else {
    1.40 +		/* XXX This needs to be fixed so that the ref and page are
    1.41 +		   placed on a list to be freed up later. */
    1.42 +		printk(KERN_WARNING
    1.43 +		       "WARNING: leaking g.e. and page still in use!\n");
    1.44 +	}
    1.45  }
    1.46  
    1.47  int
     2.1 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c	Sun Oct 30 16:25:52 2005 +0100
     2.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c	Sun Oct 30 16:33:05 2005 +0100
     2.3 @@ -350,13 +350,12 @@ static void blkif_free(struct blkfront_i
     2.4  	spin_unlock_irq(&blkif_io_lock);
     2.5  
     2.6  	/* Free resources associated with old device channel. */
     2.7 -	if (info->ring.sring != NULL) {
     2.8 -		free_page((unsigned long)info->ring.sring);
     2.9 +	if (info->ring_ref != GRANT_INVALID_REF) {
    2.10 +		gnttab_end_foreign_access(info->ring_ref, 0,
    2.11 +					  (unsigned long)info->ring.sring);
    2.12 +		info->ring_ref = GRANT_INVALID_REF;
    2.13  		info->ring.sring = NULL;
    2.14  	}
    2.15 -	if (info->ring_ref != GRANT_INVALID_REF)
    2.16 -		gnttab_end_foreign_access(info->ring_ref, 0);
    2.17 -	info->ring_ref = GRANT_INVALID_REF;
    2.18  	if (info->irq)
    2.19  		unbind_evtchn_from_irqhandler(info->irq, info); 
    2.20  	info->evtchn = info->irq = 0;
    2.21 @@ -515,10 +514,10 @@ static int setup_blkring(struct xenbus_d
    2.22  
    2.23  	err = HYPERVISOR_event_channel_op(&op);
    2.24  	if (err) {
    2.25 -		gnttab_end_foreign_access(info->ring_ref, 0);
    2.26 +		gnttab_end_foreign_access(info->ring_ref, 0,
    2.27 +					  (unsigned long)info->ring.sring);
    2.28  		info->ring_ref = GRANT_INVALID_REF;
    2.29 -		free_page((unsigned long)info->ring.sring);
    2.30 -		info->ring.sring = 0;
    2.31 +		info->ring.sring = NULL;
    2.32  		xenbus_dev_error(dev, err, "allocating event channel");
    2.33  		return err;
    2.34  	}
    2.35 @@ -740,7 +739,7 @@ static void blkif_completion(struct blk_
    2.36  	int i;
    2.37  	for (i = 0; i < s->req.nr_segments; i++)
    2.38  		gnttab_end_foreign_access(
    2.39 -			blkif_gref_from_fas(s->req.frame_and_sects[i]), 0);
    2.40 +			blkif_gref_from_fas(s->req.frame_and_sects[i]), 0, 0UL);
    2.41  }
    2.42  
    2.43  /*
     3.1 --- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c	Sun Oct 30 16:25:52 2005 +0100
     3.2 +++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c	Sun Oct 30 16:33:05 2005 +0100
     3.3 @@ -91,6 +91,8 @@
     3.4  static void network_tx_buf_gc(struct net_device *dev);
     3.5  static void network_alloc_rx_buffers(struct net_device *dev);
     3.6  
     3.7 +static void netif_free(struct netfront_info *info);
     3.8 +
     3.9  static unsigned long rx_pfn_array[NETIF_RX_RING_SIZE];
    3.10  static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE+1];
    3.11  static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE];
    3.12 @@ -978,6 +980,9 @@ static int setup_device(struct xenbus_de
    3.13  
    3.14  	info->tx_ring_ref = GRANT_INVALID_REF;
    3.15  	info->rx_ring_ref = GRANT_INVALID_REF;
    3.16 +	info->rx = NULL;
    3.17 +	info->tx = NULL;
    3.18 +	info->irq = 0;
    3.19  
    3.20  	info->tx = (netif_tx_interface_t *)__get_free_page(GFP_KERNEL);
    3.21  	if (info->tx == 0) {
    3.22 @@ -1022,40 +1027,24 @@ static int setup_device(struct xenbus_de
    3.23  	return 0;
    3.24  
    3.25   out:
    3.26 -	if (info->tx)
    3.27 -		free_page((unsigned long)info->tx);
    3.28 -	info->tx = 0;
    3.29 -	if (info->rx)
    3.30 -		free_page((unsigned long)info->rx);
    3.31 -	info->rx = 0;
    3.32 +	netif_free(info);
    3.33 +	return err;
    3.34 +}
    3.35  
    3.36 -	if (info->tx_ring_ref != GRANT_INVALID_REF)
    3.37 -		gnttab_end_foreign_access(info->tx_ring_ref, 0);
    3.38 -	info->tx_ring_ref = GRANT_INVALID_REF;
    3.39 -
    3.40 -	if (info->rx_ring_ref != GRANT_INVALID_REF)
    3.41 -		gnttab_end_foreign_access(info->rx_ring_ref, 0);
    3.42 -	info->rx_ring_ref = GRANT_INVALID_REF;
    3.43 -
    3.44 -	return err;
    3.45 +static void end_access(int ref, void *page)
    3.46 +{
    3.47 +	if (ref != GRANT_INVALID_REF)
    3.48 +		gnttab_end_foreign_access(ref, 0, (unsigned long)page);
    3.49  }
    3.50  
    3.51  static void netif_free(struct netfront_info *info)
    3.52  {
    3.53 -	if (info->tx)
    3.54 -		free_page((unsigned long)info->tx);
    3.55 -	info->tx = 0;
    3.56 -	if (info->rx)
    3.57 -		free_page((unsigned long)info->rx);
    3.58 -	info->rx = 0;
    3.59 -
    3.60 -	if (info->tx_ring_ref != GRANT_INVALID_REF)
    3.61 -		gnttab_end_foreign_access(info->tx_ring_ref, 0);
    3.62 +	end_access(info->tx_ring_ref, info->tx);
    3.63 +	end_access(info->rx_ring_ref, info->rx);
    3.64  	info->tx_ring_ref = GRANT_INVALID_REF;
    3.65 -
    3.66 -	if (info->rx_ring_ref != GRANT_INVALID_REF)
    3.67 -		gnttab_end_foreign_access(info->rx_ring_ref, 0);
    3.68  	info->rx_ring_ref = GRANT_INVALID_REF;
    3.69 +	info->tx = NULL;
    3.70 +	info->rx = NULL;
    3.71  
    3.72  	if (info->irq)
    3.73  		unbind_evtchn_from_irqhandler(info->irq, info->netdev);
     4.1 --- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c	Sun Oct 30 16:25:52 2005 +0100
     4.2 +++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c	Sun Oct 30 16:33:05 2005 +0100
     4.3 @@ -276,8 +276,8 @@ static int setup_tpmring(struct xenbus_d
     4.4  
     4.5  	err = HYPERVISOR_event_channel_op(&op);
     4.6  	if (err) {
     4.7 -		gnttab_end_foreign_access(info->ring_ref, 0);
     4.8 -		free_page((unsigned long)sring);
     4.9 +		gnttab_end_foreign_access(info->ring_ref, 0,
    4.10 +					  (unsigned long)sring);
    4.11  		tp->tx = NULL;
    4.12  		xenbus_dev_error(dev, err, "allocating event channel");
    4.13  		return err;
    4.14 @@ -294,8 +294,8 @@ static void destroy_tpmring(struct tpmfr
    4.15  	tpmif_set_connected_state(tp,0);
    4.16  
    4.17  	if ( tp->tx != NULL ) {
    4.18 -		gnttab_end_foreign_access(info->ring_ref, 0);
    4.19 -		free_page((unsigned long)tp->tx);
    4.20 +		gnttab_end_foreign_access(info->ring_ref, 0,
    4.21 +					  (unsigned long)tp->tx);
    4.22  		tp->tx = NULL;
    4.23  	}
    4.24  
     5.1 --- a/linux-2.6-xen-sparse/include/asm-xen/gnttab.h	Sun Oct 30 16:25:52 2005 +0100
     5.2 +++ b/linux-2.6-xen-sparse/include/asm-xen/gnttab.h	Sun Oct 30 16:33:05 2005 +0100
     5.3 @@ -34,8 +34,21 @@ struct gnttab_free_callback {
     5.4  int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
     5.5  				int readonly);
     5.6  
     5.7 -void gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly);
     5.8 -void gnttab_end_foreign_access(grant_ref_t ref, int readonly);
     5.9 +/*
    5.10 + * End access through the given grant reference, iff the grant entry is no
    5.11 + * longer in use.  Return 1 if the grant entry was freed, 0 if it is still in
    5.12 + * use.
    5.13 + */
    5.14 +int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly);
    5.15 +
    5.16 +/*
    5.17 + * Eventually end access through the given grant reference, and once that
    5.18 + * access has been ended, free the given page too.  Access will be ended
    5.19 + * immediately iff the grant entry is not in use, otherwise it will happen
    5.20 + * some time later.  page may be 0, in which case no freeing will occur.
    5.21 + */
    5.22 +void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
    5.23 +			       unsigned long page);
    5.24  
    5.25  int gnttab_grant_foreign_transfer(domid_t domid);
    5.26