Commit Graph

63 Commits

Author SHA1 Message Date
Cole Robinson
272c622475 storage: drop the plumbing needed for kvm-img/qcow-create
Remove all the plumbing needed for the different qcow-create/kvm-img
non-raw file creation.

We can drop the error messages because CreateQemuImg will thrown an
error for us but with slightly less fidelity (unable to find qemu-img),
which I think is acceptable given the unlikeliness of that error in
practice.
2016-04-20 08:59:57 -04:00
Olga Krishtal
ea94be4703 storage: dir: adapt .refreshVol and .refreshPool for ploop volumes
Refreshes meta-information such as allocation, capacity, format, etc.
Ploop volumes differ from other volume types. Path to volume is the path
to directory with image file root.hds and DiskDescriptor.xml.
https://openvz.org/Ploop/format
Due to this fact, operations of opening the volume have to be done once
again. get the information.

To decide whether the given volume is ploops one, it is necessary to check
the presence of root.hds and DiskDescriptor.xml files in volumes' directory.
Only in this case the volume can be manipulated as the ploops one.
Such strategy helps us to resolve problems that might occure, when we
upload some other volume type from ploop source.

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com>
Signed-off-by: Ján Tomko <jtomko@redhat.com>
2016-04-15 17:27:32 +02:00
Olga Krishtal
d957ba8deb storage: dir: .resizeVol callback for ploop volume
Changes the size of given ploop volume via ploop resize tool.

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com>
2016-04-15 17:27:32 +02:00
Olga Krishtal
cff2138b71 storage: dir: .buildVol and .buildVolFrom callbacks for ploop
These callbacks let us to create ploop volumes in dir, fs and etc. pools.
If a ploop volume was created via buildVol callback, then this volume
is an empty ploop device with DiskDescriptor.xml.
If the volume was created via .buildFrom - then its content is similar to
input volume content.

Signed-off-by: Olga Krishtal <okrishtal@virtuozzo.com>
Signed-off-by: Ján Tomko <jtomko@redhat.com>
2016-04-15 17:27:32 +02:00
John Ferlan
1bc84b0a08 storage: Handle readflags errors
Similar to the openflags VIR_STORAGE_VOL_OPEN_NOERROR processing, if some
read processing operation fails, check the readflags for the corresponding
error flag being set. If so, rather then causing an error - use VIR_WARN
to flag the error, but return -2 which some callers can use to perform
specific actions. Use a new VIR_STORAGE_VOL_READ_NOERROR flag in a new
VolReadErrorMode enum.
2015-12-09 16:31:14 -05:00
John Ferlan
22346003dc storage: Add readflags for backend error processing
Similar to the openflags which allow VIR_STORAGE_VOL_OPEN_NOERROR to be
passed to avoid open errors, add a 'readflags' variable so that in the
future read failures could also be ignored.
2015-12-09 16:31:14 -05:00
John Ferlan
4cd7d220c9 storage: On 'buildVol' failure don't delete the volume
https://bugzilla.redhat.com/show_bug.cgi?id=1233003

Commit id 'fdda3760' only managed a symptom where it was possible to
create a file in a pool without libvirt's knowledge, so it was reverted.

The real fix is to have all the createVol API's which actually create
a volume (disk, logical, zfs) and the buildVol API's which handle the
real creation of some volume file (fs, rbd, sheepdog) manage deleting
any volume which they create when there is some sort of error in
processing the volume.

This way the onus isn't left up to the storage_driver to determine whether
the buildVol failure was due to some failure as a result of adjustments
made to the volume after creation such as getting sizes, changing ownership,
changing volume protections, etc. or simple a failure in creation.

Without needing to consider that the volume has to be removed, the
buildVol failure path only needs to remove the volume from the pool.
This way if a creation failed due to duplicate name, libvirt wouldn't
remove a volume that it didn't create in the pool target.
2015-11-04 07:21:11 -05:00
Cole Robinson
7c2d65dde2 storage: conf: Don't set any default <mode> in the XML
The XML parser sets a default <mode> if none is explicitly passed in.
This is then used at pool/vol creation time, and unconditionally reported
in the XML.

The problem with this approach is that it's impossible for other code
to determine if the user explicitly requested a storage mode. There
are some cases where we want to make this distinction, but we currently
can't.

Handle <mode> parsing like we handle <owner>/<group>: if no value is
passed in, set it to -1, and adjust the internal consumers to handle
it.
2015-05-25 20:52:55 -04:00
John Ferlan
9126161d0b storage: Split out the stable path check
For virStorageBackendStablePath, in order to make decisions in other code
split out the checks regarding whether the pool's target is empty, using /dev,
using /dev/, or doesn't start with /dev
2015-04-21 06:08:05 -04:00
Ján Tomko
a832735df9 Rename virStorageBackendCreateQemuImgCmd
Add FromVol at the end. This function will create the qemu-img
command line from volume definitions and check them.
2015-04-13 15:59:20 +02:00
Erik Skultety
cf7392a0d2 storage: Remove unused attribute conn from 'checkPool' callback
In order to be able to use 'checkPool' inside functions which do not
have any connection reference, 'conn' attribute needs to be discarded
from the checkPool's signature, since it's not used by any storage backend
anyway.
2015-04-02 11:57:07 +02:00
Ján Tomko
d3452a3f73 Revert "Restore skipping of setting capacity"
This reverts commit f1856eb622.

Now that we can update capacity from image metadata,
we don't need to skip the update.
2015-03-02 08:07:11 +01:00
Peter Krempa
50f09651df storage: Implement storage driver helper to chown disk images
Gluster storage works on a similar principle to NFS where it takes the
uid and gid of the actual process and uses it to access the storage
volume on the remote server. This introduces a need to chown storage
files on gluster via native API.
2014-07-24 09:58:59 +02:00
Peter Krempa
11d28050c5 storage: Split out volume wiping as separate backend function
For non-local storage drivers we can't expect to use the "scrub" tool to
wipe the volume. Split the code into a separate backend function so that
we can add protocol specific code later.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1118710
2014-07-17 10:12:34 +02:00
Peter Krempa
4d799b65cd storage: wipe: Move helper code into storage backend
The next patch will move the storage volume wiping code into the
individual backends. This patch splits out the common code to wipe a
local volume into a separate backend helper so that the next patch is
simpler.
2014-07-17 10:12:34 +02:00
Peter Krempa
589c2ad93f storage: Split out volume upload/download as separate backend function
For non-local storage drivers we can't expect to use the FDStream
backend for up/downloading volumes. Split the code into a separate
backend function so that we can add protocol specific code later.
2014-07-11 09:54:08 +02:00
Peter Krempa
edfd6127c1 storage: backend: Add possibility to suppress errors from backend lookup
Add a new function wrapper and tweak the storage file backend lookup
function so that it can be used without reporting error. This will be
useful in the metadata crawler code where we need silently break if
metadata retrieval is not supported for the current storage type.
2014-06-03 09:27:23 +02:00
Peter Krempa
4cb2505557 storage: Add API to check accessibility of storage volumes
Add a storage driver API equivalent of the access() function.
Implementations for the filesystem and gluster backends are provided.
2014-06-03 09:27:23 +02:00
Peter Krempa
684ec651e9 storage: backend: Add unique id retrieval API
Different protocols have different means to uniquely identify a storage
file. This patch implements a storage driver API to retrieve a unique
string describing a volume. The current implementation works for local
storage only and returns the canonical path of the volume.

To add caching support the local filesystem driver now has a private
structure holding the cached string, which is created only when it's
initially accessed.

This patch provides the implementation for local files only for start.
2014-06-03 09:27:22 +02:00
Peter Krempa
81271a9261 storage: Add storage file API to read file headers
Add storage driver based functions to access headers of storage files
for metadata extraction. Along with this patch a local filesystem and
gluster via libgfapi implementation is provided. The gluster
implementation is based on code of the saferead_lim function.
2014-05-23 10:57:33 +02:00
Peter Krempa
ae26731e1f storage: Add support for access to files using provided uid/gid
To allow using the storage driver APIs to access files on various
storage sources in a universal fashion possibly on storage such as nfs
with root squash we'll need to store the desired uid/gid in the
metadata.

Add new initialisation API that will store the desired uid/gid and a
wrapper for the current use. Additionally add docs for the two APIs.
2014-05-23 10:48:48 +02:00
John Ferlan
f1856eb622 Restore skipping of setting capacity
Commit id 'ac9a0963' refactored out the 'withCapacity' for the
virStorageBackendUpdateVolInfo() API.  See:

http://www.redhat.com/archives/libvir-list/2014-April/msg00043.html

This resulted in a difference in how 'virsh vol-info --pool <poolName>
<volume>' or 'virsh vol-list vol-list --pool <poolName> --details' outputs
the capacity information for a directory pool with a qcow2 sparse file.

For example, using the following XML

mkdir /home/TestPool
cat testpool.xml
<pool type='dir'>
  <name>TestPool</name>
  <uuid>6bf80895-10b6-75a6-6059-89fdea2aefb7</uuid>
  <source>
  </source>
  <target>
    <path>/home/TestPool</path>
    <permissions>
      <mode>0755</mode>
      <owner>0</owner>
      <group>0</group>
    </permissions>
  </target>
</pool>

virsh pool-create testpool.xml
virsh vol-create-as --pool TestPool temp_vol_1 \
      --capacity 1048576 --allocation 1048576 --format qcow2
virsh vol-info --pool TestPool temp_vol_1

Results in listing a Capacity value.  Prior to the commit, the value would
be '1.0 MiB' (1048576 bytes). However, after the commit the output would be
(for example) '192.50 KiB', which for my system was the size of the volume
in my file system (eg 'ls -l TestPool/temp_vol_1' results in '197120' bytes
or 192.50 KiB). While perhaps technically correct, it's not necessarily
what the user expected (certainly virt-test didn't expect it).

This patch restores the code to not update the target capacity for this path
2014-05-02 07:11:05 -04:00
Peter Krempa
cecd656604 storage: Refactor location of metadata for storage drive access to files
Now that we store all metadata about a storage image in a
virStorageSource struct let's use it also to store information needed by
the storage driver to access and do operations on the files.
2014-04-09 14:34:19 +02:00
Cole Robinson
138e65c3be storage: Report error from VolOpen by default
Currently VolOpen notifies the user of a potentially non-fatal failure by
returning -2 and logging a VIR_WARN or VIR_INFO. Unfortunately most
callers treat -2 as fatal but don't actually report any message with
the error APIs.

Rename the VOL_OPEN_ERROR flag to VOL_OPEN_NOERROR. If NOERROR is specified,
we preserve the current behavior of returning -2 (there's only one caller
that wants this).

However in the default case, only return -1, and actually use the error
APIs. Fix up a couple callers as a result.
2014-04-02 12:44:16 -04:00
Eric Blake
ac9a0963fa conf: drop redundant parameters during probe
Now that each virStorageSource can track allocation information,
and given that we already have the information without extra
syscalls, it's easier to just always populate the information
directly into the struct than it is to sometimes pass the address
of the struct members down the call chain.

* src/storage/storage_backend.h (virStorageBackendUpdateVolInfo)
(virStorageBackendUpdateVolTargetInfo)
(virStorageBackendUpdateVolTargetInfoFD): Update signature.
* src/storage/storage_backend.c (virStorageBackendUpdateVolInfo)
(virStorageBackendUpdateVolTargetInfo)
(virStorageBackendUpdateVolTargetInfoFD): Always populate struct
members instead.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskMakeDataVol): Update client.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget)
(virStorageBackendFileSystemRefresh)
(virStorageBackendFileSystemVolRefresh): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageBackendGlusterRefreshVol): Likewise.
* src/storage/storage_backend_logical.c
(virStorageBackendLogicalMakeVol): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathNewVol): Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSINewLun): Likewise.

Signed-off-by: Eric Blake <eblake@redhat.com>
2014-04-02 06:03:01 -06:00
Eric Blake
df17611525 conf: use common struct in storage volumes
A fairly smooth transition.  And now that domain disks and
storage volumes share a common struct, it opens the doors for
a future patch to expose more details in the XML for both
objects.

* src/conf/storage_conf.h (_virStorageVolTarget): Delete.
(_virStorageVolDef): Use common type.
* src/conf/storage_conf.c (virStorageVolDefFree)
(virStorageVolTargetDefFormat): Update clients.
* src/storage/storage_backend.h: Likewise.
* src/storage/storage_backend.c
(virStorageBackendDetectBlockVolFormatFD)
(virStorageBackendUpdateVolTargetInfo)
(virStorageBackendUpdateVolTargetInfoFD): Likewise.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget):
Likewise.

Signed-off-by: Eric Blake <eblake@redhat.com>
2014-04-02 06:03:00 -06:00
Peter Krempa
05671b95db storage: netfs: Support lookup of glusterfs pool sources
https://bugzilla.redhat.com/show_bug.cgi?id=1072714

Use the "gluster" command line tool to retrieve information about remote
volumes on a gluster server to allow storage pool source lookup.

Unfortunately gluster doesn't provide a management library so that we
could use that directly, instead the RPC calls are hardcoded in the
command line tool.
2014-04-01 11:06:05 +02:00
Cole Robinson
fa5b5549cb storage: Rename VolOpenCheckMode to VolOpen
Remove the original VolOpen implementation, which is now only used in
one spot.
2014-03-31 18:32:03 -04:00
Cole Robinson
847a9eb17e storage: move block format lookup to shared UpdateVolInfo 2014-03-31 18:31:00 -04:00
Cole Robinson
16d75d19fc storage: Rename UpdateVolInfoFlags to UpdateVolInfo
And drop the original UpdateVolInfo. Makes it a bit easier to follow
the function usage.

And change the int parameter to an explicit bool.
2014-03-31 18:30:35 -04:00
Ján Tomko
0edfc9ef63 Ignore char devices in storage pools by default
Without this, using /dev/mapper as a directory pool
fails in virStorageBackendUpdateVolTargetInfoFD:
cannot seek to end of file '/dev/mapper/control': Illegal seek

Skip over character devices by default.

https://bugzilla.redhat.com/show_bug.cgi?id=710866
2014-03-20 18:13:57 +01:00
Ján Tomko
f2cc42868e Move virStorageBackendRun to vircommand
The only storage-specific parameter is the pool object, which
is only used for passing to the callback function.
2014-03-20 18:04:50 +01:00
Peter Krempa
8d8b32b0da storage: Fix build with older compilers afeter gluster snapshot series
In commit e32268184b I accidentally added
twice a typedef for virStorageFileBackend when I moved it between files
across patch iterations. The double declaration breaks build on older
compilers in RHEL5 and FreeBSD.

Remove the spurious definition.
2014-02-14 11:46:37 +01:00
Peter Krempa
e32268184b storage: Add file storage APIs in the default storage driver
Add APIs that will allow to use the storage driver to assist in
operations on files even for remote filesystems without native
representation as files in the host.
2014-02-14 10:47:56 +01:00
Peter Krempa
d952619894 storage: Break long lines and clean up spaces in storage backend header 2014-01-13 11:21:33 +01:00
Eric Blake
318ea3cb77 storage: initial support for linking with libgfapi
We support gluster volumes in domain XML, so we also ought to
support them as a storage pool.  Besides, a future patch will
want to take advantage of libgfapi to handle the case of a
gluster device holding qcow2 rather than raw storage, and for
that to work, we need a storage backend that can read gluster
storage volume contents.  This sets up the framework.

Note that the new pool is named 'gluster' to match a
<disk type='network'><source protocol='gluster'> image source
already supported in a <domain>; it does NOT match the
<pool type='netfs'><source><target type='glusterfs'>,
since that uses a FUSE mount to a local file name rather than
a network name.

This and subsequent patches have been tested against glusterfs
3.4.1 (available on Fedora 19); there are likely bugs in older
versions that may prevent decent use of gfapi, so this patch
enforces the minimum version tested.  A future patch may lower
the minimum.  On the other hand, I hit at least two bugs in
3.4.1 that will be fixed in 3.5/3.4.2, where it might be worth
raising the minimum: glfs_readdir is nicer to use than
glfs_readdir_r [1], and glfs_fini should only return failure on
an actual failure [2].

[1] http://lists.gnu.org/archive/html/gluster-devel/2013-10/msg00085.html
[2] http://lists.gnu.org/archive/html/gluster-devel/2013-10/msg00086.html

* configure.ac (WITH_STORAGE_GLUSTER): New conditional.
* m4/virt-gluster.m4: new file.
* libvirt.spec.in (BuildRequires): Support gluster in spec file.
* src/conf/storage_conf.h (VIR_STORAGE_POOL_GLUSTER): New pool
type.
* src/conf/storage_conf.c (poolTypeInfo): Treat similar to
sheepdog and rbd.
(virStoragePoolDefFormat): Don't output target for gluster.
* src/storage/storage_backend_gluster.h: New file.
* src/storage/storage_backend_gluster.c: Likewise.
* po/POTFILES.in: Add new file.
* src/storage/storage_backend.c (backends): Register new type.
* src/Makefile.am (STORAGE_DRIVER_GLUSTER_SOURCES): Build new files.
* src/storage/storage_backend.h (_virStorageBackend): Documet
assumption.

Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-25 11:02:52 -07:00
Eric Blake
9cac863965 storage: reduce number of stat calls
We are calling fstat() at least twice per storage volume in
a directory storage pool; this is rather wasteful.  Refactoring
this is also a step towards making code reusable for gluster,
where gluster can provide struct stat but cannot use fstat().

* src/storage/storage_backend.h
(virStorageBackendVolOpenCheckMode)
(virStorageBackendUpdateVolTargetInfoFD): Update signature.
* src/storage/storage_backend.c
(virStorageBackendVolOpenCheckMode): Pass stat results back.
(virStorageBackendUpdateVolTargetInfoFD): Use existing stats.
(virStorageBackendVolOpen, virStorageBackendUpdateVolTargetInfo):
Update callers.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget):
Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSIUpdateVolTargetInfo): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathUpdateVolTargetInfo): Likewise.

Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-06 17:17:08 -07:00
Ján Tomko
c6e87d1a4b storage: separate qemu-img command generation and execution
This allows us to create a test for the generated command line.
2013-02-24 18:11:40 +01:00
Daniel P. Berrange
04d9510f50 Rename command.{c,h} to vircommand.{c,h} 2012-12-21 11:17:13 +00:00
Ján Tomko
1c9a2fb1ae storage: allow metadata preallocation when creating qcow2 images
Add VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA flag to virStorageVolCreateXML
and virStorageVolCreateXMLFrom. This flag requests metadata
preallocation when creating/cloning qcow2 images, resulting in creating
a sparse file with qcow2 metadata. It has only slightly larger disk usage
compared to new image with no allocation, but offers higher performance.
2012-12-07 11:46:48 +01:00
Ján Tomko
b326765c80 storage: don't shadow global 'wait' declaration
Rename the 'wait' parameter to 'loop'.
This silences the warning:
storage/storage_backend.c:1348:34: error: declaration of 'wait' shadows
a global declaration [-Werror=shadow]
and fixes the build with -Werror.
--
Note: loop is pool backwards.
2012-10-23 13:56:59 +02:00
Cole Robinson
77eff5eeb2 storage: Don't do wait loops from VolLookupByPath
virStorageVolLookupByPath is an API call that virt-manager uses
quite a bit when dealing with storage. This call use BackendStablePath
which has several usleep() heuristics that can be tripped up
and hang virt-manager for a while.

Current example: an empty mpath pool pointing to /dev/mapper makes
_any_ calls to virStorageVolLookupByPath take 5 seconds.

The sleep heuristics are actually only needed in certain cases
when we are waiting for new storage to appear, so let's skip the
timeout steps when calling from LookupByPath.
2012-10-22 16:15:12 -04:00
Eric Blake
4ecb723b9e maint: fix up copyright notice inconsistencies
https://www.gnu.org/licenses/gpl-howto.html recommends that
the 'If not, see <url>.' phrase be a separate sentence.

* tests/securityselinuxhelper.c: Remove doubled line.
* tests/securityselinuxtest.c: Likewise.
* globally: s/;  If/.  If/
2012-09-20 16:30:55 -06:00
Eric Blake
51ee43aa55 build: fix PROBE() usage of intptr_t
Otherwise, in locations like virobject.c where PROBE is used,
for certain configure options, the compiler warns:

util/virobject.c:110:1: error: 'intptr_t' undeclared (first use in this function)

As long as we are making this header always available, we can
clean up several other files.

* src/internal.h (includes): Pull in <stdint.h>.
* src/conf/nwfilter_conf.h: Rely on internal.h.
* src/storage/storage_backend.c: Likewise.
* src/storage/storage_backend.h: Likewise.
* src/util/cgroup.c: Likewise.
* src/util/sexpr.h: Likewise.
* src/util/virhashcode.h: Likewise.
* src/util/virnetdevvportprofile.h: Likewise.
* src/util/virnetlink.h: Likewise.
* src/util/virrandom.h: Likewise.
* src/vbox/vbox_driver.c: Likewise.
* src/xenapi/xenapi_driver.c: Likewise.
* src/xenapi/xenapi_utils.c: Likewise.
* src/xenapi/xenapi_utils.h: Likewise.
* src/xenxs/xenxs_private.h: Likewise.
* tests/storagebackendsheepdogtest.c: Likewise.
2012-08-09 15:40:42 -06:00
Osier Yang
f9ce7dad60 Desert the FSF address in copyright
Per the FSF address could be changed from time to time, and GNU
recommends the following now: (http://www.gnu.org/licenses/gpl-howto.html)

  You should have received a copy of the GNU General Public License
  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.

This patch removes the explicit FSF address, and uses above instead
(of course, with inserting 'Lesser' before 'General').

Except a bunch of files for security driver, all others are changed
automatically, the copyright for securify files are not complete,
that's why to do it manually:

  src/security/security_selinux.h
  src/security/security_driver.h
  src/security/security_selinux.c
  src/security/security_apparmor.h
  src/security/security_apparmor.c
  src/security/security_driver.c
2012-07-23 10:50:50 +08:00
Daniel P. Berrange
d8a1c4c49f Replace use of virStorageReportError with virReportError
Update the storage driver to use virReportError instead of
the virStorageReportError custom macro

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-07-18 19:34:16 +01:00
Daniel P. Berrange
1e0bb184a7 Convert all files in src/conf/ to use virReportError()
This removes all the per-file error reporting macros
from the code in src/conf/

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-07-18 19:01:50 +01:00
Daniel P. Berrange
258e06c85b Remove all use of virRun in storage code
To make it easier to dynamically change the command line ARGV,
switch all storage code over to use virCommandPtr APIs for
running programs

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2012-07-12 11:02:09 +01:00
Zeeshan Ali (Khattak)
e545dd4ffe Implement virStorageVolResize() for FS backend
Currently only VIR_STORAGE_VOL_RESIZE_DELTA flag is supported.
2012-01-31 11:58:11 -05:00
Serge E. Hallyn
30f555c6a8 lvm storage backend: handle command_names=1 in lvm.conf
If the regexes supported (?:pvs)?, then we could handle this by
optionally matching but not returning the initial command name.  But it
doesn't.  So add a new char* argument to
virStorageBackendRunProgRegex().  If that argument is NULL then we act
as usual.  Otherwise, if the string at that argument is found at the
start of a returned line, we drop that before running the regex.

With this patch, virt-manager shows me lvs with command_names 1 or 0.

The definitions of PVS_BASE etc may want to be moved into the configure
scripts (though given how PVS is found, IIUC that could only happen if
pvs was a link to pvs_real), but in any case no sense dealing with that
until we're sure this is an ok way to handle it.

Signed-off-by: Serge Hallyn <serge.hallyn@canonical.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
2011-09-30 15:17:44 -06:00