├── Kconfig ├── LICENSE ├── Makefile ├── README.md ├── amap_smart.c ├── amap_smart.h ├── api.c ├── api.h ├── blkdev.c ├── cache.c ├── config.h ├── core.c ├── core.h ├── core_exfat.c ├── core_fat.c ├── dfr.c ├── dfr.h ├── extent.c ├── fatent.c ├── misc.c ├── mpage.c ├── nls.c ├── sdfat.c ├── sdfat.h ├── sdfat_fs.h ├── statistics.c ├── upcase.h ├── version.h └── xattr.c /Kconfig: -------------------------------------------------------------------------------- 1 | config SDFAT_FS 2 | tristate "sdFAT filesystem support" 3 | select NLS 4 | select NLS_UTF8 5 | select NLS_CODEPAGE_437 6 | select NLS_ISO8859_1 7 | help 8 | If you want to use the sdFAT file system, then you must say Y or M 9 | here to inlucde sdFAT support. 10 | sdFAT is unified FAT-based file system which supports not only fat12/ 11 | 16/32 with vfat but also exfat. sdFAT supports winnt short-name rule. 12 | (winnt: emulate the Windows NT rule for display/create.) 13 | 14 | To compile this as a module, choose M here: the module will be called 15 | sdfat_core and sdfat_fs. 16 | 17 | config SDFAT_USE_FOR_EXFAT 18 | bool "Register sdFAT as exFAT" 19 | default y 20 | depends on SDFAT_FS && !EXFAT_FS 21 | help 22 | If you want to register sdFAT as available for exFAT, say Y. 23 | 24 | config SDFAT_USE_FOR_VFAT 25 | bool "Register sdFAT as VFAT" 26 | default y 27 | depends on SDFAT_FS && !VFAT_FS 28 | help 29 | If you want to register sdFAT as available for VFAT, say Y. 30 | 31 | config SDFAT_DELAYED_META_DIRTY 32 | bool "Enable delayed metadata dirty" 33 | default y 34 | depends on SDFAT_FS 35 | help 36 | If you enable this feature, metadata(FAT/Directory entry) is updated 37 | by flush thread. 38 | 39 | config SDFAT_SUPPORT_DIR_SYNC 40 | bool "Enable supporting dir sync" 41 | default n 42 | depends on SDFAT_FS 43 | help 44 | If you enable this feature, the modification for directory operation 45 | is written to a storage at once. 46 | 47 | config SDFAT_DEFAULT_CODEPAGE 48 | int "Default codepage for sdFAT" 49 | default 437 50 | depends on SDFAT_FS 51 | help 52 | This option should be set to the codepage of your sdFAT filesystems. 53 | 54 | config SDFAT_DEFAULT_IOCHARSET 55 | string "Default iocharset for sdFAT" 56 | default "utf8" 57 | depends on SDFAT_FS 58 | help 59 | Set this to the default input/output character set you'd 60 | like sdFAT to use. It should probably match the character set 61 | that most of your sdFAT filesystems use, and can be overridden 62 | with the "iocharset" mount option for sdFAT filesystems. 63 | 64 | config SDFAT_CHECK_RO_ATTR 65 | bool "Check read-only attribute" 66 | default n 67 | depends on SDFAT_FS 68 | 69 | config SDFAT_ALIGNED_MPAGE_WRITE 70 | bool "Enable supporting aligned mpage_write" 71 | default y if SDFAT_FS=y 72 | default n if SDFAT_FS=m 73 | depends on SDFAT_FS 74 | 75 | config SDFAT_VIRTUAL_XATTR 76 | bool "Virtual xattr support for sdFAT" 77 | default n 78 | depends on SDFAT_FS 79 | help 80 | If you enable this feature, it supports virtual xattr. 81 | This feature will be deprecated because it might be the same with 82 | "context" mount option. 83 | 84 | config SDFAT_VIRTUAL_XATTR_SELINUX_LABEL 85 | string "Default string for SELinux label" 86 | default "u:object_r:sdcard_external:s0" 87 | depends on SDFAT_FS && SDFAT_VIRTUAL_XATTR 88 | help 89 | Set this to the default string for SELinux label. 90 | 91 | config SDFAT_SUPPORT_STLOG 92 | bool "Enable storage log" 93 | default y 94 | depends on SDFAT_FS && PROC_STLOG 95 | 96 | config SDFAT_DEBUG 97 | bool "enable debug features" 98 | depends on SDFAT_FS 99 | default y 100 | 101 | config SDFAT_DBG_IOCTL 102 | bool "enable debug-ioctl features" 103 | depends on SDFAT_FS && SDFAT_DEBUG 104 | default n 105 | 106 | config SDFAT_DBG_MSG 107 | bool "enable debug messages" 108 | depends on SDFAT_FS && SDFAT_DEBUG 109 | default y 110 | 111 | config SDFAT_DBG_BUGON 112 | bool "enable strict BUG_ON() for debugging" 113 | depends on SDFAT_FS && SDFAT_DEBUG 114 | default n 115 | 116 | config SDFAT_DBG_WARNON 117 | bool "enable strict WARN_ON() for debugging" 118 | depends on SDFAT_FS && SDFAT_DEBUG 119 | default n 120 | 121 | config SDFAT_STATISTICS 122 | bool "enable statistics for bigdata" 123 | depends on SDFAT_FS 124 | default y 125 | 126 | config SDFAT_UEVENT 127 | bool "enable uevent" 128 | depends on SDFAT_FS 129 | default y 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, 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 Lesser 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 along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for the linux FAT12/16/32(VFAT)/64(exFAT) filesystem driver. 3 | # 4 | 5 | obj-$(CONFIG_SDFAT_FS) += sdfat_fs.o 6 | 7 | sdfat_fs-objs := sdfat.o core.o core_fat.o core_exfat.o api.o blkdev.o \ 8 | fatent.o amap_smart.o cache.o dfr.o nls.o misc.o \ 9 | mpage.o extent.o 10 | 11 | sdfat_fs-$(CONFIG_SDFAT_VIRTUAL_XATTR) += xattr.o 12 | sdfat_fs-$(CONFIG_SDFAT_STATISTICS) += statistics.o 13 | 14 | 15 | all: 16 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 17 | 18 | clean: 19 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 20 | 21 | cscope: 22 | rm -rf cscope.files cscope.files 23 | find $(PWD) \( -name '*.c' -o -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.s' -o -name '*.S' \) -print > cscope.files 24 | cscope 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sdFAT FS support for Linux Kernel 4.4 2 | ===================================== 3 | 4 | sdFAT is unified FAT-based file system which supports not only fat12/16/32 with 5 | vfat but also exfat. sdFAT supports winnt short-name rule. 6 | 7 | Suggested Kernel config: 8 | 9 | CONFIG_SDFAT_FS=y 10 | CONFIG_SDFAT_DELAYED_META_DIRTY=y 11 | CONFIG_SDFAT_SUPPORT_DIR_SYNC=y 12 | CONFIG_SDFAT_DEFAULT_CODEPAGE=437 13 | CONFIG_SDFAT_DEFAULT_IOCHARSET="utf8" 14 | CONFIG_SDFAT_ALIGNED_MPAGE_WRITE=y 15 | CONFIG_SDFAT_VIRTUAL_XATTR=y 16 | CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:vfat:s0" 17 | CONFIG_SDFAT_DEBUG=y 18 | CONFIG_SDFAT_DBG_MSG=y 19 | CONFIG_SDFAT_STATISTICS=y 20 | -------------------------------------------------------------------------------- /amap_smart.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | #ifndef _SDFAT_AMAP_H 19 | #define _SDFAT_AMAP_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | /* AMAP Configuration Variable */ 26 | #define SMART_ALLOC_N_HOT_AU (5) 27 | 28 | /* Allocating Destination (for smart allocator): 29 | * moved to sdfat.h 30 | */ 31 | /* 32 | * #define ALLOC_COLD_ALIGNED (1) 33 | * #define ALLOC_COLD_PACKING (2) 34 | * #define ALLOC_COLD_SEQ (4) 35 | */ 36 | 37 | /* Minimum sectors for support AMAP create */ 38 | #define AMAP_MIN_SUPPORT_SECTORS (1048576) 39 | 40 | #define amap_add_hot_au(amap, au) amap_insert_to_list(au, &amap->slist_hot) 41 | 42 | /* singly linked list */ 43 | struct slist_head { 44 | struct slist_head *next; 45 | struct slist_head *head; 46 | }; 47 | 48 | /* AU entry type */ 49 | typedef struct __AU_INFO_T { 50 | uint16_t idx; /* the index of the AU (0, 1, 2, ... ) */ 51 | uint16_t free_clusters; /* # of available cluster */ 52 | union { 53 | struct list_head head; 54 | struct slist_head shead;/* singly linked list head for hot list */ 55 | }; 56 | } AU_INFO_T; 57 | 58 | 59 | /* Allocation Target AU */ 60 | typedef struct __TARGET_AU_T { 61 | AU_INFO_T *au; /* Working AU */ 62 | uint16_t idx; /* Intra-AU cluster index */ 63 | uint16_t clu_to_skip; /* Clusters to skip */ 64 | } TARGET_AU_T; 65 | 66 | 67 | /* AMAP free-clusters-based node */ 68 | typedef struct { 69 | struct list_head head; /* the list of AUs */ 70 | } FCLU_NODE_T; 71 | 72 | 73 | /* AMAP options */ 74 | typedef struct { 75 | unsigned int packing_ratio; /* Tunable packing ratio */ 76 | unsigned int au_size; /* AU size in sectors */ 77 | unsigned int au_align_factor; /* Hidden sectors % au_size */ 78 | } AMAP_OPT_T; 79 | 80 | typedef struct __AMAP_T { 81 | spinlock_t amap_lock; /* obsolete */ 82 | struct super_block *sb; 83 | 84 | int n_au; 85 | int n_clean_au, n_full_au; 86 | int clu_align_bias; 87 | uint16_t clusters_per_au; 88 | AU_INFO_T **au_table; /* An array of AU_INFO entries */ 89 | AMAP_OPT_T option; 90 | 91 | /* Size-based AU management pool (cold) */ 92 | FCLU_NODE_T *fclu_nodes; /* An array of listheads */ 93 | int fclu_order; /* Page order that fclu_nodes needs */ 94 | int fclu_hint; /* maximum # of free clusters in an AU */ 95 | 96 | /* Hot AU list */ 97 | unsigned int total_fclu_hot; /* Free clusters in hot list */ 98 | struct slist_head slist_hot; /* Hot AU list */ 99 | 100 | /* Ignored AU list */ 101 | struct slist_head slist_ignored; 102 | 103 | /* Allocator variables (keep 2 AUs at maximum) */ 104 | TARGET_AU_T cur_cold; 105 | TARGET_AU_T cur_hot; 106 | int n_need_packing; 107 | } AMAP_T; 108 | 109 | 110 | /* AU table */ 111 | #define N_AU_PER_TABLE (int)(PAGE_SIZE / sizeof(AU_INFO_T)) 112 | #define GET_AU(amap, i_AU) (amap->au_table[(i_AU) / N_AU_PER_TABLE] + ((i_AU) % N_AU_PER_TABLE)) 113 | //#define MAX_CLU_PER_AU (int)(PAGE_SIZE / sizeof(FCLU_NODE_T)) 114 | #define MAX_CLU_PER_AU (1024) 115 | 116 | /* Cold AU bucket <-> # of freeclusters */ 117 | #define NODE_CLEAN(amap) (&amap->fclu_nodes[amap->clusters_per_au - 1]) 118 | #define NODE(fclu, amap) (&amap->fclu_nodes[fclu - 1]) 119 | #define FREE_CLUSTERS(node, amap) ((int)(node - amap->fclu_nodes) + 1) 120 | 121 | /* AU status */ 122 | #define MAGIC_WORKING ((struct slist_head *)0xFFFF5091) 123 | #define IS_AU_HOT(au, amap) (au->shead.head == &amap->slist_hot) 124 | #define IS_AU_IGNORED(au, amap) (au->shead.head == &amap->slist_ignored) 125 | #define IS_AU_WORKING(au, amap) (au->shead.head == MAGIC_WORKING) 126 | #define SET_AU_WORKING(au) (au->shead.head = MAGIC_WORKING) 127 | 128 | /* AU <-> cluster */ 129 | #define i_AU_of_CLU(amap, clu) ((amap->clu_align_bias + clu) / amap->clusters_per_au) 130 | #define CLU_of_i_AU(amap, i_au, idx) \ 131 | ((uint32_t)(i_au) * (uint32_t)amap->clusters_per_au + (idx) - amap->clu_align_bias) 132 | 133 | /* 134 | * NOTE : AMAP internal functions are moved to core.h 135 | */ 136 | 137 | #endif /* _SDFAT_AMAP_H */ 138 | -------------------------------------------------------------------------------- /api.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | /************************************************************************/ 19 | /* */ 20 | /* PROJECT : exFAT & FAT12/16/32 File System */ 21 | /* FILE : sdfat_api.c */ 22 | /* PURPOSE : sdFAT volume lock layer */ 23 | /* */ 24 | /************************************************************************/ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "version.h" 32 | #include "config.h" 33 | 34 | #include "sdfat.h" 35 | #include "core.h" 36 | 37 | /*----------------------------------------------------------------------*/ 38 | /* Internal structures */ 39 | /*----------------------------------------------------------------------*/ 40 | 41 | /*----------------------------------------------------------------------*/ 42 | /* Constant & Macro Definitions */ 43 | /*----------------------------------------------------------------------*/ 44 | static DEFINE_MUTEX(_lock_core); 45 | 46 | /*----------------------------------------------------------------------*/ 47 | /* Global Variable Definitions */ 48 | /*----------------------------------------------------------------------*/ 49 | 50 | /*----------------------------------------------------------------------*/ 51 | /* Local Variable Definitions */ 52 | /*----------------------------------------------------------------------*/ 53 | 54 | /*----------------------------------------------------------------------*/ 55 | /* Local Function Declarations */ 56 | /*----------------------------------------------------------------------*/ 57 | 58 | /*======================================================================*/ 59 | /* Global Function Definitions */ 60 | /* - All functions for global use have same return value format, */ 61 | /* that is, 0 on success and minus error number on */ 62 | /* various error condition. */ 63 | /*======================================================================*/ 64 | 65 | /*----------------------------------------------------------------------*/ 66 | /* sdFAT Filesystem Init & Exit Functions */ 67 | /*----------------------------------------------------------------------*/ 68 | 69 | s32 fsapi_init(void) 70 | { 71 | return fscore_init(); 72 | } 73 | 74 | s32 fsapi_shutdown(void) 75 | { 76 | return fscore_shutdown(); 77 | } 78 | 79 | /*----------------------------------------------------------------------*/ 80 | /* Volume Management Functions */ 81 | /*----------------------------------------------------------------------*/ 82 | 83 | /* mount the file system volume */ 84 | s32 fsapi_mount(struct super_block *sb) 85 | { 86 | s32 err; 87 | 88 | /* acquire the core lock for file system ccritical section */ 89 | mutex_lock(&_lock_core); 90 | 91 | err = meta_cache_init(sb); 92 | if (err) 93 | goto out; 94 | 95 | err = fscore_mount(sb); 96 | out: 97 | if (err) 98 | meta_cache_shutdown(sb); 99 | 100 | /* release the core lock for file system critical section */ 101 | mutex_unlock(&_lock_core); 102 | 103 | return err; 104 | } 105 | EXPORT_SYMBOL(fsapi_mount); 106 | 107 | /* unmount the file system volume */ 108 | s32 fsapi_umount(struct super_block *sb) 109 | { 110 | s32 err; 111 | 112 | /* acquire the core lock for file system ccritical section */ 113 | mutex_lock(&_lock_core); 114 | 115 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 116 | err = fscore_umount(sb); 117 | meta_cache_shutdown(sb); 118 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 119 | 120 | /* release the core lock for file system critical section */ 121 | mutex_unlock(&_lock_core); 122 | 123 | return err; 124 | } 125 | EXPORT_SYMBOL(fsapi_umount); 126 | 127 | /* get the information of a file system volume */ 128 | s32 fsapi_statfs(struct super_block *sb, VOL_INFO_T *info) 129 | { 130 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 131 | 132 | /* check the validity of pointer parameters */ 133 | ASSERT(info); 134 | 135 | if (fsi->used_clusters == (u32) ~0) { 136 | s32 err; 137 | 138 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 139 | err = fscore_statfs(sb, info); 140 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 141 | return err; 142 | } 143 | 144 | info->FatType = fsi->vol_type; 145 | info->ClusterSize = fsi->cluster_size; 146 | info->NumClusters = fsi->num_clusters - 2; /* clu 0 & 1 */ 147 | info->UsedClusters = fsi->used_clusters + fsi->reserved_clusters; 148 | info->FreeClusters = info->NumClusters - info->UsedClusters; 149 | 150 | return 0; 151 | } 152 | EXPORT_SYMBOL(fsapi_statfs); 153 | 154 | /* synchronize a file system volume */ 155 | s32 fsapi_sync_fs(struct super_block *sb, s32 do_sync) 156 | { 157 | s32 err; 158 | 159 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 160 | err = fscore_sync_fs(sb, do_sync); 161 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 162 | return err; 163 | } 164 | EXPORT_SYMBOL(fsapi_sync_fs); 165 | 166 | s32 fsapi_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_sync) 167 | { 168 | s32 err; 169 | 170 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 171 | err = fscore_set_vol_flags(sb, new_flag, always_sync); 172 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 173 | return err; 174 | } 175 | EXPORT_SYMBOL(fsapi_set_vol_flags); 176 | 177 | /*----------------------------------------------------------------------*/ 178 | /* File Operation Functions */ 179 | /*----------------------------------------------------------------------*/ 180 | 181 | /* lookup */ 182 | s32 fsapi_lookup(struct inode *inode, u8 *path, FILE_ID_T *fid) 183 | { 184 | s32 err; 185 | struct super_block *sb = inode->i_sb; 186 | 187 | /* check the validity of pointer parameters */ 188 | ASSERT(fid && path); 189 | 190 | if (unlikely(!strlen(path))) 191 | return -EINVAL; 192 | 193 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 194 | err = fscore_lookup(inode, path, fid); 195 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 196 | return err; 197 | } 198 | EXPORT_SYMBOL(fsapi_lookup); 199 | 200 | /* create a file */ 201 | s32 fsapi_create(struct inode *inode, u8 *path, u8 mode, FILE_ID_T *fid) 202 | { 203 | s32 err; 204 | struct super_block *sb = inode->i_sb; 205 | 206 | /* check the validity of pointer parameters */ 207 | ASSERT(fid && path); 208 | 209 | if (unlikely(!strlen(path))) 210 | return -EINVAL; 211 | 212 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 213 | err = fscore_create(inode, path, mode, fid); 214 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 215 | return err; 216 | } 217 | EXPORT_SYMBOL(fsapi_create); 218 | 219 | /* read the target string of symlink */ 220 | s32 fsapi_read_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) 221 | { 222 | s32 err; 223 | struct super_block *sb = inode->i_sb; 224 | 225 | /* check the validity of pointer parameters */ 226 | ASSERT(fid && buffer); 227 | 228 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 229 | err = fscore_read_link(inode, fid, buffer, count, rcount); 230 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 231 | return err; 232 | } 233 | EXPORT_SYMBOL(fsapi_read_link); 234 | 235 | /* write the target string of symlink */ 236 | s32 fsapi_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) 237 | { 238 | s32 err; 239 | struct super_block *sb = inode->i_sb; 240 | 241 | /* check the validity of pointer parameters */ 242 | ASSERT(fid && buffer); 243 | 244 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 245 | err = fscore_write_link(inode, fid, buffer, count, wcount); 246 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 247 | return err; 248 | } 249 | EXPORT_SYMBOL(fsapi_write_link); 250 | 251 | /* resize the file length */ 252 | s32 fsapi_truncate(struct inode *inode, u64 old_size, u64 new_size) 253 | { 254 | s32 err; 255 | struct super_block *sb = inode->i_sb; 256 | 257 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 258 | TMSG("%s entered (inode %p size %llu)\n", __func__, inode, new_size); 259 | err = fscore_truncate(inode, old_size, new_size); 260 | TMSG("%s exitted (%d)\n", __func__, err); 261 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 262 | return err; 263 | } 264 | EXPORT_SYMBOL(fsapi_truncate); 265 | 266 | /* rename or move a old file into a new file */ 267 | s32 fsapi_rename(struct inode *old_parent_inode, FILE_ID_T *fid, 268 | struct inode *new_parent_inode, struct dentry *new_dentry) 269 | { 270 | s32 err; 271 | struct super_block *sb = old_parent_inode->i_sb; 272 | 273 | /* check the validity of pointer parameters */ 274 | ASSERT(fid); 275 | 276 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 277 | err = fscore_rename(old_parent_inode, fid, new_parent_inode, new_dentry); 278 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 279 | return err; 280 | } 281 | EXPORT_SYMBOL(fsapi_rename); 282 | 283 | /* remove a file */ 284 | s32 fsapi_remove(struct inode *inode, FILE_ID_T *fid) 285 | { 286 | s32 err; 287 | struct super_block *sb = inode->i_sb; 288 | 289 | /* check the validity of pointer parameters */ 290 | ASSERT(fid); 291 | 292 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 293 | err = fscore_remove(inode, fid); 294 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 295 | return err; 296 | } 297 | EXPORT_SYMBOL(fsapi_remove); 298 | 299 | /* get the information of a given file */ 300 | s32 fsapi_read_inode(struct inode *inode, DIR_ENTRY_T *info) 301 | { 302 | s32 err; 303 | struct super_block *sb = inode->i_sb; 304 | 305 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 306 | TMSG("%s entered (inode %p info %p\n", __func__, inode, info); 307 | err = fscore_read_inode(inode, info); 308 | TMSG("%s exited (err:%d)\n", __func__, err); 309 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 310 | return err; 311 | } 312 | EXPORT_SYMBOL(fsapi_read_inode); 313 | 314 | /* set the information of a given file */ 315 | s32 fsapi_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync) 316 | { 317 | s32 err; 318 | struct super_block *sb = inode->i_sb; 319 | 320 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 321 | TMSG("%s entered (inode %p info %p sync:%d\n", 322 | __func__, inode, info, sync); 323 | err = fscore_write_inode(inode, info, sync); 324 | TMSG("%s exited (err:%d)\n", __func__, err); 325 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 326 | return err; 327 | } 328 | EXPORT_SYMBOL(fsapi_write_inode); 329 | 330 | /* return the cluster number in the given cluster offset */ 331 | s32 fsapi_map_clus(struct inode *inode, u32 clu_offset, u32 *clu, int dest) 332 | { 333 | s32 err; 334 | struct super_block *sb = inode->i_sb; 335 | 336 | /* check the validity of pointer parameters */ 337 | ASSERT(clu); 338 | 339 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 340 | TMSG("%s entered (inode:%p clus:%08x dest:%d\n", 341 | __func__, inode, *clu, dest); 342 | err = fscore_map_clus(inode, clu_offset, clu, dest); 343 | TMSG("%s exited (clu:%08x err:%d)\n", __func__, *clu, err); 344 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 345 | return err; 346 | } 347 | EXPORT_SYMBOL(fsapi_map_clus); 348 | 349 | /* reserve a cluster */ 350 | s32 fsapi_reserve_clus(struct inode *inode) 351 | { 352 | s32 err; 353 | struct super_block *sb = inode->i_sb; 354 | 355 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 356 | TMSG("%s entered (inode:%p)\n", __func__, inode); 357 | err = fscore_reserve_clus(inode); 358 | TMSG("%s exited (err:%d)\n", __func__, err); 359 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 360 | return err; 361 | } 362 | EXPORT_SYMBOL(fsapi_reserve_clus); 363 | 364 | /*----------------------------------------------------------------------*/ 365 | /* Directory Operation Functions */ 366 | /*----------------------------------------------------------------------*/ 367 | 368 | /* create(make) a directory */ 369 | s32 fsapi_mkdir(struct inode *inode, u8 *path, FILE_ID_T *fid) 370 | { 371 | s32 err; 372 | struct super_block *sb = inode->i_sb; 373 | 374 | /* check the validity of pointer parameters */ 375 | ASSERT(fid && path); 376 | 377 | if (unlikely(!strlen(path))) 378 | return -EINVAL; 379 | 380 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 381 | err = fscore_mkdir(inode, path, fid); 382 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 383 | return err; 384 | } 385 | EXPORT_SYMBOL(fsapi_mkdir); 386 | 387 | /* read a directory entry from the opened directory */ 388 | s32 fsapi_readdir(struct inode *inode, DIR_ENTRY_T *dir_entry) 389 | { 390 | s32 err; 391 | struct super_block *sb = inode->i_sb; 392 | 393 | /* check the validity of pointer parameters */ 394 | ASSERT(dir_entry); 395 | 396 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 397 | err = fscore_readdir(inode, dir_entry); 398 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 399 | return err; 400 | } 401 | EXPORT_SYMBOL(fsapi_readdir); 402 | 403 | /* remove a directory */ 404 | s32 fsapi_rmdir(struct inode *inode, FILE_ID_T *fid) 405 | { 406 | s32 err; 407 | struct super_block *sb = inode->i_sb; 408 | 409 | /* check the validity of pointer parameters */ 410 | ASSERT(fid); 411 | 412 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 413 | err = fscore_rmdir(inode, fid); 414 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 415 | return err; 416 | } 417 | EXPORT_SYMBOL(fsapi_rmdir); 418 | 419 | /* unlink a file. 420 | * that is, remove an entry from a directory. BUT don't truncate 421 | */ 422 | s32 fsapi_unlink(struct inode *inode, FILE_ID_T *fid) 423 | { 424 | s32 err; 425 | struct super_block *sb = inode->i_sb; 426 | 427 | /* check the validity of pointer parameters */ 428 | ASSERT(fid); 429 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 430 | err = fscore_unlink(inode, fid); 431 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 432 | return err; 433 | } 434 | EXPORT_SYMBOL(fsapi_unlink); 435 | 436 | /* reflect the internal dirty flags to VFS bh dirty flags */ 437 | s32 fsapi_cache_flush(struct super_block *sb, int do_sync) 438 | { 439 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 440 | fcache_flush(sb, do_sync); 441 | dcache_flush(sb, do_sync); 442 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 443 | return 0; 444 | } 445 | EXPORT_SYMBOL(fsapi_cache_flush); 446 | 447 | /* release FAT & buf cache */ 448 | s32 fsapi_cache_release(struct super_block *sb) 449 | { 450 | #ifdef CONFIG_SDFAT_DEBUG 451 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 452 | 453 | fcache_release_all(sb); 454 | dcache_release_all(sb); 455 | 456 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 457 | #endif /* CONFIG_SDFAT_DEBUG */ 458 | return 0; 459 | } 460 | EXPORT_SYMBOL(fsapi_cache_release); 461 | 462 | u32 fsapi_get_au_stat(struct super_block *sb, s32 mode) 463 | { 464 | /* volume lock is not required */ 465 | return fscore_get_au_stat(sb, mode); 466 | } 467 | EXPORT_SYMBOL(fsapi_get_au_stat); 468 | 469 | /* clear extent cache */ 470 | void fsapi_invalidate_extent(struct inode *inode) 471 | { 472 | /* Volume lock is not required, 473 | * because it is only called by evict_inode. 474 | * If any other function can call it, 475 | * you should check whether volume lock is needed or not. 476 | */ 477 | extent_cache_inval_inode(inode); 478 | } 479 | EXPORT_SYMBOL(fsapi_invalidate_extent); 480 | 481 | /* check device is ejected */ 482 | s32 fsapi_check_bdi_valid(struct super_block *sb) 483 | { 484 | return fscore_check_bdi_valid(sb); 485 | } 486 | EXPORT_SYMBOL(fsapi_check_bdi_valid); 487 | 488 | 489 | 490 | #ifdef CONFIG_SDFAT_DFR 491 | /*----------------------------------------------------------------------*/ 492 | /* Defragmentation related */ 493 | /*----------------------------------------------------------------------*/ 494 | s32 fsapi_dfr_get_info(struct super_block *sb, void *arg) 495 | { 496 | /* volume lock is not required */ 497 | return defrag_get_info(sb, (struct defrag_info_arg *)arg); 498 | } 499 | EXPORT_SYMBOL(fsapi_dfr_get_info); 500 | 501 | s32 fsapi_dfr_scan_dir(struct super_block *sb, void *args) 502 | { 503 | s32 err; 504 | 505 | /* check the validity of pointer parameters */ 506 | ASSERT(args); 507 | 508 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 509 | err = defrag_scan_dir(sb, (struct defrag_trav_arg *)args); 510 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 511 | return err; 512 | } 513 | EXPORT_SYMBOL(fsapi_dfr_scan_dir); 514 | 515 | s32 fsapi_dfr_validate_clus(struct inode *inode, void *chunk, int skip_prev) 516 | { 517 | s32 err; 518 | struct super_block *sb = inode->i_sb; 519 | 520 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 521 | err = defrag_validate_cluster(inode, 522 | (struct defrag_chunk_info *)chunk, skip_prev); 523 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 524 | return err; 525 | } 526 | EXPORT_SYMBOL(fsapi_dfr_validate_clus); 527 | 528 | s32 fsapi_dfr_reserve_clus(struct super_block *sb, s32 nr_clus) 529 | { 530 | s32 err; 531 | 532 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 533 | err = defrag_reserve_clusters(sb, nr_clus); 534 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 535 | return err; 536 | } 537 | EXPORT_SYMBOL(fsapi_dfr_reserve_clus); 538 | 539 | s32 fsapi_dfr_mark_ignore(struct super_block *sb, unsigned int clus) 540 | { 541 | /* volume lock is not required */ 542 | return defrag_mark_ignore(sb, clus); 543 | } 544 | EXPORT_SYMBOL(fsapi_dfr_mark_ignore); 545 | 546 | void fsapi_dfr_unmark_ignore_all(struct super_block *sb) 547 | { 548 | /* volume lock is not required */ 549 | defrag_unmark_ignore_all(sb); 550 | } 551 | EXPORT_SYMBOL(fsapi_dfr_unmark_ignore_all); 552 | 553 | s32 fsapi_dfr_map_clus(struct inode *inode, u32 clu_offset, u32 *clu) 554 | { 555 | s32 err; 556 | struct super_block *sb = inode->i_sb; 557 | 558 | /* check the validity of pointer parameters */ 559 | ASSERT(clu); 560 | 561 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 562 | err = defrag_map_cluster(inode, clu_offset, clu); 563 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 564 | 565 | return err; 566 | } 567 | EXPORT_SYMBOL(fsapi_dfr_map_clus); 568 | 569 | void fsapi_dfr_writepage_endio(struct page *page) 570 | { 571 | /* volume lock is not required */ 572 | defrag_writepage_end_io(page); 573 | } 574 | EXPORT_SYMBOL(fsapi_dfr_writepage_endio); 575 | 576 | void fsapi_dfr_update_fat_prev(struct super_block *sb, int force) 577 | { 578 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 579 | defrag_update_fat_prev(sb, force); 580 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 581 | } 582 | EXPORT_SYMBOL(fsapi_dfr_update_fat_prev); 583 | 584 | void fsapi_dfr_update_fat_next(struct super_block *sb) 585 | { 586 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 587 | defrag_update_fat_next(sb); 588 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 589 | } 590 | EXPORT_SYMBOL(fsapi_dfr_update_fat_next); 591 | 592 | void fsapi_dfr_check_discard(struct super_block *sb) 593 | { 594 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 595 | defrag_check_discard(sb); 596 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 597 | } 598 | EXPORT_SYMBOL(fsapi_dfr_check_discard); 599 | 600 | void fsapi_dfr_free_clus(struct super_block *sb, u32 clus) 601 | { 602 | mutex_lock(&(SDFAT_SB(sb)->s_vlock)); 603 | defrag_free_cluster(sb, clus); 604 | mutex_unlock(&(SDFAT_SB(sb)->s_vlock)); 605 | } 606 | EXPORT_SYMBOL(fsapi_dfr_free_clus); 607 | 608 | s32 fsapi_dfr_check_dfr_required(struct super_block *sb, int *totalau, int *cleanau, int *fullau) 609 | { 610 | /* volume lock is not required */ 611 | return defrag_check_defrag_required(sb, totalau, cleanau, fullau); 612 | } 613 | EXPORT_SYMBOL(fsapi_dfr_check_dfr_required); 614 | 615 | s32 fsapi_dfr_check_dfr_on(struct inode *inode, loff_t start, loff_t end, s32 cancel, const char *caller) 616 | { 617 | /* volume lock is not required */ 618 | return defrag_check_defrag_on(inode, start, end, cancel, caller); 619 | } 620 | EXPORT_SYMBOL(fsapi_dfr_check_dfr_on); 621 | 622 | 623 | 624 | #ifdef CONFIG_SDFAT_DFR_DEBUG 625 | void fsapi_dfr_spo_test(struct super_block *sb, int flag, const char *caller) 626 | { 627 | /* volume lock is not required */ 628 | defrag_spo_test(sb, flag, caller); 629 | } 630 | EXPORT_SYMBOL(fsapi_dfr_spo_test); 631 | #endif 632 | 633 | 634 | #endif /* CONFIG_SDFAT_DFR */ 635 | 636 | /* end of sdfat_api.c */ 637 | -------------------------------------------------------------------------------- /api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | #ifndef _SDFAT_API_H 19 | #define _SDFAT_API_H 20 | 21 | #include "config.h" 22 | #include "sdfat_fs.h" 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif /* __cplusplus */ 27 | 28 | 29 | /*----------------------------------------------------------------------*/ 30 | /* Configure Constant & Macro Definitions */ 31 | /*----------------------------------------------------------------------*/ 32 | /* cache size (in number of sectors) */ 33 | /* (should be an exponential value of 2) */ 34 | #define FAT_CACHE_SIZE 128 35 | #define FAT_CACHE_HASH_SIZE 64 36 | #define BUF_CACHE_SIZE 256 37 | #define BUF_CACHE_HASH_SIZE 64 38 | 39 | /* Read-ahead related */ 40 | /* First config vars. should be pow of 2 */ 41 | #define FCACHE_MAX_RA_SIZE (PAGE_SIZE) 42 | #define DCACHE_MAX_RA_SIZE (128*1024) 43 | 44 | /*----------------------------------------------------------------------*/ 45 | /* Constant & Macro Definitions */ 46 | /*----------------------------------------------------------------------*/ 47 | /* type values */ 48 | #define TYPE_UNUSED 0x0000 49 | #define TYPE_DELETED 0x0001 50 | #define TYPE_INVALID 0x0002 51 | #define TYPE_CRITICAL_PRI 0x0100 52 | #define TYPE_BITMAP 0x0101 53 | #define TYPE_UPCASE 0x0102 54 | #define TYPE_VOLUME 0x0103 55 | #define TYPE_DIR 0x0104 56 | #define TYPE_FILE 0x011F 57 | #define TYPE_SYMLINK 0x015F 58 | #define TYPE_CRITICAL_SEC 0x0200 59 | #define TYPE_STREAM 0x0201 60 | #define TYPE_EXTEND 0x0202 61 | #define TYPE_ACL 0x0203 62 | #define TYPE_BENIGN_PRI 0x0400 63 | #define TYPE_GUID 0x0401 64 | #define TYPE_PADDING 0x0402 65 | #define TYPE_ACLTAB 0x0403 66 | #define TYPE_BENIGN_SEC 0x0800 67 | #define TYPE_ALL 0x0FFF 68 | 69 | /* eio values */ 70 | #define SDFAT_EIO_NONE (0x00000000) 71 | #define SDFAT_EIO_READ (0x00000001) 72 | #define SDFAT_EIO_WRITE (0x00000002) 73 | #define SDFAT_EIO_BDI (0x00000004) 74 | 75 | /* modes for volume allocation unit status */ 76 | #define VOL_AU_STAT_TOTAL (0) 77 | #define VOL_AU_STAT_CLEAN (1) 78 | #define VOL_AU_STAT_FULL (2) 79 | 80 | /*----------------------------------------------------------------------*/ 81 | /* NLS Type Definitions */ 82 | /*----------------------------------------------------------------------*/ 83 | 84 | /* DOS name structure */ 85 | typedef struct { 86 | u8 name[DOS_NAME_LENGTH]; 87 | u8 name_case; 88 | } DOS_NAME_T; 89 | 90 | /* unicode name structure */ 91 | typedef struct { 92 | u16 name[MAX_NAME_LENGTH+3]; /* +3 for null and for converting */ 93 | u16 name_hash; 94 | u8 name_len; 95 | } UNI_NAME_T; 96 | 97 | /*----------------------------------------------------------------------*/ 98 | /* Type Definitions */ 99 | /*----------------------------------------------------------------------*/ 100 | /* should be merged it to DATE_TIME_T */ 101 | typedef union { 102 | struct { 103 | u8 off : 7; 104 | u8 valid : 1; 105 | }; 106 | u8 value; 107 | } TIMEZONE_T; 108 | 109 | typedef struct { 110 | u16 sec; /* 0 ~ 59 */ 111 | u16 min; /* 0 ~ 59 */ 112 | u16 hour; /* 0 ~ 23 */ 113 | u16 day; /* 1 ~ 31 */ 114 | u16 mon; /* 1 ~ 12 */ 115 | u16 year; /* 0 ~ 127 (since 1980) */ 116 | TIMEZONE_T tz; 117 | } TIMESTAMP_T; 118 | 119 | typedef struct { 120 | u16 Year; 121 | u16 Month; 122 | u16 Day; 123 | u16 Hour; 124 | u16 Minute; 125 | u16 Second; 126 | u16 MilliSecond; 127 | TIMEZONE_T Timezone; 128 | } DATE_TIME_T; 129 | 130 | typedef struct { 131 | u64 Offset; // start sector number of the partition 132 | u64 Size; // in sectors 133 | } PART_INFO_T; 134 | 135 | typedef struct { 136 | u32 SecSize; // sector size in bytes 137 | u64 DevSize; // block device size in sectors 138 | } DEV_INFO_T; 139 | 140 | typedef struct { 141 | u32 FatType; 142 | u32 ClusterSize; 143 | u32 NumClusters; 144 | u32 FreeClusters; 145 | u32 UsedClusters; 146 | } VOL_INFO_T; 147 | 148 | /* directory structure */ 149 | typedef struct { 150 | u32 dir; 151 | u32 size; 152 | u8 flags; 153 | } CHAIN_T; 154 | 155 | /* hint structure */ 156 | typedef struct { 157 | u32 clu; 158 | union { 159 | u32 off; // cluster offset 160 | s32 eidx; // entry index 161 | }; 162 | } HINT_T; 163 | 164 | typedef struct { 165 | spinlock_t cache_lru_lock; 166 | struct list_head cache_lru; 167 | s32 nr_caches; 168 | u32 cache_valid_id; // for avoiding the race between alloc and free 169 | } EXTENT_T; 170 | 171 | /* first empty entry hint information */ 172 | typedef struct { 173 | s32 eidx; // entry index of a directory 174 | s32 count; // count of continuous empty entry 175 | CHAIN_T cur; // the cluster that first empty slot exists in 176 | } HINT_FEMP_T; 177 | 178 | /* file id structure */ 179 | typedef struct { 180 | CHAIN_T dir; 181 | s32 entry; 182 | u32 type; 183 | u32 attr; 184 | u32 start_clu; 185 | u64 size; 186 | u8 flags; 187 | u8 reserved[3]; // padding 188 | u32 version; // the copy of low 32bit of i_version to check the validation of hint_stat 189 | s64 rwoffset; // file offset or dentry index for readdir 190 | EXTENT_T extent; // extent cache for a file 191 | HINT_T hint_bmap; // hint for cluster last accessed 192 | HINT_T hint_stat; // hint for entry index we try to lookup next time 193 | HINT_FEMP_T hint_femp; // hint for first empty entry 194 | } FILE_ID_T; 195 | 196 | typedef struct { 197 | s8 *lfn; 198 | s8 *sfn; 199 | s32 lfnbuf_len; //usally MAX_UNINAME_BUF_SIZE 200 | s32 sfnbuf_len; //usally MAX_DOSNAME_BUF_SIZE, used only for vfat, not for exfat 201 | } DENTRY_NAMEBUF_T; 202 | 203 | typedef struct { 204 | u32 Attr; 205 | u64 Size; 206 | u32 NumSubdirs; 207 | DATE_TIME_T CreateTimestamp; 208 | DATE_TIME_T ModifyTimestamp; 209 | DATE_TIME_T AccessTimestamp; 210 | DENTRY_NAMEBUF_T NameBuf; 211 | } DIR_ENTRY_T; 212 | 213 | /* cache information */ 214 | typedef struct __cache_entry { 215 | struct __cache_entry *next; 216 | struct __cache_entry *prev; 217 | struct { 218 | struct __cache_entry *next; 219 | struct __cache_entry *prev; 220 | } hash; 221 | u64 sec; 222 | u32 flag; 223 | struct buffer_head *bh; 224 | } cache_ent_t; 225 | 226 | /*----------------------------------------------------------------------*/ 227 | /* Type Definitions : Wrapper & In-Core */ 228 | /*----------------------------------------------------------------------*/ 229 | typedef struct __FATENT_OPS_T { 230 | s32 (*ent_get)(struct super_block *sb, u32 loc, u32 *content); 231 | s32 (*ent_set)(struct super_block *sb, u32 loc, u32 content); 232 | } FATENT_OPS_T; 233 | 234 | typedef struct { 235 | s32 (*alloc_cluster)(struct super_block *, u32, CHAIN_T *, s32); 236 | s32 (*free_cluster)(struct super_block *, CHAIN_T *, s32); 237 | s32 (*count_used_clusters)(struct super_block *, u32 *); 238 | s32 (*init_dir_entry)(struct super_block *, CHAIN_T *, s32, u32, u32, u64); 239 | s32 (*init_ext_entry)(struct super_block *, CHAIN_T *, s32, s32, UNI_NAME_T *, DOS_NAME_T *); 240 | s32 (*find_dir_entry)(struct super_block *, FILE_ID_T *, CHAIN_T *, UNI_NAME_T *, s32, DOS_NAME_T *, u32); 241 | s32 (*delete_dir_entry)(struct super_block *, CHAIN_T *, s32, s32, s32); 242 | void (*get_uniname_from_ext_entry)(struct super_block *, CHAIN_T *, s32, u16 *); 243 | s32 (*count_ext_entries)(struct super_block *, CHAIN_T *, s32, DENTRY_T *); 244 | s32 (*calc_num_entries)(UNI_NAME_T *); 245 | s32 (*check_max_dentries)(FILE_ID_T *); 246 | u32 (*get_entry_type)(DENTRY_T *); 247 | void (*set_entry_type)(DENTRY_T *, u32); 248 | u32 (*get_entry_attr)(DENTRY_T *); 249 | void (*set_entry_attr)(DENTRY_T *, u32); 250 | u8 (*get_entry_flag)(DENTRY_T *); 251 | void (*set_entry_flag)(DENTRY_T *, u8); 252 | u32 (*get_entry_clu0)(DENTRY_T *); 253 | void (*set_entry_clu0)(DENTRY_T *, u32); 254 | u64 (*get_entry_size)(DENTRY_T *); 255 | void (*set_entry_size)(DENTRY_T *, u64); 256 | void (*get_entry_time)(DENTRY_T *, TIMESTAMP_T *, u8); 257 | void (*set_entry_time)(DENTRY_T *, TIMESTAMP_T *, u8); 258 | u32 (*get_au_stat)(struct super_block *, s32); 259 | } FS_FUNC_T; 260 | 261 | typedef struct __FS_INFO_T { 262 | s32 bd_opened; // opened or not 263 | u32 vol_type; // volume FAT type 264 | u32 vol_id; // volume serial number 265 | u64 num_sectors; // num of sectors in volume 266 | u32 num_clusters; // num of clusters in volume 267 | u32 cluster_size; // cluster size in bytes 268 | u32 cluster_size_bits; 269 | u32 sect_per_clus; // cluster size in sectors 270 | u32 sect_per_clus_bits; 271 | u64 FAT1_start_sector; // FAT1 start sector 272 | u64 FAT2_start_sector; // FAT2 start sector 273 | u64 root_start_sector; // root dir start sector 274 | u64 data_start_sector; // data area start sector 275 | u32 num_FAT_sectors; // num of FAT sectors 276 | u32 root_dir; // root dir cluster 277 | u32 dentries_in_root; // num of dentries in root dir 278 | u32 dentries_per_clu; // num of dentries per cluster 279 | u32 vol_flag; // volume dirty flag 280 | struct buffer_head *pbr_bh; // buffer_head of PBR sector 281 | 282 | u32 map_clu; // allocation bitmap start cluster 283 | u32 map_sectors; // num of allocation bitmap sectors 284 | struct buffer_head **vol_amap; // allocation bitmap 285 | 286 | u16 **vol_utbl; // upcase table 287 | 288 | u32 clu_srch_ptr; // cluster search pointer 289 | u32 used_clusters; // number of used clusters 290 | 291 | u32 prev_eio; // block device operation error flag 292 | 293 | FS_FUNC_T *fs_func; 294 | FATENT_OPS_T *fatent_ops; 295 | 296 | s32 reserved_clusters; // # of reserved clusters (DA) 297 | void *amap; // AU Allocation Map 298 | 299 | /* fat cache */ 300 | struct { 301 | cache_ent_t pool[FAT_CACHE_SIZE]; 302 | cache_ent_t lru_list; 303 | cache_ent_t hash_list[FAT_CACHE_HASH_SIZE]; 304 | } fcache; 305 | 306 | /* meta cache */ 307 | struct { 308 | cache_ent_t pool[BUF_CACHE_SIZE]; 309 | cache_ent_t lru_list; 310 | cache_ent_t keep_list; // CACHEs in this list will not be kicked by normal lru operations 311 | cache_ent_t hash_list[BUF_CACHE_HASH_SIZE]; 312 | } dcache; 313 | } FS_INFO_T; 314 | 315 | /*======================================================================*/ 316 | /* */ 317 | /* API FUNCTION DECLARATIONS */ 318 | /* (CHANGE THIS PART IF REQUIRED) */ 319 | /* */ 320 | /*======================================================================*/ 321 | 322 | /*----------------------------------------------------------------------*/ 323 | /* External Function Declarations */ 324 | /*----------------------------------------------------------------------*/ 325 | 326 | /* file system initialization & shutdown functions */ 327 | s32 fsapi_init(void); 328 | s32 fsapi_shutdown(void); 329 | 330 | /* volume management functions */ 331 | s32 fsapi_mount(struct super_block *sb); 332 | s32 fsapi_umount(struct super_block *sb); 333 | s32 fsapi_statfs(struct super_block *sb, VOL_INFO_T *info); 334 | s32 fsapi_sync_fs(struct super_block *sb, s32 do_sync); 335 | s32 fsapi_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_sync); 336 | 337 | /* file management functions */ 338 | s32 fsapi_lookup(struct inode *inode, u8 *path, FILE_ID_T *fid); 339 | s32 fsapi_create(struct inode *inode, u8 *path, u8 mode, FILE_ID_T *fid); 340 | s32 fsapi_read_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); 341 | s32 fsapi_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); 342 | s32 fsapi_remove(struct inode *inode, FILE_ID_T *fid); /* unlink and truncate */ 343 | s32 fsapi_truncate(struct inode *inode, u64 old_size, u64 new_size); 344 | s32 fsapi_rename(struct inode *old_parent_inode, FILE_ID_T *fid, 345 | struct inode *new_parent_inode, struct dentry *new_dentry); 346 | s32 fsapi_unlink(struct inode *inode, FILE_ID_T *fid); 347 | s32 fsapi_read_inode(struct inode *inode, DIR_ENTRY_T *info); 348 | s32 fsapi_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync); 349 | s32 fsapi_map_clus(struct inode *inode, u32 clu_offset, u32 *clu, int dest); 350 | s32 fsapi_reserve_clus(struct inode *inode); 351 | 352 | /* directory management functions */ 353 | s32 fsapi_mkdir(struct inode *inode, u8 *path, FILE_ID_T *fid); 354 | s32 fsapi_readdir(struct inode *inode, DIR_ENTRY_T *dir_entry); 355 | s32 fsapi_rmdir(struct inode *inode, FILE_ID_T *fid); 356 | 357 | /* FAT & buf cache functions */ 358 | s32 fsapi_cache_flush(struct super_block *sb, int do_sync); 359 | s32 fsapi_cache_release(struct super_block *sb); 360 | 361 | /* extra info functions */ 362 | u32 fsapi_get_au_stat(struct super_block *sb, s32 mode); 363 | 364 | /* extent cache functions */ 365 | void fsapi_invalidate_extent(struct inode *inode); 366 | 367 | /* bdev management */ 368 | s32 fsapi_check_bdi_valid(struct super_block *sb); 369 | 370 | #ifdef CONFIG_SDFAT_DFR 371 | /*----------------------------------------------------------------------*/ 372 | /* Defragmentation related */ 373 | /*----------------------------------------------------------------------*/ 374 | 375 | s32 fsapi_dfr_get_info(struct super_block *sb, void *arg); 376 | 377 | s32 fsapi_dfr_scan_dir(struct super_block *sb, void *args); 378 | 379 | s32 fsapi_dfr_validate_clus(struct inode *inode, void *chunk, int skip_prev); 380 | s32 fsapi_dfr_reserve_clus(struct super_block *sb, s32 nr_clus); 381 | s32 fsapi_dfr_mark_ignore(struct super_block *sb, unsigned int clus); 382 | void fsapi_dfr_unmark_ignore_all(struct super_block *sb); 383 | 384 | s32 fsapi_dfr_map_clus(struct inode *inode, u32 clu_offset, u32 *clu); 385 | void fsapi_dfr_writepage_endio(struct page *page); 386 | 387 | void fsapi_dfr_update_fat_prev(struct super_block *sb, int force); 388 | void fsapi_dfr_update_fat_next(struct super_block *sb); 389 | void fsapi_dfr_check_discard(struct super_block *sb); 390 | void fsapi_dfr_free_clus(struct super_block *sb, u32 clus); 391 | 392 | s32 fsapi_dfr_check_dfr_required(struct super_block *sb, int *totalau, int *cleanau, int *fullau); 393 | s32 fsapi_dfr_check_dfr_on(struct inode *inode, loff_t start, loff_t end, s32 cancel, const char *caller); 394 | 395 | 396 | #ifdef CONFIG_SDFAT_DFR_DEBUG 397 | void fsapi_dfr_spo_test(struct super_block *sb, int flag, const char *caller); 398 | #endif /* CONFIG_SDFAT_DFR_DEBUG */ 399 | 400 | #endif /* CONFIG_SDFAT_DFR */ 401 | 402 | 403 | #ifdef __cplusplus 404 | } 405 | #endif /* __cplusplus */ 406 | 407 | #endif /* _SDFAT_API_H */ 408 | 409 | /* end of api.h */ 410 | -------------------------------------------------------------------------------- /blkdev.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | /************************************************************************/ 19 | /* */ 20 | /* PROJECT : exFAT & FAT12/16/32 File System */ 21 | /* FILE : blkdev.c */ 22 | /* PURPOSE : sdFAT Block Device Driver Glue Layer */ 23 | /* */ 24 | /*----------------------------------------------------------------------*/ 25 | /* NOTES */ 26 | /* */ 27 | /************************************************************************/ 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "sdfat.h" 34 | 35 | /*----------------------------------------------------------------------*/ 36 | /* Constant & Macro Definitions */ 37 | /*----------------------------------------------------------------------*/ 38 | 39 | /*----------------------------------------------------------------------*/ 40 | /* Global Variable Definitions */ 41 | /*----------------------------------------------------------------------*/ 42 | 43 | /*----------------------------------------------------------------------*/ 44 | /* Local Variable Definitions */ 45 | /*----------------------------------------------------------------------*/ 46 | 47 | /*----------------------------------------------------------------------*/ 48 | /* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY */ 49 | /************************************************************************/ 50 | 51 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) 52 | /* EMPTY */ 53 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) */ 54 | static struct backing_dev_info *inode_to_bdi(struct inode *bd_inode) 55 | { 56 | return bd_inode->i_mapping->backing_dev_info; 57 | } 58 | #endif 59 | 60 | /*======================================================================*/ 61 | /* Function Definitions */ 62 | /*======================================================================*/ 63 | s32 bdev_open_dev(struct super_block *sb) 64 | { 65 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 66 | 67 | if (fsi->bd_opened) 68 | return 0; 69 | 70 | fsi->bd_opened = true; 71 | return 0; 72 | } 73 | 74 | s32 bdev_close_dev(struct super_block *sb) 75 | { 76 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 77 | 78 | fsi->bd_opened = false; 79 | return 0; 80 | } 81 | 82 | static inline s32 block_device_ejected(struct super_block *sb) 83 | { 84 | struct inode *bd_inode = sb->s_bdev->bd_inode; 85 | struct backing_dev_info *bdi = inode_to_bdi(bd_inode); 86 | 87 | return (bdi->dev == NULL); 88 | } 89 | 90 | s32 bdev_check_bdi_valid(struct super_block *sb) 91 | { 92 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 93 | 94 | if (block_device_ejected(sb)) { 95 | if (!(fsi->prev_eio & SDFAT_EIO_BDI)) { 96 | fsi->prev_eio |= SDFAT_EIO_BDI; 97 | sdfat_log_msg(sb, KERN_ERR, "%s: block device is " 98 | "eliminated.(bdi:%p)", __func__, sb->s_bdi); 99 | } 100 | return -ENXIO; 101 | } 102 | 103 | return 0; 104 | } 105 | 106 | #if IS_BUILTIN(CONFIG_SDFAT_FS) 107 | static void __bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) 108 | { 109 | u32 sects_per_page = (PAGE_SIZE >> sb->s_blocksize_bits); 110 | struct blk_plug plug; 111 | u64 i; 112 | 113 | blk_start_plug(&plug); 114 | for (i = 0; i < num_secs; i++) { 115 | if (i && !(i & (sects_per_page - 1))) 116 | blk_flush_plug(current); 117 | sb_breadahead(sb, (sector_t)(secno + i)); 118 | } 119 | blk_finish_plug(&plug); 120 | } 121 | #else 122 | static void __bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) 123 | { 124 | u64 i; 125 | 126 | for (i = 0; i < num_secs; i++) 127 | sb_breadahead(sb, (sector_t)(secno + i)); 128 | } 129 | #endif 130 | 131 | /* Make a readahead request */ 132 | s32 bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs) 133 | { 134 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 135 | 136 | if (!fsi->bd_opened) 137 | return -EIO; 138 | 139 | __bdev_readahead(sb, secno, num_secs); 140 | 141 | return 0; 142 | } 143 | 144 | s32 bdev_mread(struct super_block *sb, u64 secno, struct buffer_head **bh, u64 num_secs, s32 read) 145 | { 146 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 147 | u8 blksize_bits = sb->s_blocksize_bits; 148 | #ifdef CONFIG_SDFAT_DBG_IOCTL 149 | struct sdfat_sb_info *sbi = SDFAT_SB(sb); 150 | long flags = sbi->debug_flags; 151 | 152 | if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) 153 | return -EIO; 154 | #endif /* CONFIG_SDFAT_DBG_IOCTL */ 155 | 156 | if (!fsi->bd_opened) 157 | return -EIO; 158 | 159 | brelse(*bh); 160 | 161 | if (read) 162 | *bh = __bread(sb->s_bdev, (sector_t)secno, num_secs << blksize_bits); 163 | else 164 | *bh = __getblk(sb->s_bdev, (sector_t)secno, num_secs << blksize_bits); 165 | 166 | /* read successfully */ 167 | if (*bh) 168 | return 0; 169 | 170 | /* 171 | * patch 1.2.4 : reset ONCE warning message per volume. 172 | */ 173 | if (!(fsi->prev_eio & SDFAT_EIO_READ)) { 174 | fsi->prev_eio |= SDFAT_EIO_READ; 175 | sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); 176 | sdfat_debug_warn_on(1); 177 | } 178 | 179 | return -EIO; 180 | } 181 | 182 | s32 bdev_mwrite(struct super_block *sb, u64 secno, struct buffer_head *bh, u64 num_secs, s32 sync) 183 | { 184 | u64 count; 185 | struct buffer_head *bh2; 186 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 187 | #ifdef CONFIG_SDFAT_DBG_IOCTL 188 | struct sdfat_sb_info *sbi = SDFAT_SB(sb); 189 | long flags = sbi->debug_flags; 190 | 191 | if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) 192 | return -EIO; 193 | #endif /* CONFIG_SDFAT_DBG_IOCTL */ 194 | 195 | if (!fsi->bd_opened) 196 | return -EIO; 197 | 198 | if (secno == bh->b_blocknr) { 199 | set_buffer_uptodate(bh); 200 | mark_buffer_dirty(bh); 201 | if (sync && (sync_dirty_buffer(bh) != 0)) 202 | return -EIO; 203 | } else { 204 | count = num_secs << sb->s_blocksize_bits; 205 | 206 | bh2 = __getblk(sb->s_bdev, (sector_t)secno, count); 207 | 208 | if (!bh2) 209 | goto no_bh; 210 | 211 | lock_buffer(bh2); 212 | memcpy(bh2->b_data, bh->b_data, count); 213 | set_buffer_uptodate(bh2); 214 | mark_buffer_dirty(bh2); 215 | unlock_buffer(bh2); 216 | if (sync && (sync_dirty_buffer(bh2) != 0)) { 217 | __brelse(bh2); 218 | goto no_bh; 219 | } 220 | __brelse(bh2); 221 | } 222 | return 0; 223 | no_bh: 224 | /* 225 | * patch 1.2.4 : reset ONCE warning message per volume. 226 | */ 227 | if (!(fsi->prev_eio & SDFAT_EIO_WRITE)) { 228 | fsi->prev_eio |= SDFAT_EIO_WRITE; 229 | sdfat_log_msg(sb, KERN_ERR, "%s: No bh. I/O error.", __func__); 230 | sdfat_debug_warn_on(1); 231 | } 232 | 233 | return -EIO; 234 | } 235 | 236 | s32 bdev_sync_all(struct super_block *sb) 237 | { 238 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 239 | #ifdef CONFIG_SDFAT_DBG_IOCTL 240 | struct sdfat_sb_info *sbi = SDFAT_SB(sb); 241 | long flags = sbi->debug_flags; 242 | 243 | if (flags & SDFAT_DEBUGFLAGS_ERROR_RW) 244 | return -EIO; 245 | #endif /* CONFIG_SDFAT_DBG_IOCTL */ 246 | 247 | if (!fsi->bd_opened) 248 | return -EIO; 249 | 250 | return sync_blockdev(sb->s_bdev); 251 | } 252 | 253 | /* 254 | * Sector Read/Write Functions 255 | */ 256 | s32 read_sect(struct super_block *sb, u64 sec, struct buffer_head **bh, s32 read) 257 | { 258 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 259 | 260 | BUG_ON(!bh); 261 | if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) { 262 | sdfat_fs_error_ratelimit(sb, 263 | "%s: out of range (sect:%llu)", __func__, sec); 264 | return -EIO; 265 | } 266 | 267 | if (bdev_mread(sb, sec, bh, 1, read)) { 268 | sdfat_fs_error_ratelimit(sb, 269 | "%s: I/O error (sect:%llu)", __func__, sec); 270 | return -EIO; 271 | } 272 | 273 | return 0; 274 | } 275 | 276 | s32 write_sect(struct super_block *sb, u64 sec, struct buffer_head *bh, s32 sync) 277 | { 278 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 279 | 280 | BUG_ON(!bh); 281 | if ((sec >= fsi->num_sectors) && (fsi->num_sectors > 0)) { 282 | sdfat_fs_error_ratelimit(sb, 283 | "%s: out of range (sect:%llu)", __func__, sec); 284 | return -EIO; 285 | } 286 | 287 | if (bdev_mwrite(sb, sec, bh, 1, sync)) { 288 | sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%llu)", 289 | __func__, sec); 290 | return -EIO; 291 | } 292 | 293 | return 0; 294 | } 295 | 296 | s32 read_msect(struct super_block *sb, u64 sec, struct buffer_head **bh, u64 num_secs, s32 read) 297 | { 298 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 299 | 300 | BUG_ON(!bh); 301 | if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) { 302 | sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%llu len:%llu)", 303 | __func__, sec, num_secs); 304 | return -EIO; 305 | } 306 | 307 | if (bdev_mread(sb, sec, bh, num_secs, read)) { 308 | sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%llu len:%llu)", 309 | __func__, sec, num_secs); 310 | return -EIO; 311 | } 312 | 313 | return 0; 314 | } 315 | 316 | s32 write_msect(struct super_block *sb, u64 sec, struct buffer_head *bh, u64 num_secs, s32 sync) 317 | { 318 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 319 | 320 | BUG_ON(!bh); 321 | if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) { 322 | sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%llu len:%llu)", 323 | __func__, sec, num_secs); 324 | return -EIO; 325 | } 326 | 327 | 328 | if (bdev_mwrite(sb, sec, bh, num_secs, sync)) { 329 | sdfat_fs_error_ratelimit(sb, "%s: I/O error (sect:%llu len:%llu)", 330 | __func__, sec, num_secs); 331 | return -EIO; 332 | } 333 | 334 | return 0; 335 | } 336 | 337 | static inline void __blkdev_write_bhs(struct buffer_head **bhs, s32 nr_bhs) 338 | { 339 | s32 i; 340 | 341 | for (i = 0; i < nr_bhs; i++) 342 | write_dirty_buffer(bhs[i], WRITE); 343 | } 344 | 345 | static inline s32 __blkdev_sync_bhs(struct buffer_head **bhs, s32 nr_bhs) 346 | { 347 | s32 i, err = 0; 348 | 349 | for (i = 0; i < nr_bhs; i++) { 350 | wait_on_buffer(bhs[i]); 351 | if (!err && !buffer_uptodate(bhs[i])) 352 | err = -EIO; 353 | } 354 | return err; 355 | } 356 | 357 | static inline s32 __buffer_zeroed(struct super_block *sb, u64 blknr, u64 num_secs) 358 | { 359 | struct buffer_head *bhs[MAX_BUF_PER_PAGE]; 360 | s32 nr_bhs = MAX_BUF_PER_PAGE; 361 | u64 last_blknr = blknr + num_secs; 362 | s32 err, i, n; 363 | struct blk_plug plug; 364 | 365 | /* Zeroing the unused blocks on this cluster */ 366 | n = 0; 367 | blk_start_plug(&plug); 368 | while (blknr < last_blknr) { 369 | bhs[n] = sb_getblk(sb, (sector_t)blknr); 370 | if (!bhs[n]) { 371 | err = -ENOMEM; 372 | blk_finish_plug(&plug); 373 | goto error; 374 | } 375 | memset(bhs[n]->b_data, 0, sb->s_blocksize); 376 | set_buffer_uptodate(bhs[n]); 377 | mark_buffer_dirty(bhs[n]); 378 | 379 | n++; 380 | blknr++; 381 | 382 | if (blknr == last_blknr) 383 | break; 384 | 385 | if (n == nr_bhs) { 386 | __blkdev_write_bhs(bhs, n); 387 | 388 | for (i = 0; i < n; i++) 389 | brelse(bhs[i]); 390 | n = 0; 391 | } 392 | } 393 | __blkdev_write_bhs(bhs, n); 394 | blk_finish_plug(&plug); 395 | 396 | err = __blkdev_sync_bhs(bhs, n); 397 | if (err) 398 | goto error; 399 | 400 | for (i = 0; i < n; i++) 401 | brelse(bhs[i]); 402 | 403 | return 0; 404 | 405 | error: 406 | EMSG("%s: failed zeroed sect %llu\n", __func__, blknr); 407 | for (i = 0; i < n; i++) 408 | bforget(bhs[i]); 409 | 410 | return err; 411 | } 412 | 413 | s32 write_msect_zero(struct super_block *sb, u64 sec, u64 num_secs) 414 | { 415 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 416 | 417 | if (((sec+num_secs) > fsi->num_sectors) && (fsi->num_sectors > 0)) { 418 | sdfat_fs_error_ratelimit(sb, "%s: out of range(sect:%llu len:%llu)", 419 | __func__, sec, num_secs); 420 | return -EIO; 421 | } 422 | 423 | /* Just return -EAGAIN if it is failed */ 424 | if (__buffer_zeroed(sb, sec, num_secs)) 425 | return -EAGAIN; 426 | 427 | return 0; 428 | } /* end of write_msect_zero */ 429 | 430 | /* end of blkdev.c */ 431 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | #ifndef _SDFAT_CONFIG_H 19 | #define _SDFAT_CONFIG_H 20 | /*======================================================================*/ 21 | /* */ 22 | /* FFS CONFIGURATIONS */ 23 | /* (CHANGE THIS PART IF REQUIRED) */ 24 | /* */ 25 | /*======================================================================*/ 26 | 27 | /*----------------------------------------------------------------------*/ 28 | /* Feature Config */ 29 | /*----------------------------------------------------------------------*/ 30 | 31 | /*----------------------------------------------------------------------*/ 32 | /* Debug/Experimental Config */ 33 | /*----------------------------------------------------------------------*/ 34 | //#define CONFIG_SDFAT_TRACE_IO 35 | //#define CONFIG_SDFAT_TRACE_LOCK /* Trace elapsed time in lock_super(sb) */ 36 | 37 | /*----------------------------------------------------------------------*/ 38 | /* Defragmentation Config */ 39 | /*----------------------------------------------------------------------*/ 40 | //#define CONFIG_SDFAT_DFR 41 | //#define CONFIG_SDFAT_DFR_PACKING 42 | //#define CONFIG_SDFAT_DFR_DEBUG 43 | 44 | /*----------------------------------------------------------------------*/ 45 | /* Config for Kernel equal or newer than 3.7 */ 46 | /*----------------------------------------------------------------------*/ 47 | #ifndef CONFIG_SDFAT_WRITE_SB_INTERVAL_CSECS 48 | #define CONFIG_SDFAT_WRITE_SB_INTERVAL_CSECS (dirty_writeback_interval) 49 | #endif 50 | 51 | /*----------------------------------------------------------------------*/ 52 | /* Default Kconfig */ 53 | /*----------------------------------------------------------------------*/ 54 | /* default mount options */ 55 | #ifndef CONFIG_SDFAT_DEFAULT_CODEPAGE /* if Kconfig lacked codepage */ 56 | #define CONFIG_SDFAT_DEFAULT_CODEPAGE 437 57 | #endif 58 | 59 | #ifndef CONFIG_SDFAT_DEFAULT_IOCHARSET /* if Kconfig lacked iocharset */ 60 | #define CONFIG_SDFAT_DEFAULT_IOCHARSET "utf8" 61 | #endif 62 | 63 | #ifndef CONFIG_SDFAT_FAT32_SHORTNAME_SEQ /* Shortname ~1, ... ~9 have higher 64 | * priority (WIN32/VFAT-like) 65 | */ 66 | //#define CONFIG_SDFAT_FAT32_SHORTNAME_SEQ 67 | #endif 68 | 69 | #ifndef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE 70 | //#define CONFIG_SDFAT_ALIGNED_MPAGE_WRITE 71 | #endif 72 | 73 | #ifndef CONFIG_SDFAT_FAT_MIRRORING /* if Kconfig lacked fat-mirroring option */ 74 | #define CONFIG_SDFAT_FAT_MIRRORING /* Write FAT 1, FAT 2 simultaneously */ 75 | #endif 76 | 77 | #ifndef CONFIG_SDFAT_DELAYED_META_DIRTY 78 | //#define CONFIG_SDFAT_DELAYED_META_DIRTY /* delayed DIR/FAT dirty support */ 79 | #endif 80 | 81 | #ifndef CONFIG_SDFAT_SUPPORT_DIR_SYNC 82 | //#define CONFIG_SDFAT_SUPPORT_DIR_SYNC /* support DIR_SYNC */ 83 | #endif 84 | 85 | #ifndef CONFIG_SDFAT_CHECK_RO_ATTR 86 | //#define CONFIG_SDFAT_CHECK_RO_ATTR 87 | #endif 88 | 89 | #ifndef CONFIG_SDFAT_RESTRICT_EXT_ONLY_SFN 90 | #define CONFIG_SDFAT_RESTRICT_EXT_ONLY_SFN 91 | #endif 92 | 93 | #ifndef CONFIG_SDFAT_ALLOW_LOOKUP_LOSSY_SFN 94 | //#define CONFIG_SDFAT_ALLOW_LOOKUP_LOSSY_SFN 95 | #endif 96 | 97 | #ifndef CONFIG_SDFAT_DBG_SHOW_PID 98 | //#define CONFIG_SDFAT_DBG_SHOW_PID 99 | #endif 100 | 101 | #ifndef CONFIG_SDFAT_VIRTUAL_XATTR 102 | //#define CONFIG_SDFAT_VIRTUAL_XATTR 103 | #endif 104 | 105 | #ifndef CONFIG_SDFAT_SUPPORT_STLOG 106 | //#define CONFIG_SDFAT_SUPPORT_STLOG 107 | #endif 108 | 109 | #ifndef CONFIG_SDFAT_DEBUG 110 | //{ 111 | //#define CONFIG_SDFAT_DEBUG 112 | 113 | #ifndef CONFIG_SDFAT_DBG_IOCTL 114 | //#define CONFIG_SDFAT_DBG_IOCTL 115 | #endif 116 | 117 | #ifndef CONFIG_SDFAT_DBG_MSG 118 | //#define CONFIG_SDFAT_DBG_MSG 119 | #endif 120 | 121 | #ifndef CONFIG_SDFAT_DBG_CAREFUL 122 | //#define CONFIG_SDFAT_DBG_CAREFUL 123 | #endif 124 | 125 | #ifndef CONFIG_SDFAT_DBG_BUGON 126 | //#define CONFIG_SDFAT_DBG_BUGON 127 | #endif 128 | 129 | #ifndef CONFIG_SDFAT_DBG_WARNON 130 | //#define CONFIG_SDFAT_DBG_WARNON 131 | #endif 132 | //} 133 | #endif /* CONFIG_SDFAT_DEBUG */ 134 | 135 | 136 | #ifndef CONFIG_SDFAT_TRACE_SB_LOCK 137 | //#define CONFIG_SDFAT_TRACE_SB_LOCK 138 | #endif 139 | 140 | #ifndef CONFIG_SDFAT_TRACE_ELAPSED_TIME 141 | //#define CONFIG_SDFAT_TRACE_ELAPSED_TIME 142 | #endif 143 | 144 | #endif /* _SDFAT_CONFIG_H */ 145 | 146 | /* end of config.h */ 147 | -------------------------------------------------------------------------------- /core.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | #ifndef _SDFAT_CORE_H 19 | #define _SDFAT_CORE_H 20 | 21 | #include 22 | 23 | #include "config.h" 24 | #include "api.h" 25 | #include "upcase.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif /* __cplusplus */ 30 | 31 | /*----------------------------------------------------------------------*/ 32 | /* Constant & Macro Definitions */ 33 | /*----------------------------------------------------------------------*/ 34 | #define get_next_clus(sb, pclu) fat_ent_get(sb, *(pclu), pclu) 35 | #define get_next_clus_safe(sb, pclu) fat_ent_get_safe(sb, *(pclu), pclu) 36 | 37 | /* file status */ 38 | /* this prevents 39 | * fscore_write_inode, fscore_map_clus, ... with the unlinked inodes 40 | * from corrupting on-disk dentry data. 41 | * 42 | * The fid->dir value of unlinked inode will be DIR_DELETED 43 | * and those functions must check if fid->dir is valid prior to 44 | * the calling of get_dentry_in_dir() 45 | */ 46 | #define DIR_DELETED 0xFFFF0321 47 | 48 | /*----------------------------------------------------------------------*/ 49 | /* Type Definitions */ 50 | /*----------------------------------------------------------------------*/ 51 | #define ES_2_ENTRIES 2 52 | #define ES_3_ENTRIES 3 53 | #define ES_ALL_ENTRIES 0 54 | 55 | typedef struct { 56 | u64 sector; // sector number that contains file_entry 57 | u32 offset; // byte offset in the sector 58 | s32 alloc_flag; // flag in stream entry. 01 for cluster chain, 03 for contig. clusters. 59 | u32 num_entries; 60 | void *__buf; // __buf should be the last member 61 | } ENTRY_SET_CACHE_T; 62 | 63 | /*----------------------------------------------------------------------*/ 64 | /* Inline Functions */ 65 | /*----------------------------------------------------------------------*/ 66 | static inline bool is_valid_clus(FS_INFO_T *fsi, u32 clus) 67 | { 68 | if (clus < CLUS_BASE || fsi->num_clusters <= clus) 69 | return false; 70 | return true; 71 | } 72 | 73 | /*----------------------------------------------------------------------*/ 74 | /* External Function Declarations */ 75 | /*----------------------------------------------------------------------*/ 76 | 77 | /* file system initialization & shutdown functions */ 78 | s32 fscore_init(void); 79 | s32 fscore_shutdown(void); 80 | 81 | /* bdev management */ 82 | s32 fscore_check_bdi_valid(struct super_block *sb); 83 | 84 | /* chain management */ 85 | s32 chain_cont_cluster(struct super_block *sb, u32 chain, u32 len); 86 | 87 | /* volume management functions */ 88 | s32 fscore_mount(struct super_block *sb); 89 | s32 fscore_umount(struct super_block *sb); 90 | s32 fscore_statfs(struct super_block *sb, VOL_INFO_T *info); 91 | s32 fscore_sync_fs(struct super_block *sb, s32 do_sync); 92 | s32 fscore_set_vol_flags(struct super_block *sb, u16 new_flag, s32 always_sync); 93 | u32 fscore_get_au_stat(struct super_block *sb, s32 mode); 94 | 95 | /* file management functions */ 96 | s32 fscore_lookup(struct inode *inode, u8 *path, FILE_ID_T *fid); 97 | s32 fscore_create(struct inode *inode, u8 *path, u8 mode, FILE_ID_T *fid); 98 | s32 fscore_read_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); 99 | s32 fscore_write_link(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); 100 | s32 fscore_truncate(struct inode *inode, u64 old_size, u64 new_size); 101 | s32 fscore_rename(struct inode *old_parent_inode, FILE_ID_T *fid, 102 | struct inode *new_parent_inode, struct dentry *new_dentry); 103 | s32 fscore_remove(struct inode *inode, FILE_ID_T *fid); 104 | s32 fscore_read_inode(struct inode *inode, DIR_ENTRY_T *info); 105 | s32 fscore_write_inode(struct inode *inode, DIR_ENTRY_T *info, int sync); 106 | s32 fscore_map_clus(struct inode *inode, u32 clu_offset, u32 *clu, int dest); 107 | s32 fscore_reserve_clus(struct inode *inode); 108 | s32 fscore_unlink(struct inode *inode, FILE_ID_T *fid); 109 | 110 | /* directory management functions */ 111 | s32 fscore_mkdir(struct inode *inode, u8 *path, FILE_ID_T *fid); 112 | s32 fscore_readdir(struct inode *inode, DIR_ENTRY_T *dir_ent); 113 | s32 fscore_rmdir(struct inode *inode, FILE_ID_T *fid); 114 | 115 | 116 | /*----------------------------------------------------------------------*/ 117 | /* External Function Declarations (NOT TO UPPER LAYER) */ 118 | /*----------------------------------------------------------------------*/ 119 | 120 | /* core.c : core code for common */ 121 | /* dir entry management functions */ 122 | DENTRY_T *get_dentry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u64 *sector); 123 | 124 | /* name conversion functions */ 125 | void get_uniname_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode); 126 | 127 | /* file operation functions */ 128 | s32 walk_fat_chain(struct super_block *sb, CHAIN_T *p_dir, u32 byte_offset, u32 *clu); 129 | 130 | /* sdfat/cache.c */ 131 | s32 meta_cache_init(struct super_block *sb); 132 | s32 meta_cache_shutdown(struct super_block *sb); 133 | u8 *fcache_getblk(struct super_block *sb, u64 sec); 134 | s32 fcache_modify(struct super_block *sb, u64 sec); 135 | s32 fcache_release_all(struct super_block *sb); 136 | s32 fcache_flush(struct super_block *sb, u32 sync); 137 | 138 | u8 *dcache_getblk(struct super_block *sb, u64 sec); 139 | s32 dcache_modify(struct super_block *sb, u64 sec); 140 | s32 dcache_lock(struct super_block *sb, u64 sec); 141 | s32 dcache_unlock(struct super_block *sb, u64 sec); 142 | s32 dcache_release(struct super_block *sb, u64 sec); 143 | s32 dcache_release_all(struct super_block *sb); 144 | s32 dcache_flush(struct super_block *sb, u32 sync); 145 | s32 dcache_readahead(struct super_block *sb, u64 sec); 146 | 147 | 148 | /* fatent.c */ 149 | s32 fat_ent_ops_init(struct super_block *sb); 150 | s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content); 151 | s32 fat_ent_set(struct super_block *sb, u32 loc, u32 content); 152 | s32 fat_ent_get_safe(struct super_block *sb, u32 loc, u32 *content); 153 | 154 | /* core_fat.c : core code for fat */ 155 | s32 fat_generate_dos_name_new(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T *p_dosname, s32 n_entries); 156 | s32 mount_fat16(struct super_block *sb, pbr_t *p_pbr); 157 | s32 mount_fat32(struct super_block *sb, pbr_t *p_pbr); 158 | 159 | /* core_exfat.c : core code for exfat */ 160 | 161 | s32 load_alloc_bmp(struct super_block *sb); 162 | void free_alloc_bmp(struct super_block *sb); 163 | ENTRY_SET_CACHE_T *get_dentry_set_in_dir(struct super_block *sb, 164 | CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep); 165 | void release_dentry_set(ENTRY_SET_CACHE_T *es); 166 | s32 update_dir_chksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry); 167 | s32 update_dir_chksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es); 168 | bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir); 169 | s32 mount_exfat(struct super_block *sb, pbr_t *p_pbr); 170 | 171 | /* amap_smart.c : creation on mount / destroy on umount */ 172 | int amap_create(struct super_block *sb, u32 pack_ratio, u32 sect_per_au, u32 hidden_sect); 173 | void amap_destroy(struct super_block *sb); 174 | 175 | /* amap_smart.c : (de)allocation functions */ 176 | s32 amap_fat_alloc_cluster(struct super_block *sb, u32 num_alloc, CHAIN_T *p_chain, s32 dest); 177 | s32 amap_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse);/* Not impelmented */ 178 | s32 amap_release_cluster(struct super_block *sb, u32 clu); /* Only update AMAP */ 179 | 180 | /* amap_smart.c : misc (for defrag) */ 181 | s32 amap_mark_ignore(struct super_block *sb, u32 clu); 182 | s32 amap_unmark_ignore(struct super_block *sb, u32 clu); 183 | s32 amap_unmark_ignore_all(struct super_block *sb); 184 | s32 amap_check_working(struct super_block *sb, u32 clu); 185 | s32 amap_get_freeclus(struct super_block *sb, u32 clu); 186 | 187 | /* amap_smart.c : stat AU */ 188 | u32 amap_get_au_stat(struct super_block *sb, s32 mode); 189 | 190 | 191 | /* blkdev.c */ 192 | s32 bdev_open_dev(struct super_block *sb); 193 | s32 bdev_close_dev(struct super_block *sb); 194 | s32 bdev_check_bdi_valid(struct super_block *sb); 195 | s32 bdev_readahead(struct super_block *sb, u64 secno, u64 num_secs); 196 | s32 bdev_mread(struct super_block *sb, u64 secno, struct buffer_head **bh, u64 num_secs, s32 read); 197 | s32 bdev_mwrite(struct super_block *sb, u64 secno, struct buffer_head *bh, u64 num_secs, s32 sync); 198 | s32 bdev_sync_all(struct super_block *sb); 199 | 200 | /* blkdev.c : sector read/write functions */ 201 | s32 read_sect(struct super_block *sb, u64 sec, struct buffer_head **bh, s32 read); 202 | s32 write_sect(struct super_block *sb, u64 sec, struct buffer_head *bh, s32 sync); 203 | s32 read_msect(struct super_block *sb, u64 sec, struct buffer_head **bh, s64 num_secs, s32 read); 204 | s32 write_msect(struct super_block *sb, u64 sec, struct buffer_head *bh, s64 num_secs, s32 sync); 205 | s32 write_msect_zero(struct super_block *sb, u64 sec, u64 num_secs); 206 | 207 | /* misc.c */ 208 | u8 calc_chksum_1byte(void *data, s32 len, u8 chksum); 209 | u16 calc_chksum_2byte(void *data, s32 len, u16 chksum, s32 type); 210 | 211 | /* extent.c */ 212 | s32 extent_cache_init(void); 213 | void extent_cache_shutdown(void); 214 | void extent_cache_init_inode(struct inode *inode); 215 | void extent_cache_inval_inode(struct inode *inode); 216 | s32 extent_get_clus(struct inode *inode, u32 cluster, u32 *fclus, 217 | u32 *dclus, u32 *last_dclus, s32 allow_eof); 218 | /*----------------------------------------------------------------------*/ 219 | /* Wrapper Function */ 220 | /*----------------------------------------------------------------------*/ 221 | void set_sb_dirty(struct super_block *sb); 222 | 223 | #ifdef __cplusplus 224 | } 225 | #endif /* __cplusplus */ 226 | 227 | #endif /* _SDFAT_CORE_H */ 228 | 229 | /* end of core.h */ 230 | -------------------------------------------------------------------------------- /dfr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | #ifndef _SDFAT_DEFRAG_H 19 | #define _SDFAT_DEFRAG_H 20 | 21 | #ifdef CONFIG_SDFAT_DFR 22 | 23 | /* Tuning parameters */ 24 | #define DFR_MIN_TIMEOUT (1 * HZ) // Minimum timeout for forced-sync 25 | #define DFR_DEFAULT_TIMEOUT (10 * HZ) // Default timeout for forced-sync 26 | 27 | #define DFR_DEFAULT_CLEAN_RATIO (50) // Wake-up daemon when clean AU ratio under 50% 28 | #define DFR_DEFAULT_WAKEUP_RATIO (10) // Wake-up daemon when clean AU ratio under 10%, regardless of frag_ratio 29 | 30 | #define DFR_DEFAULT_FRAG_RATIO (130) // Wake-up daemon when frag_ratio over 130% 31 | 32 | #define DFR_DEFAULT_PACKING_RATIO (10) // Call allocator with PACKING flag, when clean AU ratio under 10% 33 | 34 | #define DFR_DEFAULT_STOP_RATIO (98) // Stop defrag_daemon when disk used ratio over 98% 35 | #define DFR_FULL_RATIO (100) 36 | 37 | #define DFR_MAX_AU_MOVED (16) // Maximum # of AUs for a request 38 | 39 | 40 | /* Debugging support*/ 41 | #define dfr_err(fmt, args...) pr_err("DFR: " fmt "\n", args) 42 | 43 | #ifdef CONFIG_SDFAT_DFR_DEBUG 44 | #define dfr_debug(fmt, args...) pr_debug("DFR: " fmt "\n", args) 45 | #else 46 | #define dfr_debug(fmt, args...) 47 | #endif 48 | 49 | 50 | /* Error handling */ 51 | #define ERR_HANDLE(err) { \ 52 | if (err) { \ 53 | dfr_debug("err %d", err); \ 54 | goto error; \ 55 | } \ 56 | } 57 | 58 | #define ERR_HANDLE2(cond, err, val) { \ 59 | if (cond) { \ 60 | err = val; \ 61 | dfr_debug("err %d", err); \ 62 | goto error; \ 63 | } \ 64 | } 65 | 66 | 67 | /* Arguments IN-OUT */ 68 | #define IN 69 | #define OUT 70 | #define INOUT 71 | 72 | 73 | /* Macros */ 74 | #define GET64_HI(var64) ((unsigned int)((var64) >> 32)) 75 | #define GET64_LO(var64) ((unsigned int)(((var64) << 32) >> 32)) 76 | #define SET64_HI(dst64, var32) { (dst64) = ((loff_t)(var32) << 32) | ((dst64) & 0x00000000ffffffffLL); } 77 | #define SET64_LO(dst64, var32) { (dst64) = ((dst64) & 0xffffffff00000000LL) | ((var32) & 0x00000000ffffffffLL); } 78 | 79 | #define GET32_HI(var32) ((unsigned short)((var32) >> 16)) 80 | #define GET32_LO(var32) ((unsigned short)(((var32) << 16) >> 16)) 81 | #define SET32_HI(dst32, var16) { (dst32) = ((unsigned int)(var16) << 16) | ((dst32) & 0x0000ffff); } 82 | #define SET32_LO(dst32, var16) { (dst32) = ((dst32) & 0xffff0000) | ((unsigned int)(var16) & 0x0000ffff); } 83 | 84 | 85 | /* FAT32 related */ 86 | #define FAT32_EOF (0x0fffffff) 87 | #define FAT32_RESERVED (0x0ffffff7) 88 | #define FAT32_UNUSED_CLUS (2) 89 | 90 | #define CLUS_PER_AU(sb) ( \ 91 | (SDFAT_SB(sb)->options.amap_opt.sect_per_au) >> (SDFAT_SB(sb)->fsi.sect_per_clus_bits) \ 92 | ) 93 | #define PAGES_PER_AU(sb) ( \ 94 | ((SDFAT_SB(sb)->options.amap_opt.sect_per_au) << ((sb)->s_blocksize_bits)) \ 95 | >> PAGE_SHIFT \ 96 | ) 97 | #define PAGES_PER_CLUS(sb) ((SDFAT_SB(sb)->fsi.cluster_size) >> PAGE_SHIFT) 98 | 99 | #define FAT32_CHECK_CLUSTER(fsi, clus, err) \ 100 | { \ 101 | if (((clus) < FAT32_UNUSED_CLUS) || \ 102 | ((clus) > (fsi)->num_clusters) || \ 103 | ((clus) >= FAT32_RESERVED)) { \ 104 | dfr_err("clus %08x, fsi->num_clusters %08x", (clus), (fsi)->num_clusters); \ 105 | err = -EINVAL; \ 106 | } else { \ 107 | err = 0; \ 108 | } \ 109 | } 110 | 111 | 112 | /* IOCTL_DFR_INFO */ 113 | struct defrag_info_arg { 114 | /* PBS info */ 115 | unsigned int sec_sz; 116 | unsigned int clus_sz; 117 | unsigned long long total_sec; 118 | unsigned long long fat_offset_sec; 119 | unsigned int fat_sz_sec; 120 | unsigned int n_fat; 121 | unsigned int hidden_sectors; 122 | 123 | /* AU info */ 124 | unsigned int sec_per_au; 125 | }; 126 | 127 | 128 | /* IOC_DFR_TRAV */ 129 | #define DFR_TRAV_HEADER_IDX (0) 130 | 131 | #define DFR_TRAV_TYPE_HEADER (0x0000000F) 132 | #define DFR_TRAV_TYPE_DIR (1) 133 | #define DFR_TRAV_TYPE_FILE (2) 134 | #define DFR_TRAV_TYPE_TEST (DFR_TRAV_TYPE_HEADER | 0x10000000) 135 | 136 | #define DFR_TRAV_ROOT_IPOS (0xFFFFFFFFFFFFFFFFLL) 137 | 138 | struct defrag_trav_arg { 139 | int type; 140 | unsigned int start_clus; 141 | loff_t i_pos; 142 | char name[MAX_DOSNAME_BUF_SIZE]; 143 | char dummy1; 144 | int dummy2; 145 | }; 146 | 147 | #define DFR_TRAV_STAT_DONE (0x1) 148 | #define DFR_TRAV_STAT_MORE (0x2) 149 | #define DFR_TRAV_STAT_ERR (0xFF) 150 | 151 | struct defrag_trav_header { 152 | int type; 153 | unsigned int start_clus; 154 | loff_t i_pos; 155 | char name[MAX_DOSNAME_BUF_SIZE]; 156 | char stat; 157 | unsigned int nr_entries; 158 | }; 159 | 160 | 161 | /* IOC_DFR_REQ */ 162 | #define REQ_HEADER_IDX (0) 163 | 164 | #define DFR_CHUNK_STAT_ERR (0xFFFFFFFF) 165 | #define DFR_CHUNK_STAT_REQ (0x1) 166 | #define DFR_CHUNK_STAT_WB (0x2) 167 | #define DFR_CHUNK_STAT_FAT (0x4) 168 | #define DFR_CHUNK_STAT_PREP (DFR_CHUNK_STAT_REQ | DFR_CHUNK_STAT_WB | DFR_CHUNK_STAT_FAT) 169 | #define DFR_CHUNK_STAT_PASS (0x0000000F) 170 | 171 | struct defrag_chunk_header { 172 | int mode; 173 | unsigned int nr_chunks; 174 | loff_t dummy1; 175 | int dummy2[4]; 176 | union { 177 | int *dummy3; 178 | int dummy4; 179 | }; 180 | int dummy5; 181 | }; 182 | 183 | struct defrag_chunk_info { 184 | int stat; 185 | /* File related */ 186 | unsigned int f_clus; 187 | loff_t i_pos; 188 | /* Cluster related */ 189 | unsigned int d_clus; 190 | unsigned int nr_clus; 191 | unsigned int prev_clus; 192 | unsigned int next_clus; 193 | union { 194 | void *dummy; 195 | /* req status */ 196 | unsigned int new_idx; 197 | }; 198 | /* AU related */ 199 | unsigned int au_clus; 200 | }; 201 | 202 | 203 | /* Global info */ 204 | #define DFR_MODE_BACKGROUND (0x1) 205 | #define DFR_MODE_FOREGROUND (0x2) 206 | #define DFR_MODE_ONESHOT (0x4) 207 | #define DFR_MODE_BATCHED (0x8) 208 | #define DFR_MODE_TEST (DFR_MODE_BACKGROUND | 0x10000000) 209 | 210 | #define DFR_SB_STAT_IDLE (0) 211 | #define DFR_SB_STAT_REQ (1) 212 | #define DFR_SB_STAT_VALID (2) 213 | 214 | #define DFR_INO_STAT_IDLE (0) 215 | #define DFR_INO_STAT_REQ (1) 216 | struct defrag_info { 217 | struct mutex lock; 218 | atomic_t stat; 219 | struct defrag_chunk_info *chunks; 220 | unsigned int nr_chunks; 221 | struct list_head entry; 222 | }; 223 | 224 | 225 | /* SPO test flags */ 226 | #define DFR_SPO_NONE (0) 227 | #define DFR_SPO_NORMAL (1) 228 | #define DFR_SPO_DISCARD (2) 229 | #define DFR_SPO_FAT_NEXT (3) 230 | #define DFR_SPO_RANDOM (4) 231 | 232 | 233 | /* Extern functions */ 234 | int defrag_get_info(struct super_block *sb, struct defrag_info_arg *arg); 235 | 236 | int defrag_scan_dir(struct super_block *sb, struct defrag_trav_arg *arg); 237 | 238 | int defrag_validate_cluster(struct inode *inode, struct defrag_chunk_info *chunk, int skip_prev); 239 | int defrag_reserve_clusters(struct super_block *sb, int nr_clus); 240 | int defrag_mark_ignore(struct super_block *sb, unsigned int clus); 241 | void defrag_unmark_ignore_all(struct super_block *sb); 242 | 243 | int defrag_map_cluster(struct inode *inode, unsigned int clu_offset, unsigned int *clu); 244 | void defrag_writepage_end_io(struct page *page); 245 | 246 | void defrag_update_fat_prev(struct super_block *sb, int force); 247 | void defrag_update_fat_next(struct super_block *sb); 248 | void defrag_check_discard(struct super_block *sb); 249 | int defrag_free_cluster(struct super_block *sb, unsigned int clus); 250 | 251 | int defrag_check_defrag_required(struct super_block *sb, int *totalau, int *cleanau, int *fullau); 252 | int defrag_check_defrag_on(struct inode *inode, loff_t start, loff_t end, int cancel, const char *caller); 253 | 254 | #ifdef CONFIG_SDFAT_DFR_DEBUG 255 | void defrag_spo_test(struct super_block *sb, int flag, const char *caller); 256 | #endif 257 | 258 | #endif /* CONFIG_SDFAT_DFR */ 259 | 260 | #endif /* _SDFAT_DEFRAG_H */ 261 | 262 | -------------------------------------------------------------------------------- /extent.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | /* 19 | * linux/fs/fat/cache.c 20 | * 21 | * Written 1992,1993 by Werner Almesberger 22 | * 23 | * Mar 1999. AV. Changed cache, so that it uses the starting cluster instead 24 | * of inode number. 25 | * May 1999. AV. Fixed the bogosity with FAT32 (read "FAT28"). Fscking lusers. 26 | */ 27 | 28 | /************************************************************************/ 29 | /* */ 30 | /* PROJECT : exFAT & FAT12/16/32 File System */ 31 | /* FILE : extent.c */ 32 | /* PURPOSE : Improve the performance of traversing fat chain. */ 33 | /* */ 34 | /*----------------------------------------------------------------------*/ 35 | /* NOTES */ 36 | /* */ 37 | /* */ 38 | /************************************************************************/ 39 | 40 | #include 41 | #include "sdfat.h" 42 | #include "core.h" 43 | 44 | #define EXTENT_CACHE_VALID 0 45 | /* this must be > 0. */ 46 | #define EXTENT_MAX_CACHE 16 47 | 48 | struct extent_cache { 49 | struct list_head cache_list; 50 | u32 nr_contig; /* number of contiguous clusters */ 51 | u32 fcluster; /* cluster number in the file. */ 52 | u32 dcluster; /* cluster number on disk. */ 53 | }; 54 | 55 | struct extent_cache_id { 56 | u32 id; 57 | u32 nr_contig; 58 | u32 fcluster; 59 | u32 dcluster; 60 | }; 61 | 62 | static struct kmem_cache *extent_cache_cachep; 63 | 64 | static void init_once(void *c) 65 | { 66 | struct extent_cache *cache = (struct extent_cache *)c; 67 | 68 | INIT_LIST_HEAD(&cache->cache_list); 69 | } 70 | 71 | s32 extent_cache_init(void) 72 | { 73 | extent_cache_cachep = kmem_cache_create("sdfat_extent_cache", 74 | sizeof(struct extent_cache), 75 | 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, 76 | init_once); 77 | if (!extent_cache_cachep) 78 | return -ENOMEM; 79 | return 0; 80 | } 81 | 82 | void extent_cache_shutdown(void) 83 | { 84 | if (!extent_cache_cachep) 85 | return; 86 | kmem_cache_destroy(extent_cache_cachep); 87 | } 88 | 89 | void extent_cache_init_inode(struct inode *inode) 90 | { 91 | EXTENT_T *extent = &(SDFAT_I(inode)->fid.extent); 92 | 93 | spin_lock_init(&extent->cache_lru_lock); 94 | extent->nr_caches = 0; 95 | extent->cache_valid_id = EXTENT_CACHE_VALID + 1; 96 | INIT_LIST_HEAD(&extent->cache_lru); 97 | } 98 | 99 | static inline struct extent_cache *extent_cache_alloc(void) 100 | { 101 | return kmem_cache_alloc(extent_cache_cachep, GFP_NOFS); 102 | } 103 | 104 | static inline void extent_cache_free(struct extent_cache *cache) 105 | { 106 | BUG_ON(!list_empty(&cache->cache_list)); 107 | kmem_cache_free(extent_cache_cachep, cache); 108 | } 109 | 110 | static inline void extent_cache_update_lru(struct inode *inode, 111 | struct extent_cache *cache) 112 | { 113 | EXTENT_T *extent = &(SDFAT_I(inode)->fid.extent); 114 | 115 | if (extent->cache_lru.next != &cache->cache_list) 116 | list_move(&cache->cache_list, &extent->cache_lru); 117 | } 118 | 119 | static u32 extent_cache_lookup(struct inode *inode, u32 fclus, 120 | struct extent_cache_id *cid, 121 | u32 *cached_fclus, u32 *cached_dclus) 122 | { 123 | EXTENT_T *extent = &(SDFAT_I(inode)->fid.extent); 124 | 125 | static struct extent_cache nohit = { .fcluster = 0, }; 126 | 127 | struct extent_cache *hit = &nohit, *p; 128 | u32 offset = CLUS_EOF; 129 | 130 | spin_lock(&extent->cache_lru_lock); 131 | list_for_each_entry(p, &extent->cache_lru, cache_list) { 132 | /* Find the cache of "fclus" or nearest cache. */ 133 | if (p->fcluster <= fclus && hit->fcluster < p->fcluster) { 134 | hit = p; 135 | if ((hit->fcluster + hit->nr_contig) < fclus) { 136 | offset = hit->nr_contig; 137 | } else { 138 | offset = fclus - hit->fcluster; 139 | break; 140 | } 141 | } 142 | } 143 | if (hit != &nohit) { 144 | extent_cache_update_lru(inode, hit); 145 | 146 | cid->id = extent->cache_valid_id; 147 | cid->nr_contig = hit->nr_contig; 148 | cid->fcluster = hit->fcluster; 149 | cid->dcluster = hit->dcluster; 150 | *cached_fclus = cid->fcluster + offset; 151 | *cached_dclus = cid->dcluster + offset; 152 | } 153 | spin_unlock(&extent->cache_lru_lock); 154 | 155 | return offset; 156 | } 157 | 158 | static struct extent_cache *extent_cache_merge(struct inode *inode, 159 | struct extent_cache_id *new) 160 | { 161 | EXTENT_T *extent = &(SDFAT_I(inode)->fid.extent); 162 | 163 | struct extent_cache *p; 164 | 165 | list_for_each_entry(p, &extent->cache_lru, cache_list) { 166 | /* Find the same part as "new" in cluster-chain. */ 167 | if (p->fcluster == new->fcluster) { 168 | ASSERT(p->dcluster == new->dcluster); 169 | if (new->nr_contig > p->nr_contig) 170 | p->nr_contig = new->nr_contig; 171 | return p; 172 | } 173 | } 174 | return NULL; 175 | } 176 | 177 | static void extent_cache_add(struct inode *inode, struct extent_cache_id *new) 178 | { 179 | EXTENT_T *extent = &(SDFAT_I(inode)->fid.extent); 180 | 181 | struct extent_cache *cache, *tmp; 182 | 183 | if (new->fcluster == -1) /* dummy cache */ 184 | return; 185 | 186 | spin_lock(&extent->cache_lru_lock); 187 | if (new->id != EXTENT_CACHE_VALID && 188 | new->id != extent->cache_valid_id) 189 | goto out; /* this cache was invalidated */ 190 | 191 | cache = extent_cache_merge(inode, new); 192 | if (cache == NULL) { 193 | if (extent->nr_caches < EXTENT_MAX_CACHE) { 194 | extent->nr_caches++; 195 | spin_unlock(&extent->cache_lru_lock); 196 | 197 | tmp = extent_cache_alloc(); 198 | if (!tmp) { 199 | spin_lock(&extent->cache_lru_lock); 200 | extent->nr_caches--; 201 | spin_unlock(&extent->cache_lru_lock); 202 | return; 203 | } 204 | 205 | spin_lock(&extent->cache_lru_lock); 206 | cache = extent_cache_merge(inode, new); 207 | if (cache != NULL) { 208 | extent->nr_caches--; 209 | extent_cache_free(tmp); 210 | goto out_update_lru; 211 | } 212 | cache = tmp; 213 | } else { 214 | struct list_head *p = extent->cache_lru.prev; 215 | cache = list_entry(p, struct extent_cache, cache_list); 216 | } 217 | cache->fcluster = new->fcluster; 218 | cache->dcluster = new->dcluster; 219 | cache->nr_contig = new->nr_contig; 220 | } 221 | out_update_lru: 222 | extent_cache_update_lru(inode, cache); 223 | out: 224 | spin_unlock(&extent->cache_lru_lock); 225 | } 226 | 227 | /* 228 | * Cache invalidation occurs rarely, thus the LRU chain is not updated. It 229 | * fixes itself after a while. 230 | */ 231 | static void __extent_cache_inval_inode(struct inode *inode) 232 | { 233 | EXTENT_T *extent = &(SDFAT_I(inode)->fid.extent); 234 | struct extent_cache *cache; 235 | 236 | while (!list_empty(&extent->cache_lru)) { 237 | cache = list_entry(extent->cache_lru.next, 238 | struct extent_cache, cache_list); 239 | list_del_init(&cache->cache_list); 240 | extent->nr_caches--; 241 | extent_cache_free(cache); 242 | } 243 | /* Update. The copy of caches before this id is discarded. */ 244 | extent->cache_valid_id++; 245 | if (extent->cache_valid_id == EXTENT_CACHE_VALID) 246 | extent->cache_valid_id++; 247 | } 248 | 249 | void extent_cache_inval_inode(struct inode *inode) 250 | { 251 | EXTENT_T *extent = &(SDFAT_I(inode)->fid.extent); 252 | 253 | spin_lock(&extent->cache_lru_lock); 254 | __extent_cache_inval_inode(inode); 255 | spin_unlock(&extent->cache_lru_lock); 256 | } 257 | 258 | static inline s32 cache_contiguous(struct extent_cache_id *cid, u32 dclus) 259 | { 260 | cid->nr_contig++; 261 | return ((cid->dcluster + cid->nr_contig) == dclus); 262 | } 263 | 264 | static inline void cache_init(struct extent_cache_id *cid, u32 fclus, u32 dclus) 265 | { 266 | cid->id = EXTENT_CACHE_VALID; 267 | cid->fcluster = fclus; 268 | cid->dcluster = dclus; 269 | cid->nr_contig = 0; 270 | } 271 | 272 | s32 extent_get_clus(struct inode *inode, u32 cluster, u32 *fclus, 273 | u32 *dclus, u32 *last_dclus, s32 allow_eof) 274 | { 275 | struct super_block *sb = inode->i_sb; 276 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 277 | u32 limit = fsi->num_clusters; 278 | FILE_ID_T *fid = &(SDFAT_I(inode)->fid); 279 | struct extent_cache_id cid; 280 | u32 content; 281 | 282 | /* FOR GRACEFUL ERROR HANDLING */ 283 | if (IS_CLUS_FREE(fid->start_clu)) { 284 | sdfat_fs_error(sb, "invalid access to " 285 | "extent cache (entry 0x%08x)", fid->start_clu); 286 | ASSERT(0); 287 | return -EIO; 288 | } 289 | 290 | *fclus = 0; 291 | *dclus = fid->start_clu; 292 | *last_dclus = *dclus; 293 | 294 | /* 295 | * Don`t use extent_cache if zero offset or non-cluster allocation 296 | */ 297 | if ((cluster == 0) || IS_CLUS_EOF(*dclus)) 298 | return 0; 299 | 300 | cache_init(&cid, CLUS_EOF, CLUS_EOF); 301 | 302 | if (extent_cache_lookup(inode, cluster, &cid, fclus, dclus) == CLUS_EOF) { 303 | /* 304 | * dummy, always not contiguous 305 | * This is reinitialized by cache_init(), later. 306 | */ 307 | ASSERT((cid.id == EXTENT_CACHE_VALID) 308 | && (cid.fcluster == CLUS_EOF) 309 | && (cid.dcluster == CLUS_EOF) 310 | && (cid.nr_contig == 0)); 311 | } 312 | 313 | if (*fclus == cluster) 314 | return 0; 315 | 316 | while (*fclus < cluster) { 317 | /* prevent the infinite loop of cluster chain */ 318 | if (*fclus > limit) { 319 | sdfat_fs_error(sb, 320 | "%s: detected the cluster chain loop" 321 | " (i_pos %u)", __func__, 322 | (*fclus)); 323 | return -EIO; 324 | } 325 | 326 | if (fat_ent_get_safe(sb, *dclus, &content)) 327 | return -EIO; 328 | 329 | *last_dclus = *dclus; 330 | *dclus = content; 331 | (*fclus)++; 332 | 333 | if (IS_CLUS_EOF(content)) { 334 | if (!allow_eof) { 335 | sdfat_fs_error(sb, 336 | "%s: invalid cluster chain (i_pos %u," 337 | "last_clus 0x%08x is EOF)", 338 | __func__, *fclus, (*last_dclus)); 339 | return -EIO; 340 | } 341 | 342 | break; 343 | } 344 | 345 | if (!cache_contiguous(&cid, *dclus)) 346 | cache_init(&cid, *fclus, *dclus); 347 | } 348 | 349 | extent_cache_add(inode, &cid); 350 | return 0; 351 | } 352 | -------------------------------------------------------------------------------- /fatent.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | /************************************************************************/ 19 | /* */ 20 | /* PROJECT : exFAT & FAT12/16/32 File System */ 21 | /* FILE : fatent.c */ 22 | /* PURPOSE : sdFAT FAT entry manager */ 23 | /* */ 24 | /*----------------------------------------------------------------------*/ 25 | /* NOTES */ 26 | /* */ 27 | /* */ 28 | /************************************************************************/ 29 | 30 | #include 31 | 32 | #include "sdfat.h" 33 | #include "core.h" 34 | 35 | /*----------------------------------------------------------------------*/ 36 | /* Global Variable Definitions */ 37 | /*----------------------------------------------------------------------*/ 38 | /* All buffer structures are protected w/ fsi->v_sem */ 39 | 40 | /*----------------------------------------------------------------------*/ 41 | /* Static functions */ 42 | /*----------------------------------------------------------------------*/ 43 | 44 | /*======================================================================*/ 45 | /* FAT Read/Write Functions */ 46 | /*======================================================================*/ 47 | /* in : sb, loc 48 | * out: content 49 | * returns 0 on success, -1 on error 50 | */ 51 | static s32 exfat_ent_get(struct super_block *sb, u32 loc, u32 *content) 52 | { 53 | u32 off, _content; 54 | u64 sec; 55 | u8 *fat_sector; 56 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 57 | 58 | /* fsi->vol_type == EXFAT */ 59 | sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2)); 60 | off = (loc << 2) & (u32)(sb->s_blocksize - 1); 61 | 62 | fat_sector = fcache_getblk(sb, sec); 63 | if (!fat_sector) 64 | return -EIO; 65 | 66 | _content = le32_to_cpu(*(__le32 *)(&fat_sector[off])); 67 | 68 | /* remap reserved clusters to simplify code */ 69 | if (_content >= CLUSTER_32(0xFFFFFFF8)) 70 | _content = CLUS_EOF; 71 | 72 | *content = CLUSTER_32(_content); 73 | return 0; 74 | } 75 | 76 | static s32 exfat_ent_set(struct super_block *sb, u32 loc, u32 content) 77 | { 78 | u32 off; 79 | u64 sec; 80 | u8 *fat_sector; 81 | __le32 *fat_entry; 82 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 83 | 84 | sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2)); 85 | off = (loc << 2) & (u32)(sb->s_blocksize - 1); 86 | 87 | fat_sector = fcache_getblk(sb, sec); 88 | if (!fat_sector) 89 | return -EIO; 90 | 91 | fat_entry = (__le32 *)&(fat_sector[off]); 92 | *fat_entry = cpu_to_le32(content); 93 | 94 | return fcache_modify(sb, sec); 95 | } 96 | 97 | #define FATENT_FAT32_VALID_MASK (0x0FFFFFFFU) 98 | #define FATENT_FAT32_IGNORE_MASK (0xF0000000U) 99 | static s32 fat32_ent_get(struct super_block *sb, u32 loc, u32 *content) 100 | { 101 | u32 off, _content; 102 | u64 sec; 103 | u8 *fat_sector; 104 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 105 | 106 | sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2)); 107 | off = (loc << 2) & (u32)(sb->s_blocksize - 1); 108 | 109 | fat_sector = fcache_getblk(sb, sec); 110 | if (!fat_sector) 111 | return -EIO; 112 | 113 | _content = le32_to_cpu(*(__le32 *)(&fat_sector[off])); 114 | _content &= FATENT_FAT32_VALID_MASK; 115 | 116 | /* remap reserved clusters to simplify code */ 117 | if (_content == CLUSTER_32(0x0FFFFFF7U)) 118 | _content = CLUS_BAD; 119 | else if (_content >= CLUSTER_32(0x0FFFFFF8U)) 120 | _content = CLUS_EOF; 121 | 122 | *content = CLUSTER_32(_content); 123 | return 0; 124 | } 125 | 126 | static s32 fat32_ent_set(struct super_block *sb, u32 loc, u32 content) 127 | { 128 | u32 off; 129 | u64 sec; 130 | u8 *fat_sector; 131 | __le32 *fat_entry; 132 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 133 | 134 | content &= FATENT_FAT32_VALID_MASK; 135 | 136 | sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-2)); 137 | off = (loc << 2) & (u32)(sb->s_blocksize - 1); 138 | 139 | fat_sector = fcache_getblk(sb, sec); 140 | if (!fat_sector) 141 | return -EIO; 142 | 143 | fat_entry = (__le32 *)&(fat_sector[off]); 144 | content |= (le32_to_cpu(*fat_entry) & FATENT_FAT32_IGNORE_MASK); 145 | *fat_entry = cpu_to_le32(content); 146 | 147 | return fcache_modify(sb, sec); 148 | } 149 | 150 | #define FATENT_FAT16_VALID_MASK (0x0000FFFFU) 151 | static s32 fat16_ent_get(struct super_block *sb, u32 loc, u32 *content) 152 | { 153 | u32 off, _content; 154 | u64 sec; 155 | u8 *fat_sector; 156 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 157 | 158 | sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-1)); 159 | off = (loc << 1) & (u32)(sb->s_blocksize - 1); 160 | 161 | fat_sector = fcache_getblk(sb, sec); 162 | if (!fat_sector) 163 | return -EIO; 164 | 165 | _content = (u32)le16_to_cpu(*(__le16 *)(&fat_sector[off])); 166 | _content &= FATENT_FAT16_VALID_MASK; 167 | 168 | /* remap reserved clusters to simplify code */ 169 | if (_content == CLUSTER_16(0xFFF7U)) 170 | _content = CLUS_BAD; 171 | else if (_content >= CLUSTER_16(0xFFF8U)) 172 | _content = CLUS_EOF; 173 | 174 | *content = CLUSTER_32(_content); 175 | return 0; 176 | } 177 | 178 | static s32 fat16_ent_set(struct super_block *sb, u32 loc, u32 content) 179 | { 180 | u32 off; 181 | u64 sec; 182 | u8 *fat_sector; 183 | __le16 *fat_entry; 184 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 185 | 186 | content &= FATENT_FAT16_VALID_MASK; 187 | 188 | sec = fsi->FAT1_start_sector + (loc >> (sb->s_blocksize_bits-1)); 189 | off = (loc << 1) & (u32)(sb->s_blocksize - 1); 190 | 191 | fat_sector = fcache_getblk(sb, sec); 192 | if (!fat_sector) 193 | return -EIO; 194 | 195 | fat_entry = (__le16 *)&(fat_sector[off]); 196 | *fat_entry = cpu_to_le16(content); 197 | 198 | return fcache_modify(sb, sec); 199 | } 200 | 201 | #define FATENT_FAT12_VALID_MASK (0x00000FFFU) 202 | static s32 fat12_ent_get(struct super_block *sb, u32 loc, u32 *content) 203 | { 204 | u32 off, _content; 205 | u64 sec; 206 | u8 *fat_sector; 207 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 208 | 209 | sec = fsi->FAT1_start_sector + ((loc + (loc >> 1)) >> sb->s_blocksize_bits); 210 | off = (loc + (loc >> 1)) & (u32)(sb->s_blocksize - 1); 211 | 212 | fat_sector = fcache_getblk(sb, sec); 213 | if (!fat_sector) 214 | return -EIO; 215 | 216 | if (off == (u32)(sb->s_blocksize - 1)) { 217 | _content = (u32) fat_sector[off]; 218 | 219 | fat_sector = fcache_getblk(sb, ++sec); 220 | if (!fat_sector) 221 | return -EIO; 222 | 223 | _content |= (u32) fat_sector[0] << 8; 224 | } else { 225 | _content = get_unaligned_le16(&fat_sector[off]); 226 | } 227 | 228 | if (loc & 1) 229 | _content >>= 4; 230 | 231 | _content &= FATENT_FAT12_VALID_MASK; 232 | 233 | /* remap reserved clusters to simplify code */ 234 | if (_content == CLUSTER_16(0x0FF7U)) 235 | _content = CLUS_BAD; 236 | else if (_content >= CLUSTER_16(0x0FF8U)) 237 | _content = CLUS_EOF; 238 | 239 | *content = CLUSTER_32(_content); 240 | return 0; 241 | } 242 | 243 | static s32 fat12_ent_set(struct super_block *sb, u32 loc, u32 content) 244 | { 245 | u32 off; 246 | u64 sec; 247 | u8 *fat_sector, *fat_entry; 248 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 249 | 250 | content &= FATENT_FAT12_VALID_MASK; 251 | 252 | sec = fsi->FAT1_start_sector + ((loc + (loc >> 1)) >> sb->s_blocksize_bits); 253 | off = (loc + (loc >> 1)) & (u32)(sb->s_blocksize - 1); 254 | 255 | fat_sector = fcache_getblk(sb, sec); 256 | if (!fat_sector) 257 | return -EIO; 258 | 259 | if (loc & 1) { /* odd */ 260 | 261 | content <<= 4; 262 | 263 | if (off == (u32)(sb->s_blocksize-1)) { 264 | fat_sector[off] = (u8)(content | (fat_sector[off] & 0x0F)); 265 | if (fcache_modify(sb, sec)) 266 | return -EIO; 267 | 268 | fat_sector = fcache_getblk(sb, ++sec); 269 | if (!fat_sector) 270 | return -EIO; 271 | 272 | fat_sector[0] = (u8)(content >> 8); 273 | } else { 274 | fat_entry = &(fat_sector[off]); 275 | content |= 0x000F & get_unaligned_le16(fat_entry); 276 | put_unaligned_le16(content, fat_entry); 277 | } 278 | } else { /* even */ 279 | fat_sector[off] = (u8)(content); 280 | 281 | if (off == (u32)(sb->s_blocksize-1)) { 282 | fat_sector[off] = (u8)(content); 283 | if (fcache_modify(sb, sec)) 284 | return -EIO; 285 | 286 | fat_sector = fcache_getblk(sb, ++sec); 287 | if (!fat_sector) 288 | return -EIO; 289 | 290 | fat_sector[0] = (u8)((fat_sector[0] & 0xF0) | (content >> 8)); 291 | } else { 292 | fat_entry = &(fat_sector[off]); 293 | content |= 0xF000 & get_unaligned_le16(fat_entry); 294 | put_unaligned_le16(content, fat_entry); 295 | } 296 | } 297 | return fcache_modify(sb, sec); 298 | } 299 | 300 | 301 | static FATENT_OPS_T fat12_ent_ops = { 302 | fat12_ent_get, 303 | fat12_ent_set 304 | }; 305 | 306 | static FATENT_OPS_T fat16_ent_ops = { 307 | fat16_ent_get, 308 | fat16_ent_set 309 | }; 310 | 311 | static FATENT_OPS_T fat32_ent_ops = { 312 | fat32_ent_get, 313 | fat32_ent_set 314 | }; 315 | 316 | static FATENT_OPS_T exfat_ent_ops = { 317 | exfat_ent_get, 318 | exfat_ent_set 319 | }; 320 | 321 | s32 fat_ent_ops_init(struct super_block *sb) 322 | { 323 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 324 | 325 | switch (fsi->vol_type) { 326 | case EXFAT: 327 | fsi->fatent_ops = &exfat_ent_ops; 328 | break; 329 | case FAT32: 330 | fsi->fatent_ops = &fat32_ent_ops; 331 | break; 332 | case FAT16: 333 | fsi->fatent_ops = &fat16_ent_ops; 334 | break; 335 | case FAT12: 336 | fsi->fatent_ops = &fat12_ent_ops; 337 | break; 338 | default: 339 | fsi->fatent_ops = NULL; 340 | EMSG("Unknown volume type : %d", (int)fsi->vol_type); 341 | return -ENOTSUPP; 342 | } 343 | 344 | return 0; 345 | } 346 | 347 | static inline bool is_reserved_clus(u32 clus) 348 | { 349 | if (IS_CLUS_FREE(clus)) 350 | return true; 351 | if (IS_CLUS_EOF(clus)) 352 | return true; 353 | if (IS_CLUS_BAD(clus)) 354 | return true; 355 | return false; 356 | } 357 | 358 | s32 fat_ent_get(struct super_block *sb, u32 loc, u32 *content) 359 | { 360 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 361 | s32 err; 362 | 363 | if (!is_valid_clus(fsi, loc)) { 364 | sdfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", loc); 365 | return -EIO; 366 | } 367 | 368 | err = fsi->fatent_ops->ent_get(sb, loc, content); 369 | if (err) { 370 | sdfat_fs_error(sb, "failed to access to FAT " 371 | "(entry 0x%08x, err:%d)", loc, err); 372 | return err; 373 | } 374 | 375 | if (!is_reserved_clus(*content) && !is_valid_clus(fsi, *content)) { 376 | sdfat_fs_error(sb, "invalid access to FAT (entry 0x%08x) " 377 | "bogus content (0x%08x)", loc, *content); 378 | return -EIO; 379 | } 380 | 381 | return 0; 382 | } 383 | 384 | s32 fat_ent_set(struct super_block *sb, u32 loc, u32 content) 385 | { 386 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 387 | 388 | return fsi->fatent_ops->ent_set(sb, loc, content); 389 | } 390 | 391 | s32 fat_ent_get_safe(struct super_block *sb, u32 loc, u32 *content) 392 | { 393 | s32 err = fat_ent_get(sb, loc, content); 394 | 395 | if (err) 396 | return err; 397 | 398 | if (IS_CLUS_FREE(*content)) { 399 | sdfat_fs_error(sb, "invalid access to FAT free cluster " 400 | "(entry 0x%08x)", loc); 401 | return -EIO; 402 | } 403 | 404 | if (IS_CLUS_BAD(*content)) { 405 | sdfat_fs_error(sb, "invalid access to FAT bad cluster " 406 | "(entry 0x%08x)", loc); 407 | return -EIO; 408 | } 409 | 410 | return 0; 411 | } 412 | 413 | /* end of fatent.c */ 414 | -------------------------------------------------------------------------------- /misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | /* 19 | * linux/fs/fat/misc.c 20 | * 21 | * Written 1992,1993 by Werner Almesberger 22 | * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 23 | * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) 24 | */ 25 | 26 | /************************************************************************/ 27 | /* */ 28 | /* PROJECT : exFAT & FAT12/16/32 File System */ 29 | /* FILE : misc.c */ 30 | /* PURPOSE : Helper function for checksum and handing sdFAT error */ 31 | /* */ 32 | /*----------------------------------------------------------------------*/ 33 | /* NOTES */ 34 | /* */ 35 | /* */ 36 | /************************************************************************/ 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include "sdfat.h" 43 | #include "version.h" 44 | 45 | #ifdef CONFIG_SDFAT_SUPPORT_STLOG 46 | #ifdef CONFIG_PROC_FSLOG 47 | #include 48 | #else 49 | #include 50 | #endif 51 | #else 52 | #define ST_LOG(fmt, ...) 53 | #endif 54 | 55 | /************************************************************************* 56 | * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY 57 | *************************************************************************/ 58 | #ifdef CONFIG_SDFAT_UEVENT 59 | static struct kobject sdfat_uevent_kobj; 60 | 61 | int sdfat_uevent_init(struct kset *sdfat_kset) 62 | { 63 | int err; 64 | struct kobj_type *ktype = get_ktype(&sdfat_kset->kobj); 65 | 66 | sdfat_uevent_kobj.kset = sdfat_kset; 67 | err = kobject_init_and_add(&sdfat_uevent_kobj, ktype, NULL, "uevent"); 68 | if (err) 69 | pr_err("[SDFAT] Unable to create sdfat uevent kobj\n"); 70 | 71 | return err; 72 | } 73 | 74 | void sdfat_uevent_uninit(void) 75 | { 76 | kobject_del(&sdfat_uevent_kobj); 77 | memset(&sdfat_uevent_kobj, 0, sizeof(struct kobject)); 78 | } 79 | 80 | void sdfat_uevent_ro_remount(struct super_block *sb) 81 | { 82 | struct block_device *bdev = sb->s_bdev; 83 | dev_t bd_dev = bdev ? bdev->bd_dev : 0; 84 | 85 | char major[16], minor[16]; 86 | char *envp[] = { major, minor, NULL }; 87 | 88 | /* Do not trigger uevent if a device has been ejected */ 89 | if (fsapi_check_bdi_valid(sb)) 90 | return; 91 | 92 | snprintf(major, sizeof(major), "MAJOR=%d", MAJOR(bd_dev)); 93 | snprintf(minor, sizeof(minor), "MINOR=%d", MINOR(bd_dev)); 94 | 95 | kobject_uevent_env(&sdfat_uevent_kobj, KOBJ_CHANGE, envp); 96 | 97 | ST_LOG("[SDFAT](%s[%d:%d]): Uevent triggered\n", 98 | sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); 99 | } 100 | #endif 101 | 102 | /* 103 | * sdfat_fs_error reports a file system problem that might indicate fa data 104 | * corruption/inconsistency. Depending on 'errors' mount option the 105 | * panic() is called, or error message is printed FAT and nothing is done, 106 | * or filesystem is remounted read-only (default behavior). 107 | * In case the file system is remounted read-only, it can be made writable 108 | * again by remounting it. 109 | */ 110 | void __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) 111 | { 112 | struct sdfat_mount_options *opts = &SDFAT_SB(sb)->options; 113 | va_list args; 114 | struct va_format vaf; 115 | struct block_device *bdev = sb->s_bdev; 116 | dev_t bd_dev = bdev ? bdev->bd_dev : 0; 117 | 118 | if (report) { 119 | va_start(args, fmt); 120 | vaf.fmt = fmt; 121 | vaf.va = &args; 122 | pr_err("[SDFAT](%s[%d:%d]):ERR: %pV\n", 123 | sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); 124 | #ifdef CONFIG_SDFAT_SUPPORT_STLOG 125 | if (opts->errors == SDFAT_ERRORS_RO && !sb_rdonly(sb)) { 126 | ST_LOG("[SDFAT](%s[%d:%d]):ERR: %pV\n", 127 | sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); 128 | } 129 | #endif 130 | va_end(args); 131 | } 132 | 133 | if (opts->errors == SDFAT_ERRORS_PANIC) { 134 | panic("[SDFAT](%s[%d:%d]): fs panic from previous error\n", 135 | sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); 136 | } else if (opts->errors == SDFAT_ERRORS_RO && !sb_rdonly(sb)) { 137 | sb->s_flags |= SB_RDONLY; 138 | sdfat_statistics_set_mnt_ro(); 139 | pr_err("[SDFAT](%s[%d:%d]): Filesystem has been set " 140 | "read-only\n", sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); 141 | #ifdef CONFIG_SDFAT_SUPPORT_STLOG 142 | ST_LOG("[SDFAT](%s[%d:%d]): Filesystem has been set read-only\n", 143 | sb->s_id, MAJOR(bd_dev), MINOR(bd_dev)); 144 | #endif 145 | sdfat_uevent_ro_remount(sb); 146 | } 147 | } 148 | EXPORT_SYMBOL(__sdfat_fs_error); 149 | 150 | /** 151 | * __sdfat_msg() - print preformated SDFAT specific messages. 152 | * All logs except what uses sdfat_fs_error() should be written by __sdfat_msg() 153 | * If 'st' is set, the log is propagated to ST_LOG. 154 | */ 155 | void __sdfat_msg(struct super_block *sb, const char *level, int st, const char *fmt, ...) 156 | { 157 | struct va_format vaf; 158 | va_list args; 159 | struct block_device *bdev = sb->s_bdev; 160 | dev_t bd_dev = bdev ? bdev->bd_dev : 0; 161 | 162 | va_start(args, fmt); 163 | vaf.fmt = fmt; 164 | vaf.va = &args; 165 | /* level means KERN_ pacility level */ 166 | printk("%s[SDFAT](%s[%d:%d]): %pV\n", level, 167 | sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); 168 | #ifdef CONFIG_SDFAT_SUPPORT_STLOG 169 | if (st) { 170 | ST_LOG("[SDFAT](%s[%d:%d]): %pV\n", 171 | sb->s_id, MAJOR(bd_dev), MINOR(bd_dev), &vaf); 172 | } 173 | #endif 174 | va_end(args); 175 | } 176 | EXPORT_SYMBOL(__sdfat_msg); 177 | 178 | void sdfat_log_version(void) 179 | { 180 | pr_info("[SDFAT] Filesystem version %s\n", SDFAT_VERSION); 181 | #ifdef CONFIG_SDFAT_SUPPORT_STLOG 182 | ST_LOG("[SDFAT] Filesystem version %s\n", SDFAT_VERSION); 183 | #endif 184 | } 185 | EXPORT_SYMBOL(sdfat_log_version); 186 | 187 | /* externs sys_tz 188 | * extern struct timezone sys_tz; 189 | */ 190 | #define UNIX_SECS_1980 315532800L 191 | 192 | #if BITS_PER_LONG == 64 193 | #define UNIX_SECS_2108 4354819200L 194 | #endif 195 | 196 | /* days between 1970/01/01 and 1980/01/01 (2 leap days) */ 197 | #define DAYS_DELTA_DECADE (365 * 10 + 2) 198 | /* 120 (2100 - 1980) isn't leap year */ 199 | #define NO_LEAP_YEAR_2100 (120) 200 | #define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100) 201 | 202 | #define SECS_PER_MIN (60) 203 | #define SECS_PER_HOUR (60 * SECS_PER_MIN) 204 | #define SECS_PER_DAY (24 * SECS_PER_HOUR) 205 | 206 | #define MAKE_LEAP_YEAR(leap_year, year) \ 207 | do { \ 208 | /* 2100 isn't leap year */ \ 209 | if (unlikely(year > NO_LEAP_YEAR_2100)) \ 210 | leap_year = ((year + 3) / 4) - 1; \ 211 | else \ 212 | leap_year = ((year + 3) / 4); \ 213 | } while (0) 214 | 215 | /* Linear day numbers of the respective 1sts in non-leap years. */ 216 | static time_t accum_days_in_year[] = { 217 | /* Month : N 01 02 03 04 05 06 07 08 09 10 11 12 */ 218 | 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 219 | }; 220 | 221 | #define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN) 222 | /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ 223 | void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, 224 | DATE_TIME_T *tp) 225 | { 226 | time_t year = tp->Year; 227 | time_t ld; /* leap day */ 228 | 229 | MAKE_LEAP_YEAR(ld, year); 230 | 231 | if (IS_LEAP_YEAR(year) && (tp->Month) > 2) 232 | ld++; 233 | 234 | ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN 235 | + tp->Hour * SECS_PER_HOUR 236 | + (year * 365 + ld + accum_days_in_year[tp->Month] 237 | + (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY; 238 | 239 | ts->tv_nsec = 0; 240 | 241 | /* Treat as local time */ 242 | if (!sbi->options.tz_utc && !tp->Timezone.valid) { 243 | ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN; 244 | return; 245 | } 246 | 247 | /* Treat as UTC time */ 248 | if (!tp->Timezone.valid) 249 | return; 250 | 251 | /* Treat as UTC time, but need to adjust timezone to UTC0 */ 252 | if (tp->Timezone.off <= 0x3F) 253 | ts->tv_sec -= TIMEZONE_SEC(tp->Timezone.off); 254 | else /* 0x40 <= (tp->Timezone & 0x7F) <=0x7F */ 255 | ts->tv_sec += TIMEZONE_SEC(0x80 - tp->Timezone.off); 256 | } 257 | 258 | #define TIMEZONE_CUR_OFFSET() ((sys_tz.tz_minuteswest / (-15)) & 0x7F) 259 | /* Convert linear UNIX date to a FAT time/date pair. */ 260 | void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, 261 | DATE_TIME_T *tp) 262 | { 263 | bool tz_valid = (sbi->fsi.vol_type == EXFAT) ? true : false; 264 | time_t second = ts->tv_sec; 265 | time_t day, month, year; 266 | time_t ld; /* leap day */ 267 | 268 | tp->Timezone.value = 0x00; 269 | 270 | /* Treats as local time with proper time */ 271 | if (tz_valid || !sbi->options.tz_utc) { 272 | second -= sys_tz.tz_minuteswest * SECS_PER_MIN; 273 | if (tz_valid) { 274 | tp->Timezone.valid = 1; 275 | tp->Timezone.off = TIMEZONE_CUR_OFFSET(); 276 | } 277 | } 278 | 279 | /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ 280 | if (second < UNIX_SECS_1980) { 281 | tp->Second = 0; 282 | tp->Minute = 0; 283 | tp->Hour = 0; 284 | tp->Day = 1; 285 | tp->Month = 1; 286 | tp->Year = 0; 287 | return; 288 | } 289 | #if (BITS_PER_LONG == 64) 290 | if (second >= UNIX_SECS_2108) { 291 | tp->Second = 59; 292 | tp->Minute = 59; 293 | tp->Hour = 23; 294 | tp->Day = 31; 295 | tp->Month = 12; 296 | tp->Year = 127; 297 | return; 298 | } 299 | #endif 300 | 301 | day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; 302 | year = day / 365; 303 | 304 | MAKE_LEAP_YEAR(ld, year); 305 | if (year * 365 + ld > day) 306 | year--; 307 | 308 | MAKE_LEAP_YEAR(ld, year); 309 | day -= year * 365 + ld; 310 | 311 | if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { 312 | month = 2; 313 | } else { 314 | if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) 315 | day--; 316 | for (month = 1; month < 12; month++) { 317 | if (accum_days_in_year[month + 1] > day) 318 | break; 319 | } 320 | } 321 | day -= accum_days_in_year[month]; 322 | 323 | tp->Second = second % SECS_PER_MIN; 324 | tp->Minute = (second / SECS_PER_MIN) % 60; 325 | tp->Hour = (second / SECS_PER_HOUR) % 24; 326 | tp->Day = day + 1; 327 | tp->Month = month; 328 | tp->Year = year; 329 | } 330 | 331 | TIMESTAMP_T *tm_now(struct inode *inode, TIMESTAMP_T *tp) 332 | { 333 | sdfat_timespec_t ts = current_time(inode); 334 | DATE_TIME_T dt; 335 | 336 | sdfat_time_unix2fat(SDFAT_SB(inode->i_sb), &ts, &dt); 337 | 338 | tp->year = dt.Year; 339 | tp->mon = dt.Month; 340 | tp->day = dt.Day; 341 | tp->hour = dt.Hour; 342 | tp->min = dt.Minute; 343 | tp->sec = dt.Second; 344 | tp->tz.value = dt.Timezone.value; 345 | 346 | return tp; 347 | } 348 | 349 | u8 calc_chksum_1byte(void *data, s32 len, u8 chksum) 350 | { 351 | s32 i; 352 | u8 *c = (u8 *) data; 353 | 354 | for (i = 0; i < len; i++, c++) 355 | chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c; 356 | 357 | return chksum; 358 | } 359 | 360 | u16 calc_chksum_2byte(void *data, s32 len, u16 chksum, s32 type) 361 | { 362 | s32 i; 363 | u8 *c = (u8 *) data; 364 | 365 | for (i = 0; i < len; i++, c++) { 366 | if (((i == 2) || (i == 3)) && (type == CS_DIR_ENTRY)) 367 | continue; 368 | chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (u16) *c; 369 | } 370 | return chksum; 371 | } 372 | 373 | #ifdef CONFIG_SDFAT_TRACE_ELAPSED_TIME 374 | struct timeval __t1, __t2; 375 | u32 sdfat_time_current_usec(struct timeval *tv) 376 | { 377 | do_gettimeofday(tv); 378 | return (u32)(tv->tv_sec*1000000 + tv->tv_usec); 379 | } 380 | #endif /* CONFIG_SDFAT_TRACE_ELAPSED_TIME */ 381 | 382 | #ifdef CONFIG_SDFAT_DBG_CAREFUL 383 | /* Check the consistency of i_size_ondisk (FAT32, or flags 0x01 only) */ 384 | void sdfat_debug_check_clusters(struct inode *inode) 385 | { 386 | unsigned int num_clusters; 387 | volatile uint32_t tmp_fat_chain[50]; 388 | volatile int tmp_i = 0; 389 | volatile unsigned int num_clusters_org, tmp_i = 0; 390 | CHAIN_T clu; 391 | FILE_ID_T *fid = &(SDFAT_I(inode)->fid); 392 | FS_INFO_T *fsi = &(SDFAT_SB(inode->i_sb)->fsi); 393 | 394 | if (SDFAT_I(inode)->i_size_ondisk == 0) 395 | num_clusters = 0; 396 | else 397 | num_clusters = ((SDFAT_I(inode)->i_size_ondisk-1) >> fsi->cluster_size_bits) + 1; 398 | 399 | clu.dir = fid->start_clu; 400 | clu.size = num_clusters; 401 | clu.flags = fid->flags; 402 | 403 | num_clusters_org = num_clusters; 404 | 405 | if (clu.flags == 0x03) 406 | return; 407 | 408 | while (num_clusters > 0) { 409 | /* FAT chain logging */ 410 | tmp_fat_chain[tmp_i] = clu.dir; 411 | tmp_i++; 412 | if (tmp_i >= 50) 413 | tmp_i = 0; 414 | 415 | BUG_ON(IS_CLUS_EOF(clu.dir) || IS_CLUS_FREE(clu.dir)); 416 | 417 | if (get_next_clus_safe(inode->i_sb, &(clu.dir))) 418 | EMSG("%s: failed to access to FAT\n"); 419 | 420 | num_clusters--; 421 | } 422 | 423 | BUG_ON(!IS_CLUS_EOF(clu.dir)); 424 | } 425 | 426 | #endif /* CONFIG_SDFAT_DBG_CAREFUL */ 427 | 428 | #ifdef CONFIG_SDFAT_DBG_MSG 429 | void __sdfat_dmsg(int level, const char *fmt, ...) 430 | { 431 | #ifdef CONFIG_SDFAT_DBG_SHOW_PID 432 | struct va_format vaf; 433 | va_list args; 434 | 435 | /* should check type */ 436 | if (level > SDFAT_MSG_LEVEL) 437 | return; 438 | 439 | va_start(args, fmt); 440 | vaf.fmt = fmt; 441 | vaf.va = &args; 442 | /* fmt already includes KERN_ pacility level */ 443 | printk("[%u] %pV", current->pid, &vaf); 444 | va_end(args); 445 | #else 446 | va_list args; 447 | 448 | /* should check type */ 449 | if (level > SDFAT_MSG_LEVEL) 450 | return; 451 | 452 | va_start(args, fmt); 453 | /* fmt already includes KERN_ pacility level */ 454 | vprintk(fmt, args); 455 | va_end(args); 456 | #endif 457 | } 458 | #endif 459 | 460 | -------------------------------------------------------------------------------- /mpage.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fs/mpage.c 3 | * 4 | * Copyright (C) 2002, Linus Torvalds. 5 | * 6 | * Contains functions related to preparing and submitting BIOs which contain 7 | * multiple pagecache pages. 8 | * 9 | * 15May2002 Andrew Morton 10 | * Initial version 11 | * 27Jun2002 axboe@suse.de 12 | * use bio_add_page() to build bio's just the right size 13 | */ 14 | 15 | /* 16 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 17 | * 18 | * This program is free software; you can redistribute it and/or 19 | * modify it under the terms of the GNU General Public License 20 | * as published by the Free Software Foundation; either version 2 21 | * of the License, or (at your option) any later version. 22 | * 23 | * This program is distributed in the hope that it will be useful, 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | * GNU General Public License for more details. 27 | * 28 | * You should have received a copy of the GNU General Public License 29 | * along with this program; if not, see . 30 | */ 31 | 32 | /************************************************************************/ 33 | /* */ 34 | /* PROJECT : exFAT & FAT12/16/32 File System */ 35 | /* FILE : core.c */ 36 | /* PURPOSE : sdFAT glue layer for supporting VFS */ 37 | /* */ 38 | /*----------------------------------------------------------------------*/ 39 | /* NOTES */ 40 | /* */ 41 | /* */ 42 | /************************************************************************/ 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include /* for mark_page_accessed() */ 63 | #include 64 | #include 65 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) 66 | #include 67 | #endif 68 | 69 | #include "sdfat.h" 70 | 71 | #ifdef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE 72 | 73 | #define MIN_ALIGNED_SIZE (PAGE_SIZE) 74 | #define MIN_ALIGNED_SIZE_MASK (MIN_ALIGNED_SIZE - 1) 75 | 76 | /************************************************************************* 77 | * INNER FUNCTIONS FOR FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY 78 | *************************************************************************/ 79 | static void __mpage_write_end_io(struct bio *bio, int err); 80 | 81 | /************************************************************************* 82 | * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY 83 | *************************************************************************/ 84 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) 85 | /* EMPTY */ 86 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */ 87 | static inline void bio_set_dev(struct bio *bio, struct block_device *bdev) 88 | { 89 | bio->bi_bdev = bdev; 90 | } 91 | #endif 92 | 93 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) 94 | static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_t block) 95 | { 96 | clean_bdev_aliases(bdev, block, 1); 97 | } 98 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) */ 99 | static inline void __sdfat_clean_bdev_aliases(struct block_device *bdev, sector_t block) 100 | { 101 | unmap_underlying_metadata(bdev, block); 102 | } 103 | 104 | static inline int wbc_to_write_flags(struct writeback_control *wbc) 105 | { 106 | if (wbc->sync_mode == WB_SYNC_ALL) 107 | return WRITE_SYNC; 108 | 109 | return 0; 110 | } 111 | #endif 112 | 113 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0) 114 | static inline void __sdfat_submit_bio_write2(int flags, struct bio *bio) 115 | { 116 | bio_set_op_attrs(bio, REQ_OP_WRITE, flags); 117 | submit_bio(bio); 118 | } 119 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) */ 120 | static inline void __sdfat_submit_bio_write2(int flags, struct bio *bio) 121 | { 122 | submit_bio(WRITE | flags, bio); 123 | } 124 | #endif 125 | 126 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) 127 | static inline int bio_get_nr_vecs(struct block_device *bdev) 128 | { 129 | return BIO_MAX_PAGES; 130 | } 131 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) */ 132 | /* EMPTY */ 133 | #endif 134 | 135 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) 136 | static inline sector_t __sdfat_bio_sector(struct bio *bio) 137 | { 138 | return bio->bi_iter.bi_sector; 139 | } 140 | 141 | static inline void __sdfat_set_bio_sector(struct bio *bio, sector_t sector) 142 | { 143 | bio->bi_iter.bi_sector = sector; 144 | } 145 | 146 | static inline unsigned int __sdfat_bio_size(struct bio *bio) 147 | { 148 | return bio->bi_iter.bi_size; 149 | } 150 | 151 | static inline void __sdfat_set_bio_size(struct bio *bio, unsigned int size) 152 | { 153 | bio->bi_iter.bi_size = size; 154 | } 155 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */ 156 | static inline sector_t __sdfat_bio_sector(struct bio *bio) 157 | { 158 | return bio->bi_sector; 159 | } 160 | 161 | static inline void __sdfat_set_bio_sector(struct bio *bio, sector_t sector) 162 | { 163 | bio->bi_sector = sector; 164 | } 165 | 166 | static inline unsigned int __sdfat_bio_size(struct bio *bio) 167 | { 168 | return bio->bi_size; 169 | } 170 | 171 | static inline void __sdfat_set_bio_size(struct bio *bio, unsigned int size) 172 | { 173 | bio->bi_size = size; 174 | } 175 | #endif 176 | 177 | /************************************************************************* 178 | * MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY 179 | *************************************************************************/ 180 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) 181 | static void mpage_write_end_io(struct bio *bio) 182 | { 183 | __mpage_write_end_io(bio, blk_status_to_errno(bio->bi_status)); 184 | } 185 | #elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) 186 | static void mpage_write_end_io(struct bio *bio) 187 | { 188 | __mpage_write_end_io(bio, bio->bi_error); 189 | } 190 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) */ 191 | static void mpage_write_end_io(struct bio *bio, int err) 192 | { 193 | if (test_bit(BIO_UPTODATE, &bio->bi_flags)) 194 | err = 0; 195 | __mpage_write_end_io(bio, err); 196 | } 197 | #endif 198 | 199 | /* __check_dfr_on() and __dfr_writepage_end_io() functions 200 | * are copied from sdfat.c 201 | * Each function should be same perfectly 202 | */ 203 | static inline int __check_dfr_on(struct inode *inode, loff_t start, loff_t end, const char *fname) 204 | { 205 | #ifdef CONFIG_SDFAT_DFR 206 | struct defrag_info *ino_dfr = &(SDFAT_I(inode)->dfr_info); 207 | 208 | if ((atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) && 209 | fsapi_dfr_check_dfr_on(inode, start, end, 0, fname)) 210 | return 1; 211 | #endif 212 | return 0; 213 | } 214 | 215 | static inline int __dfr_writepage_end_io(struct page *page) 216 | { 217 | #ifdef CONFIG_SDFAT_DFR 218 | struct defrag_info *ino_dfr = &(SDFAT_I(page->mapping->host)->dfr_info); 219 | 220 | if (atomic_read(&ino_dfr->stat) == DFR_INO_STAT_REQ) 221 | fsapi_dfr_writepage_endio(page); 222 | #endif 223 | return 0; 224 | } 225 | 226 | 227 | static inline unsigned int __calc_size_to_align(struct super_block *sb) 228 | { 229 | struct block_device *bdev = sb->s_bdev; 230 | struct gendisk *disk; 231 | struct request_queue *queue; 232 | struct queue_limits *limit; 233 | unsigned int max_sectors; 234 | unsigned int aligned = 0; 235 | 236 | disk = bdev->bd_disk; 237 | if (!disk) 238 | goto out; 239 | 240 | queue = disk->queue; 241 | if (!queue) 242 | goto out; 243 | 244 | limit = &queue->limits; 245 | max_sectors = limit->max_sectors; 246 | aligned = 1 << ilog2(max_sectors); 247 | 248 | if (aligned && (max_sectors & (aligned - 1))) 249 | aligned = 0; 250 | 251 | if (aligned && aligned < (MIN_ALIGNED_SIZE >> SECTOR_SIZE_BITS)) 252 | aligned = 0; 253 | out: 254 | return aligned; 255 | } 256 | 257 | struct mpage_data { 258 | struct bio *bio; 259 | sector_t last_block_in_bio; 260 | get_block_t *get_block; 261 | unsigned int use_writepage; 262 | unsigned int size_to_align; 263 | }; 264 | 265 | /* 266 | * After completing I/O on a page, call this routine to update the page 267 | * flags appropriately 268 | */ 269 | static void __page_write_endio(struct page *page, int err) 270 | { 271 | if (err) { 272 | struct address_space *mapping; 273 | 274 | SetPageError(page); 275 | mapping = page_mapping(page); 276 | if (mapping) 277 | mapping_set_error(mapping, err); 278 | } 279 | __dfr_writepage_end_io(page); 280 | end_page_writeback(page); 281 | } 282 | 283 | /* 284 | * I/O completion handler for multipage BIOs. 285 | * 286 | * The mpage code never puts partial pages into a BIO (except for end-of-file). 287 | * If a page does not map to a contiguous run of blocks then it simply falls 288 | * back to block_read_full_page(). 289 | * 290 | * Why is this? If a page's completion depends on a number of different BIOs 291 | * which can complete in any order (or at the same time) then determining the 292 | * status of that page is hard. See end_buffer_async_read() for the details. 293 | * There is no point in duplicating all that complexity. 294 | */ 295 | static void __mpage_write_end_io(struct bio *bio, int err) 296 | { 297 | struct bio_vec *bv; 298 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0) 299 | struct bvec_iter_all iter_all; 300 | 301 | ASSERT(bio_data_dir(bio) == WRITE); /* only write */ 302 | 303 | /* Use bio_for_each_segemnt_all() to support multi-page bvec */ 304 | bio_for_each_segment_all(bv, bio, iter_all) 305 | __page_write_endio(bv->bv_page, err); 306 | #elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) 307 | struct bvec_iter_all iter_all; 308 | int i; 309 | 310 | ASSERT(bio_data_dir(bio) == WRITE); /* only write */ 311 | 312 | /* Use bio_for_each_segemnt_all() to support multi-page bvec */ 313 | bio_for_each_segment_all(bv, bio, i, iter_all) 314 | __page_write_endio(bv->bv_page, err); 315 | #else 316 | ASSERT(bio_data_dir(bio) == WRITE); /* only write */ 317 | bv = bio->bi_io_vec + bio->bi_vcnt - 1; 318 | 319 | do { 320 | struct page *page = bv->bv_page; 321 | 322 | if (--bv >= bio->bi_io_vec) 323 | prefetchw(&bv->bv_page->flags); 324 | 325 | __page_write_endio(page, err); 326 | } while (bv >= bio->bi_io_vec); 327 | #endif 328 | bio_put(bio); 329 | } 330 | 331 | static struct bio *mpage_bio_submit_write(int flags, struct bio *bio) 332 | { 333 | bio->bi_end_io = mpage_write_end_io; 334 | __sdfat_submit_bio_write2(flags, bio); 335 | return NULL; 336 | } 337 | 338 | static struct bio * 339 | mpage_alloc(struct block_device *bdev, 340 | sector_t first_sector, int nr_vecs, 341 | gfp_t gfp_flags) 342 | { 343 | struct bio *bio; 344 | 345 | bio = bio_alloc(gfp_flags, nr_vecs); 346 | 347 | if (bio == NULL && (current->flags & PF_MEMALLOC)) { 348 | while (!bio && (nr_vecs /= 2)) 349 | bio = bio_alloc(gfp_flags, nr_vecs); 350 | } 351 | 352 | if (bio) { 353 | bio_set_dev(bio, bdev); 354 | __sdfat_set_bio_sector(bio, first_sector); 355 | } 356 | return bio; 357 | } 358 | 359 | 360 | #if IS_BUILTIN(CONFIG_SDFAT_FS) 361 | #define __write_boundary_block write_boundary_block 362 | #define sdfat_buffer_heads_over_limit buffer_heads_over_limit 363 | #else 364 | 365 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) 366 | /* 367 | * Called when we've recently written block `bblock', and it is known that 368 | * `bblock' was for a buffer_boundary() buffer. This means that the block at 369 | * `bblock + 1' is probably a dirty indirect block. Hunt it down and, if it's 370 | * dirty, schedule it for IO. So that indirects merge nicely with their data. 371 | */ 372 | static void __write_boundary_block(struct block_device *bdev, 373 | sector_t bblock, unsigned int blocksize) 374 | { 375 | struct buffer_head *bh = __find_get_block(bdev, bblock + 1, blocksize); 376 | 377 | if (bh) { 378 | if (buffer_dirty(bh)) 379 | ll_rw_block(REQ_OP_WRITE, 0, 1, &bh); 380 | put_bh(bh); 381 | } 382 | } 383 | #else 384 | #warning "Need an alternative of write_boundary_block function" 385 | #define __write_boundary_block write_boundary_block 386 | #endif 387 | 388 | #warning "sdfat could not check buffer_heads_over_limit on module. Assumed zero" 389 | #define sdfat_buffer_heads_over_limit (0) 390 | #endif 391 | 392 | static void clean_buffers(struct page *page, unsigned int first_unmapped) 393 | { 394 | unsigned int buffer_counter = 0; 395 | struct buffer_head *bh, *head; 396 | 397 | if (!page_has_buffers(page)) 398 | return; 399 | head = page_buffers(page); 400 | bh = head; 401 | 402 | do { 403 | if (buffer_counter++ == first_unmapped) 404 | break; 405 | clear_buffer_dirty(bh); 406 | bh = bh->b_this_page; 407 | } while (bh != head); 408 | 409 | /* 410 | * we cannot drop the bh if the page is not uptodate or a concurrent 411 | * readpage would fail to serialize with the bh and it would read from 412 | * disk before we reach the platter. 413 | */ 414 | if (sdfat_buffer_heads_over_limit && PageUptodate(page)) 415 | try_to_free_buffers(page); 416 | } 417 | 418 | static int sdfat_mpage_writepage(struct page *page, 419 | struct writeback_control *wbc, void *data) 420 | { 421 | struct mpage_data *mpd = data; 422 | struct bio *bio = mpd->bio; 423 | struct address_space *mapping = page->mapping; 424 | struct inode *inode = page->mapping->host; 425 | const unsigned int blkbits = inode->i_blkbits; 426 | const unsigned int blocks_per_page = PAGE_SIZE >> blkbits; 427 | sector_t last_block; 428 | sector_t block_in_file; 429 | sector_t blocks[MAX_BUF_PER_PAGE]; 430 | unsigned int page_block; 431 | unsigned int first_unmapped = blocks_per_page; 432 | struct block_device *bdev = NULL; 433 | int boundary = 0; 434 | sector_t boundary_block = 0; 435 | struct block_device *boundary_bdev = NULL; 436 | int length; 437 | struct buffer_head map_bh; 438 | loff_t i_size = i_size_read(inode); 439 | unsigned long end_index = i_size >> PAGE_SHIFT; 440 | int ret = 0; 441 | int op_flags = wbc_to_write_flags(wbc); 442 | 443 | if (page_has_buffers(page)) { 444 | struct buffer_head *head = page_buffers(page); 445 | struct buffer_head *bh = head; 446 | 447 | /* If they're all mapped and dirty, do it */ 448 | page_block = 0; 449 | do { 450 | BUG_ON(buffer_locked(bh)); 451 | if (!buffer_mapped(bh)) { 452 | /* 453 | * unmapped dirty buffers are created by 454 | * __set_page_dirty_buffers -> mmapped data 455 | */ 456 | if (buffer_dirty(bh)) 457 | goto confused; 458 | if (first_unmapped == blocks_per_page) 459 | first_unmapped = page_block; 460 | continue; 461 | } 462 | 463 | if (first_unmapped != blocks_per_page) 464 | goto confused; /* hole -> non-hole */ 465 | 466 | if (!buffer_dirty(bh) || !buffer_uptodate(bh)) 467 | goto confused; 468 | 469 | /* bh should be mapped if delay is set */ 470 | if (buffer_delay(bh)) { 471 | sector_t blk_in_file = 472 | (sector_t)(page->index << (PAGE_SHIFT - blkbits)) + page_block; 473 | 474 | BUG_ON(bh->b_size != (1 << blkbits)); 475 | if (page->index > end_index) { 476 | MMSG("%s(inode:%p) " 477 | "over end with delayed buffer" 478 | "(page_idx:%u, end_idx:%u)\n", 479 | __func__, inode, 480 | (u32)page->index, 481 | (u32)end_index); 482 | goto confused; 483 | } 484 | 485 | ret = mpd->get_block(inode, blk_in_file, bh, 1); 486 | if (ret) { 487 | MMSG("%s(inode:%p) " 488 | "failed to getblk(ret:%d)\n", 489 | __func__, inode, ret); 490 | goto confused; 491 | } 492 | 493 | BUG_ON(buffer_delay(bh)); 494 | 495 | if (buffer_new(bh)) { 496 | clear_buffer_new(bh); 497 | __sdfat_clean_bdev_aliases(bh->b_bdev, bh->b_blocknr); 498 | } 499 | } 500 | 501 | if (page_block) { 502 | if (bh->b_blocknr != blocks[page_block-1] + 1) { 503 | MMSG("%s(inode:%p) pblk(%d) " 504 | "no_seq(prev:%lld, new:%lld)\n", 505 | __func__, inode, page_block, 506 | (u64)blocks[page_block-1], 507 | (u64)bh->b_blocknr); 508 | goto confused; 509 | } 510 | } 511 | blocks[page_block++] = bh->b_blocknr; 512 | boundary = buffer_boundary(bh); 513 | if (boundary) { 514 | boundary_block = bh->b_blocknr; 515 | boundary_bdev = bh->b_bdev; 516 | } 517 | bdev = bh->b_bdev; 518 | } while ((bh = bh->b_this_page) != head); 519 | 520 | if (first_unmapped) 521 | goto page_is_mapped; 522 | 523 | /* 524 | * Page has buffers, but they are all unmapped. The page was 525 | * created by pagein or read over a hole which was handled by 526 | * block_read_full_page(). If this address_space is also 527 | * using mpage_readpages then this can rarely happen. 528 | */ 529 | goto confused; 530 | } 531 | 532 | /* 533 | * The page has no buffers: map it to disk 534 | */ 535 | BUG_ON(!PageUptodate(page)); 536 | block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits); 537 | last_block = (i_size - 1) >> blkbits; 538 | map_bh.b_page = page; 539 | for (page_block = 0; page_block < blocks_per_page; ) { 540 | 541 | map_bh.b_state = 0; 542 | map_bh.b_size = 1 << blkbits; 543 | if (mpd->get_block(inode, block_in_file, &map_bh, 1)) 544 | goto confused; 545 | 546 | if (buffer_new(&map_bh)) 547 | __sdfat_clean_bdev_aliases(map_bh.b_bdev, map_bh.b_blocknr); 548 | if (buffer_boundary(&map_bh)) { 549 | boundary_block = map_bh.b_blocknr; 550 | boundary_bdev = map_bh.b_bdev; 551 | } 552 | 553 | if (page_block) { 554 | if (map_bh.b_blocknr != blocks[page_block-1] + 1) 555 | goto confused; 556 | } 557 | blocks[page_block++] = map_bh.b_blocknr; 558 | boundary = buffer_boundary(&map_bh); 559 | bdev = map_bh.b_bdev; 560 | if (block_in_file == last_block) 561 | break; 562 | block_in_file++; 563 | } 564 | BUG_ON(page_block == 0); 565 | 566 | first_unmapped = page_block; 567 | 568 | page_is_mapped: 569 | if (page->index >= end_index) { 570 | /* 571 | * The page straddles i_size. It must be zeroed out on each 572 | * and every writepage invocation because it may be mmapped. 573 | * "A file is mapped in multiples of the page size. For a file 574 | * that is not a multiple of the page size, the remaining memory 575 | * is zeroed when mapped, and writes to that region are not 576 | * written out to the file." 577 | */ 578 | unsigned int offset = i_size & (PAGE_SIZE - 1); 579 | 580 | if (page->index > end_index || !offset) { 581 | MMSG("%s(inode:%p) over end " 582 | "(page_idx:%u, end_idx:%u off:%u)\n", 583 | __func__, inode, (u32)page->index, 584 | (u32)end_index, (u32)offset); 585 | goto confused; 586 | } 587 | zero_user_segment(page, offset, PAGE_SIZE); 588 | } 589 | 590 | /* 591 | * This page will go to BIO. Do we need to send this BIO off first? 592 | * 593 | * REMARK : added ELSE_IF for ALIGNMENT_MPAGE_WRITE of SDFAT 594 | */ 595 | if (bio) { 596 | if (mpd->last_block_in_bio != blocks[0] - 1) { 597 | bio = mpage_bio_submit_write(op_flags, bio); 598 | } else if (mpd->size_to_align) { 599 | unsigned int mask = mpd->size_to_align - 1; 600 | sector_t max_end_block = 601 | (__sdfat_bio_sector(bio) & ~(mask)) + mask; 602 | 603 | if ((__sdfat_bio_size(bio) & MIN_ALIGNED_SIZE_MASK) && 604 | (mpd->last_block_in_bio == max_end_block)) { 605 | int op_nomerge = op_flags | REQ_NOMERGE; 606 | 607 | MMSG("%s(inode:%p) alignment mpage_bio_submit" 608 | "(start:%u, len:%u size:%u aligned:%u)\n", 609 | __func__, inode, 610 | (unsigned int)__sdfat_bio_sector(bio), 611 | (unsigned int)(mpd->last_block_in_bio - 612 | __sdfat_bio_sector(bio) + 1), 613 | (unsigned int)__sdfat_bio_size(bio), 614 | (unsigned int)mpd->size_to_align); 615 | bio = mpage_bio_submit_write(op_nomerge, bio); 616 | } 617 | } 618 | } 619 | 620 | alloc_new: 621 | if (!bio) { 622 | bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), 623 | bio_get_nr_vecs(bdev), GFP_NOFS|__GFP_HIGH); 624 | if (!bio) 625 | goto confused; 626 | } 627 | 628 | /* 629 | * Must try to add the page before marking the buffer clean or 630 | * the confused fail path above (OOM) will be very confused when 631 | * it finds all bh marked clean (i.e. it will not write anything) 632 | */ 633 | length = first_unmapped << blkbits; 634 | if (bio_add_page(bio, page, length, 0) < length) { 635 | bio = mpage_bio_submit_write(op_flags, bio); 636 | goto alloc_new; 637 | } 638 | 639 | /* 640 | * OK, we have our BIO, so we can now mark the buffers clean. Make 641 | * sure to only clean buffers which we know we'll be writing. 642 | */ 643 | clean_buffers(page, first_unmapped); 644 | 645 | BUG_ON(PageWriteback(page)); 646 | set_page_writeback(page); 647 | 648 | /* 649 | * FIXME FOR DEFRAGMENTATION : CODE REVIEW IS REQUIRED 650 | * 651 | * Turn off MAPPED flag in victim's bh if defrag on. 652 | * Another write_begin can starts after get_block for defrag victims 653 | * called. 654 | * In this case, write_begin calls get_block and get original block 655 | * number and previous defrag will be canceled. 656 | */ 657 | if (unlikely(__check_dfr_on(inode, (loff_t)(page->index << PAGE_SHIFT), 658 | (loff_t)((page->index + 1) << PAGE_SHIFT), __func__))) { 659 | struct buffer_head *head = page_buffers(page); 660 | struct buffer_head *bh = head; 661 | 662 | do { 663 | clear_buffer_mapped(bh); 664 | bh = bh->b_this_page; 665 | } while (bh != head); 666 | } 667 | 668 | unlock_page(page); 669 | if (boundary || (first_unmapped != blocks_per_page)) { 670 | bio = mpage_bio_submit_write(op_flags, bio); 671 | if (boundary_block) { 672 | __write_boundary_block(boundary_bdev, 673 | boundary_block, 1 << blkbits); 674 | } 675 | } else { 676 | mpd->last_block_in_bio = blocks[blocks_per_page - 1]; 677 | } 678 | 679 | goto out; 680 | 681 | confused: 682 | if (bio) 683 | bio = mpage_bio_submit_write(op_flags, bio); 684 | 685 | if (mpd->use_writepage) { 686 | ret = mapping->a_ops->writepage(page, wbc); 687 | } else { 688 | ret = -EAGAIN; 689 | goto out; 690 | } 691 | /* 692 | * The caller has a ref on the inode, so *mapping is stable 693 | */ 694 | mapping_set_error(mapping, ret); 695 | out: 696 | mpd->bio = bio; 697 | return ret; 698 | } 699 | 700 | int sdfat_mpage_writepages(struct address_space *mapping, 701 | struct writeback_control *wbc, get_block_t *get_block) 702 | { 703 | struct blk_plug plug; 704 | int ret; 705 | struct mpage_data mpd = { 706 | .bio = NULL, 707 | .last_block_in_bio = 0, 708 | .get_block = get_block, 709 | .use_writepage = 1, 710 | .size_to_align = __calc_size_to_align(mapping->host->i_sb), 711 | }; 712 | 713 | BUG_ON(!get_block); 714 | blk_start_plug(&plug); 715 | ret = write_cache_pages(mapping, wbc, sdfat_mpage_writepage, &mpd); 716 | if (mpd.bio) { 717 | int op_flags = wbc_to_write_flags(wbc); 718 | 719 | mpage_bio_submit_write(op_flags, mpd.bio); 720 | } 721 | blk_finish_plug(&plug); 722 | return ret; 723 | } 724 | 725 | #endif /* CONFIG_SDFAT_ALIGNED_MPAGE_WRITE */ 726 | 727 | -------------------------------------------------------------------------------- /nls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | /************************************************************************/ 19 | /* */ 20 | /* PROJECT : exFAT & FAT12/16/32 File System */ 21 | /* FILE : nls.c */ 22 | /* PURPOSE : sdFAT NLS Manager */ 23 | /* */ 24 | /*----------------------------------------------------------------------*/ 25 | /* NOTES */ 26 | /* */ 27 | /* */ 28 | /************************************************************************/ 29 | #include 30 | #include 31 | 32 | #include "sdfat.h" 33 | #include "core.h" 34 | 35 | /*----------------------------------------------------------------------*/ 36 | /* Global Variable Definitions */ 37 | /*----------------------------------------------------------------------*/ 38 | 39 | /*----------------------------------------------------------------------*/ 40 | /* Local Variable Definitions */ 41 | /*----------------------------------------------------------------------*/ 42 | 43 | static u16 bad_dos_chars[] = { 44 | /* + , ; = [ ] */ 45 | 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D, 46 | 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D, 47 | 0 48 | }; 49 | 50 | /* 51 | * Allow full-width illegal characters : 52 | * "MS windows 7" supports full-width-invalid-name-characters. 53 | * So we should check half-width-invalid-name-characters(ASCII) only 54 | * for compatibility. 55 | * 56 | * " * / : < > ? \ | 57 | * 58 | * patch 1.2.0 59 | */ 60 | static u16 bad_uni_chars[] = { 61 | 0x0022, 0x002A, 0x002F, 0x003A, 62 | 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, 63 | #if 0 /* allow full-width characters */ 64 | 0x201C, 0x201D, 0xFF0A, 0xFF0F, 0xFF1A, 65 | 0xFF1C, 0xFF1E, 0xFF1F, 0xFF3C, 0xFF5C, 66 | #endif 67 | 0 68 | }; 69 | 70 | /*----------------------------------------------------------------------*/ 71 | /* Local Function Declarations */ 72 | /*----------------------------------------------------------------------*/ 73 | static s32 convert_uni_to_ch(struct nls_table *nls, u16 uni, u8 *ch, s32 *lossy); 74 | static s32 convert_ch_to_uni(struct nls_table *nls, u8 *ch, u16 *uni, s32 *lossy); 75 | 76 | static u16 nls_upper(struct super_block *sb, u16 a) 77 | { 78 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 79 | 80 | if (SDFAT_SB(sb)->options.casesensitive) 81 | return a; 82 | if ((fsi->vol_utbl)[get_col_index(a)] != NULL) 83 | return (fsi->vol_utbl)[get_col_index(a)][get_row_index(a)]; 84 | else 85 | return a; 86 | } 87 | /*======================================================================*/ 88 | /* Global Function Definitions */ 89 | /*======================================================================*/ 90 | u16 *nls_wstrchr(u16 *str, u16 wchar) 91 | { 92 | while (*str) { 93 | if (*(str++) == wchar) 94 | return str; 95 | } 96 | 97 | return 0; 98 | } 99 | 100 | s32 nls_cmp_sfn(struct super_block *sb, u8 *a, u8 *b) 101 | { 102 | return strncmp((void *)a, (void *)b, DOS_NAME_LENGTH); 103 | } 104 | 105 | s32 nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b) 106 | { 107 | s32 i; 108 | 109 | for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { 110 | if (nls_upper(sb, *a) != nls_upper(sb, *b)) 111 | return 1; 112 | if (*a == 0x0) 113 | return 0; 114 | } 115 | return 0; 116 | } 117 | 118 | #define CASE_LOWER_BASE (0x08) /* base is lower case */ 119 | #define CASE_LOWER_EXT (0x10) /* extension is lower case */ 120 | 121 | s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname, s32 *p_lossy) 122 | { 123 | s32 i, j, len, lossy = NLS_NAME_NO_LOSSY; 124 | u8 buf[MAX_CHARSET_SIZE]; 125 | u8 lower = 0, upper = 0; 126 | u8 *dosname = p_dosname->name; 127 | u16 *uniname = p_uniname->name; 128 | u16 *p, *last_period; 129 | struct nls_table *nls = SDFAT_SB(sb)->nls_disk; 130 | 131 | /* DOSNAME is filled with space */ 132 | for (i = 0; i < DOS_NAME_LENGTH; i++) 133 | *(dosname+i) = ' '; 134 | 135 | /* DOT and DOTDOT are handled by VFS layer */ 136 | 137 | /* search for the last embedded period */ 138 | last_period = NULL; 139 | for (p = uniname; *p; p++) { 140 | if (*p == (u16) '.') 141 | last_period = p; 142 | } 143 | 144 | i = 0; 145 | while (i < DOS_NAME_LENGTH) { 146 | if (i == 8) { 147 | if (last_period == NULL) 148 | break; 149 | 150 | if (uniname <= last_period) { 151 | if (uniname < last_period) 152 | lossy |= NLS_NAME_OVERLEN; 153 | uniname = last_period + 1; 154 | } 155 | } 156 | 157 | if (*uniname == (u16) '\0') { 158 | break; 159 | } else if (*uniname == (u16) ' ') { 160 | lossy |= NLS_NAME_LOSSY; 161 | } else if (*uniname == (u16) '.') { 162 | if (uniname < last_period) 163 | lossy |= NLS_NAME_LOSSY; 164 | else 165 | i = 8; 166 | } else if (nls_wstrchr(bad_dos_chars, *uniname)) { 167 | lossy |= NLS_NAME_LOSSY; 168 | *(dosname+i) = '_'; 169 | i++; 170 | } else { 171 | len = convert_uni_to_ch(nls, *uniname, buf, &lossy); 172 | 173 | if (len > 1) { 174 | if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH)) 175 | break; 176 | 177 | if ((i < 8) && ((i+len) > 8)) { 178 | i = 8; 179 | continue; 180 | } 181 | 182 | lower = 0xFF; 183 | 184 | for (j = 0; j < len; j++, i++) 185 | *(dosname+i) = *(buf+j); 186 | } else { /* len == 1 */ 187 | if ((*buf >= 'a') && (*buf <= 'z')) { 188 | *(dosname+i) = *buf - ('a' - 'A'); 189 | 190 | lower |= (i < 8) ? 191 | CASE_LOWER_BASE : 192 | CASE_LOWER_EXT; 193 | } else if ((*buf >= 'A') && (*buf <= 'Z')) { 194 | *(dosname+i) = *buf; 195 | 196 | upper |= (i < 8) ? 197 | CASE_LOWER_BASE : 198 | CASE_LOWER_EXT; 199 | } else { 200 | *(dosname+i) = *buf; 201 | } 202 | i++; 203 | } 204 | } 205 | 206 | uniname++; 207 | } 208 | 209 | if (*dosname == 0xE5) 210 | *dosname = 0x05; 211 | if (*uniname != 0x0) 212 | lossy |= NLS_NAME_OVERLEN; 213 | 214 | if (upper & lower) 215 | p_dosname->name_case = 0xFF; 216 | else 217 | p_dosname->name_case = lower; 218 | 219 | if (p_lossy) 220 | *p_lossy = lossy; 221 | return i; 222 | } 223 | 224 | s32 nls_sfn_to_uni16s(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname) 225 | { 226 | s32 i = 0, j, n = 0; 227 | u8 buf[MAX_DOSNAME_BUF_SIZE]; 228 | u8 *dosname = p_dosname->name; 229 | u16 *uniname = p_uniname->name; 230 | struct nls_table *nls = SDFAT_SB(sb)->nls_disk; 231 | 232 | if (*dosname == 0x05) { 233 | *buf = 0xE5; 234 | i++; 235 | n++; 236 | } 237 | 238 | for ( ; i < 8; i++, n++) { 239 | if (*(dosname+i) == ' ') 240 | break; 241 | 242 | if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && 243 | (p_dosname->name_case & CASE_LOWER_BASE)) 244 | *(buf+n) = *(dosname+i) + ('a' - 'A'); 245 | else 246 | *(buf+n) = *(dosname+i); 247 | } 248 | if (*(dosname+8) != ' ') { 249 | *(buf+n) = '.'; 250 | n++; 251 | } 252 | 253 | for (i = 8; i < DOS_NAME_LENGTH; i++, n++) { 254 | if (*(dosname+i) == ' ') 255 | break; 256 | 257 | if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && 258 | (p_dosname->name_case & CASE_LOWER_EXT)) 259 | *(buf+n) = *(dosname+i) + ('a' - 'A'); 260 | else 261 | *(buf+n) = *(dosname+i); 262 | } 263 | *(buf+n) = '\0'; 264 | 265 | i = j = 0; 266 | while (j < MAX_NAME_LENGTH) { 267 | if (*(buf+i) == '\0') 268 | break; 269 | 270 | i += convert_ch_to_uni(nls, (buf+i), uniname, NULL); 271 | 272 | uniname++; 273 | j++; 274 | } 275 | 276 | *uniname = (u16) '\0'; 277 | return j; 278 | } 279 | 280 | static s32 __nls_utf16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 buflen) 281 | { 282 | s32 len; 283 | const u16 *uniname = p_uniname->name; 284 | 285 | /* always len >= 0 */ 286 | len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, 287 | p_cstring, buflen); 288 | p_cstring[len] = '\0'; 289 | return len; 290 | } 291 | 292 | static s32 __nls_vfsname_to_utf16s(struct super_block *sb, const u8 *p_cstring, 293 | const s32 len, UNI_NAME_T *p_uniname, s32 *p_lossy) 294 | { 295 | s32 i, unilen, lossy = NLS_NAME_NO_LOSSY; 296 | u16 upname[MAX_NAME_LENGTH+1]; 297 | u16 *uniname = p_uniname->name; 298 | 299 | BUG_ON(!len); 300 | 301 | unilen = utf8s_to_utf16s(p_cstring, len, UTF16_HOST_ENDIAN, 302 | (wchar_t *)uniname, MAX_NAME_LENGTH+2); 303 | if (unilen < 0) { 304 | MMSG("%s: failed to vfsname_to_utf16(err:%d) " 305 | "vfsnamelen:%d", __func__, unilen, len); 306 | return unilen; 307 | } 308 | 309 | if (unilen > MAX_NAME_LENGTH) { 310 | MMSG("%s: failed to vfsname_to_utf16(estr:ENAMETOOLONG) " 311 | "vfsnamelen:%d, unilen:%d>%d", 312 | __func__, len, unilen, MAX_NAME_LENGTH); 313 | return -ENAMETOOLONG; 314 | } 315 | 316 | p_uniname->name_len = (u8)(unilen & 0xFF); 317 | 318 | for (i = 0; i < unilen; i++) { 319 | if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname)) 320 | lossy |= NLS_NAME_LOSSY; 321 | 322 | *(upname+i) = nls_upper(sb, *uniname); 323 | uniname++; 324 | } 325 | 326 | *uniname = (u16)'\0'; 327 | p_uniname->name_len = unilen; 328 | p_uniname->name_hash = calc_chksum_2byte((void *) upname, 329 | unilen << 1, 0, CS_DEFAULT); 330 | 331 | if (p_lossy) 332 | *p_lossy = lossy; 333 | 334 | return unilen; 335 | } 336 | 337 | static s32 __nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 buflen) 338 | { 339 | s32 i, j, len, out_len = 0; 340 | u8 buf[MAX_CHARSET_SIZE]; 341 | const u16 *uniname = p_uniname->name; 342 | struct nls_table *nls = SDFAT_SB(sb)->nls_io; 343 | 344 | i = 0; 345 | while ((i < MAX_NAME_LENGTH) && (out_len < (buflen-1))) { 346 | if (*uniname == (u16)'\0') 347 | break; 348 | 349 | len = convert_uni_to_ch(nls, *uniname, buf, NULL); 350 | 351 | if (out_len + len >= buflen) 352 | len = (buflen - 1) - out_len; 353 | 354 | out_len += len; 355 | 356 | if (len > 1) { 357 | for (j = 0; j < len; j++) 358 | *p_cstring++ = (s8) *(buf+j); 359 | } else { /* len == 1 */ 360 | *p_cstring++ = (s8) *buf; 361 | } 362 | 363 | uniname++; 364 | i++; 365 | } 366 | 367 | *p_cstring = '\0'; 368 | return out_len; 369 | } 370 | 371 | static s32 __nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring, 372 | const s32 len, UNI_NAME_T *p_uniname, s32 *p_lossy) 373 | { 374 | s32 i, unilen, lossy = NLS_NAME_NO_LOSSY; 375 | u16 upname[MAX_NAME_LENGTH+1]; 376 | u16 *uniname = p_uniname->name; 377 | struct nls_table *nls = SDFAT_SB(sb)->nls_io; 378 | 379 | BUG_ON(!len); 380 | 381 | i = unilen = 0; 382 | while ((unilen < MAX_NAME_LENGTH) && (i < len)) { 383 | i += convert_ch_to_uni(nls, (u8 *)(p_cstring+i), uniname, &lossy); 384 | 385 | if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname)) 386 | lossy |= NLS_NAME_LOSSY; 387 | 388 | *(upname+unilen) = nls_upper(sb, *uniname); 389 | 390 | uniname++; 391 | unilen++; 392 | } 393 | 394 | if (*(p_cstring+i) != '\0') 395 | lossy |= NLS_NAME_OVERLEN; 396 | 397 | *uniname = (u16)'\0'; 398 | p_uniname->name_len = unilen; 399 | p_uniname->name_hash = 400 | calc_chksum_2byte((void *) upname, unilen<<1, 0, CS_DEFAULT); 401 | 402 | if (p_lossy) 403 | *p_lossy = lossy; 404 | 405 | return unilen; 406 | } 407 | 408 | s32 nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *uniname, u8 *p_cstring, s32 buflen) 409 | { 410 | if (SDFAT_SB(sb)->options.utf8) 411 | return __nls_utf16s_to_vfsname(sb, uniname, p_cstring, buflen); 412 | 413 | return __nls_uni16s_to_vfsname(sb, uniname, p_cstring, buflen); 414 | } 415 | 416 | s32 nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring, const s32 len, UNI_NAME_T *uniname, s32 *p_lossy) 417 | { 418 | if (SDFAT_SB(sb)->options.utf8) 419 | return __nls_vfsname_to_utf16s(sb, p_cstring, len, uniname, p_lossy); 420 | return __nls_vfsname_to_uni16s(sb, p_cstring, len, uniname, p_lossy); 421 | } 422 | 423 | /*======================================================================*/ 424 | /* Local Function Definitions */ 425 | /*======================================================================*/ 426 | 427 | static s32 convert_ch_to_uni(struct nls_table *nls, u8 *ch, u16 *uni, s32 *lossy) 428 | { 429 | int len; 430 | 431 | *uni = 0x0; 432 | 433 | if (ch[0] < 0x80) { 434 | *uni = (u16) ch[0]; 435 | return 1; 436 | } 437 | 438 | len = nls->char2uni(ch, MAX_CHARSET_SIZE, uni); 439 | if (len < 0) { 440 | /* conversion failed */ 441 | DMSG("%s: fail to use nls\n", __func__); 442 | if (lossy != NULL) 443 | *lossy |= NLS_NAME_LOSSY; 444 | *uni = (u16) '_'; 445 | if (!strcmp(nls->charset, "utf8")) 446 | return 1; 447 | return 2; 448 | } 449 | 450 | return len; 451 | } /* end of convert_ch_to_uni */ 452 | 453 | static s32 convert_uni_to_ch(struct nls_table *nls, u16 uni, u8 *ch, s32 *lossy) 454 | { 455 | int len; 456 | 457 | ch[0] = 0x0; 458 | 459 | if (uni < 0x0080) { 460 | ch[0] = (u8) uni; 461 | return 1; 462 | } 463 | 464 | len = nls->uni2char(uni, ch, MAX_CHARSET_SIZE); 465 | if (len < 0) { 466 | /* conversion failed */ 467 | DMSG("%s: fail to use nls\n", __func__); 468 | if (lossy != NULL) 469 | *lossy |= NLS_NAME_LOSSY; 470 | ch[0] = '_'; 471 | return 1; 472 | } 473 | 474 | return len; 475 | 476 | } /* end of convert_uni_to_ch */ 477 | 478 | /* end of nls.c */ 479 | -------------------------------------------------------------------------------- /sdfat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | #ifndef _SDFAT_H 19 | #define _SDFAT_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "api.h" 31 | 32 | #ifdef CONFIG_SDFAT_DFR 33 | #include "dfr.h" 34 | #endif 35 | 36 | /* 37 | * sdfat error flags 38 | */ 39 | #define SDFAT_ERRORS_CONT (1) /* ignore error and continue */ 40 | #define SDFAT_ERRORS_PANIC (2) /* panic on error */ 41 | #define SDFAT_ERRORS_RO (3) /* remount r/o on error */ 42 | 43 | /* 44 | * sdfat allocator flags 45 | */ 46 | #define SDFAT_ALLOC_DELAY (1) /* Delayed allocation */ 47 | #define SDFAT_ALLOC_SMART (2) /* Smart allocation */ 48 | 49 | /* 50 | * sdfat allocator destination for smart allocation 51 | */ 52 | #define ALLOC_NOWHERE (0) 53 | #define ALLOC_COLD (1) 54 | #define ALLOC_HOT (16) 55 | #define ALLOC_COLD_ALIGNED (1) 56 | #define ALLOC_COLD_PACKING (2) 57 | #define ALLOC_COLD_SEQ (4) 58 | 59 | /* 60 | * sdfat nls lossy flag 61 | */ 62 | #define NLS_NAME_NO_LOSSY (0x00) /* no lossy */ 63 | #define NLS_NAME_LOSSY (0x01) /* just detected incorrect filename(s) */ 64 | #define NLS_NAME_OVERLEN (0x02) /* the length is over than its limit */ 65 | 66 | /* 67 | * sdfat common MACRO 68 | */ 69 | #define CLUSTER_16(x) ((u16)((x) & 0xFFFFU)) 70 | #define CLUSTER_32(x) ((u32)((x) & 0xFFFFFFFFU)) 71 | #define CLUS_EOF CLUSTER_32(~0) 72 | #define CLUS_BAD (0xFFFFFFF7U) 73 | #define CLUS_FREE (0) 74 | #define CLUS_BASE (2) 75 | #define IS_CLUS_EOF(x) ((x) == CLUS_EOF) 76 | #define IS_CLUS_BAD(x) ((x) == CLUS_BAD) 77 | #define IS_CLUS_FREE(x) ((x) == CLUS_FREE) 78 | #define IS_LAST_SECT_IN_CLUS(fsi, sec) \ 79 | ((((sec) - (fsi)->data_start_sector + 1) \ 80 | & ((1 << (fsi)->sect_per_clus_bits) - 1)) == 0) 81 | 82 | #define CLUS_TO_SECT(fsi, x) \ 83 | ((((unsigned long long)(x) - CLUS_BASE) << (fsi)->sect_per_clus_bits) + (fsi)->data_start_sector) 84 | 85 | #define SECT_TO_CLUS(fsi, sec) \ 86 | ((u32)((((sec) - (fsi)->data_start_sector) >> (fsi)->sect_per_clus_bits) + CLUS_BASE)) 87 | 88 | /* variables defined at sdfat.c */ 89 | extern const char *FS_TYPE_STR[]; 90 | 91 | enum { 92 | FS_TYPE_AUTO, 93 | FS_TYPE_EXFAT, 94 | FS_TYPE_VFAT, 95 | FS_TYPE_MAX 96 | }; 97 | 98 | /* 99 | * sdfat mount in-memory data 100 | */ 101 | struct sdfat_mount_options { 102 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0) 103 | kuid_t fs_uid; 104 | kgid_t fs_gid; 105 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) */ 106 | uid_t fs_uid; 107 | gid_t fs_gid; 108 | #endif 109 | unsigned short fs_fmask; 110 | unsigned short fs_dmask; 111 | unsigned short allow_utime; /* permission for setting the [am]time */ 112 | unsigned short codepage; /* codepage for shortname conversions */ 113 | char *iocharset; /* charset for filename input/display */ 114 | struct { 115 | unsigned int pack_ratio; 116 | unsigned int sect_per_au; 117 | unsigned int misaligned_sect; 118 | } amap_opt; /* AMAP-related options (see amap.c) */ 119 | 120 | unsigned char utf8; 121 | unsigned char casesensitive; 122 | unsigned char adj_hidsect; 123 | unsigned char tz_utc; 124 | unsigned char improved_allocation; 125 | unsigned char defrag; 126 | unsigned char symlink; /* support symlink operation */ 127 | unsigned char errors; /* on error: continue, panic, remount-ro */ 128 | unsigned char discard; /* flag on if -o dicard specified and device support discard() */ 129 | unsigned char fs_type; /* fs_type that user specified */ 130 | unsigned short adj_req; /* support aligned mpage write */ 131 | }; 132 | 133 | #define SDFAT_HASH_BITS 8 134 | #define SDFAT_HASH_SIZE (1UL << SDFAT_HASH_BITS) 135 | 136 | /* 137 | * SDFAT file system superblock in-memory data 138 | */ 139 | struct sdfat_sb_info { 140 | FS_INFO_T fsi; /* private filesystem info */ 141 | 142 | struct mutex s_vlock; /* volume lock */ 143 | int use_vmalloc; 144 | 145 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) 146 | struct rcu_head rcu; 147 | #endif 148 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) 149 | int s_dirt; 150 | struct mutex s_lock; /* superblock lock */ 151 | int write_super_queued; /* Write_super work is pending? */ 152 | struct delayed_work write_super_work; /* Work_queue data structrue for write_super() */ 153 | spinlock_t work_lock; /* Lock for WQ */ 154 | #endif 155 | struct super_block *host_sb; /* sb pointer */ 156 | struct sdfat_mount_options options; 157 | struct nls_table *nls_disk; /* Codepage used on disk */ 158 | struct nls_table *nls_io; /* Charset used for input and display */ 159 | struct ratelimit_state ratelimit; 160 | 161 | spinlock_t inode_hash_lock; 162 | struct hlist_head inode_hashtable[SDFAT_HASH_SIZE]; 163 | struct kobject sb_kobj; 164 | #ifdef CONFIG_SDFAT_DBG_IOCTL 165 | long debug_flags; 166 | #endif /* CONFIG_SDFAT_DBG_IOCTL */ 167 | 168 | #ifdef CONFIG_SDFAT_DFR 169 | struct defrag_info dfr_info; 170 | struct completion dfr_complete; 171 | unsigned int *dfr_new_clus; 172 | int dfr_new_idx; 173 | unsigned int *dfr_page_wb; 174 | void **dfr_pagep; 175 | unsigned int dfr_hint_clus; 176 | unsigned int dfr_hint_idx; 177 | int dfr_reserved_clus; 178 | 179 | #ifdef CONFIG_SDFAT_DFR_DEBUG 180 | int dfr_spo_flag; 181 | #endif /* CONFIG_SDFAT_DFR_DEBUG */ 182 | 183 | #endif /* CONFIG_SDFAT_DFR */ 184 | 185 | #ifdef CONFIG_SDFAT_TRACE_IO 186 | /* Statistics for allocator */ 187 | unsigned int stat_n_pages_written; /* # of written pages in total */ 188 | unsigned int stat_n_pages_added; /* # of added blocks in total */ 189 | unsigned int stat_n_bdev_pages_written; /* # of written pages owned by bdev inode */ 190 | unsigned int stat_n_pages_confused; 191 | #endif 192 | atomic_t stat_n_pages_queued; /* # of pages in the request queue (approx.) */ 193 | }; 194 | 195 | /* 196 | * SDFAT file system inode in-memory data 197 | */ 198 | struct sdfat_inode_info { 199 | FILE_ID_T fid; 200 | char *target; 201 | /* NOTE: i_size_ondisk is 64bits, so must hold ->inode_lock to access */ 202 | loff_t i_size_ondisk; /* physically allocated size */ 203 | loff_t i_size_aligned; /* block-aligned i_size (used in cont_write_begin) */ 204 | loff_t i_pos; /* on-disk position of directory entry or 0 */ 205 | struct hlist_node i_hash_fat; /* hash by i_location */ 206 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) 207 | struct rw_semaphore truncate_lock; /* protect bmap against truncate */ 208 | #endif 209 | #ifdef CONFIG_SDFAT_DFR 210 | struct defrag_info dfr_info; 211 | #endif 212 | struct inode vfs_inode; 213 | }; 214 | 215 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) 216 | typedef struct timespec64 sdfat_timespec_t; 217 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) */ 218 | typedef struct timespec sdfat_timespec_t; 219 | #endif 220 | 221 | 222 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) 223 | 224 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */ 225 | /* 226 | * sb->s_flags. Note that these mirror the equivalent MS_* flags where 227 | * represented in both. 228 | */ 229 | #define SB_RDONLY 1 /* Mount read-only */ 230 | #define SB_NODIRATIME 2048 /* Do not update directory access times */ 231 | static inline bool sb_rdonly(const struct super_block *sb) 232 | { 233 | return sb->s_flags & MS_RDONLY; 234 | } 235 | #endif 236 | 237 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) 238 | /* EMPTY */ 239 | #else 240 | static inline sdfat_timespec_t current_time(struct inode *inode) 241 | { 242 | return CURRENT_TIME_SEC; 243 | } 244 | #endif 245 | /* 246 | * FIXME : needs on-disk-slot in-memory data 247 | */ 248 | 249 | /* static inline functons */ 250 | static inline const char *sdfat_get_vol_type_str(unsigned int type) 251 | { 252 | if (type == EXFAT) 253 | return "exfat"; 254 | else if (type == FAT32) 255 | return "vfat:32"; 256 | else if (type == FAT16) 257 | return "vfat:16"; 258 | else if (type == FAT12) 259 | return "vfat:12"; 260 | 261 | return "unknown"; 262 | } 263 | 264 | static inline struct sdfat_sb_info *SDFAT_SB(struct super_block *sb) 265 | { 266 | return (struct sdfat_sb_info *)sb->s_fs_info; 267 | } 268 | 269 | static inline struct sdfat_inode_info *SDFAT_I(struct inode *inode) 270 | { 271 | return container_of(inode, struct sdfat_inode_info, vfs_inode); 272 | } 273 | 274 | /* 275 | * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to 276 | * save ATTR_RO instead of ->i_mode. 277 | * 278 | * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only 279 | * bit, it's just used as flag for app. 280 | */ 281 | static inline int sdfat_mode_can_hold_ro(struct inode *inode) 282 | { 283 | struct sdfat_sb_info *sbi = SDFAT_SB(inode->i_sb); 284 | 285 | if (S_ISDIR(inode->i_mode)) 286 | return 0; 287 | 288 | if ((~sbi->options.fs_fmask) & S_IWUGO) 289 | return 1; 290 | return 0; 291 | } 292 | 293 | /* 294 | * FIXME : needs to check symlink option. 295 | */ 296 | /* Convert attribute bits and a mask to the UNIX mode. */ 297 | static inline mode_t sdfat_make_mode(struct sdfat_sb_info *sbi, 298 | u32 attr, mode_t mode) 299 | { 300 | if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) 301 | mode &= ~S_IWUGO; 302 | 303 | if (attr & ATTR_SUBDIR) 304 | return (mode & ~sbi->options.fs_dmask) | S_IFDIR; 305 | else if (attr & ATTR_SYMLINK) 306 | return (mode & ~sbi->options.fs_dmask) | S_IFLNK; 307 | else 308 | return (mode & ~sbi->options.fs_fmask) | S_IFREG; 309 | } 310 | 311 | /* Return the FAT attribute byte for this inode */ 312 | static inline u32 sdfat_make_attr(struct inode *inode) 313 | { 314 | u32 attrs = SDFAT_I(inode)->fid.attr; 315 | 316 | if (S_ISDIR(inode->i_mode)) 317 | attrs |= ATTR_SUBDIR; 318 | if (sdfat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO)) 319 | attrs |= ATTR_READONLY; 320 | return attrs; 321 | } 322 | 323 | static inline void sdfat_save_attr(struct inode *inode, u32 attr) 324 | { 325 | if (sdfat_mode_can_hold_ro(inode)) 326 | SDFAT_I(inode)->fid.attr = attr & ATTR_RWMASK; 327 | else 328 | SDFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY); 329 | } 330 | 331 | /* sdfat/statistics.c */ 332 | /* bigdata function */ 333 | #ifdef CONFIG_SDFAT_STATISTICS 334 | extern int sdfat_statistics_init(struct kset *sdfat_kset); 335 | extern void sdfat_statistics_uninit(void); 336 | extern void sdfat_statistics_set_mnt(FS_INFO_T *fsi); 337 | extern void sdfat_statistics_set_mnt_ro(void); 338 | extern void sdfat_statistics_set_mkdir(u8 flags); 339 | extern void sdfat_statistics_set_create(u8 flags); 340 | extern void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create); 341 | extern void sdfat_statistics_set_trunc(u8 flags, CHAIN_T *clu); 342 | extern void sdfat_statistics_set_vol_size(struct super_block *sb); 343 | #else 344 | static inline int sdfat_statistics_init(struct kset *sdfat_kset) 345 | { 346 | return 0; 347 | } 348 | static inline void sdfat_statistics_uninit(void) {}; 349 | static inline void sdfat_statistics_set_mnt(FS_INFO_T *fsi) {}; 350 | static inline void sdfat_statistics_set_mnt_ro(void) {}; 351 | static inline void sdfat_statistics_set_mkdir(u8 flags) {}; 352 | static inline void sdfat_statistics_set_create(u8 flags) {}; 353 | static inline void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create) {}; 354 | static inline void sdfat_statistics_set_trunc(u8 flags, CHAIN_T *clu) {}; 355 | static inline void sdfat_statistics_set_vol_size(struct super_block *sb) {}; 356 | #endif 357 | 358 | /* sdfat/nls.c */ 359 | /* NLS management function */ 360 | s32 nls_cmp_sfn(struct super_block *sb, u8 *a, u8 *b); 361 | s32 nls_cmp_uniname(struct super_block *sb, u16 *a, u16 *b); 362 | s32 nls_uni16s_to_sfn(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname, s32 *p_lossy); 363 | s32 nls_sfn_to_uni16s(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname); 364 | s32 nls_uni16s_to_vfsname(struct super_block *sb, UNI_NAME_T *uniname, u8 *p_cstring, s32 len); 365 | s32 nls_vfsname_to_uni16s(struct super_block *sb, const u8 *p_cstring, 366 | const s32 len, UNI_NAME_T *uniname, s32 *p_lossy); 367 | 368 | /* sdfat/mpage.c */ 369 | #ifdef CONFIG_SDFAT_ALIGNED_MPAGE_WRITE 370 | int sdfat_mpage_writepages(struct address_space *mapping, 371 | struct writeback_control *wbc, get_block_t *get_block); 372 | #endif 373 | 374 | /* sdfat/xattr.c */ 375 | #ifdef CONFIG_SDFAT_VIRTUAL_XATTR 376 | void setup_sdfat_xattr_handler(struct super_block *sb); 377 | extern int sdfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); 378 | extern ssize_t sdfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size); 379 | extern ssize_t sdfat_listxattr(struct dentry *dentry, char *list, size_t size); 380 | extern int sdfat_removexattr(struct dentry *dentry, const char *name); 381 | #else 382 | static inline void setup_sdfat_xattr_handler(struct super_block *sb) {}; 383 | #endif 384 | 385 | /* sdfat/misc.c */ 386 | #ifdef CONFIG_SDFAT_UEVENT 387 | extern int sdfat_uevent_init(struct kset *sdfat_kset); 388 | extern void sdfat_uevent_uninit(void); 389 | extern void sdfat_uevent_ro_remount(struct super_block *sb); 390 | #else 391 | static inline int sdfat_uevent_init(struct kset *sdfat_kset) 392 | { 393 | return 0; 394 | } 395 | static inline void sdfat_uevent_uninit(void) {}; 396 | static inline void sdfat_uevent_ro_remount(struct super_block *sb) {}; 397 | #endif 398 | extern void 399 | __sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...) 400 | __printf(3, 4) __cold; 401 | #define sdfat_fs_error(sb, fmt, args...) \ 402 | __sdfat_fs_error(sb, 1, fmt, ## args) 403 | #define sdfat_fs_error_ratelimit(sb, fmt, args...) \ 404 | __sdfat_fs_error(sb, __ratelimit(&SDFAT_SB(sb)->ratelimit), fmt, ## args) 405 | extern void 406 | __sdfat_msg(struct super_block *sb, const char *lv, int st, const char *fmt, ...) 407 | __printf(4, 5) __cold; 408 | #define sdfat_msg(sb, lv, fmt, args...) \ 409 | __sdfat_msg(sb, lv, 0, fmt, ## args) 410 | #define sdfat_log_msg(sb, lv, fmt, args...) \ 411 | __sdfat_msg(sb, lv, 1, fmt, ## args) 412 | extern void sdfat_log_version(void); 413 | extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, 414 | DATE_TIME_T *tp); 415 | extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts, 416 | DATE_TIME_T *tp); 417 | extern TIMESTAMP_T *tm_now(struct inode *inode, TIMESTAMP_T *tm); 418 | static inline TIMESTAMP_T *tm_now_sb(struct super_block *sb, TIMESTAMP_T *tm) 419 | { 420 | struct inode fake_inode; 421 | 422 | fake_inode.i_sb = sb; 423 | return tm_now(&fake_inode, tm); 424 | } 425 | 426 | #ifdef CONFIG_SDFAT_DEBUG 427 | 428 | #ifdef CONFIG_SDFAT_DBG_CAREFUL 429 | void sdfat_debug_check_clusters(struct inode *inode); 430 | #else 431 | #define sdfat_debug_check_clusters(inode) 432 | #endif /* CONFIG_SDFAT_DBG_CAREFUL */ 433 | 434 | #ifdef CONFIG_SDFAT_DBG_BUGON 435 | #define sdfat_debug_bug_on(expr) BUG_ON(expr) 436 | #else 437 | #define sdfat_debug_bug_on(expr) 438 | #endif 439 | 440 | #ifdef CONFIG_SDFAT_DBG_WARNON 441 | #define sdfat_debug_warn_on(expr) WARN_ON(expr) 442 | #else 443 | #define sdfat_debug_warn_on(expr) 444 | #endif 445 | 446 | #else /* CONFIG_SDFAT_DEBUG */ 447 | 448 | #define sdfat_debug_check_clusters(inode) 449 | #define sdfat_debug_bug_on(expr) 450 | #define sdfat_debug_warn_on(expr) 451 | 452 | #endif /* CONFIG_SDFAT_DEBUG */ 453 | 454 | #ifdef CONFIG_SDFAT_TRACE_ELAPSED_TIME 455 | u32 sdfat_time_current_usec(struct timeval *tv); 456 | extern struct timeval __t1; 457 | extern struct timeval __t2; 458 | 459 | #define TIME_GET(tv) sdfat_time_current_usec(tv) 460 | #define TIME_START(s) sdfat_time_current_usec(s) 461 | #define TIME_END(e) sdfat_time_current_usec(e) 462 | #define TIME_ELAPSED(s, e) ((u32)(((e)->tv_sec - (s)->tv_sec) * 1000000 + \ 463 | ((e)->tv_usec - (s)->tv_usec))) 464 | #define PRINT_TIME(n) pr_info("[SDFAT] Elapsed time %d = %d (usec)\n", n, (__t2 - __t1)) 465 | #else /* CONFIG_SDFAT_TRACE_ELAPSED_TIME */ 466 | #define TIME_GET(tv) (0) 467 | #define TIME_START(s) 468 | #define TIME_END(e) 469 | #define TIME_ELAPSED(s, e) (0) 470 | #define PRINT_TIME(n) 471 | #endif /* CONFIG_SDFAT_TRACE_ELAPSED_TIME */ 472 | 473 | #define SDFAT_MSG_LV_NONE (0x00000000) 474 | #define SDFAT_MSG_LV_ERR (0x00000001) 475 | #define SDFAT_MSG_LV_INFO (0x00000002) 476 | #define SDFAT_MSG_LV_DBG (0x00000003) 477 | #define SDFAT_MSG_LV_MORE (0x00000004) 478 | #define SDFAT_MSG_LV_TRACE (0x00000005) 479 | #define SDFAT_MSG_LV_ALL (0x00000006) 480 | 481 | #define SDFAT_MSG_LEVEL SDFAT_MSG_LV_INFO 482 | 483 | #define SDFAT_TAG_NAME "SDFAT" 484 | #define __S(x) #x 485 | #define _S(x) __S(x) 486 | 487 | extern void __sdfat_dmsg(int level, const char *fmt, ...) __printf(2, 3) __cold; 488 | 489 | #define SDFAT_EMSG_T(level, ...) \ 490 | __sdfat_dmsg(level, KERN_ERR "[" SDFAT_TAG_NAME "] [" _S(__FILE__) "(" _S(__LINE__) ")] " __VA_ARGS__) 491 | #define SDFAT_DMSG_T(level, ...) \ 492 | __sdfat_dmsg(level, KERN_INFO "[" SDFAT_TAG_NAME "] " __VA_ARGS__) 493 | 494 | #define SDFAT_EMSG(...) SDFAT_EMSG_T(SDFAT_MSG_LV_ERR, __VA_ARGS__) 495 | #define SDFAT_IMSG(...) SDFAT_DMSG_T(SDFAT_MSG_LV_INFO, __VA_ARGS__) 496 | #define SDFAT_DMSG(...) SDFAT_DMSG_T(SDFAT_MSG_LV_DBG, __VA_ARGS__) 497 | #define SDFAT_MMSG(...) SDFAT_DMSG_T(SDFAT_MSG_LV_MORE, __VA_ARGS__) 498 | #define SDFAT_TMSG(...) SDFAT_DMSG_T(SDFAT_MSG_LV_TRACE, __VA_ARGS__) 499 | 500 | #define EMSG(...) 501 | #define IMSG(...) 502 | #define DMSG(...) 503 | #define MMSG(...) 504 | #define TMSG(...) 505 | 506 | #define EMSG_VAR(exp) 507 | #define IMSG_VAR(exp) 508 | #define DMSG_VAR(exp) 509 | #define MMSG_VAR(exp) 510 | #define TMSG_VAR(exp) 511 | 512 | #ifdef CONFIG_SDFAT_DBG_MSG 513 | 514 | 515 | #if (SDFAT_MSG_LEVEL >= SDFAT_MSG_LV_ERR) 516 | #undef EMSG 517 | #undef EMSG_VAR 518 | #define EMSG(...) SDFAT_EMSG(__VA_ARGS__) 519 | #define EMSG_VAR(exp) exp 520 | #endif 521 | 522 | #if (SDFAT_MSG_LEVEL >= SDFAT_MSG_LV_INFO) 523 | #undef IMSG 524 | #undef IMSG_VAR 525 | #define IMSG(...) SDFAT_IMSG(__VA_ARGS__) 526 | #define IMSG_VAR(exp) exp 527 | #endif 528 | 529 | #if (SDFAT_MSG_LEVEL >= SDFAT_MSG_LV_DBG) 530 | #undef DMSG 531 | #undef DMSG_VAR 532 | #define DMSG(...) SDFAT_DMSG(__VA_ARGS__) 533 | #define DMSG_VAR(exp) exp 534 | #endif 535 | 536 | #if (SDFAT_MSG_LEVEL >= SDFAT_MSG_LV_MORE) 537 | #undef MMSG 538 | #undef MMSG_VAR 539 | #define MMSG(...) SDFAT_MMSG(__VA_ARGS__) 540 | #define MMSG_VAR(exp) exp 541 | #endif 542 | 543 | /* should replace with trace function */ 544 | #if (SDFAT_MSG_LEVEL >= SDFAT_MSG_LV_TRACE) 545 | #undef TMSG 546 | #undef TMSG_VAR 547 | #define TMSG(...) SDFAT_TMSG(__VA_ARGS__) 548 | #define TMSG_VAR(exp) exp 549 | #endif 550 | 551 | #endif /* CONFIG_SDFAT_DBG_MSG */ 552 | 553 | 554 | #define ASSERT(expr) { \ 555 | if (!(expr)) { \ 556 | pr_err("Assertion failed! %s\n", #expr); \ 557 | BUG_ON(1); \ 558 | } \ 559 | } 560 | 561 | #endif /* !_SDFAT_H */ 562 | 563 | -------------------------------------------------------------------------------- /sdfat_fs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | #ifndef _SDFAT_FS_H 19 | #define _SDFAT_FS_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | /*----------------------------------------------------------------------*/ 26 | /* Constant & Macro Definitions */ 27 | /*----------------------------------------------------------------------*/ 28 | #ifndef MSDOS_SUPER_MAGIC 29 | #define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ 30 | #endif 31 | 32 | #ifndef EXFAT_SUPER_MAGIC 33 | #define EXFAT_SUPER_MAGIC (0x2011BAB0UL) 34 | #endif /* EXFAT_SUPER_MAGIC */ 35 | 36 | #ifndef SDFAT_SUPER_MAGIC 37 | #define SDFAT_SUPER_MAGIC (0x5EC5DFA4UL) 38 | #endif /* SDFAT_SUPER_MAGIC */ 39 | 40 | #define SDFAT_ROOT_INO 1 41 | 42 | /* FAT types */ 43 | #define FAT12 0x01 // FAT12 44 | #define FAT16 0x0E // Win95 FAT16 (LBA) 45 | #define FAT32 0x0C // Win95 FAT32 (LBA) 46 | #define EXFAT 0x07 // exFAT 47 | 48 | /* directory file name */ 49 | #define DOS_CUR_DIR_NAME ". " 50 | #define DOS_PAR_DIR_NAME ".. " 51 | 52 | #ifdef __LITTLE_ENDIAN 53 | #define UNI_CUR_DIR_NAME ".\0" 54 | #define UNI_PAR_DIR_NAME ".\0.\0" 55 | #else 56 | #define UNI_CUR_DIR_NAME "\0." 57 | #define UNI_PAR_DIR_NAME "\0.\0." 58 | #endif 59 | 60 | /* file name lengths */ 61 | /* NOTE : 62 | * The maximum length of input or output is limited to 256 including NULL, 63 | * But we allocate 4 extra bytes for utf8 translation reside in last position, 64 | * because utf8 can uses memory upto 6 bytes per one character. 65 | * Therefore, MAX_CHARSET_SIZE supports upto 6 bytes for utf8 66 | */ 67 | #define MAX_UNINAME_BUF_SIZE (((MAX_NAME_LENGTH+1)*2)+4) 68 | #define MAX_DOSNAME_BUF_SIZE ((DOS_NAME_LENGTH+2)+6) 69 | #define MAX_VFSNAME_BUF_SIZE ((MAX_NAME_LENGTH+1)*MAX_CHARSET_SIZE) 70 | #define MAX_CHARSET_SIZE 6 // max size of multi-byte character 71 | #define MAX_NAME_LENGTH 255 // max len of file name excluding NULL 72 | #define DOS_NAME_LENGTH 11 // DOS file name length excluding NULL 73 | 74 | #define SECTOR_SIZE_BITS 9 /* VFS sector size is 512 bytes */ 75 | 76 | #define DENTRY_SIZE 32 /* directory entry size */ 77 | #define DENTRY_SIZE_BITS 5 78 | 79 | #define MAX_FAT_DENTRIES 65536 /* FAT allows 65536 directory entries */ 80 | #define MAX_EXFAT_DENTRIES 8388608 /* exFAT allows 8388608(256MB) directory entries */ 81 | 82 | /* PBR entries */ 83 | #define PBR_SIGNATURE 0xAA55 84 | #define EXT_SIGNATURE 0xAA550000 85 | #define VOL_LABEL "NO NAME " /* size should be 11 */ 86 | #define OEM_NAME "MSWIN4.1" /* size should be 8 */ 87 | #define STR_FAT12 "FAT12 " /* size should be 8 */ 88 | #define STR_FAT16 "FAT16 " /* size should be 8 */ 89 | #define STR_FAT32 "FAT32 " /* size should be 8 */ 90 | #define STR_EXFAT "EXFAT " /* size should be 8 */ 91 | 92 | #define VOL_CLEAN 0x0000 93 | #define VOL_DIRTY 0x0002 94 | 95 | #define FAT_VOL_DIRTY 0x01 96 | 97 | /* max number of clusters */ 98 | #define FAT12_THRESHOLD 4087 // 2^12 - 1 + 2 (clu 0 & 1) 99 | #define FAT16_THRESHOLD 65527 // 2^16 - 1 + 2 100 | #define FAT32_THRESHOLD 268435457 // 2^28 - 1 + 2 101 | #define EXFAT_THRESHOLD 268435457 // 2^28 - 1 + 2 102 | 103 | /* dentry types */ 104 | #define MSDOS_DELETED 0xE5 /* deleted mark */ 105 | #define MSDOS_UNUSED 0x00 /* end of directory */ 106 | 107 | #define EXFAT_UNUSED 0x00 /* end of directory */ 108 | #define IS_EXFAT_DELETED(x) ((x) < 0x80) /* deleted file (0x01~0x7F) */ 109 | #define EXFAT_INVAL 0x80 /* invalid value */ 110 | #define EXFAT_BITMAP 0x81 /* allocation bitmap */ 111 | #define EXFAT_UPCASE 0x82 /* upcase table */ 112 | #define EXFAT_VOLUME 0x83 /* volume label */ 113 | #define EXFAT_FILE 0x85 /* file or dir */ 114 | #define EXFAT_STREAM 0xC0 /* stream entry */ 115 | #define EXFAT_NAME 0xC1 /* file name entry */ 116 | #define EXFAT_ACL 0xC2 /* stream entry */ 117 | 118 | /* specific flag */ 119 | #define MSDOS_LAST_LFN 0x40 120 | 121 | /* file attributes */ 122 | #define ATTR_NORMAL 0x0000 123 | #define ATTR_READONLY 0x0001 124 | #define ATTR_HIDDEN 0x0002 125 | #define ATTR_SYSTEM 0x0004 126 | #define ATTR_VOLUME 0x0008 127 | #define ATTR_SUBDIR 0x0010 128 | #define ATTR_ARCHIVE 0x0020 129 | #define ATTR_SYMLINK 0x0040 130 | #define ATTR_EXTEND (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | \ 131 | ATTR_VOLUME) /* 0x000F */ 132 | 133 | #define ATTR_EXTEND_MASK (ATTR_EXTEND | ATTR_SUBDIR | ATTR_ARCHIVE) 134 | #define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \ 135 | ATTR_SUBDIR | ATTR_ARCHIVE | ATTR_SYMLINK)/* 0x007E */ 136 | 137 | /* file creation modes */ 138 | #define FM_REGULAR 0x00 139 | #define FM_SYMLINK 0x40 140 | 141 | /* time modes */ 142 | #define TM_CREATE 0 143 | #define TM_MODIFY 1 144 | #define TM_ACCESS 2 145 | 146 | /* checksum types */ 147 | #define CS_DIR_ENTRY 0 148 | #define CS_PBR_SECTOR 1 149 | #define CS_DEFAULT 2 150 | 151 | /* time min/max */ 152 | /* Jan 1 GMT 00:00:00 1980 */ 153 | #define SDFAT_MIN_TIMESTAMP_SECS 315532800LL 154 | /* Dec 31 GMT 23:59:59 2107 */ 155 | #define SDFAT_MAX_TIMESTAMP_SECS 4354819199LL 156 | 157 | 158 | /* 159 | * ioctl command 160 | */ 161 | #define SDFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) 162 | #define SDFAT_IOCTL_DFR_INFO _IOC(_IOC_NONE, 'E', 0x13, sizeof(u32)) 163 | #define SDFAT_IOCTL_DFR_TRAV _IOC(_IOC_NONE, 'E', 0x14, sizeof(u32)) 164 | #define SDFAT_IOCTL_DFR_REQ _IOC(_IOC_NONE, 'E', 0x15, sizeof(u32)) 165 | #define SDFAT_IOCTL_DFR_SPO_FLAG _IOC(_IOC_NONE, 'E', 0x16, sizeof(u32)) 166 | #define SDFAT_IOCTL_PANIC _IOC(_IOC_NONE, 'E', 0x17, sizeof(u32)) 167 | 168 | /* 169 | * ioctl command for debugging 170 | */ 171 | 172 | /* 173 | * IOCTL code 'f' used by 174 | * - file systems typically #0~0x1F 175 | * - embedded terminal devices #128~ 176 | * - exts for debugging purpose #99 177 | * number 100 and 101 is available now but has possible conflicts 178 | * 179 | * NOTE : This is available only If CONFIG_SDFAT_DVBG_IOCTL is enabled. 180 | * 181 | */ 182 | #define SDFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long) 183 | #define SDFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long) 184 | 185 | #define SDFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01 186 | #define SDFAT_DEBUGFLAGS_ERROR_RW 0x02 187 | 188 | /*----------------------------------------------------------------------*/ 189 | /* On-Disk Type Definitions */ 190 | /*----------------------------------------------------------------------*/ 191 | 192 | /* FAT12/16/32 BIOS parameter block (64 bytes) */ 193 | typedef struct { 194 | __u8 jmp_boot[3]; 195 | __u8 oem_name[8]; 196 | 197 | __u8 sect_size[2]; /* unaligned */ 198 | __u8 sect_per_clus; 199 | __le16 num_reserved; /* . */ 200 | __u8 num_fats; 201 | __u8 num_root_entries[2]; /* unaligned */ 202 | __u8 num_sectors[2]; /* unaligned */ 203 | __u8 media_type; 204 | __le16 num_fat_sectors; 205 | __le16 sectors_in_track; 206 | __le16 num_heads; 207 | __le32 num_hid_sectors; /* . */ 208 | __le32 num_huge_sectors; 209 | 210 | union { 211 | struct { 212 | __u8 phy_drv_no; 213 | __u8 state; /* used by WinNT for mount state */ 214 | __u8 ext_signature; 215 | __u8 vol_serial[4]; 216 | __u8 vol_label[11]; 217 | __u8 vol_type[8]; 218 | __le16 nouse; 219 | } f16; 220 | 221 | struct { 222 | __le32 num_fat32_sectors; 223 | __le16 ext_flags; 224 | __u8 fs_version[2]; 225 | __le32 root_cluster; /* . */ 226 | __le16 fsinfo_sector; 227 | __le16 backup_sector; 228 | __le16 reserved[6]; /* . */ 229 | } f32; 230 | }; 231 | } bpb_t; 232 | 233 | /* FAT32 EXTEND BIOS parameter block (32 bytes) */ 234 | typedef struct { 235 | __u8 phy_drv_no; 236 | __u8 state; /* used by WindowsNT for mount state */ 237 | __u8 ext_signature; 238 | __u8 vol_serial[4]; 239 | __u8 vol_label[11]; 240 | __u8 vol_type[8]; 241 | __le16 dummy[3]; 242 | } bsx32_t; 243 | 244 | /* EXFAT BIOS parameter block (64 bytes) */ 245 | typedef struct { 246 | __u8 jmp_boot[3]; 247 | __u8 oem_name[8]; 248 | __u8 res_zero[53]; 249 | } bpb64_t; 250 | 251 | /* EXFAT EXTEND BIOS parameter block (56 bytes) */ 252 | typedef struct { 253 | __le64 vol_offset; 254 | __le64 vol_length; 255 | __le32 fat_offset; 256 | __le32 fat_length; 257 | __le32 clu_offset; 258 | __le32 clu_count; 259 | __le32 root_cluster; 260 | __le32 vol_serial; 261 | __u8 fs_version[2]; 262 | __le16 vol_flags; 263 | __u8 sect_size_bits; 264 | __u8 sect_per_clus_bits; 265 | __u8 num_fats; 266 | __u8 phy_drv_no; 267 | __u8 perc_in_use; 268 | __u8 reserved2[7]; 269 | } bsx64_t; 270 | 271 | /* FAT32 PBR (64 bytes) */ 272 | typedef struct { 273 | bpb_t bpb; 274 | } pbr16_t; 275 | 276 | /* FAT32 PBR[BPB+BSX] (96 bytes) */ 277 | typedef struct { 278 | bpb_t bpb; 279 | bsx32_t bsx; 280 | } pbr32_t; 281 | 282 | /* EXFAT PBR[BPB+BSX] (120 bytes) */ 283 | typedef struct { 284 | bpb64_t bpb; 285 | bsx64_t bsx; 286 | } pbr64_t; 287 | 288 | /* Common PBR[Partition Boot Record] (512 bytes) */ 289 | typedef struct { 290 | union { 291 | __u8 raw[64]; 292 | bpb_t fat; 293 | bpb64_t f64; 294 | } bpb; 295 | union { 296 | __u8 raw[56]; 297 | bsx32_t f32; 298 | bsx64_t f64; 299 | } bsx; 300 | __u8 boot_code[390]; 301 | __le16 signature; 302 | } pbr_t; 303 | 304 | /* FAT32 filesystem information sector (512 bytes) */ 305 | typedef struct { 306 | __le32 signature1; // aligned 307 | __u8 reserved1[480]; 308 | __le32 signature2; // aligned 309 | __le32 free_cluster; // aligned 310 | __le32 next_cluster; // aligned 311 | __u8 reserved2[14]; 312 | __le16 signature3[2]; 313 | } fat32_fsi_t; 314 | 315 | /* FAT directory entry (32 bytes) */ 316 | typedef struct { 317 | __u8 dummy[32]; 318 | } DENTRY_T; 319 | 320 | typedef struct { 321 | __u8 name[DOS_NAME_LENGTH]; /* 11 chars */ 322 | __u8 attr; 323 | __u8 lcase; 324 | __u8 create_time_ms; 325 | __le16 create_time; // aligned 326 | __le16 create_date; // aligned 327 | __le16 access_date; // aligned 328 | __le16 start_clu_hi; // aligned 329 | __le16 modify_time; // aligned 330 | __le16 modify_date; // aligned 331 | __le16 start_clu_lo; // aligned 332 | __le32 size; // aligned 333 | } DOS_DENTRY_T; 334 | 335 | /* FAT extended directory entry (32 bytes) */ 336 | typedef struct { 337 | __u8 order; 338 | __u8 unicode_0_4[10]; 339 | __u8 attr; 340 | __u8 sysid; 341 | __u8 checksum; 342 | __le16 unicode_5_10[6]; // aligned 343 | __le16 start_clu; // aligned 344 | __le16 unicode_11_12[2]; // aligned 345 | } EXT_DENTRY_T; 346 | 347 | /* EXFAT file directory entry (32 bytes) */ 348 | typedef struct { 349 | __u8 type; 350 | __u8 num_ext; 351 | __le16 checksum; // aligned 352 | __le16 attr; // aligned 353 | __le16 reserved1; 354 | __le16 create_time; // aligned 355 | __le16 create_date; // aligned 356 | __le16 modify_time; // aligned 357 | __le16 modify_date; // aligned 358 | __le16 access_time; // aligned 359 | __le16 access_date; // aligned 360 | __u8 create_time_ms; 361 | __u8 modify_time_ms; 362 | __u8 create_tz; 363 | __u8 modify_tz; 364 | __u8 access_tz; 365 | __u8 reserved2[7]; 366 | } FILE_DENTRY_T; 367 | 368 | /* EXFAT stream extension directory entry (32 bytes) */ 369 | typedef struct { 370 | __u8 type; 371 | __u8 flags; 372 | __u8 reserved1; 373 | __u8 name_len; 374 | __le16 name_hash; // aligned 375 | __le16 reserved2; 376 | __le64 valid_size; // aligned 377 | __le32 reserved3; // aligned 378 | __le32 start_clu; // aligned 379 | __le64 size; // aligned 380 | } STRM_DENTRY_T; 381 | 382 | /* EXFAT file name directory entry (32 bytes) */ 383 | typedef struct { 384 | __u8 type; 385 | __u8 flags; 386 | __le16 unicode_0_14[15]; // aligned 387 | } NAME_DENTRY_T; 388 | 389 | /* EXFAT allocation bitmap directory entry (32 bytes) */ 390 | typedef struct { 391 | __u8 type; 392 | __u8 flags; 393 | __u8 reserved[18]; 394 | __le32 start_clu; // aligned 395 | __le64 size; // aligned 396 | } BMAP_DENTRY_T; 397 | 398 | /* EXFAT up-case table directory entry (32 bytes) */ 399 | typedef struct { 400 | __u8 type; 401 | __u8 reserved1[3]; 402 | __le32 checksum; // aligned 403 | __u8 reserved2[12]; 404 | __le32 start_clu; // aligned 405 | __le64 size; // aligned 406 | } CASE_DENTRY_T; 407 | 408 | /* EXFAT volume label directory entry (32 bytes) */ 409 | typedef struct { 410 | __u8 type; 411 | __u8 label_len; 412 | __le16 unicode_0_10[11]; // aligned 413 | __u8 reserved[8]; 414 | } VOLM_DENTRY_T; 415 | 416 | #endif /* _SDFAT_FS_H */ 417 | -------------------------------------------------------------------------------- /statistics.c: -------------------------------------------------------------------------------- 1 | #include "sdfat.h" 2 | 3 | #define SDFAT_VF_CLUS_MAX 7 /* 512 Byte ~ 32 KByte */ 4 | #define SDFAT_EF_CLUS_MAX 17 /* 512 Byte ~ 32 MByte */ 5 | 6 | enum { 7 | SDFAT_MNT_FAT12, 8 | SDFAT_MNT_FAT16, 9 | SDFAT_MNT_FAT32, 10 | SDFAT_MNT_EXFAT, 11 | SDFAT_MNT_RO, 12 | SDFAT_MNT_MAX 13 | }; 14 | 15 | enum { 16 | SDFAT_OP_EXFAT_MNT, 17 | SDFAT_OP_MKDIR, 18 | SDFAT_OP_CREATE, 19 | SDFAT_OP_READ, 20 | SDFAT_OP_WRITE, 21 | SDFAT_OP_TRUNC, 22 | SDFAT_OP_MAX 23 | }; 24 | 25 | enum { 26 | SDFAT_VOL_4G, 27 | SDFAT_VOL_8G, 28 | SDFAT_VOL_16G, 29 | SDFAT_VOL_32G, 30 | SDFAT_VOL_64G, 31 | SDFAT_VOL_128G, 32 | SDFAT_VOL_256G, 33 | SDFAT_VOL_512G, 34 | SDFAT_VOL_XTB, 35 | SDFAT_VOL_MAX 36 | }; 37 | 38 | static struct sdfat_statistics { 39 | u32 clus_vfat[SDFAT_VF_CLUS_MAX]; 40 | u32 clus_exfat[SDFAT_EF_CLUS_MAX]; 41 | u32 mnt_cnt[SDFAT_MNT_MAX]; 42 | u32 nofat_op[SDFAT_OP_MAX]; 43 | u32 vol_size[SDFAT_VOL_MAX]; 44 | } statistics; 45 | 46 | static struct kset *sdfat_statistics_kset; 47 | 48 | static ssize_t vfat_cl_show(struct kobject *kobj, 49 | struct kobj_attribute *attr, char *buff) 50 | { 51 | return snprintf(buff, PAGE_SIZE, "\"VCL_512B_I\":\"%u\"," 52 | "\"VCL_1K_I\":\"%u\",\"VCL_2K_I\":\"%u\"," 53 | "\"VCL_4K_I\":\"%u\",\"VCL_8K_I\":\"%u\"," 54 | "\"VCL_16K_I\":\"%u\",\"VCL_32K_I\":\"%u\"\n", 55 | statistics.clus_vfat[0], statistics.clus_vfat[1], 56 | statistics.clus_vfat[2], statistics.clus_vfat[3], 57 | statistics.clus_vfat[4], statistics.clus_vfat[5], 58 | statistics.clus_vfat[6]); 59 | } 60 | 61 | static ssize_t exfat_cl_show(struct kobject *kobj, 62 | struct kobj_attribute *attr, char *buff) 63 | { 64 | return snprintf(buff, PAGE_SIZE, "\"ECL_512B_I\":\"%u\"," 65 | "\"ECL_1K_I\":\"%u\",\"ECL_2K_I\":\"%u\"," 66 | "\"ECL_4K_I\":\"%u\",\"ECL_8K_I\":\"%u\"," 67 | "\"ECL_16K_I\":\"%u\",\"ECL_32K_I\":\"%u\"," 68 | "\"ECL_64K_I\":\"%u\",\"ECL_128K_I\":\"%u\"," 69 | "\"ECL_256K_I\":\"%u\",\"ECL_512K_I\":\"%u\"," 70 | "\"ECL_1M_I\":\"%u\",\"ECL_2M_I\":\"%u\"," 71 | "\"ECL_4M_I\":\"%u\",\"ECL_8M_I\":\"%u\"," 72 | "\"ECL_16M_I\":\"%u\",\"ECL_32M_I\":\"%u\"\n", 73 | statistics.clus_exfat[0], statistics.clus_exfat[1], 74 | statistics.clus_exfat[2], statistics.clus_exfat[3], 75 | statistics.clus_exfat[4], statistics.clus_exfat[5], 76 | statistics.clus_exfat[6], statistics.clus_exfat[7], 77 | statistics.clus_exfat[8], statistics.clus_exfat[9], 78 | statistics.clus_exfat[10], statistics.clus_exfat[11], 79 | statistics.clus_exfat[12], statistics.clus_exfat[13], 80 | statistics.clus_exfat[14], statistics.clus_exfat[15], 81 | statistics.clus_exfat[16]); 82 | } 83 | 84 | static ssize_t mount_show(struct kobject *kobj, 85 | struct kobj_attribute *attr, char *buff) 86 | { 87 | return snprintf(buff, PAGE_SIZE, "\"FAT12_MNT_I\":\"%u\"," 88 | "\"FAT16_MNT_I\":\"%u\",\"FAT32_MNT_I\":\"%u\"," 89 | "\"EXFAT_MNT_I\":\"%u\",\"RO_MNT_I\":\"%u\"\n", 90 | statistics.mnt_cnt[SDFAT_MNT_FAT12], 91 | statistics.mnt_cnt[SDFAT_MNT_FAT16], 92 | statistics.mnt_cnt[SDFAT_MNT_FAT32], 93 | statistics.mnt_cnt[SDFAT_MNT_EXFAT], 94 | statistics.mnt_cnt[SDFAT_MNT_RO]); 95 | } 96 | 97 | static ssize_t nofat_op_show(struct kobject *kobj, 98 | struct kobj_attribute *attr, char *buff) 99 | { 100 | return snprintf(buff, PAGE_SIZE, "\"NOFAT_MOUNT_I\":\"%u\"," 101 | "\"NOFAT_MKDIR_I\":\"%u\",\"NOFAT_CREATE_I\":\"%u\"," 102 | "\"NOFAT_READ_I\":\"%u\",\"NOFAT_WRITE_I\":\"%u\"," 103 | "\"NOFAT_TRUNC_I\":\"%u\"\n", 104 | statistics.nofat_op[SDFAT_OP_EXFAT_MNT], 105 | statistics.nofat_op[SDFAT_OP_MKDIR], 106 | statistics.nofat_op[SDFAT_OP_CREATE], 107 | statistics.nofat_op[SDFAT_OP_READ], 108 | statistics.nofat_op[SDFAT_OP_WRITE], 109 | statistics.nofat_op[SDFAT_OP_TRUNC]); 110 | } 111 | 112 | static ssize_t vol_size_show(struct kobject *kobj, 113 | struct kobj_attribute *attr, char *buff) 114 | { 115 | return snprintf(buff, PAGE_SIZE, "\"VOL_4G_I\":\"%u\"," 116 | "\"VOL_8G_I\":\"%u\",\"VOL_16G_I\":\"%u\"," 117 | "\"VOL_32G_I\":\"%u\",\"VOL_64G_I\":\"%u\"," 118 | "\"VOL_128G_I\":\"%u\",\"VOL_256G_I\":\"%u\"," 119 | "\"VOL_512G_I\":\"%u\",\"VOL_XTB_I\":\"%u\"\n", 120 | statistics.vol_size[SDFAT_VOL_4G], 121 | statistics.vol_size[SDFAT_VOL_8G], 122 | statistics.vol_size[SDFAT_VOL_16G], 123 | statistics.vol_size[SDFAT_VOL_32G], 124 | statistics.vol_size[SDFAT_VOL_64G], 125 | statistics.vol_size[SDFAT_VOL_128G], 126 | statistics.vol_size[SDFAT_VOL_256G], 127 | statistics.vol_size[SDFAT_VOL_512G], 128 | statistics.vol_size[SDFAT_VOL_XTB]); 129 | } 130 | 131 | static struct kobj_attribute vfat_cl_attr = __ATTR_RO(vfat_cl); 132 | static struct kobj_attribute exfat_cl_attr = __ATTR_RO(exfat_cl); 133 | static struct kobj_attribute mount_attr = __ATTR_RO(mount); 134 | static struct kobj_attribute nofat_op_attr = __ATTR_RO(nofat_op); 135 | static struct kobj_attribute vol_size_attr = __ATTR_RO(vol_size); 136 | 137 | static struct attribute *attributes_statistics[] = { 138 | &vfat_cl_attr.attr, 139 | &exfat_cl_attr.attr, 140 | &mount_attr.attr, 141 | &nofat_op_attr.attr, 142 | &vol_size_attr.attr, 143 | NULL, 144 | }; 145 | 146 | static struct attribute_group attr_group_statistics = { 147 | .attrs = attributes_statistics, 148 | }; 149 | 150 | int sdfat_statistics_init(struct kset *sdfat_kset) 151 | { 152 | int err; 153 | 154 | sdfat_statistics_kset = kset_create_and_add("statistics", NULL, &sdfat_kset->kobj); 155 | if (!sdfat_statistics_kset) { 156 | pr_err("[SDFAT] failed to create sdfat statistics kobj\n"); 157 | return -ENOMEM; 158 | } 159 | 160 | err = sysfs_create_group(&sdfat_statistics_kset->kobj, &attr_group_statistics); 161 | if (err) { 162 | pr_err("[SDFAT] failed to create sdfat statistics attributes\n"); 163 | kset_unregister(sdfat_statistics_kset); 164 | sdfat_statistics_kset = NULL; 165 | return err; 166 | } 167 | 168 | return 0; 169 | } 170 | 171 | void sdfat_statistics_uninit(void) 172 | { 173 | if (sdfat_statistics_kset) { 174 | sysfs_remove_group(&sdfat_statistics_kset->kobj, &attr_group_statistics); 175 | kset_unregister(sdfat_statistics_kset); 176 | sdfat_statistics_kset = NULL; 177 | } 178 | memset(&statistics, 0, sizeof(struct sdfat_statistics)); 179 | } 180 | 181 | void sdfat_statistics_set_mnt(FS_INFO_T *fsi) 182 | { 183 | if (fsi->vol_type == EXFAT) { 184 | statistics.mnt_cnt[SDFAT_MNT_EXFAT]++; 185 | statistics.nofat_op[SDFAT_OP_EXFAT_MNT] = 1; 186 | if (fsi->sect_per_clus_bits < SDFAT_EF_CLUS_MAX) 187 | statistics.clus_exfat[fsi->sect_per_clus_bits]++; 188 | else 189 | statistics.clus_exfat[SDFAT_EF_CLUS_MAX - 1]++; 190 | return; 191 | } 192 | 193 | if (fsi->vol_type == FAT32) 194 | statistics.mnt_cnt[SDFAT_MNT_FAT32]++; 195 | else if (fsi->vol_type == FAT16) 196 | statistics.mnt_cnt[SDFAT_MNT_FAT16]++; 197 | else if (fsi->vol_type == FAT12) 198 | statistics.mnt_cnt[SDFAT_MNT_FAT12]++; 199 | 200 | if (fsi->sect_per_clus_bits < SDFAT_VF_CLUS_MAX) 201 | statistics.clus_vfat[fsi->sect_per_clus_bits]++; 202 | else 203 | statistics.clus_vfat[SDFAT_VF_CLUS_MAX - 1]++; 204 | } 205 | 206 | void sdfat_statistics_set_mnt_ro(void) 207 | { 208 | statistics.mnt_cnt[SDFAT_MNT_RO]++; 209 | } 210 | 211 | void sdfat_statistics_set_mkdir(u8 flags) 212 | { 213 | if (flags != 0x03) 214 | return; 215 | statistics.nofat_op[SDFAT_OP_MKDIR] = 1; 216 | } 217 | 218 | void sdfat_statistics_set_create(u8 flags) 219 | { 220 | if (flags != 0x03) 221 | return; 222 | statistics.nofat_op[SDFAT_OP_CREATE] = 1; 223 | } 224 | 225 | /* flags : file or dir flgas, 0x03 means no fat-chain. 226 | * clu_offset : file or dir logical cluster offset 227 | * create : BMAP_ADD_CLUSTER or not 228 | * 229 | * File or dir have BMAP_ADD_CLUSTER is no fat-chain write 230 | * when they have 0x03 flag and two or more clusters. 231 | * And don`t have BMAP_ADD_CLUSTER is no fat-chain read 232 | * when above same condition. 233 | */ 234 | void sdfat_statistics_set_rw(u8 flags, u32 clu_offset, s32 create) 235 | { 236 | if ((flags == 0x03) && (clu_offset > 1)) { 237 | if (create) 238 | statistics.nofat_op[SDFAT_OP_WRITE] = 1; 239 | else 240 | statistics.nofat_op[SDFAT_OP_READ] = 1; 241 | } 242 | } 243 | 244 | /* flags : file or dir flgas, 0x03 means no fat-chain. 245 | * clu : cluster chain 246 | * 247 | * Set no fat-chain trunc when file or dir have 0x03 flag 248 | * and two or more clusters. 249 | */ 250 | void sdfat_statistics_set_trunc(u8 flags, CHAIN_T *clu) 251 | { 252 | if ((flags == 0x03) && (clu->size > 1)) 253 | statistics.nofat_op[SDFAT_OP_TRUNC] = 1; 254 | } 255 | 256 | void sdfat_statistics_set_vol_size(struct super_block *sb) 257 | { 258 | u64 vol_size; 259 | FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi); 260 | 261 | vol_size = (u64)fsi->num_sectors << sb->s_blocksize_bits; 262 | 263 | if (vol_size <= ((u64)1 << 32)) 264 | statistics.vol_size[SDFAT_VOL_4G]++; 265 | else if (vol_size <= ((u64)1 << 33)) 266 | statistics.vol_size[SDFAT_VOL_8G]++; 267 | else if (vol_size <= ((u64)1 << 34)) 268 | statistics.vol_size[SDFAT_VOL_16G]++; 269 | else if (vol_size <= ((u64)1 << 35)) 270 | statistics.vol_size[SDFAT_VOL_32G]++; 271 | else if (vol_size <= ((u64)1 << 36)) 272 | statistics.vol_size[SDFAT_VOL_64G]++; 273 | else if (vol_size <= ((u64)1 << 37)) 274 | statistics.vol_size[SDFAT_VOL_128G]++; 275 | else if (vol_size <= ((u64)1 << 38)) 276 | statistics.vol_size[SDFAT_VOL_256G]++; 277 | else if (vol_size <= ((u64)1 << 39)) 278 | statistics.vol_size[SDFAT_VOL_512G]++; 279 | else 280 | statistics.vol_size[SDFAT_VOL_XTB]++; 281 | } 282 | -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | /************************************************************************/ 19 | /* */ 20 | /* PROJECT : exFAT & FAT12/16/32 File System */ 21 | /* FILE : version.h */ 22 | /* PURPOSE : sdFAT File Manager */ 23 | /* */ 24 | /************************************************************************/ 25 | #define SDFAT_VERSION "2.4.5-lineage" 26 | -------------------------------------------------------------------------------- /xattr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, see . 16 | */ 17 | 18 | /************************************************************************/ 19 | /* */ 20 | /* PROJECT : exFAT & FAT12/16/32 File System */ 21 | /* FILE : xattr.c */ 22 | /* PURPOSE : sdFAT code for supporting xattr(Extended File Attributes) */ 23 | /* */ 24 | /*----------------------------------------------------------------------*/ 25 | /* NOTES */ 26 | /* */ 27 | /* */ 28 | /************************************************************************/ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "sdfat.h" 35 | 36 | #ifndef CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL 37 | #define CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL ("undefined") 38 | #endif 39 | 40 | static const char default_xattr[] = CONFIG_SDFAT_VIRTUAL_XATTR_SELINUX_LABEL; 41 | 42 | static int can_support(const char *name) 43 | { 44 | if (!name || strcmp(name, "security.selinux")) 45 | return -1; 46 | return 0; 47 | } 48 | 49 | ssize_t sdfat_listxattr(struct dentry *dentry, char *list, size_t size) 50 | { 51 | return 0; 52 | } 53 | 54 | 55 | /************************************************************************* 56 | * INNER FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY 57 | *************************************************************************/ 58 | static int __sdfat_xattr_check_support(const char *name) 59 | { 60 | if (can_support(name)) 61 | return -EOPNOTSUPP; 62 | 63 | return 0; 64 | } 65 | 66 | ssize_t __sdfat_getxattr(const char *name, void *value, size_t size) 67 | { 68 | if (can_support(name)) 69 | return -EOPNOTSUPP; 70 | 71 | if ((size > strlen(default_xattr)+1) && value) 72 | strcpy(value, default_xattr); 73 | 74 | return strlen(default_xattr); 75 | } 76 | 77 | 78 | /************************************************************************* 79 | * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY 80 | *************************************************************************/ 81 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) 82 | #if defined(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) 83 | static int sdfat_xattr_get(const struct xattr_handler *handler, 84 | struct dentry *dentry, struct inode *inode, 85 | const char *name, void *buffer, size_t size, 86 | int flags) 87 | { 88 | return __sdfat_getxattr(name, buffer, size); 89 | } 90 | #else 91 | static int sdfat_xattr_get(const struct xattr_handler *handler, 92 | struct dentry *dentry, struct inode *inode, 93 | const char *name, void *buffer, size_t size) 94 | { 95 | return __sdfat_getxattr(name, buffer, size); 96 | } 97 | #endif 98 | 99 | static int sdfat_xattr_set(const struct xattr_handler *handler, 100 | struct dentry *dentry, struct inode *inode, 101 | const char *name, const void *value, size_t size, 102 | int flags) 103 | { 104 | return __sdfat_xattr_check_support(name); 105 | } 106 | 107 | const struct xattr_handler sdfat_xattr_handler = { 108 | .prefix = "", /* match anything */ 109 | .get = sdfat_xattr_get, 110 | .set = sdfat_xattr_set, 111 | }; 112 | 113 | const struct xattr_handler *sdfat_xattr_handlers[] = { 114 | &sdfat_xattr_handler, 115 | NULL 116 | }; 117 | 118 | void setup_sdfat_xattr_handler(struct super_block *sb) 119 | { 120 | sb->s_xattr = sdfat_xattr_handlers; 121 | } 122 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) */ 123 | int sdfat_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) 124 | { 125 | return __sdfat_xattr_check_support(name); 126 | } 127 | 128 | ssize_t sdfat_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) 129 | { 130 | return __sdfat_getxattr(name, value, size); 131 | } 132 | 133 | int sdfat_removexattr(struct dentry *dentry, const char *name) 134 | { 135 | return __sdfat_xattr_check_support(name); 136 | } 137 | 138 | void setup_sdfat_xattr_handler(struct super_block *sb) 139 | { 140 | /* DO NOTHING */ 141 | } 142 | #endif 143 | --------------------------------------------------------------------------------