ia64/xen-unstable

changeset 8427:48eb10d7a2d6

Increment page reference count for every host/device
mapping created via a grant reference, rather than one
increment for all uses of a single grant reference.
This avoids a nasty situation in put_page_from_l1e()
where we cannot reliably determine whether a mapping was
created via a grant reference and so we must always
decrement the mapped page's reference count.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Dec 21 18:25:34 2005 +0100 (2005-12-21)
parents f2a08a5a807a
children b3edbeea3e79
files xen/common/grant_table.c
line diff
     1.1 --- a/xen/common/grant_table.c	Wed Dec 21 18:16:31 2005 +0100
     1.2 +++ b/xen/common/grant_table.c	Wed Dec 21 18:25:34 2005 +0100
     1.3 @@ -177,17 +177,19 @@ static int
     1.4  
     1.5      spin_lock(&rd->grant_table->lock);
     1.6  
     1.7 -    if ( act->pin == 0 )
     1.8 +    if ( !act->pin ||
     1.9 +         (!(dev_hst_ro_flags & GNTMAP_readonly) &&
    1.10 +          !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
    1.11      {
    1.12 -        /* CASE 1: Activating a previously inactive entry. */
    1.13 -
    1.14          sflags = sha->flags;
    1.15          sdom   = sha->domid;
    1.16  
    1.17 -        /* This loop attempts to set the access (reading/writing) flags
    1.18 +        /*
    1.19 +         * This loop attempts to set the access (reading/writing) flags
    1.20           * in the grant table entry.  It tries a cmpxchg on the field
    1.21           * up to five times, and then fails under the assumption that 
    1.22 -         * the guest is misbehaving. */
    1.23 +         * the guest is misbehaving.
    1.24 +         */
    1.25          for ( ; ; )
    1.26          {
    1.27              u32 scombo, prev_scombo, new_scombo;
    1.28 @@ -196,7 +198,7 @@ static int
    1.29                   unlikely(sdom != led->domain->domain_id) )
    1.30                  PIN_FAIL(unlock_out, GNTST_general_error,
    1.31                           "Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
    1.32 -                        sflags, sdom, led->domain->domain_id);
    1.33 +                         sflags, sdom, led->domain->domain_id);
    1.34  
    1.35              /* Merge two 16-bit values into a 32-bit combined update. */
    1.36              /* NB. Endianness! */
    1.37 @@ -232,132 +234,50 @@ static int
    1.38              sdom   = (u16)(prev_scombo >> 16);
    1.39          }
    1.40  
    1.41 -        /* rmb(); */ /* not on x86 */
    1.42 -
    1.43 -        frame = __gpfn_to_mfn(rd, sha->frame);
    1.44 -
    1.45 -        if ( unlikely(!pfn_valid(frame)) ||
    1.46 -             unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ?
    1.47 -                        get_page(pfn_to_page(frame), rd) :
    1.48 -                        get_page_and_type(pfn_to_page(frame), rd,
    1.49 -                                          PGT_writable_page))) )
    1.50 -        {
    1.51 -            clear_bit(_GTF_writing, &sha->flags);
    1.52 -            clear_bit(_GTF_reading, &sha->flags);
    1.53 -            PIN_FAIL(unlock_out, GNTST_general_error,
    1.54 -                     "Could not pin the granted frame (%lx)!\n", frame);
    1.55 -        }
    1.56 -
    1.57 -        if ( dev_hst_ro_flags & GNTMAP_device_map )
    1.58 -            act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
    1.59 -                GNTPIN_devr_inc : GNTPIN_devw_inc;
    1.60 -        if ( dev_hst_ro_flags & GNTMAP_host_map )
    1.61 -            act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
    1.62 -                GNTPIN_hstr_inc : GNTPIN_hstw_inc;
    1.63 -        act->domid = sdom;
    1.64 -        act->frame = frame;
    1.65 -    }
    1.66 -    else 
    1.67 -    {
    1.68 -        /* CASE 2: Active modications to an already active entry. */
    1.69 -
    1.70 -        /*
    1.71 -         * A cheesy check for possible pin-count overflow.
    1.72 -         * A more accurate check cannot be done with a single comparison.
    1.73 -         */
    1.74 -        if ( (act->pin & 0x80808080U) != 0 )
    1.75 -            PIN_FAIL(unlock_out, ENOSPC,
    1.76 -                     "Risk of counter overflow %08x\n", act->pin);
    1.77 -
    1.78 -        sflags = sha->flags;
    1.79 -        frame  = act->frame;
    1.80 -
    1.81 -        if ( !(dev_hst_ro_flags & GNTMAP_readonly) &&
    1.82 -             !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
    1.83 +        if ( !act->pin )
    1.84          {
    1.85 -            for ( ; ; )
    1.86 -            {
    1.87 -                u16 prev_sflags;
    1.88 -                
    1.89 -                if ( unlikely(sflags & GTF_readonly) )
    1.90 -                    PIN_FAIL(unlock_out, GNTST_general_error,
    1.91 -                             "Attempt to write-pin a r/o grant entry.\n");
    1.92 -
    1.93 -                prev_sflags = sflags;
    1.94 -
    1.95 -                /* NB. prev_sflags is updated in place to seen value. */
    1.96 -                if ( unlikely(cmpxchg_user(&sha->flags, prev_sflags, 
    1.97 -                                           prev_sflags | GTF_writing)) )
    1.98 -                    PIN_FAIL(unlock_out, GNTST_general_error,
    1.99 -                         "Fault while modifying shared flags.\n");
   1.100 -
   1.101 -                if ( likely(prev_sflags == sflags) )
   1.102 -                    break;
   1.103 -
   1.104 -                if ( retries++ == 4 )
   1.105 -                    PIN_FAIL(unlock_out, GNTST_general_error,
   1.106 -                             "Shared grant entry is unstable.\n");
   1.107 +            act->domid = sdom;
   1.108 +            act->frame = __gpfn_to_mfn(rd, sha->frame);
   1.109 +        }
   1.110 +    }
   1.111 +    else if ( (act->pin & 0x80808080U) != 0 )
   1.112 +        PIN_FAIL(unlock_out, ENOSPC,
   1.113 +                 "Risk of counter overflow %08x\n", act->pin);
   1.114  
   1.115 -                sflags = prev_sflags;
   1.116 -            }
   1.117 -
   1.118 -            if ( unlikely(!get_page_type(pfn_to_page(frame),
   1.119 -                                         PGT_writable_page)) )
   1.120 -            {
   1.121 -                clear_bit(_GTF_writing, &sha->flags);
   1.122 -                PIN_FAIL(unlock_out, GNTST_general_error,
   1.123 -                         "Attempt to write-pin a unwritable page.\n");
   1.124 -            }
   1.125 -        }
   1.126 -
   1.127 -        if ( dev_hst_ro_flags & GNTMAP_device_map )
   1.128 -            act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? 
   1.129 -                GNTPIN_devr_inc : GNTPIN_devw_inc;
   1.130 -
   1.131 -        if ( dev_hst_ro_flags & GNTMAP_host_map )
   1.132 -            act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
   1.133 -                GNTPIN_hstr_inc : GNTPIN_hstw_inc;
   1.134 -    }
   1.135 -
   1.136 -    /*
   1.137 -     * At this point:
   1.138 -     * act->pin updated to reference count mappings.
   1.139 -     * sha->flags updated to indicate to granting domain mapping done.
   1.140 -     * frame contains the mfn.
   1.141 -     */
   1.142 +    if ( dev_hst_ro_flags & GNTMAP_device_map )
   1.143 +        act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
   1.144 +            GNTPIN_devr_inc : GNTPIN_devw_inc;
   1.145 +    if ( dev_hst_ro_flags & GNTMAP_host_map )
   1.146 +        act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
   1.147 +            GNTPIN_hstr_inc : GNTPIN_hstw_inc;
   1.148  
   1.149      spin_unlock(&rd->grant_table->lock);
   1.150  
   1.151 +    frame = act->frame;
   1.152 +    if ( unlikely(!pfn_valid(frame)) ||
   1.153 +         unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ?
   1.154 +                    get_page(pfn_to_page(frame), rd) :
   1.155 +                    get_page_and_type(pfn_to_page(frame), rd,
   1.156 +                                      PGT_writable_page))) )
   1.157 +        PIN_FAIL(undo_out, GNTST_general_error,
   1.158 +                 "Could not pin the granted frame (%lx)!\n", frame);
   1.159 +
   1.160      if ( dev_hst_ro_flags & GNTMAP_host_map )
   1.161      {
   1.162          rc = create_grant_host_mapping(addr, frame, dev_hst_ro_flags);
   1.163 -        if ( rc < 0 )
   1.164 +        if ( rc != GNTST_okay )
   1.165          {
   1.166 -            /* Failure: undo and abort. */
   1.167 -
   1.168 -            spin_lock(&rd->grant_table->lock);
   1.169 +            if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
   1.170 +                put_page_type(pfn_to_page(frame));
   1.171 +            put_page(pfn_to_page(frame));
   1.172 +            goto undo_out;
   1.173 +        }
   1.174  
   1.175 -            if ( dev_hst_ro_flags & GNTMAP_readonly )
   1.176 -            {
   1.177 -                act->pin -= GNTPIN_hstr_inc;
   1.178 -            }
   1.179 -            else
   1.180 -            {
   1.181 -                act->pin -= GNTPIN_hstw_inc;
   1.182 -                if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 )
   1.183 -                {
   1.184 -                    clear_bit(_GTF_writing, &sha->flags);
   1.185 -                    put_page_type(pfn_to_page(frame));
   1.186 -                }
   1.187 -            }
   1.188 -
   1.189 -            if ( act->pin == 0 )
   1.190 -            {
   1.191 -                clear_bit(_GTF_reading, &sha->flags);
   1.192 -                put_page(pfn_to_page(frame));
   1.193 -            }
   1.194 -
   1.195 -            spin_unlock(&rd->grant_table->lock);
   1.196 +        if ( dev_hst_ro_flags & GNTMAP_device_map )
   1.197 +        {
   1.198 +            (void)get_page(pfn_to_page(frame), rd);
   1.199 +            if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
   1.200 +                get_page_type(pfn_to_page(frame), PGT_writable_page);
   1.201          }
   1.202      }
   1.203  
   1.204 @@ -375,6 +295,24 @@ static int
   1.205      put_domain(rd);
   1.206      return rc;
   1.207  
   1.208 + undo_out:
   1.209 +    spin_lock(&rd->grant_table->lock);
   1.210 +
   1.211 +    if ( dev_hst_ro_flags & GNTMAP_device_map )
   1.212 +        act->pin -= (dev_hst_ro_flags & GNTMAP_readonly) ?
   1.213 +            GNTPIN_devr_inc : GNTPIN_devw_inc;
   1.214 +    if ( dev_hst_ro_flags & GNTMAP_host_map )
   1.215 +        act->pin -= (dev_hst_ro_flags & GNTMAP_readonly) ?
   1.216 +            GNTPIN_hstr_inc : GNTPIN_hstw_inc;
   1.217 +
   1.218 +    if ( !(dev_hst_ro_flags & GNTMAP_readonly) &&
   1.219 +         !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
   1.220 +        clear_bit(_GTF_writing, &sha->flags);
   1.221 +
   1.222 +    if ( !act->pin )
   1.223 +        clear_bit(_GTF_reading, &sha->flags);
   1.224 +
   1.225 +    spin_unlock(&rd->grant_table->lock);
   1.226  
   1.227   unlock_out:
   1.228      spin_unlock(&rd->grant_table->lock);
   1.229 @@ -465,27 +403,42 @@ static int
   1.230              PIN_FAIL(unmap_out, GNTST_general_error,
   1.231                       "Bad frame number doesn't match gntref.\n");
   1.232          if ( flags & GNTMAP_device_map )
   1.233 -            act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_devr_inc
   1.234 -                                                  : GNTPIN_devw_inc;
   1.235 -
   1.236 -        map->ref_and_flags &= ~GNTMAP_device_map;
   1.237 -        (void)__put_user(0, &uop->dev_bus_addr);
   1.238 +        {
   1.239 +            ASSERT(act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask));
   1.240 +            map->ref_and_flags &= ~GNTMAP_device_map;
   1.241 +            if ( flags & GNTMAP_readonly )
   1.242 +            {
   1.243 +                act->pin -= GNTPIN_devr_inc;
   1.244 +                put_page(pfn_to_page(frame));
   1.245 +            }
   1.246 +            else
   1.247 +            {
   1.248 +                act->pin -= GNTPIN_devw_inc;
   1.249 +                put_page_and_type(pfn_to_page(frame));
   1.250 +            }
   1.251 +        }
   1.252      }
   1.253  
   1.254 -    if ( (addr != 0) &&
   1.255 -         (flags & GNTMAP_host_map) &&
   1.256 -         ((act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) > 0))
   1.257 +    if ( (addr != 0) && (flags & GNTMAP_host_map) )
   1.258      {
   1.259          if ( (rc = destroy_grant_host_mapping(addr, frame, flags)) < 0 )
   1.260              goto unmap_out;
   1.261  
   1.262 +        ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask));
   1.263          map->ref_and_flags &= ~GNTMAP_host_map;
   1.264 -
   1.265 -        act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_hstr_inc
   1.266 -                                              : GNTPIN_hstw_inc;
   1.267 +        if ( flags & GNTMAP_readonly )
   1.268 +        {
   1.269 +            act->pin -= GNTPIN_hstr_inc;
   1.270 +            put_page(pfn_to_page(frame));
   1.271 +        }
   1.272 +        else
   1.273 +        {
   1.274 +            act->pin -= GNTPIN_hstw_inc;
   1.275 +            put_page_and_type(pfn_to_page(frame));
   1.276 +        }
   1.277      }
   1.278  
   1.279 -    if ( (map->ref_and_flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0)
   1.280 +    if ( (map->ref_and_flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0 )
   1.281      {
   1.282          map->ref_and_flags = 0;
   1.283          put_maptrack_handle(ld->grant_table, handle);
   1.284 @@ -495,20 +448,12 @@ static int
   1.285      if ( !(flags & GNTMAP_readonly) )
   1.286           gnttab_log_dirty(rd, frame);
   1.287  
   1.288 -    /* If the last writable mapping has been removed, put_page_type */
   1.289      if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
   1.290           !(flags & GNTMAP_readonly) )
   1.291 -    {
   1.292          clear_bit(_GTF_writing, &sha->flags);
   1.293 -        put_page_type(pfn_to_page(frame));
   1.294 -    }
   1.295  
   1.296      if ( act->pin == 0 )
   1.297 -    {
   1.298 -        act->frame = 0xdeadbeef;
   1.299          clear_bit(_GTF_reading, &sha->flags);
   1.300 -        put_page(pfn_to_page(frame));
   1.301 -    }
   1.302  
   1.303   unmap_out:
   1.304      (void)__put_user(rc, &uop->status);
   1.305 @@ -989,42 +934,40 @@ gnttab_release_mappings(
   1.306          {
   1.307              if ( map->ref_and_flags & GNTMAP_device_map )
   1.308              {
   1.309 -                BUG_ON((act->pin & GNTPIN_devr_mask) == 0);
   1.310 +                BUG_ON(!(act->pin & GNTPIN_devr_mask));
   1.311                  act->pin -= GNTPIN_devr_inc;
   1.312 +                put_page(pfn_to_page(act->frame));
   1.313              }
   1.314  
   1.315              if ( map->ref_and_flags & GNTMAP_host_map )
   1.316              {
   1.317 -                BUG_ON((act->pin & GNTPIN_hstr_mask) == 0);
   1.318 +                BUG_ON(!(act->pin & GNTPIN_hstr_mask));
   1.319                  act->pin -= GNTPIN_hstr_inc;
   1.320 +                put_page(pfn_to_page(act->frame));
   1.321              }
   1.322          }
   1.323          else
   1.324          {
   1.325              if ( map->ref_and_flags & GNTMAP_device_map )
   1.326              {
   1.327 -                BUG_ON((act->pin & GNTPIN_devw_mask) == 0);
   1.328 +                BUG_ON(!(act->pin & GNTPIN_devw_mask));
   1.329                  act->pin -= GNTPIN_devw_inc;
   1.330 +                put_page_and_type(pfn_to_page(act->frame));
   1.331              }
   1.332  
   1.333              if ( map->ref_and_flags & GNTMAP_host_map )
   1.334              {
   1.335 -                BUG_ON((act->pin & GNTPIN_hstw_mask) == 0);
   1.336 +                BUG_ON(!(act->pin & GNTPIN_hstw_mask));
   1.337                  act->pin -= GNTPIN_hstw_inc;
   1.338 +                put_page_and_type(pfn_to_page(act->frame));
   1.339              }
   1.340  
   1.341              if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
   1.342 -            {
   1.343                  clear_bit(_GTF_writing, &sha->flags);
   1.344 -                put_page_type(pfn_to_page(act->frame));
   1.345 -            }
   1.346          }
   1.347  
   1.348          if ( act->pin == 0 )
   1.349 -        {
   1.350              clear_bit(_GTF_reading, &sha->flags);
   1.351 -            put_page(pfn_to_page(act->frame));
   1.352 -        }
   1.353  
   1.354          spin_unlock(&rd->grant_table->lock);
   1.355