1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582 |
- /*
- * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
- /************************************************************************/
- /* */
- /* PROJECT : exFAT & FAT12/16/32 File System */
- /* FILE : core_exfat.c */
- /* PURPOSE : exFAT-fs core code for sdFAT */
- /* */
- /*----------------------------------------------------------------------*/
- /* NOTES */
- /* */
- /* */
- /************************************************************************/
- #include <linux/version.h>
- #include <linux/blkdev.h>
- #include <linux/workqueue.h>
- #include <linux/kernel.h>
- #include <linux/log2.h>
- #include "sdfat.h"
- #include "core.h"
- #include <asm/byteorder.h>
- #include <asm/unaligned.h>
- /*----------------------------------------------------------------------*/
- /* Constant & Macro Definitions */
- /*----------------------------------------------------------------------*/
- /*----------------------------------------------------------------------*/
- /* Global Variable Definitions */
- /*----------------------------------------------------------------------*/
- /*----------------------------------------------------------------------*/
- /* Local Variable Definitions */
- /*----------------------------------------------------------------------*/
- static u8 free_bit[] = {
- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/* 0 ~ 19*/
- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~ 39*/
- 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~ 59*/
- 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~ 79*/
- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~ 99*/
- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/
- 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/
- 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/
- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/
- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/
- 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/
- 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/
- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /*240 ~ 254*/
- };
- static u8 used_bit[] = {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/
- 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/
- 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/
- 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/
- 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/
- 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/
- 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/
- 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/
- 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/
- 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/
- 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/
- };
- /*======================================================================*/
- /* Local Function Definitions */
- /*======================================================================*/
- /*
- * Directory Entry Management Functions
- */
- static u32 exfat_get_entry_type(DENTRY_T *p_entry)
- {
- FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
- if (ep->type == EXFAT_UNUSED)
- return TYPE_UNUSED;
- if (ep->type < 0x80)
- return TYPE_DELETED;
- if (ep->type == 0x80)
- return TYPE_INVALID;
- if (ep->type < 0xA0) {
- if (ep->type == 0x81)
- return TYPE_BITMAP;
- if (ep->type == 0x82)
- return TYPE_UPCASE;
- if (ep->type == 0x83)
- return TYPE_VOLUME;
- if (ep->type == 0x85) {
- if (le16_to_cpu(ep->attr) & ATTR_SUBDIR)
- return TYPE_DIR;
- return TYPE_FILE;
- }
- return TYPE_CRITICAL_PRI;
- }
- if (ep->type < 0xC0) {
- if (ep->type == 0xA0)
- return TYPE_GUID;
- if (ep->type == 0xA1)
- return TYPE_PADDING;
- if (ep->type == 0xA2)
- return TYPE_ACLTAB;
- return TYPE_BENIGN_PRI;
- }
- if (ep->type < 0xE0) {
- if (ep->type == 0xC0)
- return TYPE_STREAM;
- if (ep->type == 0xC1)
- return TYPE_EXTEND;
- if (ep->type == 0xC2)
- return TYPE_ACL;
- return TYPE_CRITICAL_SEC;
- }
- return TYPE_BENIGN_SEC;
- } /* end of exfat_get_entry_type */
- static void exfat_set_entry_type(DENTRY_T *p_entry, u32 type)
- {
- FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry;
- if (type == TYPE_UNUSED) {
- ep->type = 0x0;
- } else if (type == TYPE_DELETED) {
- ep->type &= ~0x80;
- } else if (type == TYPE_STREAM) {
- ep->type = 0xC0;
- } else if (type == TYPE_EXTEND) {
- ep->type = 0xC1;
- } else if (type == TYPE_BITMAP) {
- ep->type = 0x81;
- } else if (type == TYPE_UPCASE) {
- ep->type = 0x82;
- } else if (type == TYPE_VOLUME) {
- ep->type = 0x83;
- } else if (type == TYPE_DIR) {
- ep->type = 0x85;
- ep->attr = cpu_to_le16(ATTR_SUBDIR);
- } else if (type == TYPE_FILE) {
- ep->type = 0x85;
- ep->attr = cpu_to_le16(ATTR_ARCHIVE);
- } else if (type == TYPE_SYMLINK) {
- ep->type = 0x85;
- ep->attr = cpu_to_le16(ATTR_ARCHIVE | ATTR_SYMLINK);
- }
- } /* end of exfat_set_entry_type */
- static u32 exfat_get_entry_attr(DENTRY_T *p_entry)
- {
- FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
- return (u32)le16_to_cpu(ep->attr);
- } /* end of exfat_get_entry_attr */
- static void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr)
- {
- FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
- ep->attr = cpu_to_le16((u16) attr);
- } /* end of exfat_set_entry_attr */
- static u8 exfat_get_entry_flag(DENTRY_T *p_entry)
- {
- STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
- return ep->flags;
- } /* end of exfat_get_entry_flag */
- static void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flags)
- {
- STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
- ep->flags = flags;
- } /* end of exfat_set_entry_flag */
- static u32 exfat_get_entry_clu0(DENTRY_T *p_entry)
- {
- STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
- return (u32)le32_to_cpu(ep->start_clu);
- } /* end of exfat_get_entry_clu0 */
- static void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu)
- {
- STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
- ep->start_clu = cpu_to_le32(start_clu);
- } /* end of exfat_set_entry_clu0 */
- static u64 exfat_get_entry_size(DENTRY_T *p_entry)
- {
- STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
- return le64_to_cpu(ep->valid_size);
- } /* end of exfat_get_entry_size */
- static void exfat_set_entry_size(DENTRY_T *p_entry, u64 size)
- {
- STRM_DENTRY_T *ep = (STRM_DENTRY_T *)p_entry;
- ep->valid_size = cpu_to_le64(size);
- ep->size = cpu_to_le64(size);
- } /* end of exfat_set_entry_size */
- #define TENS_MS_PER_SEC (100)
- #define SEC_TO_TENS_MS(sec) (((sec) & 0x01) ? TENS_MS_PER_SEC : 0)
- #define TENS_MS_TO_SEC(tens_ms) (((tens_ms) / TENS_MS_PER_SEC) ? 1 : 0)
- static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
- {
- u16 t = 0x00, d = 0x21, tz = 0x00, s = 0x00;
- FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
- switch (mode) {
- case TM_CREATE:
- t = le16_to_cpu(ep->create_time);
- d = le16_to_cpu(ep->create_date);
- s = TENS_MS_TO_SEC(ep->create_time_ms);
- tz = ep->create_tz;
- break;
- case TM_MODIFY:
- t = le16_to_cpu(ep->modify_time);
- d = le16_to_cpu(ep->modify_date);
- s = TENS_MS_TO_SEC(ep->modify_time_ms);
- tz = ep->modify_tz;
- break;
- case TM_ACCESS:
- t = le16_to_cpu(ep->access_time);
- d = le16_to_cpu(ep->access_date);
- tz = ep->access_tz;
- break;
- }
- tp->tz.value = tz;
- tp->sec = ((t & 0x001F) << 1) + s;
- tp->min = (t >> 5) & 0x003F;
- tp->hour = (t >> 11);
- tp->day = (d & 0x001F);
- tp->mon = (d >> 5) & 0x000F;
- tp->year = (d >> 9);
- } /* end of exfat_get_entry_time */
- static void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
- {
- u16 t, d;
- FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
- t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1);
- d = (tp->year << 9) | (tp->mon << 5) | tp->day;
- switch (mode) {
- case TM_CREATE:
- ep->create_time = cpu_to_le16(t);
- ep->create_time_ms = SEC_TO_TENS_MS(tp->sec);
- ep->create_date = cpu_to_le16(d);
- ep->create_tz = tp->tz.value;
- break;
- case TM_MODIFY:
- ep->modify_time = cpu_to_le16(t);
- ep->modify_date = cpu_to_le16(d);
- ep->modify_time_ms = (tp->sec & 0x1) ? TENS_MS_PER_SEC : 0;
- ep->modify_tz = tp->tz.value;
- break;
- case TM_ACCESS:
- ep->access_time = cpu_to_le16(t);
- ep->access_date = cpu_to_le16(d);
- ep->access_tz = tp->tz.value;
- break;
- }
- } /* end of exfat_set_entry_time */
- static void __init_file_entry(struct super_block *sb, FILE_DENTRY_T *ep, u32 type)
- {
- TIMESTAMP_T tm, *tp;
- exfat_set_entry_type((DENTRY_T *) ep, type);
- tp = tm_now_sb(sb, &tm);
- exfat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE);
- exfat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY);
- exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS);
- } /* end of __init_file_entry */
- static void __init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size)
- {
- exfat_set_entry_type((DENTRY_T *) ep, TYPE_STREAM);
- ep->flags = flags;
- ep->start_clu = cpu_to_le32(start_clu);
- ep->valid_size = cpu_to_le64(size);
- ep->size = cpu_to_le64(size);
- } /* end of __init_strm_entry */
- static void __init_name_entry(NAME_DENTRY_T *ep, u16 *uniname)
- {
- s32 i;
- exfat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND);
- ep->flags = 0x0;
- for (i = 0; i < 15; i++) {
- ep->unicode_0_14[i] = cpu_to_le16(*uniname);
- if (*uniname == 0x0)
- break;
- uniname++;
- }
- } /* end of __init_name_entry */
- static s32 exfat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, u32 start_clu, u64 size)
- {
- u64 sector;
- u8 flags;
- FILE_DENTRY_T *file_ep;
- STRM_DENTRY_T *strm_ep;
- flags = (type == TYPE_FILE) ? 0x01 : 0x03;
- /* we cannot use get_dentry_set_in_dir here because file ep is not initialized yet */
- file_ep = (FILE_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry, §or);
- if (!file_ep)
- return -EIO;
- strm_ep = (STRM_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry+1, §or);
- if (!strm_ep)
- return -EIO;
- __init_file_entry(sb, file_ep, type);
- if (dcache_modify(sb, sector))
- return -EIO;
- __init_strm_entry(strm_ep, flags, start_clu, size);
- if (dcache_modify(sb, sector))
- return -EIO;
- return 0;
- } /* end of exfat_init_dir_entry */
- s32 update_dir_chksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry)
- {
- s32 ret = -EIO;
- s32 i, num_entries;
- u64 sector;
- u16 chksum;
- FILE_DENTRY_T *file_ep;
- DENTRY_T *ep;
- file_ep = (FILE_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry, §or);
- if (!file_ep)
- return -EIO;
- dcache_lock(sb, sector);
- num_entries = (s32) file_ep->num_ext + 1;
- chksum = calc_chksum_2byte((void *) file_ep, DENTRY_SIZE, 0, CS_DIR_ENTRY);
- for (i = 1; i < num_entries; i++) {
- ep = get_dentry_in_dir(sb, p_dir, entry+i, NULL);
- if (!ep)
- goto out_unlock;
- chksum = calc_chksum_2byte((void *) ep, DENTRY_SIZE, chksum, CS_DEFAULT);
- }
- file_ep->checksum = cpu_to_le16(chksum);
- ret = dcache_modify(sb, sector);
- out_unlock:
- dcache_unlock(sb, sector);
- return ret;
- } /* end of update_dir_chksum */
- static s32 exfat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries,
- UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname)
- {
- s32 i;
- u64 sector;
- u16 *uniname = p_uniname->name;
- FILE_DENTRY_T *file_ep;
- STRM_DENTRY_T *strm_ep;
- NAME_DENTRY_T *name_ep;
- file_ep = (FILE_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry, §or);
- if (!file_ep)
- return -EIO;
- file_ep->num_ext = (u8)(num_entries - 1);
- dcache_modify(sb, sector);
- strm_ep = (STRM_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry+1, §or);
- if (!strm_ep)
- return -EIO;
- strm_ep->name_len = p_uniname->name_len;
- strm_ep->name_hash = cpu_to_le16(p_uniname->name_hash);
- dcache_modify(sb, sector);
- for (i = 2; i < num_entries; i++) {
- name_ep = (NAME_DENTRY_T *)get_dentry_in_dir(sb, p_dir, entry+i, §or);
- if (!name_ep)
- return -EIO;
- __init_name_entry(name_ep, uniname);
- dcache_modify(sb, sector);
- uniname += 15;
- }
- update_dir_chksum(sb, p_dir, entry);
- return 0;
- } /* end of exfat_init_ext_entry */
- static s32 exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries)
- {
- s32 i;
- u64 sector;
- DENTRY_T *ep;
- for (i = order; i < num_entries; i++) {
- ep = get_dentry_in_dir(sb, p_dir, entry+i, §or);
- if (!ep)
- return -EIO;
- exfat_set_entry_type(ep, TYPE_DELETED);
- if (dcache_modify(sb, sector))
- return -EIO;
- }
- return 0;
- }
- static s32 __write_partial_entries_in_entry_set(struct super_block *sb,
- ENTRY_SET_CACHE_T *es, u64 sec, u32 off, u32 count)
- {
- s32 num_entries;
- u32 buf_off = (off - es->offset);
- u32 remaining_byte_in_sector, copy_entries;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- u32 clu;
- u8 *buf, *esbuf = (u8 *)&(es->__buf);
- TMSG("%s entered\n", __func__);
- MMSG("%s: es %p sec %llu off %u cnt %d\n", __func__, es, sec, off, count);
- num_entries = count;
- while (num_entries) {
- /* write per sector base */
- remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off;
- copy_entries = min((s32)(remaining_byte_in_sector >> DENTRY_SIZE_BITS), num_entries);
- buf = dcache_getblk(sb, sec);
- if (!buf)
- goto err_out;
- MMSG("es->buf %p buf_off %u\n", esbuf, buf_off);
- MMSG("copying %d entries from %p to sector %llu\n", copy_entries, (esbuf + buf_off), sec);
- memcpy(buf + off, esbuf + buf_off, copy_entries << DENTRY_SIZE_BITS);
- dcache_modify(sb, sec);
- num_entries -= copy_entries;
- if (num_entries) {
- // get next sector
- if (IS_LAST_SECT_IN_CLUS(fsi, sec)) {
- clu = SECT_TO_CLUS(fsi, sec);
- if (es->alloc_flag == 0x03)
- clu++;
- else if (get_next_clus_safe(sb, &clu))
- goto err_out;
- sec = CLUS_TO_SECT(fsi, clu);
- } else {
- sec++;
- }
- off = 0;
- buf_off += copy_entries << DENTRY_SIZE_BITS;
- }
- }
- TMSG("%s exited successfully\n", __func__);
- return 0;
- err_out:
- TMSG("%s failed\n", __func__);
- return -EIO;
- }
- /* write back all entries in entry set */
- static s32 __write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es)
- {
- return __write_partial_entries_in_entry_set(sb, es, es->sector, es->offset, es->num_entries);
- }
- s32 update_dir_chksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es)
- {
- DENTRY_T *ep;
- u16 chksum = 0;
- s32 chksum_type = CS_DIR_ENTRY, i;
- ep = (DENTRY_T *)&(es->__buf);
- for (i = 0; i < es->num_entries; i++) {
- MMSG("%s %p\n", __func__, ep);
- chksum = calc_chksum_2byte((void *) ep, DENTRY_SIZE, chksum, chksum_type);
- ep++;
- chksum_type = CS_DEFAULT;
- }
- ep = (DENTRY_T *)&(es->__buf);
- ((FILE_DENTRY_T *)ep)->checksum = cpu_to_le16(chksum);
- return __write_whole_entry_set(sb, es);
- }
- /* returns a set of dentries for a file or dir.
- * Note that this is a copy (dump) of dentries so that user should call write_entry_set()
- * to apply changes made in this entry set to the real device.
- * in:
- * sb+p_dir+entry: indicates a file/dir
- * type: specifies how many dentries should be included.
- * out:
- * file_ep: will point the first dentry(= file dentry) on success
- * return:
- * pointer of entry set on success,
- * NULL on failure.
- */
- #define ES_MODE_STARTED 0
- #define ES_MODE_GET_FILE_ENTRY 1
- #define ES_MODE_GET_STRM_ENTRY 2
- #define ES_MODE_GET_NAME_ENTRY 3
- #define ES_MODE_GET_CRITICAL_SEC_ENTRY 4
- ENTRY_SET_CACHE_T *get_dentry_set_in_dir(struct super_block *sb,
- CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep)
- {
- s32 ret;
- u32 off, byte_offset, clu = 0;
- u32 entry_type;
- u64 sec;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- ENTRY_SET_CACHE_T *es = NULL;
- DENTRY_T *ep, *pos;
- u8 *buf;
- u8 num_entries;
- s32 mode = ES_MODE_STARTED;
- /* FIXME : is available in error case? */
- if (p_dir->dir == DIR_DELETED) {
- EMSG("%s : access to deleted dentry\n", __func__);
- BUG_ON(!fsi->prev_eio);
- return NULL;
- }
- TMSG("%s entered\n", __func__);
- MMSG("p_dir dir %u flags %x size %d\n", p_dir->dir, p_dir->flags, p_dir->size);
- MMSG("entry %d type %d\n", entry, type);
- byte_offset = entry << DENTRY_SIZE_BITS;
- ret = walk_fat_chain(sb, p_dir, byte_offset, &clu);
- if (ret)
- return NULL;
- /* byte offset in cluster */
- byte_offset &= fsi->cluster_size - 1;
- /* byte offset in sector */
- off = byte_offset & (u32)(sb->s_blocksize - 1);
- /* sector offset in cluster */
- sec = byte_offset >> (sb->s_blocksize_bits);
- sec += CLUS_TO_SECT(fsi, clu);
- buf = dcache_getblk(sb, sec);
- if (!buf)
- goto err_out;
- ep = (DENTRY_T *)(buf + off);
- entry_type = exfat_get_entry_type(ep);
- if ((entry_type != TYPE_FILE)
- && (entry_type != TYPE_DIR))
- goto err_out;
- if (type == ES_ALL_ENTRIES)
- num_entries = ((FILE_DENTRY_T *)ep)->num_ext+1;
- else
- num_entries = type;
- MMSG("trying to malloc %lx bytes for %d entries\n",
- (unsigned long)(offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T)), num_entries);
- es = kmalloc((offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T)), GFP_KERNEL);
- if (!es) {
- EMSG("%s: failed to alloc entryset\n", __func__);
- goto err_out;
- }
- es->num_entries = num_entries;
- es->sector = sec;
- es->offset = off;
- es->alloc_flag = p_dir->flags;
- pos = (DENTRY_T *) &(es->__buf);
- while (num_entries) {
- // instead of copying whole sector, we will check every entry.
- // this will provide minimum stablity and consistency.
- entry_type = exfat_get_entry_type(ep);
- if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED))
- goto err_out;
- switch (mode) {
- case ES_MODE_STARTED:
- if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR))
- mode = ES_MODE_GET_FILE_ENTRY;
- else
- goto err_out;
- break;
- case ES_MODE_GET_FILE_ENTRY:
- if (entry_type == TYPE_STREAM)
- mode = ES_MODE_GET_STRM_ENTRY;
- else
- goto err_out;
- break;
- case ES_MODE_GET_STRM_ENTRY:
- if (entry_type == TYPE_EXTEND)
- mode = ES_MODE_GET_NAME_ENTRY;
- else
- goto err_out;
- break;
- case ES_MODE_GET_NAME_ENTRY:
- if (entry_type == TYPE_EXTEND)
- break;
- else if (entry_type == TYPE_STREAM)
- goto err_out;
- else if (entry_type & TYPE_CRITICAL_SEC)
- mode = ES_MODE_GET_CRITICAL_SEC_ENTRY;
- else
- goto err_out;
- break;
- case ES_MODE_GET_CRITICAL_SEC_ENTRY:
- if ((entry_type == TYPE_EXTEND) || (entry_type == TYPE_STREAM))
- goto err_out;
- else if ((entry_type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC)
- goto err_out;
- break;
- }
- /* copy dentry */
- memcpy(pos, ep, sizeof(DENTRY_T));
- if (--num_entries == 0)
- break;
- if (((off + DENTRY_SIZE) & (u32)(sb->s_blocksize - 1)) <
- (off & (u32)(sb->s_blocksize - 1))) {
- // get the next sector
- if (IS_LAST_SECT_IN_CLUS(fsi, sec)) {
- if (es->alloc_flag == 0x03)
- clu++;
- else if (get_next_clus_safe(sb, &clu))
- goto err_out;
- sec = CLUS_TO_SECT(fsi, clu);
- } else {
- sec++;
- }
- buf = dcache_getblk(sb, sec);
- if (!buf)
- goto err_out;
- off = 0;
- ep = (DENTRY_T *)(buf);
- } else {
- ep++;
- off += DENTRY_SIZE;
- }
- pos++;
- }
- if (file_ep)
- *file_ep = (DENTRY_T *)&(es->__buf);
- MMSG("es sec %llu offset %u flags %d, num_entries %u buf ptr %p\n",
- es->sector, es->offset, es->alloc_flag, es->num_entries, &(es->__buf));
- TMSG("%s exited %p\n", __func__, es);
- return es;
- err_out:
- TMSG("%s exited (return NULL) (es %p)\n", __func__, es);
- /* kfree(NULL) is safe */
- kfree(es);
- es = NULL;
- return NULL;
- }
- void release_dentry_set(ENTRY_SET_CACHE_T *es)
- {
- TMSG("%s %p\n", __func__, es);
- /* kfree(NULL) is safe */
- kfree(es);
- es = NULL;
- }
- static s32 __extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order)
- {
- s32 i, len = 0;
- for (i = 0; i < 15; i++) {
- /* FIXME : unaligned? */
- *uniname = le16_to_cpu(ep->unicode_0_14[i]);
- if (*uniname == 0x0)
- return len;
- uniname++;
- len++;
- }
- *uniname = 0x0;
- return len;
- } /* end of __extract_uni_name_from_name_entry */
- #define DIRENT_STEP_FILE (0)
- #define DIRENT_STEP_STRM (1)
- #define DIRENT_STEP_NAME (2)
- #define DIRENT_STEP_SECD (3)
- /* return values of exfat_find_dir_entry()
- * >= 0 : return dir entiry position with the name in dir
- * -EEXIST : (root dir, ".") it is the root dir itself
- * -ENOENT : entry with the name does not exist
- * -EIO : I/O error
- */
- static s32 exfat_find_dir_entry(struct super_block *sb, FILE_ID_T *fid,
- CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *unused, u32 type)
- {
- s32 i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len;
- s32 order, step, name_len;
- s32 dentries_per_clu, num_empty = 0;
- u32 entry_type;
- u16 entry_uniname[16], *uniname = NULL, unichar;
- CHAIN_T clu;
- DENTRY_T *ep;
- HINT_T *hint_stat = &fid->hint_stat;
- HINT_FEMP_T candi_empty;
- FILE_DENTRY_T *file_ep;
- STRM_DENTRY_T *strm_ep;
- NAME_DENTRY_T *name_ep;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- /*
- * REMARK:
- * DOT and DOTDOT are handled by VFS layer
- */
- if (IS_CLUS_FREE(p_dir->dir))
- return -EIO;
- dentries_per_clu = fsi->dentries_per_clu;
- clu.dir = p_dir->dir;
- clu.size = p_dir->size;
- clu.flags = p_dir->flags;
- if (hint_stat->eidx) {
- clu.dir = hint_stat->clu;
- dentry = hint_stat->eidx;
- end_eidx = dentry;
- }
- candi_empty.eidx = -1;
- rewind:
- order = 0;
- step = DIRENT_STEP_FILE;
- while (!IS_CLUS_EOF(clu.dir)) {
- i = dentry & (dentries_per_clu - 1);
- for (; i < dentries_per_clu; i++, dentry++) {
- if (rewind && (dentry == end_eidx))
- goto not_found;
- ep = get_dentry_in_dir(sb, &clu, i, NULL);
- if (!ep)
- return -EIO;
- entry_type = exfat_get_entry_type(ep);
- if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) {
- step = DIRENT_STEP_FILE;
- num_empty++;
- if (candi_empty.eidx == -1) {
- if (num_empty == 1) {
- candi_empty.cur.dir = clu.dir;
- candi_empty.cur.size = clu.size;
- candi_empty.cur.flags = clu.flags;
- }
- if (num_empty >= num_entries) {
- candi_empty.eidx = dentry - (num_empty - 1);
- ASSERT(0 <= candi_empty.eidx);
- candi_empty.count = num_empty;
- if ((fid->hint_femp.eidx == -1) ||
- (candi_empty.eidx <= fid->hint_femp.eidx)) {
- memcpy(&fid->hint_femp,
- &candi_empty,
- sizeof(HINT_FEMP_T));
- }
- }
- }
- if (entry_type == TYPE_UNUSED)
- goto not_found;
- continue;
- }
- num_empty = 0;
- candi_empty.eidx = -1;
- if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) {
- step = DIRENT_STEP_FILE;
- if ((type == TYPE_ALL) || (type == entry_type)) {
- file_ep = (FILE_DENTRY_T *) ep;
- num_ext = file_ep->num_ext;
- step = DIRENT_STEP_STRM;
- }
- continue;
- }
- if (entry_type == TYPE_STREAM) {
- if (step != DIRENT_STEP_STRM) {
- step = DIRENT_STEP_FILE;
- continue;
- }
- step = DIRENT_STEP_FILE;
- strm_ep = (STRM_DENTRY_T *) ep;
- if ((p_uniname->name_hash == le16_to_cpu(strm_ep->name_hash)) &&
- (p_uniname->name_len == strm_ep->name_len)) {
- step = DIRENT_STEP_NAME;
- order = 1;
- name_len = 0;
- }
- continue;
- }
- if (entry_type == TYPE_EXTEND) {
- if (step != DIRENT_STEP_NAME) {
- step = DIRENT_STEP_FILE;
- continue;
- }
- name_ep = (NAME_DENTRY_T *) ep;
- if ((++order) == 2)
- uniname = p_uniname->name;
- else
- uniname += 15;
- len = __extract_uni_name_from_name_entry(name_ep, entry_uniname, order);
- name_len += len;
- unichar = *(uniname+len);
- *(uniname+len) = 0x0;
- if (nls_cmp_uniname(sb, uniname, entry_uniname)) {
- step = DIRENT_STEP_FILE;
- } else if (name_len == p_uniname->name_len) {
- if (order == num_ext) {
- //fid->hint_femp.eidx = -1;
- goto found;
- }
- step = DIRENT_STEP_SECD;
- }
- *(uniname+len) = unichar;
- continue;
- }
- if (entry_type & (TYPE_CRITICAL_SEC | TYPE_BENIGN_SEC)) {
- if (step == DIRENT_STEP_SECD) {
- if (++order == num_ext)
- goto found;
- continue;
- }
- }
- step = DIRENT_STEP_FILE;
- }
- if (clu.flags == 0x03) {
- if ((--clu.size) > 0)
- clu.dir++;
- else
- clu.dir = CLUS_EOF;
- } else {
- if (get_next_clus_safe(sb, &clu.dir))
- return -EIO;
- }
- }
- not_found:
- /* we started at not 0 index,so we should try to find target
- * from 0 index to the index we started at.
- */
- if (!rewind && end_eidx) {
- rewind = 1;
- dentry = 0;
- clu.dir = p_dir->dir;
- /* reset empty hint */
- num_empty = 0;
- candi_empty.eidx = -1;
- goto rewind;
- }
- /* initialized hint_stat */
- hint_stat->clu = p_dir->dir;
- hint_stat->eidx = 0;
- return -ENOENT;
- found:
- /* next dentry we'll find is out of this cluster */
- if (!((dentry + 1) & (dentries_per_clu-1))) {
- int ret = 0;
- if (clu.flags == 0x03) {
- if ((--clu.size) > 0)
- clu.dir++;
- else
- clu.dir = CLUS_EOF;
- } else {
- ret = get_next_clus_safe(sb, &clu.dir);
- }
- if (ret || IS_CLUS_EOF(clu.dir)) {
- /* just initialized hint_stat */
- hint_stat->clu = p_dir->dir;
- hint_stat->eidx = 0;
- return (dentry - num_ext);
- }
- }
- hint_stat->clu = clu.dir;
- hint_stat->eidx = dentry + 1;
- return (dentry - num_ext);
- } /* end of exfat_find_dir_entry */
- /* returns -EIO on error */
- static s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry)
- {
- s32 i, count = 0;
- u32 type;
- FILE_DENTRY_T *file_ep = (FILE_DENTRY_T *) p_entry;
- DENTRY_T *ext_ep;
- for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) {
- ext_ep = get_dentry_in_dir(sb, p_dir, entry, NULL);
- if (!ext_ep)
- return -EIO;
- type = exfat_get_entry_type(ext_ep);
- if ((type == TYPE_EXTEND) || (type == TYPE_STREAM))
- count++;
- else
- return count;
- }
- return count;
- } /* end of exfat_count_ext_entries */
- /*
- * Name Conversion Functions
- */
- static void exfat_get_uniname_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname)
- {
- s32 i;
- DENTRY_T *ep;
- ENTRY_SET_CACHE_T *es;
- es = get_dentry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep);
- if (!es)
- return;
- if (es->num_entries < 3)
- goto out;
- ep += 2;
- /*
- * First entry : file entry
- * Second entry : stream-extension entry
- * Third entry : first file-name entry
- * So, the index of first file-name dentry should start from 2.
- */
- for (i = 2; i < es->num_entries; i++, ep++) {
- /* end of name entry */
- if (exfat_get_entry_type(ep) != TYPE_EXTEND)
- goto out;
- __extract_uni_name_from_name_entry((NAME_DENTRY_T *)ep, uniname, i);
- uniname += 15;
- }
- out:
- release_dentry_set(es);
- } /* end of exfat_get_uniname_from_ext_entry */
- static s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname)
- {
- s32 len;
- len = p_uniname->name_len;
- if (len == 0)
- return 0;
- /* 1 file entry + 1 stream entry + name entries */
- return((len-1) / 15 + 3);
- } /* end of exfat_calc_num_entries */
- static s32 exfat_check_max_dentries(FILE_ID_T *fid)
- {
- if ((fid->size >> DENTRY_SIZE_BITS) >= MAX_EXFAT_DENTRIES) {
- /* exFAT spec allows a dir to grow upto 8388608(256MB) dentries */
- return -ENOSPC;
- }
- return 0;
- } /* end of check_max_dentries */
- /*
- * Allocation Bitmap Management Functions
- */
- s32 load_alloc_bmp(struct super_block *sb)
- {
- s32 ret;
- u32 i, j, map_size, type, need_map_size;
- u64 sector;
- CHAIN_T clu;
- BMAP_DENTRY_T *ep;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- clu.dir = fsi->root_dir;
- clu.flags = 0x01;
- while (!IS_CLUS_EOF(clu.dir)) {
- for (i = 0; i < fsi->dentries_per_clu; i++) {
- ep = (BMAP_DENTRY_T *) get_dentry_in_dir(sb, &clu, i, NULL);
- if (!ep)
- return -EIO;
- type = exfat_get_entry_type((DENTRY_T *) ep);
- if (type == TYPE_UNUSED)
- break;
- if (type != TYPE_BITMAP)
- continue;
- if (ep->flags == 0x0) {
- fsi->map_clu = le32_to_cpu(ep->start_clu);
- map_size = (u32) le64_to_cpu(ep->size);
- need_map_size = (((fsi->num_clusters - CLUS_BASE) - 1) >> 3) + 1;
- if (need_map_size != map_size) {
- sdfat_log_msg(sb, KERN_ERR,
- "bogus allocation bitmap size(need : %u, cur : %u)",
- need_map_size, map_size);
- /* Only allowed when bogus allocation bitmap size is large */
- if (need_map_size > map_size)
- return -EIO;
- }
- fsi->map_sectors = ((need_map_size - 1) >> (sb->s_blocksize_bits)) + 1;
- fsi->vol_amap =
- kmalloc((sizeof(struct buffer_head *) * fsi->map_sectors), GFP_KERNEL);
- if (!fsi->vol_amap)
- return -ENOMEM;
- sector = CLUS_TO_SECT(fsi, fsi->map_clu);
- for (j = 0; j < fsi->map_sectors; j++) {
- fsi->vol_amap[j] = NULL;
- ret = read_sect(sb, sector+j, &(fsi->vol_amap[j]), 1);
- if (ret) {
- /* release all buffers and free vol_amap */
- i = 0;
- while (i < j)
- brelse(fsi->vol_amap[i++]);
- /* kfree(NULL) is safe */
- kfree(fsi->vol_amap);
- fsi->vol_amap = NULL;
- return ret;
- }
- }
- fsi->pbr_bh = NULL;
- return 0;
- }
- }
- if (get_next_clus_safe(sb, &clu.dir))
- return -EIO;
- }
- return -EINVAL;
- } /* end of load_alloc_bmp */
- void free_alloc_bmp(struct super_block *sb)
- {
- s32 i;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- brelse(fsi->pbr_bh);
- for (i = 0; i < fsi->map_sectors; i++)
- __brelse(fsi->vol_amap[i]);
- /* kfree(NULL) is safe */
- kfree(fsi->vol_amap);
- fsi->vol_amap = NULL;
- }
- /* WARN :
- * If the value of "clu" is 0, it means cluster 2 which is
- * the first cluster of cluster heap.
- */
- static s32 set_alloc_bitmap(struct super_block *sb, u32 clu)
- {
- s32 i, b;
- u64 sector;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- i = clu >> (sb->s_blocksize_bits + 3);
- b = clu & (u32)((sb->s_blocksize << 3) - 1);
- sector = CLUS_TO_SECT(fsi, fsi->map_clu) + i;
- bitmap_set((unsigned long *)(fsi->vol_amap[i]->b_data), b, 1);
- return write_sect(sb, sector, fsi->vol_amap[i], 0);
- } /* end of set_alloc_bitmap */
- /* WARN :
- * If the value of "clu" is 0, it means cluster 2 which is
- * the first cluster of cluster heap.
- */
- static s32 clr_alloc_bitmap(struct super_block *sb, u32 clu)
- {
- s32 ret;
- s32 i, b;
- u64 sector;
- struct sdfat_sb_info *sbi = SDFAT_SB(sb);
- struct sdfat_mount_options *opts = &sbi->options;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- i = clu >> (sb->s_blocksize_bits + 3);
- b = clu & (u32)((sb->s_blocksize << 3) - 1);
- sector = CLUS_TO_SECT(fsi, fsi->map_clu) + i;
- bitmap_clear((unsigned long *)(fsi->vol_amap[i]->b_data), b, 1);
- ret = write_sect(sb, sector, fsi->vol_amap[i], 0);
- if (opts->discard) {
- s32 ret_discard;
- TMSG("discard cluster(%08x)\n", clu+2);
- ret_discard = sb_issue_discard(sb, CLUS_TO_SECT(fsi, clu+2),
- (1 << fsi->sect_per_clus_bits), GFP_NOFS, 0);
- if (ret_discard == -EOPNOTSUPP) {
- sdfat_msg(sb, KERN_ERR,
- "discard not supported by device, disabling");
- opts->discard = 0;
- }
- }
- return ret;
- } /* end of clr_alloc_bitmap */
- /* WARN :
- * If the value of "clu" is 0, it means cluster 2 which is
- * the first cluster of cluster heap.
- */
- static u32 test_alloc_bitmap(struct super_block *sb, u32 clu)
- {
- u32 i, map_i, map_b;
- u32 clu_base, clu_free;
- u8 k, clu_mask;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- clu_base = (clu & ~(0x7)) + 2;
- clu_mask = (1 << (clu - clu_base + 2)) - 1;
- map_i = clu >> (sb->s_blocksize_bits + 3);
- map_b = (clu >> 3) & (u32)(sb->s_blocksize - 1);
- for (i = 2; i < fsi->num_clusters; i += 8) {
- k = *(((u8 *) fsi->vol_amap[map_i]->b_data) + map_b);
- if (clu_mask > 0) {
- k |= clu_mask;
- clu_mask = 0;
- }
- if (k < 0xFF) {
- clu_free = clu_base + free_bit[k];
- if (clu_free < fsi->num_clusters)
- return clu_free;
- }
- clu_base += 8;
- if (((++map_b) >= (u32)sb->s_blocksize) ||
- (clu_base >= fsi->num_clusters)) {
- if ((++map_i) >= fsi->map_sectors) {
- clu_base = 2;
- map_i = 0;
- }
- map_b = 0;
- }
- }
- return CLUS_EOF;
- } /* end of test_alloc_bitmap */
- void sync_alloc_bmp(struct super_block *sb)
- {
- s32 i;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- if (fsi->vol_amap == NULL)
- return;
- for (i = 0; i < fsi->map_sectors; i++)
- sync_dirty_buffer(fsi->vol_amap[i]);
- }
- static s32 exfat_chain_cont_cluster(struct super_block *sb, u32 chain, u32 len)
- {
- if (!len)
- return 0;
- while (len > 1) {
- if (fat_ent_set(sb, chain, chain+1))
- return -EIO;
- chain++;
- len--;
- }
- if (fat_ent_set(sb, chain, CLUS_EOF))
- return -EIO;
- return 0;
- }
- s32 chain_cont_cluster(struct super_block *sb, u32 chain, u32 len)
- {
- return exfat_chain_cont_cluster(sb, chain, len);
- }
- static s32 exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse)
- {
- s32 ret = -EIO;
- u32 num_clusters = 0;
- u32 clu;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- s32 i;
- u64 sector;
- /* invalid cluster number */
- if (IS_CLUS_FREE(p_chain->dir) || IS_CLUS_EOF(p_chain->dir))
- return 0;
- /* no cluster to truncate */
- if (p_chain->size == 0) {
- DMSG("%s: cluster(%u) truncation is not required.",
- __func__, p_chain->dir);
- return 0;
- }
- /* check cluster validation */
- if (!is_valid_clus(fsi, p_chain->dir)) {
- EMSG("%s: invalid start cluster (%u)\n", __func__, p_chain->dir);
- sdfat_debug_bug_on(1);
- return -EIO;
- }
- set_sb_dirty(sb);
- clu = p_chain->dir;
- if (p_chain->flags == 0x03) {
- do {
- if (do_relse) {
- sector = CLUS_TO_SECT(fsi, clu);
- for (i = 0; i < fsi->sect_per_clus; i++) {
- if (dcache_release(sb, sector+i) == -EIO)
- goto out;
- }
- }
- if (clr_alloc_bitmap(sb, clu-2))
- goto out;
- clu++;
- num_clusters++;
- } while (num_clusters < p_chain->size);
- } else {
- do {
- if (do_relse) {
- sector = CLUS_TO_SECT(fsi, clu);
- for (i = 0; i < fsi->sect_per_clus; i++) {
- if (dcache_release(sb, sector+i) == -EIO)
- goto out;
- }
- }
- if (clr_alloc_bitmap(sb, (clu - CLUS_BASE)))
- goto out;
- if (get_next_clus_safe(sb, &clu))
- goto out;
- num_clusters++;
- } while (!IS_CLUS_EOF(clu));
- }
- /* success */
- ret = 0;
- out:
- fsi->used_clusters -= num_clusters;
- return ret;
- } /* end of exfat_free_cluster */
- static s32 exfat_alloc_cluster(struct super_block *sb, u32 num_alloc, CHAIN_T *p_chain, s32 dest)
- {
- s32 ret = -ENOSPC;
- u32 num_clusters = 0, total_cnt;
- u32 hint_clu, new_clu, last_clu = CLUS_EOF;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- total_cnt = fsi->num_clusters - CLUS_BASE;
- if (unlikely(total_cnt < fsi->used_clusters)) {
- sdfat_fs_error_ratelimit(sb,
- "%s: invalid used clusters(t:%u,u:%u)\n",
- __func__, total_cnt, fsi->used_clusters);
- return -EIO;
- }
- if (num_alloc > total_cnt - fsi->used_clusters)
- return -ENOSPC;
- hint_clu = p_chain->dir;
- /* find new cluster */
- if (IS_CLUS_EOF(hint_clu)) {
- if (fsi->clu_srch_ptr < CLUS_BASE) {
- EMSG("%s: fsi->clu_srch_ptr is invalid (%u)\n",
- __func__, fsi->clu_srch_ptr);
- ASSERT(0);
- fsi->clu_srch_ptr = CLUS_BASE;
- }
- hint_clu = test_alloc_bitmap(sb, fsi->clu_srch_ptr - CLUS_BASE);
- if (IS_CLUS_EOF(hint_clu))
- return -ENOSPC;
- }
- /* check cluster validation */
- if (!is_valid_clus(fsi, hint_clu)) {
- /* "last + 1" can be passed as hint_clu. Otherwise, bug_on */
- if (hint_clu != fsi->num_clusters) {
- EMSG("%s: hint_cluster is invalid (%u)\n",
- __func__, hint_clu);
- sdfat_debug_bug_on(1);
- }
- hint_clu = CLUS_BASE;
- if (p_chain->flags == 0x03) {
- if (exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters))
- return -EIO;
- p_chain->flags = 0x01;
- }
- }
- set_sb_dirty(sb);
- p_chain->dir = CLUS_EOF;
- while ((new_clu = test_alloc_bitmap(sb, hint_clu - CLUS_BASE)) != CLUS_EOF) {
- if ((new_clu != hint_clu) && (p_chain->flags == 0x03)) {
- if (exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters)) {
- ret = -EIO;
- goto error;
- }
- p_chain->flags = 0x01;
- }
- /* update allocation bitmap */
- if (set_alloc_bitmap(sb, new_clu - CLUS_BASE)) {
- ret = -EIO;
- goto error;
- }
- num_clusters++;
- /* update FAT table */
- if (p_chain->flags == 0x01) {
- if (fat_ent_set(sb, new_clu, CLUS_EOF)) {
- ret = -EIO;
- goto error;
- }
- }
- if (IS_CLUS_EOF(p_chain->dir)) {
- p_chain->dir = new_clu;
- } else if (p_chain->flags == 0x01) {
- if (fat_ent_set(sb, last_clu, new_clu)) {
- ret = -EIO;
- goto error;
- }
- }
- last_clu = new_clu;
- if ((--num_alloc) == 0) {
- fsi->clu_srch_ptr = hint_clu;
- fsi->used_clusters += num_clusters;
- p_chain->size += num_clusters;
- return 0;
- }
- hint_clu = new_clu + 1;
- if (hint_clu >= fsi->num_clusters) {
- hint_clu = CLUS_BASE;
- if (p_chain->flags == 0x03) {
- if (exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters)) {
- ret = -EIO;
- goto error;
- }
- p_chain->flags = 0x01;
- }
- }
- }
- error:
- if (num_clusters)
- exfat_free_cluster(sb, p_chain, 0);
- return ret;
- } /* end of exfat_alloc_cluster */
- static s32 exfat_count_used_clusters(struct super_block *sb, u32 *ret_count)
- {
- u32 count = 0;
- u32 i, map_i, map_b;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- u32 total_clus = fsi->num_clusters - 2;
- map_i = map_b = 0;
- for (i = 0; i < total_clus; i += 8) {
- u8 k = *(((u8 *) fsi->vol_amap[map_i]->b_data) + map_b);
- count += used_bit[k];
- if ((++map_b) >= (u32)sb->s_blocksize) {
- map_i++;
- map_b = 0;
- }
- }
- /* FIXME : abnormal bitmap count should be handled as more smart */
- if (total_clus < count)
- count = total_clus;
- *ret_count = count;
- return 0;
- } /* end of exfat_count_used_clusters */
- /*
- * File Operation Functions
- */
- static FS_FUNC_T exfat_fs_func = {
- .alloc_cluster = exfat_alloc_cluster,
- .free_cluster = exfat_free_cluster,
- .count_used_clusters = exfat_count_used_clusters,
- .init_dir_entry = exfat_init_dir_entry,
- .init_ext_entry = exfat_init_ext_entry,
- .find_dir_entry = exfat_find_dir_entry,
- .delete_dir_entry = exfat_delete_dir_entry,
- .get_uniname_from_ext_entry = exfat_get_uniname_from_ext_entry,
- .count_ext_entries = exfat_count_ext_entries,
- .calc_num_entries = exfat_calc_num_entries,
- .check_max_dentries = exfat_check_max_dentries,
- .get_entry_type = exfat_get_entry_type,
- .set_entry_type = exfat_set_entry_type,
- .get_entry_attr = exfat_get_entry_attr,
- .set_entry_attr = exfat_set_entry_attr,
- .get_entry_flag = exfat_get_entry_flag,
- .set_entry_flag = exfat_set_entry_flag,
- .get_entry_clu0 = exfat_get_entry_clu0,
- .set_entry_clu0 = exfat_set_entry_clu0,
- .get_entry_size = exfat_get_entry_size,
- .set_entry_size = exfat_set_entry_size,
- .get_entry_time = exfat_get_entry_time,
- .set_entry_time = exfat_set_entry_time,
- };
- s32 mount_exfat(struct super_block *sb, pbr_t *p_pbr)
- {
- pbr64_t *p_bpb = (pbr64_t *)p_pbr;
- FS_INFO_T *fsi = &(SDFAT_SB(sb)->fsi);
- fsi->sect_per_clus = 1 << p_bpb->bsx.sect_per_clus_bits;
- fsi->sect_per_clus_bits = p_bpb->bsx.sect_per_clus_bits;
- fsi->cluster_size_bits = fsi->sect_per_clus_bits + sb->s_blocksize_bits;
- fsi->cluster_size = 1 << fsi->cluster_size_bits;
- if (!p_bpb->bsx.num_fats) {
- sdfat_msg(sb, KERN_ERR, "bogus number of FAT structure");
- return -EINVAL;
- }
- if (p_bpb->bsx.num_fats >= 2) {
- sdfat_msg(sb, KERN_WARNING,
- "unsupported number of FAT structure :%u, try with 1",
- p_bpb->bsx.num_fats);
- }
- fsi->num_FAT_sectors = le32_to_cpu(p_bpb->bsx.fat_length);
- if (!fsi->num_FAT_sectors) {
- sdfat_msg(sb, KERN_ERR, "bogus fat size");
- return -EINVAL;
- }
- fsi->FAT1_start_sector = le32_to_cpu(p_bpb->bsx.fat_offset);
- fsi->FAT2_start_sector = fsi->FAT1_start_sector;
- fsi->root_start_sector = le32_to_cpu(p_bpb->bsx.clu_offset);
- fsi->data_start_sector = fsi->root_start_sector;
- fsi->num_sectors = le64_to_cpu(p_bpb->bsx.vol_length);
- if (!fsi->num_sectors) {
- sdfat_msg(sb, KERN_ERR, "bogus number of total sector count");
- return -EINVAL;
- }
- /* because the cluster index starts with 2 */
- fsi->num_clusters = le32_to_cpu(p_bpb->bsx.clu_count) + CLUS_BASE;
- fsi->vol_id = le32_to_cpu(p_bpb->bsx.vol_serial);
- fsi->root_dir = le32_to_cpu(p_bpb->bsx.root_cluster);
- fsi->dentries_in_root = 0;
- fsi->dentries_per_clu = 1 << (fsi->cluster_size_bits - DENTRY_SIZE_BITS);
- fsi->vol_flag = (u32) le16_to_cpu(p_bpb->bsx.vol_flags);
- fsi->clu_srch_ptr = CLUS_BASE;
- fsi->used_clusters = (u32) ~0;
- fsi->fs_func = &exfat_fs_func;
- fsi->vol_type = EXFAT;
- fat_ent_ops_init(sb);
- if (p_bpb->bsx.vol_flags & VOL_DIRTY) {
- fsi->vol_flag |= VOL_DIRTY;
- sdfat_log_msg(sb, KERN_WARNING, "Volume was not properly "
- "unmounted. Some data may be corrupt. "
- "Please run fsck.");
- }
- return 0;
- } /* end of mount_exfat */
- /* end of core_exfat.c */
|