next up previous contents
Next: 4.0.3 Kernel pages, reserved Up: 4.0.2 Frozen memory Previous: 4.0.2 Frozen memory

4.0.2.1 Freezing memory banks

Memory banks implement methods used by freeze and melt.

There are two ways to freeze a memory bank:

1.
Eagerly, by freezing every page frame (i.e. forbidding write access to every page frame) and the memory bank itself.
2.
Lazily, by still allowing write access to every page frame until the user freezes every page page on his own and freezing just the memory bank state (this forbids both memory allocation and revocation). \end{enumerate}

We implement the second one because the first one can be implemented by system users which prefer it that way. Besides, by implementing the second one applications can still run until they produce further physical memory allocation requests.

We must implement these methods to support freeze:

<Other protected methods of off_MBank. >+= (<-U) [<-D->]
// These are for freeze:
// Freeze dynamic resource state at curbuf in buf with avail bytes. 
virtual err_t freeze_state(char *buf, char *&curbuf, size_t &avail,
                           char *&curto, size_t &toavail,
                           const off_prtl_id_t &frozen_domain);

// Copy static resource state in curbuf with toavail bytes. 
virtual err_t copy_state(char *&curto, size_t &toavail) const;

as well as these others to support melt:

<Other protected methods of off_MBank. >+= (<-U) [<-D->]
// These are for melt:
// Does resource cleanup. No external resource should be used after 
// return. 
virtual err_t cleanup(void);
// Restores the static state from a user supplied buffer. 
virtual err_t restore_state(char *&buf, size_t &bsize);
// Restores dynamic resource state. 
virtual err_t melt_state(char *&buf, size_t &bsize, char *&from, size_t &size,
                         const off_prtl_id_t &melted_domain);

The most simple are cleanup and copy_state. Any existing memory bank inspector is also deleted.

<off_MBank::cleanup implementation. >= (U->)
// Does resource cleanup. No external resource should be used after 
// return. 
err_t off_MBank::cleanup(void)
{
  assert(valid() && m_name && m_url);
  delete[] m_name;
  delete[] m_url;
  return EOK;
}

<off_MBank::copy_state implementation. >= (U->)
// Copy static resource state in curbuf with toavail bytes. 
err_t off_MBank::copy_state(char *&curto, size_t &toavail) const
{
  assert(valid());
  if (curto){
    if (toavail<sizeof(*this))
      return ENOSPC;
    *(off_MBank*)curto = *this;
    curto += sizeof(*this);
    toavail-=sizeof(*this);
  }
  return EOK;
}

The counterpart, restore_state, uses a copy operator tailored not to those members which must remain unaltered (m_attrs).

<Other public methods of off_MBank. >+= (<-U) [<-D->]
// Copy memory bank contents. 
const off_MBank &operator=(const off_MBank &other);

It also uses can_melt to know if the frozen memory bank can be melted on this one.

<Other protected methods of off_MBank. >+= (<-U) [<-D]
// Is the other bank meltable at this one?
boolean_t can_melt(const off_MBank *other) const;

<off_MBank::restore_state implementation. >= (U->)
// Restores the static state from a user supplied buffer. 
err_t off_MBank::restore_state(char *&buf, size_t &bsize)
{
  off_MBank *other=(off_MBank*)buf;
  assert(valid());
  if (buf){
    if (bsize < sizeof(*this) || !can_melt(other)){
      return EINVAL;
    }
    assert(other->valid());
    *this=*other;
    bsize-=sizeof(*this);
    buf+=sizeof(*this);
  }    
  return EOK;
}

<off_MBank::operator= implementation. >= (U->)
// Copy memory bank contents. 
const off_MBank &off_MBank::operator=(const off_MBank &other)
{
  *(off_HWCompResource*)this = *(off_HWCompResource*)&other;
  assert(valid() && other.valid());
  m_alloc = other.m_alloc;
  m_url=other.m_url;
  m_name=other.m_name;
  m_mdep=other.m_mdep;
  return *this;
}

The frozen memory bank can be melted only if addresses contained in the frozen bank are valid for us. Otherwise a ``bigger'' memory bank might be needed. Besides, we should check that we do not loose memory features.

<off_MBank::can_melt implementation. >= (U->)
// Is the other bank meltable at this one?
boolean_t off_MBank::can_melt(const off_MBank *other) const
{
  // NB: Perhaps we should relax and allow `degraded' melts
  //     where some features are missing. XXX
  //     Besides, only addresses for allocated pages need to be
  //     taken into account, not every address. 
  assert(valid() && other && other->valid());
  return ( !  ((other->is_dmable()     && !is_dmable())    ||
               (other->is_iomapable()  && !is_iomapable()) ||
               (other->is_persistent() && !is_persistent()) ) 
           && (other->get_first() >= get_first() &&
               other->get_last()  <= get_last()  &&
               other->get_mat()   >= get_mat()   &&
               other->get_pgsize(0) >= get_pgsize(0) &&
               other->get_pgsize(0) % get_pgsize(0) == 0));
}

Note how, with respect to page sizes, we admit melts whenever the page size in the frozen bank is an integral multiple of the page size in this bank (this may require some adjustment4.3 when melting frozen pages).

To freeze (or melt) the state of a memory bank we must freeze (or melt) dynamic members of the bank and also the page allocator being used. Only the allocator itself is affected, page frames will remain melted. That means that every page service (but for allocation and deallocation) is still available. Applications can keep on running while the memory bank is being transferred. The application issuing the freeze is expected to eventually freeze its page frames too.

<off_MBank::freeze_state implementation. >= (U->)
// Freeze dynamic resource state at curbuf in buf with avail bytes. 
err_t off_MBank::freeze_state(char *buf, char *&curbuf, size_t &avail,
                              char *&curto, size_t &toavail,
                              const off_prtl_id_t &frozen_domain)
{
  assert(valid() && buf && curbuf);
  if (!::freeze(m_name,buf,curbuf,avail) ||
      !::freeze(m_url,buf,curbuf,avail))
    return ENOSPC;
  set_domain(frozen_domain);
  return m_alloc.freeze_state(buf,curbuf,avail,curto,toavail);
}

<Off memory bank implementation dependencies. >+= (U->) [<-D->]
#include <klib/freeze.h>        // for ::freeze, ::melt et al.

<off_MBank::melt_state implementation. >= (U->)
// Restores dynamic resource state. 
err_t off_MBank::melt_state(char *&buf, size_t &bsize, 
                            char *&from, size_t &size,
                            const off_prtl_id_t &melted_domain)
{
  assert(valid() && buf && bsize>0);
  m_name=::melt(m_name,buf,bsize);
  m_url=::melt(m_url,buf,bsize);
  set_domain(melted_domain);
  return m_alloc.melt_state(buf,bsize,from,size);
}

\subsubsection{Freezing page frames}

We need to implement only these methods:

<Other protected methods of off_PFrame. >+= (<-U) [<-D]
// Copy static resource state in curbuf with toavail bytes. 
virtual err_t copy_state(char *&curto, size_t &toavail) const;

// Restores the static state from a user supplied buffer. 
virtual err_t restore_state(char *&buf, size_t &bsize);
// Restores dynamic resource state. 

<off_PFrame::copy_state implementation. >= (U->)
// Copy static resource state in curbuf with toavail bytes. 
err_t off_PFrame::copy_state(char *&curto, size_t &toavail) const
{
  assert(valid());
  if (curto){
    if (toavail<sizeof(*this))
      return ENOSPC;
    *(off_PFrame*)curto = *this;
    assert(((off_PFrame*)curto)->valid());
    curto += sizeof(*this);
    toavail-=sizeof(*this);
  }
  return EOK;
}

Note how in this one we take care that the reference to the container is not affected by the state restore.

<off_PFrame::restore_state implementation. >= (U->)
// Restores the static state from a user supplied buffer. 
err_t off_PFrame::restore_state(char *&buf, size_t &bsize)
{
  off_PFrame *other=(off_PFrame*)buf;
  assert(valid());
  if (buf){
    off_MBank *bank=(off_MBank*)get_container();
    if (bsize < sizeof(*this)){
      return EINVAL;
    }
    assert(other->valid());
    *this=*other;
    set_container(bank);
    buf+=sizeof(*this);
    bsize-=sizeof(*this);
  }    
  return EOK;
}

\subsection{Dumping memory}

To dump a memory bank we use this operator.

<Other public methods of off_MBank. >+= (<-U) [<-D->]
// Dumps mbank state. 
friend OStr &operator<<(OStr &s, off_MBank &m);

<off_MBank::operator<< implementation. >= (U->)
// Dumps mbank state. 
OStr &operator<<(OStr &s,  off_MBank &m)
{
  s << *(off_HWCompResource*)&m << nl;

  s << "name=" << m.nameof() << " url=" << m.get_url() << nl;
  s << "first=" << fmt("%08x",m.get_first()) <<
       " last="  << fmt("%08x",m.get_last())  <<
       fmt(" (%d pages)",m.get_npgs()) << ":" << nl;

  for (vm_size_t sz=0;(sz=m.get_pgsize(sz)) != 0; ){
    if (sz) 
      s << ",";
    s << fmt("%d",sz); 
  }
  s << ")" << nl;

  for (vm_offset_t p=m.get_first(),old=p; p < m.get_last() ; 
       old=p,p+=m.get_pgsize()){
    if (p==m.get_first() ||
    (m+old)->get_domain() != (m+p)->get_domain()){
      if (p>m.get_first())
        s<<" - "<<fmt("%05x",m.a2p(p-m.get_pgsize())) <<"]" <<nl;
      if ((m+p)->get_domain() == OFF_PRTL_NULL)
        s << "available                   [" << fmt("%05x",m.a2p(p));
      else if ((m+p)->get_domain() == nd.get_domain())
        s << "kernel                      [" << fmt("%05x",m.a2p(p));
      else
        s << (m+p)->get_domain() << "[" << fmt("%05x",m.a2p(p));
    }
  }
  s << " - " << fmt("%05x",m.a2p(m.get_last())) << "]" << nl;

  return s;

}

<Off memory bank implementation dependencies. >+= (U->) [<-D]
#include <klib/str.h>           // for OStr et al.

A similar operator is provided for page frames.

<Other public methods of off_PFrame. >+= (<-U) [<-D]
// Dumps pframe state. 
friend OStr &operator<<(OStr &s,  off_PFrame &p);

Its implementation dumps more than a full memory bank dump would do.

<off_PFrame::operator<< implementation. >= (U->)
// Dumps pframe state. 
OStr &operator<<(OStr &s,  off_PFrame &p)
{
   s << (off_HWResUnit)p << fmt("bits=%02x",p.p_bits) << nl;
   return s;
}

<Off page frame implementation dependencies. >+= (U->) [<-D]
#include <klib/str.h>           // for OStr et al.


next up previous contents
Next: 4.0.3 Kernel pages, reserved Up: 4.0.2 Frozen memory Previous: 4.0.2 Frozen memory
Francisco J. Ballesteros
1998-05-25