ia64/xen-unstable

changeset 9925:42a70a529753

Introduce some finer-grained locking to prevent calling
copy_from/to_user while preventing interrupts and fix allocation of
memory from within a task and other issues.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed May 03 11:00:57 2006 +0100 (2006-05-03)
parents 1449c89adb8b
children 40cd49c88d69
files linux-2.6-xen-sparse/drivers/xen/tpmback/common.h linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h	Wed May 03 10:59:54 2006 +0100
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/common.h	Wed May 03 11:00:57 2006 +0100
     1.3 @@ -50,6 +50,8 @@ typedef struct tpmif_st {
     1.4  	grant_handle_t shmem_handle;
     1.5  	grant_ref_t shmem_ref;
     1.6  	struct page *pagerange;
     1.7 +
     1.8 +	char devname[20];
     1.9  } tpmif_t;
    1.10  
    1.11  void tpmif_disconnect_complete(tpmif_t * tpmif);
     2.1 --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c	Wed May 03 10:59:54 2006 +0100
     2.2 +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/interface.c	Wed May 03 11:00:57 2006 +0100
     2.3 @@ -32,6 +32,7 @@ static tpmif_t *alloc_tpmif(domid_t domi
     2.4  	tpmif->domid = domid;
     2.5  	tpmif->status = DISCONNECTED;
     2.6  	tpmif->tpm_instance = instance;
     2.7 +	snprintf(tpmif->devname, sizeof(tpmif->devname), "tpmif%d", domid);
     2.8  	atomic_set(&tpmif->refcnt, 1);
     2.9  
    2.10  	tpmif->pagerange = balloon_alloc_empty_page_range(TPMIF_TX_RING_SIZE);
    2.11 @@ -144,7 +145,7 @@ int tpmif_map(tpmif_t *tpmif, unsigned l
    2.12  	tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr;
    2.13  
    2.14  	tpmif->irq = bind_evtchn_to_irqhandler(
    2.15 -		tpmif->evtchn, tpmif_be_int, 0, "tpmif-backend", tpmif);
    2.16 +		tpmif->evtchn, tpmif_be_int, 0, tpmif->devname, tpmif);
    2.17  	tpmif->shmem_ref = shared_page;
    2.18  	tpmif->active = 1;
    2.19  
     3.1 --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c	Wed May 03 10:59:54 2006 +0100
     3.2 +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c	Wed May 03 11:00:57 2006 +0100
     3.3 @@ -28,7 +28,8 @@ struct data_exchange {
     3.4  	struct list_head pending_pak;
     3.5  	struct list_head current_pak;
     3.6  	unsigned int copied_so_far;
     3.7 -	u8 has_opener;
     3.8 +	u8 has_opener:1;
     3.9 +	u8 aborted:1;
    3.10  	rwlock_t pak_lock;	// protects all of the previous fields
    3.11  	wait_queue_head_t wait_queue;
    3.12  };
    3.13 @@ -101,6 +102,16 @@ static inline int copy_to_buffer(void *t
    3.14  	return 0;
    3.15  }
    3.16  
    3.17 +
    3.18 +static void dataex_init(struct data_exchange *dataex)
    3.19 +{
    3.20 +	INIT_LIST_HEAD(&dataex->pending_pak);
    3.21 +	INIT_LIST_HEAD(&dataex->current_pak);
    3.22 +	dataex->has_opener = 0;
    3.23 +	rwlock_init(&dataex->pak_lock);
    3.24 +	init_waitqueue_head(&dataex->wait_queue);
    3.25 +}
    3.26 +
    3.27  /***************************************************************
    3.28   Packet-related functions
    3.29  ***************************************************************/
    3.30 @@ -148,11 +159,12 @@ static struct packet *packet_alloc(tpmif
    3.31  				   u32 size, u8 req_tag, u8 flags)
    3.32  {
    3.33  	struct packet *pak = NULL;
    3.34 -	pak = kzalloc(sizeof (struct packet), GFP_KERNEL);
    3.35 +	pak = kzalloc(sizeof (struct packet), GFP_ATOMIC);
    3.36  	if (NULL != pak) {
    3.37  		if (tpmif) {
    3.38  			pak->tpmif = tpmif;
    3.39  			pak->tpm_instance = tpmif->tpm_instance;
    3.40 +			tpmif_get(tpmif);
    3.41  		}
    3.42  		pak->data_len = size;
    3.43  		pak->req_tag = req_tag;
    3.44 @@ -180,6 +192,9 @@ static void packet_free(struct packet *p
    3.45  	if (timer_pending(&pak->processing_timer)) {
    3.46  		BUG();
    3.47  	}
    3.48 +
    3.49 +	if (pak->tpmif)
    3.50 +		tpmif_put(pak->tpmif);
    3.51  	kfree(pak->data_buffer);
    3.52  	/*
    3.53  	 * cannot do tpmif_put(pak->tpmif); bad things happen
    3.54 @@ -271,7 +286,6 @@ int _packet_write(struct packet *pak,
    3.55  		struct gnttab_map_grant_ref map_op;
    3.56  		struct gnttab_unmap_grant_ref unmap_op;
    3.57  		tpmif_tx_request_t *tx;
    3.58 -		unsigned long pfn, mfn, mfn_orig;
    3.59  
    3.60  		tx = &tpmif->tx->ring[i].req;
    3.61  
    3.62 @@ -295,12 +309,6 @@ int _packet_write(struct packet *pak,
    3.63  			return 0;
    3.64  		}
    3.65  
    3.66 -		pfn = __pa(MMAP_VADDR(tpmif, i)) >> PAGE_SHIFT;
    3.67 -		mfn = FOREIGN_FRAME(map_op.dev_bus_addr >> PAGE_SHIFT);
    3.68 -		mfn_orig = pfn_to_mfn(pfn);
    3.69 -
    3.70 -		set_phys_to_machine(pfn, mfn);
    3.71 -
    3.72  		tocopy = MIN(size - offset, PAGE_SIZE);
    3.73  
    3.74  		if (copy_from_buffer((void *)(MMAP_VADDR(tpmif, i) |
    3.75 @@ -311,8 +319,6 @@ int _packet_write(struct packet *pak,
    3.76  		}
    3.77  		tx->size = tocopy;
    3.78  
    3.79 -		set_phys_to_machine(pfn, mfn_orig);
    3.80 -
    3.81  		gnttab_set_unmap_op(&unmap_op, MMAP_VADDR(tpmif, i),
    3.82  				    GNTMAP_host_map, handle);
    3.83  
    3.84 @@ -514,27 +520,41 @@ static ssize_t vtpm_op_read(struct file 
    3.85  	unsigned long flags;
    3.86  
    3.87  	write_lock_irqsave(&dataex.pak_lock, flags);
    3.88 +	if (dataex.aborted) {
    3.89 +		dataex.aborted = 0;
    3.90 +		dataex.copied_so_far = 0;
    3.91 +		write_unlock_irqrestore(&dataex.pak_lock, flags);
    3.92 +		return -EIO;
    3.93 +	}
    3.94  
    3.95  	if (list_empty(&dataex.pending_pak)) {
    3.96  		write_unlock_irqrestore(&dataex.pak_lock, flags);
    3.97  		wait_event_interruptible(dataex.wait_queue,
    3.98  					 !list_empty(&dataex.pending_pak));
    3.99  		write_lock_irqsave(&dataex.pak_lock, flags);
   3.100 +		dataex.copied_so_far = 0;
   3.101  	}
   3.102  
   3.103  	if (!list_empty(&dataex.pending_pak)) {
   3.104  		unsigned int left;
   3.105 +
   3.106  		pak = list_entry(dataex.pending_pak.next, struct packet, next);
   3.107 -
   3.108  		left = pak->data_len - dataex.copied_so_far;
   3.109 +		list_del(&pak->next);
   3.110 +		write_unlock_irqrestore(&dataex.pak_lock, flags);
   3.111  
   3.112  		DPRINTK("size given by app: %d, available: %d\n", size, left);
   3.113  
   3.114  		ret_size = MIN(size, left);
   3.115  
   3.116  		ret_size = packet_read(pak, ret_size, data, size, 1);
   3.117 +
   3.118 +		write_lock_irqsave(&dataex.pak_lock, flags);
   3.119 +
   3.120  		if (ret_size < 0) {
   3.121 -			ret_size = -EFAULT;
   3.122 +			del_singleshot_timer_sync(&pak->processing_timer);
   3.123 +			packet_free(pak);
   3.124 +			dataex.copied_so_far = 0;
   3.125  		} else {
   3.126  			DPRINTK("Copied %d bytes to user buffer\n", ret_size);
   3.127  
   3.128 @@ -545,7 +565,6 @@ static ssize_t vtpm_op_read(struct file 
   3.129  
   3.130  				del_singleshot_timer_sync(&pak->
   3.131  							  processing_timer);
   3.132 -				list_del(&pak->next);
   3.133  				list_add_tail(&pak->next, &dataex.current_pak);
   3.134  				/*
   3.135  				 * The more fontends that are handled at the same time,
   3.136 @@ -554,6 +573,8 @@ static ssize_t vtpm_op_read(struct file 
   3.137  				mod_timer(&pak->processing_timer,
   3.138  					  jiffies + (num_frontends * 60 * HZ));
   3.139  				dataex.copied_so_far = 0;
   3.140 +			} else {
   3.141 +				list_add(&pak->next, &dataex.pending_pak);
   3.142  			}
   3.143  		}
   3.144  	}
   3.145 @@ -601,8 +622,8 @@ static ssize_t vtpm_op_write(struct file
   3.146  
   3.147  	if (pak == NULL) {
   3.148  		write_unlock_irqrestore(&dataex.pak_lock, flags);
   3.149 -		printk(KERN_ALERT "No associated packet! (inst=%d)\n",
   3.150 -		       ntohl(vrh.instance_no));
   3.151 +		DPRINTK(KERN_ALERT "No associated packet! (inst=%d)\n",
   3.152 +		        ntohl(vrh.instance_no));
   3.153  		return -EFAULT;
   3.154  	}
   3.155  
   3.156 @@ -784,15 +805,17 @@ static int tpm_send_fail_message(struct 
   3.157  	return rc;
   3.158  }
   3.159  
   3.160 -static void _vtpm_release_packets(struct list_head *head,
   3.161 -				  tpmif_t * tpmif, int send_msgs)
   3.162 +static int _vtpm_release_packets(struct list_head *head,
   3.163 +				 tpmif_t * tpmif, int send_msgs)
   3.164  {
   3.165 +	int aborted = 0;
   3.166 +	int c = 0;
   3.167  	struct packet *pak;
   3.168 -	struct list_head *pos,
   3.169 -	         *tmp;
   3.170 +	struct list_head *pos, *tmp;
   3.171  
   3.172  	list_for_each_safe(pos, tmp, head) {
   3.173  		pak = list_entry(pos, struct packet, next);
   3.174 +		c += 1;
   3.175  
   3.176  		if (tpmif == NULL || pak->tpmif == tpmif) {
   3.177  			int can_send = 0;
   3.178 @@ -808,8 +831,11 @@ static void _vtpm_release_packets(struct
   3.179  				tpm_send_fail_message(pak, pak->req_tag);
   3.180  			}
   3.181  			packet_free(pak);
   3.182 +			if (c == 1)
   3.183 +				aborted = 1;
   3.184  		}
   3.185  	}
   3.186 +	return aborted;
   3.187  }
   3.188  
   3.189  int vtpm_release_packets(tpmif_t * tpmif, int send_msgs)
   3.190 @@ -818,7 +844,9 @@ int vtpm_release_packets(tpmif_t * tpmif
   3.191  
   3.192  	write_lock_irqsave(&dataex.pak_lock, flags);
   3.193  
   3.194 -	_vtpm_release_packets(&dataex.pending_pak, tpmif, send_msgs);
   3.195 +	dataex.aborted = _vtpm_release_packets(&dataex.pending_pak,
   3.196 +					       tpmif,
   3.197 +					       send_msgs);
   3.198  	_vtpm_release_packets(&dataex.current_pak, tpmif, send_msgs);
   3.199  
   3.200  	write_unlock_irqrestore(&dataex.pak_lock, flags);
   3.201 @@ -1020,11 +1048,7 @@ static int __init tpmback_init(void)
   3.202  		return rc;
   3.203  	}
   3.204  
   3.205 -	INIT_LIST_HEAD(&dataex.pending_pak);
   3.206 -	INIT_LIST_HEAD(&dataex.current_pak);
   3.207 -	dataex.has_opener = 0;
   3.208 -	rwlock_init(&dataex.pak_lock);
   3.209 -	init_waitqueue_head(&dataex.wait_queue);
   3.210 +	dataex_init(&dataex);
   3.211  
   3.212  	spin_lock_init(&tpm_schedule_list_lock);
   3.213  	INIT_LIST_HEAD(&tpm_schedule_list);
   3.214 @@ -1041,6 +1065,7 @@ module_init(tpmback_init);
   3.215  
   3.216  static void __exit tpmback_exit(void)
   3.217  {
   3.218 +	vtpm_release_packets(NULL, 0);
   3.219  	tpmif_xenbus_exit();
   3.220  	tpmif_interface_exit();
   3.221  	misc_deregister(&vtpms_miscdevice);