1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-18 03:33:15 +03:00

Compare commits

...

207 Commits

Author SHA1 Message Date
Alasdair Kergon
e748a5d5f4 Tidy up for another release: updated documentation; removed old files;
module build fix.
2002-06-26 21:50:53 +00:00
Patrick Caulfield
99c5a3ae46 Flush on open as well as close. 2002-06-25 14:02:28 +00:00
Alasdair Kergon
51da710f5a o Long-awaited ioctl interface clean-up. *** Not backwardly compatible ***
o Various other kernel side tidy-ups.
o Version number changes so we have the option of adding new ioctl commands
  in future without affecting the use of existing ones should you later
  revert to an older kernel but not revert the userspace library/tools.
o Better separation of kernel/userspace elements in the build process to
  prepare for independent distribution of the kernel driver.
2002-06-19 13:07:05 +00:00
Joe Thornber
569d69b3d2 o Knock the version check out of the makefile, Alasdair will no doubt put it back :)
o  Change to new ioctl names.
2002-06-17 15:50:17 +00:00
Patrick Caulfield
059a6b1d90 Get rid of compile warnings on 64bit platforms. 2002-06-07 08:37:07 +00:00
Alasdair Kergon
990af7548a Increment version. 2002-05-31 19:33:30 +00:00
Alasdair Kergon
a38aefdfc8 Add vgsplit. 2002-05-31 19:30:51 +00:00
Alasdair Kergon
3bcb12e7d1 Tidy/fix segment rounding. 2002-05-31 19:29:43 +00:00
Alasdair Kergon
7904ecb462 Tidy 2002-05-31 19:28:37 +00:00
Alasdair Kergon
9ba4d45109 Remember to update VG free_count when reducing size of an LV. 2002-05-30 16:08:19 +00:00
Alasdair Kergon
56b8afe19d Fix vgcfgrestore segfault (wrong variable used). 2002-05-30 16:03:26 +00:00
Alasdair Kergon
f7aed9a94c update 2002-05-27 13:00:18 +00:00
AJ Lewis
e12a7e881d o fix changed function names 2002-05-23 14:13:21 +00:00
Alasdair Kergon
5afb65325d Fix LVM1 backwards compatibility issue when LV with a low LV number is deleted. 2002-05-23 11:37:51 +00:00
Joe Thornber
135f520f32 o Remove ext3 incompatibility bug
o	Mention 2.4.18 VM problem
2002-05-23 08:20:44 +00:00
Andres Salomon
bc251f4ff6 update for .08 2002-05-23 07:49:25 +00:00
Alasdair Kergon
b8769751f6 Rename; add some FIXMEs. 2002-05-22 14:03:45 +00:00
Alasdair Kergon
eff96d839e Revert to standard linux macros (for correct behaviour on rare architectures). 2002-05-21 12:37:07 +00:00
Alasdair Kergon
aa34c23807 Update version. 2002-05-21 12:14:05 +00:00
Andres Salomon
195acdac8c ack, missing include 2002-05-19 04:11:34 +00:00
Andres Salomon
903e03c56c update create_dir() comment 2002-05-19 03:52:38 +00:00
Andres Salomon
0892767b8a support recursive mkdir in create_dir() 2002-05-19 03:46:34 +00:00
Andres Salomon
83ebfa772c synch w/ -3 "oh shit" release 2002-05-14 03:56:40 +00:00
Joe Thornber
1583641322 Drop the default chunk size for snapshots down to 8k 2002-05-13 15:14:21 +00:00
Alasdair Kergon
9510e2c256 Rewrite missing/corrupt metadata in more cases. 2002-05-13 12:38:54 +00:00
AJ Lewis
a9dbabe07e o the _status fxns now take more arguments - this way i don't get the
preparsed status info, shove it all into a string, and then parse it
   again to get the info back out (which is what i was doing before)
 o basically that's it...i like this *much* better than the previous
   method and i think it makes the _status fxn more flexible if we need
   to use it to get other info out.
2002-05-10 16:06:06 +00:00
Alasdair Kergon
12884008fa Import snapshot status & persistence + indent etc. 2002-05-10 15:25:38 +00:00
AJ Lewis
02543bad1c o Actually read snapshot percentage from the kernel - what a pain! :)
o Not sure if the code in dev_manager is really optimal, but it works..
   will look at adjusting it a bit now.
 o I *think* it works right when one snapshot if full but others aren't,
   but I haven't really been able to test it because the full snapshot
   somehow resets itself and weird things start happening to the system...
2002-05-09 21:17:57 +00:00
Alasdair Kergon
a8c56a5251 Remove a no-op. 2002-05-09 12:03:55 +00:00
AJ Lewis
4e5a855f3f o header should only be printed once... 2002-05-08 17:58:52 +00:00
AJ Lewis
7e497a951e o Added function find_snapshots to snapshot_manip.c that returns a list
of snapshots whose origin is the lv passed in.
 o Used this new function to make lvdisplay properly display all snapshots
   attached to a origin.
2002-05-08 16:57:46 +00:00
Joe Thornber
cd08eabbfa i) Put back chunksize_ARG for lvcreate. 2002-05-08 14:36:10 +00:00
Alasdair Kergon
f7e62d9f81 Always call init_log() to initialise logging defaults. 2002-05-08 12:26:45 +00:00
Andres Salomon
9a3761e86e implement our own swabbing functions, instead of relying on the kernel's. 2002-05-07 15:28:59 +00:00
Alasdair Kergon
3619a68693 log/{prefix,command_names} use defaults.h & reset between shell cmds 2002-05-07 13:00:01 +00:00
Alasdair Kergon
efaf3c3bf9 Default values for some display output settings 2002-05-07 12:50:01 +00:00
Alasdair Kergon
0e4e6a6f67 Tweaks 2002-05-07 12:47:11 +00:00
Andres Salomon
42458e6278 updated. 2002-05-07 06:13:03 +00:00
Andres Salomon
41ec995377 Make lvm2 compile on big endian archs; use the kernel/glibc's endian
conversion stuff, instead of implementing our own.  Tested on a little
endian system (x86); I'll let the debian handle big endian testing.  :)
2002-05-07 05:54:14 +00:00
AJ Lewis
4f37599326 o Will now correctly remove expired achive files from the system when
archive_vg is called.
 o Added a #define to the top of the file - not sure if this is the
   appropriate place for it though
2002-05-03 19:28:07 +00:00
Patrick Caulfield
4144520e5c Add features to get table/status & wait for next event. 2002-05-03 11:55:58 +00:00
Andres Salomon
6c4800546c forgot to add Conflicts against lvm1 packages 2002-05-03 04:57:49 +00:00
Andres Salomon
733733c8a7 updated for 0.95.05-2. 2002-05-03 04:43:46 +00:00
Andres Salomon
2aa67cc946 ditto 2002-05-03 04:43:24 +00:00
Andres Salomon
9385981a9d dh_installinit makes a perfectly find postrm script.. 2002-05-03 04:13:02 +00:00
Alasdair Kergon
fff780035d Update. 2002-04-30 17:13:43 +00:00
Alasdair Kergon
46127e673d Some partial VG support with format_text. 2002-04-30 17:12:37 +00:00
Alasdair Kergon
70df59b224 get_vgs must check for text format VGs when no lvm1 format VGs present 2002-04-30 12:27:13 +00:00
AJ Lewis
0fdbaa803f o Updated *display output for LVM1 compatibility
o There is still a bit missing
   + all are missing the {PV,VG,LV} # - that is not applicable in LVM2
   + pvdisplay doesn't show how many LVs are contained on it
   + much of the snapshot information isn't available for lvdisplay
 o Look at the code for other potiential FIXMEs  :)
2002-04-29 21:43:14 +00:00
Heinz Mauelshagen
6af1830eff Changed DEFAULT_PV and DEFAULT_LV to 256 (has been fixed in LVM1 before) 2002-04-25 10:53:58 +00:00
Andres Salomon
6f860e2bd5 Updated for new release 2002-04-25 06:12:07 +00:00
Alasdair Kergon
20a492f7ee Update example config 2002-04-24 18:41:02 +00:00
Alasdair Kergon
63875e7591 Merge with text format branch.
Lots of changes/very little testing so far => there'll be bugs!

Use 'vgcreate -M text' to create a volume group with its metadata stored
in text files.  Text format metadata changes should be reasonably atomic,
with a (basic) automatic recovery mechanism if the system crashes while a
change is in progress.

Add a metadata section to lvm.conf to specify multiple directories if
you want (recommended) to keep multiple copies of the metadata (eg on
different filesystems).

e.g. metadata {
        dirs = ["/etc/lvm/metadata1","/usr/local/lvm/metadata2"]
}

Plenty of refinements still in the pipeline.
2002-04-24 18:20:51 +00:00
Patrick Caulfield
0ad98cabde add setlocale() call so that localisation of things like number entry
and display will work correctly.
2002-04-24 10:42:09 +00:00
Joe Thornber
668879d2e1 o Stop printing errors if flushing fails (could be an unconfigured device). 2002-04-24 08:37:34 +00:00
Alasdair Kergon
2e09783302 Prepare for another beta release. 2002-04-23 22:13:04 +00:00
Alasdair Kergon
49734114b3 Commit snapshot-related changes preparing for the next beta release. 2002-04-23 21:47:50 +00:00
Alasdair Kergon
950d9d6ee7 Missing seg->lv gives segfault when activating from text format. 2002-04-16 19:41:54 +00:00
Alasdair Kergon
f7974aee2e Allow deactivation of final snapshot. 2002-04-16 14:42:20 +00:00
Joe Thornber
c870a82621 o Added support for chunk_size to lvcreate. 2002-04-15 18:49:20 +00:00
Alasdair Kergon
984929a001 Missing VG lock when iterating through all LVs. 2002-04-15 16:27:39 +00:00
Patrick Caulfield
7f9e2c1db8 More memory leak plugging. 2002-04-15 13:24:14 +00:00
Joe Thornber
324e8389dc o Drop the default chunk size for snapshots down to 16k. 2002-04-15 08:41:00 +00:00
Alasdair Kergon
6f448c5a38 Implement a no_locking module that *does* attempt activation. 2002-04-11 14:10:32 +00:00
Patrick Caulfield
ec43efbb20 Rename device node during a DM_RENAME command. 2002-04-11 12:45:18 +00:00
Patrick Caulfield
3ed065de37 Return status from _lv_activate and friends.
Alasdair, I think this is right (and I need it) but you may like to check.
2002-04-11 09:14:04 +00:00
Patrick Caulfield
8152f0d72c Remove \n from log messages. 2002-04-10 15:49:47 +00:00
Joe Thornber
f8047f4736 o Perform a BLKFLSBUF ioctl whenever a block device is closed.
Patrick, can you see if this fixes your cluster syncing problem please ?
If so I'll make it so it only syncs if you have actually written to the
device.
2002-04-08 18:59:50 +00:00
Patrick Caulfield
b93c66dc2d Implement an external locking interface. 2002-04-08 16:04:50 +00:00
Patrick Caulfield
ac877b3065 Fix prototype. 2002-04-08 13:35:09 +00:00
Alasdair Kergon
dee8abfdde Fix lv_setup() not to generate a new lvid each time if asked to setup the
same LV more than once - subsequent times validate only.
2002-04-05 14:32:22 +00:00
Patrick Caulfield
cef3841d73 Make lock type numbers match the DLM numbers in use, and move UNLOCK out
of the way.
2002-04-04 13:31:21 +00:00
Alasdair Kergon
3cd5e8a041 Rename LCK_NONE to LCK_UNLOCK 2002-04-04 11:18:45 +00:00
Alasdair Kergon
515b5f866e Tidying. 2002-04-03 12:17:55 +00:00
Alasdair Kergon
321f62bf92 Cope with creation of additional snapshots while active.
(More work on suspension dependencies still needed.)
2002-03-27 18:17:43 +00:00
Alasdair Kergon
f94fa47b52 Snapshots are now attached to their origin device for locking purposes
so lock the origin instead of the snapshot itself when creating one.
2002-03-26 15:01:57 +00:00
Alasdair Kergon
c502f8a722 New-style persistent minor support. 2002-03-26 13:41:37 +00:00
Alasdair Kergon
59b4868ac3 o read-only device support
o name/uuid disambiguation
2002-03-25 18:54:59 +00:00
Alasdair Kergon
3634e12cce Fix typo. 2002-03-25 18:50:37 +00:00
Andres Salomon
6d45445391 all people to actually uninstall lvm2 (*grin*) 2002-03-23 08:23:15 +00:00
Alasdair Kergon
4f47e268cc Improve log messages. 2002-03-20 14:34:15 +00:00
Alasdair Kergon
0035b31cdb Better support for LVs with hyphens in names. 2002-03-19 16:41:44 +00:00
Alasdair Kergon
f2565aee03 Support device queries by uuid as well as by name. (Used by lvrename.) 2002-03-18 23:39:42 +00:00
Alasdair Kergon
5bd85668dd lvrename works on snapshots now 2002-03-18 23:25:50 +00:00
Alasdair Kergon
20f990b6ce Tie all snapshot (de)activation requests to (de)activation of origin device. 2002-03-18 13:09:27 +00:00
Alasdair Kergon
6821379586 s/Removing/Unloading/ in messages to reduce confusion 2002-03-15 23:01:59 +00:00
Alasdair Kergon
73b040eb49 Cut the number of device-mapper calls. 2002-03-15 22:59:12 +00:00
Alasdair Kergon
49aa4b2e1e New function to enable suppression of messages to stdout/stderr. 2002-03-15 22:54:04 +00:00
Alasdair Kergon
972241c74c Review locking: block signals instead of ignoring them and restore state
afterwards; avoid race condition with unlink; add LCK_HOLD to process_each_vg.
2002-03-15 16:07:38 +00:00
Alasdair Kergon
680750e3c2 Reduce the number of dm info calls. 2002-03-14 21:17:30 +00:00
Alasdair Kergon
5e7d4d9d15 distclean also to remove libdm-common.h 2002-03-14 16:56:02 +00:00
Alasdair Kergon
1e57e60613 Integrate suspend. 2002-03-14 15:36:07 +00:00
Alasdair Kergon
3ac7ce605a Suppress verbose/debug messages from libdevmapper. 2002-03-14 13:39:33 +00:00
Joe Thornber
b720dea9f0 o dev_manager_suspend, untested. 2002-03-14 10:56:09 +00:00
Alasdair Kergon
c80722aefe A missing free() found by Valgrind. ( http://developer.kde.org/~sewardj/ ) 2002-03-13 23:19:20 +00:00
Alasdair Kergon
a84fa69f28 dmsetup display uuid 2002-03-13 16:19:17 +00:00
Alasdair Kergon
e33781e59f Set LV uuid. 2002-03-13 15:11:29 +00:00
Joe Thornber
8824bc7ece o Mention that vgscan needs to be run after changing the filter var. 2002-03-13 14:25:53 +00:00
Patrick Caulfield
c2e3b0e448 Fix _align so it works on 64-bit machines. 2002-03-12 15:27:51 +00:00
Alasdair Kergon
f61a38e85a Let dmsetup store the uuid on device creation. 2002-03-11 22:44:36 +00:00
Alasdair Kergon
d23e948216 Move is_empty_dir to lvm-file 2002-03-11 22:23:24 +00:00
Joe Thornber
58bdaa31f0 o Actually check that the vg directory is empty rather than speculatively
rmdiring it.  Work around for devfs bug.
2002-03-11 20:43:58 +00:00
Joe Thornber
b6491d88a6 o This should complete the dev_manager alg. Please could people now
report any activation oddities they see.
2002-03-11 20:36:04 +00:00
Alasdair Kergon
f6061ba62e lv_info replaces lv_active etc. 2002-03-11 19:02:28 +00:00
Alasdair Kergon
427899ddce o activate/reactivate merge
o unlocking macro
2002-03-11 15:08:39 +00:00
Joe Thornber
c4ab7d2dbd o dm->active_list now filled in, ATM this is based on the layer name rather
than the uuid.
2002-03-11 11:27:48 +00:00
Joe Thornber
0fd2ba033f o Comment out some new code that was preventing pjc activating
snapshots.  This will go back in when the active_list is working.
2002-03-11 10:38:16 +00:00
Joe Thornber
ed38939a93 o knock out the offset for origin targets. 2002-03-08 10:45:01 +00:00
Joe Thornber
c7ee26ce5a o Add active_list to dev_manager
o  Origin layer is only added to snapshots if a snapshot is in the
   active_list.
2002-03-08 10:41:48 +00:00
Andres Salomon
909b8cb303 heh, whoops. s/device-mapper/LVM2/g. 2002-03-08 02:39:08 +00:00
Alasdair Kergon
b0277370cf o dm_destroy_all() called on exit - but doesn't touch suspended devices yet.
o 'dmsetup remove_all' calls dm_destroy_all() to provide a quick way to
  prepare for unloading the module
o Ran through indent again.
2002-03-07 20:56:10 +00:00
Joe Thornber
2ec8656bea o First cut at dev scanning.
o  Split up _expand_lv
2002-03-07 17:37:38 +00:00
Joe Thornber
b2ef256910 o Add comment describing what we're aiming for with dev_manager.
o  Remove dev_manager_reactivate, since it'll be the same as activate.

o  Merge the mark, visible and dirty fields into the same flags field.
2002-03-07 16:48:46 +00:00
Joe Thornber
63d6ce95db o Top level device is now just called <vg>-<lv> (there's no 'top'
layer appended).

o  Got rid of the unused layer->type field and enum.
2002-03-07 15:29:31 +00:00
Alasdair Kergon
a9532b189c Kernel functionality that returns device dependencies (ejt). 2002-03-06 19:42:23 +00:00
Joe Thornber
844545411f o Rename dmsetup dependencies -> dmsetup deps 2002-03-06 14:47:13 +00:00
Joe Thornber
4e23a2b9b8 o Add support for getting dependencies for a device.
o  dmsetup dependencies <dev>
2002-03-06 14:38:25 +00:00
Andres Salomon
5deba027eb convert from debian native package 2002-03-06 05:43:54 +00:00
Alasdair Kergon
fc8b7efc6f o Use new LCK_HOLD flag to indicate whether lock should be held on return
from lock_vol() - otherwise it now attempts to acquire the lock and then
  immediately releases it.
o Extend the id field in struct logical_volume to hold VG uuid + LV uuid
  for format1. This unique lvid can be used directly when calling lock_vol().
o Add the VG uuid to vgcache to make VG uuid lookups possible.  (Another
  step towards using them instead of VG names internally.)
2002-03-05 20:03:09 +00:00
Alasdair Kergon
a1c2d9c0f3 Fix activation for VG with more than one LV. 2002-03-04 18:50:34 +00:00
Alasdair Kergon
4ca49a0501 snapshot/zero logic 2002-03-04 15:25:52 +00:00
Joe Thornber
493c53d090 o Add a line to lvdisplay to say if the volume is a snapshot. 2002-03-04 15:12:30 +00:00
Joe Thornber
b27e956d35 o Bad dependency, meant the origin was always getting activated. 2002-03-04 15:10:30 +00:00
Alasdair Kergon
35ebed75c6 Remove unused fns. 2002-03-04 14:27:25 +00:00
Joe Thornber
7bfdb5f77f o I was tearing down device bottom-up instead of top down. Which
is why lvremove of snapshots wasn't working.
2002-03-04 14:26:43 +00:00
Joe Thornber
8d8c02317f o Break creating a snapshot down into:
i)   create cow
   ii)  activate cow
   iii) zero cow
   iv)  deactivate
   v)   add snapshot info
   vi)  reactivate
2002-03-04 13:46:37 +00:00
Andres Salomon
a34482feab proper /etc/lvm/lvm.conf now 2002-03-04 11:13:47 +00:00
Andres Salomon
cbdc8fd4a6 fix various issues 2002-03-04 11:12:57 +00:00
Alasdair Kergon
8d3afaa53c More use of LV locking. 2002-03-01 19:08:11 +00:00
Joe Thornber
7ced9ef3df o point snapshots at origin:real rather than origin:top, and *ping*
snapshots work.
2002-03-01 09:07:00 +00:00
Alasdair Kergon
e8a9ae7e80 Fix unlock parameter. 2002-02-27 14:48:42 +00:00
Alasdair Kergon
73a88ab3d3 o Lock mechanism for LV activation
o #defines for common lock flag combinations
o Try out hyphens instead of colons in device-mapper names - does this
  make messages containing filenames easier to read?
2002-02-27 12:26:41 +00:00
Alasdair Kergon
aaed82738a Running out of filehandles? Close /dev/device-mapper/control then. 2002-02-26 18:30:02 +00:00
Joe Thornber
de7f7b96db o Format1 wasn't recording the snapshot chunk size properly
o  Activation of snapshots now works - though the resulting device
   doesn't (pjc ?)

o  text format wasn't setting vg->cmd.
2002-02-26 16:48:52 +00:00
Alasdair Kergon
1a669b3e68 Clearer link pathname display. 2002-02-26 16:08:22 +00:00
Joe Thornber
333af9b13a o _build_name was allocating 1 byte too few, which meant the
terminating zero was falling off at some later point.

o Don't try and iterate from a deleted node in _prune_unmarked.
2002-02-26 14:44:13 +00:00
Joe Thornber
a5bca5e240 o Removed old files
o  rewrote activate.c to use dev-manager, I'm sure these two will merge
   at some point.

o  Rename is broken ATM

o  dev-manager puts the calls through to fs.c for layers that have the
   'visible' flag set.
2002-02-26 11:49:17 +00:00
Joe Thornber
c885633e02 o More dev_manager fns. 2002-02-25 16:53:12 +00:00
Heinz Mauelshagen
ca7e20b7ca pvresize command 2002-02-25 15:32:58 +00:00
Joe Thornber
545e11a3d7 o In go the populate functions. 2002-02-25 15:19:53 +00:00
Joe Thornber
44f5287664 o More dev_manager work. 2002-02-25 14:46:57 +00:00
Alasdair Kergon
cf510897f1 Begin conversion so LV id is passed to activation unit instead of
struct logical_volume.
2002-02-25 12:56:16 +00:00
Joe Thornber
1d171345f8 o Sync with cvs, dev_manager still needs to be wired into activate.c 2002-02-25 12:02:33 +00:00
Joe Thornber
4fa7e1cd49 o Remove the vg argument from find_cow 2002-02-25 11:55:39 +00:00
Joe Thornber
acd008298e o hash_iterate -> hash_iter 2002-02-25 11:54:15 +00:00
Joe Thornber
83a8021515 o Added a macro called hash_iterate, that is similar to list_iterate
o Renamed hash_iterate function, hash_iter.
2002-02-25 11:52:58 +00:00
Alasdair Kergon
cf88dfb1db indent 2002-02-24 22:31:55 +00:00
Heinz Mauelshagen
8937c4b481 lvmdiskscan 2002-02-22 13:17:46 +00:00
Patrick Caulfield
cc6af10a4d Fill in format_text functions.
Sort of seems to work.
2002-02-22 11:44:56 +00:00
Alasdair Kergon
6d94578955 o Convert lv->id back to lv_number when writing back to disk
o Use first unused lv_number when creating new LV
o Use lv_number for refs to snapshots
o Update persistent minor logic after the lvcreate restructure
o Reset all parameters before use in lvcreate.
2002-02-21 19:04:37 +00:00
Heinz Mauelshagen
08442ab71e Avoid ambigous volume_group argument in vg_add_snapshot() 2002-02-21 18:31:48 +00:00
Alasdair Kergon
10d91d213f Generate LV uuid from lv_number when reading in LVs. 2002-02-21 15:26:44 +00:00
Heinz Mauelshagen
b7a3b06994 Removed wrong 'lv->vg' argument from lv_is_cow() call. Is used in lv_is_cow internally. 2002-02-21 14:00:45 +00:00
Joe Thornber
5f12c37f23 o typo 2002-02-21 10:17:01 +00:00
Joe Thornber
585edebccd o add find_cow function. 2002-02-21 10:16:33 +00:00
Joe Thornber
9921c62234 o misc little fixes. 2002-02-21 10:15:54 +00:00
Andres Salomon
1ac76d2e16 ah, it was that "set -e" that was the culprit.. 2002-02-21 08:52:36 +00:00
Andres Salomon
6e983bf400 stop init script from returning w/ non-zero if not really an error 2002-02-21 08:30:14 +00:00
Alasdair Kergon
6a8fd4fa6e Try out using LV locking for reactivation. 2002-02-20 21:30:27 +00:00
Alasdair Kergon
3698eaa2d2 Remove lv_update_write_access: use lv_reactivate directly now instead. 2002-02-20 21:28:22 +00:00
Alasdair Kergon
8d97ca433c Suppress meaningless <backtrace> msg on screen (no prog/line number given) 2002-02-20 21:26:40 +00:00
Alasdair Kergon
23cc65e537 lvd->lv_access & LV_SNAPSHOT not lvd->lv_status 2002-02-20 21:24:45 +00:00
Alasdair Kergon
2f5a3c2bbe Remove VG arg from lv_is_cow() and lv_is_origin() - use lv->vg instead. 2002-02-20 19:04:55 +00:00
Alasdair Kergon
f6485616cd o Use 'pvcreate --setphysicalvolumesize' with no short form (instead of -s)
and add severe warning if it's used to make a device seem bigger than
  it really is.  This is not an option people should be using as it
  breaks metadata integrity.
o Use uint64_t throughout (rather than unsigned long long)
o Convert a few messages that contain pathnames into the more common form:
  pathname: message
2002-02-20 18:29:30 +00:00
Andres Salomon
6544fb43d9 initial lvm2 debian packages; still missing some manpages, but otherwise lintian passes
E: lvm2: binary-without-manpage e2fsadm
E: lvm2: binary-without-manpage lvmdiskscan
E: lvm2: binary-without-manpage lvmsadc
E: lvm2: binary-without-manpage lvmsar
E: lvm2: binary-without-manpage lvresize
E: lvm2: binary-without-manpage pvdata
E: lvm2: binary-without-manpage pvmove
E: lvm2: binary-without-manpage version
E: lvm2: binary-without-manpage vgcfgrestore
E: lvm2: binary-without-manpage vgexport
E: lvm2: binary-without-manpage vgimport
E: lvm2: binary-without-manpage vgmknodes
E: lvm2: binary-without-manpage vgsplit
2002-02-20 10:28:49 +00:00
Andres Salomon
a954b32dcc install all the manpages (another make-lintian-happy exercise) 2002-02-20 10:22:02 +00:00
Joe Thornber
426dc7836c o Removed the -z (suspend) option from the tools
o  New function: int lv_setup_cow_store(struct logical_volume *lv)
   This zeroes the start of the cow device.

o  Made lvcreate call above fn.
2002-02-18 15:52:48 +00:00
Joe Thornber
ff941ffc16 o small bug in the format1 export code for snapshots.
o  tidied newlines in the snapshot section of format text.
2002-02-18 11:25:43 +00:00
Joe Thornber
a063c201df o Add support for the -s and -c flags to lvcreate. 2002-02-18 10:59:51 +00:00
Heinz Mauelshagen
e2be3fa0aa Second path on "pvcreate -s" 2002-02-15 14:33:59 +00:00
Joe Thornber
609da6fb50 o split lvcreate into seperate functions for parsing the command line,
and creating the lv.  A lot of changes in here so be on the lookout
   for bugs.
2002-02-15 11:53:22 +00:00
Heinz Mauelshagen
fc9f3ccec3 Forgot to remove test printf :-) 2002-02-15 09:37:23 +00:00
Heinz Mauelshagen
f7baa67a0a First cut on "pvcreate -s" 2002-02-15 01:26:16 +00:00
Joe Thornber
e8d78c2cdb o Initialise the snapshot list properly in vgcreate. 2002-02-14 15:06:24 +00:00
Joe Thornber
9d33366092 o Define _read_uint32 2002-02-14 14:52:21 +00:00
Heinz Mauelshagen
f5d61515c2 test printf removed 2002-02-13 21:30:51 +00:00
Heinz Mauelshagen
711a04a972 LV maximum size limit of 2TB ensured in _lv_setup() 2002-02-13 21:28:56 +00:00
Heinz Mauelshagen
e5b470a3f1 spaces 2002-02-13 21:28:15 +00:00
Heinz Mauelshagen
31820e1e22 > 2TB numbers in vgdisplay_full 2002-02-13 20:21:13 +00:00
Joe Thornber
4849e8cd6d o snapshot support for the text format.
The logical_volumes, and snapshots sections of the text format are now
optional.
2002-02-13 13:29:16 +00:00
Joe Thornber
77e3b460aa o First pass at format1 snapshot support. 2002-02-13 11:43:29 +00:00
Joe Thornber
b5321001f8 o First changes to add snapshot support.
I'm taking a different route from LVM1 here in that snapshots are a
seperate entity from the logical volumes, I think of them as an
application of an LV (or two lvs rather).  As such there is a list of
snapshots held against the vg, and there is *not* a SNAPSHOT, or
SHAPSHOT_ORG flag in lv->status.
2002-02-12 16:31:31 +00:00
Patrick Caulfield
38eba9f5ea use portable <inttypes.h> macros for printing. 2002-02-12 14:12:13 +00:00
Joe Thornber
ea6f399454 o Turn the device_create_* functions into device_populate_*, they only
fill in an already created dm_task.  This allows common code, such
  as minor number selection, and read_only to be lifted.
2002-02-12 11:15:45 +00:00
Alasdair Kergon
f8bf2d7b7d Run through indent - no (intentional) changes to any code. 2002-02-11 21:00:35 +00:00
Alasdair Kergon
c4856caebb Preparation for an LVM2 liblvm - pass cmd_context into each tool and
link some globals that the tools need into that structure.
2002-02-11 20:50:53 +00:00
Alasdair Kergon
fc1030bb22 Now that most of the usage of 'stack' only occurs when there's an error,
don't suppress it from the screen output any longer.
2002-02-11 18:25:18 +00:00
Alasdair Kergon
9eb6cad8dc dbg_free(tc->desc) 2002-02-11 18:21:54 +00:00
Alasdair Kergon
0fa2a78dce Document return codes. 2002-02-11 17:42:02 +00:00
Joe Thornber
a56fa1558b o Split activate.c into a high level (remaining in activate.c) and low level (ll-activate.[hc]) API.
o  Creation of a device from an lv now lives in activate-lv.c
2002-02-11 15:48:34 +00:00
Alasdair Kergon
261c73a997 o Support locking with local lock files
o Disable control-c during updates (except if blocked waiting for a lock)
2002-02-11 15:42:34 +00:00
Joe Thornber
929c1333ca o Little recipe for testing LVM2 with loopback devices. 2002-02-11 12:01:59 +00:00
Joe Thornber
286a79d94d o Added functions to display what's in the archive.
o  For now vgcfgrestore -l <vg> displays this list.

A bit hacky, but it'll get better.
2002-02-11 11:43:17 +00:00
Alasdair Kergon
8b951f99da Locking prototypes. 2002-02-08 14:30:37 +00:00
Alasdair Kergon
abb449bca0 move defaults.h 2002-02-08 14:28:52 +00:00
Alasdair Kergon
bd084028d1 Move defaults.h 2002-02-08 14:28:14 +00:00
Joe Thornber
138a27570b o I decided that the archive_format shouldn't really be a format at
all since it only supports vg_write.  It has been replaced with:

int archive_vg(struct volume_group *vg,
	       const char *dir,
	       const char *desc,
	       uint32_t retain_days,
	       uint32_t min_archive);

which is now called directly by tools/archive.c
2002-02-08 11:58:18 +00:00
Joe Thornber
c2ed40a74f o Add cmd_line field to struct cmd_context
o  Text format now has a description and time field at the top level.

o  archiving and backup set the description appropriately. eg,

   for an archive:

     description = "Created *before* executing 'lvextend test_vg/lvol0 -l +1'."
     creation_time = 1013166332

   for a backup:

     description = "Created *after* executing 'lvextend test_vg/lvol0 -l +1'."
     creation_time = 1013166332

This is preparing the way for a simple vgcfgundo command.
2002-02-08 11:13:47 +00:00
Heinz Mauelshagen
a7e7a00cab Poor mans lvmdiskscan 2002-02-05 14:31:57 +00:00
Alasdair Kergon
64a31ab3cd Another release (includes some fixes from last week; persistent minors,
partial activation etc.)
2002-02-04 13:30:21 +00:00
Alasdair Kergon
71958bc0f1 lv->minor >= 0 (ejt) 2002-02-04 13:08:31 +00:00
Alasdair Kergon
366ec35612 Basic support for persistent minor numbers;
slightly different from the current LVM1 method.

  lvcreate --persistent y  --minor 10   (to specify when created)
  lvchange --persistent n  (to turn off)
  lvchange --persistent y  --minor 11   (to change)

--persistent uses a new LV status flag stored on disk
minor number is stored on disk the same way as LVM1 does
(but major number stored is 0; any LVM1 major/minor setting gets lost)

  lvchange -ay --minor 12 (to activate using minor 12, regardless of the
                           on-disk setting, which doesn't get changed)

--minor == -m
--persistent == -M
2002-02-01 17:54:39 +00:00
Alasdair Kergon
3738f6e8ae Failure signalled by -1 not 0; MAX_DEVICES 256 (was 64); change a '>' to '>='. 2002-02-01 17:39:20 +00:00
Alasdair Kergon
051a8e2af1 Display error when running unimplemented functions. 2002-01-31 20:37:26 +00:00
Alasdair Kergon
2f43f28d5e Remove gcc -D to support as different gcc versions handle it differently. 2002-01-31 20:15:26 +00:00
Alasdair Kergon
b64769754b "exit" means "quit" (lamer) 2002-01-31 20:08:52 +00:00
Joe Thornber
a97daa18d1 o Remove redundant dbg_free. 2002-01-31 15:28:30 +00:00
144 changed files with 9499 additions and 3856 deletions

3
BUGS
View File

@@ -1 +1,2 @@
LVM2's device-mapper driver and ext3 are incompatible at the moment.
Snapshots under 2.4.18 can deadlock due to a bug in the VM system.
2.4.19-pre8 is fine.

7
TODO
View File

@@ -4,24 +4,23 @@ before 2.0
vgexport
vgimport
snapshots
pvmove
device-mapper support for 2.5 kernel series
review FIXMEs
extra validation & full consistency checks in format1 with LVM1
partial activation
partial activation (aka VG quorum)
error message review
locking during metadata changes
format2 with atomic transactions
bidirectional format1/format2 migration tool
persistent minors
stats
pvmove
statistics target and tool support
review tool exit codes for LVM1 compatibility
before 2.1
----------
e2fsadm
lvmdiskscan
lvmsadc
lvmsar
pvdata

View File

@@ -1 +1 @@
0.95.03-cvs (2002-01-30)
1.95.10-cvs (2002-05-31)

50
debian/changelog vendored Normal file
View File

@@ -0,0 +1,50 @@
lvm2 (1.95.08-1) unstable; urgency=low
* New upstream release (Beta3).
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 23 May 2002 03:46:37 -0500
lvm2 (0.95.05-3) unstable; urgency=low
* Get rid of awk dependency in init script. (Closes: #146257)
-- Andres Salomon <dilinger@mp3revolution.net> Sun, 12 May 2002 04:39:06 -0500
lvm2 (0.95.05-2) unstable; urgency=low
* Use ${shlibs:Depends} in Depends.
* Get rid of postinst/postrm scripts, use debhelper's init script instead.
* Add Conflicts against lvm10, lvm-common.
* Fix endian issues on big-endian machines.
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 2 May 2002 23:53:53 -0500
lvm2 (0.95.05-1) unstable; urgency=low
* New release (Beta2).
-- Andres Salomon <dilinger@mp3revolution.net> Thu, 25 Apr 2002 00:37:41 -0500
lvm2 (0.95.04cvs20020306-1) unstable; urgency=low
* CVS updated.
* Convert from debian native package.
-- Andres Salomon <dilinger@mp3revolution.net> Wed, 6 Mar 2002 00:43:21 -0500
lvm2 (0.95.04cvs20020304) unstable; urgency=low
* CVS updated.
* Enhance init script; create devmapper control device, etc.
* Add dmsetup as a suggestion.
* Add /etc/lvm/lvm.conf conffile.
* Add undocumented(7) for the commands missing manpages.
-- Andres Salomon <dilinger@mp3revolution.net> Mon, 4 Mar 2002 04:51:26 -0500
lvm2 (0.95.02cvs20020220) unstable; urgency=low
* Initial Release.
-- Andres Salomon <dilinger@mp3revolution.net> Wed, 20 Feb 2002 03:17:25 -0500

2
debian/conffiles vendored Normal file
View File

@@ -0,0 +1,2 @@
/etc/lvm/lvm.conf
/etc/init.d/lvm2

20
debian/control vendored Normal file
View File

@@ -0,0 +1,20 @@
Source: lvm2
Section: admin
Priority: optional
Maintainer: Andres Salomon <dilinger@mp3revolution.net>
Build-Depends: debhelper (>> 3.0.0), libdevmapper-dev, libreadline4-dev
Standards-Version: 3.5.2
Package: lvm2
Architecture: any
Depends: ${shlibs:Depends}
Conflicts: lvm10, lvm-common
Replaces: lvm10, lvm-common
Provides: lvm-binaries
Suggests: dmsetup
Description: The Linux Logical Volume Manager
This is LVM2, the rewrite of The Linux Logical Volume Manager. LVM
supports enterprise level volume management of disk and disk subsystems
by grouping arbitrary disks into volume groups. The total capacity of
volume groups can be allocated to logical volumes, which are accessed as
regular block devices.

25
debian/copyright vendored Normal file
View File

@@ -0,0 +1,25 @@
This package was debianized by Andres Salomon <dilinger@mp3revolution.net> on
Wed, 20 Feb 2002 03:17:25 -0500.
It was downloaded from http://www.sistina.com/products_lvm.htm
Upstream Author(s): LVM Development Team
Copyright (c) 2001-2002 LVM Development Team
LVM2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
LVM2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
On Debian systems, the full text of the GPL can be found in
/usr/share/common-licenses/GPL

4
debian/dirs vendored Normal file
View File

@@ -0,0 +1,4 @@
etc/lvm
usr/share/man/man5
usr/share/man/man8
sbin

6
debian/docs vendored Normal file
View File

@@ -0,0 +1,6 @@
BUGS
INTRO
README
TODO
VERSION
doc/*

58
debian/init.d vendored Normal file
View File

@@ -0,0 +1,58 @@
#! /bin/sh
#
# lvm2 This script handles LVM2 initialization/shutdown.
#
# Written by Andres Salomon <dilinger@mp3revolution.net>.
#
PATH=/sbin:/bin:/usr/sbin:/usr/bin
NAME=lvm2
DESC=LVM
test -x /sbin/vgchange || exit 0
modprobe dm-mod >/dev/null 2>&1
# Create necessary files in /dev for device-mapper
create_devfiles() {
DIR="/dev/device-mapper"
FILE="$DIR/control"
major=$(grep "[0-9] misc$" /proc/devices | sed 's/[ ]\+misc//')
minor=$(grep "[0-9] device-mapper$" /proc/misc | sed 's/[ ]\+device-mapper//')
if test ! -d $DIR; then
mkdir --mode=755 $DIR >/dev/null 2>&1
fi
if test ! -c $FILE -a ! -z "$minor"; then
mknod --mode=600 $FILE c $major $minor >/dev/null 2>&1
fi
}
case "$1" in
start)
echo -n "Initializing $DESC: "
create_devfiles
vgchange -a y
echo "$NAME."
;;
stop)
echo -n "Shutting down $DESC: "
# We don't really try all that hard to shut it down; far too many
# things that can keep it from successfully shutting down.
vgchange -a n
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
vgchange -a n
sleep 1
vgchange -a y
echo "$NAME."
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

26
debian/manpages vendored Normal file
View File

@@ -0,0 +1,26 @@
debian/lvm2/usr/share/man/man5/lvm.conf.5
debian/lvm2/usr/share/man/man8/lvchange.8
debian/lvm2/usr/share/man/man8/lvcreate.8
debian/lvm2/usr/share/man/man8/lvdisplay.8
debian/lvm2/usr/share/man/man8/lvextend.8
debian/lvm2/usr/share/man/man8/lvm.8
debian/lvm2/usr/share/man/man8/lvmchange.8
debian/lvm2/usr/share/man/man8/lvreduce.8
debian/lvm2/usr/share/man/man8/lvremove.8
debian/lvm2/usr/share/man/man8/lvrename.8
debian/lvm2/usr/share/man/man8/lvscan.8
debian/lvm2/usr/share/man/man8/pvchange.8
debian/lvm2/usr/share/man/man8/pvcreate.8
debian/lvm2/usr/share/man/man8/pvdisplay.8
debian/lvm2/usr/share/man/man8/pvscan.8
debian/lvm2/usr/share/man/man8/vgcfgbackup.8
debian/lvm2/usr/share/man/man8/vgchange.8
debian/lvm2/usr/share/man/man8/vgck.8
debian/lvm2/usr/share/man/man8/vgcreate.8
debian/lvm2/usr/share/man/man8/vgdisplay.8
debian/lvm2/usr/share/man/man8/vgextend.8
debian/lvm2/usr/share/man/man8/vgmerge.8
debian/lvm2/usr/share/man/man8/vgreduce.8
debian/lvm2/usr/share/man/man8/vgremove.8
debian/lvm2/usr/share/man/man8/vgrename.8
debian/lvm2/usr/share/man/man8/vgscan.8

120
debian/rules vendored Executable file
View File

@@ -0,0 +1,120 @@
#!/usr/bin/make -f
# Sample debian/rules that uses debhelper.
# GNU copyright 1997 by Joey Hess.
#
# This version is for a hypothetical package that builds an
# architecture-dependant package, as well as an architecture-independent
# package.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# This is the debhelper compatibility version to use.
export DH_COMPAT=3
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
CFLAGS += -g
endif
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
INSTALL_PROGRAM += -s
endif
configure: configure-stamp
configure-stamp:
dh_testdir
# Add here commands to configure the package.
./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/ --mandir=\$${prefix}/usr/share/man --infodir=\$${prefix}/usr/share/info
touch configure-stamp
build-arch: configure-stamp build-arch-stamp
build-arch-stamp:
dh_testdir
# Add here command to compile/build the package.
$(MAKE)
touch build-arch-stamp
build-indep: configure-stamp build-indep-stamp
build-indep-stamp:
dh_testdir
# Add here command to compile/build the arch indep package.
# It's ok not to do anything here, if you don't need to build
# anything for this package.
#/usr/bin/docbook-to-man debian/lvm2.sgml > lvm2.1
touch build-indep-stamp
build: build-arch build-indep
clean:
dh_testdir
dh_testroot
rm -f build-stamp configure-stamp
# Add here commands to clean up after the build process.
-$(MAKE) distclean
-test -r /usr/share/misc/config.sub && \
cp -f /usr/share/misc/config.sub config.sub
-test -r /usr/share/misc/config.guess && \
cp -f /usr/share/misc/config.guess config.guess
dh_clean
install: DH_OPTIONS=
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Add here commands to install the package into debian/lvm2.
$(MAKE) install prefix=$(CURDIR)/debian/lvm2
install -m 0644 doc/example.conf debian/lvm2/etc/lvm/lvm.conf
# Build architecture-independent files here.
# Pass -i to all debhelper commands in this target to reduce clutter.
binary-indep: build install
# nada.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
# dh_installdebconf
dh_installdocs
dh_installexamples
# dh_installlogrotate -a
# dh_installemacsen -a
# dh_installpam -a
# dh_installmime -a
dh_installinit --update-rcd-params="start 25 S . start 50 0 6 ."
dh_installcron
dh_installman
dh_installinfo
dh_undocumented
dh_installchangelogs
dh_strip
dh_link
dh_compress
dh_fixperms
dh_makeshlibs
dh_installdeb
# dh_perl -a
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install configure

14
debian/undocumented vendored Normal file
View File

@@ -0,0 +1,14 @@
e2fsadm.8
lvmdiskscan.8
lvmsadc.8
lvmsar.8
lvresize.8
pvdata.8
pvmove.8
pvresize.8
version.8
vgcfgrestore.8
vgexport.8
vgimport.8
vgmknodes.8
vgsplit.8

View File

@@ -24,6 +24,8 @@ devices {
# prefixed with either an 'a' (for accept) or 'r' (for reject).
# ATM you cannot use anchors (^ or $) in your regular expression.
# Remember to run vgscan after you change this parameter.
# By default we accept every block device:
filter = "a/.*/"
@@ -120,6 +122,12 @@ shell {
history_size = 100
}
# Metadata settings
metadata {
# List of directories holding copies of text format metadata
dirs = [ "/etc/lvm/metadata" ]
}
# Miscellaneous global settings
global {
@@ -134,4 +142,11 @@ global {
# will be made. Equivalent to having the -t option on every
# command. Defaults to off.
test = 0
# Default metadata format commands use - "lvm1" (default) or "text"
format = "lvm1"
# Location of proc filesystem
proc = "/proc"
}

46
doc/testing.txt Normal file
View File

@@ -0,0 +1,46 @@
Here's how I test new LVM2 builds without interfering with the stable
LVM2 that is running the LV's on my development box.
1) Create a set of loopback devices.
2) Create a new directory to contain the LVM2 configuration files for
this setup. (I use /etc/lvm_loops)
3) Write a suitable lvm.conf file, this goes in the directory you just
created. eg, my /etc/lvm_loops/lvm.conf looks like:
log {
file="/tmp/lvm2_loop.log"
level=9
verbose=0
overwrite=1
}
devices {
scan = "/dev"
filter = ["a/loop/", "r/.*/"]
}
The important this to note is the devices section which makes sure that
only the loopback devices are considered for LVM2 operations.
4) When you want to use this test setup just set the environment
variable LVM_SYSTEM_DIR to point to your config directory
(/etc/lvm_loops in my case).
5) It's a good idea to do a vgscan to initialise the filters:
export LVM_SYSTEM_DIR=/etc/lvm_loops
./lvm vgscan
where ./lvm is the new build of LVM2 that I'm trying out.
7) Test away. Make sure that you are explicit about which lvm
executable you want to execute (eg, ./lvm if you are in
LVM2/tools).

View File

@@ -1,5 +1,8 @@
../lib/activate/activate.h
../lib/commands/errors.h
../lib/commands/toolcontext.h
../lib/config/config.h
../lib/config/defaults.h
../lib/datastruct/bitset.h
../lib/datastruct/btree.h
../lib/datastruct/hash.h
@@ -17,6 +20,7 @@
../lib/format_text/format-text.h
../lib/label/label.h
../lib/label/uuid-map.h
../lib/locking/locking.h
../lib/log/log.h
../lib/metadata/metadata.h
../lib/mm/dbg_malloc.h

View File

@@ -10,8 +10,8 @@ VPATH = @srcdir@
SOURCES=\
activate/activate.c \
activate/dev_manager.c \
activate/fs.c \
activate/names.c \
config/config.c \
datastruct/bitset.c \
datastruct/btree.c \
@@ -38,11 +38,16 @@ SOURCES=\
format_text/import.c \
label/label.c \
label/uuid-map.c \
locking/external_locking.c \
locking/file_locking.c \
locking/locking.c \
locking/no_locking.c \
log/log.c \
metadata/lv_manip.c \
metadata/merge.c \
metadata/metadata.c \
metadata/pv_map.c \
metadata/snapshot_manip.c \
misc/lvm-file.c \
mm/dbg_malloc.c \
mm/pool.c \

View File

@@ -10,10 +10,18 @@
#include "log.h"
#include "fs.h"
#include "lvm-string.h"
#include "names.h"
#include "pool.h"
#include "toolcontext.h"
#include "dev_manager.h"
/* FIXME Temporary */
#include "vgcache.h"
#include <limits.h>
#include <linux/kdev_t.h>
#include <fcntl.h>
#define _skip(fmt, args...) log_very_verbose("Skipping: " fmt , ## args)
int library_version(char *version, size_t size)
{
@@ -22,33 +30,6 @@ int library_version(char *version, size_t size)
return 1;
}
static struct dm_task *_setup_task_with_name(struct logical_volume *lv,
const char *lv_name,
int task)
{
char name[128];
struct dm_task *dmt;
if (!(dmt = dm_task_create(task))) {
stack;
return NULL;
}
if (!build_dm_name(name, sizeof(name), lv->vg->name, lv_name)) {
stack;
return NULL;
}
dm_task_set_name(dmt, name);
return dmt;
}
static struct dm_task *_setup_task(struct logical_volume *lv, int task)
{
return _setup_task_with_name(lv, lv->name, task);
}
int driver_version(char *version, size_t size)
{
int r = 0;
@@ -74,355 +55,127 @@ int driver_version(char *version, size_t size)
return r;
}
/*
* Returns 1 if info structure populated, else 0 on failure.
*/
int lv_info(struct logical_volume *lv, struct dm_info *info)
{
int r = 0;
struct dm_task *dmt;
int r;
struct dev_manager *dm;
log_very_verbose("Getting device info for %s", lv->name);
if (!(dmt = _setup_task(lv, DM_DEVICE_INFO))) {
if (!(dm = dev_manager_create(lv->vg->name))) {
stack;
return 0;
}
if (!dm_task_run(dmt)) {
if (!(r = dev_manager_info(dm, lv, info)))
stack;
goto out;
}
if (!dm_task_get_info(dmt, info)) {
stack;
goto out;
}
r = 1;
out:
dm_task_destroy(dmt);
dev_manager_destroy(dm);
return r;
}
int lv_rename(const char *old_name, struct logical_volume *lv)
{
int r = 0;
char new_name[PATH_MAX];
struct dm_task *dmt;
if (test_mode())
return 0;
if (!(dmt = _setup_task_with_name(lv, old_name, DM_DEVICE_RENAME))) {
stack;
return 0;
}
if (!build_dm_name(new_name, sizeof(new_name),
lv->vg->name, lv->name)) {
stack;
return 0;
}
if (!dm_task_set_newname(dmt, new_name)) {
stack;
r = 0;
goto end;
}
if (!dm_task_run(dmt)) {
stack;
r = 0;
goto end;
}
fs_rename_lv(old_name, lv);
end:
dm_task_destroy(dmt);
return r;
}
int lv_active(struct logical_volume *lv)
{
int r = -1;
struct dm_info info;
if (!lv_info(lv, &info)) {
stack;
return r;
}
log_very_verbose("%s is%s active", lv->name, info.exists ? "":" not");
return info.exists;
}
int lv_suspended(struct logical_volume *lv)
{
int r = -1;
struct dm_info info;
if (!lv_info(lv, &info)) {
stack;
return r;
}
log_very_verbose("%s is%s suspended", lv->name,
info.suspended ? "":" not");
return info.suspended;
}
int lv_open_count(struct logical_volume *lv)
{
int r = -1;
struct dm_info info;
if (!lv_info(lv, &info)) {
stack;
return r;
}
log_very_verbose("%s is open %d time(s)", lv->name, info.open_count);
return info.open_count;
}
/*
* Emit a target for a given segment.
* Returns 1 if percent set, else 0 on failure.
*/
static int _emit_target(struct dm_task *dmt, struct stripe_segment *seg)
{
char params[1024];
uint64_t esize = seg->lv->vg->extent_size;
uint32_t s, stripes = seg->stripes;
int w = 0, tw = 0, error = 0;
const char *no_space =
"Insufficient space to write target parameters.";
char *filler = "/dev/ioerror";
char *target;
if (stripes == 1) {
if (!seg->area[0].pv) {
target = "error";
error = 1;
}
else
target = "linear";
}
if (stripes > 1) {
target = "striped";
tw = lvm_snprintf(params, sizeof(params), "%u %u ",
stripes, seg->stripe_size);
if (tw < 0) {
log_err(no_space);
return 0;
}
w = tw;
}
if (!error) {
for (s = 0; s < stripes; s++, w += tw) {
if (!seg->area[s].pv)
tw = lvm_snprintf(
params + w, sizeof(params) - w,
"%s 0%s", filler,
s == (stripes - 1) ? "" : " ");
else
tw = lvm_snprintf(
params + w, sizeof(params) - w,
"%s %" PRIu64 "%s",
dev_name(seg->area[s].pv->dev),
(seg->area[s].pv->pe_start +
(esize * seg->area[s].pe)),
s == (stripes - 1) ? "" : " ");
if (tw < 0) {
log_err(no_space);
return 0;
}
}
}
log_very_verbose("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
esize * seg->le, esize * seg->len,
target, params);
if (!dm_task_add_target(dmt, esize * seg->le, esize * seg->len,
target, params)) {
stack;
return 0;
}
return 1;
}
int _load(struct logical_volume *lv, int task)
{
int r = 0;
struct dm_task *dmt;
struct list *segh;
struct stripe_segment *seg;
log_very_verbose("Generating devmapper parameters for %s", lv->name);
if (!(dmt = _setup_task(lv, task))) {
stack;
return 0;
}
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
if (!_emit_target(dmt, seg)) {
log_error("Unable to activate logical volume '%s'",
lv->name);
goto out;
}
}
if (!((lv->status & LVM_WRITE) && (lv->vg->status & LVM_WRITE))) {
if (!dm_task_set_ro(dmt))
log_error("Failed to set %s read-only during "
"activation.", lv->name);
else
log_very_verbose("Activating %s read-only", lv->name);
}
if (!(r = dm_task_run(dmt)))
stack;
log_verbose("Logical volume %s%s activated", lv->name,
r == 1 ? "" : " not");
out:
dm_task_destroy(dmt);
return r;
}
/* FIXME: Always display error msg */
int lv_activate(struct logical_volume *lv)
{
if (test_mode())
return 0;
log_very_verbose("Activating %s", lv->name);
return _load(lv, DM_DEVICE_CREATE) && fs_add_lv(lv);
}
int _suspend(struct logical_volume *lv, int sus)
int lv_snapshot_percent(struct logical_volume *lv, float *percent)
{
int r;
struct dm_task *dmt;
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
struct dev_manager *dm;
log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", lv->name);
if (!(dmt = _setup_task(lv, task))) {
if (!(dm = dev_manager_create(lv->vg->name))) {
stack;
return 0;
}
if (!(r = dm_task_run(dmt)))
log_err("Couldn't %s device '%s'", sus ? "suspend" : "resume",
lv->name);
if (!(r = dev_manager_snapshot_percent(dm, lv, percent)))
stack;
dev_manager_destroy(dm);
dm_task_destroy(dmt);
return r;
}
int lv_suspend(struct logical_volume *lv)
static int _lv_active(struct logical_volume *lv)
{
return _suspend(lv, 1);
struct dm_info info;
if (!lv_info(lv, &info)) {
stack;
return -1;
}
return info.exists;
}
int lv_reactivate(struct logical_volume *lv)
static int _lv_open_count(struct logical_volume *lv)
{
struct dm_info info;
if (!lv_info(lv, &info)) {
stack;
return -1;
}
return info.open_count;
}
/* FIXME Need to detect and handle an lv rename */
static int _lv_activate(struct logical_volume *lv)
{
int r;
struct dev_manager *dm;
if (test_mode())
return 0;
if (!lv_suspended(lv) && !_suspend(lv, 1)) {
if (!(dm = dev_manager_create(lv->vg->name))) {
stack;
return 0;
}
r = _load(lv, DM_DEVICE_RELOAD);
if (!_suspend(lv, 0)) {
if (!(r = dev_manager_activate(dm, lv)))
stack;
return 0;
}
dev_manager_destroy(dm);
return r;
}
int lv_deactivate(struct logical_volume *lv)
static int _lv_deactivate(struct logical_volume *lv)
{
int r;
struct dm_task *dmt;
struct dev_manager *dm;
log_very_verbose("Deactivating %s", lv->name);
if (test_mode())
return 0;
if (!(dmt = _setup_task(lv, DM_DEVICE_REMOVE))) {
if (!(dm = dev_manager_create(lv->vg->name))) {
stack;
return 0;
}
if (!(r = dm_task_run(dmt)))
if (!(r = dev_manager_deactivate(dm, lv)))
stack;
dm_task_destroy(dmt);
fs_del_lv(lv);
dev_manager_destroy(dm);
return r;
}
int activate_lvs_in_vg(struct volume_group *vg)
static int _lv_suspend(struct logical_volume *lv)
{
struct list *lvh;
struct logical_volume *lv;
int count = 0;
int r;
struct dev_manager *dm;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (!lv_active(lv) && lv_activate(lv));
if (!(dm = dev_manager_create(lv->vg->name))) {
stack;
return 0;
}
return count;
}
int lv_update_write_access(struct logical_volume *lv)
{
struct dm_info info;
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (!info.exists || info.suspended)
/* Noop */
return 1;
return lv_reactivate(lv);
}
int deactivate_lvs_in_vg(struct volume_group *vg)
{
struct list *lvh;
struct logical_volume *lv;
int count = 0;
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += ((lv_active(lv) == 1) && lv_deactivate(lv));
}
return count;
if (!(r = dev_manager_suspend(dm, lv)))
stack;
dev_manager_destroy(dm);
return r;
}
/*
* These two functions return the number of LVs in the state,
* or -1 on error.
*/
int lvs_in_vg_activated(struct volume_group *vg)
{
struct list *lvh;
@@ -431,7 +184,7 @@ int lvs_in_vg_activated(struct volume_group *vg)
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (lv_active(lv) == 1);
count += (_lv_active(lv) == 1);
}
return count;
@@ -445,8 +198,134 @@ int lvs_in_vg_opened(struct volume_group *vg)
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
count += (lv_open_count(lv) == 1);
count += (_lv_open_count(lv) == 1);
}
return count;
}
static struct logical_volume *_lv_from_lvid(struct cmd_context *cmd,
const char *lvid_s)
{
struct lv_list *lvl;
struct volume_group *vg;
union lvid *lvid;
lvid = (union lvid *) lvid_s;
log_very_verbose("Finding volume group for uuid %s", lvid_s);
if (!(vg = vg_read_by_vgid(cmd, lvid->id[0].uuid))) {
log_error("Volume group for uuid not found: %s", lvid_s);
return NULL;
}
log_verbose("Found volume group \"%s\"", vg->name);
if (vg->status & EXPORTED_VG) {
log_error("Volume group \"%s\" is exported", vg->name);
return NULL;
}
if (!(lvl = find_lv_in_vg_by_lvid(vg, lvid))) {
log_very_verbose("Can't find logical volume id %s", lvid_s);
return NULL;
}
return lvl->lv;
}
/* These return success if the device is not active */
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Suspending '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists && !info.suspended)
return _lv_suspend(lv);
return 1;
}
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Resuming '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists && info.suspended)
return _lv_activate(lv);
return 1;
}
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Deactivating '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (info.exists)
return _lv_deactivate(lv);
return 1;
}
int lv_activate(struct cmd_context *cmd, const char *lvid_s)
{
struct logical_volume *lv;
struct dm_info info;
if (!(lv = _lv_from_lvid(cmd, lvid_s)))
return 0;
if (test_mode()) {
_skip("Activating '%s'.", lv->name);
return 0;
}
if (!lv_info(lv, &info)) {
stack;
return 0;
}
if (!info.exists || info.suspended)
return _lv_activate(lv);
return 1;
}

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
* This file is released under the LGPL.
*/
#ifndef LVM_ACTIVATE_H
@@ -9,44 +9,38 @@
#include <libdevmapper.h>
/* FIXME Snapshot handling? */
int driver_version(char *version, size_t size);
int library_version(char *version, size_t size);
int lv_active(struct logical_volume *lv);
int lv_suspended(struct logical_volume *lv);
int lv_open_count(struct logical_volume *lv);
/*
* Returns 1 if info structure has been populated, else 0.
*/
int lv_info(struct logical_volume *lv, struct dm_info *info);
int lv_rename(const char *old_name, struct logical_volume *lv);
int lv_activate(struct logical_volume *lv);
int lv_reactivate(struct logical_volume *lv);
int lv_deactivate(struct logical_volume *lv);
int lv_suspend(struct logical_volume *lv);
/*
* Returns 1 if percent has been set, else 0.
*/
int lv_snapshot_percent(struct logical_volume *lv, float *percent);
/*
* Return number of LVs in the VG that are
* active.
* These should eventually use config file
* to determine whether or not to activate
*/
int lv_suspend_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_resume_if_active(struct cmd_context *cmd, const char *lvid_s);
int lv_activate(struct cmd_context *cmd, const char *lvid_s);
int lv_deactivate(struct cmd_context *cmd, const char *lvid_s);
/*
* FIXME:
* I don't like the *lvs_in_vg* function names.
*/
/*
* Return number of LVs in the VG that are active.
*/
int lvs_in_vg_activated(struct volume_group *vg);
int lvs_in_vg_opened(struct volume_group *vg);
/*
* Test for (lv->status & LVM_WRITE)
*/
int lv_update_write_access(struct logical_volume *lv);
/*
* Activate all LVs in the VG. Ignore any that
* are already active. Return number
* activated.
*/
int activate_lvs_in_vg(struct volume_group *vg);
/*
* Deactivate all LVs in the VG
*/
int deactivate_lvs_in_vg(struct volume_group *vg);
int lv_setup_cow_store(struct logical_volume *lv);
#endif

1640
lib/activate/dev_manager.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_DEV_MANAGER_H
#define _LVM_DEV_MANAGER_H
#include "metadata.h"
#include <libdevmapper.h>
struct dev_manager;
/*
* Constructor and destructor.
*/
struct dev_manager *dev_manager_create(const char *vg_name);
void dev_manager_destroy(struct dev_manager *dm);
/*
* The device handler is responsible for creating all the layered
* dm devices, and ensuring that all constraints are maintained
* (eg, an origin is created before its snapshot, but is not
* unsuspended until the snapshot is also created.)
*/
int dev_manager_info(struct dev_manager *dm, struct logical_volume *lv,
struct dm_info *info);
int dev_manager_snapshot_percent(struct dev_manager *dm,
struct logical_volume *lv, float *percent);
int dev_manager_suspend(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_activate(struct dev_manager *dm, struct logical_volume *lv);
int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv);
/*
* Put the desired changes into effect.
*/
int dev_manager_execute(struct dev_manager *dm);
#endif

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#ifndef DMFS_INTERFACE_H
#define DMFS_INTERFACE_H
struct dmfs;
struct dmfs *dmfs_create(void);
void dmfs_destroy(struct dmfs *dm);
int dmfs_dev_is_present(struct dmfs *dm, const char *dev);
int dmfs_dev_is_active(struct dmfs *dm, const char *dev);
int dmfs_table_is_present(struct dmfs *dm, const char *dev, const char *table);
int dmfs_table_is_active(struct dmfs *dm, const char *dev, const char *table);
int dmfs_dev_create(struct dmfs *dm, const char *name);
int dmfs_dev_load_table(struct dmfs *dm, const char *dev,
const char *table, const char *file);
int dmfs_dev_drop_table(struct dmfs *dm, const char *dev, const char *table);
int dmfs_dev_activate_table(struct dmfs *dm, const char *dev,
const char *table);
int dmfs_dev_deactivate(struct dmfs *dm, const char *dev);
#endif

View File

@@ -4,6 +4,12 @@
* This file is released under the LGPL.
*/
#include "fs.h"
#include "log.h"
#include "toolcontext.h"
#include "lvm-string.h"
#include "lvm-file.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -12,30 +18,27 @@
#include <stdio.h>
#include <string.h>
#include "fs.h"
#include "log.h"
#include "names.h"
#include <libdevmapper.h>
/*
* Lazy programmer: I'm just going to always try
* and create/remove the vg directory, and not say
* anything if it fails.
*/
static int _mk_dir(struct volume_group *vg)
{
char vg_path[PATH_MAX];
if (!build_vg_path(vg_path, sizeof(vg_path),
vg->cmd->dev_dir, vg->name)) {
log_error("Couldn't construct name of volume group directory.");
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
vg->cmd->dev_dir, vg->name) == -1) {
log_error("Couldn't construct name of volume "
"group directory.");
return 0;
}
if (dir_exists(vg_path))
return 1;
log_very_verbose("Creating directory %s", vg_path);
mkdir(vg_path, 0555);
if (mkdir(vg_path, 0555)) {
log_sys_error("mkdir", vg_path);
return 0;
}
return 1;
}
@@ -44,53 +47,56 @@ static int _rm_dir(struct volume_group *vg)
{
char vg_path[PATH_MAX];
if (!build_vg_path(vg_path, sizeof(vg_path),
vg->cmd->dev_dir, vg->name)) {
log_error("Couldn't construct name of volume group dir for %s",
vg->name);
if (lvm_snprintf(vg_path, sizeof(vg_path), "%s%s",
vg->cmd->dev_dir, vg->name) == -1) {
log_error("Couldn't construct name of volume "
"group directory.");
return 0;
}
log_very_verbose("Removing directory %s", vg_path);
rmdir(vg_path);
if (is_empty_dir(vg_path))
rmdir(vg_path);
return 1;
}
static int _mk_link(struct logical_volume *lv)
static int _mk_link(struct logical_volume *lv, const char *dev)
{
char lv_path[PATH_MAX], link_path[PATH_MAX];
struct stat buf;
if (!build_dm_path(lv_path, sizeof(lv_path), lv->vg->name, lv->name)) {
log_error("Couldn't create destination pathname for "
"logical volume link for %s", lv->name);
return 0;
}
if (!build_lv_link_path(link_path, sizeof(link_path),
lv->vg->cmd->dev_dir,
lv->vg->name, lv->name)) {
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
lv->vg->cmd->dev_dir, lv->vg->name, lv->name) == -1) {
log_error("Couldn't create source pathname for "
"logical volume link %s", lv->name);
return 0;
}
if (!lstat(link_path, &buf)) {
if (lvm_snprintf(link_path, sizeof(link_path), "%s/%s",
dm_dir(), dev) == -1) {
log_error("Couldn't create destination pathname for "
"logical volume link for %s", lv->name);
return 0;
}
if (!lstat(lv_path, &buf)) {
if (!S_ISLNK(buf.st_mode)) {
log_error("Symbolic link %s not created: file exists",
link_path);
return 0;
}
if (unlink(link_path) < 0) {
log_sys_error("unlink", link_path);
if (unlink(lv_path) < 0) {
log_sys_error("unlink", lv_path);
return 0;
}
}
log_very_verbose("Linking %s to %s", link_path, lv_path);
if (symlink(lv_path, link_path) < 0) {
log_sys_error("symlink", link_path);
log_very_verbose("Linking %s -> %s", lv_path, link_path);
if (symlink(link_path, lv_path) < 0) {
log_sys_error("symlink", lv_path);
return 0;
}
@@ -100,36 +106,31 @@ static int _mk_link(struct logical_volume *lv)
static int _rm_link(struct logical_volume *lv, const char *lv_name)
{
struct stat buf;
char link_path[PATH_MAX];
char lv_path[PATH_MAX];
if (!lv_name)
lv_name = lv->name;
if (!build_lv_link_path(link_path, sizeof(link_path),
lv->vg->cmd->dev_dir,
lv->vg->name, lv->name)) {
if (lvm_snprintf(lv_path, sizeof(lv_path), "%s%s/%s",
lv->vg->cmd->dev_dir, lv->vg->name, lv_name) == -1) {
log_error("Couldn't determine link pathname.");
return 0;
}
log_very_verbose("Removing link %s", link_path);
if (lstat(link_path, &buf) || !S_ISLNK(buf.st_mode)) {
log_error("%s not symbolic link - not removing",
link_path);
return 0;
log_very_verbose("Removing link %s", lv_path);
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
log_error("%s not symbolic link - not removing", lv_path);
return 0;
}
if (unlink(link_path) < 0) {
log_sys_error("unlink", link_path);
if (unlink(lv_path) < 0) {
log_sys_error("unlink", lv_path);
return 0;
}
return 1;
}
int fs_add_lv(struct logical_volume *lv)
int fs_add_lv(struct logical_volume *lv, const char *dev)
{
if (!_mk_dir(lv->vg) ||
!_mk_link(lv)) {
if (!_mk_dir(lv->vg) || !_mk_link(lv, dev)) {
stack;
return 0;
}
@@ -139,8 +140,7 @@ int fs_add_lv(struct logical_volume *lv)
int fs_del_lv(struct logical_volume *lv)
{
if (!_rm_link(lv, NULL) ||
!_rm_dir(lv->vg)) {
if (!_rm_link(lv, lv->name) || !_rm_dir(lv->vg)) {
stack;
return 0;
}
@@ -148,12 +148,14 @@ int fs_del_lv(struct logical_volume *lv)
return 1;
}
int fs_rename_lv(const char *old_name, struct logical_volume *lv)
/* FIXME Use rename() */
int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name)
{
if (!_rm_link(lv, old_name))
if (old_name && !_rm_link(lv, old_name))
stack;
if (!_mk_link(lv))
if (!_mk_link(lv, dev))
stack;
return 1;

View File

@@ -14,10 +14,10 @@
* up the volume group directory in /dev and the
* symbolic links to the dm device.
*/
int fs_add_lv(struct logical_volume *lv);
int fs_add_lv(struct logical_volume *lv, const char *dev);
int fs_del_lv(struct logical_volume *lv);
int fs_rename_lv(const char *old_name, struct logical_volume *lv);
int fs_rename_lv(struct logical_volume *lv,
const char *dev, const char *old_name);
#endif

View File

@@ -1,88 +0,0 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "names.h"
#include "lvm-string.h"
#include "log.h"
#include "limits.h"
#include <libdevmapper.h>
/*
* The volume group name and the logical volume name are
* seperated by a single ':', any colons in the vg name are
* doubled up to form a pair.
*/
int build_dm_name(char *buffer, size_t len,
const char *vg_name, const char *lv_name)
{
char *out;
const char *in;
for (out = buffer, in = vg_name; len && *in; len--) {
if (*in == ':') {
*out++ = ':';
if (!--len)
break;
}
*out++ = *in++;
len--;
}
if (!len)
return 0;
if (lvm_snprintf(out, len, ":%s", lv_name) == -1) {
log_err("Couldn't build logical volume name.");
return 0;
}
return 1;
}
int build_dm_path(char *buffer, size_t len,
const char *vg_name, const char *lv_name)
{
char dev_name[PATH_MAX];
if (!build_dm_name(dev_name, sizeof(dev_name), vg_name, lv_name)) {
stack;
return 0;
}
if (lvm_snprintf(buffer, len, "%s/%s", dm_dir(), dev_name) == -1) {
stack;
return 0;
}
return 1;
}
int build_vg_path(char *buffer, size_t len,
const char *dev_dir, const char *vg_name)
{
if (lvm_snprintf(buffer, len, "%s%s", dev_dir, vg_name) == -1) {
stack;
return 0;
}
return 1;
}
int build_lv_link_path(char *buffer, size_t len, const char *dev_dir,
const char *vg_name, const char *lv_name)
{
if (lvm_snprintf(buffer, len, "%s%s/%s",
dev_dir, vg_name, lv_name) == -1) {
stack;
return 0;
}
return 1;
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_NAMES_H
#define _LVM_NAMES_H
#include <stdlib.h>
/*
* Functions that build up useful paths to devices, sym-links
* etc. Names are passed in as strings, rather than via the
* appropriate metadata structures, so we can use it for renaming
* devices.
*/
/*
* The name of the device-mapper device for a particular LV.
* eg, vg0:music
*/
int build_dm_name(char *buffer, size_t len,
const char *vg_name, const char *lv_name);
/*
* The path of the device-mapper device for a particular LV.
* eg, /dev/device-mapper/vg0:music
*/
int build_dm_path(char *buffer, size_t len,
const char *vg_name, const char *lv_name);
/*
* Path to the volume group directory.
* eg, /dev/vg0
*/
int build_vg_path(char *buffer, size_t len,
const char *dev_dir, const char *vg_name);
/*
* Path to the symbolic link that lives in the volume group
* directory.
* eg, /dev/vg0/music
*/
int build_lv_link_path(char *buffer, size_t len,
const char *dev_dir,
const char *vg_name, const char *lv_name);
#endif

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "table-build.c"
static void _print_run(FILE *fp, struct logical_volume *lv)
{
}
int build_table(struct volume_group *vg, struct logical_volume *lv,
const char *file)
{
int i;
uint64_t sector = 0;
uint64_t pe_size = vg->extent_size;
uint64_t dest;
struct pe_specifier *pes;
FILE *fp = fopen(file, "w");
if (!fp) {
log_err("couldn't open '%s' to write table", file);
return 0;
}
for (i = 0; i < lv->le_count; i++) {
pes = lv->map + i;
dest = pes->pv->pe_start + (pe_size * pes->pe);
fprintf(fp, "%ull %ull linear %s %ull\n",
sector, pe_size, pes->pv->dev->name, dest);
sector += pe_size;
}
fclose(fp);
return 1;
}

View File

@@ -1,13 +0,0 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
#ifndef TABLE_BUILD_H
#define TABLE_BUILD_H
int build_table(struct volume_group *vg, struct logical_volume *lv,
const char *file);
#endif

16
lib/commands/errors.h Normal file
View File

@@ -0,0 +1,16 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#ifndef _LVM_ERRORS_H
#define _LVM_ERRORS_H
#define EINVALID_CMD_LINE 1
#define ENO_SUCH_CMD 3
#define ECMD_PROCESSED 4
#define ECMD_FAILED 5
#endif

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#ifndef _LVM_TOOLCONTEXT_H
#define _LVM_TOOLCONTEXT_H
#include "dev-cache.h"
#include "config.h"
#include "pool.h"
#include "metadata.h"
/* command-instance-related variables needed by library */
struct cmd_context {
/* format handler allocates all objects from here */
struct pool *mem;
struct format_type *fmt; /* Current format to use by default */
/* FIXME Move into dynamic list */
struct format_type *fmt1; /* Format1 */
struct format_type *fmtt; /* Format_text */
char *cmd_line;
char *dev_dir;
struct dev_filter *filter;
struct config_file *cf;
struct command *command;
struct uuid_map *um;
struct arg *args;
};
#endif

View File

@@ -18,34 +18,34 @@
#include "log.h"
enum {
TOK_INT,
TOK_FLOAT,
TOK_STRING,
TOK_EQ,
TOK_SECTION_B,
TOK_SECTION_E,
TOK_ARRAY_B,
TOK_ARRAY_E,
TOK_IDENTIFIER,
TOK_INT,
TOK_FLOAT,
TOK_STRING,
TOK_EQ,
TOK_SECTION_B,
TOK_SECTION_E,
TOK_ARRAY_B,
TOK_ARRAY_E,
TOK_IDENTIFIER,
TOK_COMMA,
TOK_EOF
};
struct parser {
const char *fb, *fe; /* file limits */
const char *fb, *fe; /* file limits */
int t; /* token limits and type */
const char *tb, *te;
int t; /* token limits and type */
const char *tb, *te;
int fd; /* descriptor for file being parsed */
int fd; /* descriptor for file being parsed */
int line; /* line number we are on */
struct pool *mem;
struct pool *mem;
};
struct cs {
struct config_file cf;
struct pool *mem;
struct config_file cf;
struct pool *mem;
};
static void _get_token(struct parser *p);
@@ -68,7 +68,6 @@ static char *_dup_tok(struct parser *p);
} \
} while(0);
static int _tok_match(const char *str, const char *b, const char *e)
{
while (*str && (b != e)) {
@@ -79,88 +78,92 @@ static int _tok_match(const char *str, const char *b, const char *e)
return !(*str || (b != e));
}
/*
* public interface
*/
struct config_file *create_config_file(void)
{
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
struct cs *c;
struct pool *mem = pool_create(10 * 1024);
if (!mem) {
stack;
return 0;
}
if (!mem) {
stack;
return 0;
}
if (!(c = pool_alloc(mem, sizeof(*c)))) {
stack;
pool_destroy(mem);
return 0;
}
if (!(c = pool_alloc(mem, sizeof(*c)))) {
stack;
pool_destroy(mem);
return 0;
}
c->mem = mem;
c->cf.root = (struct config_node *)NULL;
return &c->cf;
c->mem = mem;
c->cf.root = (struct config_node *) NULL;
return &c->cf;
}
void destroy_config_file(struct config_file *cf)
{
pool_destroy(((struct cs *) cf)->mem);
pool_destroy(((struct cs *) cf)->mem);
}
int read_config(struct config_file *cf, const char *file)
{
struct cs *c = (struct cs *) cf;
struct parser *p;
struct stat info;
int r = 1, fd;
struct parser *p;
struct stat info;
int r = 1, fd;
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
return 0;
}
if (!(p = pool_alloc(c->mem, sizeof(*p)))) {
stack;
return 0;
}
p->mem = c->mem;
/* memory map the file */
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
log_sys_error("stat", file);
return 0;
}
/* memory map the file */
if (stat(file, &info) || S_ISDIR(info.st_mode)) {
log_sys_error("stat", file);
return 0;
}
if ((fd = open(file, O_RDONLY)) < 0) {
log_sys_error("open", file);
return 0;
}
if (info.st_size == 0) {
log_verbose("%s is empty", file);
return 1;
}
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == MAP_FAILED) {
log_sys_error("mmap", file);
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
if ((fd = open(file, O_RDONLY)) < 0) {
log_sys_error("open", file);
return 0;
}
/* parse */
p->tb = p->te = p->fb;
p->fb = mmap((caddr_t) 0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (p->fb == (caddr_t) (-1)) {
log_sys_error("mmap", file);
close(fd);
return 0;
}
p->fe = p->fb + info.st_size;
/* parse */
p->tb = p->te = p->fb;
p->line = 1;
_get_token(p);
if (!(cf->root = _file(p))) {
stack;
r = 0;
}
if (!(cf->root = _file(p))) {
stack;
r = 0;
}
/* unmap the file */
if (munmap((char *) p->fb, info.st_size)) {
log_sys_error("munmap", file);
r = 0;
}
/* unmap the file */
if (munmap((char *) p->fb, info.st_size)) {
log_sys_error("munmap", file);
r = 0;
}
close(fd);
return r;
close(fd);
return r;
}
static void _write_value(FILE *fp, struct config_value *v)
static void _write_value(FILE * fp, struct config_value *v)
{
switch (v->type) {
case CFG_STRING:
@@ -177,21 +180,21 @@ static void _write_value(FILE *fp, struct config_value *v)
}
}
static int _write_config(struct config_node *n, FILE *fp, int level)
static int _write_config(struct config_node *n, FILE * fp, int level)
{
char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
int i;
char space[MAX_INDENT + 1];
int l = (level < MAX_INDENT) ? level : MAX_INDENT;
int i;
if (!n)
return 1;
for (i = 0; i < l; i++)
space[i] = ' ';
space[i] = '\0';
for (i = 0; i < l; i++)
space[i] = ' ';
space[i] = '\0';
while (n) {
fprintf(fp, "%s%s", space, n->key);
while (n) {
fprintf(fp, "%s%s", space, n->key);
if (!n->v) {
/* it's a sub section */
fprintf(fp, " {\n");
@@ -214,8 +217,8 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
_write_value(fp, v);
}
fprintf(fp, "\n");
n = n->sib;
}
n = n->sib;
}
/* FIXME: add error checking */
return 1;
}
@@ -223,17 +226,17 @@ static int _write_config(struct config_node *n, FILE *fp, int level)
int write_config(struct config_file *cf, const char *file)
{
int r = 1;
FILE *fp = fopen(file, "w");
if (!fp) {
log_sys_error("open", file);
return 0;
}
FILE *fp = fopen(file, "w");
if (!fp) {
log_sys_error("open", file);
return 0;
}
if (!_write_config(cf->root, fp, 0)) {
if (!_write_config(cf->root, fp, 0)) {
stack;
r = 0;
}
fclose(fp);
fclose(fp);
return r;
}
@@ -260,7 +263,7 @@ static struct config_node *_file(struct parser *p)
static struct config_node *_section(struct parser *p)
{
/* IDENTIFIER '{' VALUE* '}' */
/* IDENTIFIER '{' VALUE* '}' */
struct config_node *root, *n, *l = NULL;
if (!(root = _create_node(p))) {
stack;
@@ -272,7 +275,7 @@ static struct config_node *_section(struct parser *p)
return 0;
}
match (TOK_IDENTIFIER);
match(TOK_IDENTIFIER);
if (p->t == TOK_SECTION_B) {
match(TOK_SECTION_B);
@@ -297,17 +300,17 @@ static struct config_node *_section(struct parser *p)
}
}
return root;
return root;
}
static struct config_value *_value(struct parser *p)
{
/* '[' TYPE* ']' | TYPE */
/* '[' TYPE* ']' | TYPE */
struct config_value *h = 0, *l, *ll = 0;
if (p->t == TOK_ARRAY_B) {
match (TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
if (!(l = _type(p))) {
if (p->t == TOK_ARRAY_B) {
match(TOK_ARRAY_B);
while (p->t != TOK_ARRAY_E) {
if (!(l = _type(p))) {
stack;
return 0;
}
@@ -321,48 +324,48 @@ static struct config_value *_value(struct parser *p)
if (p->t == TOK_COMMA)
match(TOK_COMMA);
}
match(TOK_ARRAY_E);
} else
match(TOK_ARRAY_E);
} else
h = _type(p);
return h;
return h;
}
static struct config_value *_type(struct parser *p)
{
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
/* [0-9]+ | [0-9]*\.[0-9]* | ".*" */
struct config_value *v = _create_value(p);
switch (p->t) {
case TOK_INT:
switch (p->t) {
case TOK_INT:
v->type = CFG_INT;
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
match(TOK_INT);
break;
v->v.i = strtol(p->tb, 0, 0); /* FIXME: check error */
match(TOK_INT);
break;
case TOK_FLOAT:
case TOK_FLOAT:
v->type = CFG_FLOAT;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
match(TOK_FLOAT);
break;
v->v.r = strtod(p->tb, 0); /* FIXME: check error */
match(TOK_FLOAT);
break;
case TOK_STRING:
case TOK_STRING:
v->type = CFG_STRING;
p->tb++, p->te--; /* strip "'s */
p->tb++, p->te--; /* strip "'s */
if (!(v->v.str = _dup_tok(p))) {
stack;
return 0;
}
p->te++;
match(TOK_STRING);
break;
match(TOK_STRING);
break;
default:
default:
log_error("Parse error at line %d: expected a value", p->line);
return 0;
}
return v;
return 0;
}
return v;
}
static int _match_aux(struct parser *p, int t)
@@ -379,106 +382,114 @@ static int _match_aux(struct parser *p, int t)
*/
static void _get_token(struct parser *p)
{
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe) {
p->tb = p->te;
_eat_space(p);
if (p->tb == p->fe) {
p->t = TOK_EOF;
return;
}
p->t = TOK_INT; /* fudge so the fall through for
floats works */
switch (*p->te) {
case '{':
p->t = TOK_SECTION_B;
p->te++;
break;
case '}':
p->t = TOK_SECTION_E;
p->te++;
break;
case '[':
p->t = TOK_ARRAY_B;
p->te++;
break;
case ']':
p->t = TOK_ARRAY_E;
p->te++;
break;
case ',':
p->t = TOK_COMMA;
p->te++;
break;
case '=':
p->t = TOK_EQ;
p->te++;
break;
case '"':
p->t = TOK_STRING;
p->t = TOK_INT; /* fudge so the fall through for
floats works */
switch (*p->te) {
case '{':
p->t = TOK_SECTION_B;
p->te++;
while ((p->te != p->fe) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe))
p->te++;
p->te++;
}
break;
if (p->te != p->fe)
p->te++;
break;
case '}':
p->t = TOK_SECTION_E;
p->te++;
break;
case '.':
p->t = TOK_FLOAT;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
p->te++;
while (p->te != p->fe) {
if (*p->te == '.') {
if (p->t == TOK_FLOAT)
break;
p->t = TOK_FLOAT;
} else if (!isdigit((int) *p->te))
break;
p->te++;
}
break;
case '[':
p->t = TOK_ARRAY_B;
p->te++;
break;
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '='))
p->te++;
break;
}
case ']':
p->t = TOK_ARRAY_E;
p->te++;
break;
case ',':
p->t = TOK_COMMA;
p->te++;
break;
case '=':
p->t = TOK_EQ;
p->te++;
break;
case '"':
p->t = TOK_STRING;
p->te++;
while ((p->te != p->fe) && (*p->te != '"')) {
if ((*p->te == '\\') && (p->te + 1 != p->fe))
p->te++;
p->te++;
}
if (p->te != p->fe)
p->te++;
break;
case '.':
p->t = TOK_FLOAT;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
p->te++;
while (p->te != p->fe) {
if (*p->te == '.') {
if (p->t == TOK_FLOAT)
break;
p->t = TOK_FLOAT;
} else if (!isdigit((int) *p->te))
break;
p->te++;
}
break;
default:
p->t = TOK_IDENTIFIER;
while ((p->te != p->fe) && !isspace(*p->te) &&
(*p->te != '#') && (*p->te != '='))
p->te++;
break;
}
}
static void _eat_space(struct parser *p)
{
while (p->tb != p->fe) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te != '\n'))
p->te++;
while (p->tb != p->fe) {
if (*p->te == '#') {
while ((p->te != p->fe) && (*p->te != '\n'))
p->te++;
p->line++;
}
else if (isspace(*p->te)) {
while ((p->te != p->fe) && isspace(*p->te)) {
while ((p->te != p->fe) && isspace(*p->te)) {
if (*p->te == '\n')
p->line++;
p->te++;
p->te++;
}
}
else
return;
else
return;
p->tb = p->te;
}
p->tb = p->te;
}
}
/*
@@ -525,8 +536,7 @@ struct config_node *find_config_node(struct config_node *cn,
path++;
/* find the end of this segment */
for (e = path; *e && (*e != sep); e++)
;
for (e = path; *e && (*e != sep); e++) ;
/* hunt for the node */
while (cn) {
@@ -547,20 +557,20 @@ struct config_node *find_config_node(struct config_node *cn,
return cn;
}
const char *
find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail)
const char *find_config_str(struct config_node *cn,
const char *path, char sep, const char *fail)
{
struct config_node *n = find_config_node(cn, path, sep);
if (n && n->v->type == CFG_STRING) {
log_very_verbose("Setting %s to %s", path, n->v->v.str);
if (*n->v->v.str)
log_very_verbose("Setting %s to %s", path, n->v->v.str);
return n->v->v.str;
}
if (fail)
log_very_verbose("%s not found in config: defaulting to %s",
path, fail);
path, fail);
return fail;
}
@@ -574,7 +584,7 @@ int find_config_int(struct config_node *cn, const char *path,
return n->v->v.i;
}
log_very_verbose("%s not found in config: defaulting to %d",
log_very_verbose("%s not found in config: defaulting to %d",
path, fail);
return fail;
}
@@ -590,7 +600,7 @@ float find_config_float(struct config_node *cn, const char *path,
}
log_very_verbose("%s not found in config: defaulting to %f",
path, fail);
path, fail);
return fail;
@@ -609,8 +619,9 @@ static int _str_in_array(const char *str, const char *values[])
static int _str_to_bool(const char *str, int fail)
{
static const char *_true_values[] = {"y", "yes", "on", "true", NULL};
static const char *_false_values[] = {"n", "no", "off", "false", NULL};
static const char *_true_values[] = { "y", "yes", "on", "true", NULL };
static const char *_false_values[] =
{ "n", "no", "off", "false", NULL };
if (_str_in_array(str, _true_values))
return 1;
@@ -622,7 +633,7 @@ static int _str_to_bool(const char *str, int fail)
}
int find_config_bool(struct config_node *cn, const char *path,
char sep, int fail)
char sep, int fail)
{
struct config_node *n = find_config_node(cn, path, sep);
struct config_value *v;
@@ -644,7 +655,7 @@ int find_config_bool(struct config_node *cn, const char *path,
}
int get_config_uint32(struct config_node *cn, const char *path,
char sep, uint32_t *result)
char sep, uint32_t * result)
{
struct config_node *n;
@@ -658,7 +669,7 @@ int get_config_uint32(struct config_node *cn, const char *path,
}
int get_config_uint64(struct config_node *cn, const char *path,
char sep, uint64_t *result)
char sep, uint64_t * result)
{
struct config_node *n;
@@ -671,4 +682,3 @@ int get_config_uint64(struct config_node *cn, const char *path,
*result = (uint64_t) n->v->v.i;
return 1;
}

View File

@@ -22,8 +22,16 @@
#define DEFAULT_DEV_DIR "/dev"
#define DEFAULT_PROC_DIR "/proc"
#define DEFAULT_LOCK_DIR "/var/lock/lvm"
#define DEFAULT_UMASK 0077
#define DEFAULT_FORMAT "lvm1"
#define DEFAULT_MSG_PREFIX " "
#define DEFAULT_CMD_NAME 0
#ifdef READLINE_SUPPORT
#define DEFAULT_MAX_HISTORY 100
#endif

View File

@@ -12,7 +12,7 @@
/* FIXME: calculate this. */
#define INT_SHIFT 5
bitset_t bitset_create(struct pool *mem, unsigned num_bits)
bitset_t bitset_create(struct pool * mem, unsigned num_bits)
{
int n = (num_bits / BITS_PER_INT) + 2;
int size = sizeof(int) * n;
@@ -33,7 +33,7 @@ void bitset_destroy(bitset_t bs)
void bit_union(bitset_t out, bitset_t in1, bitset_t in2)
{
int i;
for(i = (in1[0] / BITS_PER_INT) + 1; i; i--)
for (i = (in1[0] / BITS_PER_INT) + 1; i; i--)
out[i] = in1[i] | in2[i];
}
@@ -58,7 +58,7 @@ int bit_get_next(bitset_t bs, int last_bit)
last_bit++; /* otherwise we'll return the same bit again */
while(last_bit < bs[0]) {
while (last_bit < bs[0]) {
word = last_bit >> INT_SHIFT;
test = bs[word + 1];
bit = last_bit & (BITS_PER_INT - 1);
@@ -66,8 +66,8 @@ int bit_get_next(bitset_t bs, int last_bit)
if ((bit = _test_word(test, bit)) >= 0)
return (word * BITS_PER_INT) + bit;
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
BITS_PER_INT;
last_bit = last_bit - (last_bit & (BITS_PER_INT - 1)) +
BITS_PER_INT;
}
return -1;

View File

@@ -40,8 +40,7 @@ static uint32_t _shuffle(uint32_t k)
#if 1
return ((k & 0xff) << 24 |
(k & 0xff00) << 8 |
(k & 0xff0000) >> 8 |
(k & 0xff000000) >> 24);
(k & 0xff0000) >> 8 | (k & 0xff000000) >> 24);
#else
return k;
#endif

View File

@@ -4,7 +4,6 @@
* This file is released under the LGPL.
*/
#include "dbg_malloc.h"
#include "hash.h"
#include "log.h"
@@ -23,22 +22,30 @@ struct hash_table {
/* Permutation of the Integers 0 through 255 */
static unsigned char _nums[] = {
1, 14,110, 25, 97,174,132,119,138,170,125,118, 27,233,140, 51,
87,197,177,107,234,169, 56, 68, 30, 7,173, 73,188, 40, 36, 65,
49,213,104,190, 57,211,148,223, 48,115, 15, 2, 67,186,210, 28,
12,181,103, 70, 22, 58, 75, 78,183,167,238,157,124,147,172,144,
176,161,141, 86, 60, 66,128, 83,156,241, 79, 46,168,198, 41,254,
178, 85,253,237,250,154,133, 88, 35,206, 95,116,252,192, 54,221,
102,218,255,240, 82,106,158,201, 61, 3, 89, 9, 42,155,159, 93,
166, 80, 50, 34,175,195,100, 99, 26,150, 16,145, 4, 33, 8,189,
121, 64, 77, 72,208,245,130,122,143, 55,105,134, 29,164,185,194,
193,239,101,242, 5,171,126, 11, 74, 59,137,228,108,191,232,139,
6, 24, 81, 20,127, 17, 91, 92,251,151,225,207, 21, 98,113,112,
84,226, 18,214,199,187, 13, 32, 94,220,224,212,247,204,196, 43,
249,236, 45,244,111,182,153,136,129, 90,217,202, 19,165,231, 71,
230,142, 96,227, 62,179,246,114,162, 53,160,215,205,180, 47,109,
44, 38, 31,149,135, 0,216, 52, 63, 23, 37, 69, 39,117,146,184,
163,200,222,235,248,243,219, 10,152,131,123,229,203, 76,120,209
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51,
87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65,
49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28,
12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172,
144,
176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254,
178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54,
221,
102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93,
166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189,
121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185,
194,
193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232,
139,
6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112,
84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196,
43,
249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231,
71,
230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47,
109,
44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
209
};
static struct hash_node *_create_node(const char *str)
@@ -83,7 +90,7 @@ struct hash_table *hash_create(unsigned size_hint)
/* round size hint up to a power of two */
while (new_size < size_hint)
new_size = new_size << 1;
new_size = new_size << 1;
hc->num_slots = new_size;
len = sizeof(*(hc->slots)) * new_size;
@@ -94,7 +101,7 @@ struct hash_table *hash_create(unsigned size_hint)
memset(hc->slots, 0, len);
return hc;
bad:
bad:
dbg_free(hc->slots);
dbg_free(hc);
return 0;
@@ -124,8 +131,8 @@ static inline struct hash_node **_find(struct hash_table *t, const char *key)
unsigned h = _hash(key) & (t->num_slots - 1);
struct hash_node **c;
for(c = &t->slots[h]; *c; c = &((*c)->next))
if(!strcmp(key, (*c)->key))
for (c = &t->slots[h]; *c; c = &((*c)->next))
if (!strcmp(key, (*c)->key))
break;
return c;
@@ -141,7 +148,7 @@ int hash_insert(struct hash_table *t, const char *key, void *data)
{
struct hash_node **c = _find(t, key);
if(*c)
if (*c)
(*c)->data = data;
else {
struct hash_node *n = _create_node(key);
@@ -175,7 +182,7 @@ unsigned hash_get_num_entries(struct hash_table *t)
return t->num_nodes;
}
void hash_iterate(struct hash_table *t, iterate_fn f)
void hash_iter(struct hash_table *t, iterate_fn f)
{
struct hash_node *c;
int i;
@@ -223,4 +230,3 @@ struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
unsigned int h = _hash(n->key) & (t->num_slots - 1);
return n->next ? n->next : _next_slot(t, h + 1);
}

View File

@@ -21,12 +21,16 @@ int hash_insert(struct hash_table *t, const char *key, void *data);
void hash_remove(struct hash_table *t, const char *key);
unsigned hash_get_num_entries(struct hash_table *t);
void hash_iterate(struct hash_table *t, iterate_fn f);
void hash_iter(struct hash_table *t, iterate_fn f);
char *hash_get_key(struct hash_table *t, struct hash_node *n);
void *hash_get_data(struct hash_table *t, struct hash_node *n);
struct hash_node *hash_get_first(struct hash_table *t);
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n);
#define hash_iterate(v, h) \
for (v = hash_get_first(h); v; \
v = hash_get_next(h, v))
#endif

View File

@@ -46,7 +46,6 @@ static struct {
} _cache;
#define _alloc(x) pool_alloc(_cache.mem, (x))
#define _free(x) pool_free(_cache.mem, (x))
@@ -194,7 +193,7 @@ static int _insert(const char *path, int rec)
return 0;
}
if (S_ISDIR(info.st_mode)) { /* add a directory */
if (S_ISDIR(info.st_mode)) { /* add a directory */
if (rec)
r = _insert_dir(path);
@@ -255,7 +254,7 @@ int dev_cache_init(void)
return 1;
bad:
bad:
dev_cache_exit();
return 0;
}
@@ -268,7 +267,7 @@ void _check_closed(struct device *dev)
static inline void _check_for_open_devices(void)
{
hash_iterate(_cache.names, (iterate_fn)_check_closed);
hash_iter(_cache.names, (iterate_fn) _check_closed);
}
void dev_cache_exit(void)
@@ -313,8 +312,8 @@ const char *dev_name_confirmed(struct device *dev)
char *name;
int r;
while ((r = stat(name = list_item(dev->aliases.n,
struct str_list)->str, &buf)) ||
while ((r = stat(name = list_item(dev->aliases.n,
struct str_list)->str, &buf)) ||
(buf.st_rdev != dev->dev)) {
if (r < 0)
log_sys_error("stat", name);
@@ -342,7 +341,6 @@ const char *dev_name_confirmed(struct device *dev)
return dev_name(dev);
}
struct device *dev_cache_get(const char *name, struct dev_filter *f)
{
struct stat buf;
@@ -399,4 +397,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
return NULL;
}

View File

@@ -13,9 +13,9 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h> // UGH!!! for BLKSSZGET
#include <linux/fs.h> // UGH!!! for BLKSSZGET
int dev_get_size(struct device *dev, uint64_t *size)
int dev_get_size(struct device *dev, uint64_t * size)
{
int fd;
long s;
@@ -39,7 +39,7 @@ int dev_get_size(struct device *dev, uint64_t *size)
return 1;
}
int dev_get_sectsize(struct device *dev, uint32_t *size)
int dev_get_sectsize(struct device *dev, uint32_t * size)
{
int fd;
int s;
@@ -62,6 +62,12 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
return 1;
}
static void _flush(int fd)
{
ioctl(fd, BLKFLSBUF, 0);
}
int dev_open(struct device *dev, int flags)
{
struct stat buf;
@@ -92,6 +98,8 @@ int dev_open(struct device *dev, int flags)
dev_close(dev);
return 0;
}
_flush(dev->fd);
dev->flags = 0;
return 1;
}
@@ -104,6 +112,9 @@ int dev_close(struct device *dev)
return 0;
}
if (dev->flags & DEV_ACCESSED_W)
_flush(dev->fd);
if (close(dev->fd))
log_sys_error("close", dev_name(dev));
@@ -135,7 +146,7 @@ int _read(int fd, void *buf, size_t count)
return tot;
}
int64_t dev_read(struct device *dev, uint64_t offset,
int64_t dev_read(struct device * dev, uint64_t offset,
int64_t len, void *buffer)
{
const char *name = dev_name(dev);
@@ -178,7 +189,7 @@ int _write(int fd, const void *buf, size_t count)
return tot;
}
int64_t dev_write(struct device *dev, uint64_t offset,
int64_t dev_write(struct device * dev, uint64_t offset,
int64_t len, void *buffer)
{
const char *name = dev_name(dev);
@@ -194,6 +205,8 @@ int64_t dev_write(struct device *dev, uint64_t offset,
return 0;
}
dev->flags |= DEV_ACCESSED_W;
return _write(fd, buffer, len);
}
@@ -230,6 +243,8 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len)
}
}
dev->flags |= DEV_ACCESSED_W;
/* FIXME: Always display error */
return (len == 0);
}

View File

@@ -38,8 +38,6 @@
#include <linux/major.h>
#include <linux/genhd.h>
#if 0
int _get_partition_type(struct dev_filter *filter, struct device *d);

View File

@@ -10,6 +10,8 @@
#include "lvm-types.h"
#include "list.h"
#define DEV_ACCESSED_W 0x00000001 /* Device written to? */
/*
* All devices in LVM will be represented by one of these.
* pointer comparisons are valid.
@@ -20,6 +22,7 @@ struct device {
/* private */
int fd;
uint32_t flags;
};
struct device_list {
@@ -44,7 +47,8 @@ int dev_zero(struct device *dev, uint64_t offset, int64_t len);
static inline const char *dev_name(struct device *dev) {
return list_item(dev->aliases.n, struct str_list)->str;
return (dev) ? list_item(dev->aliases.n, struct str_list)->str :
"unknown device";
}
/* Return a valid device name from the alias list; NULL otherwise */

View File

@@ -24,13 +24,14 @@
#include "display.h"
#include "activate.h"
#include "uuid.h"
#include "toolcontext.h"
#include <sys/types.h>
#include <string.h>
#define SIZE_BUF 128
char *display_size(unsigned long long size, size_len_t sl)
char *display_size(uint64_t size, size_len_t sl)
{
int s;
ulong byte = 1024 * 1024 * 1024;
@@ -78,12 +79,12 @@ void pvdisplay_colons(struct physical_volume *pv)
dev_name(pv->dev), pv->vg_name, pv->size,
/* FIXME pv->pv_number, Derive or remove? */
pv->status, /* FIXME Support old or new format here? */
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
pv->status & ALLOCATABLE_PV, /* FIXME remove? */
/* FIXME pv->lv_cur, Remove? */
pv->pe_size / 2,
pv->pe_count,
pv->pe_count - pv->pe_allocated,
pv->pe_allocated, *uuid ? uuid : "none");
pv->pe_count - pv->pe_alloc_count,
pv->pe_alloc_count, *uuid ? uuid : "none");
return;
}
@@ -103,22 +104,36 @@ void pvdisplay_full(struct physical_volume *pv)
return;
}
/* Compat */
if(!pv->pe_size) {
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
log_print("\"%s\" is a new physical volume of %s", dev_name(pv->dev), size);
dbg_free(size);
return;
}
set_cmd_name("");
init_msg_prefix("");
/****** FIXME Do we really need this conditional here? */
log_print("--- %sPhysical volume ---", pv->pe_size ? "" : "NEW ");
log_print("PV Name %s", dev_name(pv->dev));
log_print("VG Name %s%s", pv->vg_name,
pv->status & EXPORTED_VG ? " (exported)" : "");
size = display_size(pv->size / 2, SIZE_SHORT);
size = display_size((uint64_t) pv->size / 2, SIZE_SHORT);
if (pv->pe_size && pv->pe_count) {
size1 = display_size((pv->size - pv->pe_count * pv->pe_size)
/ 2, SIZE_SHORT);
/******** FIXME display LVM on-disk data size
/******** FIXME display LVM on-disk data size - static for now...
size2 = display_size(pv->size / 2, SIZE_SHORT);
********/
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
size, size1); /* , size2); */
log_print("PV Size %s [%llu secs]" " / not "
"usable %s [LVM: %s]",
size, (uint64_t) pv->size, size1, "151 KB");
/* , size2); */
dbg_free(size1);
/* dbg_free(size2); */
@@ -126,24 +141,27 @@ void pvdisplay_full(struct physical_volume *pv)
log_print("PV Size %s", size);
dbg_free(size);
/******** FIXME anytime this *isn't* available? */
log_print("PV Status available");
/*********FIXME Anything use this?
log_print("PV# %u", pv->pv_number);
**********/
pe_free = pv->pe_count - pv->pe_allocated;
pe_free = pv->pe_count - pv->pe_alloc_count;
if (pv->pe_count && (pv->status & ALLOCATABLE_PV))
log_print("Allocatable yes %s",
(!pe_free && pv->pe_count) ? "(but full)" : "");
else
log_print("Allocatable NO");
/*********FIXME
log_print("Cur LV %u", pv->lv_cur);
*********/
/*********FIXME Erm...where is this stored?
log_print("Cur LV %u", vg->lv_count);
*/
log_print("PE Size (KByte) %" PRIu64, pv->pe_size / 2);
log_print("Total PE %u", pv->pe_count);
log_print("Free PE %" PRIu64, pe_free);
log_print("Allocated PE %u", pv->pe_allocated);
log_print("Allocated PE %u", pv->pe_alloc_count);
#ifdef LVM_FUTURE
printf("Stale PE %u", pv->pe_stale);
@@ -155,7 +173,8 @@ void pvdisplay_full(struct physical_volume *pv)
return;
}
int pvdisplay_short(struct volume_group *vg, struct physical_volume *pv)
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg,
struct physical_volume *pv)
{
if (!pv)
return 0;
@@ -165,12 +184,14 @@ int pvdisplay_short(struct volume_group *vg, struct physical_volume *pv)
log_print("PV Status %sallocatable",
(pv->status & ALLOCATABLE_PV) ? "" : "NOT ");
log_print("Total PE / Free PE %u / %u",
pv->pe_count, pv->pe_count - pv->pe_allocated);
pv->pe_count, pv->pe_count - pv->pe_alloc_count);
log_print(" ");
return 0;
}
void lvdisplay_colons(struct logical_volume *lv)
{
int inkernel;
@@ -182,95 +203,99 @@ void lvdisplay_colons(struct logical_volume *lv)
lv->vg->name,
lv->name,
lv->vg->name,
(lv->status & (LVM_READ | LVM_WRITE)) >> 8,
inkernel ? 1 : 0,
(lv->status & (LVM_READ | LVM_WRITE)) >> 8, inkernel ? 1 : 0,
/* FIXME lv->lv_number, */
inkernel ? info.open_count : 0, lv->size, lv->le_count,
/* FIXME Add num allocated to struct! lv->lv_allocated_le, */
((lv->status & ALLOC_STRICT) +
(lv->status & ALLOC_CONTIGUOUS) * 2), lv->read_ahead,
inkernel ? info.major : -1,
inkernel ? info.minor : -1
);
inkernel ? info.major : -1, inkernel ? info.minor : -1);
return;
}
int lvdisplay_full(struct logical_volume *lv)
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv)
{
char *size;
uint32_t alloc;
struct dm_info info;
int inkernel;
char uuid[64];
struct snapshot *snap;
struct stripe_segment *seg;
struct list *lvseg;
struct logical_volume *origin;
float snap_percent;
int snap_active;
if (!id_write_format(&lv->lvid.id[1], uuid, sizeof(uuid))) {
stack;
return 0;
}
inkernel = lv_info(lv, &info) && info.exists;
set_cmd_name("");
init_msg_prefix("");
log_print("--- Logical volume ---");
log_print("LV Name %s%s/%s", lv->vg->cmd->dev_dir,
lv->vg->name, lv->name);
log_print("VG Name %s", lv->vg->name);
/* Not in LVM1 format
log_print("LV UUID %s", uuid);
**/
log_print("LV Write Access %s",
(lv->status & LVM_WRITE) ? "read/write" : "read only");
/******* FIXME Snapshot
if (lv->status & (LVM_SNAPSHOT_ORG | LVM_SNAPSHOT)) {
if (lvm_tab_vg_read_with_pv_and_lv(vg_name, &vg) < 0) {
ret = -LVM_ELV_SHOW_VG_READ_WITH_PV_AND_LV;
goto lv_show_end;
}
printf("LV snapshot status ");
if (vg_check_active(vg_name) == TRUE) {
vg_t *vg_core;
if ((ret = vg_status_with_pv_and_lv(vg_name, &vg_core)) == 0) {
lv_t *lv_ptr =
vg_core->
lv[lv_get_index_by_name(vg_core, lv->lv_name)];
if (lv_ptr->lv_access & LV_SNAPSHOT) {
if (lv_ptr->lv_status & LV_ACTIVE)
printf("active ");
else
printf("INACTIVE ");
/* see if this LV is an origin for a snapshot */
if ((snap = find_origin(lv))) {
struct list *slh, *snaplist = find_snapshots(lv);
log_print("LV snapshot status source of");
list_iterate(slh, snaplist) {
snap = list_item(slh, struct snapshot_list)->snapshot;
snap_active = lv_snapshot_percent(snap->cow,
&snap_percent);
log_print(" %s%s/%s [%s]",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->cow->name,
(snap_active > 0) ? "active" : "INACTIVE");
}
if (lv_ptr->lv_access & LV_SNAPSHOT_ORG) {
printf("source of\n");
while (lv_ptr->lv_snapshot_next != NULL) {
lv_ptr = lv_ptr->lv_snapshot_next;
printf(" %s [%s]\n",
lv_ptr->lv_name,
(lv_ptr->
lv_status & LV_ACTIVE) ? "active" :
"INACTIVE");
}
vg_free(vg_core, TRUE);
} else {
printf("destination for %s\n",
lv_ptr->lv_snapshot_org->lv_name);
}
}
} else {
printf("INACTIVE ");
if (lv->lv_access & LV_SNAPSHOT_ORG)
printf("original\n");
else
printf("snapshot\n");
/* reset so we don't try to use this to display other snapshot
* related information. */
snap = NULL;
snap_active = 0;
}
}
***********/
/* Check to see if this LV is a COW target for a snapshot */
else if ((snap = find_cow(lv))) {
snap_active = lv_snapshot_percent(lv, &snap_percent);
log_print("LV snapshot status %s destination for %s%s/%s",
(snap_active > 0) ? "active" : "INACTIVE",
lv->vg->cmd->dev_dir, lv->vg->name,
snap->origin->name);
}
if (inkernel && info.suspended)
log_print("LV Status suspended");
else
log_print("LV Status %savailable",
inkernel ? "" : "NOT ");
!inkernel || (snap && (snap_active < 1))
? "NOT " : "");
/********* FIXME lv_number
/********* FIXME lv_number - not sure that we're going to bother with this
log_print("LV # %u", lv->lv_number + 1);
************/
/* LVM1 lists the number of LVs open in this field, therefore, so do we. */
log_print("# open %u", lvs_in_vg_opened(lv->vg));
/* We're not going to use this count ATM, 'cause it's not what LVM1 does
if (inkernel)
log_print("# open %u", info.open_count);
*/
/********
#ifdef LVM_FUTURE
printf("Mirror copies %u\n", lv->lv_mirror_copies);
@@ -283,49 +308,57 @@ int lvdisplay_full(struct logical_volume *lv)
#endif
********/
size = display_size(lv->size / 2, SIZE_SHORT);
if(snap)
origin = snap->origin;
else
origin = lv;
size = display_size(origin->size / 2, SIZE_SHORT);
log_print("LV Size %s", size);
dbg_free(size);
log_print("Current LE %u", lv->le_count);
log_print("Current LE %u", origin->le_count);
/********** FIXME allocation - is there anytime the allocated LEs will not
* equal the current LEs? */
log_print("Allocated LE %u", origin->le_count);
/**********/
/********** FIXME allocation
log_print("Allocated LE %u", lv->allocated_le);
**********/
/********** FIXME Snapshot
if (lv->lv_access & LV_SNAPSHOT) {
printf("snapshot chunk size %s\n",
(dummy = lvm_show_size(lv->lv_chunk_size / 2, SHORT)));
dbg_free(dummy);
dummy = NULL;
if (lv->lv_remap_end > 0) {
lv_remap_ptr = lv->lv_remap_ptr;
if (lv_remap_ptr > lv->lv_remap_end)
lv_remap_ptr = lv->lv_remap_end;
dummy = lvm_show_size(lv_remap_ptr *
lv->lv_chunk_size / 2, SHORT);
dummy1 = lvm_show_size(lv->lv_remap_end *
lv->lv_chunk_size / 2, SHORT);
printf("Allocated to snapshot %.2f%% [%s/%s]\n",
(float) lv_remap_ptr * 100 / lv->lv_remap_end,
dummy, dummy1);
dbg_free(dummy);
dbg_free(dummy1);
dummy =
lvm_show_size((vg->
lv[lv_get_index_by_number
(vg,
lv->lv_number)]->lv_size -
lv->lv_remap_end * lv->lv_chunk_size) / 2,
SHORT);
printf("Allocated to COW-table %s\n", dummy);
dbg_free(dummy);
list_iterate(lvseg, &lv->segments) {
seg = list_item(lvseg, struct stripe_segment);
if(seg->stripes > 1) {
log_print("Stripes %u", seg->stripes);
log_print("Stripe size (KByte) %u",
seg->stripe_size/2);
}
/* only want the first segment for LVM1 format output */
break;
}
}
******************/
if(snap) {
float fused, fsize;
if(snap_percent == -1)
snap_percent=100;
size = display_size(snap->chunk_size / 2, SIZE_SHORT);
log_print("snapshot chunk size %s", size);
dbg_free(size);
size = display_size(lv->size / 2, SIZE_SHORT);
sscanf(size, "%f", &fsize);
fused = fsize * ( snap_percent / 100 );
log_print("Allocated to snapshot %2.2f%% [%2.2f/%s]",
snap_percent, fused, size);
dbg_free(size);
/* FIXME: Think this'll make them wonder?? */
log_print("Allocated to COW-table %s", "00.01 KB");
}
/** Not in LVM1 format output **
log_print("Segments %u", list_size(&lv->segments));
***/
/********* FIXME Stripes & stripesize for each segment
log_print("Stripe size (KByte) %u", lv->stripesize / 2);
@@ -353,6 +386,9 @@ int lvdisplay_full(struct logical_volume *lv)
log_print("Read ahead sectors %u", lv->read_ahead);
if (lv->status & FIXED_MINOR)
log_print("Persistent minor %d", lv->minor);
/****************
#ifdef LVM_FUTURE
printf("IO Timeout (seconds) ");
@@ -364,7 +400,7 @@ int lvdisplay_full(struct logical_volume *lv)
*************/
if (inkernel)
log_print("Block device %d:%d", info.major,
log_print("Block device %d:%d", info.major,
info.minor);
log_print(" ");
@@ -381,7 +417,7 @@ void _display_stripe(struct stripe_segment *seg, int s, const char *pre)
if (seg->area[s].pv)
log_print("%sphysical extents\t%d to %d", pre,
seg->area[s].pe, seg->area[s].pe + len - 1);
seg->area[s].pe, seg->area[s].pe + len - 1);
}
int lvdisplay_segments(struct logical_volume *lv)
@@ -392,7 +428,7 @@ int lvdisplay_segments(struct logical_volume *lv)
log_print("--- Segments ---");
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
log_print("logical extent %d to %d:",
@@ -417,8 +453,6 @@ int lvdisplay_segments(struct logical_volume *lv)
return 1;
}
void vgdisplay_extents(struct volume_group *vg)
{
return;
@@ -429,10 +463,27 @@ void vgdisplay_full(struct volume_group *vg)
uint32_t access;
char *s1;
char uuid[64];
uint32_t active_pvs;
struct list *pvlist;
set_cmd_name("");
init_msg_prefix("");
/* get the number of active PVs */
if(vg->status & PARTIAL_VG) {
active_pvs=0;
list_iterate(pvlist, &(vg->pvs)) {
active_pvs++;
}
}
else
active_pvs=vg->pv_count;
log_print("--- Volume group ---");
log_print("VG Name %s", vg->name);
/****** Not in LVM1 output, so we aren't outputing it here:
log_print("System ID %s", vg->system_id);
*******/
access = vg->status & (LVM_READ | LVM_WRITE);
log_print("VG Access %s%s%s%s",
access == (LVM_READ | LVM_WRITE) ? "read/write" : "",
@@ -440,33 +491,28 @@ void vgdisplay_full(struct volume_group *vg)
access == LVM_WRITE ? "write" : "",
access == 0 ? "error" : "");
log_print("VG Status %s%sresizable",
vg->status & EXPORTED_VG ? "exported/" : "",
vg->status & EXPORTED_VG ? "exported/" : "available/",
vg->status & RESIZEABLE_VG ? "" : "NOT ");
/******* FIXME vg number
log_print ("VG # %u\n", vg->vg_number);
********/
if (vg->status & CLUSTERED) {
log_print("Clustered yes");
log_print("Shared %s",
vg->status & SHARED ? "yes" : "no");
}
/****** FIXME VG # - we aren't implementing this because people should
* use the UUID for this anyway
log_print("VG # %u", vg->vg_number);
*******/
log_print("MAX LV %u", vg->max_lv);
log_print("Cur LV %u", vg->lv_count);
/****** FIXME Open LVs
log_print ( "Open LV %u", vg->lv_open);
*******/
/****** FIXME Max LV Size
log_print ( "MAX LV Size %s",
( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
free ( s1);
*********/
log_print("Open LV %u", lvs_in_vg_opened(vg));
log_print("MAX LV Size 256 TB");
log_print("Max PV %u", vg->max_pv);
log_print("Cur PV %u", vg->pv_count);
/******* FIXME act PVs
log_print ( "Act PV %u", vg->pv_act);
*********/
log_print("Act PV %u", active_pvs);
s1 = display_size(vg->extent_count * vg->extent_size / 2, SIZE_SHORT);
s1 =
display_size((uint64_t) vg->extent_count * (vg->extent_size / 2),
SIZE_SHORT);
log_print("VG Size %s", s1);
dbg_free(s1);
@@ -476,14 +522,16 @@ void vgdisplay_full(struct volume_group *vg)
log_print("Total PE %u", vg->extent_count);
s1 =
display_size((vg->extent_count - vg->free_count) *
vg->extent_size / 2, SIZE_SHORT);
s1 = display_size(((uint64_t)
vg->extent_count - vg->free_count) *
(vg->extent_size / 2), SIZE_SHORT);
log_print("Alloc PE / Size %u / %s",
vg->extent_count - vg->free_count, s1);
dbg_free(s1);
s1 = display_size(vg->free_count * vg->extent_size / 2, SIZE_SHORT);
s1 =
display_size((uint64_t) vg->free_count * (vg->extent_size / 2),
SIZE_SHORT);
log_print("Free PE / Size %u / %s", vg->free_count, s1);
dbg_free(s1);

View File

@@ -28,16 +28,16 @@
typedef enum {SIZE_LONG=0, SIZE_SHORT=1} size_len_t;
/* Specify size in KB */
char *display_size(unsigned long long size, size_len_t sl);
char *display_size(uint64_t size, size_len_t sl);
char *display_uuid(char *uuidstr);
void pvdisplay_colons(struct physical_volume *pv);
void pvdisplay_full(struct physical_volume *pv);
int pvdisplay_short(struct volume_group *vg, struct physical_volume *pv);
int pvdisplay_short(struct cmd_context *cmd, struct volume_group *vg, struct physical_volume *pv);
void lvdisplay_colons(struct logical_volume *lv);
int lvdisplay_segments(struct logical_volume *lv);
int lvdisplay_full(struct logical_volume *lv);
int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv);
void vgdisplay_extents(struct volume_group *vg);
void vgdisplay_full(struct volume_group *vg);

View File

@@ -36,7 +36,6 @@ static void _destroy(struct dev_filter *f)
dbg_free(f);
}
struct dev_filter *composite_filter_create(int n, ...)
{
struct dev_filter **filters = dbg_malloc(sizeof(*filters) * (n + 1));

View File

@@ -54,7 +54,7 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
if (!(cn = find_config_node(cf->root, path, '/'))) {
log_very_verbose("Couldn't find %s array in '%s'",
path, pf->file);
path, pf->file);
return 0;
}
@@ -65,13 +65,13 @@ static int _read_array(struct pfilter *pf, struct config_file *cf,
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_verbose("Devices array contains a value "
"which is not a string ... ignoring");
"which is not a string ... ignoring");
continue;
}
if (!hash_insert(pf->devices, cv->v.str, data))
log_verbose("Couldn't add '%s' to filter ... ignoring",
cv->v.str);
cv->v.str);
}
return 1;
}
@@ -101,12 +101,12 @@ int persistent_filter_load(struct dev_filter *f)
if (hash_get_num_entries(pf->devices))
r = 1;
out:
out:
destroy_config_file(cf);
return r;
}
static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
static void _write_array(struct pfilter *pf, FILE * fp, const char *path,
void *data)
{
void *d;
@@ -175,7 +175,7 @@ static int _lookup_p(struct dev_filter *f, struct device *dev)
if (!l) {
l = pf->real->passes_filter(pf->real, dev) ?
PF_GOOD_DEVICE : PF_BAD_DEVICE;
PF_GOOD_DEVICE : PF_BAD_DEVICE;
list_iterate(ah, &dev->aliases) {
sl = list_item(ah, struct str_list);
@@ -232,7 +232,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
return f;
bad:
bad:
dbg_free(pf->file);
if (pf->devices)
hash_destroy(pf->devices);

View File

@@ -128,8 +128,7 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
* the matcher gives.
*/
for (v = val, i = count - 1; v; v = v->next, i--)
if (!_extract_pattern(scratch, v->v.str,
regex, rf->accept, i)) {
if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
log_info("invalid filter pattern");
goto out;
}
@@ -137,12 +136,12 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
/*
* build the matcher.
*/
if (!(rf->engine = matcher_create(rf->mem,
(const char **) regex, count)))
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
count)))
stack;
r = 1;
out:
out:
pool_destroy(scratch);
return r;
}
@@ -221,8 +220,7 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
f->private = rf;
return f;
bad:
bad:
pool_destroy(mem);
return NULL;
}

View File

@@ -71,12 +71,12 @@ static int passes_lvm_type_device_filter(struct dev_filter *f,
return 0;
/* Check it's accessible */
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("Unable to open %s: %s", name, strerror(errno));
if ((fd = open(name, O_RDONLY)) < 0) {
log_debug("Unable to open %s: %s", name, strerror(errno));
return 0;
}
close(fd);
close(fd);
return 1;
}
@@ -85,7 +85,7 @@ struct dev_filter *lvm_type_filter_create(const char *proc)
{
struct dev_filter *f;
if (!(f = dbg_malloc(sizeof (struct dev_filter)))) {
if (!(f = dbg_malloc(sizeof(struct dev_filter)))) {
log_error("LVM type filter allocation failed");
return NULL;
}
@@ -124,12 +124,13 @@ static int *scan_proc_dev(const char *proc)
int *max_partitions_by_major;
if (!(max_partitions_by_major = dbg_malloc(sizeof (int) * NUMBER_OF_MAJORS))) {
if (!(max_partitions_by_major =
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
log_error("Filter failed to allocate max_partitions_by_major");
return NULL;
}
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
if (lvm_snprintf(proc_devices, sizeof(proc_devices),
"%s/devices", proc) < 0) {
log_error("Failed to create /proc/devices string");
return NULL;
@@ -140,7 +141,7 @@ static int *scan_proc_dev(const char *proc)
return NULL;
}
memset(max_partitions_by_major, 0, sizeof (int) * NUMBER_OF_MAJORS);
memset(max_partitions_by_major, 0, sizeof(int) * NUMBER_OF_MAJORS);
while (fgets(line, 80, pd) != NULL) {
i = 0;
while (line[i] == ' ' && line[i] != '\0')
@@ -168,7 +169,7 @@ static int *scan_proc_dev(const char *proc)
_md_major = line_maj;
/* Go through the valid device names and if there is a
match store max number of partitions */
match store max number of partitions */
for (j = 0; device_info[j].name != NULL; j++) {
dev_len = strlen(device_info[j].name);

View File

@@ -21,7 +21,7 @@
#ifndef _LVM_FILTER_H
#define _LVM_FILTER_H
struct dev_filter *lvm_type_filter_create();
struct dev_filter *lvm_type_filter_create(const char *proc);
void lvm_type_filter_destroy(struct dev_filter *f);

View File

@@ -135,7 +135,7 @@ static int _munge_formats(struct pv_disk *pvd)
int read_pvd(struct device *dev, struct pv_disk *pvd)
{
if (dev_read(dev, 0, sizeof(*pvd), pvd) != sizeof(*pvd)) {
log_very_verbose("Failed to read PV data from %s",
log_very_verbose("Failed to read PV data from %s",
dev_name(dev));
return 0;
}
@@ -265,35 +265,35 @@ static void _munge_exported_vg(struct disk_list *data)
int l, s;
/* Return if PV not in a VG or VG not exported */
if ((!*data->pvd.vg_name) ||
!(data->vgd.vg_status & VG_EXPORTED))
if ((!*data->pvd.vg_name) || !(data->vgd.vg_status & VG_EXPORTED))
return;
l = strlen(data->pvd.vg_name);
s = sizeof(EXPORTED_TAG);
if (!strncmp(data->pvd.vg_name + l - s + 1, EXPORTED_TAG, s))
data->pvd.vg_name[l - s + 1] = '\0';
data->pvd.vg_name[l - s + 1] = '\0';
data->pvd.pv_status |= VG_EXPORTED;
}
static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
static struct disk_list *__read_disk(struct format_type *fmt,
struct device *dev, struct pool *mem,
const char *vg_name)
{
struct disk_list *data = pool_alloc(mem, sizeof(*data));
struct disk_list *dl = pool_alloc(mem, sizeof(*dl));
const char *name = dev_name(dev);
if (!data) {
if (!dl) {
stack;
return NULL;
}
data->dev = dev;
data->mem = mem;
list_init(&data->uuids);
list_init(&data->lvds);
dl->dev = dev;
dl->mem = mem;
list_init(&dl->uuids);
list_init(&dl->lvds);
if (!read_pvd(dev, &data->pvd)) {
if (!read_pvd(dev, &dl->pvd)) {
stack;
goto bad;
}
@@ -301,60 +301,60 @@ static struct disk_list *__read_disk(struct device *dev, struct pool *mem,
/*
* is it an orphan ?
*/
if (!*data->pvd.vg_name) {
log_very_verbose("%s is not a member of any VG", name);
if (!*dl->pvd.vg_name) {
log_very_verbose("%s is not a member of any format1 VG", name);
/* Update VG cache */
vgcache_add(data->pvd.vg_name, dev);
vgcache_add(dl->pvd.vg_name, NULL, dev, fmt);
return (vg_name) ? NULL : data;
return (vg_name) ? NULL : dl;
}
if (!_read_vgd(data)) {
if (!_read_vgd(dl)) {
log_error("Failed to read VG data from PV (%s)", name);
goto bad;
}
/* If VG is exported, set VG name back to the real name */
_munge_exported_vg(data);
_munge_exported_vg(dl);
/* Update VG cache with what we found */
vgcache_add(data->pvd.vg_name, dev);
vgcache_add(dl->pvd.vg_name, dl->vgd.vg_uuid, dev, fmt);
if (vg_name && strcmp(vg_name, data->pvd.vg_name)) {
if (vg_name && strcmp(vg_name, dl->pvd.vg_name)) {
log_very_verbose("%s is not a member of the VG %s",
name, vg_name);
goto bad;
}
if (!_read_uuids(data)) {
if (!_read_uuids(dl)) {
log_error("Failed to read PV uuid list from %s", name);
goto bad;
}
if (!_read_lvs(data)) {
if (!_read_lvs(dl)) {
log_error("Failed to read LV's from %s", name);
goto bad;
}
if (!_read_extents(data)) {
if (!_read_extents(dl)) {
log_error("Failed to read extents from %s", name);
goto bad;
}
log_very_verbose("Found %s in %sVG %s", name,
(data->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
data->pvd.vg_name);
log_very_verbose("Found %s in %sVG %s", name,
(dl->vgd.vg_status & VG_EXPORTED) ? "exported " : "",
dl->pvd.vg_name);
return data;
return dl;
bad:
pool_free(data->mem, data);
pool_free(dl->mem, dl);
return NULL;
}
struct disk_list *read_disk(struct device *dev, struct pool *mem,
const char *vg_name)
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name)
{
struct disk_list *r;
@@ -363,7 +363,7 @@ struct disk_list *read_disk(struct device *dev, struct pool *mem,
return NULL;
}
r = __read_disk(dev, mem, vg_name);
r = __read_disk(fmt, dev, mem, vg_name);
if (!dev_close(dev))
stack;
@@ -378,16 +378,16 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
list_iterate(pvdh, head) {
pvd = &list_item(pvdh, struct disk_list)->pvd;
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
if (!strncmp(data->pvd.pv_uuid, pvd->pv_uuid,
sizeof(pvd->pv_uuid))) {
if (MAJOR(data->dev->dev) != md_major()) {
log_very_verbose("Ignoring duplicate PV %s on "
"%s", pvd->pv_uuid,
"%s", pvd->pv_uuid,
dev_name(data->dev));
return;
}
log_very_verbose("Duplicate PV %s - using md %s",
pvd->pv_uuid, dev_name(data->dev));
log_very_verbose("Duplicate PV %s - using md %s",
pvd->pv_uuid, dev_name(data->dev));
list_del(pvdh);
break;
}
@@ -400,8 +400,9 @@ static void _add_pv_to_list(struct list *head, struct disk_list *data)
* We keep track of the first object allocated form the pool
* so we can free off all the memory if something goes wrong.
*/
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
struct pool *mem, struct list *head)
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
struct dev_filter *filter, struct pool *mem,
struct list *head)
{
struct dev_iter *iter;
struct device *dev;
@@ -413,7 +414,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
if ((pvdh = vgcache_find(vg_name))) {
list_iterate(pvdh2, pvdh) {
dev = list_item(pvdh2, struct pvdev_list)->dev;
if (!(data = read_disk(dev, mem, vg_name)))
if (!(data = read_disk(fmt, dev, mem, vg_name)))
break;
_add_pv_to_list(head, data);
}
@@ -421,8 +422,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
/* Did we find the whole VG? */
if (!vg_name || !*vg_name ||
(data && *data->pvd.vg_name &&
list_size(head) == data->vgd.pv_cur))
return 1;
list_size(head) == data->vgd.pv_cur)) return 1;
/* Something changed. Remove the hints. */
list_init(head);
@@ -436,7 +436,7 @@ int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
/* Otherwise do a complete scan */
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
if ((data = read_disk(dev, mem, vg_name))) {
if ((data = read_disk(fmt, dev, mem, vg_name))) {
_add_pv_to_list(head, data);
}
}
@@ -500,7 +500,7 @@ static int _write_lvd(struct device *dev, ulong pos, struct lv_disk *disk)
static int _write_lvs(struct disk_list *data)
{
struct list *lvh;
ulong pos;
ulong pos, offset;
pos = data->pvd.lv_on_disk.base;
@@ -513,10 +513,15 @@ static int _write_lvs(struct disk_list *data)
list_iterate(lvh, &data->lvds) {
struct lvd_list *ll = list_item(lvh, struct lvd_list);
if (!_write_lvd(data->dev, pos, &ll->lvd))
fail;
offset = sizeof(struct lv_disk) * ll->lvd.lv_number;
if (offset + sizeof(struct lv_disk) >
data->pvd.lv_on_disk.size) {
log_error("lv_number %d too large", ll->lvd.lv_number);
return 0;
}
pos += sizeof(struct lv_disk);
if (!_write_lvd(data->dev, pos + offset, &ll->lvd))
fail;
}
return 1;
@@ -543,16 +548,16 @@ static int _write_pvd(struct disk_list *data)
ulong pos = data->pvd.pv_on_disk.base;
ulong size = data->pvd.pv_on_disk.size;
if(size < sizeof(struct pv_disk)) {
if (size < sizeof(struct pv_disk)) {
log_error("Invalid PV structure size.");
return 0;
}
/* Make sure that the gap between the PV structure and
/* Make sure that the gap between the PV structure and
the next one is zeroed in order to make non LVM tools
happy (idea from AED) */
buf = dbg_malloc(size);
if(!buf) {
if (!buf) {
log_err("Couldn't allocate temporary PV buffer.");
return 0;
}
@@ -560,7 +565,7 @@ static int _write_pvd(struct disk_list *data)
memset(buf, 0, size);
memcpy(buf, &data->pvd, sizeof(struct pv_disk));
_xlate_pvd((struct pv_disk *)buf);
_xlate_pvd((struct pv_disk *) buf);
if (dev_write(data->dev, pos, size, buf) != size) {
dbg_free(buf);
fail;
@@ -573,7 +578,7 @@ static int _write_pvd(struct disk_list *data)
/*
* assumes the device has been opened.
*/
static int __write_all_pvd(struct disk_list *data)
static int __write_all_pvd(struct format_type *fmt, struct disk_list *data)
{
const char *pv_name = dev_name(data->dev);
@@ -582,13 +587,19 @@ static int __write_all_pvd(struct disk_list *data)
return 0;
}
if (!test_mode())
vgcache_add(data->pvd.vg_name, data->dev);
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt);
/*
* Stop here for orphan pv's.
*/
if (data->pvd.vg_name[0] == '\0')
if (data->pvd.vg_name[0] == '\0') {
if (!test_mode())
vgcache_add(data->pvd.vg_name, NULL, data->dev, fmt);
return 1;
}
if (!test_mode())
vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev,
fmt);
if (!_write_vgd(data)) {
log_error("Failed to write VG data to %s", pv_name);
@@ -616,7 +627,7 @@ static int __write_all_pvd(struct disk_list *data)
/*
* opens the device and hands to the above fn.
*/
static int _write_all_pvd(struct disk_list *data)
static int _write_all_pvd(struct format_type *fmt, struct disk_list *data)
{
int r;
@@ -625,7 +636,7 @@ static int _write_all_pvd(struct disk_list *data)
return 0;
}
r = __write_all_pvd(data);
r = __write_all_pvd(fmt, data);
if (!dev_close(data->dev))
stack;
@@ -638,17 +649,17 @@ static int _write_all_pvd(struct disk_list *data)
* little sanity checking, so make sure correct
* data is passed to here.
*/
int write_disks(struct list *pvs)
int write_disks(struct format_type *fmt, struct list *pvs)
{
struct list *pvh;
struct disk_list *dl;
list_iterate(pvh, pvs) {
dl = list_item(pvh, struct disk_list);
if (!(_write_all_pvd(dl)))
if (!(_write_all_pvd(fmt, dl)))
fail;
log_very_verbose("Successfully wrote data to %s",
log_very_verbose("Successfully wrote data to %s",
dev_name(dl->dev));
}

View File

@@ -18,6 +18,7 @@
#define MAX_LV 256
#define MAX_VG 99
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
#define MIN_PE_SIZE (8192L / SECTOR_SIZE) /* 8 KB in sectors */
#define MAX_PE_SIZE (16L * 1024L * 1024L / SECTOR_SIZE * 1024)
#define PE_SIZE_PV_SIZE_REL 5 /* PV size must be at least 5 times PE size */
@@ -40,6 +41,7 @@
/* logical volume */
#define LV_ACTIVE 0x01 /* lv_status */
#define LV_SPINDOWN 0x02 /* " */
#define LV_PERSISTENT_MINOR 0x04 /* " */
#define LV_READ 0x01 /* lv_access */
#define LV_WRITE 0x02 /* " */
@@ -166,7 +168,6 @@ struct disk_list {
* Layout constants.
*/
#define METADATA_ALIGN 4096UL
#define PE_ALIGN (65536UL / SECTOR_SIZE)
#define METADATA_BASE 0UL
#define PV_SIZE 1024UL
@@ -186,13 +187,14 @@ int calculate_extent_count(struct physical_volume *pv);
*/
int read_pvd(struct device *dev, struct pv_disk *pvd);
struct disk_list *read_disk(struct device *dev, struct pool *mem,
const char *vg_name);
struct disk_list *read_disk(struct format_type *fmt, struct device *dev,
struct pool *mem, const char *vg_name);
int read_pvs_in_vg(const char *vg_name, struct dev_filter *filter,
int read_pvs_in_vg(struct format_type *fmt, const char *vg_name,
struct dev_filter *filter,
struct pool *mem, struct list *results);
int write_disks(struct list *pvds);
int write_disks(struct format_type *fmt, struct list *pvds);
/*
@@ -215,13 +217,14 @@ int import_lv(struct pool *mem, struct logical_volume *lv,
void export_lv(struct lv_disk *lvd, struct volume_group *vg,
struct logical_volume *lv, const char *dev_dir);
int import_extents(struct pool *mem, struct volume_group *vg,
int import_extents(struct pool *mem, struct volume_group *vg,
struct list *pvds);
int export_extents(struct disk_list *dl, int lv_num,
struct logical_volume *lv,
struct physical_volume *pv);
int import_pvs(struct pool *mem, struct volume_group *vg,
int import_pvs(struct format_instance *fid, struct pool *mem,
struct volume_group *vg,
struct list *pvds, struct list *results, int *count);
int import_lvs(struct pool *mem, struct volume_group *vg,
@@ -229,6 +232,9 @@ int import_lvs(struct pool *mem, struct volume_group *vg,
int export_lvs(struct disk_list *dl, struct volume_group *vg,
struct physical_volume *pv, const char *dev_dir);
int import_snapshots(struct pool *mem, struct volume_group *vg,
struct list *pvds);
int export_uuids(struct disk_list *dl, struct volume_group *vg);
void export_numbers(struct list *pvds, struct volume_group *vg);
@@ -236,10 +242,10 @@ void export_numbers(struct list *pvds, struct volume_group *vg);
void export_pv_act(struct list *pvds);
/* blech */
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
int *result);
int export_vg_number(struct list *pvds, const char *vg_name,
struct dev_filter *filter);
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
const char *candidate_vg, int *result);
int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter);
#endif

View File

@@ -8,9 +8,11 @@
#include "dbg_malloc.h"
#include "pool.h"
#include "hash.h"
#include "limits.h"
#include "list.h"
#include "log.h"
#include "display.h"
#include "toolcontext.h"
/* VG consistency checks */
static int _check_vgs(struct list *pvs, int *partial)
@@ -28,7 +30,7 @@ static int _check_vgs(struct list *pvs, int *partial)
* If there are exported and unexported PVs, ignore exported ones.
* This means an active VG won't be affected if disks are inserted
* bearing an exported VG with the same name.
*/
*/
list_iterate(pvh, pvs) {
dl = list_item(pvh, struct disk_list);
@@ -48,7 +50,6 @@ static int _check_vgs(struct list *pvs, int *partial)
}
}
/* Remove any PVs with VG structs that differ from the first */
list_iterate_safe(pvh, t, pvs) {
dl = list_item(pvh, struct disk_list);
@@ -81,8 +82,10 @@ static int _check_vgs(struct list *pvs, int *partial)
return 1;
}
static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
static struct volume_group *_build_vg(struct format_instance *fid,
struct list *pvs)
{
struct pool *mem = fid->fmt->cmd->mem;
struct volume_group *vg = pool_alloc(mem, sizeof(*vg));
struct disk_list *dl;
int partial;
@@ -95,8 +98,12 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
memset(vg, 0, sizeof(*vg));
vg->cmd = fid->fmt->cmd;
vg->fid = fid;
vg->seqno = 0;
list_init(&vg->pvs);
list_init(&vg->lvs);
list_init(&vg->snapshots);
if (!_check_vgs(pvs, &partial))
goto bad;
@@ -106,7 +113,7 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
if (!import_vg(mem, vg, dl, partial))
goto bad;
if (!import_pvs(mem, vg, pvs, &vg->pvs, &vg->pv_count))
if (!import_pvs(fid, mem, vg, pvs, &vg->pvs, &vg->pv_count))
goto bad;
if (!import_lvs(mem, vg, pvs))
@@ -115,16 +122,19 @@ static struct volume_group *_build_vg(struct pool *mem, struct list *pvs)
if (!import_extents(mem, vg, pvs))
goto bad;
if (!import_snapshots(mem, vg, pvs))
goto bad;
return vg;
bad:
bad:
stack;
pool_free(mem, vg);
return NULL;
}
static struct volume_group *_vg_read(struct format_instance *fi,
const char *vg_name)
static struct volume_group *_vg_read(struct format_instance *fid,
const char *vg_name, void *mda)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvs;
@@ -136,22 +146,21 @@ static struct volume_group *_vg_read(struct format_instance *fi,
return NULL;
}
/* Strip dev_dir if present */
vg_name = strip_dir(vg_name, fi->cmd->dev_dir);
/* Strip dev_dir if present */
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
if (!read_pvs_in_vg(vg_name, fi->cmd->filter, mem, &pvs)) {
if (!read_pvs_in_vg
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) {
stack;
goto bad;
}
if (!(vg = _build_vg(fi->cmd->mem, &pvs))) {
if (!(vg = _build_vg(fid, &pvs))) {
stack;
goto bad;
}
vg->cmd = fi->cmd;
bad:
bad:
pool_destroy(mem);
return vg;
}
@@ -186,7 +195,8 @@ static struct disk_list *_flatten_pv(struct pool *mem, struct volume_group *vg,
return dl;
}
static int _flatten_vg(struct pool *mem, struct volume_group *vg,
static int _flatten_vg(struct format_instance *fid, struct pool *mem,
struct volume_group *vg,
struct list *pvds, const char *dev_dir,
struct dev_filter *filter)
{
@@ -208,7 +218,7 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
export_numbers(pvds, vg);
export_pv_act(pvds);
if (!export_vg_number(pvds, vg->name, filter)) {
if (!export_vg_number(fid, pvds, vg->name, filter)) {
stack;
return 0;
}
@@ -216,7 +226,8 @@ static int _flatten_vg(struct pool *mem, struct volume_group *vg,
return 1;
}
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
static int _vg_write(struct format_instance *fid, struct volume_group *vg,
void *mdl)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvds;
@@ -227,65 +238,58 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
return 0;
}
if (vg->status & PARTIAL_VG) {
log_error("Cannot change metadata for partial volume group %s",
vg->name);
return 0;
}
list_init(&pvds);
r = (_flatten_vg(mem, vg, &pvds, fi->cmd->dev_dir, fi->cmd->filter) &&
write_disks(&pvds));
r = (_flatten_vg(fid, mem, vg, &pvds, fid->fmt->cmd->dev_dir,
fid->fmt->cmd->filter) &&
write_disks(fid->fmt, &pvds));
pool_destroy(mem);
return r;
}
static struct physical_volume *_pv_read(struct format_instance *fi,
const char *name)
int _pv_read(struct format_type *fmt, const char *name,
struct physical_volume *pv)
{
struct pool *mem = pool_create(1024);
struct physical_volume *pv = NULL;
struct disk_list *dl;
struct device *dev;
int r = 0;
log_very_verbose("Reading physical volume data %s from disk", name);
log_very_verbose("Reading physical volume data %s from disk", name);
if (!mem) {
stack;
return NULL;
return 0;
}
if (!(dev = dev_cache_get(name, fi->cmd->filter))) {
if (!(dev = dev_cache_get(name, fmt->cmd->filter))) {
stack;
goto out;
}
if (!(dl = read_disk(dev, mem, NULL))) {
if (!(dl = read_disk(fmt, dev, mem, NULL))) {
stack;
goto out;
}
if (!(pv = pool_alloc(fi->cmd->mem, sizeof(*pv)))) {
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
stack;
goto out;
}
if (!import_pv(fi->cmd->mem, dl->dev, NULL, pv, &dl->pvd)) {
stack;
pool_free(fi->cmd->mem, pv);
pv = NULL;
}
pv->fid = fmt->ops->create_instance(fmt, NULL, NULL);
out:
r = 1;
out:
pool_destroy(mem);
return pv;
return r;
}
static struct list *_get_pvs(struct format_instance *fi)
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
{
struct pool *mem = pool_create(1024 * 10);
struct list pvs, *results;
struct list pvs;
uint32_t count;
if (!mem) {
@@ -293,21 +297,14 @@ static struct list *_get_pvs(struct format_instance *fi)
return NULL;
}
if (!(results = pool_alloc(fi->cmd->mem, sizeof(*results)))) {
stack;
pool_destroy(mem);
return NULL;
}
list_init(&pvs);
list_init(results);
if (!read_pvs_in_vg(NULL, fi->cmd->filter, mem, &pvs)) {
if (!read_pvs_in_vg(fmt, NULL, fmt->cmd->filter, mem, &pvs)) {
stack;
goto bad;
}
if (!import_pvs(fi->cmd->mem, NULL, &pvs, results, &count)) {
if (!import_pvs(NULL, fmt->cmd->mem, NULL, &pvs, results, &count)) {
stack;
goto bad;
}
@@ -315,8 +312,7 @@ static struct list *_get_pvs(struct format_instance *fi)
pool_destroy(mem);
return results;
bad:
pool_free(fi->cmd->mem, results);
bad:
pool_destroy(mem);
return NULL;
}
@@ -335,58 +331,70 @@ static int _find_vg_name(struct list *names, const char *vg)
return 0;
}
static struct list *_get_vgs(struct format_instance *fi)
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
{
struct list *pvh;
struct list *pvs, *names = pool_alloc(fi->cmd->mem, sizeof(*names));
struct list *pvs;
struct name_list *nl;
if (!names) {
stack;
return NULL;
if (!(pvs = pool_alloc(fmt->cmd->mem, sizeof(*pvs)))) {
log_error("PV list allocation failed");
goto err;
}
list_init(names);
list_init(pvs);
if (!(pvs = _get_pvs(fi))) {
if (!_get_pvs(fmt, pvs)) {
stack;
goto bad;
goto err;
}
list_iterate(pvh, pvs) {
struct pv_list *pvl = list_item(pvh, struct pv_list);
if (!(*pvl->pv->vg_name) ||
_find_vg_name(names, pvl->pv->vg_name))
_find_vg_name(names, pvl->pv->vg_name))
continue;
if (!(nl = pool_alloc(fi->cmd->mem, sizeof(*nl)))) {
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
stack;
goto bad;
goto err;
}
if (!(nl->name = pool_strdup(fi->cmd->mem,
pvl->pv->vg_name))) {
if (!(nl->name = pool_strdup(fmt->cmd->mem, pvl->pv->vg_name))) {
stack;
goto bad;
goto err;
}
list_add(names, &nl->list);
}
if (list_empty(names))
goto bad;
pool_free(fmt->cmd->mem, pvs);
return names;
bad:
pool_free(fi->cmd->mem, names);
err:
pool_free(fmt->cmd->mem, pvs);
return NULL;
}
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
static int _pv_setup(struct format_instance *fid, struct physical_volume *pv,
struct volume_group *vg)
{
/* setup operations for the PV structure */
if (pv->size > MAX_PV_SIZE)
pv->size--;
if (pv->size > MAX_PV_SIZE) {
/* FIXME Limit hardcoded */
log_error("Physical volumes cannot be bigger than 2TB");
return 0;
}
/* Nothing more to do if pe_size isn't known */
if (!vg)
return 1;
/*
* This works out pe_start and pe_count.
*/
@@ -398,18 +406,50 @@ static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
return 1;
}
static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
static int _find_free_lvnum(struct logical_volume *lv)
{
int lvnum_used[MAX_LV];
int i = 0;
struct list *lvh;
struct lv_list *lvl;
memset(&lvnum_used, 0, sizeof(lvnum_used));
list_iterate(lvh, &lv->vg->lvs) {
lvl = list_item(lvh, struct lv_list);
lvnum_used[lvnum_from_lvid(&lvl->lv->lvid)] = 1;
}
while (lvnum_used[i])
i++;
return i;
}
static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
{
uint64_t max_size = UINT_MAX;
if (!*lv->lvid.s)
lvid_from_lvnum(&lv->lvid, &lv->vg->id, _find_free_lvnum(lv));
if (lv->le_count > MAX_LE_TOTAL) {
log_error("logical volumes cannot contain more than "
"%d extents.", MAX_LE_TOTAL);
return 0;
}
if (lv->size > max_size) {
char *dummy = display_size(max_size, SIZE_SHORT);
log_error("logical volumes cannot be larger than %s", dummy);
dbg_free(dummy);
return 0;
}
return 1;
}
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
static int _pv_write(struct format_instance *fid, struct physical_volume *pv,
void *mdl)
{
struct pool *mem;
struct disk_list *dl;
@@ -417,14 +457,15 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
list_init(&pvs);
if (*pv->vg_name || pv->pe_allocated ) {
if (*pv->vg_name || pv->pe_alloc_count) {
log_error("Assertion failed: can't _pv_write non-orphan PV "
"(in VG %s)", pv->vg_name);
return 0;
}
/* Ensure any residual PE structure is gone */
pv->pe_size = pv->pe_count = pv->pe_start = 0;
pv->pe_size = pv->pe_count = 0;
pv->pe_start = PE_ALIGN;
if (!(mem = pool_create(1024))) {
stack;
@@ -447,9 +488,10 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
dev_write in order to make other disk tools happy */
dl->pvd.pv_on_disk.base = METADATA_BASE;
dl->pvd.pv_on_disk.size = PV_SIZE;
dl->pvd.pe_on_disk.base = PE_ALIGN * SECTOR_SIZE;
list_add(&pvs, &dl->list);
if (!write_disks(&pvs)) {
if (!write_disks(fid->fmt, &pvs)) {
stack;
goto bad;
}
@@ -457,26 +499,26 @@ static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
pool_destroy(mem);
return 1;
bad:
bad:
pool_destroy(mem);
return 0;
}
int _vg_setup(struct format_instance *fi, struct volume_group *vg)
int _vg_setup(struct format_instance *fid, struct volume_group *vg)
{
/* just check max_pv and max_lv */
if (vg->max_lv >= MAX_LV)
vg->max_lv = MAX_LV - 1;
if (vg->max_pv >= MAX_PV)
if (vg->max_pv >= MAX_PV)
vg->max_pv = MAX_PV - 1;
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
char *dummy, *dummy2;
log_error("Extent size must be between %s and %s",
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)),
(dummy2 = display_size(MAX_PE_SIZE / 2, SIZE_SHORT)));
dbg_free(dummy);
dbg_free(dummy2);
@@ -486,7 +528,7 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
if (vg->extent_size % MIN_PE_SIZE) {
char *dummy;
log_error("Extent size must be multiple of %s",
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
(dummy = display_size(MIN_PE_SIZE / 2, SIZE_SHORT)));
dbg_free(dummy);
return 0;
}
@@ -500,37 +542,72 @@ int _vg_setup(struct format_instance *fi, struct volume_group *vg)
return 1;
}
void _destroy(struct format_instance *fi)
struct format_instance *_create_instance(struct format_type *fmt,
const char *vgname, void *private)
{
dbg_free(fi);
}
struct format_instance *fid;
struct metadata_area *mda;
static struct format_handler _format1_ops = {
get_vgs: _get_vgs,
get_pvs: _get_pvs,
pv_read: _pv_read,
pv_setup: _pv_setup,
pv_write: _pv_write,
lv_setup: _lv_setup,
vg_read: _vg_read,
vg_setup: _vg_setup,
vg_write: _vg_write,
destroy: _destroy,
};
struct format_instance *create_lvm1_format(struct cmd_context *cmd)
{
struct format_instance *fi = dbg_malloc(sizeof(*fi));
if (!fi) {
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
stack;
return NULL;
}
fi->cmd = cmd;
fi->ops = &_format1_ops;
fi->private = NULL;
fid->fmt = fmt;
list_init(&fid->metadata_areas);
return fi;
/* Define a NULL metadata area */
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
stack;
pool_free(fmt->cmd->mem, fid);
return NULL;
}
mda->metadata_locn = NULL;
list_add(&fid->metadata_areas, &mda->list);
return fid;
}
void _destroy_instance(struct format_instance *fid)
{
return;
}
void _destroy(struct format_type *fmt)
{
dbg_free(fmt);
}
static struct format_handler _format1_ops = {
get_vgs: _get_vgs,
get_pvs: _get_pvs,
pv_read: _pv_read,
pv_setup: _pv_setup,
pv_write: _pv_write,
lv_setup: _lv_setup,
vg_read: _vg_read,
vg_setup: _vg_setup,
vg_write: _vg_write,
create_instance:_create_instance,
destroy_instance:_destroy_instance,
destroy: _destroy,
};
struct format_type *create_lvm1_format(struct cmd_context *cmd)
{
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
if (!fmt) {
stack;
return NULL;
}
fmt->cmd = cmd;
fmt->ops = &_format1_ops;
fmt->name = FMT_LVM1_NAME;
fmt->features = 0;
fmt->private = NULL;
return fmt;
}

View File

@@ -9,6 +9,6 @@
#include "metadata.h"
struct format_instance *create_lvm1_format(struct cmd_context *cmd);
struct format_type *create_lvm1_format(struct cmd_context *cmd);
#endif

View File

@@ -16,6 +16,7 @@
#include <time.h>
#include <sys/utsname.h>
#include <linux/kdev_t.h>
static int _check_vg_name(const char *name)
{
@@ -52,15 +53,15 @@ int import_pv(struct pool *mem, struct device *dev,
/* Store system_id from first PV if PV belongs to a VG */
if (vg && !*vg->system_id)
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
if (vg &&
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id)))
log_very_verbose("System ID %s on %s differs from %s for "
"volume group", pvd->system_id,
dev_name(pv->dev), vg->system_id);
/*
log_very_verbose("System ID %s on %s differs from %s for "
"volume group", pvd->system_id,
dev_name(pv->dev), vg->system_id);
/*
* If exported, we still need to flag in pv->status too because
* we don't always have a struct volume_group when we need this.
*/
@@ -74,7 +75,7 @@ int import_pv(struct pool *mem, struct device *dev,
pv->pe_size = pvd->pe_size;
pv->pe_start = pvd->pe_start;
pv->pe_count = pvd->pe_total;
pv->pe_allocated = pvd->pe_allocated;
pv->pe_alloc_count = pvd->pe_allocated;
return 1;
}
@@ -88,7 +89,7 @@ int _system_id(char *s, const char *prefix)
return 0;
}
if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
if (lvm_snprintf(s, NAME_LEN, "%s%s%lu",
prefix, uts.nodename, time(NULL)) < 0) {
log_error("Generated system_id too long");
return 0;
@@ -119,14 +120,14 @@ int export_pv(struct pool *mem, struct volume_group *vg,
strncpy(pvd->vg_name, pv->vg_name, sizeof(pvd->vg_name));
/* Preserve existing system_id if it exists */
if (vg && *vg->system_id)
if (vg && *vg->system_id)
strncpy(pvd->system_id, vg->system_id, sizeof(pvd->system_id));
/* Is VG already exported or being exported? */
if (vg && (vg->status & EXPORTED_VG)) {
/* Does system_id need setting? */
if (!*vg->system_id ||
strncmp(vg->system_id, EXPORTED_TAG,
if (!*vg->system_id ||
strncmp(vg->system_id, EXPORTED_TAG,
sizeof(EXPORTED_TAG) - 1)) {
if (!_system_id(pvd->system_id, EXPORTED_TAG)) {
stack;
@@ -159,10 +160,10 @@ int export_pv(struct pool *mem, struct volume_group *vg,
}
/* Update internal system_id if we changed it */
if (vg &&
if (vg &&
(!*vg->system_id ||
strncmp(vg->system_id, pvd->system_id, sizeof(pvd->system_id))))
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
strncpy(vg->system_id, pvd->system_id, NAME_LEN);
//pvd->pv_major = MAJOR(pv->dev);
@@ -173,15 +174,14 @@ int export_pv(struct pool *mem, struct volume_group *vg,
pvd->lv_cur = 0; /* this is set when exporting the lv list */
pvd->pe_size = pv->pe_size;
pvd->pe_total = pv->pe_count;
pvd->pe_allocated = pv->pe_allocated;
pvd->pe_allocated = pv->pe_alloc_count;
pvd->pe_start = pv->pe_start;
return 1;
}
int import_vg(struct pool *mem,
struct volume_group *vg, struct disk_list *dl,
int partial)
struct volume_group *vg, struct disk_list *dl, int partial)
{
struct vg_disk *vgd = &dl->vgd;
memcpy(vg->id.uuid, vgd->vg_uuid, ID_LEN);
@@ -271,8 +271,9 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg)
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
{
memset(&lv->id, 0, sizeof(lv->id));
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
lvid_from_lvnum(&lv->lvid, &lv->vg->id, lvd->lv_number);
if (!(lv->name = _create_lv_name(mem, lvd->lv_name))) {
stack;
return 0;
}
@@ -280,18 +281,18 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
if (lvd->lv_status & LV_SPINDOWN)
lv->status |= SPINDOWN_LV;
if (lvd->lv_status & LV_PERSISTENT_MINOR) {
lv->status |= FIXED_MINOR;
lv->minor = MINOR(lvd->lv_dev);
} else
lv->minor = -1;
if (lvd->lv_access & LV_READ)
lv->status |= LVM_READ;
if (lvd->lv_access & LV_WRITE)
lv->status |= LVM_WRITE;
if (lvd->lv_access & LV_SNAPSHOT)
lv->status |= SNAPSHOT;
if (lvd->lv_access & LV_SNAPSHOT_ORG)
lv->status |= SNAPSHOT_ORG;
if (lvd->lv_badblock)
lv->status |= BADBLOCK_ON;
@@ -304,8 +305,8 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
lv->status |= ALLOC_SIMPLE;
lv->read_ahead = lvd->lv_read_ahead;
lv->size = lvd->lv_size;
lv->le_count = lvd->lv_allocated_le;
lv->size = lvd->lv_size;
lv->le_count = lvd->lv_allocated_le;
list_init(&lv->segments);
@@ -329,23 +330,22 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
if (lv->status & LVM_WRITE)
lvd->lv_access |= LV_WRITE;
if (lv->status & SNAPSHOT)
lvd->lv_access |= LV_SNAPSHOT;
if (lv->status & SNAPSHOT_ORG)
lvd->lv_access |= LV_SNAPSHOT_ORG;
if (lv->status & SPINDOWN_LV)
lvd->lv_status |= LV_SPINDOWN;
if (lv->status & FIXED_MINOR) {
lvd->lv_status |= LV_PERSISTENT_MINOR;
lvd->lv_dev = MKDEV(0, lv->minor);
}
lvd->lv_read_ahead = lv->read_ahead;
lvd->lv_stripes = list_item(lv->segments.n,
struct stripe_segment)->stripes;
lvd->lv_stripesize = list_item(lv->segments.n,
struct stripe_segment)->stripe_size;
struct stripe_segment)->stripe_size;
lvd->lv_size = lv->size;
lvd->lv_allocated_le = lv->le_count;
lvd->lv_size = lv->size;
lvd->lv_allocated_le = lv->le_count;
if (lv->status & BADBLOCK_ON)
lvd->lv_badblock = LV_BADBLOCK_ON;
@@ -358,26 +358,25 @@ void export_lv(struct lv_disk *lvd, struct volume_group *vg,
}
int export_extents(struct disk_list *dl, int lv_num,
struct logical_volume *lv,
struct physical_volume *pv)
struct logical_volume *lv, struct physical_volume *pv)
{
struct list *segh;
struct pe_disk *ped;
struct stripe_segment *seg;
uint32_t pe, s;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
for (s = 0; s < seg->stripes; s++) {
if (seg->area[s].pv != pv)
continue; /* not our pv */
continue; /* not our pv */
for (pe = 0; pe < (seg->len / seg->stripes); pe++) {
ped = &dl->extents[pe + seg->area[s].pe];
ped->lv_num = lv_num;
ped->le_num = (seg->le / seg->stripes) + pe +
s * (lv->le_count / seg->stripes);
s * (lv->le_count / seg->stripes);
}
}
}
@@ -385,7 +384,8 @@ int export_extents(struct disk_list *dl, int lv_num,
return 1;
}
int import_pvs(struct pool *mem, struct volume_group *vg,
int import_pvs(struct format_instance *fid, struct pool *mem,
struct volume_group *vg,
struct list *pvds, struct list *results, int *count)
{
struct list *pvdh;
@@ -408,6 +408,7 @@ int import_pvs(struct pool *mem, struct volume_group *vg,
return 0;
}
pvl->pv->fid = fid;
list_add(results, &pvl->list);
(*count)++;
}
@@ -428,6 +429,7 @@ static struct logical_volume *_add_lv(struct pool *mem,
return NULL;
}
lv = ll->lv;
lv->vg = vg;
if (!import_lv(mem, lv, lvd)) {
stack;
@@ -435,14 +437,12 @@ static struct logical_volume *_add_lv(struct pool *mem,
}
list_add(&vg->lvs, &ll->list);
lv->vg = vg;
vg->lv_count++;
return lv;
}
int import_lvs(struct pool *mem, struct volume_group *vg,
struct list *pvds)
int import_lvs(struct pool *mem, struct volume_group *vg, struct list *pvds)
{
struct disk_list *dl;
struct lvd_list *ll;
@@ -466,13 +466,21 @@ int import_lvs(struct pool *mem, struct volume_group *vg,
return 1;
}
/* FIXME: tidy */
int export_lvs(struct disk_list *dl, struct volume_group *vg,
struct physical_volume *pv, const char *dev_dir)
{
struct list *lvh;
int r = 0;
struct list *lvh, *sh;
struct lv_list *ll;
struct lvd_list *lvdl;
int lv_num = 0, len;
int lv_num, len;
struct hash_table *lvd_hash;
if (!(lvd_hash = hash_create(32))) {
stack;
return 0;
}
/*
* setup the pv's extents array
@@ -480,29 +488,141 @@ int export_lvs(struct disk_list *dl, struct volume_group *vg,
len = sizeof(struct pe_disk) * dl->pvd.pe_total;
if (!(dl->extents = pool_alloc(dl->mem, len))) {
stack;
return 0;
goto out;
}
memset(dl->extents, 0, len);
list_iterate(lvh, &vg->lvs) {
ll = list_item(lvh, struct lv_list);
if (!(lvdl = pool_alloc(dl->mem, sizeof(*lvdl)))) {
stack;
return 0;
goto out;
}
export_lv(&lvdl->lvd, vg, ll->lv, dev_dir);
lv_num = lvnum_from_lvid(&ll->lv->lvid);
lvdl->lvd.lv_number = lv_num;
if (!hash_insert(lvd_hash, ll->lv->name, &lvdl->lvd)) {
stack;
goto out;
}
if (!export_extents(dl, lv_num + 1, ll->lv, pv)) {
stack;
return 0;
goto out;
}
list_add(&dl->lvds, &lvdl->list);
dl->pvd.lv_cur++;
lv_num++;
}
/*
* Now we need to run through the snapshots, exporting
* the SNAPSHOT_ORG flags etc.
*/
list_iterate(sh, &vg->snapshots) {
struct lv_disk *org, *cow;
struct snapshot *s = list_item(sh,
struct snapshot_list)->snapshot;
if (!(org = hash_lookup(lvd_hash, s->origin->name))) {
log_err("Couldn't find snapshot origin '%s'.",
s->origin->name);
goto out;
}
if (!(cow = hash_lookup(lvd_hash, s->cow->name))) {
log_err("Couldn't find snapshot cow store '%s'.",
s->cow->name);
goto out;
}
org->lv_access |= LV_SNAPSHOT_ORG;
cow->lv_access |= LV_SNAPSHOT;
cow->lv_snapshot_minor = org->lv_number;
cow->lv_chunk_size = s->chunk_size;
}
r = 1;
out:
hash_destroy(lvd_hash);
return r;
}
/*
* FIXME: More inefficient code.
*/
int import_snapshots(struct pool *mem, struct volume_group *vg,
struct list *pvds)
{
struct logical_volume *lvs[MAX_LV];
struct list *pvdh, *lvdh;
struct disk_list *dl;
struct lv_disk *lvd;
int lvnum;
struct logical_volume *org, *cow;
/* build an index of lv numbers */
memset(lvs, 0, sizeof(lvs));
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate(lvdh, &dl->lvds) {
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
lvnum = lvd->lv_number;
if (lvnum > MAX_LV) {
log_err("Logical volume number "
"out of bounds.");
return 0;
}
if (!lvs[lvnum] &&
!(lvs[lvnum] = find_lv(vg, lvd->lv_name))) {
log_err("Couldn't find logical volume '%s'.",
lvd->lv_name);
return 0;
}
}
}
/*
* Now iterate through yet again adding the snapshots.
*/
list_iterate(pvdh, pvds) {
dl = list_item(pvdh, struct disk_list);
list_iterate(lvdh, &dl->lvds) {
lvd = &(list_item(lvdh, struct lvd_list)->lvd);
if (!(lvd->lv_access & LV_SNAPSHOT))
continue;
lvnum = lvd->lv_number;
cow = lvs[lvnum];
if (!(org = lvs[lvd->lv_snapshot_minor])) {
log_err("Couldn't find origin logical volume "
"for snapshot '%s'.", lvd->lv_name);
return 0;
}
/* we may have already added this snapshot */
if (lv_is_cow(cow))
continue;
/* insert the snapshot */
if (!vg_add_snapshot(org, cow, 1, lvd->lv_chunk_size)) {
log_err("Couldn't add snapshot.");
return 0;
}
}
}
return 1;
}
@@ -528,9 +648,8 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg)
}
/*
* This calculates the nasty pv_number and
* lv_number fields used by LVM1. Very
* inefficient code.
* This calculates the nasty pv_number field
* used by LVM1.
*/
void export_numbers(struct list *pvds, struct volume_group *vg)
{
@@ -565,14 +684,14 @@ void export_pv_act(struct list *pvds)
}
}
int export_vg_number(struct list *pvds, const char *vg_name,
struct dev_filter *filter)
int export_vg_number(struct format_instance *fid, struct list *pvds,
const char *vg_name, struct dev_filter *filter)
{
struct list *pvdh;
struct disk_list *dl;
int vg_num;
if (!get_free_vg_number(filter, vg_name, &vg_num)) {
if (!get_free_vg_number(fid, filter, vg_name, &vg_num)) {
stack;
return 0;
}
@@ -584,4 +703,3 @@ int export_vg_number(struct list *pvds, const char *vg_name,
return 1;
}

View File

@@ -249,7 +249,7 @@ static int _check_stripe(struct lv_map *lvm, struct stripe_segment *seg,
*/
for (st = 0; st < seg->stripes; st++)
if ((lvm->map[le + st * len].pv != seg->area[st].pv) ||
(lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
(lvm->map[le + st * len].pe != seg->area[st].pe + seg->len))
return 0;
return 1;
@@ -266,8 +266,7 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
if (lvm->lv->le_count % lvm->stripes) {
log_error("Number of stripes (%u) incompatible "
"with logical extent count (%u) for %s",
lvm->stripes, lvm->lv->le_count,
lvm->lv->name);
lvm->stripes, lvm->lv->le_count, lvm->lv->name);
}
len = lvm->lv->le_count / lvm->stripes;

View File

@@ -8,7 +8,6 @@
#include "log.h"
#include "dbg_malloc.h"
/*
* Only works with powers of 2.
*/
@@ -51,17 +50,17 @@ static void _calc_simple_layout(struct pv_disk *pvd)
pvd->pv_on_disk.base = METADATA_BASE;
pvd->pv_on_disk.size = PV_SIZE;
pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
pvd->vg_on_disk.size = VG_SIZE;
pvd->vg_on_disk.base = _next_base(&pvd->pv_on_disk);
pvd->vg_on_disk.size = VG_SIZE;
pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
pvd->pv_uuidlist_on_disk.base = _next_base(&pvd->vg_on_disk);
pvd->pv_uuidlist_on_disk.size = MAX_PV * NAME_LEN;
pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
pvd->lv_on_disk.base = _next_base(&pvd->pv_uuidlist_on_disk);
pvd->lv_on_disk.size = MAX_LV * sizeof(struct lv_disk);
pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
pvd->pe_on_disk.base = _next_base(&pvd->lv_on_disk);
pvd->pe_on_disk.size = pvd->pe_total * sizeof(struct pe_disk);
}
int _check_vg_limits(struct disk_list *dl)
@@ -103,11 +102,9 @@ int calculate_layout(struct disk_list *dl)
return 1;
}
/*
* It may seem strange to have a struct
* physical_volume in here, but the number of
* extents that can fit on a disk *is* metadata
* It may seem strange to have a struct physical_volume in here,
* but the number of extents that can fit on a disk *is* metadata
* format dependant.
*/
int calculate_extent_count(struct physical_volume *pv)
@@ -117,15 +114,13 @@ int calculate_extent_count(struct physical_volume *pv)
if (!pvd) {
stack;
dbg_free(pvd);
return 0;
}
/*
* Guess how many extents will fit,
* bearing in mind that one is going to be
* knocked off at the start of the next
* loop.
* Guess how many extents will fit, bearing in mind that
* one is going to be knocked off at the start of the
* next loop.
*/
pvd->pe_total = (pv->size / pv->pe_size);
@@ -136,16 +131,15 @@ int calculate_extent_count(struct physical_volume *pv)
return 0;
}
do {
pvd->pe_total--;
_calc_simple_layout(pvd);
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size + \
SECTOR_SIZE - 1) / SECTOR_SIZE);
end = ((pvd->pe_on_disk.base + pvd->pe_on_disk.size +
SECTOR_SIZE - 1) / SECTOR_SIZE);
pvd->pe_start = _round_up(end, PE_ALIGN);
} while((pvd->pe_start + (pvd->pe_total * pv->pe_size)) > pv->size);
} while ((pvd->pe_start + (pvd->pe_total * pv->pe_size)) > pv->size);
if (pvd->pe_total > MAX_PE_TOTAL) {
log_error("Metadata extent limit (%u) exceeded for %s - "

View File

@@ -25,21 +25,20 @@ static int _can_handle(struct labeller *l, struct device *dev)
struct pv_disk pvd;
int r;
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
r = read_pvd(dev, &pvd);
if (!dev_close(dev))
stack;
if (!dev_close(dev))
stack;
return r;
}
static int _write(struct labeller *l,
struct device *dev, struct label *label)
static int _write(struct labeller *l, struct device *dev, struct label *label)
{
_not_supported("write");
return 0;
@@ -81,15 +80,15 @@ static int _read(struct labeller *l, struct device *dev, struct label **label)
struct pv_disk pvd;
int r = 0;
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
if (!dev_open(dev, O_RDONLY)) {
stack;
return 0;
}
r = read_pvd(dev, &pvd);
if (!dev_close(dev))
stack;
if (!dev_close(dev))
stack;
if (!r) {
stack;
@@ -118,15 +117,14 @@ static void _destroy(struct labeller *l)
dbg_free(l);
}
struct label_ops _lvm1_ops = {
can_handle: _can_handle,
write: _write,
remove: _remove,
read: _read,
verify: _can_handle,
destroy_label: _destroy_label,
destroy: _destroy
can_handle: _can_handle,
write: _write,
remove: _remove,
read: _read,
verify: _can_handle,
destroy_label: _destroy_label,
destroy: _destroy
};
struct labeller *lvm1_labeller_create(void)

View File

@@ -15,8 +15,8 @@
* Put in separate file so it wouldn't contaminate
* other code.
*/
int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
int *result)
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
const char *candidate_vg, int *result)
{
struct list *pvh;
struct list all_pvs;
@@ -31,7 +31,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
return 0;
}
if (!read_pvs_in_vg(NULL, filter, mem, &all_pvs)) {
if (!read_pvs_in_vg(fid->fmt, NULL, filter, mem, &all_pvs)) {
stack;
goto out;
}
@@ -40,8 +40,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
list_iterate(pvh, &all_pvs) {
dl = list_item(pvh, struct disk_list);
if (!*dl->pvd.vg_name ||
!strcmp(dl->pvd.vg_name, candidate_vg))
if (!*dl->pvd.vg_name || !strcmp(dl->pvd.vg_name, candidate_vg))
continue;
numbers[dl->vgd.vg_number] = 1;
@@ -55,7 +54,7 @@ int get_free_vg_number(struct dev_filter *filter, const char *candidate_vg,
}
}
out:
out:
pool_destroy(mem);
return r;
}

View File

@@ -13,6 +13,7 @@
#include "import-export.h"
#include "lvm-string.h"
#include "lvm-file.h"
#include "toolcontext.h"
#include <dirent.h>
#include <unistd.h>
@@ -20,7 +21,9 @@
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <time.h>
#define SECS_PER_DAY 86400 /* 24*60*60 */
/*
* The format instance is given a directory path upon creation.
@@ -34,103 +37,22 @@
* Backup files that have expired will be removed.
*/
struct archive_c {
uint32_t retain_days;
uint32_t min_retains;
char *dir;
/*
* An ordered list of previous archives. Each list
* entered against the vg name. Most recent first.
*/
struct hash_table *vg_archives;
/*
* Scratch pool. Contents of vg_archives come from here.
*/
struct pool *mem;
};
/*
* A list of these is built up for each volume group. Ordered
* A list of these is built up for our volume group. Ordered
* with the least recent at the head.
*/
struct archive_file {
struct list list;
char *path;
char *vg;
int index;
};
/*
* This format is write only.
*/
static void _unsupported(const char *cmd)
{
log_err("The archive format doesn't support '%s'", cmd);
}
static struct list *_get_vgs(struct format_instance *fi)
{
_unsupported("get_vgs");
return NULL;
}
static struct list *_get_pvs(struct format_instance *fi)
{
_unsupported("get_pvs");
return NULL;
}
static struct physical_volume *_pv_read(struct format_instance *fi,
const char *pv_name)
{
_unsupported("pv_read");
return NULL;
}
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
struct volume_group *vg)
{
_unsupported("pv_setup");
return 0;
}
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
{
_unsupported("pv_write");
return 0;
}
static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
{
_unsupported("vg_setup");
return 0;
}
static struct volume_group *_vg_read(struct format_instance *fi,
const char *vg_name)
{
_unsupported("vg_read");
return NULL;
}
static void _destroy(struct format_instance *fi)
{
struct archive_c *bc = (struct archive_c *) fi->private;
if (bc->vg_archives)
hash_destroy(bc->vg_archives);
pool_destroy(bc->mem);
}
/*
* Extract vg name and version number from a filename.
*/
static int _split_vg(const char *filename, char *vg, size_t vg_size,
uint32_t *index)
uint32_t * index)
{
int len, vg_len;
char *dot, *underscore;
@@ -170,7 +92,7 @@ static void _insert_file(struct list *head, struct archive_file *b)
}
/* index increases through list */
list_iterate (bh, head) {
list_iterate(bh, head) {
bf = list_item(bh, struct archive_file);
if (bf->index > b->index) {
@@ -182,50 +104,6 @@ static void _insert_file(struct list *head, struct archive_file *b)
list_add_h(&bf->list, &b->list);
}
static int _scan_vg(struct archive_c *bc, const char *file,
const char *vg_name, int index)
{
struct archive_file *b;
struct list *files;
/*
* Do we need to create a new list of archive files for
* this vg ?
*/
if (!(files = hash_lookup(bc->vg_archives, vg_name))) {
if (!(files = pool_alloc(bc->mem, sizeof(*files)))) {
stack;
return 0;
}
list_init(files);
if (!hash_insert(bc->vg_archives, vg_name, files)) {
log_err("Couldn't insert archive file "
"into hash table.");
return 0;
}
}
/*
* Create a new archive file.
*/
if (!(b = pool_alloc(bc->mem, sizeof(*b)))) {
log_err("Couldn't create new archive file.");
return 0;
}
b->index = index;
b->path = (char *)file;
b->vg = (char *)vg_name;
/*
* Insert it to the correct part of the list.
*/
_insert_file(files, b);
return 1;
}
static char *_join(struct pool *mem, const char *dir, const char *name)
{
if (!pool_begin_object(mem, 32) ||
@@ -240,70 +118,130 @@ static char *_join(struct pool *mem, const char *dir, const char *name)
return pool_end_object(mem);
}
static int _scan_dir(struct archive_c *bc)
/*
* Returns a list of archive_files.
*/
static struct list *_scan_archive(struct pool *mem,
const char *vg, const char *dir)
{
int r = 0, i, count, index;
int i, count, index;
char vg_name[64], *path;
struct dirent **dirent;
struct archive_file *af;
struct list *results;
if ((count = scandir(bc->dir, &dirent, NULL, alphasort)) < 0) {
if (!(results = pool_alloc(mem, sizeof(*results)))) {
stack;
return NULL;
}
list_init(results);
/* Sort fails beyond 5-digit indexes */
if ((count = scandir(dir, &dirent, NULL, alphasort)) < 0) {
log_err("Couldn't scan archive directory.");
return 0;
}
for (i = 0; i < count; i++) {
if ((dirent[i]->d_name[0] == '.') ||
!_split_vg(dirent[i]->d_name, vg_name,
sizeof(vg_name), &index))
/* ignore dot files */
if (dirent[i]->d_name[0] == '.')
continue;
if (!(path = _join(bc->mem, bc->dir, dirent[i]->d_name))) {
/* check the name is the correct format */
if (!_split_vg(dirent[i]->d_name, vg_name, sizeof(vg_name),
&index))
continue;
/* is it the vg we're interested in ? */
if (strcmp(vg, vg_name))
continue;
if (!(path = _join(mem, dir, dirent[i]->d_name))) {
stack;
goto out;
}
_scan_vg(bc, path, vg_name, index);
}
r = 1;
/*
* Create a new archive_file.
*/
if (!(af = pool_alloc(mem, sizeof(*af)))) {
log_err("Couldn't create new archive file.");
results = NULL;
goto out;
}
out:
af->index = index;
af->path = path;
/*
* Insert it to the correct part of the list.
*/
_insert_file(results, af);
}
out:
for (i = 0; i < count; i++)
free(dirent[i]);
free(dirent);
return r;
return results;
}
static int _scan_archives(struct archive_c *bc)
static void _remove_expired(struct list *archives, uint32_t archives_size,
uint32_t retain_days, uint32_t min_archive)
{
pool_empty(bc->mem);
struct list *bh;
struct archive_file *bf;
struct stat sb;
time_t retain_time;
if (bc->vg_archives)
hash_destroy(bc->vg_archives);
/* Make sure there are enough archives to even bother looking for
* expired ones... */
if (archives_size <= min_archive)
return;
if (!(bc->vg_archives = hash_create(128))) {
log_err("Couldn't create hash table for scanning archives.");
return 0;
/* Convert retain_days into the time after which we must retain */
retain_time = time(NULL) - (time_t) retain_days * SECS_PER_DAY;
/* Assume list is ordered oldest first (by index) */
list_iterate(bh, archives) {
bf = list_item(bh, struct archive_file);
/* Get the mtime of the file and unlink if too old */
if (stat(bf->path, &sb)) {
log_sys_error("stat", bf->path);
continue;
}
if (sb.st_mtime > retain_time)
return;
log_very_verbose("Expiring archive %s", bf->path);
if (unlink(bf->path))
log_sys_error("unlink", bf->path);
/* Don't delete any more if we've reached the minimum */
if (--archives_size <= min_archive)
return;
}
if (!_scan_dir(bc)) {
stack;
return 0;
}
return 1;
}
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
int archive_vg(struct volume_group *vg,
const char *dir, const char *desc,
uint32_t retain_days, uint32_t min_archive)
{
int r = 0, i, fd;
int i, fd, renamed = 0;
unsigned int index = 0;
struct archive_c *bc = (struct archive_c *) fi->private;
struct archive_file *last;
FILE *fp = NULL;
char temp_file[PATH_MAX], archive_name[PATH_MAX];
struct list *archives;
if (!create_temp_name(bc->dir, temp_file, sizeof(temp_file), &fd)) {
/*
* Write the vg out to a temporary file.
*/
if (!create_temp_name(dir, temp_file, sizeof(temp_file), &fd)) {
log_err("Couldn't create temporary archive name.");
return 0;
}
@@ -314,7 +252,7 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
return 0;
}
if (!text_vg_export(fp, vg)) {
if (!text_vg_export(fp, vg, desc)) {
stack;
fclose(fp);
return 0;
@@ -325,97 +263,97 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
/*
* Now we want to rename this file to <vg>_index.vg.
*/
if (!_scan_archives(bc)) {
log_err("Couldn't scan the archive directory (%s).", bc->dir);
goto out;
if (!(archives = _scan_archive(vg->cmd->mem, vg->name, dir))) {
log_err("Couldn't scan the archive directory (%s).", dir);
return 0;
}
if ((last = (struct archive_file *) hash_lookup(bc->vg_archives,
vg->name))) {
/* move to the last in the list */
last = list_item(last->list.p, struct archive_file);
if (list_empty(archives))
index = 0;
else {
last = list_item(archives->p, struct archive_file);
index = last->index + 1;
}
for (i = 0; i < 10; i++) {
if (lvm_snprintf(archive_name, sizeof(archive_name),
"%s/%s_%05d.vg",
bc->dir, vg->name, index) < 0) {
log_err("archive file name too long.");
goto out;
"%s/%s_%05d.vg", dir, vg->name, index) < 0) {
log_error("Archive file name too long.");
return 0;
}
if (lvm_rename(temp_file, archive_name)) {
r = 1;
if ((renamed = lvm_rename(temp_file, archive_name)))
break;
}
index++;
}
out:
return r;
if (!renamed)
log_error("Archive rename failed for %s", temp_file);
_remove_expired(archives, list_size(archives) + renamed, retain_days,
min_archive);
return 1;
}
void archive_expire(struct format_instance *fi)
static void _display_archive(struct cmd_context *cmd, struct uuid_map *um,
struct archive_file *af)
{
/* FIXME: finish */
struct volume_group *vg = NULL;
struct format_instance *tf;
time_t when;
char *desc;
void *context;
log_print("path:\t\t%s", af->path);
if (!(context = create_text_context(cmd->fmtt, af->path, NULL)) ||
!(tf = cmd->fmtt->ops->create_instance(cmd->fmtt, NULL, context))) {
log_error("Couldn't create text instance object.");
return;
}
/*
* Read the archive file to ensure that it is valid, and
* retrieve the archive time and description.
*/
/* FIXME Use variation on _vg_read */
if (!(vg = text_vg_import(tf, af->path, um, &when, &desc))) {
log_print("Unable to read archive file.");
tf->fmt->ops->destroy_instance(tf);
return;
}
log_print("description:\t%s", desc ? desc : "<No description>");
log_print("time:\t\t%s", ctime(&when));
pool_free(cmd->mem, vg);
tf->fmt->ops->destroy_instance(tf);
}
static struct format_handler _archive_handler = {
get_vgs: _get_vgs,
get_pvs: _get_pvs,
pv_read: _pv_read,
pv_setup: _pv_setup,
pv_write: _pv_write,
vg_setup: _vg_setup,
vg_read: _vg_read,
vg_write: _vg_write,
destroy: _destroy
};
struct format_instance *archive_format_create(struct cmd_context *cmd,
const char *dir,
uint32_t retain_days,
uint32_t min_retains)
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
const char *dir, const char *vg)
{
struct format_instance *fi;
struct archive_c *bc = NULL;
struct pool *mem = cmd->mem;
struct list *archives, *ah;
struct archive_file *af;
if (!(bc = pool_zalloc(mem, sizeof(*bc)))) {
stack;
return NULL;
if (!(archives = _scan_archive(cmd->mem, vg, dir))) {
log_err("Couldn't scan the archive directory (%s).", dir);
return 0;
}
if (!(bc->mem = pool_create(1024))) {
stack;
goto bad;
if (list_empty(archives))
log_print("No archives found.");
list_iterate(ah, archives) {
af = list_item(ah, struct archive_file);
_display_archive(cmd, um, af);
log_print(" ");
}
if (!(bc->dir = pool_strdup(mem, dir))) {
stack;
goto bad;
}
pool_free(cmd->mem, archives);
bc->retain_days = retain_days;
bc->min_retains = min_retains;
if (!(fi = pool_alloc(mem, sizeof(*fi)))) {
stack;
goto bad;
}
fi->cmd = cmd;
fi->ops = &_archive_handler;
fi->private = bc;
return fi;
bad:
if (bc->mem)
pool_destroy(bc->mem);
pool_free(mem, bc);
return NULL;
return 1;
}

View File

@@ -16,14 +16,13 @@
#include <stdarg.h>
#include <time.h>
/*
* The first half of this file deals with
* exporting the vg, ie. writing it to a file.
*/
struct formatter {
struct pool *mem; /* pv names allocated from here */
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
struct hash_table *pv_names; /* dev_name -> pv_name (eg, pv1) */
FILE *fp; /* where we're writing to */
int indent; /* current level of indentation */
@@ -34,16 +33,14 @@ struct formatter {
/*
* Formatting functions.
*/
static void _out_size(struct formatter *f, uint64_t size,
const char *fmt, ...)
__attribute__ (( format (printf, 3, 4) ));
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
static void _out_hint(struct formatter *f, const char *fmt, ...)
__attribute__ (( format (printf, 2, 3) ));
__attribute__ ((format(printf, 2, 3)));
static void _out(struct formatter *f, const char *fmt, ...)
__attribute__ (( format (printf, 2, 3) ));
__attribute__ ((format(printf, 2, 3)));
#define MAX_INDENT 5
static void _inc_indent(struct formatter *f)
@@ -116,7 +113,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
"Gigabytes",
"Terrabytes",
NULL
};
};
int i;
double d = (double) sectors;
@@ -124,7 +121,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
/* to convert to K */
d /= 2.0;
for (i = 0; (d > 1024.0) && _units[i]; i++)
for (i = 0; (d > 1024.0) && _units[i]; i++)
d /= 1024.0;
return lvm_snprintf(buffer, s, "# %g %s", d, _units[i]) > 0;
@@ -134,8 +131,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
* Appends a comment giving a size in more easily
* readable form (eg, 4M instead of 8096).
*/
static void _out_size(struct formatter *f, uint64_t size,
const char *fmt, ...)
static void _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
{
char buffer[64];
va_list ap;
@@ -172,7 +168,8 @@ static void _out(struct formatter *f, const char *fmt, ...)
va_end(ap);
}
static int _print_header(struct formatter *f, struct volume_group *vg)
static int _print_header(struct formatter *f,
struct volume_group *vg, const char *desc)
{
time_t t;
@@ -181,6 +178,10 @@ static int _print_header(struct formatter *f, struct volume_group *vg)
_out(f,
"# This file was originally generated by the LVM2 library\n"
"# Generated: %s\n", ctime(&t));
_out(f, "description = \"%s\"", desc);
_out(f, "creation_time = %lu\n", t);
return 1;
}
@@ -195,6 +196,7 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
_out(f, "id = \"%s\"", buffer);
_out(f, "seqno = %u", vg->seqno);
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
@@ -214,12 +216,11 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
* Get the pv%d name from the formatters hash
* table.
*/
static inline const char *
_get_pv_name(struct formatter *f, struct physical_volume *pv)
static inline const char *_get_pv_name(struct formatter *f,
struct physical_volume *pv)
{
return (pv) ? (const char *)
hash_lookup(f->pv_names, dev_name(pv->dev)) :
"Missing";
return (pv) ? (const char *)
hash_lookup(f->pv_names, dev_name(pv->dev)) : "Missing";
}
static int _print_pvs(struct formatter *f, struct volume_group *vg)
@@ -232,7 +233,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
_out(f, "physical_volumes {");
_inc_indent(f);
list_iterate (pvh, &vg->pvs) {
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
@@ -254,8 +255,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
_out_hint(f, "device = \"%s\"", dev_name(pv->dev));
_nl(f);
if (!print_flags(pv->status, PV_FLAGS,
buffer, sizeof(buffer))) {
if (!print_flags(pv->status, PV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
@@ -319,8 +319,8 @@ static int _count_segments(struct logical_volume *lv)
int r = 0;
struct list *segh;
list_iterate (segh, &lv->segments)
r++;
list_iterate(segh, &lv->segments)
r++;
return r;
}
@@ -333,29 +333,44 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
char buffer[256];
int seg_count;
/*
* Don't bother with an lv section if there are no lvs.
*/
if (list_empty(&vg->lvs))
return 1;
_out(f, "logical_volumes {");
_nl(f);
_inc_indent(f);
list_iterate (lvh, &vg->lvs) {
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
_nl(f);
_out(f, "%s {", lv->name);
_inc_indent(f);
if (!print_flags(lv->status, LV_FLAGS,
buffer, sizeof(buffer))) {
/* FIXME: Write full lvid */
if (!id_write_format(&lv->lvid.id[1], buffer, sizeof(buffer))) {
stack;
return 0;
}
_out(f, "id = \"%s\"", buffer);
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
stack;
return 0;
}
_out(f, "status = %s", buffer);
_out(f, "read_ahead = %u", lv->read_ahead);
if (lv->minor >= 0)
_out(f, "minor = %d", lv->minor);
_out(f, "segment_count = %u", _count_segments(lv));
_nl(f);
seg_count = 1;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
if (!_print_segment(f, vg, seg_count++, seg)) {
@@ -374,13 +389,60 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
return 1;
}
static int _print_snapshot(struct formatter *f, struct snapshot *s,
unsigned int count)
{
_nl(f);
_out(f, "snapshot%u {", count);
_inc_indent(f);
_out(f, "chunk_size = %u", s->chunk_size);
_out(f, "origin = \"%s\"", s->origin->name);
_out(f, "cow_store = \"%s\"", s->cow->name);
_dec_indent(f);
_out(f, "}");
return 1;
}
static int _print_snapshots(struct formatter *f, struct volume_group *vg)
{
struct list *sh;
struct snapshot *s;
unsigned int count = 0;
/*
* Don't bother with a snapshot section if there are no
* snapshots.
*/
if (list_empty(&vg->snapshots))
return 1;
_out(f, "snapshots {");
_inc_indent(f);
list_iterate(sh, &vg->snapshots) {
s = list_item(sh, struct snapshot_list)->snapshot;
if (!_print_snapshot(f, s, count++)) {
stack;
return 0;
}
}
_dec_indent(f);
_out(f, "}");
return 1;
}
/*
* In the text format we refer to pv's as 'pv1',
* 'pv2' etc. This function builds a hash table
* to enable a quick lookup from device -> name.
*/
static int _build_pv_names(struct formatter *f,
struct volume_group *vg)
static int _build_pv_names(struct formatter *f, struct volume_group *vg)
{
int count = 0;
struct list *pvh;
@@ -397,11 +459,10 @@ static int _build_pv_names(struct formatter *f,
goto bad;
}
list_iterate (pvh, &vg->pvs) {
list_iterate(pvh, &vg->pvs) {
pv = list_item(pvh, struct pv_list)->pv;
if (lvm_snprintf(buffer, sizeof(buffer),
"pv%d", count++) < 0) {
if (lvm_snprintf(buffer, sizeof(buffer), "pv%d", count++) < 0) {
stack;
goto bad;
}
@@ -419,7 +480,7 @@ static int _build_pv_names(struct formatter *f,
return 1;
bad:
bad:
if (f->mem)
pool_destroy(f->mem);
@@ -429,7 +490,7 @@ static int _build_pv_names(struct formatter *f,
return 0;
}
int text_vg_export(FILE *fp, struct volume_group *vg)
int text_vg_export(FILE * fp, struct volume_group *vg, const char *desc)
{
int r = 0;
struct formatter *f;
@@ -447,10 +508,9 @@ int text_vg_export(FILE *fp, struct volume_group *vg)
stack;
goto out;
}
#define fail do {stack; goto out;} while(0)
if (!_print_header(f, vg))
if (!_print_header(f, vg, desc))
fail;
_out(f, "%s {", vg->name);
@@ -460,22 +520,24 @@ int text_vg_export(FILE *fp, struct volume_group *vg)
fail;
_nl(f);
if (!_print_pvs(f, vg))
fail;
_nl(f);
if (!_print_lvs(f, vg))
fail;
_nl(f);
if (!_print_snapshots(f, vg))
fail;
#undef fail
_dec_indent(f);
_out(f, "}");
r = !ferror(f->fp);
out:
out:
if (f->mem)
pool_destroy(f->mem);

View File

@@ -41,8 +41,7 @@ static struct flag _lv_flags[] = {
{ALLOC_SIMPLE, "ALLOC_SIMPLE"},
{ALLOC_STRICT, "ALLOC_STRICT"},
{ALLOC_CONTIGUOUS, "ALLOC_CONTIGUOUS"},
{SNAPSHOT, "SNASHOT"},
{SNAPSHOT_ORG, "SNAPSHOT_ORIGIN"},
{FIXED_MINOR, "FIXED_MINOR"},
{0, NULL}
};
@@ -63,7 +62,7 @@ static struct flag *_get_flags(int type)
return NULL;
}
static int _emit(char **buffer, size_t *size, const char *fmt, ...)
static int _emit(char **buffer, size_t * size, const char *fmt, ...)
{
size_t n;
va_list ap;
@@ -125,7 +124,7 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
return 1;
}
int read_flags(uint32_t *status, int type, struct config_value *cv)
int read_flags(uint32_t * status, int type, struct config_value *cv)
{
int f;
uint32_t s = 0;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
@@ -12,72 +12,98 @@
#include "pool.h"
#include "config.h"
#include "hash.h"
#include "display.h"
#include "dbg_malloc.h"
#include "toolcontext.h"
#include "vgcache.h"
#include "lvm-string.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <limits.h>
#include <dirent.h>
/* Arbitrary limits copied from format1/disk_rep.h */
#define MAX_PV 256
#define MAX_LV 256
#define MAX_VG 99
#define MAX_PV_SIZE ((uint32_t) -1) /* 2TB in sectors - 1 */
struct dir_list {
struct list list;
char dir[0];
};
struct text_context {
char *path_live; /* Path to file holding live metadata */
char *path_edit; /* Path to file holding edited metadata */
char *desc; /* Description placed inside file */
};
/*
* NOTE: Currently there can be only one vg per file.
*/
struct text_c {
char *path;
struct uuid_map *um;
};
static void _not_written(const char *cmd)
{
log_err("The text format is lacking an implementation for '%s'", cmd);
}
static struct list *_get_vgs(struct format_instance *fi)
{
_not_written("_get_vgs");
return NULL;
}
static struct list *_get_pvs(struct format_instance *fi)
{
_not_written("_get_vgs");
return NULL;
}
static struct physical_volume *_pv_read(struct format_instance *fi,
const char *pv_name)
{
_not_written("_get_vgs");
return NULL;
}
static int _pv_setup(struct format_instance *fi, struct physical_volume *pv,
struct volume_group *vg)
{
_not_written("_get_vgs");
return 0;
}
/* setup operations for the PV structure */
if (pv->size > MAX_PV_SIZE)
pv->size--;
if (pv->size > MAX_PV_SIZE) {
/* FIXME Limit hardcoded */
log_error("Physical volumes cannot be bigger than 2TB");
return 0;
}
static int _pv_write(struct format_instance *fi, struct physical_volume *pv)
{
_not_written("_get_vgs");
return 0;
return 1;
}
static int _vg_setup(struct format_instance *fi, struct volume_group *vg)
{
_not_written("_get_vgs");
return 0;
/* just check max_pv and max_lv */
if (vg->max_lv >= MAX_LV)
vg->max_lv = MAX_LV - 1;
if (vg->max_pv >= MAX_PV)
vg->max_pv = MAX_PV - 1;
if (vg->extent_size & (vg->extent_size - 1)) {
log_error("Extent size must be power of 2");
return 0;
}
return 1;
}
static int _lv_setup(struct format_instance *fi, struct logical_volume *lv)
{
uint64_t max_size = UINT_MAX;
if (!*lv->lvid.s)
lvid_create(&lv->lvid, &lv->vg->id);
if (lv->size > max_size) {
char *dummy = display_size(max_size, SIZE_SHORT);
log_error("logical volumes cannot be larger than %s", dummy);
dbg_free(dummy);
return 0;
}
return 1;
}
static struct volume_group *_vg_read(struct format_instance *fi,
const char *vg_name)
const char *vgname, void *mdl)
{
struct text_c *tc = (struct text_c *) fi->private;
struct text_context *tc = (struct text_context *) mdl;
struct volume_group *vg;
time_t when;
char *desc;
if (!(vg = text_vg_import(fi->cmd, tc->path, tc->um))) {
if (!(vg = text_vg_import(fi, tc->path_live, fi->fmt->cmd->um, &when,
&desc))) {
stack;
return NULL;
}
@@ -87,42 +113,43 @@ static struct volume_group *_vg_read(struct format_instance *fi,
* text file (this restriction may remain). We need to
* check that it contains the correct volume group.
*/
if (strcmp(vg_name, vg->name)) {
pool_free(fi->cmd->mem, vg);
if (strcmp(vgname, vg->name)) {
pool_free(fi->fmt->cmd->mem, vg);
log_err("'%s' does not contain volume group '%s'.",
tc->path, vg_name);
tc->path_live, vgname);
return NULL;
}
return vg;
}
static int _vg_write(struct format_instance *fi, struct volume_group *vg)
static int _vg_write(struct format_instance *fi, struct volume_group *vg,
void *mdl)
{
struct text_c *tc = (struct text_c *) fi->private;
struct text_context *tc = (struct text_context *) mdl;
FILE *fp;
int fd;
char *slash;
char temp_file[PATH_MAX], temp_dir[PATH_MAX];
slash = rindex(tc->path, '/');
slash = rindex(tc->path_edit, '/');
if (slash == 0)
strcpy(temp_dir, ".");
else if (slash - tc->path < PATH_MAX) {
strncpy(temp_dir, tc->path, slash - tc->path);
temp_dir[slash - tc->path] = '\0';
else if (slash - tc->path_edit < PATH_MAX) {
strncpy(temp_dir, tc->path_edit, slash - tc->path_edit);
temp_dir[slash - tc->path_edit] = '\0';
} else {
log_error("Text format failed to determine directory.");
return 0;
}
if (!create_temp_name(temp_dir, temp_file, sizeof(temp_file), &fd)) {
log_err("Couldn't create temporary text file name.");
return 0;
}
if (!create_temp_name(temp_dir, temp_file, sizeof(temp_file), &fd)) {
log_err("Couldn't create temporary text file name.");
return 0;
}
if (!(fp = fdopen(fd, "w"))) {
log_sys_error("fdopen", temp_file);
@@ -130,81 +157,482 @@ static int _vg_write(struct format_instance *fi, struct volume_group *vg)
return 0;
}
if (!text_vg_export(fp, vg)) {
if (!text_vg_export(fp, vg, tc->desc)) {
log_error("Failed to write metadata to %s.", temp_file);
fclose(fp);
return 0;
}
if (fclose(fp)) {
log_sys_error("fclose", tc->path);
if (fsync(fd)) {
log_sys_error("fsync", tc->path_edit);
fclose(fp);
return 0;
}
if (rename(temp_file, tc->path)) {
log_error("%s: rename to %s failed: %s", temp_file, tc->path,
strerror(errno));
if (fclose(fp)) {
log_sys_error("fclose", tc->path_edit);
return 0;
}
if (rename(temp_file, tc->path_edit)) {
log_error("%s: rename to %s failed: %s", temp_file,
tc->path_edit, strerror(errno));
return 0;
}
return 1;
}
static void _destroy(struct format_instance *fi)
static int _pv_commit(struct format_instance *fi, struct physical_volume *pv,
void *mdl)
{
struct text_c *tc = (struct text_c *) fi->private;
// struct text_context *tc = (struct text_context *) mdl;
dbg_free(tc->path);
dbg_free(tc);
dbg_free(fi);
return 1;
}
static int _vg_commit(struct format_instance *fi, struct volume_group *vg,
void *mdl)
{
struct text_context *tc = (struct text_context *) mdl;
if (rename(tc->path_edit, tc->path_live)) {
log_error("%s: rename to %s failed: %s", tc->path_edit,
tc->path_edit, strerror(errno));
return 0;
}
sync();
return 1;
}
static int _vg_remove(struct format_instance *fi, struct volume_group *vg,
void *mdl)
{
struct text_context *tc = (struct text_context *) mdl;
if (path_exists(tc->path_edit) && unlink(tc->path_edit)) {
log_sys_error("unlink", tc->path_edit);
return 0;
}
if (path_exists(tc->path_live) && unlink(tc->path_live)) {
log_sys_error("unlink", tc->path_live);
return 0;
}
sync();
return 1;
}
/* Add vgname to list if it's not already there */
static int _add_vgname(struct format_type *fmt, struct list *names,
char *vgname)
{
struct list *nlh;
struct name_list *nl;
list_iterate(nlh, names) {
nl = list_item(nlh, struct name_list);
if (!strcmp(vgname, nl->name))
return 1;
}
vgcache_add(vgname, NULL, NULL, fmt);
if (!(nl = pool_alloc(fmt->cmd->mem, sizeof(*nl)))) {
stack;
return 0;
}
if (!(nl->name = pool_strdup(fmt->cmd->mem, vgname))) {
log_error("strdup %s failed", vgname);
return 0;
}
list_add(names, &nl->list);
return 1;
}
static struct list *_get_vgs(struct format_type *fmt, struct list *names)
{
struct dirent *dirent;
struct dir_list *dl;
struct list *dlh, *dir_list;
char *tmp;
DIR *d;
dir_list = (struct list *) fmt->private;
list_iterate(dlh, dir_list) {
dl = list_item(dlh, struct dir_list);
if (!(d = opendir(dl->dir))) {
log_sys_error("opendir", dl->dir);
continue;
}
while ((dirent = readdir(d)))
if (strcmp(dirent->d_name, ".") &&
strcmp(dirent->d_name, "..") &&
(!(tmp = strstr(dirent->d_name, ".tmp")) ||
tmp != dirent->d_name + strlen(dirent->d_name)
- 4))
if (!_add_vgname(fmt, names, dirent->d_name))
return NULL;
if (closedir(d))
log_sys_error("closedir", dl->dir);
}
return names;
}
static struct list *_get_pvs(struct format_type *fmt, struct list *results)
{
struct pv_list *pvl, *rhl;
struct list *vgh;
struct list *pvh;
struct list *names = pool_alloc(fmt->cmd->mem, sizeof(*names));
struct list *rh;
struct name_list *nl;
struct volume_group *vg;
list_init(names);
if (!_get_vgs(fmt, names)) {
stack;
return NULL;
}
list_iterate(vgh, names) {
nl = list_item(vgh, struct name_list);
if (!(vg = vg_read(fmt->cmd, nl->name))) {
log_error("format_text: _get_pvs failed to read VG %s",
nl->name);
continue;
}
/* FIXME Use temp hash! */
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
/* If in use, remove from list of orphans */
list_iterate(rh, results) {
rhl = list_item(rh, struct pv_list);
if (id_equal(&rhl->pv->id, &pvl->pv->id)) {
if (*rhl->pv->vg_name)
log_err("PV %s in two VGs "
"%s and %s",
dev_name(rhl->pv->dev),
rhl->pv->vg_name,
vg->name);
else
memcpy(&rhl->pv, &pvl->pv,
sizeof(struct
physical_volume));
}
}
}
}
pool_free(fmt->cmd->mem, names);
return results;
}
static int _pv_write(struct format_instance *fi, struct physical_volume *pv,
void *mdl)
{
/* No on-disk PV structure change required! */
/* FIXME vgcache could be wrong */
return 1;
//return (fi->fmt->cmd->fmt1->ops->pv_write(fi, pv, NULL));
/*** FIXME Not required?
struct volume_group *vg;
struct list *pvh;
vg = _vg_read(fi, pv->vg_name);
// Find the PV in this VG
if (vg) {
list_iterate(pvh, &vg->pvs) {
struct pv_list *vgpv = list_item(pvh, struct pv_list);
if (id_equal(&pv->id, &vgpv->pv->id)) {
vgpv->pv->status = pv->status;
vgpv->pv->size = pv->size;
// Not sure if it's worth doing these
vgpv->pv->pe_size = pv->pe_size;
vgpv->pv->pe_count = pv->pe_count;
vgpv->pv->pe_start = pv->pe_start;
vgpv->pv->pe_alloc_count = pv->pe_alloc_count;
// Write it back
_vg_write(fi, vg);
pool_free(fi->fmt->cmd->mem, vg);
return 1;
}
}
pool_free(fi->fmt->cmd->mem, vg);
}
// Can't handle PVs not in a VG
return 0;
***/
}
static int _pv_read(struct format_type *fmt, const char *pv_name,
struct physical_volume *pv)
{
struct pv_list *pvl;
struct list *vgh;
struct list *pvh;
struct list *names = pool_alloc(fmt->cmd->mem, sizeof(*names));
struct name_list *nl;
struct volume_group *vg;
struct id *id;
/* FIXME Push up to pv_read */
if (!(id = uuid_map_lookup_label(fmt->cmd->mem, fmt->cmd->um, pv_name))) {
stack;
return 0;
}
list_init(names);
if (!_get_vgs(fmt, names)) {
stack;
return 0;
}
list_iterate(vgh, names) {
nl = list_item(vgh, struct name_list);
if (!(vg = vg_read(fmt->cmd, nl->name))) {
log_error("format_text: _pv_read failed to read VG %s",
nl->name);
return 0;
}
list_iterate(pvh, &vg->pvs) {
pvl = list_item(pvh, struct pv_list);
if (id_equal(&pvl->pv->id, id)) {
memcpy(pv, pvl->pv, sizeof(*pv));
break;
}
}
}
pool_free(fmt->cmd->mem, names);
return 1;
}
static void _destroy_instance(struct format_instance *fid)
{
return;
}
static void _free_dirs(struct list *dir_list)
{
struct list *dl, *tmp;
list_iterate_safe(dl, tmp, dir_list) {
list_del(dl);
dbg_free(dl);
}
}
static void _destroy(struct format_type *fmt)
{
if (fmt->private) {
_free_dirs((struct list *) fmt->private);
dbg_free(fmt->private);
}
dbg_free(fmt);
}
static struct format_instance *_create_text_instance(struct format_type *fmt,
const char *vgname,
void *context)
{
struct format_instance *fid;
struct metadata_area *mda;
struct dir_list *dl;
struct list *dlh, *dir_list;
char path[PATH_MAX];
if (!(fid = pool_alloc(fmt->cmd->mem, sizeof(*fid)))) {
log_error("Couldn't allocate format instance object.");
return NULL;
}
fid->fmt = fmt;
list_init(&fid->metadata_areas);
if (!vgname) {
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
stack;
return NULL;
}
mda->metadata_locn = context;
list_add(&fid->metadata_areas, &mda->list);
} else {
dir_list = (struct list *) fmt->private;
list_iterate(dlh, dir_list) {
dl = list_item(dlh, struct dir_list);
if (lvm_snprintf(path, PATH_MAX, "%s/%s",
dl->dir, vgname) < 0) {
log_error("Name too long %s/%s", dl->dir,
vgname);
return NULL;
}
context = create_text_context(fmt, path, NULL);
if (!(mda = pool_alloc(fmt->cmd->mem, sizeof(*mda)))) {
stack;
return NULL;
}
mda->metadata_locn = context;
list_add(&fid->metadata_areas, &mda->list);
}
}
return fid;
}
void *create_text_context(struct format_type *fmt, const char *path,
const char *desc)
{
struct text_context *tc;
char *tmp;
if ((tmp = strstr(path, ".tmp")) && (tmp == path + strlen(path) - 4)) {
log_error("%s: Volume group filename may not end in .tmp",
path);
return NULL;
}
if (!(tc = pool_alloc(fmt->cmd->mem, sizeof(*tc)))) {
stack;
return NULL;
}
if (!(tc->path_live = pool_strdup(fmt->cmd->mem, path))) {
stack;
goto no_mem;
}
if (!(tc->path_edit = pool_alloc(fmt->cmd->mem, strlen(path) + 5))) {
stack;
goto no_mem;
}
sprintf(tc->path_edit, "%s.tmp", path);
if (!desc)
desc = "";
if (!(tc->desc = pool_strdup(fmt->cmd->mem, desc))) {
stack;
goto no_mem;
}
return (void *) tc;
no_mem:
pool_free(fmt->cmd->mem, tc);
log_err("Couldn't allocate text format context object.");
return NULL;
}
static struct format_handler _text_handler = {
get_vgs: _get_vgs,
get_pvs: _get_pvs,
pv_read: _pv_read,
pv_setup: _pv_setup,
pv_write: _pv_write,
vg_setup: _vg_setup,
vg_read: _vg_read,
vg_write: _vg_write,
destroy: _destroy
get_vgs: _get_vgs,
get_pvs: _get_pvs,
pv_read: _pv_read,
pv_setup: _pv_setup,
pv_write: _pv_write,
pv_commit: _pv_commit,
vg_setup: _vg_setup,
lv_setup: _lv_setup,
vg_read: _vg_read,
vg_write: _vg_write,
vg_remove: _vg_remove,
vg_commit: _vg_commit,
create_instance:_create_text_instance,
destroy_instance:_destroy_instance,
destroy: _destroy
};
struct format_instance *text_format_create(struct cmd_context *cmd,
const char *file,
struct uuid_map *um)
static int _add_dir(const char *dir, struct list *dir_list)
{
const char *no_alloc = "Couldn't allocate text format object.";
struct dir_list *dl;
struct format_instance *fi;
char *path;
struct text_c *tc;
if (!(fi = dbg_malloc(sizeof(*fi)))) {
log_err(no_alloc);
return NULL;
if (create_dir(dir)) {
if (!(dl = dbg_malloc(sizeof(struct list) + strlen(dir) + 1))) {
log_error("_add_dir allocation failed");
return 0;
}
strcpy(dl->dir, dir);
list_add(dir_list, &dl->list);
return 1;
}
if (!(path = dbg_strdup(file))) {
dbg_free(fi);
log_err(no_alloc);
return NULL;
}
if (!(tc = dbg_malloc(sizeof(*tc)))) {
dbg_free(fi);
dbg_free(path);
log_err(no_alloc);
return NULL;
}
tc->path = path;
tc->um = um;
fi->cmd = cmd;
fi->ops = &_text_handler;
fi->private = tc;
return fi;
return 0;
}
struct format_type *create_text_format(struct cmd_context *cmd)
{
struct format_type *fmt;
struct config_node *cn;
struct config_value *cv;
struct list *dir_list;
if (!(fmt = dbg_malloc(sizeof(*fmt)))) {
stack;
return NULL;
}
fmt->cmd = cmd;
fmt->ops = &_text_handler;
fmt->name = FMT_TEXT_NAME;
fmt->features = FMT_SEGMENTS;
if (!(dir_list = dbg_malloc(sizeof(struct list)))) {
log_error("Failed to allocate dir_list");
return NULL;
}
list_init(dir_list);
fmt->private = (void *) dir_list;
if (!(cn = find_config_node(cmd->cf->root, "metadata/dirs", '/'))) {
log_verbose("metadata/dirs not in config file: Defaulting "
"to /etc/lvm/metadata");
_add_dir("/etc/lvm/metadata", dir_list);
return fmt;
}
for (cv = cn->v; cv; cv = cv->next) {
if (cv->type != CFG_STRING) {
log_error("Invalid string in config file: "
"metadata/dirs");
goto err;
}
if (!_add_dir(cv->v.str, dir_list)) {
log_error("Failed to add %s to internal device cache",
cv->v.str);
goto err;
}
}
return fmt;
err:
_free_dirs(dir_list);
dbg_free(fmt);
return NULL;
}

View File

@@ -12,26 +12,28 @@
#include "uuid-map.h"
/*
* The archive format is used to maintain a set of metadata backup files
* in an archive directory.
* 'retain_days' is the minimum number of days that an archive file must
* be held for.
*
* 'min_archives' is the minimum number of archives required to be kept
* for each volume group.
* Archives a vg config. 'retain_days' is the minimum number of
* days that an archive file must be held for. 'min_archives' is
* the minimum number of archives required to be kept for each
* volume group.
*/
struct format_instance *archive_format_create(struct cmd_context *cmd,
const char *dir,
uint32_t retain_days,
uint32_t min_archives);
int archive_vg(struct volume_group *vg,
const char *dir,
const char *desc,
uint32_t retain_days,
uint32_t min_archive);
void backup_expire(struct format_instance *fi);
/*
* Displays a list of vg backups in a particular archive directory.
*/
int archive_list(struct cmd_context *cmd, struct uuid_map *um,
const char *dir, const char *vg);
/*
* The text format can read and write a volume_group to a file.
*/
struct format_instance *text_format_create(struct cmd_context *cmd,
const char *file,
struct uuid_map *um);
struct format_type *create_text_format(struct cmd_context *cmd);
void *create_text_context(struct format_type *fmt, const char *path,
const char *desc);
#endif

View File

@@ -24,8 +24,10 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size);
int read_flags(uint32_t *status, int type, struct config_value *cv);
int text_vg_export(FILE *fp, struct volume_group *vg);
struct volume_group *text_vg_import(struct cmd_context *cmd, const char *file,
struct uuid_map *um);
int text_vg_export(FILE *fp, struct volume_group *vg, const char *desc);
struct volume_group *text_vg_import(struct format_instance *fid,
const char *file,
struct uuid_map *um,
time_t *when, char **desc);
#endif

View File

@@ -10,16 +10,19 @@
#include "log.h"
#include "uuid.h"
#include "hash.h"
#include "toolcontext.h"
typedef int (*section_fn)(struct pool *mem,
struct volume_group *vg, struct config_node *pvn,
struct config_node *vgn, struct hash_table *pv_hash,
struct uuid_map *um);
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
struct volume_group * vg, struct config_node * pvn,
struct config_node * vgn,
struct hash_table * pv_hash, struct uuid_map * um);
#define _read_int32(root, path, result) \
get_config_uint32(root, path, '/', result)
#define _read_uint32(root, path, result) \
get_config_uint32(root, path, '/', result)
#define _read_int64(root, path, result) \
get_config_uint64(root, path, '/', result)
@@ -46,11 +49,10 @@ static int _read_id(struct id *id, struct config_node *cn, const char *path)
return 1;
}
static int _read_pv(struct pool *mem,
static int _read_pv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *pvn,
struct config_node *vgn,
struct hash_table *pv_hash,
struct uuid_map *um)
struct hash_table *pv_hash, struct uuid_map *um)
{
struct physical_volume *pv;
struct pv_list *pvl;
@@ -89,13 +91,15 @@ static int _read_pv(struct pool *mem,
if (!(pv->dev = uuid_map_lookup(um, &pv->id))) {
char buffer[64];
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
log_err("Couldn't find device.");
return 0;
}
else
log_err("Couldn't find device with uuid '%s'.", buffer);
log_err("Couldn't find device with uuid '%s'.", buffer);
return 0;
if (partial_mode())
vg->status |= PARTIAL_VG;
else
return 0;
}
if (!(pv->vg_name = pool_strdup(mem, vg->name))) {
@@ -130,7 +134,8 @@ static int _read_pv(struct pool *mem,
pv->pe_size = vg->extent_size;
pv->size = pv->pe_size * (uint64_t) pv->pe_count;
pv->pe_allocated = 0;
pv->pe_alloc_count = 0;
pv->fid = fid;
vg->pv_count++;
list_add(&vg->pvs, &pvl->list);
@@ -144,7 +149,7 @@ static void _insert_segment(struct logical_volume *lv,
struct list *segh;
struct stripe_segment *comp;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
comp = list_item(segh, struct stripe_segment);
if (comp->le > seg->le) {
@@ -174,8 +179,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
}
if (!_read_int32(sn, "stripes", &stripes)) {
log_err("Couldn't read 'stripes' for segment '%s'.",
sn->key);
log_err("Couldn't read 'stripes' for segment '%s'.", sn->key);
return 0;
}
@@ -185,6 +189,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
return 0;
}
seg->stripes = stripes;
seg->lv = lv;
if (!_read_int32(sn, "start_extent", &seg->le)) {
log_err("Couldn't read 'start_extent' for segment '%s'.",
@@ -236,9 +241,8 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
if (!(pv = hash_lookup(pv_hash, cv->v.str))) {
log_err("Couldn't find physical volume '%s' for "
"segment '%s'.",
cn->v->v.str ? cn->v->v.str : "NULL",
seg_name);
return 0;
cn->v->v.str ? cn->v->v.str : "NULL", seg_name);
return 0;
}
seg->area[s].pv = pv;
@@ -259,7 +263,7 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
* Adjust the extent counts in the pv and vg.
*/
allocated = seg->len / seg->stripes;
pv->pe_allocated += allocated;
pv->pe_alloc_count += allocated;
vg->free_count -= allocated;
}
@@ -331,7 +335,7 @@ static int _read_segments(struct pool *mem, struct volume_group *vg,
return 1;
}
static int _read_lv(struct pool *mem,
static int _read_lv(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *lvn,
struct config_node *vgn, struct hash_table *pv_hash,
struct uuid_map *um)
@@ -360,6 +364,13 @@ static int _read_lv(struct pool *mem,
lv->vg = vg;
/* FIXME: read full lvid */
if (!_read_id(&lv->lvid.id[1], lvn, "id")) {
log_err("Couldn't read uuid for logical volume %s.", lv->name);
return 0;
}
memcpy(&lv->lvid.id[0], &lv->vg->id, sizeof(lv->lvid.id[0]));
if (!(cn = find_config_node(lvn, "status", '/'))) {
log_err("Couldn't find status flags for logical volume.");
@@ -371,6 +382,13 @@ static int _read_lv(struct pool *mem,
return 0;
}
lv->minor = -1;
if ((lv->status & FIXED_MINOR) &&
!_read_int32(lvn, "minor", &lv->minor)) {
log_error("Couldn't read 'minor' value for logical volume.");
return 0;
}
if (!_read_int32(lvn, "read_ahead", &lv->read_ahead)) {
log_err("Couldn't read 'read_ahead' value for "
"logical volume.");
@@ -390,21 +408,75 @@ static int _read_lv(struct pool *mem,
return 1;
}
static int _read_sections(const char *section, section_fn fn,
static int _read_snapshot(struct format_instance *fid, struct pool *mem,
struct volume_group *vg, struct config_node *sn,
struct config_node *vgn, struct hash_table *pv_hash,
struct uuid_map *um)
{
uint32_t chunk_size;
const char *org_name, *cow_name;
struct logical_volume *org, *cow;
if (!(sn = sn->child)) {
log_err("Empty snapshot section.");
return 0;
}
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
log_err("Couldn't read chunk size for snapshot.");
return 0;
}
if (!(cow_name = find_config_str(sn, "cow_store", '/', NULL))) {
log_err("Snapshot cow storage not specified.");
return 0;
}
if (!(org_name = find_config_str(sn, "origin", '/', NULL))) {
log_err("Snapshot origin not specified.");
return 0;
}
if (!(cow = find_lv(vg, cow_name))) {
log_err("Unknown logical volume specified for "
"snapshot cow store.");
return 0;
}
if (!(org = find_lv(vg, org_name))) {
log_err("Unknown logical volume specified for "
"snapshot origin.");
return 0;
}
if (!vg_add_snapshot(org, cow, 1, chunk_size)) {
stack;
return 0;
}
return 1;
}
static int _read_sections(struct format_instance *fid,
const char *section, section_fn fn,
struct pool *mem,
struct volume_group *vg, struct config_node *vgn,
struct hash_table *pv_hash,
struct uuid_map *um)
struct uuid_map *um, int optional)
{
struct config_node *n;
if (!(n = find_config_node(vgn, section, '/'))) {
log_err("Couldn't find section '%s'.", section);
return 0;
if (!optional) {
log_err("Couldn't find section '%s'.", section);
return 0;
}
return 1;
}
for (n = n->child; n; n = n->sib) {
if (!fn(mem, vg, n, vgn, pv_hash, um)) {
if (!fn(fid, mem, vg, n, vgn, pv_hash, um)) {
stack;
return 0;
}
@@ -413,19 +485,19 @@ static int _read_sections(const char *section, section_fn fn,
return 1;
}
static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
static struct volume_group *_read_vg(struct format_instance *fid,
struct config_file *cf,
struct uuid_map *um)
{
struct config_node *vgn = cf->root, *cn;
struct config_node *vgn, *cn;
struct volume_group *vg;
struct hash_table *pv_hash = NULL;
struct pool *mem = fid->fmt->cmd->mem;
/* skip any top-level values */
for (vgn = cf->root; (vgn && vgn->v); vgn = vgn->sib) ;
if (!vgn) {
log_err("Couldn't find volume group.");
return NULL;
}
if (!(vgn = cf->root)) {
log_err("Couldn't find volume group in file.");
return NULL;
}
@@ -434,16 +506,39 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
stack;
return NULL;
}
vg->cmd = fid->fmt->cmd;
/* FIXME Determine format type from file contents */
/* eg Set to instance of fmt1 here if reading a format1 backup? */
vg->fid = fid;
if (!(vg->name = pool_strdup(mem, vgn->key))) {
stack;
goto bad;
}
if (!(vg->system_id = pool_zalloc(mem, NAME_LEN))) {
stack;
goto bad;
}
vgn = vgn->child;
if ((cn = find_config_node(vgn, "system_id", '/')) && cn->v) {
if (!cn->v->v.str) {
log_error("system_id must be a string");
goto bad;
}
strncpy(vg->system_id, cn->v->v.str, NAME_LEN);
}
if (!_read_id(&vg->id, vgn, "id")) {
log_err("Couldn't read uuid for volume group %s.",
vg->name);
log_err("Couldn't read uuid for volume group %s.", vg->name);
goto bad;
}
if (!_read_int32(vgn, "seqno", &vg->seqno)) {
log_err("Couldn't read 'seqno' for volume group %s.", vg->name);
goto bad;
}
@@ -492,29 +587,42 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
}
list_init(&vg->pvs);
if (!_read_sections("physical_volumes", _read_pv, mem, vg,
vgn, pv_hash, um)) {
if (!_read_sections(fid, "physical_volumes", _read_pv, mem, vg,
vgn, pv_hash, um, 0)) {
log_err("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->lvs);
if (!_read_sections("logical_volumes", _read_lv, mem, vg,
vgn, pv_hash, um)) {
if (!_read_sections(fid, "logical_volumes", _read_lv, mem, vg,
vgn, pv_hash, um, 1)) {
log_err("Couldn't read all logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
list_init(&vg->snapshots);
if (!_read_sections(fid, "snapshots", _read_snapshot, mem, vg,
vgn, pv_hash, um, 1)) {
log_err("Couldn't read all snapshots for volume group %s.",
vg->name);
goto bad;
}
hash_destroy(pv_hash);
if (vg->status & PARTIAL_VG) {
vg->status &= ~LVM_WRITE;
vg->status |= LVM_READ;
}
/*
* Finished.
*/
return vg;
bad:
bad:
if (pv_hash)
hash_destroy(pv_hash);
@@ -522,13 +630,30 @@ static struct volume_group *_read_vg(struct pool *mem, struct config_file *cf,
return NULL;
}
struct volume_group *text_vg_import(struct cmd_context *cmd,
static void _read_desc(struct pool *mem,
struct config_file *cf, time_t * when, char **desc)
{
const char *d;
unsigned int u = 0u;
d = find_config_str(cf->root, "description", '/', "");
*desc = pool_strdup(mem, d);
get_config_uint32(cf->root, "creation_time", '/', &u);
*when = u;
}
struct volume_group *text_vg_import(struct format_instance *fid,
const char *file,
struct uuid_map *um)
struct uuid_map *um,
time_t * when, char **desc)
{
struct volume_group *vg = NULL;
struct config_file *cf;
*desc = NULL;
*when = 0;
if (!(cf = create_config_file())) {
stack;
goto out;
@@ -539,14 +664,14 @@ struct volume_group *text_vg_import(struct cmd_context *cmd,
goto out;
}
if (!(vg = _read_vg(cmd->mem, cf, um))) {
if (!(vg = _read_vg(fid, cf, um))) {
stack;
goto out;
}
vg->cmd = cmd;
_read_desc(fid->fmt->cmd->mem, cf, when, desc);
out:
out:
destroy_config_file(cf);
return vg;
}

View File

@@ -21,7 +21,6 @@ struct labeller_i {
static struct list _labellers;
static struct labeller_i *_alloc_li(const char *name, struct labeller *l)
{
struct labeller_i *li;
@@ -45,7 +44,6 @@ static void _free_li(struct labeller_i *li)
dbg_free(li);
}
int label_init(void)
{
list_init(&_labellers);
@@ -82,7 +80,7 @@ struct labeller *label_get_handler(const char *name)
struct list *lih;
struct labeller_i *li;
list_iterate (lih, &_labellers) {
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (!strcmp(li->name, name))
return li->l;
@@ -96,7 +94,7 @@ static struct labeller *_find_labeller(struct device *dev)
struct list *lih;
struct labeller_i *li;
list_iterate (lih, &_labellers) {
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if (li->l->ops->can_handle(li->l, dev))
return li->l;
@@ -124,7 +122,7 @@ int label_read(struct device *dev, struct label **result)
struct list *lih;
struct labeller_i *li;
list_iterate (lih, &_labellers) {
list_iterate(lih, &_labellers) {
li = list_item(lih, struct labeller_i);
if ((r = li->l->ops->read(li->l, dev, result))) {
(*result)->labeller = li->l;

View File

@@ -27,324 +27,337 @@
#define BLOCK_SIZE 512
/* This is just the "struct lvm2_label" with the data pointer removed */
struct label_ondisk
{
uint32_t magic;
uint32_t crc;
uint64_t label1_loc;
uint64_t label2_loc;
uint16_t datalen;
uint16_t pad;
struct label_ondisk {
uint32_t magic;
uint32_t crc;
uint64_t label1_loc;
uint64_t label2_loc;
uint16_t datalen;
uint16_t pad;
uint32_t version[3];
char disk_type[32];
uint32_t version[3];
char disk_type[32];
};
struct filter_private
{
void *mem;
char disk_type[32];
uint32_t version[3];
int version_match;
struct filter_private {
void *mem;
char disk_type[32];
uint32_t version[3];
int version_match;
};
/* Calculate CRC32 of a buffer */
static uint32_t crc32(uint32_t initial, const unsigned char *databuf, size_t datalen)
static uint32_t crc32(uint32_t initial, const unsigned char *databuf,
size_t datalen)
{
static const u_int crctab[] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
uint32_t idx, crc = initial;
static const u_int crctab[] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
uint32_t idx, crc = initial;
for (idx = 0; idx < datalen; idx++) {
crc ^= *databuf++;
crc = (crc >> 4) ^ crctab[crc & 0xf];
crc = (crc >> 4) ^ crctab[crc & 0xf];
}
return crc;
for (idx = 0; idx < datalen; idx++) {
crc ^= *databuf++;
crc = (crc >> 4) ^ crctab[crc & 0xf];
crc = (crc >> 4) ^ crctab[crc & 0xf];
}
return crc;
}
/* Calculate crc */
static uint32_t calc_crc(struct label_ondisk *label, char *data)
{
uint32_t crcval = 0xffffffff;
uint32_t crcval = 0xffffffff;
crcval = crc32(crcval, (char *)&label->magic, sizeof(label->magic));
crcval = crc32(crcval, (char *)&label->label1_loc, sizeof(label->label1_loc));
crcval = crc32(crcval, (char *)&label->label2_loc, sizeof(label->label2_loc));
crcval = crc32(crcval, (char *)&label->datalen, sizeof(label->datalen));
crcval = crc32(crcval, (char *)&label->version, sizeof(label->version));
crcval = crc32(crcval, (char *)label->disk_type, strlen(label->disk_type));
crcval = crc32(crcval, (char *)data, label->datalen);
crcval = crc32(crcval, (char *) &label->magic, sizeof(label->magic));
crcval =
crc32(crcval, (char *) &label->label1_loc,
sizeof(label->label1_loc));
crcval =
crc32(crcval, (char *) &label->label2_loc,
sizeof(label->label2_loc));
crcval =
crc32(crcval, (char *) &label->datalen, sizeof(label->datalen));
crcval =
crc32(crcval, (char *) &label->version, sizeof(label->version));
crcval =
crc32(crcval, (char *) label->disk_type, strlen(label->disk_type));
crcval = crc32(crcval, (char *) data, label->datalen);
return crcval;
return crcval;
}
/* Calculate the locations we should find the labels in */
static inline void get_label_locations(uint64_t size, uint32_t sectsize, long *first, long *second)
static inline void get_label_locations(uint64_t size, uint32_t sectsize,
long *first, long *second)
{
*first = sectsize;
*second = size*BLOCK_SIZE - sectsize;
*first = sectsize;
*second = size * BLOCK_SIZE - sectsize;
}
/* Read a label off disk */
static int lvm2_label_read(struct labeller *l, struct device *dev, struct label **label)
static int lvm2_label_read(struct labeller *l, struct device *dev,
struct label **label)
{
uint64_t size;
uint32_t sectsize;
char *block;
struct label_ondisk *ondisk;
int status;
int iter;
long offset[2];
uint64_t size;
uint32_t sectsize;
char *block;
struct label_ondisk *ondisk;
int status;
int iter;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_open(dev, O_RDONLY))
return 0;
block = dbg_malloc(sectsize);
if (!block)
{
stack;
return 0;
}
ondisk = (struct label_ondisk *)block;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* If the first label is bad then use the second */
for (iter = 0; iter <= 1; iter++)
{
status = dev_read(dev, offset[iter], sectsize, block);
if (status)
{
struct label *incore;
int i;
int found_nul;
/* If the MAGIC doesn't match there's no point in
carrying on */
if (xlate32(ondisk->magic) != LABEL_MAGIC)
continue;
/* Look for a NUL in the disk_type string so we don't
SEGV is something has gone horribly wrong */
found_nul = 0;
for (i=0; i<sizeof(ondisk->disk_type); i++)
if (ondisk->disk_type[i] == '\0')
found_nul = 1;
if (!found_nul)
continue;
incore = dbg_malloc(sizeof(struct label));
if (incore == NULL)
{
if (!dev_get_size(dev, &size))
return 0;
}
/* Copy and convert endianness */
strncpy(incore->volume_type, ondisk->disk_type, sizeof(incore->volume_type));
incore->version[0] = xlate32(ondisk->version[0]);
incore->version[1] = xlate32(ondisk->version[1]);
incore->version[2] = xlate32(ondisk->version[2]);
incore->extra_len = xlate16(ondisk->datalen);
incore->extra_info = block + sizeof(struct label_ondisk);
if (!dev_get_sectsize(dev, &sectsize))
return 0;
/* Make sure datalen is a sensible size too */
if (incore->extra_len > sectsize)
continue;
if (!dev_open(dev, O_RDONLY))
return 0;
/* Check Crc */
if (xlate32(ondisk->crc) != calc_crc(ondisk, incore->extra_info))
{
log_error("Crc %d on device %s does not match. got %x, expected %x",
iter, dev_name(dev), xlate32(ondisk->crc), calc_crc(ondisk, incore->extra_info));
continue;
}
/* Check label locations match our view of the device */
if (xlate64(ondisk->label1_loc) != offset[0])
log_error("Label 1 location is wrong in label %d - check block size of the device\n",
iter);
if (xlate64(ondisk->label2_loc) != offset[1])
log_error("Label 2 location is wrong in label %d - the size of the device must have changed\n",
iter);
/* Copy to user's data area */
*label = incore;
incore->extra_info = dbg_malloc(incore->extra_len);
if (!incore->extra_info)
{
block = dbg_malloc(sectsize);
if (!block) {
stack;
return 0;
}
memcpy(incore->extra_info, block + sizeof(struct label_ondisk), incore->extra_len);
dbg_free(block);
dev_close(dev);
return 1;
}
}
ondisk = (struct label_ondisk *) block;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
dbg_free(block);
dev_close(dev);
/* If the first label is bad then use the second */
for (iter = 0; iter <= 1; iter++) {
status = dev_read(dev, offset[iter], sectsize, block);
if (status) {
struct label *incore;
int i;
int found_nul;
return 0;
/* If the MAGIC doesn't match there's no point in
carrying on */
if (xlate32(ondisk->magic) != LABEL_MAGIC)
continue;
/* Look for a NUL in the disk_type string so we don't
SEGV is something has gone horribly wrong */
found_nul = 0;
for (i = 0; i < sizeof(ondisk->disk_type); i++)
if (ondisk->disk_type[i] == '\0')
found_nul = 1;
if (!found_nul)
continue;
incore = dbg_malloc(sizeof(struct label));
if (incore == NULL) {
return 0;
}
/* Copy and convert endianness */
strncpy(incore->volume_type, ondisk->disk_type,
sizeof(incore->volume_type));
incore->version[0] = xlate32(ondisk->version[0]);
incore->version[1] = xlate32(ondisk->version[1]);
incore->version[2] = xlate32(ondisk->version[2]);
incore->extra_len = xlate16(ondisk->datalen);
incore->extra_info =
block + sizeof(struct label_ondisk);
/* Make sure datalen is a sensible size too */
if (incore->extra_len > sectsize)
continue;
/* Check Crc */
if (xlate32(ondisk->crc) !=
calc_crc(ondisk, incore->extra_info)) {
log_error
("Crc %d on device %s does not match. got %x, expected %x",
iter, dev_name(dev), xlate32(ondisk->crc),
calc_crc(ondisk, incore->extra_info));
continue;
}
/* Check label locations match our view of the device */
if (xlate64(ondisk->label1_loc) != offset[0])
log_error
("Label 1 location is wrong in label %d - check block size of the device\n",
iter);
if (xlate64(ondisk->label2_loc) != offset[1])
log_error
("Label 2 location is wrong in label %d - the size of the device must have changed\n",
iter);
/* Copy to user's data area */
*label = incore;
incore->extra_info = dbg_malloc(incore->extra_len);
if (!incore->extra_info) {
stack;
return 0;
}
memcpy(incore->extra_info,
block + sizeof(struct label_ondisk),
incore->extra_len);
dbg_free(block);
dev_close(dev);
return 1;
}
}
dbg_free(block);
dev_close(dev);
return 0;
}
/* Write a label to a device */
static int lvm2_label_write(struct labeller *l, struct device *dev, struct label *label)
static int lvm2_label_write(struct labeller *l, struct device *dev,
struct label *label)
{
uint64_t size;
uint32_t sectsize;
char *block;
struct label_ondisk *ondisk;
int status1, status2;
long offset[2];
uint64_t size;
uint32_t sectsize;
char *block;
struct label_ondisk *ondisk;
int status1, status2;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
/* Can the metata fit in the remaining space ? */
if (label->extra_len > sectsize - sizeof(struct label_ondisk))
return 0;
/* Can the metata fit in the remaining space ? */
if (label->extra_len > sectsize - sizeof(struct label_ondisk))
return 0;
block = dbg_malloc(sizeof(struct label_ondisk) + label->extra_len);
if (!block)
{
stack;
return 0;
}
ondisk = (struct label_ondisk *)block;
block = dbg_malloc(sizeof(struct label_ondisk) + label->extra_len);
if (!block) {
stack;
return 0;
}
ondisk = (struct label_ondisk *) block;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* Make into ondisk format */
ondisk->magic = xlate32(LABEL_MAGIC);
ondisk->version[0] = xlate32(label->version[0]);
ondisk->version[1] = xlate32(label->version[1]);
ondisk->version[2] = xlate32(label->version[2]);
ondisk->label1_loc = xlate64(offset[0]);
ondisk->label2_loc = xlate64(offset[1]);
ondisk->datalen = xlate16(label->extra_len);
strncpy(ondisk->disk_type, label->volume_type, sizeof(ondisk->disk_type));
memcpy(block+sizeof(struct label_ondisk), label->extra_info, label->extra_len);
ondisk->crc = xlate32(calc_crc(ondisk, label->extra_info));
/* Make into ondisk format */
ondisk->magic = xlate32(LABEL_MAGIC);
ondisk->version[0] = xlate32(label->version[0]);
ondisk->version[1] = xlate32(label->version[1]);
ondisk->version[2] = xlate32(label->version[2]);
ondisk->label1_loc = xlate64(offset[0]);
ondisk->label2_loc = xlate64(offset[1]);
ondisk->datalen = xlate16(label->extra_len);
strncpy(ondisk->disk_type, label->volume_type,
sizeof(ondisk->disk_type));
memcpy(block + sizeof(struct label_ondisk), label->extra_info,
label->extra_len);
ondisk->crc = xlate32(calc_crc(ondisk, label->extra_info));
/* Write metadata to disk */
if (!dev_open(dev, O_RDWR)) {
dbg_free(block);
return 0;
}
status1 =
dev_write(dev, offset[0],
sizeof(struct label_ondisk) + label->extra_len, block);
if (!status1)
log_error("Error writing label 1\n");
/* Write another at the end of the device */
status2 =
dev_write(dev, offset[1],
sizeof(struct label_ondisk) + label->extra_len, block);
if (!status2) {
char zerobuf[sizeof(struct label_ondisk)];
log_error("Error writing label 2\n");
/* Wipe the first label so it doesn't get confusing */
memset(zerobuf, 0, sizeof(struct label_ondisk));
if (!dev_write
(dev, offset[0], sizeof(struct label_ondisk),
zerobuf)) log_error("Error erasing label 1\n");
}
/* Write metadata to disk */
if (!dev_open(dev, O_RDWR))
{
dbg_free(block);
return 0;
}
dev_close(dev);
status1 = dev_write(dev, offset[0], sizeof(struct label_ondisk) + label->extra_len, block);
if (!status1)
log_error("Error writing label 1\n");
/* Write another at the end of the device */
status2 = dev_write(dev, offset[1], sizeof(struct label_ondisk) + label->extra_len, block);
if (!status2)
{
char zerobuf[sizeof(struct label_ondisk)];
log_error("Error writing label 2\n");
/* Wipe the first label so it doesn't get confusing */
memset(zerobuf, 0, sizeof(struct label_ondisk));
if (!dev_write(dev, offset[0], sizeof(struct label_ondisk), zerobuf))
log_error("Error erasing label 1\n");
}
dbg_free(block);
dev_close(dev);
return ((status1 != 0) && (status2 != 0));
return ((status1 != 0) && (status2 != 0));
}
/* Return 1 for Yes, 0 for No */
static int lvm2_is_labelled(struct labeller *l, struct device *dev)
{
struct label *label;
int status;
struct label *label;
int status;
status = lvm2_label_read(l, dev, &label);
if (status) label_free(label);
status = lvm2_label_read(l, dev, &label);
if (status)
label_free(label);
return status;
return status;
}
/* Check the device is labelled and has the right format_type */
static int _accept_format(struct dev_filter *f, struct device *dev)
{
struct label *l;
int status;
struct filter_private *fp = (struct filter_private *) f->private;
struct label *l;
int status;
struct filter_private *fp = (struct filter_private *) f->private;
status = lvm2_label_read(NULL, dev, &l);
status = lvm2_label_read(NULL, dev, &l);
if (status)
{
if (strcmp(l->volume_type, fp->disk_type) == 0)
{
switch (fp->version_match)
{
case VERSION_MATCH_EQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] == fp->version[1] &&
l->version[2] == fp->version[2])
return 1;
break;
if (status) {
if (strcmp(l->volume_type, fp->disk_type) == 0) {
switch (fp->version_match) {
case VERSION_MATCH_EQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] == fp->version[1] &&
l->version[2] == fp->version[2])
return 1;
break;
case VERSION_MATCH_LESSTHAN:
if (l->version[0] == fp->version[0] &&
l->version[1] < fp->version[1])
return 1;
break;
case VERSION_MATCH_LESSTHAN:
if (l->version[0] == fp->version[0] &&
l->version[1] < fp->version[1])
return 1;
break;
case VERSION_MATCH_LESSEQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] <= fp->version[1])
return 1;
break;
case VERSION_MATCH_LESSEQUAL:
if (l->version[0] == fp->version[0] &&
l->version[1] <= fp->version[1])
return 1;
break;
case VERSION_MATCH_ANY:
return 1;
}
case VERSION_MATCH_ANY:
return 1;
}
}
label_free(l);
}
label_free(l);
}
return 0;
return 0;
}
/* We just want to know if it's labelled or not */
static int _accept_label(struct dev_filter *f, struct device *dev)
{
return lvm2_is_labelled(NULL, dev);
return lvm2_is_labelled(NULL, dev);
}
static void _destroy(struct dev_filter *f)
{
struct filter_private *fp = (struct filter_private *) f->private;
struct filter_private *fp = (struct filter_private *) f->private;
}
/* A filter to find devices with a particular label type on them */
struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t version[3], int match_type)
struct dev_filter *lvm2_label_format_filter_create(char *disk_type,
uint32_t version[3],
int match_type)
{
struct pool *mem;
struct pool *mem;
struct filter_private *fp;
struct dev_filter *f;
@@ -353,7 +366,7 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
match_type != VERSION_MATCH_LESSTHAN &&
match_type != VERSION_MATCH_LESSEQUAL &&
match_type != VERSION_MATCH_ANY)
return 0;
return 0;
mem = pool_create(10 * 1024);
if (!mem) {
@@ -362,13 +375,13 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
stack;
goto bad;
}
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
stack;
goto bad;
stack;
goto bad;
}
fp->mem = mem;
@@ -383,7 +396,7 @@ struct dev_filter *lvm2_label_format_filter_create(char *disk_type, uint32_t ver
return f;
bad:
bad:
pool_destroy(mem);
return NULL;
}
@@ -401,13 +414,13 @@ struct dev_filter *lvm2_label_filter_create()
}
if (!(f = pool_zalloc(mem, sizeof(*f)))) {
stack;
goto bad;
stack;
goto bad;
}
if (!(fp = pool_zalloc(mem, sizeof(*fp)))) {
stack;
goto bad;
stack;
goto bad;
}
fp->mem = mem;
@@ -417,7 +430,7 @@ struct dev_filter *lvm2_label_filter_create()
return f;
bad:
bad:
pool_destroy(mem);
return NULL;
}
@@ -425,137 +438,132 @@ struct dev_filter *lvm2_label_filter_create()
/* Return 1 if both labels are identical, 0 if not or there was an error */
static int lvm2_labels_match(struct labeller *l, struct device *dev)
{
uint64_t size;
uint32_t sectsize;
char *block1;
char *block2;
struct label_ondisk *ondisk1;
struct label_ondisk *ondisk2;
int status = 0;
long offset[2];
uint64_t size;
uint32_t sectsize;
char *block1;
char *block2;
struct label_ondisk *ondisk1;
struct label_ondisk *ondisk2;
int status = 0;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
/* Allocate some space for the blocks we are going to read in */
block1 = dbg_malloc(sectsize);
if (!block1)
{
stack;
return 0;
}
block1 = dbg_malloc(sectsize);
if (!block1) {
stack;
return 0;
}
block2 = dbg_malloc(sectsize);
if (!block2)
{
stack;
block2 = dbg_malloc(sectsize);
if (!block2) {
stack;
dbg_free(block1);
return 0;
}
ondisk1 = (struct label_ondisk *) block1;
ondisk2 = (struct label_ondisk *) block2;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* Fetch em */
if (!dev_open(dev, O_RDONLY))
goto finish;
if (!dev_read(dev, offset[0], sectsize, block1))
goto finish;
if (!dev_read(dev, offset[1], sectsize, block2))
goto finish;
dev_close(dev);
/* Is it labelled? */
if (xlate32(ondisk1->magic) != LABEL_MAGIC)
goto finish;
/* Compare the whole structs */
if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0)
goto finish;
/* OK, check the data area */
if (memcmp(block1 + sizeof(struct label_ondisk),
block2 + sizeof(struct label_ondisk),
xlate16(ondisk1->datalen)) != 0)
goto finish;
/* They match !! */
status = 1;
finish:
dbg_free(block2);
dbg_free(block1);
return 0;
}
ondisk1 = (struct label_ondisk *)block1;
ondisk2 = (struct label_ondisk *)block2;
get_label_locations(size, sectsize, &offset[0], &offset[1]);
/* Fetch em */
if (!dev_open(dev, O_RDONLY))
goto finish;
if (!dev_read(dev, offset[0], sectsize, block1))
goto finish;
if (!dev_read(dev, offset[1], sectsize, block2))
goto finish;
dev_close(dev);
/* Is it labelled? */
if (xlate32(ondisk1->magic) != LABEL_MAGIC)
goto finish;
/* Compare the whole structs */
if (memcmp(ondisk1, ondisk2, sizeof(struct label_ondisk)) != 0)
goto finish;
/* OK, check the data area */
if (memcmp(block1 + sizeof(struct label_ondisk),
block2 + sizeof(struct label_ondisk),
xlate16(ondisk1->datalen)) != 0)
goto finish;
/* They match !! */
status = 1;
finish:
dbg_free(block2);
dbg_free(block1);
return status;
return status;
}
static int lvm2_label_remove(struct labeller *l, struct device *dev)
{
uint64_t size;
uint32_t sectsize;
char block[BLOCK_SIZE];
int status1, status2;
long offset[2];
uint64_t size;
uint32_t sectsize;
char block[BLOCK_SIZE];
int status1, status2;
long offset[2];
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_size(dev, &size))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_get_sectsize(dev, &sectsize))
return 0;
if (!dev_open(dev, O_RDWR))
{
dbg_free(block);
return 0;
}
if (!dev_open(dev, O_RDWR)) {
dbg_free(block);
return 0;
}
get_label_locations(size, sectsize, &offset[0], &offset[1]);
memset(block, 0, BLOCK_SIZE);
get_label_locations(size, sectsize, &offset[0], &offset[1]);
memset(block, 0, BLOCK_SIZE);
/* Blank out the first label */
status1 = dev_write(dev, offset[0], BLOCK_SIZE, block);
if (!status1)
log_error("Error erasing label 1\n");
/* Blank out the first label */
status1 = dev_write(dev, offset[0], BLOCK_SIZE, block);
if (!status1)
log_error("Error erasing label 1\n");
/* ...and the other at the end of the device */
status2 = dev_write(dev, offset[1], BLOCK_SIZE, block);
if (!status2)
log_error("Error erasing label 2\n");
/* ...and the other at the end of the device */
status2 = dev_write(dev, offset[1], BLOCK_SIZE, block);
if (!status2)
log_error("Error erasing label 2\n");
dev_close(dev);
dev_close(dev);
return ((status1 != 0) && (status2 != 0));
return ((status1 != 0) && (status2 != 0));
}
static void lvm2_label_destroy(struct labeller *l)
{
}
static struct label_ops handler_ops =
{
can_handle: lvm2_is_labelled,
write: lvm2_label_write,
remove: lvm2_label_remove,
read: lvm2_label_read,
verify: lvm2_labels_match,
destroy: lvm2_label_destroy,
static struct label_ops handler_ops = {
can_handle: lvm2_is_labelled,
write: lvm2_label_write,
remove: lvm2_label_remove,
read: lvm2_label_read,
verify: lvm2_labels_match,
destroy: lvm2_label_destroy,
};
static struct labeller this_labeller =
{
private : NULL,
ops : &handler_ops,
static struct labeller this_labeller = {
private: NULL,
ops: &handler_ops,
};
/* Don't know how this gets called... */
void lvm2_label_init()
{
label_register_handler("LVM2", &this_labeller);
label_register_handler("LVM2", &this_labeller);
}

View File

@@ -12,12 +12,12 @@
#include "dbg_malloc.h"
#include "log.h"
#include "label.h"
#include "pool.h"
struct uuid_map {
struct dev_filter *filter;
};
struct uuid_map *uuid_map_create(struct dev_filter *devices)
{
struct uuid_map *um;
@@ -67,4 +67,33 @@ struct device *uuid_map_lookup(struct uuid_map *um, struct id *id)
return dev;
}
struct id *uuid_map_lookup_label(struct pool *mem, struct uuid_map *um,
const char *name)
{
struct device *dev;
struct label *lab;
struct id *id;
if (!(dev = dev_cache_get(name, um->filter))) {
stack;
return NULL;
}
if (!label_read(dev, &lab)) {
stack;
return NULL;
}
if (!(id = pool_alloc(mem, sizeof(*id)))) {
stack;
label_destroy(lab);
return NULL;
}
memcpy(id, &lab->id, sizeof(*id));
label_destroy(lab);
return id;
}
#endif

View File

@@ -9,6 +9,7 @@
#include "uuid.h"
#include "dev-cache.h"
#include "pool.h"
/*
* Holds a mapping from uuid -> device.
@@ -22,5 +23,7 @@ void uuid_map_destroy(struct uuid_map *um);
* Find the device with a particular uuid.
*/
struct device *uuid_map_lookup(struct uuid_map *um, struct id *id);
struct id *uuid_map_lookup_label(struct pool *mem, struct uuid_map *um,
const char *name);
#endif

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "log.h"
#include "locking.h"
#include "locking_types.h"
#include "activate.h"
#include "config.h"
#include "defaults.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <signal.h>
static void *locking_module = NULL;
static void (*end_fn) (void) = NULL;
static int (*lock_fn) (struct cmd_context * cmd, const char *resource,
int flags) = NULL;
static int (*init_fn) (int type, struct config_file * cf) = NULL;
static int lock_resource(struct cmd_context *cmd, const char *resource,
int flags)
{
if (lock_fn)
return lock_fn(cmd, resource, flags);
else
return 0;
}
static void fin_external_locking(void)
{
if (end_fn)
end_fn();
dlclose(locking_module);
locking_module = NULL;
end_fn = NULL;
lock_fn = NULL;
}
int init_external_locking(struct locking_type *locking, struct config_file *cf)
{
char _lock_lib[PATH_MAX];
if (locking_module) {
log_error("External locking already initialised");
return 1;
}
locking->lock_resource = lock_resource;
locking->fin_locking = fin_external_locking;
/* Get locking module name from config file */
strncpy(_lock_lib, find_config_str(cf->root, "global/locking_library",
'/', "lvm2_locking.so"),
sizeof(_lock_lib));
/* If there is a module_dir in the config file then
look for the locking module in there first and then
using the normal dlopen(3) mechanism of looking
down LD_LIBRARY_PATH and /lib, /usr/lib.
If course, if the library name starts with a slash then
just use the name... */
if (_lock_lib[0] != '/') {
struct stat st;
char _lock_lib1[PATH_MAX];
lvm_snprintf(_lock_lib1, sizeof(_lock_lib1),
"%s/%s",
find_config_str(cf->root, "global/module_dir",
'/', "RUBBISH"), _lock_lib);
/* Does it exist ? */
if (stat(_lock_lib1, &st) == 0) {
strcpy(_lock_lib, _lock_lib1);
}
}
log_very_verbose("Opening locking library %s", _lock_lib);
locking_module = dlopen(_lock_lib, RTLD_LAZY);
if (!locking_module) {
log_error("Unable to open external locking module %s",
_lock_lib);
return 0;
}
/* Get the functions we need */
init_fn = dlsym(locking_module, "init_locking");
lock_fn = dlsym(locking_module, "lock_resource");
end_fn = dlsym(locking_module, "end_locking");
/* Are they all there ? */
if (!end_fn || !init_fn || !lock_fn) {
log_error ("Shared library %s does not contain locking "
"functions", _lock_lib);
dlclose(locking_module);
return 0;
}
log_verbose("Opened external locking module %s", _lock_lib);
return init_fn(2, cf);
}

260
lib/locking/file_locking.c Normal file
View File

@@ -0,0 +1,260 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "log.h"
#include "locking.h"
#include "locking_types.h"
#include "activate.h"
#include "config.h"
#include "defaults.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <signal.h>
struct lock_list {
struct list list;
int lf;
char *res;
};
static struct list _lock_list;
static char _lock_dir[NAME_LEN];
static sig_t _oldhandler;
static sigset_t _fullsigset, _intsigset;
static int _handler_installed;
static int _release_lock(const char *file)
{
struct lock_list *ll;
struct list *llh, *llt;
struct stat buf1, buf2;
list_iterate_safe(llh, llt, &_lock_list) {
ll = list_item(llh, struct lock_list);
if (!file || !strcmp(ll->res, file)) {
list_del(llh);
log_very_verbose("Unlocking %s", ll->res);
if (flock(ll->lf, LOCK_NB | LOCK_UN))
log_sys_error("flock", ll->res);
if (!flock(ll->lf, LOCK_NB | LOCK_EX) &&
!stat(ll->res, &buf1) &&
!fstat(ll->lf, &buf2) &&
!memcmp(&buf1.st_ino, &buf2.st_ino, sizeof(ino_t)))
if (unlink(ll->res))
log_sys_error("unlink", ll->res);
if (close(ll->lf) < 0)
log_sys_error("close", ll->res);
dbg_free(ll->res);
dbg_free(llh);
if (file)
return 1;
}
}
return 0;
}
void fin_file_locking(void)
{
_release_lock(NULL);
}
static void _remove_ctrl_c_handler()
{
siginterrupt(SIGINT, 0);
if (!_handler_installed || _oldhandler == SIG_ERR)
return;
sigprocmask(SIG_SETMASK, &_fullsigset, NULL);
if (signal(SIGINT, _oldhandler) == SIG_ERR)
log_sys_error("signal", "_remove_ctrl_c_handler");
_handler_installed = 0;
}
void _trap_ctrl_c(int signal)
{
_remove_ctrl_c_handler();
log_error("CTRL-c detected: giving up waiting for lock");
return;
}
static void _install_ctrl_c_handler()
{
if ((_oldhandler = signal(SIGINT, _trap_ctrl_c)) == SIG_ERR)
return;
sigprocmask(SIG_SETMASK, &_intsigset, NULL);
siginterrupt(SIGINT, 1);
_handler_installed = 1;
}
static int _lock_file(const char *file, int flags)
{
int operation;
int r = 1;
struct lock_list *ll;
struct stat buf1, buf2;
switch (flags & LCK_TYPE_MASK) {
case LCK_READ:
operation = LOCK_SH;
break;
case LCK_WRITE:
operation = LOCK_EX;
break;
case LCK_UNLOCK:
return _release_lock(file);
default:
log_error("Unrecognised lock type: %d", flags & LCK_TYPE_MASK);
return 0;
}
if (!(ll = dbg_malloc(sizeof(struct lock_list))))
return 0;
if (!(ll->res = dbg_strdup(file))) {
dbg_free(ll);
return 0;
}
ll->lf = -1;
log_very_verbose("Locking %s", ll->res);
do {
if (ll->lf > -1)
close(ll->lf);
if ((ll->lf = open(file, O_CREAT | O_APPEND | O_RDWR, 0777))
< 0) {
log_sys_error("open", file);
goto err;
}
if ((flags & LCK_NONBLOCK))
operation |= LOCK_NB;
else
_install_ctrl_c_handler();
r = flock(ll->lf, operation);
if (!(flags & LCK_NONBLOCK))
_remove_ctrl_c_handler();
if (r) {
log_sys_error("flock", ll->res);
goto err;
}
if (!stat(ll->res, &buf1) && !fstat(ll->lf, &buf2) &&
!memcmp(&buf1.st_ino, &buf2.st_ino, sizeof(ino_t)))
break;
} while (!(flags & LCK_NONBLOCK));
list_add(&_lock_list, &ll->list);
return 1;
err:
dbg_free(ll->res);
dbg_free(ll);
return 0;
}
int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
{
char lockfile[PATH_MAX];
switch (flags & LCK_SCOPE_MASK) {
case LCK_VG:
if (!resource || !*resource)
lvm_snprintf(lockfile, sizeof(lockfile),
"%s/P_orphans", _lock_dir);
else
lvm_snprintf(lockfile, sizeof(lockfile),
"%s/V_%s", _lock_dir, resource);
if (!_lock_file(lockfile, flags))
return 0;
break;
case LCK_LV:
/* Skip if driver isn't loaded */
/* FIXME Use /proc/misc instead? */
if (!driver_version(NULL, 0))
return 1;
switch (flags & LCK_TYPE_MASK) {
case LCK_UNLOCK:
if (!lv_resume_if_active(cmd, resource))
return 0;
break;
case LCK_READ:
if (!lv_activate(cmd, resource))
return 0;
break;
case LCK_WRITE:
if (!lv_suspend_if_active(cmd, resource))
return 0;
break;
case LCK_EXCL:
if (!lv_deactivate(cmd, resource))
return 0;
break;
default:
break;
}
break;
default:
log_error("Unrecognised lock scope: %d",
flags & LCK_SCOPE_MASK);
return 0;
}
return 1;
}
int init_file_locking(struct locking_type *locking, struct config_file *cf)
{
locking->lock_resource = lock_resource;
locking->fin_locking = fin_file_locking;
/* Get lockfile directory from config file */
strncpy(_lock_dir, find_config_str(cf->root, "global/locking_dir",
'/', DEFAULT_LOCK_DIR),
sizeof(_lock_dir));
if (!create_dir(_lock_dir))
return 0;
list_init(&_lock_list);
if (sigfillset(&_intsigset) || sigfillset(&_fullsigset)) {
log_sys_error("sigfillset", "init_file_locking");
return 0;
}
if (sigdelset(&_intsigset, SIGINT)) {
log_sys_error("sigdelset", "init_file_locking");
return 0;
}
return 1;
}

149
lib/locking/locking.c Normal file
View File

@@ -0,0 +1,149 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "log.h"
#include "locking.h"
#include "locking_types.h"
#include "lvm-string.h"
#include "activate.h"
#include <signal.h>
static struct locking_type _locking;
static sigset_t _oldset;
static int _lock_count = 0; /* Number of locks held */
static int _signals_blocked = 0;
static void _block_signals(void)
{
sigset_t set;
if (_signals_blocked)
return;
if (sigfillset(&set)) {
log_sys_error("sigfillset", "_block_signals");
return;
}
if (sigprocmask(SIG_SETMASK, &set, &_oldset)) {
log_sys_error("sigprocmask", "_block_signals");
return;
}
_signals_blocked = 1;
return;
}
static void _unblock_signals(void)
{
/* Don't unblock signals while any locks are held */
if (!_signals_blocked || _lock_count)
return;
if (sigprocmask(SIG_SETMASK, &_oldset, NULL)) {
log_sys_error("sigprocmask", "_block_signals");
return;
}
_signals_blocked = 0;
return;
}
static inline void _update_lock_count(int flags)
{
if ((flags & LCK_TYPE_MASK) == LCK_UNLOCK)
_lock_count--;
else
_lock_count++;
}
/*
* Select a locking type
*/
int init_locking(int type, struct config_file *cf)
{
switch (type) {
case 0:
init_no_locking(&_locking, cf);
log_print("WARNING: Locking disabled. Be careful! "
"This could corrupt your metadata.");
break;
case 1:
if (!init_file_locking(&_locking, cf))
return 0;
log_very_verbose("File-based locking enabled.");
break;
case 2:
if (!init_external_locking(&_locking, cf))
return 0;
log_very_verbose("External locking enabled.");
break;
default:
log_error("Unknown locking type requested.");
return 0;
}
return 1;
}
void fin_locking(void)
{
_locking.fin_locking();
}
/*
* VG locking is by VG name.
* FIXME This should become VG uuid.
*/
int _lock_vol(struct cmd_context *cmd, const char *resource, int flags)
{
_block_signals();
if (!(_locking.lock_resource(cmd, resource, flags))) {
_unblock_signals();
return 0;
}
_update_lock_count(flags);
_unblock_signals();
return 1;
}
int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
{
char resource[258];
switch (flags & LCK_SCOPE_MASK) {
case LCK_VG: /* Lock VG to change on-disk metadata. */
case LCK_LV: /* Suspends LV if it's active. */
strncpy(resource, (char *) vol, sizeof(resource));
break;
default:
log_error("Unrecognised lock scope: %d",
flags & LCK_SCOPE_MASK);
return 0;
}
if (!_lock_vol(cmd, resource, flags))
return 0;
/* Perform immediate unlock unless LCK_HOLD set */
if (!(flags & LCK_HOLD) && ((flags & LCK_TYPE_MASK) != LCK_UNLOCK)) {
if (!_lock_vol(cmd, resource,
(flags & ~LCK_TYPE_MASK) | LCK_UNLOCK))
return 0;
}
return 1;
}

67
lib/locking/locking.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "metadata.h"
#include "uuid.h"
#include "config.h"
int init_locking(int type, struct config_file *cf);
void fin_locking(void);
/*
* LCK_VG:
* Lock/unlock on-disk volume group data
* Use "" to lock orphan PVs
* char *vol holds volume group name
*
* LCK_LV:
* Lock/unlock an individual logical volume
* char *vol holds lvid
*/
int lock_vol(struct cmd_context *cmd, const char *vol, int flags);
/*
* Lock type - these numbers are the same as VMS and the IBM DLM
*/
#define LCK_TYPE_MASK 0x000000FF
#define LCK_NULL 0x00000000 /* LCK$_NLMODE */
#define LCK_READ 0x00000001 /* LCK$_CRMODE */
/* LCK$_CWMODE */
/* LCK$_PRMODE */
#define LCK_WRITE 0x00000004 /* LCK$_PWMODE */
#define LCK_EXCL 0x00000005 /* LCK$_EXMODE */
#define LCK_UNLOCK 0x00000010 /* This is ours */
/*
* Lock scope
*/
#define LCK_SCOPE_MASK 0x0000FF00
#define LCK_VG 0x00000000
#define LCK_LV 0x00000100
/*
* Lock bits
*/
#define LCK_NONBLOCK 0x00010000 /* Don't block waiting for lock? */
#define LCK_HOLD 0x00020000 /* Hold lock when lock_vol returns? */
/*
* Common combinations
*/
#define LCK_VG_READ (LCK_VG | LCK_READ | LCK_HOLD)
#define LCK_VG_WRITE (LCK_VG | LCK_WRITE | LCK_HOLD)
#define LCK_VG_UNLOCK (LCK_VG | LCK_UNLOCK)
#define LCK_LV_DEACTIVATE (LCK_LV | LCK_EXCL)
#define LCK_LV_SUSPEND (LCK_LV | LCK_WRITE)
#define LCK_LV_ACTIVATE (LCK_LV | LCK_READ)
#define LCK_LV_UNLOCK (LCK_LV | LCK_UNLOCK)
#define unlock_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_UNLOCK)
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "metadata.h"
#include "config.h"
typedef int (*lock_resource_fn)(struct cmd_context *cmd, const char *resource,
int flags);
typedef void (*fin_lock_fn)(void);
struct locking_type {
lock_resource_fn lock_resource;
fin_lock_fn fin_locking;
};
/*
* Locking types
*/
int init_no_locking(struct locking_type *locking, struct config_file *cf);
int init_file_locking(struct locking_type *locking, struct config_file *cf);
int init_external_locking(struct locking_type *locking, struct config_file *cf);

60
lib/locking/no_locking.c Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*
*/
#include "log.h"
#include "locking.h"
#include "locking_types.h"
#include "lvm-string.h"
#include "activate.h"
#include <signal.h>
/*
* No locking
*/
static void _no_fin_locking(void)
{
return;
}
static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
int flags)
{
switch (flags & LCK_SCOPE_MASK) {
case LCK_VG:
break;
case LCK_LV:
switch (flags & LCK_TYPE_MASK) {
case LCK_UNLOCK:
return lv_resume_if_active(cmd, resource);
case LCK_READ:
return lv_activate(cmd, resource);
case LCK_WRITE:
return lv_suspend_if_active(cmd, resource);
case LCK_EXCL:
return lv_deactivate(cmd, resource);
default:
break;
}
break;
default:
log_error("Unrecognised lock scope: %d",
flags & LCK_SCOPE_MASK);
return 0;
}
return 1;
}
int init_no_locking(struct locking_type *locking, struct config_file *cf)
{
locking->lock_resource = _no_lock_resource;
locking->fin_locking = _no_fin_locking;
return 1;
}

View File

@@ -17,137 +17,162 @@ static int _debug_level = 0;
static int _syslog = 0;
static int _indent = 1;
static int _log_cmd_name = 0;
static int _log_suppress = 0;
static char _cmd_name[30] = "";
static char _msg_prefix[30] = " ";
void init_log(FILE *fp) {
void init_log(FILE * fp)
{
_log = fp;
}
void init_syslog(int facility) {
void init_syslog(int facility)
{
openlog("lvm", LOG_PID, facility);
_syslog = 1;
}
void fin_log() {
void log_suppress(int suppress)
{
_log_suppress = suppress;
}
void fin_log()
{
_log = 0;
}
void fin_syslog() {
void fin_syslog()
{
if (_syslog)
closelog();
_syslog = 0;
}
void init_verbose(int level) {
void init_verbose(int level)
{
_verbose_level = level;
}
void init_test(int level) {
void init_test(int level)
{
_test = level;
if (_test)
log_print("Test mode. Metadata will NOT be updated.");
}
void init_partial(int level) {
void init_partial(int level)
{
_partial = level;
}
void init_cmd_name(int status) {
void init_cmd_name(int status)
{
_log_cmd_name = status;
}
void set_cmd_name(const char *cmd) {
void set_cmd_name(const char *cmd)
{
if (!_log_cmd_name)
return;
strncpy(_cmd_name, cmd, sizeof(_cmd_name));
_cmd_name[sizeof(_cmd_name) - 1] = '\0';
}
void init_msg_prefix(const char *prefix) {
void init_msg_prefix(const char *prefix)
{
strncpy(_msg_prefix, prefix, sizeof(_msg_prefix));
_msg_prefix[sizeof(_msg_prefix) - 1] = '\0';
}
void init_indent(int indent) {
void init_indent(int indent)
{
_indent = indent;
}
int test_mode() {
int test_mode()
{
return _test;
}
int partial_mode() {
int partial_mode()
{
return _partial;
}
void init_debug(int level) {
void init_debug(int level)
{
_debug_level = level;
}
int debug_level() {
int debug_level()
{
return _debug_level;
}
void print_log(int level, const char *file, int line, const char *format, ...) {
void print_log(int level, const char *file, int line, const char *format, ...)
{
va_list ap;
va_start(ap, format);
switch(level) {
case _LOG_DEBUG:
if (_verbose_level > 2 && format[1]) {
printf("%s%s", _cmd_name, _msg_prefix);
if (_indent)
printf(" ");
vprintf(format, ap);
putchar('\n');
}
break;
if (!_log_suppress) {
va_start(ap, format);
switch (level) {
case _LOG_DEBUG:
if (!strcmp("<backtrace>", format))
break;
if (_verbose_level > 2) {
printf("%s%s", _cmd_name, _msg_prefix);
if (_indent)
printf(" ");
vprintf(format, ap);
putchar('\n');
}
break;
case _LOG_INFO:
if (_verbose_level > 1) {
case _LOG_INFO:
if (_verbose_level > 1) {
printf("%s%s", _cmd_name, _msg_prefix);
if (_indent)
printf(" ");
vprintf(format, ap);
putchar('\n');
}
break;
case _LOG_NOTICE:
if (_verbose_level) {
printf("%s%s", _cmd_name, _msg_prefix);
if (_indent)
printf(" ");
vprintf(format, ap);
putchar('\n');
}
break;
case _LOG_WARN:
printf("%s%s", _cmd_name, _msg_prefix);
if (_indent)
printf(" ");
vprintf(format, ap);
putchar('\n');
break;
case _LOG_ERR:
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
vfprintf(stderr, format, ap);
fputc('\n', stderr);
break;
case _LOG_FATAL:
default:
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
vfprintf(stderr, format, ap);
fputc('\n', stderr);
break;
;
}
break;
case _LOG_NOTICE:
if (_verbose_level) {
printf("%s%s", _cmd_name, _msg_prefix);
if (_indent)
printf(" ");
vprintf(format, ap);
putchar('\n');
}
break;
case _LOG_WARN:
printf("%s%s", _cmd_name, _msg_prefix);
vprintf(format, ap);
putchar('\n');
break;
case _LOG_ERR:
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
vfprintf(stderr, format, ap);
fputc('\n',stderr);
break;
case _LOG_FATAL:
default:
fprintf(stderr, "%s%s", _cmd_name, _msg_prefix);
vfprintf(stderr, format, ap);
fputc('\n',stderr);
break;
;
va_end(ap);
}
va_end(ap);
if (level > _debug_level)
return;
if (_log) {
fprintf(_log, "%s:%d %s%s", file, line, _cmd_name,
_msg_prefix);
fprintf(_log, "%s:%d %s%s", file, line, _cmd_name, _msg_prefix);
va_start(ap, format);
vfprintf(_log, format, ap);
@@ -158,9 +183,8 @@ void print_log(int level, const char *file, int line, const char *format, ...) {
}
if (_syslog) {
va_start(ap, format);
va_start(ap, format);
vsyslog(level, format, ap);
va_end(ap);
}
}

View File

@@ -15,7 +15,6 @@
* log_verbose - print to stdout if verbose is set (-v)
* log_very_verbose - print to stdout if verbose is set twice (-vv)
* log_debug - print to stdout if verbose is set three times (-vvv)
* (suppressed if single-character string such as with 'stack')
*
* In addition, messages will be logged to file or syslog if they
* are more serious than the log level specified with the log/debug_level
@@ -60,6 +59,9 @@ int test_mode(void);
int partial_mode(void);
int debug_level(void);
/* Suppress messages to stdout/stderr */
void log_suppress(int suppress);
void print_log(int level, const char *file, int line, const char *format, ...)
__attribute__ (( format (printf, 4, 5) ));
@@ -72,7 +74,7 @@ void print_log(int level, const char *file, int line, const char *format, ...)
#define log_err(x...) plog(_LOG_ERR, x)
#define log_fatal(x...) plog(_LOG_FATAL, x)
#define stack log_debug( "s" ) /* Backtrace on error */
#define stack log_debug("<backtrace>") /* Backtrace on error */
#define log_error(fmt, args...) log_err(fmt , ## args)
#define log_print(fmt, args...) log_warn(fmt , ## args)

View File

@@ -9,6 +9,7 @@
#include "log.h"
#include "dbg_malloc.h"
#include "lvm-string.h"
#include "toolcontext.h"
#include <assert.h>
@@ -24,7 +25,7 @@ static void _get_extents(struct stripe_segment *seg)
for (s = 0; s < seg->stripes; s++) {
pv = seg->area[s].pv;
count = seg->len / seg->stripes;
pv->pe_allocated += count;
pv->pe_alloc_count += count;
}
}
@@ -37,8 +38,8 @@ static void _put_extents(struct stripe_segment *seg)
pv = seg->area[s].pv;
count = seg->len / seg->stripes;
assert(pv->pe_allocated >= count);
pv->pe_allocated -= count;
assert(pv->pe_alloc_count >= count);
pv->pe_alloc_count -= count;
}
}
@@ -57,7 +58,7 @@ static struct stripe_segment *_alloc_segment(struct pool *mem, int stripes)
static int _alloc_stripe_area(struct logical_volume *lv, uint32_t stripes,
uint32_t stripe_size,
struct pv_area **areas, uint32_t *index)
struct pv_area **areas, uint32_t * index)
{
uint32_t count = lv->le_count - *index;
uint32_t per_area = count / stripes;
@@ -116,8 +117,8 @@ static int _alloc_striped(struct logical_volume *lv,
struct pv_map *pvm;
size_t len;
list_iterate (pvmh, pvms)
pv_count++;
list_iterate(pvmh, pvms)
pv_count++;
/* allocate an array of pv_areas, one candidate per pv */
len = sizeof(*areas) * pv_count;
@@ -129,7 +130,7 @@ static int _alloc_striped(struct logical_volume *lv,
while (allocated != lv->le_count) {
index = 0;
list_iterate (pvmh, pvms) {
list_iterate(pvmh, pvms) {
pvm = list_item(pvmh, struct pv_map);
if (list_empty(&pvm->areas))
@@ -142,8 +143,7 @@ static int _alloc_striped(struct logical_volume *lv,
if (index < stripes) {
log_error("Insufficient allocatable extents suitable "
"for striping for logical volume "
"%s: %u required",
lv->name, lv->le_count);
"%s: %u required", lv->name, lv->le_count);
goto out;
}
@@ -158,19 +158,18 @@ static int _alloc_striped(struct logical_volume *lv,
}
r = 1;
out:
out:
dbg_free(areas);
return r;
}
/*
* The heart of the allocation code. This function takes a
* pv_area and allocates it to the lv. If the lv doesn't need
* the complete area then the area is split, otherwise the area
* is unlinked from the pv_map.
*/
static int _alloc_linear_area(struct logical_volume *lv, uint32_t *index,
static int _alloc_linear_area(struct logical_volume *lv, uint32_t * index,
struct pv_map *map, struct pv_area *pva)
{
uint32_t count, remaining;
@@ -267,7 +266,7 @@ static int _alloc_simple(struct logical_volume *lv,
}
}
done:
done:
if (allocated != lv->le_count) {
log_error("Insufficient allocatable logical extents (%u) "
"for logical volume %s: %u required",
@@ -395,7 +394,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
if (stripes > list_size(acceptable_pvs)) {
log_error("Number of stripes (%u) must not exceed "
"number of physical volumes (%d)", stripes,
list_size(acceptable_pvs));
list_size(acceptable_pvs));
return NULL;
}
@@ -415,7 +414,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
lv = ll->lv;
strcpy(lv->id.uuid, "");
lv->vg = vg;
if (!(lv->name = pool_strdup(cmd->mem, name))) {
stack;
@@ -424,9 +423,9 @@ struct logical_volume *lv_create(struct format_instance *fi,
lv->status = status;
lv->read_ahead = 0;
lv->size = extents * vg->extent_size;
lv->minor = -1;
lv->size = (uint64_t) extents *vg->extent_size;
lv->le_count = extents;
lv->vg = vg;
list_init(&lv->segments);
if (!_allocate(vg, lv, acceptable_pvs, 0u, stripes, stripe_size)) {
@@ -434,7 +433,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
goto bad;
}
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
goto bad;
}
@@ -444,7 +443,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
return lv;
bad:
bad:
if (ll)
pool_free(cmd->mem, ll);
@@ -459,8 +458,7 @@ int lv_reduce(struct format_instance *fi,
uint32_t count = extents;
for (segh = lv->segments.p;
(segh != &lv->segments) && count;
segh = segh->p) {
(segh != &lv->segments) && count; segh = segh->p) {
seg = list_item(segh, struct stripe_segment);
if (seg->len <= count) {
@@ -478,9 +476,10 @@ int lv_reduce(struct format_instance *fi,
}
lv->le_count -= extents;
lv->size = lv->le_count * lv->vg->extent_size;
lv->size = (uint64_t) lv->le_count * lv->vg->extent_size;
lv->vg->free_count += extents;
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
return 0;
}
@@ -491,16 +490,13 @@ int lv_reduce(struct format_instance *fi,
int lv_extend(struct format_instance *fi,
struct logical_volume *lv,
uint32_t stripes, uint32_t stripe_size,
uint32_t extents,
struct list *acceptable_pvs)
uint32_t extents, struct list *acceptable_pvs)
{
uint32_t old_le_count = lv->le_count;
uint64_t old_size = lv->size;
lv->le_count += extents;
lv->size += extents * lv->vg->extent_size;
/* FIXME: Format1 must ensure stripes is consistent with 1st seg */
lv->size += (uint64_t) extents *lv->vg->extent_size;
if (!_allocate(lv->vg, lv, acceptable_pvs, old_le_count,
stripes, stripe_size)) {
@@ -515,7 +511,7 @@ int lv_extend(struct format_instance *fi,
return 0;
}
if (fi->ops->lv_setup && !fi->ops->lv_setup(fi, lv)) {
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
stack;
return 0;
}
@@ -535,8 +531,8 @@ int lv_remove(struct volume_group *vg, struct logical_volume *lv)
}
/* iterate through the lv's segments freeing off the pe's */
list_iterate (segh, &lv->segments)
_put_extents(list_item(segh, struct stripe_segment));
list_iterate(segh, &lv->segments)
_put_extents(list_item(segh, struct stripe_segment));
vg->lv_count--;
vg->free_count += lv->le_count;

View File

@@ -41,7 +41,7 @@ int lv_merge_segments(struct logical_volume *lv)
struct list *segh;
struct stripe_segment *current, *prev = NULL;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
current = list_item(segh, struct stripe_segment);
if (_merge(prev, current))

View File

@@ -9,6 +9,10 @@
#include "device.h"
#include "dev-cache.h"
#include "metadata.h"
#include "toolcontext.h"
#include "lvm-string.h"
#include "uuid.h"
#include "vgcache.h"
#include <string.h>
@@ -17,17 +21,17 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
{
struct pv_list *pvl;
struct physical_volume *pv;
struct pool *mem = fi->cmd->mem;
struct pool *mem = fi->fmt->cmd->mem;
log_verbose("Adding physical volume '%s' to volume group '%s'",
pv_name, vg->name);
if (!(pvl = pool_alloc(mem, sizeof (*pvl)))) {
if (!(pvl = pool_alloc(mem, sizeof(*pvl)))) {
log_error("pv_list allocation for '%s' failed", pv_name);
return 0;
}
if (!(pv = fi->ops->pv_read(fi, pv_name))) {
if (!(pv = pv_read(fi->fmt->cmd, pv_name))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
@@ -44,25 +48,23 @@ int _add_pv_to_vg(struct format_instance *fi, struct volume_group *vg,
return 0;
}
/* Units of 512-byte sectors */
if (!dev_get_size(pv->dev, &pv->size)) {
stack;
return 0;
}
/* Units of 512-byte sectors */
pv->pe_size = vg->extent_size;
/* FIXME Do proper rounding-up alignment? */
/* Reserved space for label; this holds 0 for PVs created by LVM1 */
if (pv->pe_start < PE_ALIGN)
pv->pe_start = PE_ALIGN;
/*
* The next two fields should be corrected
* by fi->pv_setup.
*/
pv->pe_start = 0;
pv->pe_count = pv->size / pv->pe_size;
pv->pe_count = (pv->size - pv->pe_start) / pv->pe_size;
pv->pe_allocated = 0;
pv->pe_alloc_count = 0;
if (!fi->ops->pv_setup(fi, pv, vg)) {
if (!fi->fmt->ops->pv_setup(fi, pv, vg)) {
log_error("Format-specific setup of physical volume '%s' "
"failed.", pv_name);
return 0;
@@ -116,42 +118,43 @@ const char *strip_dir(const char *vg_name, const char *dev_dir)
return vg_name;
}
struct volume_group *vg_create(struct format_instance *fi, const char *vg_name,
struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
uint32_t extent_size, int max_pv, int max_lv,
int pv_count, char **pv_names)
{
struct volume_group *vg;
struct pool *mem = fi->cmd->mem;
struct pool *mem = cmd->mem;
if (!(vg = pool_alloc(mem, sizeof (*vg)))) {
if (!(vg = pool_zalloc(mem, sizeof(*vg)))) {
stack;
return NULL;
}
/* is this vg name already in use ? */
init_partial(1);
if (fi->ops->vg_read(fi, vg_name)) {
if (vg_read(cmd, vg_name)) {
log_err("A volume group called '%s' already exists.", vg_name);
goto bad;
}
init_partial(0);
if (!id_create(&vg->id)) {
log_err("Couldn't create uuid for volume group '%s'.",
vg_name);
log_err("Couldn't create uuid for volume group '%s'.", vg_name);
goto bad;
}
/* Strip dev_dir if present */
vg_name = strip_dir(vg_name, fi->cmd->dev_dir);
vg_name = strip_dir(vg_name, cmd->dev_dir);
vg->cmd = fi->cmd;
vg->cmd = cmd;
if (!(vg->name = pool_strdup(mem, vg_name))) {
stack;
goto bad;
}
vg->seqno = 0;
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
vg->system_id = pool_alloc(mem, NAME_LEN);
*vg->system_id = '\0';
@@ -169,29 +172,38 @@ struct volume_group *vg_create(struct format_instance *fi, const char *vg_name,
vg->lv_count = 0;
list_init(&vg->lvs);
if (!fi->ops->vg_setup(fi, vg)) {
vg->snapshot_count = 0;
list_init(&vg->snapshots);
if (!(vg->fid = cmd->fmt->ops->create_instance(cmd->fmt, vg_name,
NULL))) {
log_error("Failed to create format instance");
goto bad;
}
if (!vg->fid->fmt->ops->vg_setup(vg->fid, vg)) {
log_error("Format specific setup of volume group '%s' failed.",
vg_name);
goto bad;
}
/* attach the pv's */
if (!vg_extend(fi, vg, pv_count, pv_names))
if (!vg_extend(vg->fid, vg, pv_count, pv_names))
goto bad;
return vg;
bad:
bad:
pool_free(mem, vg);
return NULL;
}
struct physical_volume *pv_create(struct format_instance *fi,
struct physical_volume *pv_create(struct format_instance *fid,
const char *name,
struct id *id)
struct id *id, uint64_t size)
{
struct pool *mem = fi->cmd->mem;
struct physical_volume *pv = pool_alloc(mem, sizeof (*pv));
struct pool *mem = fid->fmt->cmd->mem;
struct physical_volume *pv = pool_alloc(mem, sizeof(*pv));
if (!pv) {
stack;
@@ -203,8 +215,8 @@ struct physical_volume *pv_create(struct format_instance *fi,
else
memcpy(&pv->id, id, sizeof(*id));
if (!(pv->dev = dev_cache_get(name, fi->cmd->filter))) {
log_err("Couldn't find device '%s'", name);
if (!(pv->dev = dev_cache_get(name, fid->fmt->cmd->filter))) {
log_error("%s: Couldn't find device.", name);
goto bad;
}
@@ -217,14 +229,36 @@ struct physical_volume *pv_create(struct format_instance *fi,
pv->status = ALLOCATABLE_PV;
if (!dev_get_size(pv->dev, &pv->size)) {
log_err("Couldn't get size of device '%s'", name);
log_error("%s: Couldn't get size.", name);
goto bad;
}
if (size) {
if (size > pv->size)
log_print("WARNING: %s: Overriding real size. "
"You could lose data.", name);
log_verbose("%s: Pretending size is %" PRIu64 " sectors.",
name, size);
pv->size = size;
}
if (pv->size < PV_MIN_SIZE) {
log_error("%s: Size must exceed minimum of %lu sectors.",
name, PV_MIN_SIZE);
goto bad;
}
pv->pe_size = 0;
pv->pe_start = 0;
pv->pe_count = 0;
pv->pe_allocated = 0;
pv->pe_alloc_count = 0;
pv->fid = fid;
if (!fid->fmt->ops->pv_setup(fid, pv, NULL)) {
log_error("%s: Format-specific setup of physical volume "
"failed.", name);
goto bad;
}
return pv;
bad:
@@ -268,6 +302,20 @@ struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name)
return NULL;
}
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg, union lvid *lvid)
{
struct list *lvh;
struct lv_list *lvl;
list_iterate(lvh, &vg->lvs) {
lvl = list_item(lvh, struct lv_list);
if (!strncmp(lvl->lv->lvid.s, lvid->s, sizeof(*lvid)))
return lvl;
}
return NULL;
}
struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name)
{
struct lv_list *lvl = find_lv_in_vg(vg, lv_name);
@@ -287,3 +335,250 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
}
return NULL;
}
int vg_remove(struct volume_group *vg)
{
struct list *mdah;
void *mdl;
if (!vg->fid->fmt->ops->vg_remove)
return 1;
/* FIXME Improve recovery situation? */
/* Remove each copy of the metadata */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_remove(vg->fid, vg, mdl)) {
stack;
return 0;
}
}
return 1;
}
int vg_write(struct volume_group *vg)
{
struct list *mdah;
void *mdl;
if (vg->status & PARTIAL_VG) {
log_error("Cannot change metadata for partial volume group %s",
vg->name);
return 0;
}
vg->seqno++;
/* Write to each copy of the metadata area */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_write(vg->fid, vg, mdl)) {
stack;
return 0;
}
}
if (!vg->fid->fmt->ops->vg_commit)
return 1;
/* Commit to each copy of the metadata area */
list_iterate(mdah, &vg->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!vg->fid->fmt->ops->vg_commit(vg->fid, vg, mdl)) {
stack;
return 0;
}
}
return 1;
}
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name)
{
struct format_instance *fid;
struct format_type *fmt;
struct volume_group *vg, *correct_vg;
struct list *mdah, *names;
void *mdl;
int inconsistent = 0, first_time = 1;
/* create format instance with appropriate metadata area */
if (!(fmt = vgcache_find_format(vg_name))) {
/* Do full scan */
if (!(names = get_vgs(cmd))) {
stack;
return NULL;
}
pool_free(cmd->mem, names);
if (!(fmt = vgcache_find_format(vg_name))) {
stack;
return NULL;
}
}
if (!(fid = fmt->ops->create_instance(fmt, vg_name, NULL))) {
log_error("Failed to create format instance");
return NULL;
}
/* Ensure contents of all metadata areas match - else do recovery */
list_iterate(mdah, &fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!(vg = fid->fmt->ops->vg_read(fid, vg_name, mdl))) {
inconsistent = 1;
continue;
}
if (first_time) {
correct_vg = vg;
first_time = 0;
continue;
}
if (correct_vg->seqno != vg->seqno) {
inconsistent = 1;
if (vg->seqno > correct_vg->seqno)
correct_vg = vg;
}
}
/* Failed to find VG */
if (first_time) {
stack;
return NULL;
}
if (inconsistent) {
log_print("Inconsistent metadata copies found - updating "
"to use version %u", correct_vg->seqno);
if (!vg_write(correct_vg)) {
log_error("Automatic metadata correction failed");
return NULL;
}
}
vgcache_add(vg_name, correct_vg->id.uuid, NULL, fmt);
return correct_vg;
}
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid)
{
char *vgname;
struct list *vgs, *vgh;
struct volume_group *vg;
if (!(vgs = get_vgs(cmd))) {
log_error("vg_read_by_vgid: get_vgs failed");
return NULL;
}
list_iterate(vgh, vgs) {
vgname = list_item(vgh, struct name_list)->name;
if ((vg = vg_read(cmd, vgname)) &&
!strncmp(vg->id.uuid, vgid, ID_LEN)) return vg;
}
pool_free(cmd->mem, vgs);
return NULL;
}
/* FIXME Use label functions instead of PV functions? */
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name)
{
struct physical_volume *pv;
if (!(pv = pool_zalloc(cmd->mem, sizeof(*pv)))) {
log_error("pv_list allocation for '%s' failed", pv_name);
return 0;
}
/* Member of a format1 VG? */
if (!(cmd->fmt1->ops->pv_read(cmd->fmt1, pv_name, pv))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
}
/* Member of a format_text VG? */
if (!(cmd->fmtt->ops->pv_read(cmd->fmtt, pv_name, pv))) {
log_error("Failed to read existing physical volume '%s'",
pv_name);
return 0;
}
if (!pv->size)
return NULL;
else
return pv;
}
struct list *get_vgs(struct cmd_context *cmd)
{
struct list *names;
if (!(names = pool_alloc(cmd->mem, sizeof(*names)))) {
log_error("VG name list allocation failed");
return NULL;
}
list_init(names);
if (!cmd->fmt1->ops->get_vgs(cmd->fmt1, names) ||
!cmd->fmtt->ops->get_vgs(cmd->fmtt, names) ||
list_empty(names)) {
pool_free(cmd->mem, names);
return NULL;
}
return names;
}
struct list *get_pvs(struct cmd_context *cmd)
{
struct list *results;
if (!(results = pool_alloc(cmd->mem, sizeof(*results)))) {
log_error("PV list allocation failed");
return NULL;
}
list_init(results);
/* fmtt modifies fmt1 output */
if (!cmd->fmt1->ops->get_pvs(cmd->fmt1, results) ||
!cmd->fmtt->ops->get_pvs(cmd->fmtt, results)) {
pool_free(cmd->mem, results);
return NULL;
}
return results;
}
int pv_write(struct cmd_context *cmd, struct physical_volume *pv)
{
struct list *mdah;
void *mdl;
/* Write to each copy of the metadata area */
list_iterate(mdah, &pv->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!pv->fid->fmt->ops->pv_write(pv->fid, pv, mdl)) {
stack;
return 0;
}
}
if (!pv->fid->fmt->ops->pv_commit)
return 1;
/* Commit to each copy of the metadata area */
list_iterate(mdah, &pv->fid->metadata_areas) {
mdl = list_item(mdah, struct metadata_area)->metadata_locn;
if (!pv->fid->fmt->ops->pv_commit(pv->fid, pv, mdl)) {
stack;
return 0;
}
}
return 1;
}

View File

@@ -22,6 +22,8 @@
#define STRIPE_SIZE_DEFAULT 16 /* 16KB */
#define STRIPE_SIZE_MIN ( PAGE_SIZE/SECTOR_SIZE) /* PAGESIZE in sectors */
#define STRIPE_SIZE_MAX ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */
#define PV_MIN_SIZE ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */
#define PE_ALIGN (65536UL / SECTOR_SIZE) /* PE alignment */
/* Various flags */
@@ -36,6 +38,7 @@
#define SPINDOWN_LV 0x00000010 /* LV */
#define BADBLOCK_ON 0x00000020 /* LV */
#define FIXED_MINOR 0x00000080 /* LV */
/* FIXME: do we really set read/write for a whole vg ? */
#define LVM_READ 0x00000100 /* LV VG */
@@ -49,13 +52,15 @@
#define ALLOC_STRICT 0x00002000 /* LV */
#define ALLOC_CONTIGUOUS 0x00004000 /* LV */
#define SNAPSHOT 0x00010000 /* LV */
#define SNAPSHOT_ORG 0x00020000 /* LV */
#define FMT_SEGMENTS 0x00000001 /* Arbitrary segment parameters? */
#define FMT_TEXT_NAME "text"
#define FMT_LVM1_NAME "lvm1"
struct physical_volume {
struct id id;
struct device *dev;
struct format_instance *fid;
char *vg_name;
uint32_t status;
@@ -65,13 +70,33 @@ struct physical_volume {
uint64_t pe_size;
uint64_t pe_start;
uint32_t pe_count;
uint32_t pe_allocated; /* FIXME: change the name to alloc_count ? */
uint32_t pe_alloc_count;
};
struct cmd_context;
struct format_type {
struct cmd_context *cmd;
struct format_handler *ops;
const char *name;
uint32_t features;
void *private;
};
struct metadata_area {
struct list list;
void *metadata_locn;
};
struct format_instance {
struct format_type *fmt;
struct list metadata_areas; /* e.g. metadata locations */
};
struct volume_group {
struct cmd_context *cmd;
struct format_instance *fid;
uint32_t seqno; /* Metadata sequence number */
struct id id;
char *name;
@@ -93,6 +118,10 @@ struct volume_group {
/* logical volumes */
uint32_t lv_count;
struct list lvs;
/* snapshots */
uint32_t snapshot_count;
struct list snapshots;
};
struct stripe_segment {
@@ -112,13 +141,14 @@ struct stripe_segment {
};
struct logical_volume {
struct id id;
union lvid lvid;
char *name;
struct volume_group *vg;
uint32_t status;
uint32_t read_ahead;
int32_t minor;
uint64_t size;
uint32_t le_count;
@@ -126,6 +156,14 @@ struct logical_volume {
struct list segments;
};
struct snapshot {
int persistent; /* boolean */
uint32_t chunk_size; /* in 512 byte sectors */
struct logical_volume *origin;
struct logical_volume *cow;
};
struct name_list {
struct list list;
char *name;
@@ -141,21 +179,12 @@ struct lv_list {
struct logical_volume *lv;
};
struct cmd_context {
/* format handler allocates all objects from here */
struct pool *mem;
struct snapshot_list {
struct list list;
/* misc. vars needed by format handler */
char *dev_dir;
struct dev_filter *filter;
struct config_file *cf;
struct snapshot *snapshot;
};
struct format_instance {
struct cmd_context *cmd;
struct format_handler *ops;
void *private;
};
/*
@@ -165,18 +194,19 @@ struct format_handler {
/*
* Returns a name_list of vg's.
*/
struct list *(*get_vgs)(struct format_instance *fi);
struct list *(*get_vgs)(struct format_type *fmt, struct list *names);
/*
* Returns pv_list of fully-populated pv structures.
*/
struct list *(*get_pvs)(struct format_instance *fi);
struct list *(*get_pvs)(struct format_type *fmt, struct list *results);
/*
* Return PV with given path.
*/
struct physical_volume *(*pv_read)(struct format_instance *fi,
const char *pv_name);
int (*pv_read)(struct format_type *fmt,
const char *pv_name,
struct physical_volume *pv);
/*
* Tweak an already filled out a pv ready for importing into a
@@ -189,8 +219,10 @@ struct format_handler {
* Write a PV structure to disk. Fails if the PV is in a VG ie
* pv->vg_name must be null.
*/
int (*pv_write)(struct format_instance *fi,
struct physical_volume *pv);
int (*pv_write)(struct format_instance *fi, struct physical_volume *pv,
void *mdl);
int (*pv_commit)(struct format_instance *fid,
struct physical_volume *pv, void *mdl);
/*
* Tweak an already filled out a lv eg, check there
@@ -203,13 +235,16 @@ struct format_handler {
* specific.
*/
int (*vg_setup)(struct format_instance *fi, struct volume_group *vg);
int (*vg_remove)(struct format_instance *fi, struct volume_group *vg,
void *mdl);
/*
* The name may be prefixed with the dev_dir from the
* job_context.
* mdl is the metadata location to use
*/
struct volume_group *(*vg_read)(struct format_instance *fi,
const char *vg_name);
const char *vg_name, void *mdl);
/*
* Write out complete VG metadata. You must ensure internal
@@ -225,24 +260,50 @@ struct format_handler {
* in the volume_group structure it is handed. Note: format1
* does read all pv's currently.
*/
int (*vg_write)(struct format_instance *fi, struct volume_group *vg);
int (*vg_write)(struct format_instance *fid, struct volume_group *vg,
void *mdl);
int (*vg_commit)(struct format_instance *fid, struct volume_group *vg,
void *mdl);
/*
* Create format instance with a particular metadata area
*/
struct format_instance *(*create_instance)(struct format_type *fmt,
const char *vgname,
void *context);
/*
* Destructor for this object.
* Destructor for format instance
*/
void (*destroy)(struct format_instance *fi);
void (*destroy_instance)(struct format_instance *fid);
/*
* Destructor for format type
*/
void (*destroy)(struct format_type *fmt);
};
/*
* Utility functions
*/
int vg_write(struct volume_group *vg);
struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name);
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name);
struct list *get_pvs(struct cmd_context *cmd);
struct list *get_vgs(struct cmd_context *cmd);
int pv_write(struct cmd_context *cmd, struct physical_volume *pv);
struct physical_volume *pv_create(struct format_instance *fi,
const char *name,
struct id *id);
struct id *id,
uint64_t size);
struct volume_group *vg_create(struct format_instance *fi, const char *name,
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
uint32_t extent_size, int max_pv, int max_lv,
int pv_count, char **pv_names);
int vg_remove(struct volume_group *vg);
/*
* This needs the format instance to check the
@@ -265,7 +326,7 @@ struct logical_volume *lv_create(struct format_instance *fi,
struct volume_group *vg,
struct list *acceptable_pvs);
int lv_reduce(struct format_instance *fi,
int lv_reduce(struct format_instance *fi,
struct logical_volume *lv, uint32_t extents);
int lv_extend(struct format_instance *fi,
@@ -294,6 +355,8 @@ struct pv_list *find_pv_in_vg(struct volume_group *vg, const char *pv_name);
/* Find an LV within a given VG */
struct lv_list *find_lv_in_vg(struct volume_group *vg, const char *lv_name);
struct lv_list *find_lv_in_vg_by_lvid(struct volume_group *vg,
union lvid *lvid);
/* Return the VG that contains a given LV (based on path given in lv_name) */
/* or environment var */
@@ -323,4 +386,22 @@ int lv_check_segments(struct logical_volume *lv);
int lv_merge_segments(struct logical_volume *lv);
/*
* Useful functions for managing snapshots.
*/
int lv_is_origin(struct logical_volume *lv);
int lv_is_cow(struct logical_volume *lv);
struct snapshot *find_cow(struct logical_volume *lv);
struct snapshot *find_origin(struct logical_volume *lv);
struct list *find_snapshots(struct logical_volume *lv);
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow,
int persistent,
uint32_t chunk_size);
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
#endif

View File

@@ -82,7 +82,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
}
/* populate the hash table */
list_iterate (pvmh, maps) {
list_iterate(pvmh, maps) {
pvm = list_item(pvmh, struct pv_map);
if (!hash_insert(hash, dev_name(pvm->pv->dev), pvm)) {
stack;
@@ -91,18 +91,18 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
}
/* iterate through all the lv's setting bit's for used pe's */
list_iterate (lvh, &vg->lvs) {
list_iterate(lvh, &vg->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
list_iterate (segh, &lv->segments) {
list_iterate(segh, &lv->segments) {
seg = list_item(segh, struct stripe_segment);
for (s = 0; s < seg->stripes; s++) {
for (pe = 0; pe < (seg->len / seg->stripes);
pe++) {
if (!_set_allocated(hash,
seg->area[s].pv,
seg->area[s].pe
seg->area[s].pv,
seg->area[s].pe
+ pe)) {
stack;
goto out;
@@ -113,7 +113,7 @@ static int _fill_bitsets(struct volume_group *vg, struct list *maps)
}
r = 1;
out:
out:
hash_destroy(hash);
return r;
}
@@ -131,7 +131,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
return;
}
list_iterate (pvah, head) {
list_iterate(pvah, head) {
pva = list_item(pvah, struct pv_area);
if (pva->count < a->count)
@@ -142,7 +142,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
}
static int _create_single_area(struct pool *mem, struct pv_map *pvm,
uint32_t *extent)
uint32_t * extent)
{
uint32_t e = *extent, b, count = pvm->pv->pe_count;
struct pv_area *pva;

View File

@@ -0,0 +1,153 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "log.h"
#include "metadata.h"
#include "toolcontext.h"
int lv_is_origin(struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->origin == lv)
return 1;
}
return 0;
}
int lv_is_cow(struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->cow == lv)
return 1;
}
return 0;
}
struct snapshot *find_origin(struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->origin == lv)
return s;
}
return NULL;
}
struct snapshot *find_cow(struct logical_volume *lv)
{
struct list *slh;
struct snapshot *s;
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (s->cow == lv)
return s;
}
return NULL;
}
struct list *find_snapshots(struct logical_volume *lv)
{
struct list *slh;
struct list *snaplist;
struct snapshot *s;
struct snapshot_list *newsl;
struct pool *mem = lv->vg->cmd->mem;
if (!(snaplist = pool_alloc(mem, sizeof(*snaplist)))) {
log_error("snapshot name list allocation failed");
return NULL;
}
list_init(snaplist);
list_iterate(slh, &lv->vg->snapshots) {
s = list_item(slh, struct snapshot_list)->snapshot;
if (!(s->origin == lv))
continue;
if (!(newsl = pool_alloc(mem, sizeof(*newsl)))) {
log_error("snapshot_list structure allocation failed");
pool_free(mem, snaplist);
return NULL;
}
newsl->snapshot = s;
list_add(snaplist, &newsl->list);
}
return snaplist;
}
int vg_add_snapshot(struct logical_volume *origin,
struct logical_volume *cow,
int persistent, uint32_t chunk_size)
{
struct snapshot *s;
struct snapshot_list *sl;
struct pool *mem = origin->vg->cmd->mem;
/*
* Is the cow device already being used ?
*/
if (lv_is_cow(cow)) {
log_err("'%s' is already in use as a snapshot.", cow->name);
return 0;
}
if (!(s = pool_alloc(mem, sizeof(*s)))) {
stack;
return 0;
}
s->persistent = persistent;
s->chunk_size = chunk_size;
s->origin = origin;
s->cow = cow;
if (!(sl = pool_alloc(mem, sizeof(*sl)))) {
stack;
pool_free(mem, s);
return 0;
}
sl->snapshot = s;
list_add(&origin->vg->snapshots, &sl->list);
return 1;
}
int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow)
{
struct list *slh;
struct snapshot_list *sl;
list_iterate(slh, &vg->snapshots) {
sl = list_item(slh, struct snapshot_list);
if (sl->snapshot->cow == cow) {
list_del(slh);
return 1;
}
}
/* fail */
log_err("Asked to remove an unknown snapshot.");
return 0;
}

View File

@@ -7,6 +7,7 @@
#include "log.h"
#include "lvm-file.h"
#include "lvm-string.h"
#include "dbg_malloc.h"
#include <stdlib.h>
#include <unistd.h>
@@ -14,6 +15,7 @@
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#include <dirent.h>
/*
* Creates a temporary filename, and opens a descriptor to the
@@ -21,17 +23,16 @@
* rename the file after successfully writing it. Grab
* NFS-supported exclusive fcntl discretionary lock.
*/
int create_temp_name(const char *dir, char *buffer, size_t len,
int *fd)
int create_temp_name(const char *dir, char *buffer, size_t len, int *fd)
{
int i, num;
pid_t pid;
char hostname[255];
struct flock lock = {
l_type: F_WRLCK,
l_whence: 0,
l_start: 0,
l_len: 0
l_type:F_WRLCK,
l_whence:0,
l_start:0,
l_len:0
};
num = rand();
@@ -99,3 +100,100 @@ int lvm_rename(const char *old, const char *new)
return 1;
}
int path_exists(const char *path)
{
struct stat info;
if (!*path)
return 0;
if (stat(path, &info) < 0)
return 0;
return 1;
}
int dir_exists(const char *path)
{
struct stat info;
if (!*path)
return 0;
if (stat(path, &info) < 0)
return 0;
if (!S_ISDIR(info.st_mode))
return 0;
return 1;
}
static int _create_dir_recursive(const char *dir)
{
char *orig, *s;
int rc;
log_verbose("Creating directory \"%s\"", dir);
/* Create parent directories */
orig = s = dbg_strdup(dir);
while ((s = strchr(s, '/')) != NULL) {
*s = '\0';
if (*orig) {
rc = mkdir(orig, 0777);
if (rc < 0 && errno != EEXIST) {
log_sys_error("mkdir", orig);
dbg_free(orig);
return 0;
}
}
*s++ = '/';
}
dbg_free(orig);
/* Create final directory */
rc = mkdir(dir, 0777);
if (rc < 0 && errno != EEXIST) {
log_sys_error("mkdir", dir);
return 0;
}
return 1;
}
int create_dir(const char *dir)
{
struct stat info;
if (!*dir)
return 1;
if (stat(dir, &info) < 0)
return _create_dir_recursive(dir);
if (S_ISDIR(info.st_mode))
return 1;
log_error("Directory \"%s\" not found", dir);
return 0;
}
int is_empty_dir(const char *dir)
{
struct dirent *dirent;
DIR *d;
if (!(d = opendir(dir))) {
log_sys_error("opendir", dir);
return 0;
}
while ((dirent = readdir(d)))
if (strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, ".."))
break;
if (closedir(d)) {
log_sys_error("closedir", dir);
}
return dirent ? 0 : 1;
}

View File

@@ -16,3 +16,19 @@ int create_temp_name(const char *dir, char *buffer, size_t len, int *fd);
*/
int lvm_rename(const char *old, const char *new);
/*
* Return 1 if path exists else return 0
*/
int path_exists(const char *path);
int dir_exists(const char *path);
/*
* Return 1 if dir is empty
*/
int is_empty_dir(const char *dir);
/*
* Create directory (recursively) if necessary. Return 1
* if directory was successfully created (or already exists), else 0.
*/
int create_dir(const char *dir);

View File

@@ -14,19 +14,20 @@
#include "log.h"
struct memblock {
struct memblock *prev, *next; /* All allocated blocks are linked */
size_t length; /* Size of the requested block */
int id; /* Index of the block */
const char *file; /* File that allocated */
int line; /* Line that allocated */
void *magic; /* Address of this block */
struct memblock *prev, *next; /* All allocated blocks are linked */
size_t length; /* Size of the requested block */
int id; /* Index of the block */
const char *file; /* File that allocated */
int line; /* Line that allocated */
void *magic; /* Address of this block */
};
static struct {
unsigned int blocks, mblocks;
unsigned int bytes, mbytes;
} _mem_stats = {0, 0, 0, 0};
} _mem_stats = {
0, 0, 0, 0};
static struct memblock *_head = 0;
static struct memblock *_tail = 0;
@@ -104,7 +105,7 @@ void free_aux(void *p)
/* check data at the far boundary */
ptr = ((char *) mb) + sizeof(struct memblock) + mb->length;
for (i = 0; i < sizeof(unsigned long); i++)
if(*ptr++ != (char) mb->id)
if (*ptr++ != (char) mb->id)
assert(!"Damage at far end of block");
/* have we freed this before ? */
@@ -159,7 +160,7 @@ int dump_memory(void)
log_very_verbose("You have a memory leak:");
for (mb = _head; mb; mb = mb->next) {
print_log(_LOG_INFO, mb->file, mb->line,
print_log(_LOG_INFO, mb->file, mb->line,
"block %d at %p, size %" PRIdPTR,
mb->id, mb->magic, mb->length);
tot += mb->length;

View File

@@ -1,11 +1,12 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "pool.h"
#include "dbg_malloc.h"
@@ -17,11 +18,11 @@ struct chunk {
};
struct pool {
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
list to stop 'bobbling' */
struct chunk *chunk, *spare_chunk; /* spare_chunk is a one entry free
list to stop 'bobbling' */
size_t chunk_size;
size_t object_len;
unsigned object_alignment;
unsigned object_alignment;
};
void _align_chunk(struct chunk *c, unsigned alignment);
@@ -36,7 +37,7 @@ struct pool *pool_create(size_t chunk_hint)
struct pool *p = dbg_malloc(sizeof(*p));
if (!p) {
log_error("Couldn't create memory pool (size %u)",
log_error("Couldn't create memory pool (size %" PRIuPTR ")",
sizeof(*p));
return 0;
}
@@ -74,12 +75,12 @@ void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment)
struct chunk *c = p->chunk;
void *r;
/* realign begin */
/* realign begin */
if (c)
_align_chunk(c, alignment);
/* have we got room ? */
if(!c || (c->begin > c->end) || (c->end - c->begin < s)) {
if (!c || (c->begin > c->end) || (c->end - c->begin < s)) {
/* allocate new chunk */
int needed = s + alignment + sizeof(struct chunk);
c = _new_chunk(p, (needed > p->chunk_size) ?
@@ -224,7 +225,8 @@ struct chunk *_new_chunk(struct pool *p, size_t s)
p->spare_chunk = 0;
} else {
if (!(c = dbg_malloc(s))) {
log_err("Out of memory. Requested %u bytes.", s);
log_err("Out of memory. Requested %" PRIuPTR " bytes.",
s);
return NULL;
}
@@ -237,4 +239,3 @@ struct chunk *_new_chunk(struct pool *p, size_t s)
return c;
}

View File

@@ -1,32 +1,17 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
* This file is released under the LGPL.
*
*/
#ifndef _LVM_XLATE_H
#define _LVM_XLATE_H
/* FIXME: finish these as inlines */
#include <asm/byteorder.h>
uint16_t shuffle16(uint16_t n);
uint32_t shuffle32(uint32_t n);
uint64_t shuffle64(uint64_t n);
/* xlate functions move data between core and disk */
#if __BYTE_ORDER == __BIG_ENDIAN
# define xlate16(x) shuffle16(x)
# define xlate32(x) shuffle32(x)
# define xlate64(x) shuffle64(x)
#elif __BYTE_ORDER == __LITTLE_ENDIAN
# define xlate16(x) (x)
# define xlate32(x) (x)
# define xlate64(x) (x)
#else
# error "__BYTE_ORDER must be defined as __LITTLE_ENDIAN or __BIG_ENDIAN"
#endif
#define xlate16(x) __cpu_to_le16((x));
#define xlate32(x) __cpu_to_le32((x));
#define xlate64(x) __cpu_to_le64((x));
#endif

View File

@@ -25,7 +25,7 @@ struct state_queue {
struct state_queue *next;
};
struct matcher { /* Instance variables for the lexer */
struct matcher { /* Instance variables for the lexer */
struct dfa_state *start;
int num_nodes, nodes_entered;
struct rx_node **nodes;
@@ -38,10 +38,10 @@ static int _count_nodes(struct rx_node *rx)
{
int r = 1;
if(rx->left)
if (rx->left)
r += _count_nodes(rx->left);
if(rx->right)
if (rx->right)
r += _count_nodes(rx->right);
return r;
@@ -51,10 +51,10 @@ static void _fill_table(struct matcher *m, struct rx_node *rx)
{
assert((rx->type != OR) || (rx->left && rx->right));
if(rx->left)
if (rx->left)
_fill_table(m, rx->left);
if(rx->right)
if (rx->right)
_fill_table(m, rx->right);
m->nodes[m->nodes_entered++] = rx;
@@ -64,7 +64,7 @@ static void _create_bitsets(struct matcher *m)
{
int i;
for(i = 0; i < m->num_nodes; i++) {
for (i = 0; i < m->num_nodes; i++) {
struct rx_node *n = m->nodes[i];
n->firstpos = bitset_create(m->scratch, m->num_nodes);
n->lastpos = bitset_create(m->scratch, m->num_nodes);
@@ -77,23 +77,23 @@ static void _calc_functions(struct matcher *m)
int i, j, final = 1;
struct rx_node *rx, *c1, *c2;
for(i = 0; i < m->num_nodes; i++) {
for (i = 0; i < m->num_nodes; i++) {
rx = m->nodes[i];
c1 = rx->left;
c2 = rx->right;
if(bit(rx->charset, TARGET_TRANS))
if (bit(rx->charset, TARGET_TRANS))
rx->final = final++;
switch(rx->type) {
switch (rx->type) {
case CAT:
if(c1->nullable)
if (c1->nullable)
bit_union(rx->firstpos,
c1->firstpos, c2->firstpos);
else
bit_copy(rx->firstpos, c1->firstpos);
if(c2->nullable)
if (c2->nullable)
bit_union(rx->lastpos,
c1->lastpos, c2->lastpos);
else
@@ -136,10 +136,10 @@ static void _calc_functions(struct matcher *m)
* because PLUS and STAR do the
* same thing.
*/
switch(rx->type) {
switch (rx->type) {
case CAT:
for(j = 0; j < m->num_nodes; j++) {
if(bit(c1->lastpos, j)) {
for (j = 0; j < m->num_nodes; j++) {
if (bit(c1->lastpos, j)) {
struct rx_node *n = m->nodes[j];
bit_union(n->followpos,
n->followpos, c2->firstpos);
@@ -149,8 +149,8 @@ static void _calc_functions(struct matcher *m)
case PLUS:
case STAR:
for(j = 0; j < m->num_nodes; j++) {
if(bit(rx->lastpos, j)) {
for (j = 0; j < m->num_nodes; j++) {
if (bit(rx->lastpos, j)) {
struct rx_node *n = m->nodes[j];
bit_union(n->followpos,
n->followpos, rx->firstpos);
@@ -178,7 +178,7 @@ static struct state_queue *_create_state_queue(struct pool *mem,
}
r->s = dfa;
r->bits = bitset_create(mem, bits[0]); /* first element is the size */
r->bits = bitset_create(mem, bits[0]); /* first element is the size */
bit_copy(r->bits, bits);
r->next = 0;
return r;
@@ -218,28 +218,30 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
/* iterate through all the inputs for this state */
bit_clear_all(bs);
for(a = 0; a < 256; a++) {
for (a = 0; a < 256; a++) {
/* iterate through all the states in firstpos */
for(i = bit_get_first(dfa_bits);
i >=0;
i = bit_get_next(dfa_bits, i)) {
if(bit(m->nodes[i]->charset, a)) {
if(a == TARGET_TRANS)
for (i = bit_get_first(dfa_bits);
i >= 0; i = bit_get_next(dfa_bits, i)) {
if (bit(m->nodes[i]->charset, a)) {
if (a == TARGET_TRANS)
dfa->final = m->nodes[i]->final;
bit_union(bs, bs, m->nodes[i]->followpos);
bit_union(bs, bs,
m->nodes[i]->followpos);
set_bits = 1;
}
}
if(set_bits) {
if (set_bits) {
ldfa = ttree_lookup(tt, bs + 1);
if(!ldfa) {
if (!ldfa) {
/* push */
ldfa = _create_dfa_state(m->mem);
ttree_insert(tt, bs + 1, ldfa);
tmp = _create_state_queue(m->scratch, ldfa, bs);
if(!h)
tmp =
_create_state_queue(m->scratch,
ldfa, bs);
if (!h)
h = t = tmp;
else {
t->next = tmp;
@@ -260,8 +262,7 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
return 1;
}
struct matcher *matcher_create(struct pool *mem,
const char **patterns, int num)
struct matcher *matcher_create(struct pool *mem, const char **patterns, int num)
{
char *all, *ptr;
int i, len = 0;
@@ -282,7 +283,7 @@ struct matcher *matcher_create(struct pool *mem,
memset(m, 0, sizeof(*m));
/* join the regexps together, delimiting with zero */
for(i = 0; i < num; i++)
for (i = 0; i < num; i++)
len += strlen(patterns[i]) + 8;
ptr = all = pool_alloc(scratch, len + 1);
@@ -292,15 +293,14 @@ struct matcher *matcher_create(struct pool *mem,
goto bad;
}
for(i = 0; i < num; i++) {
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i],
TARGET_TRANS);
if(i < (num - 1))
for (i = 0; i < num; i++) {
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
if (i < (num - 1))
*ptr++ = '|';
}
/* parse this expression */
if(!(rx = rx_parse_tok(scratch, all, ptr))) {
if (!(rx = rx_parse_tok(scratch, all, ptr))) {
log_error("Couldn't parse regex");
goto bad;
}
@@ -324,7 +324,7 @@ struct matcher *matcher_create(struct pool *mem,
return m;
bad:
bad:
pool_destroy(scratch);
pool_destroy(mem);
return NULL;

View File

@@ -12,7 +12,6 @@
#include <stdlib.h>
#include <stdio.h>
struct parse_sp { /* scratch pad for the parsing process */
struct pool *mem;
int type; /* token type, 0 indicates a charset */
@@ -21,10 +20,8 @@ struct parse_sp { /* scratch pad for the parsing process */
const char *rx_end; /* 1pte for the expression being parsed */
};
static struct rx_node *_or_term(struct parse_sp *ps);
/*
* Get the next token from the regular expression.
* Returns: 1 success, 0 end of input, -1 error.
@@ -34,16 +31,16 @@ static int _get_token(struct parse_sp *ps)
int neg = 0, range = 0;
char c, lc = 0;
const char *ptr = ps->cursor;
if(ptr == ps->rx_end) { /* end of input ? */
if (ptr == ps->rx_end) { /* end of input ? */
ps->type = -1;
return 0;
}
switch(*ptr) {
/* charsets and ncharsets */
switch (*ptr) {
/* charsets and ncharsets */
case '[':
ptr++;
if(*ptr == '^') {
if (*ptr == '^') {
bit_set_all(ps->charset);
/* never transition on zero */
@@ -54,40 +51,46 @@ static int _get_token(struct parse_sp *ps)
} else
bit_clear_all(ps->charset);
while((ptr < ps->rx_end) && (*ptr != ']')) {
if(*ptr == '\\') {
while ((ptr < ps->rx_end) && (*ptr != ']')) {
if (*ptr == '\\') {
/* an escaped character */
ptr++;
switch(*ptr) {
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
switch (*ptr) {
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
default:
c = *ptr;
}
} else if(*ptr == '-' && lc) {
} else if (*ptr == '-' && lc) {
/* we've got a range on our hands */
range = 1;
ptr++;
if(ptr == ps->rx_end) {
if (ptr == ps->rx_end) {
log_error("Incomplete range"
"specification");
"specification");
return -1;
}
c = *ptr;
} else
c = *ptr;
if(range) {
if (range) {
/* add lc - c into the bitset */
if(lc > c) {
if (lc > c) {
char tmp = c;
c = lc;
lc = tmp;
}
for(; lc <= c; lc++) {
if(neg)
for (; lc <= c; lc++) {
if (neg)
bit_clear(ps->charset, lc);
else
bit_set(ps->charset, lc);
@@ -95,7 +98,7 @@ static int _get_token(struct parse_sp *ps)
range = 0;
} else {
/* add c into the bitset */
if(neg)
if (neg)
bit_clear(ps->charset, c);
else
bit_set(ps->charset, c);
@@ -104,7 +107,7 @@ static int _get_token(struct parse_sp *ps)
lc = c;
}
if(ptr >= ps->rx_end) {
if (ptr >= ps->rx_end) {
ps->type = -1;
return -1;
}
@@ -141,7 +144,7 @@ static int _get_token(struct parse_sp *ps)
case '\\':
/* escaped character */
ptr++;
if(ptr >= ps->rx_end) {
if (ptr >= ps->rx_end) {
log_error("Badly quoted character at end "
"of expression");
ps->type = -1;
@@ -151,10 +154,16 @@ static int _get_token(struct parse_sp *ps)
ps->type = 0;
ps->cursor = ptr + 1;
bit_clear_all(ps->charset);
switch(*ptr) {
case 'n': bit_set(ps->charset, (int) '\n'); break;
case 'r': bit_set(ps->charset, (int) '\r'); break;
case 't': bit_set(ps->charset, (int) '\t'); break;
switch (*ptr) {
case 'n':
bit_set(ps->charset, (int) '\n');
break;
case 'r':
bit_set(ps->charset, (int) '\r');
break;
case 't':
bit_set(ps->charset, (int) '\t');
break;
default:
bit_set(ps->charset, (int) *ptr);
}
@@ -195,7 +204,7 @@ static struct rx_node *_term(struct parse_sp *ps)
{
struct rx_node *n;
switch(ps->type) {
switch (ps->type) {
case 0:
if (!(n = _node(ps->mem, CHARSET, NULL, NULL))) {
stack;
@@ -203,17 +212,17 @@ static struct rx_node *_term(struct parse_sp *ps)
}
bit_copy(n->charset, ps->charset);
_get_token(ps); /* match charset */
_get_token(ps); /* match charset */
break;
case '(':
_get_token(ps); /* match '(' */
_get_token(ps); /* match '(' */
n = _or_term(ps);
if(ps->type != ')') {
if (ps->type != ')') {
log_error("missing ')' in regular expression");
return 0;
}
_get_token(ps); /* match ')' */
_get_token(ps); /* match ')' */
break;
default:
@@ -227,11 +236,11 @@ static struct rx_node *_closure_term(struct parse_sp *ps)
{
struct rx_node *l, *n;
if(!(l = _term(ps)))
if (!(l = _term(ps)))
return NULL;
for (;;) {
switch(ps->type) {
switch (ps->type) {
case '*':
n = _node(ps->mem, STAR, l, NULL);
break;
@@ -289,7 +298,7 @@ static struct rx_node *_or_term(struct parse_sp *ps)
if (ps->type != '|')
return l;
_get_token(ps); /* match '|' */
_get_token(ps); /* match '|' */
if (!(r = _or_term(ps))) {
log_error("Badly formed 'or' expression");
@@ -317,7 +326,7 @@ struct rx_node *rx_parse_tok(struct pool *mem,
ps->charset = bitset_create(mem, 256);
ps->cursor = begin;
ps->rx_end = end;
_get_token(ps); /* load the first token */
_get_token(ps); /* load the first token */
if (!(r = _or_term(ps))) {
log_error("Parse error in regex");

View File

@@ -74,7 +74,6 @@ int ttree_insert(struct ttree *tt, unsigned int *key, void *data)
} while (*c && count);
if (!*c) {
count++;

View File

@@ -19,6 +19,44 @@ static unsigned char _c[] =
static int _built_inverse;
static unsigned char _inverse_c[256];
int lvid_create(union lvid *lvid, struct id *vgid)
{
memcpy(lvid->id, vgid, sizeof(*lvid->id));
id_create(&lvid->id[1]);
return 1;
}
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, int lv_num)
{
int i;
memcpy(lvid->id, vgid, sizeof(*lvid->id));
for (i = ID_LEN; i; i--) {
lvid->id[1].uuid[i - 1] = _c[lv_num % (sizeof(_c) - 1)];
lv_num /= sizeof(_c) - 1;
}
lvid->s[sizeof(lvid->s) - 1] = '\0';
return 1;
}
int lvnum_from_lvid(union lvid *lvid)
{
int i, lv_num = 0;
unsigned char *c;
for (i = 0; i < ID_LEN; i++) {
lv_num *= sizeof(_c) - 1;
if ((c = strchr(_c, lvid->id[1].uuid[i])))
lv_num += (int) (c - _c);
}
return lv_num;
}
int id_create(struct id *id)
{
int random, i, len = sizeof(id->uuid);
@@ -86,7 +124,7 @@ int id_write_format(struct id *id, char *buffer, size_t size)
{
int i, tot;
static int group_size[] = {6, 4, 4, 4, 4, 4, 6};
static int group_size[] = { 6, 4, 4, 4, 4, 4, 6 };
assert(ID_LEN == 32);

View File

@@ -10,11 +10,25 @@
#include "lvm-types.h"
#define ID_LEN 32
#define ID_LEN_S "32"
struct id {
uint8_t uuid[ID_LEN];
};
/*
* Unique logical volume identifier
* With format1 this is VG uuid + LV uuid + '\0'
*/
union lvid {
struct id id[2];
char s[2 * sizeof(struct id) + 1];
};
int lvid_from_lvnum(union lvid *lvid, struct id *vgid, int lv_num);
int lvnum_from_lvid(union lvid *lvid);
int lvid_create(union lvid *lvid, struct id *vgid);
int id_create(struct id *id);
int id_valid(struct id *id);
int id_equal(struct id *lhs, struct id *rhs);

View File

@@ -10,8 +10,11 @@
#include "hash.h"
#include "dbg_malloc.h"
#include "log.h"
#include "uuid.h"
#include "toolcontext.h"
static struct hash_table *_vghash;
static struct hash_table *_vgidhash;
static struct hash_table *_pvhash;
const char *all_devices = "\0";
@@ -21,6 +24,9 @@ int vgcache_init()
if (!(_vghash = hash_create(128)))
return 0;
if (!(_vgidhash = hash_create(128)))
return 0;
if (!(_pvhash = hash_create(128)))
return 0;
@@ -44,6 +50,39 @@ struct list *vgcache_find(const char *vg_name)
return &vgn->pvdevs;
}
struct format_type *vgcache_find_format(const char *vg_name)
{
struct vgname_entry *vgn;
if (!_vghash)
return NULL;
if (!vg_name)
vg_name = all_devices;
if (!(vgn = hash_lookup(_vghash, vg_name)))
return NULL;
return vgn->fmt;
}
struct list *vgcache_find_by_vgid(const char *vgid)
{
struct vgname_entry *vgn;
char vgid_s[ID_LEN + 1];
if (!_vgidhash || !vgid)
return NULL;
memcpy(vgid_s, vgid, ID_LEN);
vgid_s[ID_LEN] = '\0';
if (!(vgn = hash_lookup(_vgidhash, vgid_s)))
return NULL;
return &vgn->pvdevs;
}
void vgcache_del_orphan(struct device *dev)
{
struct pvdev_list *pvdev;
@@ -55,7 +94,8 @@ void vgcache_del_orphan(struct device *dev)
}
}
int vgcache_add_entry(const char *vg_name, struct device *dev)
int vgcache_add_entry(const char *vg_name, const char *vgid, struct device *dev,
struct format_type *fmt)
{
const char *pv_name;
struct vgname_entry *vgn;
@@ -67,7 +107,9 @@ int vgcache_add_entry(const char *vg_name, struct device *dev)
log_error("struct vgname_entry allocation failed");
return 0;
}
memset(vgn, 0, sizeof(struct vgname_entry));
vgn->fmt = fmt;
pvdevs = &vgn->pvdevs;
list_init(pvdevs);
@@ -80,8 +122,26 @@ int vgcache_add_entry(const char *vg_name, struct device *dev)
log_error("vgcache_add: VG hash insertion failed");
return 0;
}
} else if (!(vgn = hash_lookup(_vghash, vg_name))) {
log_error("vgcache_add: VG name entry %s not found", vg_name);
return 0;
}
if (vgid && strncmp(vgid, vgn->vgid, ID_LEN)) {
hash_remove(_vgidhash, vgn->vgid);
memcpy(vgn->vgid, vgid, ID_LEN);
vgn->vgid[ID_LEN] = '\0';
if (!hash_insert(_vgidhash, vgn->vgid, vgn)) {
log_error("vgcache_add: vgid hash insertion " "failed");
return 0;
}
}
if (!dev)
return 1;
list_iterate(pvdh, pvdevs) {
pvdev = list_item(pvdh, struct pvdev_list);
if (dev == pvdev->dev)
@@ -115,21 +175,25 @@ int vgcache_add_entry(const char *vg_name, struct device *dev)
}
/* vg_name of "\0" is an orphan PV; NULL means only add to all_devices */
int vgcache_add(const char *vg_name, struct device *dev)
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev,
struct format_type *fmt)
{
if (!_vghash && !vgcache_init())
return 0;
/* If orphan PV remove it */
if (vg_name && !*vg_name)
if (dev && vg_name && !*vg_name)
vgcache_del_orphan(dev);
/* Add PV if vg_name supplied */
if (vg_name && *vg_name && !vgcache_add_entry(vg_name, dev))
if (vg_name && *vg_name && !vgcache_add_entry(vg_name, vgid, dev, fmt))
return 0;
/* Always add to all_devices */
return vgcache_add_entry(all_devices, dev);
/* Add to all_devices */
if (dev)
return vgcache_add_entry(all_devices, NULL, dev, fmt);
return 1;
}
void vgcache_destroy_entry(struct vgname_entry *vgn)
@@ -147,6 +211,8 @@ void vgcache_destroy_entry(struct vgname_entry *vgn)
dbg_free(pvdev);
}
dbg_free(vgn->vgname);
if (_vgidhash && vgn->vgid[0])
hash_remove(_vgidhash, vgn->vgid);
}
dbg_free(vgn);
}
@@ -165,19 +231,65 @@ void vgcache_del(const char *vg_name)
return;
hash_remove(_vghash, vg_name);
if (vgn->vgid[0])
hash_remove(_vgidhash, vgn->vgid);
vgcache_destroy_entry(vgn);
}
void vgcache_del_by_vgid(const char *vgid)
{
struct vgname_entry *vgn;
char vgid_s[ID_LEN + 1];
if (!_vgidhash || !vgid)
return;
memcpy(vgid_s, vgid, ID_LEN);
vgid_s[ID_LEN] = '\0';
if (!(vgn = hash_lookup(_vghash, vgid_s)))
return;
hash_remove(_vgidhash, vgn->vgid);
if (vgn->vgname[0])
hash_remove(_vghash, vgn->vgname);
vgcache_destroy_entry(vgn);
}
void vgcache_destroy()
{
if (_vghash) {
hash_iterate(_vghash, (iterate_fn)vgcache_destroy_entry);
hash_iter(_vghash, (iterate_fn) vgcache_destroy_entry);
hash_destroy(_vghash);
_vghash = NULL;
}
if (_vgidhash) {
hash_destroy(_vgidhash);
_vgidhash = NULL;
}
if (_pvhash) {
hash_destroy(_pvhash);
_pvhash = NULL;
}
}
char *vgname_from_vgid(struct cmd_context *cmd, struct id *vgid)
{
struct vgname_entry *vgn;
char vgid_s[ID_LEN + 1];
if (!_vgidhash || !vgid)
return NULL;
memcpy(vgid_s, vgid->uuid, ID_LEN);
vgid_s[ID_LEN] = '\0';
if (!(vgn = hash_lookup(_vgidhash, vgid_s)))
return NULL;
return pool_strdup(cmd->mem, vgn->vgname);
}

View File

@@ -12,10 +12,14 @@
#include <asm/page.h>
#include "dev-cache.h"
#include "list.h"
#include "uuid.h"
#include "toolcontext.h"
struct vgname_entry {
struct list pvdevs;
char *vgname;
char vgid[ID_LEN + 1];
struct format_type *fmt;
};
struct pvdev_list {
@@ -28,9 +32,15 @@ void vgcache_destroy();
/* Return list of PVs in named VG */
struct list *vgcache_find(const char *vg_name);
struct format_type *vgcache_find_format(const char *vg_name);
struct list *vgcache_find_by_vgid(const char *vgid);
/* FIXME Temporary function */
char *vgname_from_vgid(struct cmd_context *cmd, struct id *vgid);
/* Add/delete a device */
int vgcache_add(const char *vg_name, struct device *dev);
int vgcache_add(const char *vg_name, const char *vgid, struct device *dev,
struct format_type *fmt);
void vgcache_del(const char *vg_name);
#endif

View File

@@ -31,18 +31,12 @@ install_fs: fs/libdevmapper.so
install_ioctl: ioctl/libdevmapper.so
$(INSTALL) -D -o $(OWNER) -g $(GROUP) -m 555 $(STRIP) $< \
$(libdir)/libdevmapper.so.$(LIB_VERSION).$(IOCTL_VERSION)
$(LN_S) -f libdevmapper.so.$(LIB_VERSION).$(IOCTL_VERSION) \
$(libdir)/libdevmapper.so.$(LIB_VERSION)
$(libdir)/libdevmapper.so.$(LIB_VERSION)
ioctl/libdevmapper.o: ioctl_version
distclean_lib:
$(RM) libdm-common.h
ioctl_version: ioctl/libdevmapper.c
@echo Checking library version compatible with kernel version in dm-ioctl.h
test "$(IOCTL_VERSION)" = \
"$(shell $(CC) -E -dM $(INCLUDES) $(CFLAGS) \
ioctl/libdevmapper.c | \
awk -F '[ \t\"]+' '/DM_IOCTL_VERSION/ {print $$3}' )"
distclean: distclean_lib
.PHONY: ioctl_version
.PHONY: distclean_lib distclean

View File

@@ -16,7 +16,7 @@
#include <errno.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/limits.h>
#include <sys/ioctl.h>
#include <linux/dm-ioctl.h>
@@ -25,31 +25,118 @@
#define ALIGNMENT sizeof(int)
/*
* Ensure build compatibility. The hard-coded version here (major, minor)
* is the highest present in the _cmd_data array below.
*/
#if DM_VERSION_MAJOR != 1 || DM_VERSION_MINOR < 0
#error The version of dm-ioctl.h included is incompatible.
#endif
static struct {
char *name;
int cmd;
int version[3];
} _cmd_data[] = {
{ "create", DM_DEV_CREATE, {1, 0, 0} },
{ "reload", DM_DEV_RELOAD, {1, 0, 0} },
{ "remove", DM_DEV_REMOVE, {1, 0, 0} },
{ "remove_all", DM_REMOVE_ALL, {1, 0, 0} },
{ "suspend", DM_DEV_SUSPEND, {1, 0, 0} },
{ "resume", DM_DEV_SUSPEND, {1, 0, 0} },
{ "info", DM_DEV_STATUS, {1, 0, 0} },
{ "deps", DM_DEV_DEPS, {1, 0, 0} },
{ "rename", DM_DEV_RENAME, {1, 0, 0} },
{ "version", DM_VERSION, {1, 0, 0} },
{ "status", DM_TARGET_STATUS, {1, 0, 0} },
{ "table", DM_TARGET_STATUS, {1, 0, 0} },
{ "waitevent", DM_TARGET_WAIT, {1, 0, 0} },
};
static void *_align(void *ptr, unsigned int a)
{
register unsigned long align = --a;
return (void *) (((unsigned long) ptr + align) & ~align);
}
void dm_task_destroy(struct dm_task *dmt)
{
struct target *t, *n;
for (t = dmt->head; t; t = n) {
n = t->next;
free(t->params);
free(t->type);
free(t);
}
if (dmt->dev_name)
free(dmt->dev_name);
if (dmt->newname)
free(dmt->newname);
if (dmt->dmi)
free(dmt->dmi);
if (dmt->uuid)
free(dmt->uuid);
free(dmt);
}
int dm_task_get_driver_version(struct dm_task *dmt, char *version,
size_t size)
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size)
{
unsigned int *v;
if (!dmt->dmi)
return 0;
strncpy(version, dmt->dmi->version, size);
v = dmt->dmi->version;
snprintf(version, size, "%u.%u.%u", v[0], v[1], v[2]);
return 1;
}
void *dm_get_next_target(struct dm_task *dmt, void *next,
uint64_t *start, uint64_t *length,
char **target_type, char **params)
{
struct target *t = (struct target *) next;
if (!t)
t = dmt->head;
if (!t)
return NULL;
*start = t->start;
*length = t->length;
*target_type = t->type;
*params = t->params;
return t->next;
}
/* Unmarshall the target info returned from a status call */
static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi)
{
char *outbuf = (char *) dmi + sizeof(struct dm_ioctl);
char *outptr = outbuf;
int i;
for (i = 0; i < dmi->target_count; i++) {
struct dm_target_spec *spec = (struct dm_target_spec *) outptr;
if (!dm_task_add_target(dmt, spec->sector_start, spec->length,
spec->target_type,
outptr + sizeof(*spec)))
return 0;
outptr += sizeof(struct dm_target_spec);
outptr += strlen(outptr) + 1;
_align(outptr, ALIGNMENT);
}
return 1;
}
@@ -75,6 +162,16 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
return 1;
}
const char *dm_task_get_uuid(struct dm_task *dmt)
{
return (dmt->dmi->uuid);
}
struct dm_deps *dm_task_get_deps(struct dm_task *dmt)
{
return (struct dm_deps *) (((void *) dmt->dmi) + dmt->dmi->data_start);
}
int dm_task_set_ro(struct dm_task *dmt)
{
dmt->read_only = 1;
@@ -91,14 +188,13 @@ int dm_task_set_newname(struct dm_task *dmt, const char *newname)
return 1;
}
struct target *create_target(uint64_t start,
uint64_t len,
const char *type, const char *params)
struct target *create_target(uint64_t start, uint64_t len, const char *type,
const char *params)
{
struct target *t = malloc(sizeof(*t));
if (!t) {
log_error("create_target: malloc(%d) failed", sizeof(*t));
log_error("create_target: malloc(%d) failed", sizeof(*t));
return NULL;
}
@@ -118,19 +214,13 @@ struct target *create_target(uint64_t start,
t->length = len;
return t;
bad:
bad:
free(t->params);
free(t->type);
free(t);
return NULL;
}
static void *_align(void *ptr, unsigned int align)
{
align--;
return (void *) (((unsigned long) ptr + align) & ~align);
}
static void *_add_target(struct target *t, void *out, void *end)
{
void *out_sp = out;
@@ -171,6 +261,8 @@ static void *_add_target(struct target *t, void *out, void *end)
static struct dm_ioctl *_flatten(struct dm_task *dmt)
{
const size_t min_size = 16 * 1024;
struct dm_ioctl *dmi;
struct target *t;
size_t len = sizeof(struct dm_ioctl);
@@ -191,12 +283,21 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
if (dmt->newname)
len += strlen(dmt->newname) + 1;
/*
* Give len a minimum size so that we have space to store
* dependencies or status information.
*/
if (len < min_size)
len = min_size;
if (!(dmi = malloc(len)))
return NULL;
memset(dmi, 0, len);
strncpy(dmi->version, DM_IOCTL_VERSION, sizeof(dmi->version));
dmi->version[0] = _cmd_data[dmt->type].version[0];
dmi->version[1] = _cmd_data[dmt->type].version[1];
dmi->version[2] = _cmd_data[dmt->type].version[2];
dmi->data_size = len;
dmi->data_start = sizeof(struct dm_ioctl);
@@ -208,11 +309,14 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
if (dmt->read_only)
dmi->flags |= DM_READONLY_FLAG;
if (dmt->minor > 0) {
if (dmt->minor >= 0) {
dmi->flags |= DM_PERSISTENT_DEV_FLAG;
dmi->dev = MKDEV(0, dmt->minor);
}
if (dmt->uuid)
strncpy(dmi->uuid, dmt->uuid, sizeof(dmi->uuid));
dmi->target_count = count;
b = (void *) (dmi + 1);
@@ -227,7 +331,7 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt)
return dmi;
bad:
bad:
free(dmi);
return NULL;
}
@@ -251,48 +355,23 @@ int dm_task_run(struct dm_task *dmt)
goto bad;
}
switch (dmt->type) {
case DM_DEVICE_CREATE:
command = DM_CREATE;
break;
case DM_DEVICE_RELOAD:
command = DM_RELOAD;
break;
case DM_DEVICE_REMOVE:
command = DM_REMOVE;
break;
case DM_DEVICE_SUSPEND:
command = DM_SUSPEND;
break;
case DM_DEVICE_RESUME:
command = DM_SUSPEND;
break;
case DM_DEVICE_INFO:
command = DM_INFO;
break;
case DM_DEVICE_RENAME:
command = DM_RENAME;
break;
case DM_DEVICE_VERSION:
command = DM_VERSION;
break;
default:
if (dmt->type >= (sizeof(_cmd_data) / sizeof(*_cmd_data))) {
log_error("Internal error: unknown device-mapper task %d",
dmt->type);
dmt->type);
goto bad;
}
command = _cmd_data[dmt->type].cmd;
if (dmt->type == DM_DEVICE_TABLE)
dmi->flags |= DM_STATUS_TABLE_FLAG;
log_debug("dm %s %s %s %s", _cmd_data[dmt->type].name, dmi->name,
dmi->uuid, dmt->newname ? dmt->newname : "");
if (ioctl(fd, command, dmi) < 0) {
log_error("device-mapper ioctl cmd %d failed: %s", dmt->type,
strerror(errno));
log_error("device-mapper ioctl cmd %d failed: %s",
_IOC_NR(command), strerror(errno));
goto bad;
}
@@ -304,15 +383,25 @@ int dm_task_run(struct dm_task *dmt)
case DM_DEVICE_REMOVE:
rm_dev_node(dmt->dev_name);
break;
case DM_DEVICE_RENAME:
rename_dev_node(dmt->dev_name, dmt->newname);
break;
case DM_DEVICE_STATUS:
case DM_DEVICE_TABLE:
if (!_unmarshal_status(dmt, dmi))
goto bad;
break;
}
dmt->dmi = dmi;
close(fd);
return 1;
bad:
bad:
free(dmi);
if (fd >= 0)
close(fd);
return 0;
}

View File

@@ -23,5 +23,7 @@ struct dm_task {
int minor;
struct dm_ioctl *dmi;
char *newname;
char *uuid;
};

View File

@@ -9,6 +9,7 @@
#include <inttypes.h>
#include <sys/types.h>
#include <linux/types.h>
/*
* Since it is quite laborious to build the ioctl
@@ -19,9 +20,8 @@
* each ioctl command you want to execute.
*/
typedef void (*dm_log_fn)(int level, const char *file, int line,
const char *f, ...);
typedef void (*dm_log_fn) (int level, const char *file, int line,
const char *f, ...);
/*
* The library user may wish to register their own
@@ -34,16 +34,21 @@ enum {
DM_DEVICE_CREATE,
DM_DEVICE_RELOAD,
DM_DEVICE_REMOVE,
DM_DEVICE_REMOVE_ALL,
DM_DEVICE_SUSPEND,
DM_DEVICE_RESUME,
DM_DEVICE_INFO,
DM_DEVICE_DEPS,
DM_DEVICE_RENAME,
DM_DEVICE_VERSION,
};
DM_DEVICE_STATUS,
DM_DEVICE_TABLE,
DM_DEVICE_WAITEVENT
};
struct dm_task;
@@ -51,6 +56,7 @@ struct dm_task *dm_task_create(int type);
void dm_task_destroy(struct dm_task *dmt);
int dm_task_set_name(struct dm_task *dmt, const char *name);
int dm_task_set_uuid(struct dm_task *dmt, const char *uuid);
/*
* Retrieve attributes after an info.
@@ -66,9 +72,17 @@ struct dm_info {
unsigned int target_count;
};
struct dm_deps {
unsigned int count;
__kernel_dev_t device[0];
};
int dm_get_library_version(char *version, size_t size);
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
const char *dm_task_get_uuid(struct dm_task *dmt);
struct dm_deps *dm_task_get_deps(struct dm_task *dmt);
int dm_task_set_ro(struct dm_task *dmt);
int dm_task_set_newname(struct dm_task *dmt, const char *newname);
@@ -79,9 +93,12 @@ int dm_task_set_minor(struct dm_task *dmt, int minor);
*/
int dm_task_add_target(struct dm_task *dmt,
uint64_t start,
uint64_t size,
const char *ttype,
const char *params);
uint64_t size, const char *ttype, const char *params);
/* Use this to retrive target information returned from a STATUS call */
void *dm_get_next_target(struct dm_task *dmt,
void *next, uint64_t *start, uint64_t *length,
char **target_type, char **params);
/*
* Call this to actually run the ioctl.
@@ -94,4 +111,4 @@ int dm_task_run(struct dm_task *dmt);
int dm_set_dev_dir(const char *dir);
const char *dm_dir(void);
#endif /* LIB_DEVICE_MAPPER_H */
#endif /* LIB_DEVICE_MAPPER_H */

View File

@@ -30,23 +30,30 @@ static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR;
* Library users can provide their own logging
* function.
*/
void _default_log(int level, const char *file, int line,
const char *f, ...)
void _default_log(int level, const char *file, int line, const char *f, ...)
{
va_list ap;
va_list ap;
va_start(ap, f);
vfprintf(stderr, f, ap);
va_end(ap);
if (level > _LOG_WARN)
return;
fprintf(stderr, "\n");
va_start(ap, f);
if (level == _LOG_WARN)
vprintf(f, ap);
else
vfprintf(stderr, f, ap);
va_end(ap);
fprintf(stderr, "\n");
}
dm_log_fn _log = _default_log;
void dm_log_init(dm_log_fn fn)
{
_log = fn;
_log = fn;
}
void _build_dev_path(char *buffer, size_t len, const char *dev_name)
@@ -55,7 +62,7 @@ void _build_dev_path(char *buffer, size_t len, const char *dev_name)
if (strchr(dev_name, '/'))
snprintf(buffer, len, "%s", dev_name);
else
snprintf(buffer, len, "%s/%s", _dm_dir, dev_name);
snprintf(buffer, len, "%s/%s", _dm_dir, dev_name);
}
int dm_get_library_version(char *version, size_t size)
@@ -66,18 +73,18 @@ int dm_get_library_version(char *version, size_t size)
struct dm_task *dm_task_create(int type)
{
struct dm_task *dmt = malloc(sizeof(*dmt));
struct dm_task *dmt = malloc(sizeof(*dmt));
if (!dmt) {
log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt));
return NULL;
}
if (!dmt) {
log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt));
return NULL;
}
memset(dmt, 0, sizeof(*dmt));
memset(dmt, 0, sizeof(*dmt));
dmt->type = type;
dmt->type = type;
dmt->minor = -1;
return dmt;
return dmt;
}
int dm_task_set_name(struct dm_task *dmt, const char *name)
@@ -86,8 +93,10 @@ int dm_task_set_name(struct dm_task *dmt, const char *name)
char path[PATH_MAX];
struct stat st1, st2;
if (dmt->dev_name)
free(dmt->dev_name);
if (dmt->dev_name) {
free(dmt->dev_name);
dmt->dev_name = NULL;
}
/* If path was supplied, remove it if it points to the same device
* as its last component.
@@ -97,106 +106,156 @@ int dm_task_set_name(struct dm_task *dmt, const char *name)
if (stat(name, &st1) || stat(path, &st2) ||
!(st1.st_dev == st2.st_dev)) {
log_error("dm_task_set_name: Device %s not found", name);
log_error("dm_task_set_name: Device %s not found",
name);
return 0;
}
name = pos + 1;
}
if (!(dmt->dev_name = strdup(name))) {
if (!(dmt->dev_name = strdup(name))) {
log_error("dm_task_set_name: strdup(%s) failed", name);
return 0;
}
return 1;
return 1;
}
int dm_task_set_uuid(struct dm_task *dmt, const char *uuid)
{
if (dmt->uuid) {
free(dmt->uuid);
dmt->uuid = NULL;
}
if (!(dmt->uuid = strdup(uuid))) {
log_error("dm_task_set_uuid: strdup(%s) failed", uuid);
return 0;
}
return 1;
}
int dm_task_set_minor(struct dm_task *dmt, int minor)
{
dmt->minor = minor;
return 1;
dmt->minor = minor;
log_debug("Setting minor: %d", dmt->minor);
return 1;
}
int dm_task_add_target(struct dm_task *dmt,
uint64_t start,
uint64_t size,
const char *ttype,
const char *params)
int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
const char *ttype, const char *params)
{
struct target *t = create_target(start, size, ttype, params);
struct target *t = create_target(start, size, ttype, params);
if (!t)
return 0;
if (!t)
return 0;
if (!dmt->head)
dmt->head = dmt->tail = t;
else {
dmt->tail->next = t;
dmt->tail = t;
}
if (!dmt->head)
dmt->head = dmt->tail = t;
else {
dmt->tail->next = t;
dmt->tail = t;
}
return 1;
return 1;
}
int add_dev_node(const char *dev_name, dev_t dev)
{
char path[PATH_MAX];
struct stat info;
char path[PATH_MAX];
struct stat info;
_build_dev_path(path, sizeof(path), dev_name);
_build_dev_path(path, sizeof(path), dev_name);
if (stat(path, &info) >= 0) {
if (!S_ISBLK(info.st_mode)) {
log_error("A non-block device file at '%s' "
"is already present", path);
return 0;
}
if (stat(path, &info) >= 0) {
if (!S_ISBLK(info.st_mode)) {
log_error("A non-block device file at '%s' "
"is already present", path);
return 0;
}
if (info.st_rdev == dev)
return 1;
if (info.st_rdev == dev)
return 1;
if (unlink(path) < 0) {
log_error("Unable to unlink device node for '%s'", dev_name);
return 0;
}
}
if (unlink(path) < 0) {
log_error("Unable to unlink device node for '%s'",
dev_name);
return 0;
}
}
if (mknod(path, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, dev) < 0) {
log_error("Unable to make device node for '%s'", dev_name);
return 0;
}
if (mknod(path, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, dev) < 0) {
log_error("Unable to make device node for '%s'", dev_name);
return 0;
}
return 1;
return 1;
}
int rename_dev_node(const char *old_name, const char *new_name)
{
char oldpath[PATH_MAX];
char newpath[PATH_MAX];
struct stat info;
_build_dev_path(oldpath, sizeof(oldpath), old_name);
_build_dev_path(newpath, sizeof(newpath), new_name);
if (stat(newpath, &info) == 0) {
if (!S_ISBLK(info.st_mode)) {
log_error("A non-block device file at '%s' "
"is already present", newpath);
return 0;
}
if (unlink(newpath) < 0) {
if (errno == EPERM) {
/* devfs, entry has already been renamed */
return 1;
}
log_error("Unable to unlink device node for '%s'",
new_name);
return 0;
}
}
if (rename(oldpath, newpath) < 0) {
log_error("Unable to rename device node from '%s' to '%s'",
old_name, new_name);
return 0;
}
return 1;
}
int rm_dev_node(const char *dev_name)
{
char path[PATH_MAX];
struct stat info;
char path[PATH_MAX];
struct stat info;
_build_dev_path(path, sizeof(path), dev_name);
_build_dev_path(path, sizeof(path), dev_name);
if (stat(path, &info) < 0)
return 1;
if (stat(path, &info) < 0)
return 1;
if (unlink(path) < 0) {
log_error("Unable to unlink device node for '%s'", dev_name);
return 0;
}
if (unlink(path) < 0) {
log_error("Unable to unlink device node for '%s'", dev_name);
return 0;
}
return 1;
return 1;
}
int dm_set_dev_dir(const char *dir)
{
snprintf(_dm_dir, sizeof(_dm_dir), "%s%s", dir, DM_DIR);
return 1;
snprintf(_dm_dir, sizeof(_dm_dir), "%s%s", dir, DM_DIR);
return 1;
}
const char *dm_dir(void)
{
return _dm_dir;
return _dm_dir;
}

View File

@@ -25,6 +25,7 @@ extern struct target *create_target(uint64_t start,
int add_dev_node(const char *dev_name, dev_t dev);
int rm_dev_node(const char *dev_name);
int rename_dev_node(const char *old_name, const char *new_name);
#define DM_LIB_VERSION @DM_LIB_VERSION@

View File

@@ -21,7 +21,11 @@ top_srcdir = @top_srcdir@
VPATH = @srcdir@
MAN5=lvm.conf.5
MAN8=lvm.8
MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \
lvreduce.8 lvremove.8 lvrename.8 lvscan.8 pvchange.8 \
pvcreate.8 pvdisplay.8 pvscan.8 vgcfgbackup.8 vgchange.8 vgck.8 \
vgcreate.8 vgdisplay.8 vgextend.8 vgmerge.8 vgreduce.8 vgremove.8 \
vgrename.8 vgscan.8
MAN5DIR=${mandir}/man5
MAN8DIR=${mandir}/man8

Some files were not shown because too many files have changed in this diff Show More