├── .gitignore ├── 69-bcache.rules ├── COPYING ├── Makefile ├── README ├── bcache-register.c ├── bcache-super-show.8 ├── bcache-super-show.c ├── bcache-test.c ├── bcache.c ├── bcache.h ├── dracut └── module-setup.sh ├── initcpio └── install ├── initramfs └── hook ├── make-bcache.8 ├── make-bcache.c ├── probe-bcache.8 └── probe-bcache.c /.gitignore: -------------------------------------------------------------------------------- 1 | /bcache-super-show 2 | /bcache-test 3 | /bcache-register 4 | /make-bcache 5 | /probe-bcache 6 | .* 7 | /*.o 8 | -------------------------------------------------------------------------------- /69-bcache.rules: -------------------------------------------------------------------------------- 1 | # register bcache devices as they come up 2 | # man 7 udev for syntax 3 | 4 | SUBSYSTEM!="block", GOTO="bcache_end" 5 | ACTION=="remove", GOTO="bcache_end" 6 | ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", GOTO="bcache_end" 7 | KERNEL=="fd*|sr*", GOTO="bcache_end" 8 | 9 | # blkid was run by the standard udev rules 10 | # It recognised bcache (util-linux 2.24+) 11 | ENV{ID_FS_TYPE}=="bcache", GOTO="bcache_backing_found" 12 | # It recognised something else; bail 13 | ENV{ID_FS_TYPE}=="?*", GOTO="bcache_backing_end" 14 | 15 | # Backing devices: scan, symlink, register 16 | IMPORT{program}="probe-bcache -o udev $tempnode" 17 | ENV{ID_FS_TYPE}!="bcache", GOTO="bcache_backing_end" 18 | ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}" 19 | 20 | LABEL="bcache_backing_found" 21 | RUN{builtin}+="kmod load bcache" 22 | RUN+="bcache-register $tempnode" 23 | LABEL="bcache_backing_end" 24 | 25 | # Cached devices: symlink 26 | DRIVER=="bcache", ENV{CACHED_UUID}=="?*", \ 27 | SYMLINK+="bcache/by-uuid/$env{CACHED_UUID}" 28 | DRIVER=="bcache", ENV{CACHED_LABEL}=="?*", \ 29 | SYMLINK+="bcache/by-label/$env{CACHED_LABEL}" 30 | 31 | LABEL="bcache_end" 32 | 33 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | PREFIX=/usr 3 | UDEVLIBDIR=/lib/udev 4 | DRACUTLIBDIR=/lib/dracut 5 | INSTALL=install 6 | CFLAGS+=-O2 -Wall -g 7 | 8 | all: make-bcache probe-bcache bcache-super-show bcache-register 9 | 10 | install: make-bcache probe-bcache bcache-super-show 11 | $(INSTALL) -m0755 make-bcache bcache-super-show $(DESTDIR)${PREFIX}/sbin/ 12 | $(INSTALL) -m0755 probe-bcache bcache-register $(DESTDIR)$(UDEVLIBDIR)/ 13 | $(INSTALL) -m0644 69-bcache.rules $(DESTDIR)$(UDEVLIBDIR)/rules.d/ 14 | $(INSTALL) -m0644 -- *.8 $(DESTDIR)${PREFIX}/share/man/man8/ 15 | $(INSTALL) -D -m0755 initramfs/hook $(DESTDIR)/usr/share/initramfs-tools/hooks/bcache 16 | $(INSTALL) -D -m0755 initcpio/install $(DESTDIR)/usr/lib/initcpio/install/bcache 17 | $(INSTALL) -D -m0755 dracut/module-setup.sh $(DESTDIR)$(DRACUTLIBDIR)/modules.d/90bcache/module-setup.sh 18 | # $(INSTALL) -m0755 bcache-test $(DESTDIR)${PREFIX}/sbin/ 19 | 20 | clean: 21 | $(RM) -f make-bcache probe-bcache bcache-super-show bcache-test -- *.o 22 | 23 | bcache-test: LDLIBS += `pkg-config --libs openssl` -lm 24 | make-bcache: LDLIBS += `pkg-config --libs uuid blkid` 25 | make-bcache: CFLAGS += `pkg-config --cflags uuid blkid` 26 | make-bcache: bcache.o 27 | probe-bcache: LDLIBS += `pkg-config --libs uuid blkid` 28 | probe-bcache: CFLAGS += `pkg-config --cflags uuid blkid` 29 | bcache-super-show: LDLIBS += `pkg-config --libs uuid` 30 | bcache-super-show: CFLAGS += -std=gnu99 31 | bcache-super-show: bcache.o 32 | bcache-register: bcache-register.o 33 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | These are the userspace tools required for bcache. 2 | 3 | Bcache is a patch for the Linux kernel to use SSDs to cache other block 4 | devices. For more information, see http://bcache.evilpiepirate.org. 5 | Documentation for the run time interface is included in the kernel tree, in 6 | Documentation/bcache.txt. 7 | 8 | Included: 9 | 10 | make-bcache 11 | Formats a block device for use with bcache. A device can be formatted for use 12 | as a cache or as a backing device (requires yet to be implemented kernel 13 | support). The most important option is for specifying the bucket size. 14 | Allocation is done in terms of buckets, and cache hits are counted per bucket; 15 | thus a smaller bucket size will give better cache utilization, but poorer write 16 | performance. The bucket size is intended to be equal to the size of your SSD's 17 | erase blocks, which seems to be 128k-512k for most SSDs; feel free to 18 | experiment. 19 | 20 | bcache-super-show 21 | Prints the bcache superblock of a cache device or a backing device. 22 | 23 | 24 | Udev rules 25 | The first half of the rules do auto-assembly and add uuid symlinks 26 | to cache and backing devices. If util-linux's libblkid is 27 | sufficiently recent (2.24) the rules will take advantage of 28 | the fact that bcache has already been detected. Otherwise 29 | they call a small probe-bcache program that imitates blkid. 30 | 31 | The second half of the rules add symlinks to cached devices, 32 | which are the devices created by the bcache kernel module. 33 | 34 | 35 | Initramfs support 36 | Currently initramfs-tools, mkinitcpio and dracut are supported. 37 | 38 | 39 | -------------------------------------------------------------------------------- /bcache-register.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Simon Gomizelj 3 | * 4 | * GPLv2 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | int fd; 14 | 15 | if (argc != 2) 16 | { 17 | fprintf(stderr, "bcache-register takes exactly one argument\n"); 18 | return 1; 19 | } 20 | 21 | fd = open("/sys/fs/bcache/register", O_WRONLY); 22 | if (fd < 0) 23 | { 24 | perror("Error opening /sys/fs/bcache/register"); 25 | fprintf(stderr, "The bcache kernel module must be loaded\n"); 26 | return 1; 27 | } 28 | 29 | if (dprintf(fd, "%s\n", argv[1]) < 0) 30 | { 31 | fprintf(stderr, "Error registering %s with bcache: %m\n", argv[1]); 32 | return 1; 33 | } 34 | 35 | return 0; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /bcache-super-show.8: -------------------------------------------------------------------------------- 1 | .TH bcache-super-show 8 2 | .SH NAME 3 | bcache-super-show \- Print the bcache superblock 4 | .SH SYNOPSIS 5 | .B bcache-super-show 6 | [\fB \-f] 7 | .I device 8 | .SH OPTIONS 9 | .TP 10 | .BR \-f 11 | Keep going if the superblock crc is invalid 12 | -------------------------------------------------------------------------------- /bcache-super-show.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Gabriel de Perthuis 3 | * 4 | * GPLv2 5 | */ 6 | 7 | 8 | #define _FILE_OFFSET_BITS 64 9 | #define __USE_FILE_OFFSET64 10 | #define _XOPEN_SOURCE 500 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "bcache.h" 28 | 29 | 30 | static void usage() 31 | { 32 | fprintf(stderr, "Usage: bcache-super-show [-f] \n"); 33 | } 34 | 35 | 36 | static bool accepted_char(char c) 37 | { 38 | if ('0' <= c && c <= '9') 39 | return true; 40 | if ('A' <= c && c <= 'Z') 41 | return true; 42 | if ('a' <= c && c <= 'z') 43 | return true; 44 | if (strchr(".-_", c)) 45 | return true; 46 | return false; 47 | } 48 | 49 | static void print_encode(char* in) 50 | { 51 | for (char* pos = in; *pos; pos++) 52 | if (accepted_char(*pos)) 53 | putchar(*pos); 54 | else 55 | printf("%%%x", *pos); 56 | } 57 | 58 | 59 | int main(int argc, char **argv) 60 | { 61 | bool force_csum = false; 62 | int o; 63 | extern char *optarg; 64 | struct cache_sb sb; 65 | char uuid[40]; 66 | uint64_t expected_csum; 67 | 68 | while ((o = getopt(argc, argv, "f")) != EOF) 69 | switch (o) { 70 | case 'f': 71 | force_csum = 1; 72 | break; 73 | 74 | default: 75 | usage(); 76 | exit(1); 77 | } 78 | 79 | argv += optind; 80 | argc -= optind; 81 | 82 | if (argc != 1) { 83 | usage(); 84 | exit(1); 85 | } 86 | 87 | int fd = open(argv[0], O_RDONLY); 88 | if (fd < 0) { 89 | printf("Can't open dev %s: %s\n", argv[0], strerror(errno)); 90 | exit(2); 91 | } 92 | 93 | if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) { 94 | fprintf(stderr, "Couldn't read\n"); 95 | exit(2); 96 | } 97 | 98 | printf("sb.magic\t\t"); 99 | if (!memcmp(sb.magic, bcache_magic, 16)) { 100 | printf("ok\n"); 101 | } else { 102 | printf("bad magic\n"); 103 | fprintf(stderr, "Invalid superblock (bad magic)\n"); 104 | exit(2); 105 | } 106 | 107 | printf("sb.first_sector\t\t%" PRIu64, sb.offset); 108 | if (sb.offset == SB_SECTOR) { 109 | printf(" [match]\n"); 110 | } else { 111 | printf(" [expected %ds]\n", SB_SECTOR); 112 | fprintf(stderr, "Invalid superblock (bad sector)\n"); 113 | exit(2); 114 | } 115 | 116 | printf("sb.csum\t\t\t%" PRIX64, sb.csum); 117 | expected_csum = csum_set(&sb); 118 | if (sb.csum == expected_csum) { 119 | printf(" [match]\n"); 120 | } else { 121 | printf(" [expected %" PRIX64 "]\n", expected_csum); 122 | if (!force_csum) { 123 | fprintf(stderr, "Corrupt superblock (bad csum)\n"); 124 | exit(2); 125 | } 126 | } 127 | 128 | printf("sb.version\t\t%" PRIu64, sb.version); 129 | switch (sb.version) { 130 | // These are handled the same by the kernel 131 | case BCACHE_SB_VERSION_CDEV: 132 | case BCACHE_SB_VERSION_CDEV_WITH_UUID: 133 | printf(" [cache device]\n"); 134 | break; 135 | 136 | // The second adds data offset support 137 | case BCACHE_SB_VERSION_BDEV: 138 | case BCACHE_SB_VERSION_BDEV_WITH_OFFSET: 139 | printf(" [backing device]\n"); 140 | break; 141 | 142 | default: 143 | printf(" [unknown]\n"); 144 | // exit code? 145 | return 0; 146 | } 147 | 148 | putchar('\n'); 149 | 150 | char label[SB_LABEL_SIZE + 1]; 151 | strncpy(label, (char*)sb.label, SB_LABEL_SIZE); 152 | label[SB_LABEL_SIZE] = '\0'; 153 | printf("dev.label\t\t"); 154 | if (*label) 155 | print_encode(label); 156 | else 157 | printf("(empty)"); 158 | putchar('\n'); 159 | 160 | uuid_unparse(sb.uuid, uuid); 161 | printf("dev.uuid\t\t%s\n", uuid); 162 | 163 | printf("dev.sectors_per_block\t%u\n" 164 | "dev.sectors_per_bucket\t%u\n", 165 | sb.block_size, 166 | sb.bucket_size); 167 | 168 | if (!SB_IS_BDEV(&sb)) { 169 | // total_sectors includes the superblock; 170 | printf("dev.cache.first_sector\t%u\n" 171 | "dev.cache.cache_sectors\t%ju\n" 172 | "dev.cache.total_sectors\t%ju\n" 173 | "dev.cache.ordered\t%s\n" 174 | "dev.cache.discard\t%s\n" 175 | "dev.cache.pos\t\t%u\n" 176 | "dev.cache.replacement\t%ju", 177 | sb.bucket_size * sb.first_bucket, 178 | sb.bucket_size * (sb.nbuckets - sb.first_bucket), 179 | sb.bucket_size * sb.nbuckets, 180 | CACHE_SYNC(&sb) ? "yes" : "no", 181 | CACHE_DISCARD(&sb) ? "yes" : "no", 182 | sb.nr_this_dev, 183 | CACHE_REPLACEMENT(&sb)); 184 | switch (CACHE_REPLACEMENT(&sb)) { 185 | case CACHE_REPLACEMENT_LRU: 186 | printf(" [lru]\n"); 187 | break; 188 | case CACHE_REPLACEMENT_FIFO: 189 | printf(" [fifo]\n"); 190 | break; 191 | case CACHE_REPLACEMENT_RANDOM: 192 | printf(" [random]\n"); 193 | break; 194 | default: 195 | putchar('\n'); 196 | } 197 | 198 | } else { 199 | uint64_t first_sector; 200 | if (sb.version == BCACHE_SB_VERSION_BDEV) { 201 | first_sector = BDEV_DATA_START_DEFAULT; 202 | } else { 203 | if (sb.keys == 1 || sb.d[0]) { 204 | fprintf(stderr, 205 | "Possible experimental format detected, bailing\n"); 206 | exit(3); 207 | } 208 | first_sector = sb.data_offset; 209 | } 210 | 211 | printf("dev.data.first_sector\t%ju\n" 212 | "dev.data.cache_mode\t%ju", 213 | first_sector, 214 | BDEV_CACHE_MODE(&sb)); 215 | switch (BDEV_CACHE_MODE(&sb)) { 216 | case CACHE_MODE_WRITETHROUGH: 217 | printf(" [writethrough]\n"); 218 | break; 219 | case CACHE_MODE_WRITEBACK: 220 | printf(" [writeback]\n"); 221 | break; 222 | case CACHE_MODE_WRITEAROUND: 223 | printf(" [writearound]\n"); 224 | break; 225 | case CACHE_MODE_NONE: 226 | printf(" [no caching]\n"); 227 | break; 228 | default: 229 | putchar('\n'); 230 | } 231 | 232 | printf("dev.data.cache_state\t%ju", 233 | BDEV_STATE(&sb)); 234 | switch (BDEV_STATE(&sb)) { 235 | case BDEV_STATE_NONE: 236 | printf(" [detached]\n"); 237 | break; 238 | case BDEV_STATE_CLEAN: 239 | printf(" [clean]\n"); 240 | break; 241 | case BDEV_STATE_DIRTY: 242 | printf(" [dirty]\n"); 243 | break; 244 | case BDEV_STATE_STALE: 245 | printf(" [inconsistent]\n"); 246 | break; 247 | default: 248 | putchar('\n'); 249 | } 250 | } 251 | putchar('\n'); 252 | 253 | uuid_unparse(sb.set_uuid, uuid); 254 | printf("cset.uuid\t\t%s\n", uuid); 255 | 256 | return 0; 257 | } 258 | -------------------------------------------------------------------------------- /bcache-test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Kent Overstreet 3 | * 4 | * GPLv2 5 | */ 6 | 7 | #define _FILE_OFFSET_BITS 64 8 | #define _XOPEN_SOURCE 500 9 | #define _GNU_SOURCE 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | static const unsigned char bcache_magic[] = { 32 | 0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca, 33 | 0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81 }; 34 | 35 | unsigned char zero[4096]; 36 | 37 | bool klog = false; 38 | 39 | #define Pread(fd, buf, size, offset) do { \ 40 | int _read = 0, _r; \ 41 | while (_read < size) { \ 42 | _r = pread(fd, buf, (size) - _read, (offset) + _read); \ 43 | if (_r <= 0) \ 44 | goto err; \ 45 | _read += _r; \ 46 | } \ 47 | } while (0) 48 | 49 | #define Pwrite(fd, buf, size, offset) do { \ 50 | int _write = 0, _r; \ 51 | while (_write < size) { \ 52 | _r = pwrite(fd, buf, (size) - _write, offset + _write); \ 53 | if (_r < 0) \ 54 | goto err; \ 55 | _write += _r; \ 56 | } \ 57 | } while (0) 58 | 59 | /* Marsaglia polar method 60 | */ 61 | double normal() 62 | { 63 | double x, y, s; 64 | static double n = 0 / (double) 0; 65 | 66 | if (n == n) { 67 | x = n; 68 | n = 0 / (double) 0; 69 | return x; 70 | } 71 | 72 | do { 73 | x = random() / (double) (RAND_MAX / 2) - 1; 74 | y = random() / (double) (RAND_MAX / 2) - 1; 75 | 76 | s = x * x + y * y; 77 | } while (s >= 1); 78 | 79 | s = sqrt(-2 * log(s) / s); 80 | n = y * s; 81 | return x * s; 82 | } 83 | 84 | long getblocks(int fd) 85 | { 86 | long ret; 87 | struct stat statbuf; 88 | if (fstat(fd, &statbuf)) { 89 | perror("stat error"); 90 | exit(EXIT_FAILURE); 91 | } 92 | ret = statbuf.st_size / 512; 93 | if (S_ISBLK(statbuf.st_mode)) 94 | if (ioctl(fd, BLKGETSIZE, &ret)) { 95 | perror("ioctl error"); 96 | exit(EXIT_FAILURE); 97 | } 98 | return ret; 99 | } 100 | 101 | struct pagestuff { 102 | unsigned char csum[16]; 103 | unsigned char oldcsum[16]; 104 | int readcount; 105 | int writecount; 106 | }; 107 | 108 | void flushlog(void) 109 | { 110 | char logbuf[1 << 21]; 111 | int w = 0, len; 112 | static int fd; 113 | 114 | if (!klog) 115 | return; 116 | 117 | if (!fd) { 118 | klogctl(8, 0, 6); 119 | 120 | sprintf(logbuf, "log.%i", abs(random()) % 1000); 121 | fd = open(logbuf, O_WRONLY|O_CREAT|O_TRUNC, 0644); 122 | 123 | if (fd == -1) { 124 | perror("Error opening log file"); 125 | exit(EXIT_FAILURE); 126 | } 127 | } 128 | 129 | len = klogctl(4, logbuf, 1 << 21); 130 | 131 | if (len == -1) { 132 | perror("Error reading kernel log"); 133 | exit(EXIT_FAILURE); 134 | } 135 | 136 | while (w < len) { 137 | int r = write(fd, logbuf + w, len - w); 138 | if (r == -1) { 139 | perror("Error writing log"); 140 | exit(EXIT_FAILURE); 141 | } 142 | w += r; 143 | } 144 | } 145 | 146 | void aio_loop(int nr) 147 | { 148 | 149 | } 150 | 151 | void usage() 152 | { 153 | exit(EXIT_FAILURE); 154 | } 155 | 156 | int main(int argc, char **argv) 157 | { 158 | bool walk = false, randsize = false, verbose = false, csum = false, rtest = false, wtest = false; 159 | int fd1, fd2 = 0, direct = 0, nbytes = 4096, j, o; 160 | unsigned long size, i, offset = 0, done = 0, unique = 0, benchmark = 0; 161 | void *buf1 = NULL, *buf2 = NULL; 162 | struct pagestuff *pages, *p; 163 | unsigned char c[16]; 164 | time_t last_printed = 0; 165 | extern char *optarg; 166 | 167 | RC4_KEY writedata; 168 | RC4_set_key(&writedata, 16, bcache_magic); 169 | 170 | while ((o = getopt(argc, argv, "dnwvscwlb:")) != EOF) 171 | switch (o) { 172 | case 'd': 173 | direct = O_DIRECT; 174 | break; 175 | case 'n': 176 | walk = true; 177 | break; 178 | case 'v': 179 | verbose = true; 180 | break; 181 | case 's': 182 | randsize = true; 183 | break; 184 | case 'c': 185 | csum = true; 186 | break; 187 | case 'w': 188 | wtest = true; 189 | break; 190 | case 'r': 191 | rtest = true; 192 | break; 193 | case 'l': 194 | klog = true; 195 | break; 196 | case 'b': 197 | benchmark = atol(optarg); 198 | break; 199 | default: 200 | usage(); 201 | } 202 | 203 | argv += optind; 204 | argc -= optind; 205 | 206 | if (!rtest && !wtest) 207 | rtest = true; 208 | 209 | if (argc < 1) { 210 | printf("Please enter a device to test\n"); 211 | exit(EXIT_FAILURE); 212 | } 213 | 214 | if (!csum && !benchmark && argc < 2) { 215 | printf("Please enter a device to compare against\n"); 216 | exit(EXIT_FAILURE); 217 | } 218 | 219 | fd1 = open(argv[0], (wtest ? O_RDWR : O_RDONLY)|direct); 220 | if (!csum && !benchmark) 221 | fd2 = open(argv[1], (wtest ? O_RDWR : O_RDONLY)|direct); 222 | 223 | if (fd1 == -1 || fd2 == -1) { 224 | perror("Error opening device"); 225 | exit(EXIT_FAILURE); 226 | } 227 | 228 | size = getblocks(fd1); 229 | if (!csum && !benchmark) 230 | size = MIN(size, getblocks(fd2)); 231 | 232 | size = size / 8 - 16; 233 | pages = calloc(size + 16, sizeof(*pages)); 234 | printf("size %li\n", size); 235 | 236 | if (posix_memalign(&buf1, 4096, 4096 * 16) || 237 | posix_memalign(&buf2, 4096, 4096 * 16)) { 238 | printf("Could not allocate buffers\n"); 239 | exit(EXIT_FAILURE); 240 | } 241 | //setvbuf(stdout, NULL, _IONBF, 0); 242 | 243 | for (i = 0; !benchmark || i < benchmark; i++) { 244 | bool writing = (wtest && (i & 1)) || !rtest; 245 | nbytes = randsize ? drand48() * 16 + 1 : 1; 246 | nbytes <<= 12; 247 | 248 | offset >>= 12; 249 | offset += walk ? normal() * 20 : random(); 250 | offset %= size; 251 | offset <<= 12; 252 | 253 | if (!(i % 200)) 254 | flushlog(); 255 | 256 | if (!verbose) { 257 | time_t now = time(NULL); 258 | if (now - last_printed >= 2) { 259 | last_printed = now; 260 | goto print; 261 | } 262 | } else 263 | print: printf("Loop %6li offset %9li sectors %3i, %6lu mb done, %6lu mb unique\n", 264 | i, offset >> 9, nbytes >> 9, done >> 11, unique >> 11); 265 | 266 | done += nbytes >> 9; 267 | 268 | if (!writing) 269 | Pread(fd1, buf1, nbytes, offset); 270 | if (!writing && !csum && !benchmark) 271 | Pread(fd2, buf2, nbytes, offset); 272 | 273 | for (j = 0; j < nbytes; j += 4096) { 274 | p = &pages[(offset + j) / 4096]; 275 | 276 | if (writing) 277 | RC4(&writedata, 4096, zero, buf1 + j); 278 | 279 | if (csum) { 280 | MD4(buf1 + j, 4096, &c[0]); 281 | 282 | if (writing || 283 | (!p->readcount && !p->writecount)) { 284 | memcpy(&p->oldcsum[0], &p->csum[0], 16); 285 | memcpy(&p->csum[0], c, 16); 286 | } else if (memcmp(&p->csum[0], c, 16)) 287 | goto bad; 288 | } else if (!writing && !benchmark && 289 | memcmp(buf1 + j, 290 | buf2 + j, 291 | 4096)) 292 | goto bad; 293 | 294 | if (!p->writecount && !p->readcount) 295 | unique += 8; 296 | 297 | writing ? p->writecount++ : p->readcount++; 298 | } 299 | if (writing) 300 | Pwrite(fd1, buf1, nbytes, offset); 301 | if (writing && !csum && !benchmark) 302 | Pwrite(fd2, buf2, nbytes, offset); 303 | } 304 | printf("Loop %6li offset %9li sectors %3i, %6lu mb done, %6lu mb unique\n", 305 | i, offset >> 9, nbytes >> 9, done >> 11, unique >> 11); 306 | exit(EXIT_SUCCESS); 307 | err: 308 | perror("IO error"); 309 | flushlog(); 310 | exit(EXIT_FAILURE); 311 | bad: 312 | printf("Bad read! loop %li offset %li readcount %i writecount %i\n", 313 | i, (offset + j) >> 9, p->readcount, p->writecount); 314 | 315 | if (!memcmp(&p->oldcsum[0], c, 16)) 316 | printf("Matches previous csum\n"); 317 | 318 | flushlog(); 319 | exit(EXIT_FAILURE); 320 | } 321 | -------------------------------------------------------------------------------- /bcache.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group (Any 10 | * use permitted, subject to terms of PostgreSQL license; see.) 11 | 12 | * If we have a 64-bit integer type, then a 64-bit CRC looks just like the 13 | * usual sort of implementation. (See Ross Williams' excellent introduction 14 | * A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS, available from 15 | * ftp://ftp.rocksoft.com/papers/crc_v3.txt or several other net sites.) 16 | * If we have no working 64-bit type, then fake it with two 32-bit registers. 17 | * 18 | * The present implementation is a normal (not "reflected", in Williams' 19 | * terms) 64-bit CRC, using initial all-ones register contents and a final 20 | * bit inversion. The chosen polynomial is borrowed from the DLT1 spec 21 | * (ECMA-182, available from http://www.ecma.ch/ecma1/STAND/ECMA-182.HTM): 22 | * 23 | * x^64 + x^62 + x^57 + x^55 + x^54 + x^53 + x^52 + x^47 + x^46 + x^45 + 24 | * x^40 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 + 25 | * x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 + 26 | * x^7 + x^4 + x + 1 27 | */ 28 | 29 | static const uint64_t crc_table[256] = { 30 | 0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL, 31 | 0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL, 32 | 0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL, 33 | 0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL, 34 | 0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL, 35 | 0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL, 36 | 0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL, 37 | 0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL, 38 | 0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL, 39 | 0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL, 40 | 0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL, 41 | 0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL, 42 | 0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL, 43 | 0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL, 44 | 0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL, 45 | 0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL, 46 | 0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL, 47 | 0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL, 48 | 0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL, 49 | 0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL, 50 | 0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL, 51 | 0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL, 52 | 0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL, 53 | 0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL, 54 | 0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL, 55 | 0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL, 56 | 0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL, 57 | 0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL, 58 | 0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL, 59 | 0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL, 60 | 0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL, 61 | 0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL, 62 | 0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL, 63 | 0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL, 64 | 0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL, 65 | 0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL, 66 | 0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL, 67 | 0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL, 68 | 0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL, 69 | 0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL, 70 | 0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL, 71 | 0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL, 72 | 0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL, 73 | 0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL, 74 | 0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL, 75 | 0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL, 76 | 0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL, 77 | 0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL, 78 | 0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL, 79 | 0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL, 80 | 0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL, 81 | 0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL, 82 | 0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL, 83 | 0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL, 84 | 0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL, 85 | 0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL, 86 | 0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL, 87 | 0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL, 88 | 0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL, 89 | 0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL, 90 | 0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL, 91 | 0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL, 92 | 0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL, 93 | 0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL, 94 | 0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL, 95 | 0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL, 96 | 0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL, 97 | 0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL, 98 | 0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL, 99 | 0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL, 100 | 0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL, 101 | 0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL, 102 | 0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL, 103 | 0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL, 104 | 0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL, 105 | 0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL, 106 | 0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL, 107 | 0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL, 108 | 0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL, 109 | 0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL, 110 | 0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL, 111 | 0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL, 112 | 0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL, 113 | 0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL, 114 | 0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL, 0xD80C07CD676F8394ULL, 115 | 0x9AFCE626CE85B507ULL 116 | }; 117 | 118 | inline uint64_t crc64(const void *_data, size_t len) 119 | { 120 | uint64_t crc = 0xFFFFFFFFFFFFFFFFULL; 121 | const unsigned char *data = _data; 122 | 123 | while (len--) { 124 | int i = ((int) (crc >> 56) ^ *data++) & 0xFF; 125 | crc = crc_table[i] ^ (crc << 8); 126 | } 127 | 128 | return crc ^ 0xFFFFFFFFFFFFFFFFULL; 129 | } 130 | -------------------------------------------------------------------------------- /bcache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Kent Overstreet 3 | * 4 | * GPLv2 5 | */ 6 | 7 | #ifndef _BCACHE_H 8 | #define _BCACHE_H 9 | 10 | #define BITMASK(name, type, field, offset, size) \ 11 | static inline uint64_t name(const type *k) \ 12 | { return (k->field >> offset) & ~(((uint64_t) ~0) << size); } \ 13 | \ 14 | static inline void SET_##name(type *k, uint64_t v) \ 15 | { \ 16 | k->field &= ~(~((uint64_t) ~0 << size) << offset); \ 17 | k->field |= v << offset; \ 18 | } 19 | 20 | static const char bcache_magic[] = { 21 | 0xc6, 0x85, 0x73, 0xf6, 0x4e, 0x1a, 0x45, 0xca, 22 | 0x82, 0x65, 0xf5, 0x7f, 0x48, 0xba, 0x6d, 0x81 }; 23 | 24 | /* 25 | * Version 0: Cache device 26 | * Version 1: Backing device 27 | * Version 2: Seed pointer into btree node checksum 28 | * Version 3: Cache device with new UUID format 29 | * Version 4: Backing device with data offset 30 | */ 31 | #define BCACHE_SB_VERSION_CDEV 0 32 | #define BCACHE_SB_VERSION_BDEV 1 33 | #define BCACHE_SB_VERSION_CDEV_WITH_UUID 3 34 | #define BCACHE_SB_VERSION_BDEV_WITH_OFFSET 4 35 | #define BCACHE_SB_MAX_VERSION 4 36 | 37 | #define SB_SECTOR 8 38 | #define SB_LABEL_SIZE 32 39 | #define SB_JOURNAL_BUCKETS 256U 40 | #define BDEV_DATA_START_DEFAULT 16 /* sectors */ 41 | #define SB_START (SB_SECTOR * 512) 42 | 43 | struct cache_sb { 44 | uint64_t csum; 45 | uint64_t offset; /* sector where this sb was written */ 46 | uint64_t version; 47 | 48 | uint8_t magic[16]; 49 | 50 | uint8_t uuid[16]; 51 | union { 52 | uint8_t set_uuid[16]; 53 | uint64_t set_magic; 54 | }; 55 | uint8_t label[SB_LABEL_SIZE]; 56 | 57 | uint64_t flags; 58 | uint64_t seq; 59 | uint64_t pad[8]; 60 | 61 | union { 62 | struct { 63 | /* Cache devices */ 64 | uint64_t nbuckets; /* device size */ 65 | 66 | uint16_t block_size; /* sectors */ 67 | uint16_t bucket_size; /* sectors */ 68 | 69 | uint16_t nr_in_set; 70 | uint16_t nr_this_dev; 71 | }; 72 | struct { 73 | /* Backing devices */ 74 | uint64_t data_offset; 75 | 76 | /* 77 | * block_size from the cache device section is still used by 78 | * backing devices, so don't add anything here until we fix 79 | * things to not need it for backing devices anymore 80 | */ 81 | }; 82 | }; 83 | 84 | uint32_t last_mount; /* time_t */ 85 | 86 | uint16_t first_bucket; 87 | union { 88 | uint16_t njournal_buckets; 89 | uint16_t keys; 90 | }; 91 | uint64_t d[SB_JOURNAL_BUCKETS]; /* journal buckets */ 92 | }; 93 | 94 | static inline bool SB_IS_BDEV(const struct cache_sb *sb) 95 | { 96 | return sb->version == BCACHE_SB_VERSION_BDEV 97 | || sb->version == BCACHE_SB_VERSION_BDEV_WITH_OFFSET; 98 | } 99 | 100 | BITMASK(CACHE_SYNC, struct cache_sb, flags, 0, 1); 101 | BITMASK(CACHE_DISCARD, struct cache_sb, flags, 1, 1); 102 | BITMASK(CACHE_REPLACEMENT, struct cache_sb, flags, 2, 3); 103 | #define CACHE_REPLACEMENT_LRU 0U 104 | #define CACHE_REPLACEMENT_FIFO 1U 105 | #define CACHE_REPLACEMENT_RANDOM 2U 106 | 107 | BITMASK(BDEV_CACHE_MODE, struct cache_sb, flags, 0, 4); 108 | #define CACHE_MODE_WRITETHROUGH 0U 109 | #define CACHE_MODE_WRITEBACK 1U 110 | #define CACHE_MODE_WRITEAROUND 2U 111 | #define CACHE_MODE_NONE 3U 112 | BITMASK(BDEV_STATE, struct cache_sb, flags, 61, 2); 113 | #define BDEV_STATE_NONE 0U 114 | #define BDEV_STATE_CLEAN 1U 115 | #define BDEV_STATE_DIRTY 2U 116 | #define BDEV_STATE_STALE 3U 117 | 118 | uint64_t crc64(const void *_data, size_t len); 119 | 120 | #define node(i, j) ((void *) ((i)->d + (j))) 121 | #define end(i) node(i, (i)->keys) 122 | 123 | #define csum_set(i) \ 124 | crc64(((void *) (i)) + 8, ((void *) end(i)) - (((void *) (i)) + 8)) 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /dracut/module-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- 3 | # ex: ts=8 sw=4 sts=4 et filetype=sh 4 | 5 | # 6 | # At some point (util-linux v2.24) blkid will be able to identify bcache 7 | # but until every system has this version of util-linux, probe-bcache is 8 | # provided as an alternative. 9 | # 10 | 11 | check() { 12 | if [[ $hostonly ]] || [[ $mount_needs ]] 13 | then 14 | for fs in "${host_fs_types[@]}"; do 15 | [[ $fs = "bcache" ]] && return 0 16 | done 17 | return 255 18 | fi 19 | 20 | return 0 21 | } 22 | 23 | depends() { 24 | return 0 25 | } 26 | 27 | installkernel() { 28 | instmods bcache 29 | } 30 | 31 | install() { 32 | inst_multiple ${udevdir}/probe-bcache ${udevdir}/bcache-register 33 | inst_rules 69-bcache.rules 34 | } 35 | -------------------------------------------------------------------------------- /initcpio/install: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | build() { 3 | add_module bcache 4 | add_binary /usr/lib/udev/bcache-register 5 | add_binary /usr/lib/udev/probe-bcache 6 | add_file /usr/lib/udev/rules.d/69-bcache.rules 7 | } 8 | help() { 9 | cat < 3 | * 4 | * GPLv2 5 | */ 6 | 7 | #define _FILE_OFFSET_BITS 64 8 | #define __USE_FILE_OFFSET64 9 | #define _XOPEN_SOURCE 600 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "bcache.h" 30 | 31 | #define max(x, y) ({ \ 32 | typeof(x) _max1 = (x); \ 33 | typeof(y) _max2 = (y); \ 34 | (void) (&_max1 == &_max2); \ 35 | _max1 > _max2 ? _max1 : _max2; }) 36 | 37 | uint64_t getblocks(int fd) 38 | { 39 | uint64_t ret; 40 | struct stat statbuf; 41 | if (fstat(fd, &statbuf)) { 42 | perror("stat error\n"); 43 | exit(EXIT_FAILURE); 44 | } 45 | ret = statbuf.st_size / 512; 46 | if (S_ISBLK(statbuf.st_mode)) 47 | if (ioctl(fd, BLKGETSIZE, &ret)) { 48 | perror("ioctl error"); 49 | exit(EXIT_FAILURE); 50 | } 51 | return ret; 52 | } 53 | 54 | uint64_t hatoi(const char *s) 55 | { 56 | char *e; 57 | long long i = strtoll(s, &e, 10); 58 | switch (*e) { 59 | case 't': 60 | case 'T': 61 | i *= 1024; 62 | case 'g': 63 | case 'G': 64 | i *= 1024; 65 | case 'm': 66 | case 'M': 67 | i *= 1024; 68 | case 'k': 69 | case 'K': 70 | i *= 1024; 71 | } 72 | return i; 73 | } 74 | 75 | unsigned hatoi_validate(const char *s, const char *msg) 76 | { 77 | uint64_t v = hatoi(s); 78 | 79 | if (v & (v - 1)) { 80 | fprintf(stderr, "%s must be a power of two\n", msg); 81 | exit(EXIT_FAILURE); 82 | } 83 | 84 | v /= 512; 85 | 86 | if (v > USHRT_MAX) { 87 | fprintf(stderr, "%s too large\n", msg); 88 | exit(EXIT_FAILURE); 89 | } 90 | 91 | if (!v) { 92 | fprintf(stderr, "%s too small\n", msg); 93 | exit(EXIT_FAILURE); 94 | } 95 | 96 | return v; 97 | } 98 | 99 | char *skip_spaces(const char *str) 100 | { 101 | while (isspace(*str)) 102 | ++str; 103 | return (char *)str; 104 | } 105 | 106 | char *strim(char *s) 107 | { 108 | size_t size; 109 | char *end; 110 | 111 | s = skip_spaces(s); 112 | size = strlen(s); 113 | if (!size) 114 | return s; 115 | 116 | end = s + size - 1; 117 | while (end >= s && isspace(*end)) 118 | end--; 119 | *(end + 1) = '\0'; 120 | 121 | return s; 122 | } 123 | 124 | ssize_t read_string_list(const char *buf, const char * const list[]) 125 | { 126 | size_t i; 127 | char *s, *d = strdup(buf); 128 | if (!d) 129 | return -ENOMEM; 130 | 131 | s = strim(d); 132 | 133 | for (i = 0; list[i]; i++) 134 | if (!strcmp(list[i], s)) 135 | break; 136 | 137 | free(d); 138 | 139 | if (!list[i]) 140 | return -EINVAL; 141 | 142 | return i; 143 | } 144 | 145 | void usage() 146 | { 147 | fprintf(stderr, 148 | "Usage: make-bcache [options] device\n" 149 | " -C, --cache Format a cache device\n" 150 | " -B, --bdev Format a backing device\n" 151 | " -b, --bucket bucket size\n" 152 | " -w, --block block size (hard sector size of SSD, often 2k)\n" 153 | " -o, --data-offset data offset in sectors\n" 154 | " --cset-uuid UUID for the cache set\n" 155 | // " -U UUID\n" 156 | " --writeback enable writeback\n" 157 | " --discard enable discards\n" 158 | " --cache_replacement_policy=(lru|fifo)\n" 159 | " -h, --help display this help and exit\n"); 160 | exit(EXIT_FAILURE); 161 | } 162 | 163 | const char * const cache_replacement_policies[] = { 164 | "lru", 165 | "fifo", 166 | "random", 167 | NULL 168 | }; 169 | 170 | static void write_sb(char *dev, unsigned block_size, unsigned bucket_size, 171 | bool writeback, bool discard, bool wipe_bcache, 172 | unsigned cache_replacement_policy, 173 | uint64_t data_offset, 174 | uuid_t set_uuid, bool bdev) 175 | { 176 | int fd; 177 | char uuid_str[40], set_uuid_str[40], zeroes[SB_START] = {0}; 178 | struct cache_sb sb; 179 | blkid_probe pr; 180 | 181 | if ((fd = open(dev, O_RDWR|O_EXCL)) == -1) { 182 | fprintf(stderr, "Can't open dev %s: %s\n", dev, strerror(errno)); 183 | exit(EXIT_FAILURE); 184 | } 185 | 186 | if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) 187 | exit(EXIT_FAILURE); 188 | 189 | if (!memcmp(sb.magic, bcache_magic, 16) && !wipe_bcache) { 190 | fprintf(stderr, "Already a bcache device on %s, " 191 | "overwrite with --wipe-bcache\n", dev); 192 | exit(EXIT_FAILURE); 193 | } 194 | 195 | if (!(pr = blkid_new_probe())) 196 | exit(EXIT_FAILURE); 197 | if (blkid_probe_set_device(pr, fd, 0, 0)) 198 | exit(EXIT_FAILURE); 199 | /* enable ptable probing; superblock probing is enabled by default */ 200 | if (blkid_probe_enable_partitions(pr, true)) 201 | exit(EXIT_FAILURE); 202 | if (!blkid_do_probe(pr)) { 203 | /* XXX wipefs doesn't know how to remove partition tables */ 204 | fprintf(stderr, "Device %s already has a non-bcache superblock, " 205 | "remove it using wipefs and wipefs -a\n", dev); 206 | exit(EXIT_FAILURE); 207 | } 208 | 209 | memset(&sb, 0, sizeof(struct cache_sb)); 210 | 211 | sb.offset = SB_SECTOR; 212 | sb.version = bdev 213 | ? BCACHE_SB_VERSION_BDEV 214 | : BCACHE_SB_VERSION_CDEV; 215 | 216 | memcpy(sb.magic, bcache_magic, 16); 217 | uuid_generate(sb.uuid); 218 | memcpy(sb.set_uuid, set_uuid, sizeof(sb.set_uuid)); 219 | 220 | sb.bucket_size = bucket_size; 221 | sb.block_size = block_size; 222 | 223 | uuid_unparse(sb.uuid, uuid_str); 224 | uuid_unparse(sb.set_uuid, set_uuid_str); 225 | 226 | if (SB_IS_BDEV(&sb)) { 227 | SET_BDEV_CACHE_MODE( 228 | &sb, writeback ? CACHE_MODE_WRITEBACK : CACHE_MODE_WRITETHROUGH); 229 | 230 | if (data_offset != BDEV_DATA_START_DEFAULT) { 231 | sb.version = BCACHE_SB_VERSION_BDEV_WITH_OFFSET; 232 | sb.data_offset = data_offset; 233 | } 234 | 235 | printf("UUID: %s\n" 236 | "Set UUID: %s\n" 237 | "version: %u\n" 238 | "block_size: %u\n" 239 | "data_offset: %ju\n", 240 | uuid_str, set_uuid_str, 241 | (unsigned) sb.version, 242 | sb.block_size, 243 | data_offset); 244 | } else { 245 | sb.nbuckets = getblocks(fd) / sb.bucket_size; 246 | sb.nr_in_set = 1; 247 | sb.first_bucket = (23 / sb.bucket_size) + 1; 248 | 249 | if (sb.nbuckets < 1 << 7) { 250 | fprintf(stderr, "Not enough buckets: %ju, need %u\n", 251 | sb.nbuckets, 1 << 7); 252 | exit(EXIT_FAILURE); 253 | } 254 | 255 | SET_CACHE_DISCARD(&sb, discard); 256 | SET_CACHE_REPLACEMENT(&sb, cache_replacement_policy); 257 | 258 | printf("UUID: %s\n" 259 | "Set UUID: %s\n" 260 | "version: %u\n" 261 | "nbuckets: %ju\n" 262 | "block_size: %u\n" 263 | "bucket_size: %u\n" 264 | "nr_in_set: %u\n" 265 | "nr_this_dev: %u\n" 266 | "first_bucket: %u\n", 267 | uuid_str, set_uuid_str, 268 | (unsigned) sb.version, 269 | sb.nbuckets, 270 | sb.block_size, 271 | sb.bucket_size, 272 | sb.nr_in_set, 273 | sb.nr_this_dev, 274 | sb.first_bucket); 275 | } 276 | 277 | sb.csum = csum_set(&sb); 278 | 279 | /* Zero start of disk */ 280 | if (pwrite(fd, zeroes, SB_START, 0) != SB_START) { 281 | perror("write error\n"); 282 | exit(EXIT_FAILURE); 283 | } 284 | /* Write superblock */ 285 | if (pwrite(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) { 286 | perror("write error\n"); 287 | exit(EXIT_FAILURE); 288 | } 289 | 290 | fsync(fd); 291 | close(fd); 292 | } 293 | 294 | static unsigned get_blocksize(const char *path) 295 | { 296 | struct stat statbuf; 297 | 298 | if (stat(path, &statbuf)) { 299 | fprintf(stderr, "Error statting %s: %s\n", 300 | path, strerror(errno)); 301 | exit(EXIT_FAILURE); 302 | } 303 | 304 | if (S_ISBLK(statbuf.st_mode)) { 305 | /* check IO limits: 306 | * BLKALIGNOFF: alignment_offset 307 | * BLKPBSZGET: physical_block_size 308 | * BLKSSZGET: logical_block_size 309 | * BLKIOMIN: minimum_io_size 310 | * BLKIOOPT: optimal_io_size 311 | * 312 | * It may be tempting to use physical_block_size, 313 | * or even minimum_io_size. 314 | * But to be as transparent as possible, 315 | * we want to use logical_block_size. 316 | */ 317 | unsigned int logical_block_size; 318 | int fd = open(path, O_RDONLY); 319 | 320 | if (fd < 0) { 321 | fprintf(stderr, "open(%s) failed: %m\n", path); 322 | exit(EXIT_FAILURE); 323 | } 324 | if (ioctl(fd, BLKSSZGET, &logical_block_size)) { 325 | fprintf(stderr, "ioctl(%s, BLKSSZGET) failed: %m\n", path); 326 | exit(EXIT_FAILURE); 327 | } 328 | close(fd); 329 | return logical_block_size / 512; 330 | 331 | } 332 | /* else: not a block device. 333 | * Why would we even want to write a bcache super block there? */ 334 | 335 | return statbuf.st_blksize / 512; 336 | } 337 | 338 | int main(int argc, char **argv) 339 | { 340 | int c, bdev = -1; 341 | unsigned i, ncache_devices = 0, nbacking_devices = 0; 342 | char *cache_devices[argc]; 343 | char *backing_devices[argc]; 344 | 345 | unsigned block_size = 0, bucket_size = 1024; 346 | int writeback = 0, discard = 0, wipe_bcache = 0; 347 | unsigned cache_replacement_policy = 0; 348 | uint64_t data_offset = BDEV_DATA_START_DEFAULT; 349 | uuid_t set_uuid; 350 | 351 | uuid_generate(set_uuid); 352 | 353 | struct option opts[] = { 354 | { "cache", 0, NULL, 'C' }, 355 | { "bdev", 0, NULL, 'B' }, 356 | { "bucket", 1, NULL, 'b' }, 357 | { "block", 1, NULL, 'w' }, 358 | { "writeback", 0, &writeback, 1 }, 359 | { "wipe-bcache", 0, &wipe_bcache, 1 }, 360 | { "discard", 0, &discard, 1 }, 361 | { "cache_replacement_policy", 1, NULL, 'p' }, 362 | { "cache-replacement-policy", 1, NULL, 'p' }, 363 | { "data_offset", 1, NULL, 'o' }, 364 | { "data-offset", 1, NULL, 'o' }, 365 | { "cset-uuid", 1, NULL, 'u' }, 366 | { "help", 0, NULL, 'h' }, 367 | { NULL, 0, NULL, 0 }, 368 | }; 369 | 370 | while ((c = getopt_long(argc, argv, 371 | "-hCBUo:w:b:", 372 | opts, NULL)) != -1) 373 | switch (c) { 374 | case 'C': 375 | bdev = 0; 376 | break; 377 | case 'B': 378 | bdev = 1; 379 | break; 380 | case 'b': 381 | bucket_size = hatoi_validate(optarg, "bucket size"); 382 | break; 383 | case 'w': 384 | block_size = hatoi_validate(optarg, "block size"); 385 | break; 386 | #if 0 387 | case 'U': 388 | if (uuid_parse(optarg, sb.uuid)) { 389 | fprintf(stderr, "Bad uuid\n"); 390 | exit(EXIT_FAILURE); 391 | } 392 | break; 393 | #endif 394 | case 'p': 395 | cache_replacement_policy = read_string_list(optarg, 396 | cache_replacement_policies); 397 | break; 398 | case 'o': 399 | data_offset = atoll(optarg); 400 | if (data_offset < BDEV_DATA_START_DEFAULT) { 401 | fprintf(stderr, "Bad data offset; minimum %d sectors\n", 402 | BDEV_DATA_START_DEFAULT); 403 | exit(EXIT_FAILURE); 404 | } 405 | break; 406 | case 'u': 407 | if (uuid_parse(optarg, set_uuid)) { 408 | fprintf(stderr, "Bad uuid\n"); 409 | exit(EXIT_FAILURE); 410 | } 411 | break; 412 | case 'h': 413 | usage(); 414 | break; 415 | case 1: 416 | if (bdev == -1) { 417 | fprintf(stderr, "Please specify -C or -B\n"); 418 | exit(EXIT_FAILURE); 419 | } 420 | 421 | if (bdev) 422 | backing_devices[nbacking_devices++] = optarg; 423 | else 424 | cache_devices[ncache_devices++] = optarg; 425 | break; 426 | } 427 | 428 | if (!ncache_devices && !nbacking_devices) { 429 | fprintf(stderr, "Please supply a device\n"); 430 | usage(); 431 | } 432 | 433 | if (bucket_size < block_size) { 434 | fprintf(stderr, "Bucket size cannot be smaller than block size\n"); 435 | exit(EXIT_FAILURE); 436 | } 437 | 438 | if (!block_size) { 439 | for (i = 0; i < ncache_devices; i++) 440 | block_size = max(block_size, 441 | get_blocksize(cache_devices[i])); 442 | 443 | for (i = 0; i < nbacking_devices; i++) 444 | block_size = max(block_size, 445 | get_blocksize(backing_devices[i])); 446 | } 447 | 448 | for (i = 0; i < ncache_devices; i++) 449 | write_sb(cache_devices[i], block_size, bucket_size, 450 | writeback, discard, wipe_bcache, 451 | cache_replacement_policy, 452 | data_offset, set_uuid, false); 453 | 454 | for (i = 0; i < nbacking_devices; i++) 455 | write_sb(backing_devices[i], block_size, bucket_size, 456 | writeback, discard, wipe_bcache, 457 | cache_replacement_policy, 458 | data_offset, set_uuid, true); 459 | 460 | return 0; 461 | } 462 | -------------------------------------------------------------------------------- /probe-bcache.8: -------------------------------------------------------------------------------- 1 | .TH probe-bcache 8 2 | .SH NAME 3 | probe-bcache \- probe a bcache device 4 | .SH SYNOPSIS 5 | .B probe-bcache 6 | [\fB \-o\ \fIudev\fR ] 7 | .I device 8 | .SH OPTIONS 9 | .TP 10 | .BR \-o 11 | return UUID in udev style for invocation by udev rule as IMPORT{program} 12 | .SH USAGE 13 | Return UUID if device identified as bcache-formatted. 14 | 15 | Only necessary until support for the bcache superblock is included 16 | in blkid; in the meantime, provides just enough functionality for a udev script 17 | to create the /dev/disk/by-uuid symlink. 18 | -------------------------------------------------------------------------------- /probe-bcache.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Kent Overstreet 3 | * 4 | * GPLv2 5 | */ 6 | 7 | #define _FILE_OFFSET_BITS 64 8 | #define __USE_FILE_OFFSET64 9 | #define _XOPEN_SOURCE 500 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "bcache.h" 26 | 27 | int main(int argc, char **argv) 28 | { 29 | bool udev = false; 30 | int i, o; 31 | extern char *optarg; 32 | struct cache_sb sb; 33 | char uuid[40]; 34 | blkid_probe pr; 35 | 36 | while ((o = getopt(argc, argv, "o:")) != EOF) 37 | switch (o) { 38 | case 'o': 39 | if (strcmp("udev", optarg)) { 40 | printf("Invalid output format %s\n", optarg); 41 | exit(EXIT_FAILURE); 42 | } 43 | udev = true; 44 | break; 45 | } 46 | 47 | 48 | argv += optind; 49 | argc -= optind; 50 | 51 | for (i = 0; i < argc; i++) { 52 | int fd = open(argv[i], O_RDONLY); 53 | if (fd == -1) 54 | continue; 55 | 56 | if (!(pr = blkid_new_probe())) 57 | continue; 58 | if (blkid_probe_set_device(pr, fd, 0, 0)) 59 | continue; 60 | /* probe partitions too */ 61 | if (blkid_probe_enable_partitions(pr, true)) 62 | continue; 63 | /* bail if anything was found 64 | * probe-bcache isn't needed once blkid recognizes bcache */ 65 | if (!blkid_do_probe(pr)) { 66 | continue; 67 | } 68 | 69 | if (pread(fd, &sb, sizeof(sb), SB_START) != sizeof(sb)) 70 | continue; 71 | 72 | if (memcmp(sb.magic, bcache_magic, 16)) 73 | continue; 74 | 75 | uuid_unparse(sb.uuid, uuid); 76 | 77 | if (udev) 78 | printf("ID_FS_UUID=%s\n" 79 | "ID_FS_UUID_ENC=%s\n" 80 | "ID_FS_TYPE=bcache\n", 81 | uuid, uuid); 82 | else 83 | printf("%s: UUID=\"\" TYPE=\"bcache\"\n", uuid); 84 | } 85 | 86 | return 0; 87 | } 88 | --------------------------------------------------------------------------------