pax_global_header00006660000000000000000000000064116657261210014521gustar00rootroot0000000000000052 comment=fdb6c0402337d9607c7a39155088eaf033742752 btrfs-progs/000077500000000000000000000000001166572612100133355ustar00rootroot00000000000000btrfs-progs/.gitignore000066400000000000000000000002211166572612100153200ustar00rootroot00000000000000*.o .*.o.d version.h man/*.gz btrfs btrfs-debug-tree btrfs-map-logical btrfs-show btrfs-vol btrfsck btrfsctl find-root mkfs.btrfs repair restore btrfs-progs/.hgignore000066400000000000000000000000121166572612100151310ustar00rootroot00000000000000version.h btrfs-progs/.hgtags000066400000000000000000000012711166572612100146140ustar00rootroot000000000000009cebac62e0c9df99a4ac5a9d489efe0c2e957713 v0.2 1ef7cf63ac2c67e99b1a1c084554e9c87b08d2b0 v0.3 c760f17dde33c970fc91ece5360567320396b627 v0.4 c969452d5ae70db57fdd668557fbdb07756101e8 v0.4 85bf731757729f25aaf76e47837b39122bea569f v0.5 75b9a16fff1ae31c572317f2516476750fd1919a v0.6 f4810b8d5822f06f7104806477863756886eb57f v0.8 99eb8cf2ca515c2d747ec132e166222089b17056 v0.9 548ea8d7514ba7fed921983029e5ef690fb3ef0a v0.10 b3e59089dab67cc3ba52f83f41e9650773d89bd7 v0.11 5e8f040cdf7c1d7e2cb583444b9434c31b673935 v0.12 58b803dc9faeb19f2260f8aa37a8a4590fae085b v0.13 969099968b60600901f90531fddd2f18e32ac336 v0.14 e6571e2ce0c8ac9fcad9b5b638008e7c8980bf4d v0.15 2b26e4f8c71ea411d7df35f23e38627cdcbef310 v0.16 btrfs-progs/COPYING000066400000000000000000000431341166572612100143750ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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. This program 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. btrfs-progs/INSTALL000066400000000000000000000034101166572612100143640ustar00rootroot00000000000000Install Instructions Btrfs puts snapshots and subvolumes into the root directory of the FS. This directory can only be changed by btrfsctl right now, and normal filesystem operations do not work on it. The default subvolume is called 'default', and you can create files and directories in mount_point/default Btrfs uses libcrc32c in the kernel for file and metadata checksums. You need to compile the kernel with: CONFIG_LIBCRC32C=m libcrc32c can be static as well. Once your kernel is setup, typing make in the btrfs module sources will build against the running kernel. When the build is complete: modprobe libcrc32c insmod btrfs.ko The Btrfs utility programs require libuuid to build. This can be found in the e2fsprogs sources, and is usually available as libuuid or e2fsprogs-devel from various distros. Building the utilities is just make ; make install. The programs go into /usr/local/bin. The mains commands available are: mkfs.btrfs: create a filesystem btrfs: control program to create snapshots and subvolumes: # mount a btrfs filesystem mount /dev/sda2 /mnt # create a subvolume btrfs subvolume create /mnt/new_subvol_name # snapshot of a subvolume btrfs subvolume snapshot /mnt/default /mnt/snapshot_of_default btrfs subvolume snapshot /mnt/snapshot_of_default \ /mnt/snapshot_of_a_snapshot # list of the subvolumes ls /mnt default snapshot_of_a_snapshot snapshot_of_new_subvol new_subvol_name snapshot_of_default # removal of a subvolume or a snapshot btrfs subvolume delete /mn/snapshot_of_a_snapshot # look a the btrfs man page for further information man btrfs btrfsck: do a limited check of the FS extent trees. btrfs-debug-tree: print all of the FS metadata in text form. Example: btrfs-debug-tree /dev/sda2 >& big_output_file btrfs-progs/Makefile000066400000000000000000000072331166572612100150020ustar00rootroot00000000000000CC = gcc AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 CFLAGS = -g -O0 objects = ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ root-tree.o dir-item.o file-item.o inode-item.o \ inode-map.o crc32c.o rbtree.o extent-cache.o extent_io.o \ volumes.o utils.o btrfs-list.o btrfslabel.o CHECKFLAGS= -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise \ -Wuninitialized -Wshadow -Wundef DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ INSTALL = install prefix ?= /usr/local bindir = $(prefix)/bin LIBS=-luuid RESTORE_LIBS=-lz progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \ btrfs btrfs-map-logical restore find-root calc-size btrfs-corrupt-block # make C=1 to enable sparse ifdef C check = sparse $(CHECKFLAGS) else check = ls endif .c.o: $(check) $< $(CC) $(DEPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c $< all: version $(progs) manpages version: bash version.sh btrfs: $(objects) btrfs.o btrfs_cmds.o scrub.o $(CC) $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o scrub.o \ $(objects) $(LDFLAGS) $(LIBS) -lpthread calc-size: $(objects) calc-size.o gcc $(CFLAGS) -o calc-size calc-size.o $(objects) $(LDFLAGS) $(LIBS) find-root: $(objects) find-root.o gcc $(CFLAGS) -o find-root find-root.o $(objects) $(LDFLAGS) $(LIBS) restore: $(objects) restore.o gcc $(CFLAGS) -o restore restore.o $(objects) $(LDFLAGS) $(LIBS) $(RESTORE_LIBS) btrfsctl: $(objects) btrfsctl.o $(CC) $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS) btrfs-vol: $(objects) btrfs-vol.o $(CC) $(CFLAGS) -o btrfs-vol btrfs-vol.o $(objects) $(LDFLAGS) $(LIBS) btrfs-show: $(objects) btrfs-show.o $(CC) $(CFLAGS) -o btrfs-show btrfs-show.o $(objects) $(LDFLAGS) $(LIBS) btrfsck: $(objects) btrfsck.o $(CC) $(CFLAGS) -o btrfsck btrfsck.o $(objects) $(LDFLAGS) $(LIBS) mkfs.btrfs: $(objects) mkfs.o $(CC) $(CFLAGS) -o mkfs.btrfs $(objects) mkfs.o $(LDFLAGS) $(LIBS) btrfs-debug-tree: $(objects) debug-tree.o $(CC) $(CFLAGS) -o btrfs-debug-tree $(objects) debug-tree.o $(LDFLAGS) $(LIBS) btrfs-zero-log: $(objects) btrfs-zero-log.o $(CC) $(CFLAGS) -o btrfs-zero-log $(objects) btrfs-zero-log.o $(LDFLAGS) $(LIBS) btrfs-select-super: $(objects) btrfs-select-super.o $(CC) $(CFLAGS) -o btrfs-select-super $(objects) btrfs-select-super.o $(LDFLAGS) $(LIBS) btrfstune: $(objects) btrfstune.o $(CC) $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS) btrfs-map-logical: $(objects) btrfs-map-logical.o $(CC) $(CFLAGS) -o btrfs-map-logical $(objects) btrfs-map-logical.o $(LDFLAGS) $(LIBS) btrfs-corrupt-block: $(objects) btrfs-corrupt-block.o $(CC) $(CFLAGS) -o btrfs-corrupt-block $(objects) btrfs-corrupt-block.o $(LDFLAGS) $(LIBS) btrfs-image: $(objects) btrfs-image.o $(CC) $(CFLAGS) -o btrfs-image $(objects) btrfs-image.o -lpthread -lz $(LDFLAGS) $(LIBS) dir-test: $(objects) dir-test.o $(CC) $(CFLAGS) -o dir-test $(objects) dir-test.o $(LDFLAGS) $(LIBS) quick-test: $(objects) quick-test.o $(CC) $(CFLAGS) -o quick-test $(objects) quick-test.o $(LDFLAGS) $(LIBS) convert: $(objects) convert.o $(CC) $(CFLAGS) -o btrfs-convert $(objects) convert.o -lext2fs -lcom_err $(LDFLAGS) $(LIBS) ioctl-test: $(objects) ioctl-test.o $(CC) $(CFLAGS) -o ioctl-test $(objects) ioctl-test.o $(LDFLAGS) $(LIBS) manpages: cd man; make install-man: cd man; make install clean : rm -f $(progs) cscope.out *.o .*.d btrfs-convert btrfs-image btrfs-select-super \ btrfs-zero-log btrfstune dir-test ioctl-test quick-test version.h cd man; make clean install: $(progs) install-man $(INSTALL) -m755 -d $(DESTDIR)$(bindir) $(INSTALL) $(progs) $(DESTDIR)$(bindir) if [ -e btrfs-convert ]; then $(INSTALL) btrfs-convert $(DESTDIR)$(bindir); fi -include .*.d btrfs-progs/bcp000077500000000000000000000114431166572612100140320ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (C) 2007 Oracle. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License v2 as published by the Free Software Foundation. # # This program 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 021110-1307, USA. # import sys, os, stat, fcntl from optparse import OptionParser def copylink(srcname, dst, filename, statinfo, force_name): dstname = os.path.join(dst, force_name or filename) if not os.path.exists(dstname): link_target = os.readlink(srcname) os.symlink(link_target, dstname) def copydev(srcname, dst, filename, statinfo, force_name): devbits = statinfo.st_mode & (stat.S_IFBLK | stat.S_IFCHR) mode = stat.S_IMODE(statinfo.st_mode) | devbits dstname = os.path.join(dst, force_name or filename) if not os.path.exists(dstname): os.mknod(dstname, mode, statinfo.st_rdev) def copyfile(srcname, dst, filename, statinfo, force_name): written = 0 dstname = os.path.join(dst, force_name or filename) st_mode = statinfo.st_mode if stat.S_ISLNK(st_mode): copylink(srcname, dst, part, statinfo, None) return elif stat.S_ISBLK(st_mode) or stat.S_ISCHR(st_mode): copydev(srcname, dst, part, statinfo, None) return elif not stat.S_ISREG(st_mode): return try: os.unlink(dstname) except: pass if options.link: os.link(srcname, dstname) return dstf = file(dstname, 'w') srcf = file(srcname, 'r') ret = 1 try: if not options.copy: ret = fcntl.ioctl(dstf.fileno(), 1074041865, srcf.fileno()) except: pass if ret != 0: while True: buf = srcf.read(256 * 1024) if not buf: break written += len(buf) dstf.write(buf) os.chmod(dstname, stat.S_IMODE(statinfo.st_mode)) os.chown(dstname, statinfo.st_uid, statinfo.st_gid) usage = "usage: %prog [options]" parser = OptionParser(usage=usage) parser.add_option("-l", "--link", help="Create hard links", default=False, action="store_true") parser.add_option("-c", "--copy", help="Copy file bytes (don't cow)", default=False, action="store_true") (options,args) = parser.parse_args() if len(args) < 2: sys.stderr.write("source or destination not specified\n") sys.exit(1) if options.link and options.copy: sys.stderr.write("Both -l and -c specified, using copy mode\n") options.link = False total_args = len(args) src_args = total_args - 1 orig_dst = args[-1] if src_args > 1: if not os.path.exists(orig_dst): os.makedirs(orig_dst) if not os.path.isdir(orig_dst): sys.stderr.write("Destination %s is not a directory\n" % orig_dst) exit(1) for srci in xrange(0, src_args): src = args[srci] if os.path.isfile(src): statinfo = os.lstat(src) force_name = None if src_args == 1: if not os.path.isdir(orig_dst): force_name = os.path.basename(orig_dst) orig_dst = os.path.dirname(orig_dst) or '.' copyfile(src, orig_dst, os.path.basename(src), statinfo, force_name) continue if src_args > 1 or os.path.exists(orig_dst): dst = os.path.join(orig_dst, os.path.basename(src)) else: dst = orig_dst if not os.path.exists(dst): os.makedirs(dst) statinfo = os.stat(src) os.chmod(dst, stat.S_IMODE(statinfo.st_mode)) os.chown(dst, statinfo.st_uid, statinfo.st_gid) iter = os.walk(src, topdown=True) for (dirpath, dirnames, filenames) in iter: for x in dirnames: srcname = os.path.join(dirpath, x) statinfo = os.lstat(srcname) part = os.path.relpath(srcname, src) if stat.S_ISLNK(statinfo.st_mode): copylink(srcname, dst, part, statinfo, None) continue dst_dir = os.path.join(dst, part) if not os.path.exists(dst_dir): os.makedirs(dst_dir) os.chmod(dst_dir, stat.S_IMODE(statinfo.st_mode)) os.chown(dst_dir, statinfo.st_uid, statinfo.st_gid) for f in filenames: srcname = os.path.join(dirpath, f) part = os.path.relpath(srcname, src) statinfo = os.lstat(srcname) copyfile(srcname, dst, part, statinfo, None) btrfs-progs/bit-radix.c000066400000000000000000000113451166572612100153700ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #include "kerncompat.h" #include "radix-tree.h" #define BIT_ARRAY_BYTES 256 #define BIT_RADIX_BITS_PER_ARRAY ((BIT_ARRAY_BYTES - sizeof(unsigned long)) * 8) int set_radix_bit(struct radix_tree_root *radix, unsigned long bit) { unsigned long *bits; unsigned long slot; int bit_slot; int ret; slot = bit / BIT_RADIX_BITS_PER_ARRAY; bit_slot = bit % BIT_RADIX_BITS_PER_ARRAY; bits = radix_tree_lookup(radix, slot); if (!bits) { bits = malloc(BIT_ARRAY_BYTES); if (!bits) return -ENOMEM; memset(bits + 1, 0, BIT_ARRAY_BYTES - sizeof(unsigned long)); bits[0] = slot; radix_tree_preload(GFP_NOFS); ret = radix_tree_insert(radix, slot, bits); radix_tree_preload_end(); if (ret) return ret; } __set_bit(bit_slot, bits + 1); return 0; } int test_radix_bit(struct radix_tree_root *radix, unsigned long bit) { unsigned long *bits; unsigned long slot; int bit_slot; slot = bit / BIT_RADIX_BITS_PER_ARRAY; bit_slot = bit % BIT_RADIX_BITS_PER_ARRAY; bits = radix_tree_lookup(radix, slot); if (!bits) return 0; return test_bit(bit_slot, bits + 1); } int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit) { unsigned long *bits; unsigned long slot; int bit_slot; int i; int empty = 1; slot = bit / BIT_RADIX_BITS_PER_ARRAY; bit_slot = bit % BIT_RADIX_BITS_PER_ARRAY; bits = radix_tree_lookup(radix, slot); if (!bits) return 0; __clear_bit(bit_slot, bits + 1); for (i = 1; i < BIT_ARRAY_BYTES / sizeof(unsigned long); i++) { if (bits[i]) { empty = 0; break; } } if (empty) { bits = radix_tree_delete(radix, slot); BUG_ON(!bits); free(bits); } return 0; } #define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) /** * __ffs - find first bit in word. * @word: The word to search * * Undefined if no bit exists, so code should check against 0 first. */ static unsigned long __ffs(unsigned long word) { int num = 0; if (sizeof(long) == 8 && (word & 0xffffffff) == 0) { num += 32; word >>= sizeof(long) * 4; } if ((word & 0xffff) == 0) { num += 16; word >>= 16; } if ((word & 0xff) == 0) { num += 8; word >>= 8; } if ((word & 0xf) == 0) { num += 4; word >>= 4; } if ((word & 0x3) == 0) { num += 2; word >>= 2; } if ((word & 0x1) == 0) num += 1; return num; } /** * find_next_bit - find the next set bit in a memory region * @addr: The address to base the search on * @offset: The bitnumber to start searching at * @size: The maximum size to search */ unsigned long find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) { const unsigned long *p = addr + BITOP_WORD(offset); unsigned long result = offset & ~(BITS_PER_LONG-1); unsigned long tmp; if (offset >= size) return size; size -= result; offset %= BITS_PER_LONG; if (offset) { tmp = *(p++); tmp &= (~0UL << offset); if (size < BITS_PER_LONG) goto found_first; if (tmp) goto found_middle; size -= BITS_PER_LONG; result += BITS_PER_LONG; } while (size & ~(BITS_PER_LONG-1)) { if ((tmp = *(p++))) goto found_middle; result += BITS_PER_LONG; size -= BITS_PER_LONG; } if (!size) return result; tmp = *p; found_first: tmp &= (~0UL >> (BITS_PER_LONG - size)); if (tmp == 0UL) /* Are any bits set? */ return result + size; /* Nope. */ found_middle: return result + __ffs(tmp); } int find_first_radix_bit(struct radix_tree_root *radix, unsigned long *retbits, unsigned long start, int nr) { unsigned long *bits; unsigned long *gang[4]; int found; int ret; int i; int total_found = 0; unsigned long slot; slot = start / BIT_RADIX_BITS_PER_ARRAY; ret = radix_tree_gang_lookup(radix, (void *)gang, slot, ARRAY_SIZE(gang)); found = start % BIT_RADIX_BITS_PER_ARRAY; for (i = 0; i < ret && nr > 0; i++) { bits = gang[i]; while(nr > 0) { found = find_next_bit(bits + 1, BIT_RADIX_BITS_PER_ARRAY, found); if (found < BIT_RADIX_BITS_PER_ARRAY) { *retbits = bits[0] * BIT_RADIX_BITS_PER_ARRAY + found; retbits++; nr--; total_found++; found++; } else break; } found = 0; } return total_found; } btrfs-progs/bit-radix.h000066400000000000000000000022761166572612100154000ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #ifndef __BIT_RADIX__ #define __BIT_RADIX__ #include "radix-tree.h" int set_radix_bit(struct radix_tree_root *radix, unsigned long bit); int test_radix_bit(struct radix_tree_root *radix, unsigned long bit); int clear_radix_bit(struct radix_tree_root *radix, unsigned long bit); int find_first_radix_bit(struct radix_tree_root *radix, unsigned long *retbits, unsigned long start, int nr); static inline void init_bit_radix(struct radix_tree_root *radix) { INIT_RADIX_TREE(radix, GFP_NOFS); } #endif btrfs-progs/btrfs-corrupt-block.c000066400000000000000000000116751166572612100174170ustar00rootroot00000000000000/* * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _XOPEN_SOURCE 500 #define _GNU_SOURCE 1 #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "volumes.h" #include "disk-io.h" #include "print-tree.h" #include "transaction.h" #include "list.h" #include "version.h" /* we write the mirror info to stdout unless they are dumping the data * to stdout * */ static FILE *info_file; struct extent_buffer *debug_corrupt_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, int copy) { int ret; struct extent_buffer *eb; u64 length; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; int num_copies; int mirror_num = 1; eb = btrfs_find_create_tree_block(root, bytenr, blocksize); if (!eb) return NULL; length = blocksize; while (1) { ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, eb->start, &length, &multi, mirror_num); BUG_ON(ret); device = multi->stripes[0].dev; eb->fd = device->fd; device->total_ios++; eb->dev_bytenr = multi->stripes[0].physical; fprintf(info_file, "mirror %d logical %Lu physical %Lu " "device %s\n", mirror_num, (unsigned long long)bytenr, (unsigned long long)eb->dev_bytenr, device->name); kfree(multi); if (!copy || mirror_num == copy) { ret = read_extent_from_disk(eb); printf("corrupting %llu copy %d\n", eb->start, mirror_num); memset(eb->data, 0, eb->len); write_extent_to_disk(eb); fsync(eb->fd); } num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, eb->start, eb->len); if (num_copies == 1) break; mirror_num++; if (mirror_num > num_copies) break; } return eb; } static void print_usage(void) { fprintf(stderr, "usage: btrfs-map-logical [options] mount_point\n"); fprintf(stderr, "\t-l Logical extent to map\n"); fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n"); fprintf(stderr, "\t-o Output file to hold the extent\n"); fprintf(stderr, "\t-b Number of bytes to read\n"); exit(1); } static struct option long_options[] = { /* { "byte-count", 1, NULL, 'b' }, */ { "logical", 1, NULL, 'l' }, { "copy", 1, NULL, 'c' }, { "bytes", 1, NULL, 'b' }, { 0, 0, 0, 0} }; int main(int ac, char **av) { struct cache_tree root_cache; struct btrfs_root *root; struct extent_buffer *eb; char *dev; char *output_file = NULL; u64 logical = 0; int ret = 0; int option_index = 0; int copy = 0; u64 bytes = 4096; int out_fd = 0; int err; while(1) { int c; c = getopt_long(ac, av, "l:c:", long_options, &option_index); if (c < 0) break; switch(c) { case 'l': logical = atoll(optarg); if (logical == 0) { fprintf(stderr, "invalid extent number\n"); print_usage(); } break; case 'c': copy = atoi(optarg); if (copy == 0) { fprintf(stderr, "invalid copy number\n"); print_usage(); } break; case 'b': bytes = atoll(optarg); if (bytes == 0) { fprintf(stderr, "invalid byte count\n"); print_usage(); } break; default: print_usage(); } } ac = ac - optind; if (ac == 0) print_usage(); if (logical == 0) print_usage(); if (copy < 0) print_usage(); dev = av[optind]; radix_tree_init(); cache_tree_init(&root_cache); root = open_ctree(dev, 0, 1); if (!root) { fprintf(stderr, "Open ctree failed\n"); exit(1); } info_file = stdout; if (output_file) { if (strcmp(output_file, "-") == 0) { out_fd = 1; info_file = stderr; } else { out_fd = open(output_file, O_RDWR | O_CREAT, 0600); if (out_fd < 0) goto close; err = ftruncate(out_fd, 0); if (err) { close(out_fd); goto close; } info_file = stdout; } } if (bytes == 0) bytes = root->sectorsize; bytes = (bytes + root->sectorsize - 1) / root->sectorsize; bytes *= root->sectorsize; while (bytes > 0) { eb = debug_corrupt_block(root, logical, root->sectorsize, copy); if (eb && output_file) { err = write(out_fd, eb->data, eb->len); if (err < 0 || err != eb->len) { fprintf(stderr, "output file write failed\n"); goto out_close_fd; } } free_extent_buffer(eb); logical += root->sectorsize; bytes -= root->sectorsize; } out_close_fd: if (output_file && out_fd != 1) close(out_fd); close: return ret; } btrfs-progs/btrfs-defrag.c000066400000000000000000000021301166572612100160430ustar00rootroot00000000000000/* * Copyright (C) 2010 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #ifndef __CHECKER__ #include #include #include "ioctl.h" #endif #include #include #include #include #include #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "transaction.h" #include "utils.h" #include "version.h" btrfs-progs/btrfs-image.c000066400000000000000000000504141166572612100157050ustar00rootroot00000000000000/* * Copyright (C) 2008 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _XOPEN_SOURCE 500 #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include #include #include "kerncompat.h" #include "crc32c.h" #include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "utils.h" #include "version.h" #define HEADER_MAGIC 0xbd5c25e27295668bULL #define MAX_PENDING_SIZE (256 * 1024) #define BLOCK_SIZE 1024 #define BLOCK_MASK (BLOCK_SIZE - 1) #define COMPRESS_NONE 0 #define COMPRESS_ZLIB 1 struct meta_cluster_item { __le64 bytenr; __le32 size; } __attribute__ ((__packed__)); struct meta_cluster_header { __le64 magic; __le64 bytenr; __le32 nritems; u8 compress; } __attribute__ ((__packed__)); /* cluster header + index items + buffers */ struct meta_cluster { struct meta_cluster_header header; struct meta_cluster_item items[]; } __attribute__ ((__packed__)); #define ITEMS_PER_CLUSTER ((BLOCK_SIZE - sizeof(struct meta_cluster)) / \ sizeof(struct meta_cluster_item)) struct async_work { struct list_head list; struct list_head ordered; u64 start; u64 size; u8 *buffer; size_t bufsize; }; struct metadump_struct { struct btrfs_root *root; FILE *out; struct meta_cluster *cluster; pthread_t *threads; size_t num_threads; pthread_mutex_t mutex; pthread_cond_t cond; struct list_head list; struct list_head ordered; size_t num_items; size_t num_ready; u64 pending_start; u64 pending_size; int compress_level; int done; }; struct mdrestore_struct { FILE *in; FILE *out; pthread_t *threads; size_t num_threads; pthread_mutex_t mutex; pthread_cond_t cond; struct list_head list; size_t num_items; int compress_method; int done; }; static void csum_block(u8 *buf, size_t len) { char result[BTRFS_CRC32_SIZE]; u32 crc = ~(u32)0; crc = crc32c(crc, buf + BTRFS_CSUM_SIZE, len - BTRFS_CSUM_SIZE); btrfs_csum_final(crc, result); memcpy(buf, result, BTRFS_CRC32_SIZE); } /* * zero inline extents and csum items */ static void zero_items(u8 *dst, struct extent_buffer *src) { struct btrfs_file_extent_item *fi; struct btrfs_item *item; struct btrfs_key key; u32 nritems = btrfs_header_nritems(src); size_t size; unsigned long ptr; int i, extent_type; for (i = 0; i < nritems; i++) { item = btrfs_item_nr(src, i); btrfs_item_key_to_cpu(src, &key, i); if (key.type == BTRFS_CSUM_ITEM_KEY) { size = btrfs_item_size_nr(src, i); memset(dst + btrfs_leaf_data(src) + btrfs_item_offset_nr(src, i), 0, size); continue; } if (key.type != BTRFS_EXTENT_DATA_KEY) continue; fi = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); extent_type = btrfs_file_extent_type(src, fi); if (extent_type != BTRFS_FILE_EXTENT_INLINE) continue; ptr = btrfs_file_extent_inline_start(fi); size = btrfs_file_extent_inline_item_len(src, item); memset(dst + ptr, 0, size); } } /* * copy buffer and zero useless data in the buffer */ static void copy_buffer(u8 *dst, struct extent_buffer *src) { int level; size_t size; u32 nritems; memcpy(dst, src->data, src->len); if (src->start == BTRFS_SUPER_INFO_OFFSET) return; level = btrfs_header_level(src); nritems = btrfs_header_nritems(src); if (nritems == 0) { size = sizeof(struct btrfs_header); memset(dst + size, 0, src->len - size); } else if (level == 0) { size = btrfs_leaf_data(src) + btrfs_item_offset_nr(src, nritems - 1) - btrfs_item_nr_offset(nritems); memset(dst + btrfs_item_nr_offset(nritems), 0, size); zero_items(dst, src); } else { size = offsetof(struct btrfs_node, ptrs) + sizeof(struct btrfs_key_ptr) * nritems; memset(dst + size, 0, src->len - size); } csum_block(dst, src->len); } static void *dump_worker(void *data) { struct metadump_struct *md = (struct metadump_struct *)data; struct async_work *async; int ret; while (1) { pthread_mutex_lock(&md->mutex); while (list_empty(&md->list)) { if (md->done) { pthread_mutex_unlock(&md->mutex); goto out; } pthread_cond_wait(&md->cond, &md->mutex); } async = list_entry(md->list.next, struct async_work, list); list_del_init(&async->list); pthread_mutex_unlock(&md->mutex); if (md->compress_level > 0) { u8 *orig = async->buffer; async->bufsize = compressBound(async->size); async->buffer = malloc(async->bufsize); ret = compress2(async->buffer, (unsigned long *)&async->bufsize, orig, async->size, md->compress_level); BUG_ON(ret != Z_OK); free(orig); } pthread_mutex_lock(&md->mutex); md->num_ready++; pthread_mutex_unlock(&md->mutex); } out: pthread_exit(NULL); } static void meta_cluster_init(struct metadump_struct *md, u64 start) { struct meta_cluster_header *header; md->num_items = 0; md->num_ready = 0; header = &md->cluster->header; header->magic = cpu_to_le64(HEADER_MAGIC); header->bytenr = cpu_to_le64(start); header->nritems = cpu_to_le32(0); header->compress = md->compress_level > 0 ? COMPRESS_ZLIB : COMPRESS_NONE; } static int metadump_init(struct metadump_struct *md, struct btrfs_root *root, FILE *out, int num_threads, int compress_level) { int i, ret; memset(md, 0, sizeof(*md)); pthread_cond_init(&md->cond, NULL); pthread_mutex_init(&md->mutex, NULL); INIT_LIST_HEAD(&md->list); INIT_LIST_HEAD(&md->ordered); md->root = root; md->out = out; md->pending_start = (u64)-1; md->compress_level = compress_level; md->cluster = calloc(1, BLOCK_SIZE); if (!md->cluster) return -ENOMEM; meta_cluster_init(md, 0); if (!num_threads) return 0; md->num_threads = num_threads; md->threads = calloc(num_threads, sizeof(pthread_t)); if (!md->threads) return -ENOMEM; for (i = 0; i < num_threads; i++) { ret = pthread_create(md->threads + i, NULL, dump_worker, md); if (ret) break; } return ret; } static void metadump_destroy(struct metadump_struct *md) { int i; pthread_mutex_lock(&md->mutex); md->done = 1; pthread_cond_broadcast(&md->cond); pthread_mutex_unlock(&md->mutex); for (i = 0; i < md->num_threads; i++) pthread_join(md->threads[i], NULL); pthread_cond_destroy(&md->cond); pthread_mutex_destroy(&md->mutex); free(md->threads); free(md->cluster); } static int write_zero(FILE *out, size_t size) { static char zero[BLOCK_SIZE]; return fwrite(zero, size, 1, out); } static int write_buffers(struct metadump_struct *md, u64 *next) { struct meta_cluster_header *header = &md->cluster->header; struct meta_cluster_item *item; struct async_work *async; u64 bytenr = 0; u32 nritems = 0; int ret; if (list_empty(&md->ordered)) goto out; /* wait until all buffers are compressed */ while (md->num_items > md->num_ready) { struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000, }; pthread_mutex_unlock(&md->mutex); nanosleep(&ts, NULL); pthread_mutex_lock(&md->mutex); } /* setup and write index block */ list_for_each_entry(async, &md->ordered, ordered) { item = md->cluster->items + nritems; item->bytenr = cpu_to_le64(async->start); item->size = cpu_to_le32(async->bufsize); nritems++; } header->nritems = cpu_to_le32(nritems); ret = fwrite(md->cluster, BLOCK_SIZE, 1, md->out); BUG_ON(ret != 1); /* write buffers */ bytenr += le64_to_cpu(header->bytenr) + BLOCK_SIZE; while (!list_empty(&md->ordered)) { async = list_entry(md->ordered.next, struct async_work, ordered); list_del_init(&async->ordered); bytenr += async->bufsize; ret = fwrite(async->buffer, async->bufsize, 1, md->out); BUG_ON(ret != 1); free(async->buffer); free(async); } /* zero unused space in the last block */ if (bytenr & BLOCK_MASK) { size_t size = BLOCK_SIZE - (bytenr & BLOCK_MASK); bytenr += size; ret = write_zero(md->out, size); BUG_ON(ret != 1); } out: *next = bytenr; return 0; } static int flush_pending(struct metadump_struct *md, int done) { struct async_work *async = NULL; struct extent_buffer *eb; u64 blocksize = md->root->nodesize; u64 start; u64 size; size_t offset; int ret; if (md->pending_size) { async = calloc(1, sizeof(*async)); if (!async) return -ENOMEM; async->start = md->pending_start; async->size = md->pending_size; async->bufsize = async->size; async->buffer = malloc(async->bufsize); offset = 0; start = async->start; size = async->size; while (size > 0) { eb = read_tree_block(md->root, start, blocksize, 0); BUG_ON(!eb); copy_buffer(async->buffer + offset, eb); free_extent_buffer(eb); start += blocksize; offset += blocksize; size -= blocksize; } md->pending_start = (u64)-1; md->pending_size = 0; } else if (!done) { return 0; } pthread_mutex_lock(&md->mutex); if (async) { list_add_tail(&async->ordered, &md->ordered); md->num_items++; if (md->compress_level > 0) { list_add_tail(&async->list, &md->list); pthread_cond_signal(&md->cond); } else { md->num_ready++; } } if (md->num_items >= ITEMS_PER_CLUSTER || done) { ret = write_buffers(md, &start); BUG_ON(ret); meta_cluster_init(md, start); } pthread_mutex_unlock(&md->mutex); return 0; } static int add_metadata(u64 start, u64 size, struct metadump_struct *md) { int ret; if (md->pending_size + size > MAX_PENDING_SIZE || md->pending_start + md->pending_size != start) { ret = flush_pending(md, 0); if (ret) return ret; md->pending_start = start; } readahead_tree_block(md->root, start, size, 0); md->pending_size += size; return 0; } #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 static int is_tree_block(struct btrfs_root *extent_root, struct btrfs_path *path, u64 bytenr) { struct extent_buffer *leaf; struct btrfs_key key; u64 ref_objectid; int ret; leaf = path->nodes[0]; while (1) { struct btrfs_extent_ref_v0 *ref_item; path->slots[0]++; if (path->slots[0] >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(extent_root, path); BUG_ON(ret < 0); if (ret > 0) break; leaf = path->nodes[0]; } btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid != bytenr) break; if (key.type != BTRFS_EXTENT_REF_V0_KEY) continue; ref_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_ref_v0); ref_objectid = btrfs_ref_objectid_v0(leaf, ref_item); if (ref_objectid < BTRFS_FIRST_FREE_OBJECTID) return 1; break; } return 0; } #endif static int create_metadump(const char *input, FILE *out, int num_threads, int compress_level) { struct btrfs_root *root; struct btrfs_root *extent_root; struct btrfs_path *path; struct extent_buffer *leaf; struct btrfs_extent_item *ei; struct btrfs_key key; struct metadump_struct metadump; u64 bytenr; u64 num_bytes; int ret; root = open_ctree(input, 0, 0); BUG_ON(root->nodesize != root->leafsize); ret = metadump_init(&metadump, root, out, num_threads, compress_level); BUG_ON(ret); ret = add_metadata(BTRFS_SUPER_INFO_OFFSET, 4096, &metadump); BUG_ON(ret); extent_root = root->fs_info->extent_root; path = btrfs_alloc_path(); bytenr = BTRFS_SUPER_INFO_OFFSET + 4096; key.objectid = bytenr; key.type = BTRFS_EXTENT_ITEM_KEY; key.offset = 0; ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); BUG_ON(ret < 0); while (1) { leaf = path->nodes[0]; if (path->slots[0] >= btrfs_header_nritems(leaf)) { ret = btrfs_next_leaf(extent_root, path); BUG_ON(ret < 0); if (ret > 0) break; leaf = path->nodes[0]; } btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); if (key.objectid < bytenr || key.type != BTRFS_EXTENT_ITEM_KEY) { path->slots[0]++; continue; } bytenr = key.objectid; num_bytes = key.offset; if (btrfs_item_size_nr(leaf, path->slots[0]) > sizeof(*ei)) { ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); if (btrfs_extent_flags(leaf, ei) & BTRFS_EXTENT_FLAG_TREE_BLOCK) { ret = add_metadata(bytenr, num_bytes, &metadump); BUG_ON(ret); } } else { #ifdef BTRFS_COMPAT_EXTENT_TREE_V0 if (is_tree_block(extent_root, path, bytenr)) { ret = add_metadata(bytenr, num_bytes, &metadump); BUG_ON(ret); } #else BUG_ON(1); #endif } bytenr += num_bytes; } ret = flush_pending(&metadump, 1); BUG_ON(ret); metadump_destroy(&metadump); btrfs_free_path(path); ret = close_ctree(root); return 0; } static void update_super(u8 *buffer) { struct btrfs_super_block *super = (struct btrfs_super_block *)buffer; struct btrfs_chunk *chunk; struct btrfs_disk_key *key; u32 sectorsize = btrfs_super_sectorsize(super); u64 flags = btrfs_super_flags(super); flags |= BTRFS_SUPER_FLAG_METADUMP; btrfs_set_super_flags(super, flags); key = (struct btrfs_disk_key *)(super->sys_chunk_array); chunk = (struct btrfs_chunk *)(super->sys_chunk_array + sizeof(struct btrfs_disk_key)); btrfs_set_disk_key_objectid(key, BTRFS_FIRST_CHUNK_TREE_OBJECTID); btrfs_set_disk_key_type(key, BTRFS_CHUNK_ITEM_KEY); btrfs_set_disk_key_offset(key, 0); btrfs_set_stack_chunk_length(chunk, (u64)-1); btrfs_set_stack_chunk_owner(chunk, BTRFS_EXTENT_TREE_OBJECTID); btrfs_set_stack_chunk_stripe_len(chunk, 64 * 1024); btrfs_set_stack_chunk_type(chunk, BTRFS_BLOCK_GROUP_SYSTEM); btrfs_set_stack_chunk_io_align(chunk, sectorsize); btrfs_set_stack_chunk_io_width(chunk, sectorsize); btrfs_set_stack_chunk_sector_size(chunk, sectorsize); btrfs_set_stack_chunk_num_stripes(chunk, 1); btrfs_set_stack_chunk_sub_stripes(chunk, 0); chunk->stripe.devid = super->dev_item.devid; chunk->stripe.offset = cpu_to_le64(0); memcpy(chunk->stripe.dev_uuid, super->dev_item.uuid, BTRFS_UUID_SIZE); btrfs_set_super_sys_array_size(super, sizeof(*key) + sizeof(*chunk)); csum_block(buffer, 4096); } static void *restore_worker(void *data) { struct mdrestore_struct *mdres = (struct mdrestore_struct *)data; struct async_work *async; size_t size; u8 *buffer; u8 *outbuf; int outfd; int ret; outfd = fileno(mdres->out); buffer = malloc(MAX_PENDING_SIZE * 2); BUG_ON(!buffer); while (1) { pthread_mutex_lock(&mdres->mutex); while (list_empty(&mdres->list)) { if (mdres->done) { pthread_mutex_unlock(&mdres->mutex); goto out; } pthread_cond_wait(&mdres->cond, &mdres->mutex); } async = list_entry(mdres->list.next, struct async_work, list); list_del_init(&async->list); pthread_mutex_unlock(&mdres->mutex); if (mdres->compress_method == COMPRESS_ZLIB) { size = MAX_PENDING_SIZE * 2; ret = uncompress(buffer, (unsigned long *)&size, async->buffer, async->bufsize); BUG_ON(ret != Z_OK); outbuf = buffer; } else { outbuf = async->buffer; size = async->bufsize; } if (async->start == BTRFS_SUPER_INFO_OFFSET) update_super(outbuf); ret = pwrite64(outfd, outbuf, size, async->start); BUG_ON(ret != size); pthread_mutex_lock(&mdres->mutex); mdres->num_items--; pthread_mutex_unlock(&mdres->mutex); free(async->buffer); free(async); } out: free(buffer); pthread_exit(NULL); } static int mdresotre_init(struct mdrestore_struct *mdres, FILE *in, FILE *out, int num_threads) { int i, ret = 0; memset(mdres, 0, sizeof(*mdres)); pthread_cond_init(&mdres->cond, NULL); pthread_mutex_init(&mdres->mutex, NULL); INIT_LIST_HEAD(&mdres->list); mdres->in = in; mdres->out = out; if (!num_threads) return 0; mdres->num_threads = num_threads; mdres->threads = calloc(num_threads, sizeof(pthread_t)); if (!mdres->threads) return -ENOMEM; for (i = 0; i < num_threads; i++) { ret = pthread_create(mdres->threads + i, NULL, restore_worker, mdres); if (ret) break; } return ret; } static void mdresotre_destroy(struct mdrestore_struct *mdres) { int i; pthread_mutex_lock(&mdres->mutex); mdres->done = 1; pthread_cond_broadcast(&mdres->cond); pthread_mutex_unlock(&mdres->mutex); for (i = 0; i < mdres->num_threads; i++) pthread_join(mdres->threads[i], NULL); pthread_cond_destroy(&mdres->cond); pthread_mutex_destroy(&mdres->mutex); free(mdres->threads); } static int add_cluster(struct meta_cluster *cluster, struct mdrestore_struct *mdres, u64 *next) { struct meta_cluster_item *item; struct meta_cluster_header *header = &cluster->header; struct async_work *async; u64 bytenr; u32 i, nritems; int ret; BUG_ON(mdres->num_items); mdres->compress_method = header->compress; bytenr = le64_to_cpu(header->bytenr) + BLOCK_SIZE; nritems = le32_to_cpu(header->nritems); for (i = 0; i < nritems; i++) { item = &cluster->items[i]; async = calloc(1, sizeof(*async)); async->start = le64_to_cpu(item->bytenr); async->bufsize = le32_to_cpu(item->size); async->buffer = malloc(async->bufsize); ret = fread(async->buffer, async->bufsize, 1, mdres->in); BUG_ON(ret != 1); bytenr += async->bufsize; pthread_mutex_lock(&mdres->mutex); list_add_tail(&async->list, &mdres->list); mdres->num_items++; pthread_cond_signal(&mdres->cond); pthread_mutex_unlock(&mdres->mutex); } if (bytenr & BLOCK_MASK) { char buffer[BLOCK_MASK]; size_t size = BLOCK_SIZE - (bytenr & BLOCK_MASK); bytenr += size; ret = fread(buffer, size, 1, mdres->in); BUG_ON(ret != 1); } *next = bytenr; return 0; } static int wait_for_worker(struct mdrestore_struct *mdres) { pthread_mutex_lock(&mdres->mutex); while (mdres->num_items > 0) { struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000, }; pthread_mutex_unlock(&mdres->mutex); nanosleep(&ts, NULL); pthread_mutex_lock(&mdres->mutex); } pthread_mutex_unlock(&mdres->mutex); return 0; } static int restore_metadump(const char *input, FILE *out, int num_threads) { struct meta_cluster *cluster; struct meta_cluster_header *header; struct mdrestore_struct mdrestore; u64 bytenr = 0; FILE *in; int ret; if (!strcmp(input, "-")) { in = stdin; } else { in = fopen(input, "r"); if (!in) { perror("unable to open metadump image"); return 1; } } cluster = malloc(BLOCK_SIZE); BUG_ON(!cluster); ret = mdresotre_init(&mdrestore, in, out, num_threads); BUG_ON(ret); while (1) { ret = fread(cluster, BLOCK_SIZE, 1, in); if (!ret) break; header = &cluster->header; if (le64_to_cpu(header->magic) != HEADER_MAGIC || le64_to_cpu(header->bytenr) != bytenr) { fprintf(stderr, "bad header in metadump image\n"); return 1; } ret = add_cluster(cluster, &mdrestore, &bytenr); BUG_ON(ret); wait_for_worker(&mdrestore); } mdresotre_destroy(&mdrestore); free(cluster); if (in != stdin) fclose(in); return ret; } static void print_usage(void) { fprintf(stderr, "usage: btrfs-image [options] source target\n"); fprintf(stderr, "\t-r \trestore metadump image\n"); fprintf(stderr, "\t-c value\tcompression level (0 ~ 9)\n"); fprintf(stderr, "\t-t value\tnumber of threads (1 ~ 32)\n"); exit(1); } int main(int argc, char *argv[]) { char *source; char *target; int num_threads = 0; int compress_level = 0; int create = 1; int ret; FILE *out; while (1) { int c = getopt(argc, argv, "rc:t:"); if (c < 0) break; switch (c) { case 'r': create = 0; break; case 't': num_threads = atoi(optarg); if (num_threads <= 0 || num_threads > 32) print_usage(); break; case 'c': compress_level = atoi(optarg); if (compress_level < 0 || compress_level > 9) print_usage(); break; default: print_usage(); } } argc = argc - optind; if (argc != 2) print_usage(); source = argv[optind]; target = argv[optind + 1]; if (create && !strcmp(target, "-")) { out = stdout; } else { out = fopen(target, "w+"); if (!out) { perror("unable to create target file"); exit(1); } } if (num_threads == 0 && compress_level > 0) { num_threads = sysconf(_SC_NPROCESSORS_ONLN); if (num_threads <= 0) num_threads = 1; } if (create) ret = create_metadump(source, out, num_threads, compress_level); else ret = restore_metadump(source, out, 1); if (out == stdout) fflush(out); else fclose(out); exit(ret); } btrfs-progs/btrfs-list.c000066400000000000000000000527121166572612100156010ustar00rootroot00000000000000/* * Copyright (C) 2010 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _GNU_SOURCE #ifndef __CHECKER__ #include #include #include "ioctl.h" #endif #include #include #include #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "transaction.h" #include "utils.h" /* we store all the roots we find in an rbtree so that we can * search for them later. */ struct root_lookup { struct rb_root root; }; /* * one of these for each root we find. */ struct root_info { struct rb_node rb_node; /* this root's id */ u64 root_id; /* the id of the root that references this one */ u64 ref_tree; /* the dir id we're in from ref_tree */ u64 dir_id; /* path from the subvol we live in to this root, including the * root's name. This is null until we do the extra lookup ioctl. */ char *path; /* the name of this root in the directory it lives in */ char name[]; }; static void root_lookup_init(struct root_lookup *tree) { tree->root.rb_node = NULL; } static int comp_entry(struct root_info *entry, u64 root_id, u64 ref_tree) { if (entry->root_id > root_id) return 1; if (entry->root_id < root_id) return -1; if (entry->ref_tree > ref_tree) return 1; if (entry->ref_tree < ref_tree) return -1; return 0; } /* * insert a new root into the tree. returns the existing root entry * if one is already there. Both root_id and ref_tree are used * as the key */ static struct rb_node *tree_insert(struct rb_root *root, u64 root_id, u64 ref_tree, struct rb_node *node) { struct rb_node ** p = &root->rb_node; struct rb_node * parent = NULL; struct root_info *entry; int comp; while(*p) { parent = *p; entry = rb_entry(parent, struct root_info, rb_node); comp = comp_entry(entry, root_id, ref_tree); if (comp < 0) p = &(*p)->rb_left; else if (comp > 0) p = &(*p)->rb_right; else return parent; } entry = rb_entry(parent, struct root_info, rb_node); rb_link_node(node, parent, p); rb_insert_color(node, root); return NULL; } /* * find a given root id in the tree. We return the smallest one, * rb_next can be used to move forward looking for more if required */ static struct root_info *tree_search(struct rb_root *root, u64 root_id) { struct rb_node * n = root->rb_node; struct root_info *entry; while(n) { entry = rb_entry(n, struct root_info, rb_node); if (entry->root_id < root_id) n = n->rb_left; else if (entry->root_id > root_id) n = n->rb_right; else { struct root_info *prev; struct rb_node *prev_n; while (1) { prev_n = rb_prev(n); if (!prev_n) break; prev = rb_entry(prev_n, struct root_info, rb_node); if (prev->root_id != root_id) break; entry = prev; n = prev_n; } return entry; } } return NULL; } /* * this allocates a new root in the lookup tree. * * root_id should be the object id of the root * * ref_tree is the objectid of the referring root. * * dir_id is the directory in ref_tree where this root_id can be found. * * name is the name of root_id in that directory * * name_len is the length of name */ static int add_root(struct root_lookup *root_lookup, u64 root_id, u64 ref_tree, u64 dir_id, char *name, int name_len) { struct root_info *ri; struct rb_node *ret; ri = malloc(sizeof(*ri) + name_len + 1); if (!ri) { printf("memory allocation failed\n"); exit(1); } memset(ri, 0, sizeof(*ri) + name_len + 1); ri->path = NULL; ri->dir_id = dir_id; ri->root_id = root_id; ri->ref_tree = ref_tree; strncpy(ri->name, name, name_len); ret = tree_insert(&root_lookup->root, root_id, ref_tree, &ri->rb_node); if (ret) { printf("failed to insert tree %llu\n", (unsigned long long)root_id); exit(1); } return 0; } /* * for a given root_info, search through the root_lookup tree to construct * the full path name to it. * * This can't be called until all the root_info->path fields are filled * in by lookup_ino_path */ static int resolve_root(struct root_lookup *rl, struct root_info *ri, u64 *root_id, u64 *parent_id, u64 *top_id, char **path) { char *full_path = NULL; int len = 0; struct root_info *found; /* * we go backwards from the root_info object and add pathnames * from parent directories as we go. */ *parent_id = 0; found = ri; while (1) { char *tmp; u64 next; int add_len = strlen(found->path); /* room for / and for null */ tmp = malloc(add_len + 2 + len); if (full_path) { memcpy(tmp + add_len + 1, full_path, len); tmp[add_len] = '/'; memcpy(tmp, found->path, add_len); tmp [add_len + len + 1] = '\0'; free(full_path); full_path = tmp; len += add_len + 1; } else { full_path = strdup(found->path); len = add_len; } next = found->ref_tree; /* record the first parent */ if (*parent_id == 0) *parent_id = next; /* if the ref_tree refers to ourselves, we're at the top */ if (next == found->root_id) { *top_id = next; break; } /* * if the ref_tree wasn't in our tree of roots, we're * at the top */ found = tree_search(&rl->root, next); if (!found) { *top_id = next; break; } } *root_id = ri->root_id; *path = full_path; return 0; } /* * for a single root_info, ask the kernel to give us a path name * inside it's ref_root for the dir_id where it lives. * * This fills in root_info->path with the path to the directory and and * appends this root's name. */ static int lookup_ino_path(int fd, struct root_info *ri) { struct btrfs_ioctl_ino_lookup_args args; int ret, e; if (ri->path) return 0; memset(&args, 0, sizeof(args)); args.treeid = ri->ref_tree; args.objectid = ri->dir_id; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); e = errno; if (ret) { fprintf(stderr, "ERROR: Failed to lookup path for root %llu - %s\n", (unsigned long long)ri->ref_tree, strerror(e)); return ret; } if (args.name[0]) { /* * we're in a subdirectory of ref_tree, the kernel ioctl * puts a / in there for us */ ri->path = malloc(strlen(ri->name) + strlen(args.name) + 1); if (!ri->path) { perror("malloc failed"); exit(1); } strcpy(ri->path, args.name); strcat(ri->path, ri->name); } else { /* we're at the root of ref_tree */ ri->path = strdup(ri->name); if (!ri->path) { perror("strdup failed"); exit(1); } } return 0; } /* finding the generation for a given path is a two step process. * First we use the inode loookup routine to find out the root id * * Then we use the tree search ioctl to scan all the root items for a * given root id and spit out the latest generation we can find */ static u64 find_root_gen(int fd) { struct btrfs_ioctl_ino_lookup_args ino_args; int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; unsigned long off = 0; u64 max_found = 0; int i; int e; memset(&ino_args, 0, sizeof(ino_args)); ino_args.objectid = BTRFS_FIRST_FREE_OBJECTID; /* this ioctl fills in ino_args->treeid */ ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &ino_args); e = errno; if (ret) { fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n", (unsigned long long)BTRFS_FIRST_FREE_OBJECTID, strerror(e)); return 0; } memset(&args, 0, sizeof(args)); sk->tree_id = 1; /* * there may be more than one ROOT_ITEM key if there are * snapshots pending deletion, we have to loop through * them. */ sk->min_objectid = ino_args.treeid; sk->max_objectid = ino_args.treeid; sk->max_type = BTRFS_ROOT_ITEM_KEY; sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->nr_items = 4096; while (1) { ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(e)); return 0; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; for (i = 0; i < sk->nr_items; i++) { struct btrfs_root_item *item; sh = (struct btrfs_ioctl_search_header *)(args.buf + off); off += sizeof(*sh); item = (struct btrfs_root_item *)(args.buf + off); off += sh->len; sk->min_objectid = sh->objectid; sk->min_type = sh->type; sk->min_offset = sh->offset; if (sh->objectid > ino_args.treeid) break; if (sh->objectid == ino_args.treeid && sh->type == BTRFS_ROOT_ITEM_KEY) { max_found = max(max_found, btrfs_root_generation(item)); } } if (sk->min_offset < (u64)-1) sk->min_offset++; else break; if (sk->min_type != BTRFS_ROOT_ITEM_KEY) break; if (sk->min_objectid != BTRFS_ROOT_ITEM_KEY) break; } return max_found; } /* pass in a directory id and this will return * the full path of the parent directory inside its * subvolume root. * * It may return NULL if it is in the root, or an ERR_PTR if things * go badly. */ static char *__ino_resolve(int fd, u64 dirid) { struct btrfs_ioctl_ino_lookup_args args; int ret; char *full; int e; memset(&args, 0, sizeof(args)); args.objectid = dirid; ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); e = errno; if (ret) { fprintf(stderr, "ERROR: Failed to lookup path for dirid %llu - %s\n", (unsigned long long)dirid, strerror(e) ); return ERR_PTR(ret); } if (args.name[0]) { /* * we're in a subdirectory of ref_tree, the kernel ioctl * puts a / in there for us */ full = strdup(args.name); if (!full) { perror("malloc failed"); return ERR_PTR(-ENOMEM); } } else { /* we're at the root of ref_tree */ full = NULL; } return full; } /* * simple string builder, returning a new string with both * dirid and name */ char *build_name(char *dirid, char *name) { char *full; if (!dirid) return strdup(name); full = malloc(strlen(dirid) + strlen(name) + 1); if (!full) return NULL; strcpy(full, dirid); strcat(full, name); return full; } /* * given an inode number, this returns the full path name inside the subvolume * to that file/directory. cache_dirid and cache_name are used to * cache the results so we can avoid tree searches if a later call goes * to the same directory or file name */ static char *ino_resolve(int fd, u64 ino, u64 *cache_dirid, char **cache_name) { u64 dirid; char *dirname; char *name; char *full; int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; unsigned long off = 0; int namelen; int e; memset(&args, 0, sizeof(args)); sk->tree_id = 0; /* * step one, we search for the inode back ref. We just use the first * one */ sk->min_objectid = ino; sk->max_objectid = ino; sk->max_type = BTRFS_INODE_REF_KEY; sk->max_offset = (u64)-1; sk->min_type = BTRFS_INODE_REF_KEY; sk->max_transid = (u64)-1; sk->nr_items = 1; ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(e)); return NULL; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) return NULL; off = 0; sh = (struct btrfs_ioctl_search_header *)(args.buf + off); if (sh->type == BTRFS_INODE_REF_KEY) { struct btrfs_inode_ref *ref; dirid = sh->offset; ref = (struct btrfs_inode_ref *)(sh + 1); namelen = btrfs_stack_inode_ref_name_len(ref); name = (char *)(ref + 1); name = strndup(name, namelen); /* use our cached value */ if (dirid == *cache_dirid && *cache_name) { dirname = *cache_name; goto build; } } else { return NULL; } /* * the inode backref gives us the file name and the parent directory id. * From here we use __ino_resolve to get the path to the parent */ dirname = __ino_resolve(fd, dirid); build: full = build_name(dirname, name); if (*cache_name && dirname != *cache_name) free(*cache_name); *cache_name = dirname; *cache_dirid = dirid; free(name); return full; } static int __list_subvol_search(int fd, struct root_lookup *root_lookup) { int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; struct btrfs_root_ref *ref; unsigned long off = 0; int name_len; char *name; u64 dir_id; int i; root_lookup_init(root_lookup); memset(&args, 0, sizeof(args)); root_lookup_init(root_lookup); memset(&args, 0, sizeof(args)); /* search in the tree of tree roots */ sk->tree_id = 1; /* * set the min and max to backref keys. The search will * only send back this type of key now. */ sk->max_type = BTRFS_ROOT_BACKREF_KEY; sk->min_type = BTRFS_ROOT_BACKREF_KEY; /* * set all the other params to the max, we'll take any objectid * and any trans */ sk->max_objectid = (u64)-1; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; /* just a big number, doesn't matter much */ sk->nr_items = 4096; while(1) { ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); if (ret < 0) return ret; /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; /* * for each item, pull the key out of the header and then * read the root_ref item it contains */ for (i = 0; i < sk->nr_items; i++) { sh = (struct btrfs_ioctl_search_header *)(args.buf + off); off += sizeof(*sh); if (sh->type == BTRFS_ROOT_BACKREF_KEY) { ref = (struct btrfs_root_ref *)(args.buf + off); name_len = btrfs_stack_root_ref_name_len(ref); name = (char *)(ref + 1); dir_id = btrfs_stack_root_ref_dirid(ref); add_root(root_lookup, sh->objectid, sh->offset, dir_id, name, name_len); } off += sh->len; /* * record the mins in sk so we can make sure the * next search doesn't repeat this root */ sk->min_objectid = sh->objectid; sk->min_type = sh->type; sk->min_offset = sh->offset; } sk->nr_items = 4096; /* this iteration is done, step forward one root for the next * ioctl */ if (sk->min_type < BTRFS_ROOT_BACKREF_KEY) { sk->min_type = BTRFS_ROOT_BACKREF_KEY; sk->min_offset = 0; } else if (sk->min_objectid < (u64)-1) { sk->min_objectid++; sk->min_type = BTRFS_ROOT_BACKREF_KEY; sk->min_offset = 0; } else break; } return 0; } static int __list_subvol_fill_paths(int fd, struct root_lookup *root_lookup) { struct rb_node *n; n = rb_first(&root_lookup->root); while (n) { struct root_info *entry; int ret; entry = rb_entry(n, struct root_info, rb_node); ret = lookup_ino_path(fd, entry); if(ret < 0) return ret; n = rb_next(n); } return 0; } int list_subvols(int fd, int print_parent) { struct root_lookup root_lookup; struct rb_node *n; int ret; ret = __list_subvol_search(fd, &root_lookup); if (ret) { fprintf(stderr, "ERROR: can't perform the search - %s\n", strerror(errno)); return ret; } /* * now we have an rbtree full of root_info objects, but we need to fill * in their path names within the subvol that is referencing each one. */ ret = __list_subvol_fill_paths(fd, &root_lookup); if (ret < 0) return ret; /* now that we have all the subvol-relative paths filled in, * we have to string the subvols together so that we can get * a path all the way back to the FS root */ n = rb_last(&root_lookup.root); while (n) { struct root_info *entry; u64 root_id; u64 level; u64 parent_id; char *path; entry = rb_entry(n, struct root_info, rb_node); resolve_root(&root_lookup, entry, &root_id, &parent_id, &level, &path); if (print_parent) { printf("ID %llu parent %llu top level %llu path %s\n", (unsigned long long)root_id, (unsigned long long)parent_id, (unsigned long long)level, path); } else { printf("ID %llu top level %llu path %s\n", (unsigned long long)root_id, (unsigned long long)level, path); } free(path); n = rb_prev(n); } return ret; } static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh, struct btrfs_file_extent_item *item, u64 found_gen, u64 *cache_dirid, char **cache_dir_name, u64 *cache_ino, char **cache_full_name) { u64 len = 0; u64 disk_start = 0; u64 disk_offset = 0; u8 type; int compressed = 0; int flags = 0; char *name = NULL; if (sh->objectid == *cache_ino) { name = *cache_full_name; } else if (*cache_full_name) { free(*cache_full_name); *cache_full_name = NULL; } if (!name) { name = ino_resolve(fd, sh->objectid, cache_dirid, cache_dir_name); *cache_full_name = name; *cache_ino = sh->objectid; } if (!name) return -EIO; type = btrfs_stack_file_extent_type(item); compressed = btrfs_stack_file_extent_compression(item); if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { disk_start = btrfs_stack_file_extent_disk_bytenr(item); disk_offset = btrfs_stack_file_extent_offset(item); len = btrfs_stack_file_extent_num_bytes(item); } else if (type == BTRFS_FILE_EXTENT_INLINE) { disk_start = 0; disk_offset = 0; len = btrfs_stack_file_extent_ram_bytes(item); } else { printf("unhandled extent type %d for inode %llu " "file offset %llu gen %llu\n", type, (unsigned long long)sh->objectid, (unsigned long long)sh->offset, (unsigned long long)found_gen); return -EIO; } printf("inode %llu file offset %llu len %llu disk start %llu " "offset %llu gen %llu flags ", (unsigned long long)sh->objectid, (unsigned long long)sh->offset, (unsigned long long)len, (unsigned long long)disk_start, (unsigned long long)disk_offset, (unsigned long long)found_gen); if (compressed) { printf("COMPRESS"); flags++; } if (type == BTRFS_FILE_EXTENT_PREALLOC) { printf("%sPREALLOC", flags ? "|" : ""); flags++; } if (type == BTRFS_FILE_EXTENT_INLINE) { printf("%sINLINE", flags ? "|" : ""); flags++; } if (!flags) printf("NONE"); printf(" %s\n", name); return 0; } int find_updated_files(int fd, u64 root_id, u64 oldest_gen) { int ret; struct btrfs_ioctl_search_args args; struct btrfs_ioctl_search_key *sk = &args.key; struct btrfs_ioctl_search_header *sh; struct btrfs_file_extent_item *item; unsigned long off = 0; u64 found_gen; u64 max_found = 0; int i; int e; u64 cache_dirid = 0; u64 cache_ino = 0; char *cache_dir_name = NULL; char *cache_full_name = NULL; struct btrfs_file_extent_item backup; memset(&backup, 0, sizeof(backup)); memset(&args, 0, sizeof(args)); sk->tree_id = root_id; /* * set all the other params to the max, we'll take any objectid * and any trans */ sk->max_objectid = (u64)-1; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; sk->max_type = BTRFS_EXTENT_DATA_KEY; sk->min_transid = oldest_gen; /* just a big number, doesn't matter much */ sk->nr_items = 4096; max_found = find_root_gen(fd); while(1) { ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args); e = errno; if (ret < 0) { fprintf(stderr, "ERROR: can't perform the search- %s\n", strerror(e)); return ret; } /* the ioctl returns the number of item it found in nr_items */ if (sk->nr_items == 0) break; off = 0; /* * for each item, pull the key out of the header and then * read the root_ref item it contains */ for (i = 0; i < sk->nr_items; i++) { sh = (struct btrfs_ioctl_search_header *)(args.buf + off); off += sizeof(*sh); /* * just in case the item was too big, pass something other * than garbage */ if (sh->len == 0) item = &backup; else item = (struct btrfs_file_extent_item *)(args.buf + off); found_gen = btrfs_stack_file_extent_generation(item); if (sh->type == BTRFS_EXTENT_DATA_KEY && found_gen >= oldest_gen) { print_one_extent(fd, sh, item, found_gen, &cache_dirid, &cache_dir_name, &cache_ino, &cache_full_name); } off += sh->len; /* * record the mins in sk so we can make sure the * next search doesn't repeat this root */ sk->min_objectid = sh->objectid; sk->min_offset = sh->offset; sk->min_type = sh->type; } sk->nr_items = 4096; if (sk->min_offset < (u64)-1) sk->min_offset++; else if (sk->min_objectid < (u64)-1) { sk->min_objectid++; sk->min_offset = 0; sk->min_type = 0; } else break; } free(cache_dir_name); free(cache_full_name); printf("transid marker was %llu\n", (unsigned long long)max_found); return ret; } char *path_for_root(int fd, u64 root) { struct root_lookup root_lookup; struct rb_node *n; char *ret_path = NULL; int ret; ret = __list_subvol_search(fd, &root_lookup); if (ret < 0) return ERR_PTR(ret); ret = __list_subvol_fill_paths(fd, &root_lookup); if (ret < 0) return ERR_PTR(ret); n = rb_last(&root_lookup.root); while (n) { struct root_info *entry; u64 root_id; u64 parent_id; u64 level; char *path; entry = rb_entry(n, struct root_info, rb_node); resolve_root(&root_lookup, entry, &root_id, &parent_id, &level, &path); if (root_id == root) ret_path = path; else free(path); n = rb_prev(n); } return ret_path; } btrfs-progs/btrfs-map-logical.c000066400000000000000000000116041166572612100170060ustar00rootroot00000000000000/* * Copyright (C) 2009 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _XOPEN_SOURCE 500 #define _GNU_SOURCE 1 #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "volumes.h" #include "disk-io.h" #include "print-tree.h" #include "transaction.h" #include "list.h" #include "version.h" /* we write the mirror info to stdout unless they are dumping the data * to stdout * */ static FILE *info_file; struct extent_buffer *debug_read_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, int copy) { int ret; struct extent_buffer *eb; u64 length; struct btrfs_multi_bio *multi = NULL; struct btrfs_device *device; int num_copies; int mirror_num = 1; eb = btrfs_find_create_tree_block(root, bytenr, blocksize); if (!eb) return NULL; length = blocksize; while (1) { ret = btrfs_map_block(&root->fs_info->mapping_tree, READ, eb->start, &length, &multi, mirror_num); BUG_ON(ret); device = multi->stripes[0].dev; eb->fd = device->fd; device->total_ios++; eb->dev_bytenr = multi->stripes[0].physical; fprintf(info_file, "mirror %d logical %Lu physical %Lu " "device %s\n", mirror_num, (unsigned long long)bytenr, (unsigned long long)eb->dev_bytenr, device->name); kfree(multi); if (!copy || mirror_num == copy) ret = read_extent_from_disk(eb); num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, eb->start, eb->len); if (num_copies == 1) break; mirror_num++; if (mirror_num > num_copies) break; } return eb; } static void print_usage(void) { fprintf(stderr, "usage: btrfs-map-logical [options] mount_point\n"); fprintf(stderr, "\t-l Logical extent to map\n"); fprintf(stderr, "\t-c Copy of the extent to read (usually 1 or 2)\n"); fprintf(stderr, "\t-o Output file to hold the extent\n"); fprintf(stderr, "\t-b Number of bytes to read\n"); exit(1); } static struct option long_options[] = { /* { "byte-count", 1, NULL, 'b' }, */ { "logical", 1, NULL, 'l' }, { "copy", 1, NULL, 'c' }, { "output", 1, NULL, 'c' }, { "bytes", 1, NULL, 'b' }, { 0, 0, 0, 0} }; int main(int ac, char **av) { struct cache_tree root_cache; struct btrfs_root *root; struct extent_buffer *eb; char *dev; char *output_file = NULL; u64 logical = 0; int ret = 0; int option_index = 0; int copy = 0; u64 bytes = 0; int out_fd = 0; int err; while(1) { int c; c = getopt_long(ac, av, "l:c:o:b:", long_options, &option_index); if (c < 0) break; switch(c) { case 'l': logical = atoll(optarg); if (logical == 0) { fprintf(stderr, "invalid extent number\n"); print_usage(); } break; case 'c': copy = atoi(optarg); if (copy == 0) { fprintf(stderr, "invalid copy number\n"); print_usage(); } break; case 'b': bytes = atoll(optarg); if (bytes == 0) { fprintf(stderr, "invalid byte count\n"); print_usage(); } break; case 'o': output_file = strdup(optarg); break; default: print_usage(); } } ac = ac - optind; if (ac == 0) print_usage(); if (logical == 0) print_usage(); if (copy < 0) print_usage(); dev = av[optind]; radix_tree_init(); cache_tree_init(&root_cache); root = open_ctree(dev, 0, 0); if (!root) { fprintf(stderr, "Open ctree failed\n"); exit(1); } info_file = stdout; if (output_file) { if (strcmp(output_file, "-") == 0) { out_fd = 1; info_file = stderr; } else { out_fd = open(output_file, O_RDWR | O_CREAT, 0600); if (out_fd < 0) goto close; err = ftruncate(out_fd, 0); if (err) { close(out_fd); goto close; } info_file = stdout; } } if (bytes == 0) bytes = root->sectorsize; bytes = (bytes + root->sectorsize - 1) / root->sectorsize; bytes *= root->sectorsize; while (bytes > 0) { eb = debug_read_block(root, logical, root->sectorsize, copy); if (eb && output_file) { err = write(out_fd, eb->data, eb->len); if (err < 0 || err != eb->len) { fprintf(stderr, "output file write failed\n"); goto out_close_fd; } } free_extent_buffer(eb); logical += root->sectorsize; bytes -= root->sectorsize; } out_close_fd: if (output_file && out_fd != 1) close(out_fd); close: close_ctree(root); return ret; } btrfs-progs/btrfs-select-super.c000066400000000000000000000045771166572612100172470ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _XOPEN_SOURCE 500 #define _GNU_SOURCE 1 #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "disk-io.h" #include "print-tree.h" #include "transaction.h" #include "list.h" #include "version.h" #include "utils.h" static void print_usage(void) { fprintf(stderr, "usage: btrfs-select-super -s number dev\n"); fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); exit(1); } int main(int ac, char **av) { struct btrfs_root *root; int ret; int num; u64 bytenr = 0; while(1) { int c; c = getopt(ac, av, "s:"); if (c < 0) break; switch(c) { case 's': num = atol(optarg); bytenr = btrfs_sb_offset(num); printf("using SB copy %d, bytenr %llu\n", num, (unsigned long long)bytenr); break; default: print_usage(); } } ac = ac - optind; if (ac != 1) print_usage(); if (bytenr == 0) { fprintf(stderr, "Please select the super copy with -s\n"); print_usage(); } radix_tree_init(); if((ret = check_mounted(av[optind])) < 0) { fprintf(stderr, "Could not check mount status: %s\n", strerror(-ret)); return ret; } else if(ret) { fprintf(stderr, "%s is currently mounted. Aborting.\n", av[optind]); return -EBUSY; } root = open_ctree(av[optind], bytenr, 1); if (root == NULL) return 1; /* make the super writing code think we've read the first super */ root->fs_info->super_bytenr = BTRFS_SUPER_INFO_OFFSET; ret = write_all_supers(root); /* we don't close the ctree or anything, because we don't want a real * transaction commit. We just want the super copy we pulled off the * disk to overwrite all the other copies */ return ret; } btrfs-progs/btrfs-show.c000066400000000000000000000075261166572612100156110ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _GNU_SOURCE #ifndef __CHECKER__ #include #include #include "ioctl.h" #endif #include #include #include #include #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "transaction.h" #include "utils.h" #include "volumes.h" #include "version.h" static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search) { struct list_head *cur; struct btrfs_device *device; list_for_each(cur, &fs_devices->devices) { device = list_entry(cur, struct btrfs_device, dev_list); if ((device->label && strcmp(device->label, search) == 0) || strcmp(device->name, search) == 0) return 1; } return 0; } static void print_one_uuid(struct btrfs_fs_devices *fs_devices) { char uuidbuf[37]; struct list_head *cur; struct btrfs_device *device; char *super_bytes_used; u64 devs_found = 0; u64 total; uuid_unparse(fs_devices->fsid, uuidbuf); device = list_entry(fs_devices->devices.next, struct btrfs_device, dev_list); if (device->label && device->label[0]) printf("Label: %s ", device->label); else printf("Label: none "); super_bytes_used = pretty_sizes(device->super_bytes_used); total = device->total_devs; printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf, (unsigned long long)total, super_bytes_used); free(super_bytes_used); list_for_each(cur, &fs_devices->devices) { char *total_bytes; char *bytes_used; device = list_entry(cur, struct btrfs_device, dev_list); total_bytes = pretty_sizes(device->total_bytes); bytes_used = pretty_sizes(device->bytes_used); printf("\tdevid %4llu size %s used %s path %s\n", (unsigned long long)device->devid, total_bytes, bytes_used, device->name); free(total_bytes); free(bytes_used); devs_found++; } if (devs_found < total) { printf("\t*** Some devices missing\n"); } printf("\n"); } static void print_usage(void) { fprintf(stderr, "usage: btrfs-show [search label or device]\n"); fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); exit(1); } static struct option long_options[] = { /* { "byte-count", 1, NULL, 'b' }, */ { 0, 0, 0, 0} }; int main(int ac, char **av) { struct list_head *all_uuids; struct btrfs_fs_devices *fs_devices; struct list_head *cur_uuid; char *search = NULL; int ret; int option_index = 0; printf( "**\n" "** WARNING: this program is considered deprecated\n" "** Please consider to switch to the btrfs utility\n" "**\n"); while(1) { int c; c = getopt_long(ac, av, "", long_options, &option_index); if (c < 0) break; switch(c) { default: print_usage(); } } ac = ac - optind; if (ac != 0) { search = av[optind]; } ret = btrfs_scan_one_dir("/dev", 0); if (ret) fprintf(stderr, "error %d while scanning\n", ret); all_uuids = btrfs_scanned_uuids(); list_for_each(cur_uuid, all_uuids) { fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices, list); if (search && uuid_search(fs_devices, search) == 0) continue; print_one_uuid(fs_devices); } printf("%s\n", BTRFS_BUILD_VERSION); return 0; } btrfs-progs/btrfs-vol.c000066400000000000000000000076271166572612100154330ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _GNU_SOURCE #ifndef __CHECKER__ #include #include #include "ioctl.h" #endif #include #include #include #include #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "transaction.h" #include "utils.h" #include "volumes.h" #ifdef __CHECKER__ #define BLKGETSIZE64 0 #define BTRFS_IOC_SNAP_CREATE 0 #define BTRFS_IOC_ADD_DEV 0 #define BTRFS_IOC_RM_DEV 0 #define BTRFS_VOL_NAME_MAX 255 struct btrfs_ioctl_vol_args { char name[BTRFS_VOL_NAME_MAX]; }; static inline int ioctl(int fd, int define, void *arg) { return 0; } #endif static void print_usage(void) { fprintf(stderr, "usage: btrfs-vol [options] mount_point\n"); fprintf(stderr, "\t-a device add one device\n"); fprintf(stderr, "\t-b balance chunks across all devices\n"); fprintf(stderr, "\t-r device remove one device\n"); exit(1); } static struct option long_options[] = { /* { "byte-count", 1, NULL, 'b' }, */ { "add", 1, NULL, 'a' }, { "balance", 0, NULL, 'b' }, { "remove", 1, NULL, 'r' }, { 0, 0, 0, 0} }; int main(int ac, char **av) { struct stat st; char *device = NULL; char *mnt = NULL; int ret; int option_index = 0; int cmd = 0; int fd; int devfd = 0; DIR *dirstream; struct btrfs_ioctl_vol_args args; u64 dev_block_count = 0; printf( "**\n" "** WARNING: this program is considered deprecated\n" "** Please consider to switch to the btrfs utility\n" "**\n"); while(1) { int c; c = getopt_long(ac, av, "a:br:", long_options, &option_index); if (c < 0) break; switch(c) { case 'a': device = strdup(optarg); cmd = BTRFS_IOC_ADD_DEV; break; case 'b': cmd = BTRFS_IOC_BALANCE; break; case 'r': device = strdup(optarg); cmd = BTRFS_IOC_RM_DEV; break; default: print_usage(); } } ac = ac - optind; if (ac == 0) print_usage(); mnt = av[optind]; if (device && strcmp(device, "missing") == 0 && cmd == BTRFS_IOC_RM_DEV) { fprintf(stderr, "removing missing devices from %s\n", mnt); } else if (cmd != BTRFS_IOC_BALANCE) { if (cmd == BTRFS_IOC_ADD_DEV) { ret = check_mounted(device); if (ret < 0) { fprintf(stderr, "error checking %s mount status\n", device); exit(1); } if (ret == 1) { fprintf(stderr, "%s is mounted\n", device); exit(1); } } devfd = open(device, O_RDWR); if (devfd < 0) { fprintf(stderr, "Unable to open device %s\n", device); exit(1); } ret = fstat(devfd, &st); if (ret) { fprintf(stderr, "Unable to stat %s\n", device); exit(1); } if (!S_ISBLK(st.st_mode)) { fprintf(stderr, "%s is not a block device\n", device); exit(1); } } dirstream = opendir(mnt); if (!dirstream) { fprintf(stderr, "Unable to open directory %s\n", mnt); exit(1); } if (cmd == BTRFS_IOC_ADD_DEV) { int mixed = 0; ret = btrfs_prepare_device(devfd, device, 1, &dev_block_count, &mixed); if (ret) { fprintf(stderr, "Unable to init %s\n", device); exit(1); } } fd = dirfd(dirstream); if (device) strcpy(args.name, device); else args.name[0] = '\0'; ret = ioctl(fd, cmd, &args); printf("ioctl returns %d\n", ret); return 0; } btrfs-progs/btrfs-zero-log.c000066400000000000000000000035071166572612100163620ustar00rootroot00000000000000/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _XOPEN_SOURCE 500 #define _GNU_SOURCE 1 #include #include #include #include #include #include "kerncompat.h" #include "ctree.h" #include "disk-io.h" #include "print-tree.h" #include "transaction.h" #include "list.h" #include "version.h" #include "utils.h" static void print_usage(void) { fprintf(stderr, "usage: btrfs-zero-log dev\n"); fprintf(stderr, "%s\n", BTRFS_BUILD_VERSION); exit(1); } int main(int ac, char **av) { struct btrfs_root *root; struct btrfs_trans_handle *trans; int ret; if (ac != 2) print_usage(); radix_tree_init(); if((ret = check_mounted(av[1])) < 0) { fprintf(stderr, "Could not check mount status: %s\n", strerror(-ret)); return ret; } else if(ret) { fprintf(stderr, "%s is currently mounted. Aborting.\n", av[1]); return -EBUSY; } root = open_ctree(av[1], 0, 1); if (root == NULL) return 1; trans = btrfs_start_transaction(root, 1); btrfs_set_super_log_root(&root->fs_info->super_copy, 0); btrfs_set_super_log_root_level(&root->fs_info->super_copy, 0); btrfs_commit_transaction(trans, root); close_ctree(root); return ret; } btrfs-progs/btrfs.c000066400000000000000000000266021166572612100146270ustar00rootroot00000000000000/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program 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 021110-1307, USA. */ #define _GNU_SOURCE #include #include #include #include "kerncompat.h" #include "btrfs_cmds.h" #include "version.h" #define BASIC_HELP 0 #define ADVANCED_HELP 1 typedef int (*CommandFunction)(int argc, char **argv); struct Command { CommandFunction func; /* function which implements the command */ int nargs; /* if == 999, any number of arguments if >= 0, number of arguments, if < 0, _minimum_ number of arguments */ char *verb; /* verb */ char *help; /* help lines; from the 2nd line onward they are automatically indented */ char *adv_help; /* advanced help message; from the 2nd line onward they are automatically indented */ /* the following fields are run-time filled by the program */ char **cmds; /* array of subcommands */ int ncmds; /* number of subcommand */ }; static struct Command commands[] = { /* avoid short commands different for the case only */ { do_clone, -2, "subvolume snapshot", "[-r] [/]\n" "Create a writable/readonly snapshot of the subvolume with\n" "the name in the directory.", NULL }, { do_delete_subvolume, 1, "subvolume delete", "\n" "Delete the subvolume .", NULL }, { do_create_subvol, 1, "subvolume create", "[/]\n" "Create a subvolume in (or the current directory if\n" "not passed).", NULL }, { do_subvol_list, -1, "subvolume list", "[-p] \n" "List the snapshot/subvolume of a filesystem.", "[-p] \n" "List the snapshot/subvolume of a filesystem.\n" "-p print parent ID" }, { do_set_default_subvol, 2, "subvolume set-default", " \n" "Set the subvolume of the filesystem which will be mounted\n" "as default.", NULL }, { do_find_newer, 2, "subvolume find-new", " \n" "List the recently modified files in a filesystem.", NULL }, { do_defrag, -1, "filesystem defragment", "[-vf] [-c[zlib,lzo]] [-s start] [-l len] [-t size] | [|...]\n" "Defragment a file or a directory.", "[-vcf] [-s start] [-l len] [-t size] | [|...]\n" "Defragment file data or directory metadata.\n" "-v be verbose\n" "-c compress the file while defragmenting\n" "-f flush data to disk immediately after defragmenting\n" "-s start defragment only from byte onward\n" "-l len defragment only up to len bytes\n" "-t size minimal size of file to be considered for defragmenting\n" }, { do_get_default_subvol, 1, "subvolume get-default", "\n" "Get the default subvolume of a filesystem." }, { do_fssync, 1, "filesystem sync", "\n" "Force a sync on the filesystem .", NULL }, { do_resize, 2, "filesystem resize", "[+/-][gkm]|max \n" "Resize the file system. If 'max' is passed, the filesystem\n" "will occupe all available space on the device.", NULL }, { do_show_filesystem, 999, "filesystem show", "[--all-devices][|