| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * super.c
- *
- * PURPOSE
- * Super block routines for the OSTA-UDF(tm) filesystem.
- *
- * DESCRIPTION
- * OSTA-UDF(tm) = Optical Storage Technology Association
- * Universal Disk Format.
- *
- * This code is based on version 2.00 of the UDF specification,
- * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346].
- * http://www.osta.org/
- * https://www.ecma.ch/
- * https://www.iso.org/
- *
- * COPYRIGHT
- * (C) 1998 Dave Boynton
- * (C) 1998-2004 Ben Fennema
- * (C) 2000 Stelias Computing Inc
- *
- * HISTORY
- *
- * 09/24/98 dgb changed to allow compiling outside of kernel, and
- * added some debugging.
- * 10/01/98 dgb updated to allow (some) possibility of compiling w/2.0.34
- * 10/16/98 attempting some multi-session support
- * 10/17/98 added freespace count for "df"
- * 11/11/98 gr added novrs option
- * 11/26/98 dgb added fileset,anchor mount options
- * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced
- * vol descs. rewrote option handling based on isofs
- * 12/20/98 find the free space bitmap (if it exists)
- */
- #include "udfdecl.h"
- #include <linux/blkdev.h>
- #include <linux/slab.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/stat.h>
- #include <linux/cdrom.h>
- #include <linux/nls.h>
- #include <linux/vfs.h>
- #include <linux/vmalloc.h>
- #include <linux/errno.h>
- #include <linux/seq_file.h>
- #include <linux/bitmap.h>
- #include <linux/crc-itu-t.h>
- #include <linux/log2.h>
- #include <asm/byteorder.h>
- #include <linux/iversion.h>
- #include <linux/fs_context.h>
- #include <linux/fs_parser.h>
- #include "udf_sb.h"
- #include "udf_i.h"
- #include <linux/init.h>
- #include <linux/uaccess.h>
- enum {
- VDS_POS_PRIMARY_VOL_DESC,
- VDS_POS_UNALLOC_SPACE_DESC,
- VDS_POS_LOGICAL_VOL_DESC,
- VDS_POS_IMP_USE_VOL_DESC,
- VDS_POS_LENGTH
- };
- #define VSD_FIRST_SECTOR_OFFSET 32768
- #define VSD_MAX_SECTOR_OFFSET 0x800000
- /*
- * Maximum number of Terminating Descriptor / Logical Volume Integrity
- * Descriptor redirections. The chosen numbers are arbitrary - just that we
- * hopefully don't limit any real use of rewritten inode on write-once media
- * but avoid looping for too long on corrupted media.
- */
- #define UDF_MAX_TD_NESTING 64
- #define UDF_MAX_LVID_NESTING 1000
- enum { UDF_MAX_LINKS = 0xffff };
- /*
- * We limit filesize to 4TB. This is arbitrary as the on-disk format supports
- * more but because the file space is described by a linked list of extents,
- * each of which can have at most 1GB, the creation and handling of extents
- * gets unusably slow beyond certain point...
- */
- #define UDF_MAX_FILESIZE (1ULL << 42)
- /* These are the "meat" - everything else is stuffing */
- static int udf_fill_super(struct super_block *sb, struct fs_context *fc);
- static void udf_put_super(struct super_block *);
- static int udf_sync_fs(struct super_block *, int);
- static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad);
- static void udf_open_lvid(struct super_block *);
- static void udf_close_lvid(struct super_block *);
- static unsigned int udf_count_free(struct super_block *);
- static int udf_statfs(struct dentry *, struct kstatfs *);
- static int udf_show_options(struct seq_file *, struct dentry *);
- static int udf_init_fs_context(struct fs_context *fc);
- static int udf_parse_param(struct fs_context *fc, struct fs_parameter *param);
- static int udf_reconfigure(struct fs_context *fc);
- static void udf_free_fc(struct fs_context *fc);
- static const struct fs_parameter_spec udf_param_spec[];
- struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)
- {
- struct logicalVolIntegrityDesc *lvid;
- unsigned int partnum;
- unsigned int offset;
- if (!UDF_SB(sb)->s_lvid_bh)
- return NULL;
- lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data;
- partnum = le32_to_cpu(lvid->numOfPartitions);
- /* The offset is to skip freeSpaceTable and sizeTable arrays */
- offset = partnum * 2 * sizeof(uint32_t);
- return (struct logicalVolIntegrityDescImpUse *)
- (((uint8_t *)(lvid + 1)) + offset);
- }
- /* UDF filesystem type */
- static int udf_get_tree(struct fs_context *fc)
- {
- return get_tree_bdev(fc, udf_fill_super);
- }
- static const struct fs_context_operations udf_context_ops = {
- .parse_param = udf_parse_param,
- .get_tree = udf_get_tree,
- .reconfigure = udf_reconfigure,
- .free = udf_free_fc,
- };
- static struct file_system_type udf_fstype = {
- .owner = THIS_MODULE,
- .name = "udf",
- .kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV,
- .init_fs_context = udf_init_fs_context,
- .parameters = udf_param_spec,
- };
- MODULE_ALIAS_FS("udf");
- static struct kmem_cache *udf_inode_cachep;
- static struct inode *udf_alloc_inode(struct super_block *sb)
- {
- struct udf_inode_info *ei;
- ei = alloc_inode_sb(sb, udf_inode_cachep, GFP_KERNEL);
- if (!ei)
- return NULL;
- ei->i_unique = 0;
- ei->i_lenExtents = 0;
- ei->i_lenStreams = 0;
- ei->i_next_alloc_block = 0;
- ei->i_next_alloc_goal = 0;
- ei->i_strat4096 = 0;
- ei->i_streamdir = 0;
- ei->i_hidden = 0;
- init_rwsem(&ei->i_data_sem);
- ei->cached_extent.lstart = -1;
- spin_lock_init(&ei->i_extent_cache_lock);
- inode_set_iversion(&ei->vfs_inode, 1);
- return &ei->vfs_inode;
- }
- static void udf_free_in_core_inode(struct inode *inode)
- {
- kmem_cache_free(udf_inode_cachep, UDF_I(inode));
- }
- static void init_once(void *foo)
- {
- struct udf_inode_info *ei = foo;
- ei->i_data = NULL;
- inode_init_once(&ei->vfs_inode);
- }
- static int __init init_inodecache(void)
- {
- udf_inode_cachep = kmem_cache_create("udf_inode_cache",
- sizeof(struct udf_inode_info),
- 0, (SLAB_RECLAIM_ACCOUNT |
- SLAB_ACCOUNT),
- init_once);
- if (!udf_inode_cachep)
- return -ENOMEM;
- return 0;
- }
- static void destroy_inodecache(void)
- {
- /*
- * Make sure all delayed rcu free inodes are flushed before we
- * destroy cache.
- */
- rcu_barrier();
- kmem_cache_destroy(udf_inode_cachep);
- }
- /* Superblock operations */
- static const struct super_operations udf_sb_ops = {
- .alloc_inode = udf_alloc_inode,
- .free_inode = udf_free_in_core_inode,
- .write_inode = udf_write_inode,
- .evict_inode = udf_evict_inode,
- .put_super = udf_put_super,
- .sync_fs = udf_sync_fs,
- .statfs = udf_statfs,
- .show_options = udf_show_options,
- };
- struct udf_options {
- unsigned int blocksize;
- unsigned int session;
- unsigned int lastblock;
- unsigned int anchor;
- unsigned int flags;
- umode_t umask;
- kgid_t gid;
- kuid_t uid;
- umode_t fmode;
- umode_t dmode;
- struct nls_table *nls_map;
- };
- /*
- * UDF has historically preserved prior mount options across
- * a remount, so copy those here if remounting, otherwise set
- * initial mount defaults.
- */
- static void udf_init_options(struct fs_context *fc, struct udf_options *uopt)
- {
- if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
- struct super_block *sb = fc->root->d_sb;
- struct udf_sb_info *sbi = UDF_SB(sb);
- uopt->flags = sbi->s_flags;
- uopt->uid = sbi->s_uid;
- uopt->gid = sbi->s_gid;
- uopt->umask = sbi->s_umask;
- uopt->fmode = sbi->s_fmode;
- uopt->dmode = sbi->s_dmode;
- uopt->nls_map = NULL;
- } else {
- uopt->flags = (1 << UDF_FLAG_USE_AD_IN_ICB) |
- (1 << UDF_FLAG_STRICT);
- /*
- * By default we'll use overflow[ug]id when UDF
- * inode [ug]id == -1
- */
- uopt->uid = make_kuid(current_user_ns(), overflowuid);
- uopt->gid = make_kgid(current_user_ns(), overflowgid);
- uopt->umask = 0;
- uopt->fmode = UDF_INVALID_MODE;
- uopt->dmode = UDF_INVALID_MODE;
- uopt->nls_map = NULL;
- uopt->session = 0xFFFFFFFF;
- }
- }
- static int udf_init_fs_context(struct fs_context *fc)
- {
- struct udf_options *uopt;
- uopt = kzalloc_obj(*uopt);
- if (!uopt)
- return -ENOMEM;
- udf_init_options(fc, uopt);
- fc->fs_private = uopt;
- fc->ops = &udf_context_ops;
- return 0;
- }
- static void udf_free_fc(struct fs_context *fc)
- {
- struct udf_options *uopt = fc->fs_private;
- unload_nls(uopt->nls_map);
- kfree(fc->fs_private);
- }
- static int __init init_udf_fs(void)
- {
- int err;
- err = init_inodecache();
- if (err)
- goto out1;
- err = register_filesystem(&udf_fstype);
- if (err)
- goto out;
- return 0;
- out:
- destroy_inodecache();
- out1:
- return err;
- }
- static void __exit exit_udf_fs(void)
- {
- unregister_filesystem(&udf_fstype);
- destroy_inodecache();
- }
- static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- sbi->s_partmaps = kzalloc_objs(*sbi->s_partmaps, count);
- if (!sbi->s_partmaps) {
- sbi->s_partitions = 0;
- return -ENOMEM;
- }
- sbi->s_partitions = count;
- return 0;
- }
- static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
- {
- int i;
- int nr_groups = bitmap->s_nr_groups;
- for (i = 0; i < nr_groups; i++)
- if (!IS_ERR_OR_NULL(bitmap->s_block_bitmap[i]))
- brelse(bitmap->s_block_bitmap[i]);
- kvfree(bitmap);
- }
- static void udf_free_partition(struct udf_part_map *map)
- {
- int i;
- struct udf_meta_data *mdata;
- if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
- iput(map->s_uspace.s_table);
- if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
- udf_sb_free_bitmap(map->s_uspace.s_bitmap);
- if (map->s_partition_type == UDF_SPARABLE_MAP15)
- for (i = 0; i < 4; i++)
- brelse(map->s_type_specific.s_sparing.s_spar_map[i]);
- else if (map->s_partition_type == UDF_METADATA_MAP25) {
- mdata = &map->s_type_specific.s_metadata;
- iput(mdata->s_metadata_fe);
- mdata->s_metadata_fe = NULL;
- iput(mdata->s_mirror_fe);
- mdata->s_mirror_fe = NULL;
- iput(mdata->s_bitmap_fe);
- mdata->s_bitmap_fe = NULL;
- }
- }
- static void udf_sb_free_partitions(struct super_block *sb)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- int i;
- if (!sbi->s_partmaps)
- return;
- for (i = 0; i < sbi->s_partitions; i++)
- udf_free_partition(&sbi->s_partmaps[i]);
- kfree(sbi->s_partmaps);
- sbi->s_partmaps = NULL;
- }
- static int udf_show_options(struct seq_file *seq, struct dentry *root)
- {
- struct super_block *sb = root->d_sb;
- struct udf_sb_info *sbi = UDF_SB(sb);
- if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT))
- seq_puts(seq, ",nostrict");
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_BLOCKSIZE_SET))
- seq_printf(seq, ",bs=%lu", sb->s_blocksize);
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
- seq_puts(seq, ",unhide");
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
- seq_puts(seq, ",undelete");
- if (!UDF_QUERY_FLAG(sb, UDF_FLAG_USE_AD_IN_ICB))
- seq_puts(seq, ",noadinicb");
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_USE_SHORT_AD))
- seq_puts(seq, ",shortad");
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_FORGET))
- seq_puts(seq, ",uid=forget");
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_FORGET))
- seq_puts(seq, ",gid=forget");
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET))
- seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, sbi->s_uid));
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET))
- seq_printf(seq, ",gid=%u", from_kgid(&init_user_ns, sbi->s_gid));
- if (sbi->s_umask != 0)
- seq_printf(seq, ",umask=%ho", sbi->s_umask);
- if (sbi->s_fmode != UDF_INVALID_MODE)
- seq_printf(seq, ",mode=%ho", sbi->s_fmode);
- if (sbi->s_dmode != UDF_INVALID_MODE)
- seq_printf(seq, ",dmode=%ho", sbi->s_dmode);
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_SESSION_SET))
- seq_printf(seq, ",session=%d", sbi->s_session);
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET))
- seq_printf(seq, ",lastblock=%u", sbi->s_last_block);
- if (sbi->s_anchor != 0)
- seq_printf(seq, ",anchor=%u", sbi->s_anchor);
- if (sbi->s_nls_map)
- seq_printf(seq, ",iocharset=%s", sbi->s_nls_map->charset);
- else
- seq_puts(seq, ",iocharset=utf8");
- return 0;
- }
- /*
- * udf_parse_param
- *
- * PURPOSE
- * Parse mount options.
- *
- * DESCRIPTION
- * The following mount options are supported:
- *
- * gid= Set the default group.
- * umask= Set the default umask.
- * mode= Set the default file permissions.
- * dmode= Set the default directory permissions.
- * uid= Set the default user.
- * bs= Set the block size.
- * unhide Show otherwise hidden files.
- * undelete Show deleted files in lists.
- * adinicb Embed data in the inode (default)
- * noadinicb Don't embed data in the inode
- * shortad Use short ad's
- * longad Use long ad's (default)
- * nostrict Unset strict conformance
- * iocharset= Set the NLS character set
- *
- * The remaining are for debugging and disaster recovery:
- *
- * novrs Skip volume sequence recognition
- *
- * The following expect a offset from 0.
- *
- * session= Set the CDROM session (default= last session)
- * anchor= Override standard anchor location. (default= 256)
- * volume= Override the VolumeDesc location. (unused)
- * partition= Override the PartitionDesc location. (unused)
- * lastblock= Set the last block of the filesystem/
- *
- * The following expect a offset from the partition root.
- *
- * fileset= Override the fileset block location. (unused)
- * rootdir= Override the root directory location. (unused)
- * WARNING: overriding the rootdir to a non-directory may
- * yield highly unpredictable results.
- *
- * PRE-CONDITIONS
- * fc fs_context with pointer to mount options variable.
- * param Pointer to fs_parameter being parsed.
- *
- * POST-CONDITIONS
- * <return> 0 Mount options parsed okay.
- * <return> errno Error parsing mount options.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
- enum {
- Opt_novrs, Opt_nostrict, Opt_bs, Opt_unhide, Opt_undelete,
- Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad,
- Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock,
- Opt_anchor, Opt_volume, Opt_partition, Opt_fileset,
- Opt_rootdir, Opt_utf8, Opt_iocharset, Opt_err, Opt_fmode, Opt_dmode
- };
- static const struct fs_parameter_spec udf_param_spec[] = {
- fsparam_flag ("novrs", Opt_novrs),
- fsparam_flag ("nostrict", Opt_nostrict),
- fsparam_u32 ("bs", Opt_bs),
- fsparam_flag ("unhide", Opt_unhide),
- fsparam_flag ("undelete", Opt_undelete),
- fsparam_flag_no ("adinicb", Opt_adinicb),
- fsparam_flag ("shortad", Opt_shortad),
- fsparam_flag ("longad", Opt_longad),
- fsparam_string ("gid", Opt_gid),
- fsparam_string ("uid", Opt_uid),
- fsparam_u32 ("umask", Opt_umask),
- fsparam_u32 ("session", Opt_session),
- fsparam_u32 ("lastblock", Opt_lastblock),
- fsparam_u32 ("anchor", Opt_anchor),
- fsparam_u32 ("volume", Opt_volume),
- fsparam_u32 ("partition", Opt_partition),
- fsparam_u32 ("fileset", Opt_fileset),
- fsparam_u32 ("rootdir", Opt_rootdir),
- fsparam_flag ("utf8", Opt_utf8),
- fsparam_string ("iocharset", Opt_iocharset),
- fsparam_u32 ("mode", Opt_fmode),
- fsparam_u32 ("dmode", Opt_dmode),
- {}
- };
- static int udf_parse_param(struct fs_context *fc, struct fs_parameter *param)
- {
- unsigned int uv;
- unsigned int n;
- struct udf_options *uopt = fc->fs_private;
- struct fs_parse_result result;
- int token;
- bool remount = (fc->purpose & FS_CONTEXT_FOR_RECONFIGURE);
- token = fs_parse(fc, udf_param_spec, param, &result);
- if (token < 0)
- return token;
- switch (token) {
- case Opt_novrs:
- uopt->flags |= (1 << UDF_FLAG_NOVRS);
- break;
- case Opt_bs:
- n = result.uint_32;
- if (n != 512 && n != 1024 && n != 2048 && n != 4096)
- return -EINVAL;
- uopt->blocksize = n;
- uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET);
- break;
- case Opt_unhide:
- uopt->flags |= (1 << UDF_FLAG_UNHIDE);
- break;
- case Opt_undelete:
- uopt->flags |= (1 << UDF_FLAG_UNDELETE);
- break;
- case Opt_adinicb:
- if (result.negated)
- uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
- else
- uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
- break;
- case Opt_shortad:
- uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
- break;
- case Opt_longad:
- uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
- break;
- case Opt_gid:
- if (kstrtoint(param->string, 10, &uv) == 0) {
- kgid_t gid = make_kgid(current_user_ns(), uv);
- if (!gid_valid(gid))
- return -EINVAL;
- uopt->gid = gid;
- uopt->flags |= (1 << UDF_FLAG_GID_SET);
- } else if (!strcmp(param->string, "forget")) {
- uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
- } else if (!strcmp(param->string, "ignore")) {
- /* this option is superseded by gid=<number> */
- ;
- } else {
- return -EINVAL;
- }
- break;
- case Opt_uid:
- if (kstrtoint(param->string, 10, &uv) == 0) {
- kuid_t uid = make_kuid(current_user_ns(), uv);
- if (!uid_valid(uid))
- return -EINVAL;
- uopt->uid = uid;
- uopt->flags |= (1 << UDF_FLAG_UID_SET);
- } else if (!strcmp(param->string, "forget")) {
- uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
- } else if (!strcmp(param->string, "ignore")) {
- /* this option is superseded by uid=<number> */
- ;
- } else {
- return -EINVAL;
- }
- break;
- case Opt_umask:
- uopt->umask = result.uint_32;
- break;
- case Opt_nostrict:
- uopt->flags &= ~(1 << UDF_FLAG_STRICT);
- break;
- case Opt_session:
- uopt->session = result.uint_32;
- if (!remount)
- uopt->flags |= (1 << UDF_FLAG_SESSION_SET);
- break;
- case Opt_lastblock:
- uopt->lastblock = result.uint_32;
- if (!remount)
- uopt->flags |= (1 << UDF_FLAG_LASTBLOCK_SET);
- break;
- case Opt_anchor:
- uopt->anchor = result.uint_32;
- break;
- case Opt_volume:
- case Opt_partition:
- case Opt_fileset:
- case Opt_rootdir:
- /* Ignored (never implemented properly) */
- break;
- case Opt_utf8:
- if (!remount) {
- unload_nls(uopt->nls_map);
- uopt->nls_map = NULL;
- }
- break;
- case Opt_iocharset:
- if (!remount) {
- unload_nls(uopt->nls_map);
- uopt->nls_map = NULL;
- }
- /* When nls_map is not loaded then UTF-8 is used */
- if (!remount && strcmp(param->string, "utf8") != 0) {
- uopt->nls_map = load_nls(param->string);
- if (!uopt->nls_map) {
- errorf(fc, "iocharset %s not found",
- param->string);
- return -EINVAL;
- }
- }
- break;
- case Opt_fmode:
- uopt->fmode = result.uint_32 & 0777;
- break;
- case Opt_dmode:
- uopt->dmode = result.uint_32 & 0777;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int udf_reconfigure(struct fs_context *fc)
- {
- struct udf_options *uopt = fc->fs_private;
- struct super_block *sb = fc->root->d_sb;
- struct udf_sb_info *sbi = UDF_SB(sb);
- int readonly = fc->sb_flags & SB_RDONLY;
- int error = 0;
- if (!readonly && UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT))
- return -EACCES;
- sync_filesystem(sb);
- write_lock(&sbi->s_cred_lock);
- sbi->s_flags = uopt->flags;
- sbi->s_uid = uopt->uid;
- sbi->s_gid = uopt->gid;
- sbi->s_umask = uopt->umask;
- sbi->s_fmode = uopt->fmode;
- sbi->s_dmode = uopt->dmode;
- write_unlock(&sbi->s_cred_lock);
- if (readonly == sb_rdonly(sb))
- goto out_unlock;
- if (readonly)
- udf_close_lvid(sb);
- else
- udf_open_lvid(sb);
- out_unlock:
- return error;
- }
- /*
- * Check VSD descriptor. Returns -1 in case we are at the end of volume
- * recognition area, 0 if the descriptor is valid but non-interesting, 1 if
- * we found one of NSR descriptors we are looking for.
- */
- static int identify_vsd(const struct volStructDesc *vsd)
- {
- int ret = 0;
- if (!memcmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) {
- switch (vsd->structType) {
- case 0:
- udf_debug("ISO9660 Boot Record found\n");
- break;
- case 1:
- udf_debug("ISO9660 Primary Volume Descriptor found\n");
- break;
- case 2:
- udf_debug("ISO9660 Supplementary Volume Descriptor found\n");
- break;
- case 3:
- udf_debug("ISO9660 Volume Partition Descriptor found\n");
- break;
- case 255:
- udf_debug("ISO9660 Volume Descriptor Set Terminator found\n");
- break;
- default:
- udf_debug("ISO9660 VRS (%u) found\n", vsd->structType);
- break;
- }
- } else if (!memcmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN))
- ; /* ret = 0 */
- else if (!memcmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN))
- ret = 1;
- else if (!memcmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN))
- ret = 1;
- else if (!memcmp(vsd->stdIdent, VSD_STD_ID_BOOT2, VSD_STD_ID_LEN))
- ; /* ret = 0 */
- else if (!memcmp(vsd->stdIdent, VSD_STD_ID_CDW02, VSD_STD_ID_LEN))
- ; /* ret = 0 */
- else {
- /* TEA01 or invalid id : end of volume recognition area */
- ret = -1;
- }
- return ret;
- }
- /*
- * Check Volume Structure Descriptors (ECMA 167 2/9.1)
- * We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1)
- * @return 1 if NSR02 or NSR03 found,
- * -1 if first sector read error, 0 otherwise
- */
- static int udf_check_vsd(struct super_block *sb)
- {
- struct volStructDesc *vsd = NULL;
- loff_t sector = VSD_FIRST_SECTOR_OFFSET;
- int sectorsize;
- struct buffer_head *bh = NULL;
- int nsr = 0;
- struct udf_sb_info *sbi;
- loff_t session_offset;
- sbi = UDF_SB(sb);
- if (sb->s_blocksize < sizeof(struct volStructDesc))
- sectorsize = sizeof(struct volStructDesc);
- else
- sectorsize = sb->s_blocksize;
- session_offset = (loff_t)sbi->s_session << sb->s_blocksize_bits;
- sector += session_offset;
- udf_debug("Starting at sector %u (%lu byte sectors)\n",
- (unsigned int)(sector >> sb->s_blocksize_bits),
- sb->s_blocksize);
- /* Process the sequence (if applicable). The hard limit on the sector
- * offset is arbitrary, hopefully large enough so that all valid UDF
- * filesystems will be recognised. There is no mention of an upper
- * bound to the size of the volume recognition area in the standard.
- * The limit will prevent the code to read all the sectors of a
- * specially crafted image (like a bluray disc full of CD001 sectors),
- * potentially causing minutes or even hours of uninterruptible I/O
- * activity. This actually happened with uninitialised SSD partitions
- * (all 0xFF) before the check for the limit and all valid IDs were
- * added */
- for (; !nsr && sector < VSD_MAX_SECTOR_OFFSET; sector += sectorsize) {
- /* Read a block */
- bh = sb_bread(sb, sector >> sb->s_blocksize_bits);
- if (!bh)
- break;
- vsd = (struct volStructDesc *)(bh->b_data +
- (sector & (sb->s_blocksize - 1)));
- nsr = identify_vsd(vsd);
- /* Found NSR or end? */
- if (nsr) {
- brelse(bh);
- break;
- }
- /*
- * Special handling for improperly formatted VRS (e.g., Win10)
- * where components are separated by 2048 bytes even though
- * sectors are 4K
- */
- if (sb->s_blocksize == 4096) {
- nsr = identify_vsd(vsd + 1);
- /* Ignore unknown IDs... */
- if (nsr < 0)
- nsr = 0;
- }
- brelse(bh);
- }
- if (nsr > 0)
- return 1;
- else if (!bh && sector - session_offset == VSD_FIRST_SECTOR_OFFSET)
- return -1;
- else
- return 0;
- }
- static int udf_verify_domain_identifier(struct super_block *sb,
- struct regid *ident, char *dname)
- {
- struct domainIdentSuffix *suffix;
- if (memcmp(ident->ident, UDF_ID_COMPLIANT, strlen(UDF_ID_COMPLIANT))) {
- udf_warn(sb, "Not OSTA UDF compliant %s descriptor.\n", dname);
- goto force_ro;
- }
- if (ident->flags & ENTITYID_FLAGS_DIRTY) {
- udf_warn(sb, "Possibly not OSTA UDF compliant %s descriptor.\n",
- dname);
- goto force_ro;
- }
- suffix = (struct domainIdentSuffix *)ident->identSuffix;
- if ((suffix->domainFlags & DOMAIN_FLAGS_HARD_WRITE_PROTECT) ||
- (suffix->domainFlags & DOMAIN_FLAGS_SOFT_WRITE_PROTECT)) {
- if (!sb_rdonly(sb)) {
- udf_warn(sb, "Descriptor for %s marked write protected."
- " Forcing read only mount.\n", dname);
- }
- goto force_ro;
- }
- return 0;
- force_ro:
- if (!sb_rdonly(sb))
- return -EACCES;
- UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
- return 0;
- }
- static int udf_load_fileset(struct super_block *sb, struct fileSetDesc *fset,
- struct kernel_lb_addr *root)
- {
- int ret;
- ret = udf_verify_domain_identifier(sb, &fset->domainIdent, "file set");
- if (ret < 0)
- return ret;
- *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation);
- UDF_SB(sb)->s_serial_number = le16_to_cpu(fset->descTag.tagSerialNum);
- udf_debug("Rootdir at block=%u, partition=%u\n",
- root->logicalBlockNum, root->partitionReferenceNum);
- return 0;
- }
- static int udf_find_fileset(struct super_block *sb,
- struct kernel_lb_addr *fileset,
- struct kernel_lb_addr *root)
- {
- struct buffer_head *bh;
- uint16_t ident;
- int ret;
- if (fileset->logicalBlockNum == 0xFFFFFFFF &&
- fileset->partitionReferenceNum == 0xFFFF)
- return -EINVAL;
- bh = udf_read_ptagged(sb, fileset, 0, &ident);
- if (!bh)
- return -EIO;
- if (ident != TAG_IDENT_FSD) {
- brelse(bh);
- return -EINVAL;
- }
- udf_debug("Fileset at block=%u, partition=%u\n",
- fileset->logicalBlockNum, fileset->partitionReferenceNum);
- UDF_SB(sb)->s_partition = fileset->partitionReferenceNum;
- ret = udf_load_fileset(sb, (struct fileSetDesc *)bh->b_data, root);
- brelse(bh);
- return ret;
- }
- /*
- * Load primary Volume Descriptor Sequence
- *
- * Return <0 on error, 0 on success. -EAGAIN is special meaning next sequence
- * should be tried.
- */
- static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
- {
- struct primaryVolDesc *pvoldesc;
- uint8_t *outstr;
- struct buffer_head *bh;
- uint16_t ident;
- int ret;
- struct timestamp *ts;
- outstr = kzalloc(128, GFP_KERNEL);
- if (!outstr)
- return -ENOMEM;
- bh = udf_read_tagged(sb, block, block, &ident);
- if (!bh) {
- ret = -EAGAIN;
- goto out2;
- }
- if (ident != TAG_IDENT_PVD) {
- ret = -EIO;
- goto out_bh;
- }
- pvoldesc = (struct primaryVolDesc *)bh->b_data;
- udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time,
- pvoldesc->recordingDateAndTime);
- ts = &pvoldesc->recordingDateAndTime;
- udf_debug("recording time %04u/%02u/%02u %02u:%02u (%x)\n",
- le16_to_cpu(ts->year), ts->month, ts->day, ts->hour,
- ts->minute, le16_to_cpu(ts->typeAndTimezone));
- ret = udf_dstrCS0toChar(sb, outstr, 31, pvoldesc->volIdent, 32);
- if (ret < 0) {
- strscpy_pad(UDF_SB(sb)->s_volume_ident, "InvalidName");
- pr_warn("incorrect volume identification, setting to "
- "'InvalidName'\n");
- } else {
- strscpy_pad(UDF_SB(sb)->s_volume_ident, outstr);
- }
- udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident);
- ret = udf_dstrCS0toChar(sb, outstr, 127, pvoldesc->volSetIdent, 128);
- if (ret < 0) {
- ret = 0;
- goto out_bh;
- }
- outstr[ret] = 0;
- udf_debug("volSetIdent[] = '%s'\n", outstr);
- ret = 0;
- out_bh:
- brelse(bh);
- out2:
- kfree(outstr);
- return ret;
- }
- struct inode *udf_find_metadata_inode_efe(struct super_block *sb,
- u32 meta_file_loc, u32 partition_ref)
- {
- struct kernel_lb_addr addr;
- struct inode *metadata_fe;
- addr.logicalBlockNum = meta_file_loc;
- addr.partitionReferenceNum = partition_ref;
- metadata_fe = udf_iget_special(sb, &addr);
- if (IS_ERR(metadata_fe)) {
- udf_warn(sb, "metadata inode efe not found\n");
- return metadata_fe;
- }
- if (UDF_I(metadata_fe)->i_alloc_type != ICBTAG_FLAG_AD_SHORT) {
- udf_warn(sb, "metadata inode efe does not have short allocation descriptors!\n");
- iput(metadata_fe);
- return ERR_PTR(-EIO);
- }
- return metadata_fe;
- }
- static int udf_load_metadata_files(struct super_block *sb, int partition,
- int type1_index)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct udf_part_map *map;
- struct udf_meta_data *mdata;
- struct kernel_lb_addr addr;
- struct inode *fe;
- map = &sbi->s_partmaps[partition];
- mdata = &map->s_type_specific.s_metadata;
- mdata->s_phys_partition_ref = type1_index;
- /* metadata address */
- udf_debug("Metadata file location: block = %u part = %u\n",
- mdata->s_meta_file_loc, mdata->s_phys_partition_ref);
- fe = udf_find_metadata_inode_efe(sb, mdata->s_meta_file_loc,
- mdata->s_phys_partition_ref);
- if (IS_ERR(fe)) {
- /* mirror file entry */
- udf_debug("Mirror metadata file location: block = %u part = %u\n",
- mdata->s_mirror_file_loc, mdata->s_phys_partition_ref);
- fe = udf_find_metadata_inode_efe(sb, mdata->s_mirror_file_loc,
- mdata->s_phys_partition_ref);
- if (IS_ERR(fe)) {
- udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n");
- return PTR_ERR(fe);
- }
- mdata->s_mirror_fe = fe;
- } else
- mdata->s_metadata_fe = fe;
- /*
- * bitmap file entry
- * Note:
- * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102)
- */
- if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) {
- addr.logicalBlockNum = mdata->s_bitmap_file_loc;
- addr.partitionReferenceNum = mdata->s_phys_partition_ref;
- udf_debug("Bitmap file location: block = %u part = %u\n",
- addr.logicalBlockNum, addr.partitionReferenceNum);
- fe = udf_iget_special(sb, &addr);
- if (IS_ERR(fe)) {
- if (sb_rdonly(sb))
- udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n");
- else {
- udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n");
- return PTR_ERR(fe);
- }
- } else
- mdata->s_bitmap_fe = fe;
- }
- udf_debug("udf_load_metadata_files Ok\n");
- return 0;
- }
- int udf_compute_nr_groups(struct super_block *sb, u32 partition)
- {
- struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
- return DIV_ROUND_UP(map->s_partition_len +
- (sizeof(struct spaceBitmapDesc) << 3),
- sb->s_blocksize * 8);
- }
- static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
- {
- struct udf_bitmap *bitmap;
- int nr_groups = udf_compute_nr_groups(sb, index);
- bitmap = kvzalloc_flex(*bitmap, s_block_bitmap, nr_groups);
- if (!bitmap)
- return NULL;
- bitmap->s_nr_groups = nr_groups;
- return bitmap;
- }
- static int check_partition_desc(struct super_block *sb,
- struct partitionDesc *p,
- struct udf_part_map *map)
- {
- bool umap, utable, fmap, ftable;
- struct partitionHeaderDesc *phd;
- switch (le32_to_cpu(p->accessType)) {
- case PD_ACCESS_TYPE_READ_ONLY:
- case PD_ACCESS_TYPE_WRITE_ONCE:
- case PD_ACCESS_TYPE_NONE:
- goto force_ro;
- }
- /* No Partition Header Descriptor? */
- if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) &&
- strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03))
- goto force_ro;
- phd = (struct partitionHeaderDesc *)p->partitionContentsUse;
- utable = phd->unallocSpaceTable.extLength;
- umap = phd->unallocSpaceBitmap.extLength;
- ftable = phd->freedSpaceTable.extLength;
- fmap = phd->freedSpaceBitmap.extLength;
- /* No allocation info? */
- if (!utable && !umap && !ftable && !fmap)
- goto force_ro;
- /* We don't support blocks that require erasing before overwrite */
- if (ftable || fmap)
- goto force_ro;
- /* UDF 2.60: 2.3.3 - no mixing of tables & bitmaps, no VAT. */
- if (utable && umap)
- goto force_ro;
- if (map->s_partition_type == UDF_VIRTUAL_MAP15 ||
- map->s_partition_type == UDF_VIRTUAL_MAP20 ||
- map->s_partition_type == UDF_METADATA_MAP25)
- goto force_ro;
- return 0;
- force_ro:
- if (!sb_rdonly(sb))
- return -EACCES;
- UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
- return 0;
- }
- static int udf_fill_partdesc_info(struct super_block *sb,
- struct partitionDesc *p, int p_index)
- {
- struct udf_part_map *map;
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct partitionHeaderDesc *phd;
- u32 sum;
- int err;
- map = &sbi->s_partmaps[p_index];
- map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */
- map->s_partition_root = le32_to_cpu(p->partitionStartingLocation);
- if (check_add_overflow(map->s_partition_root, map->s_partition_len,
- &sum)) {
- udf_err(sb, "Partition %d has invalid location %u + %u\n",
- p_index, map->s_partition_root, map->s_partition_len);
- return -EFSCORRUPTED;
- }
- if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY))
- map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY;
- if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE))
- map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE;
- if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE))
- map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE;
- if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE))
- map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE;
- udf_debug("Partition (%d type %x) starts at physical %u, block length %u\n",
- p_index, map->s_partition_type,
- map->s_partition_root, map->s_partition_len);
- err = check_partition_desc(sb, p, map);
- if (err)
- return err;
- /*
- * Skip loading allocation info it we cannot ever write to the fs.
- * This is a correctness thing as we may have decided to force ro mount
- * to avoid allocation info we don't support.
- */
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT))
- return 0;
- phd = (struct partitionHeaderDesc *)p->partitionContentsUse;
- if (phd->unallocSpaceTable.extLength) {
- struct kernel_lb_addr loc = {
- .logicalBlockNum = le32_to_cpu(
- phd->unallocSpaceTable.extPosition),
- .partitionReferenceNum = p_index,
- };
- struct inode *inode;
- inode = udf_iget_special(sb, &loc);
- if (IS_ERR(inode)) {
- udf_debug("cannot load unallocSpaceTable (part %d)\n",
- p_index);
- return PTR_ERR(inode);
- }
- map->s_uspace.s_table = inode;
- map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE;
- udf_debug("unallocSpaceTable (part %d) @ %lu\n",
- p_index, map->s_uspace.s_table->i_ino);
- }
- if (phd->unallocSpaceBitmap.extLength) {
- struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
- if (!bitmap)
- return -ENOMEM;
- map->s_uspace.s_bitmap = bitmap;
- bitmap->s_extPosition = le32_to_cpu(
- phd->unallocSpaceBitmap.extPosition);
- map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP;
- /* Check whether math over bitmap won't overflow. */
- if (check_add_overflow(map->s_partition_len,
- sizeof(struct spaceBitmapDesc) << 3,
- &sum)) {
- udf_err(sb, "Partition %d is too long (%u)\n", p_index,
- map->s_partition_len);
- return -EFSCORRUPTED;
- }
- udf_debug("unallocSpaceBitmap (part %d) @ %u\n",
- p_index, bitmap->s_extPosition);
- }
- return 0;
- }
- static void udf_find_vat_block(struct super_block *sb, int p_index,
- int type1_index, sector_t start_block)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct udf_part_map *map = &sbi->s_partmaps[p_index];
- sector_t vat_block;
- struct kernel_lb_addr ino;
- struct inode *inode;
- /*
- * VAT file entry is in the last recorded block. Some broken disks have
- * it a few blocks before so try a bit harder...
- */
- ino.partitionReferenceNum = type1_index;
- for (vat_block = start_block;
- vat_block >= map->s_partition_root &&
- vat_block >= start_block - 3; vat_block--) {
- ino.logicalBlockNum = vat_block - map->s_partition_root;
- inode = udf_iget_special(sb, &ino);
- if (!IS_ERR(inode)) {
- sbi->s_vat_inode = inode;
- break;
- }
- }
- }
- static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct udf_part_map *map = &sbi->s_partmaps[p_index];
- struct buffer_head *bh = NULL;
- struct udf_inode_info *vati;
- struct virtualAllocationTable20 *vat20;
- sector_t blocks = sb_bdev_nr_blocks(sb);
- udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block);
- if (!sbi->s_vat_inode &&
- sbi->s_last_block != blocks - 1) {
- pr_notice("Failed to read VAT inode from the last recorded block (%lu), retrying with the last block of the device (%lu).\n",
- (unsigned long)sbi->s_last_block,
- (unsigned long)blocks - 1);
- udf_find_vat_block(sb, p_index, type1_index, blocks - 1);
- }
- if (!sbi->s_vat_inode)
- return -EIO;
- if (map->s_partition_type == UDF_VIRTUAL_MAP15) {
- map->s_type_specific.s_virtual.s_start_offset = 0;
- map->s_type_specific.s_virtual.s_num_entries =
- (sbi->s_vat_inode->i_size - 36) >> 2;
- } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) {
- vati = UDF_I(sbi->s_vat_inode);
- if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
- int err = 0;
- bh = udf_bread(sbi->s_vat_inode, 0, 0, &err);
- if (!bh) {
- if (!err)
- err = -EFSCORRUPTED;
- return err;
- }
- vat20 = (struct virtualAllocationTable20 *)bh->b_data;
- } else {
- vat20 = (struct virtualAllocationTable20 *)
- vati->i_data;
- }
- map->s_type_specific.s_virtual.s_start_offset =
- le16_to_cpu(vat20->lengthHeader);
- map->s_type_specific.s_virtual.s_num_entries =
- (sbi->s_vat_inode->i_size -
- map->s_type_specific.s_virtual.
- s_start_offset) >> 2;
- brelse(bh);
- }
- return 0;
- }
- /*
- * Load partition descriptor block
- *
- * Returns <0 on error, 0 on success, -EAGAIN is special - try next descriptor
- * sequence.
- */
- static int udf_load_partdesc(struct super_block *sb, sector_t block)
- {
- struct buffer_head *bh;
- struct partitionDesc *p;
- struct udf_part_map *map;
- struct udf_sb_info *sbi = UDF_SB(sb);
- int i, type1_idx;
- uint16_t partitionNumber;
- uint16_t ident;
- int ret;
- bh = udf_read_tagged(sb, block, block, &ident);
- if (!bh)
- return -EAGAIN;
- if (ident != TAG_IDENT_PD) {
- ret = 0;
- goto out_bh;
- }
- p = (struct partitionDesc *)bh->b_data;
- partitionNumber = le16_to_cpu(p->partitionNumber);
- /* First scan for TYPE1 and SPARABLE partitions */
- for (i = 0; i < sbi->s_partitions; i++) {
- map = &sbi->s_partmaps[i];
- udf_debug("Searching map: (%u == %u)\n",
- map->s_partition_num, partitionNumber);
- if (map->s_partition_num == partitionNumber &&
- (map->s_partition_type == UDF_TYPE1_MAP15 ||
- map->s_partition_type == UDF_SPARABLE_MAP15))
- break;
- }
- if (i >= sbi->s_partitions) {
- udf_debug("Partition (%u) not found in partition map\n",
- partitionNumber);
- ret = 0;
- goto out_bh;
- }
- ret = udf_fill_partdesc_info(sb, p, i);
- if (ret < 0)
- goto out_bh;
- /*
- * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and
- * PHYSICAL partitions are already set up
- */
- type1_idx = i;
- map = NULL; /* supress 'maybe used uninitialized' warning */
- for (i = 0; i < sbi->s_partitions; i++) {
- map = &sbi->s_partmaps[i];
- if (map->s_partition_num == partitionNumber &&
- (map->s_partition_type == UDF_VIRTUAL_MAP15 ||
- map->s_partition_type == UDF_VIRTUAL_MAP20 ||
- map->s_partition_type == UDF_METADATA_MAP25))
- break;
- }
- if (i >= sbi->s_partitions) {
- ret = 0;
- goto out_bh;
- }
- ret = udf_fill_partdesc_info(sb, p, i);
- if (ret < 0)
- goto out_bh;
- if (map->s_partition_type == UDF_METADATA_MAP25) {
- ret = udf_load_metadata_files(sb, i, type1_idx);
- if (ret < 0) {
- udf_err(sb, "error loading MetaData partition map %d\n",
- i);
- goto out_bh;
- }
- } else {
- /*
- * If we have a partition with virtual map, we don't handle
- * writing to it (we overwrite blocks instead of relocating
- * them).
- */
- if (!sb_rdonly(sb)) {
- ret = -EACCES;
- goto out_bh;
- }
- UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
- ret = udf_load_vat(sb, i, type1_idx);
- if (ret < 0)
- goto out_bh;
- }
- ret = 0;
- out_bh:
- /* In case loading failed, we handle cleanup in udf_fill_super */
- brelse(bh);
- return ret;
- }
- static int udf_load_sparable_map(struct super_block *sb,
- struct udf_part_map *map,
- struct sparablePartitionMap *spm)
- {
- uint32_t loc;
- uint16_t ident;
- struct sparingTable *st;
- struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing;
- int i;
- struct buffer_head *bh;
- map->s_partition_type = UDF_SPARABLE_MAP15;
- sdata->s_packet_len = le16_to_cpu(spm->packetLength);
- if (!is_power_of_2(sdata->s_packet_len)) {
- udf_err(sb, "error loading logical volume descriptor: "
- "Invalid packet length %u\n",
- (unsigned)sdata->s_packet_len);
- return -EIO;
- }
- if (spm->numSparingTables > 4) {
- udf_err(sb, "error loading logical volume descriptor: "
- "Too many sparing tables (%d)\n",
- (int)spm->numSparingTables);
- return -EIO;
- }
- if (le32_to_cpu(spm->sizeSparingTable) > sb->s_blocksize) {
- udf_err(sb, "error loading logical volume descriptor: "
- "Too big sparing table size (%u)\n",
- le32_to_cpu(spm->sizeSparingTable));
- return -EIO;
- }
- for (i = 0; i < spm->numSparingTables; i++) {
- loc = le32_to_cpu(spm->locSparingTable[i]);
- bh = udf_read_tagged(sb, loc, loc, &ident);
- if (!bh)
- continue;
- st = (struct sparingTable *)bh->b_data;
- if (ident != 0 ||
- strncmp(st->sparingIdent.ident, UDF_ID_SPARING,
- strlen(UDF_ID_SPARING)) ||
- sizeof(*st) + le16_to_cpu(st->reallocationTableLen) >
- sb->s_blocksize) {
- brelse(bh);
- continue;
- }
- sdata->s_spar_map[i] = bh;
- }
- map->s_partition_func = udf_get_pblock_spar15;
- return 0;
- }
- static int udf_load_logicalvol(struct super_block *sb, sector_t block,
- struct kernel_lb_addr *fileset)
- {
- struct logicalVolDesc *lvd;
- int i, offset;
- uint8_t type;
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct genericPartitionMap *gpm;
- uint16_t ident;
- struct buffer_head *bh;
- unsigned int table_len, part_map_count;
- int ret;
- bh = udf_read_tagged(sb, block, block, &ident);
- if (!bh)
- return -EAGAIN;
- BUG_ON(ident != TAG_IDENT_LVD);
- lvd = (struct logicalVolDesc *)bh->b_data;
- table_len = le32_to_cpu(lvd->mapTableLength);
- if (table_len > sb->s_blocksize - sizeof(*lvd)) {
- udf_err(sb, "error loading logical volume descriptor: "
- "Partition table too long (%u > %lu)\n", table_len,
- sb->s_blocksize - sizeof(*lvd));
- ret = -EIO;
- goto out_bh;
- }
- ret = udf_verify_domain_identifier(sb, &lvd->domainIdent,
- "logical volume");
- if (ret)
- goto out_bh;
- part_map_count = le32_to_cpu(lvd->numPartitionMaps);
- if (part_map_count > table_len / sizeof(struct genericPartitionMap1)) {
- udf_err(sb, "error loading logical volume descriptor: "
- "Too many partition maps (%u > %u)\n", part_map_count,
- table_len / (unsigned)sizeof(struct genericPartitionMap1));
- ret = -EIO;
- goto out_bh;
- }
- ret = udf_sb_alloc_partition_maps(sb, part_map_count);
- if (ret)
- goto out_bh;
- for (i = 0, offset = 0;
- i < sbi->s_partitions && offset < table_len;
- i++, offset += gpm->partitionMapLength) {
- struct udf_part_map *map = &sbi->s_partmaps[i];
- gpm = (struct genericPartitionMap *)
- &(lvd->partitionMaps[offset]);
- type = gpm->partitionMapType;
- if (type == 1) {
- struct genericPartitionMap1 *gpm1 =
- (struct genericPartitionMap1 *)gpm;
- map->s_partition_type = UDF_TYPE1_MAP15;
- map->s_volumeseqnum = le16_to_cpu(gpm1->volSeqNum);
- map->s_partition_num = le16_to_cpu(gpm1->partitionNum);
- map->s_partition_func = NULL;
- } else if (type == 2) {
- struct udfPartitionMap2 *upm2 =
- (struct udfPartitionMap2 *)gpm;
- if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL,
- strlen(UDF_ID_VIRTUAL))) {
- u16 suf =
- le16_to_cpu(((__le16 *)upm2->partIdent.
- identSuffix)[0]);
- if (suf < 0x0200) {
- map->s_partition_type =
- UDF_VIRTUAL_MAP15;
- map->s_partition_func =
- udf_get_pblock_virt15;
- } else {
- map->s_partition_type =
- UDF_VIRTUAL_MAP20;
- map->s_partition_func =
- udf_get_pblock_virt20;
- }
- } else if (!strncmp(upm2->partIdent.ident,
- UDF_ID_SPARABLE,
- strlen(UDF_ID_SPARABLE))) {
- ret = udf_load_sparable_map(sb, map,
- (struct sparablePartitionMap *)gpm);
- if (ret < 0)
- goto out_bh;
- } else if (!strncmp(upm2->partIdent.ident,
- UDF_ID_METADATA,
- strlen(UDF_ID_METADATA))) {
- struct udf_meta_data *mdata =
- &map->s_type_specific.s_metadata;
- struct metadataPartitionMap *mdm =
- (struct metadataPartitionMap *)
- &(lvd->partitionMaps[offset]);
- udf_debug("Parsing Logical vol part %d type %u id=%s\n",
- i, type, UDF_ID_METADATA);
- map->s_partition_type = UDF_METADATA_MAP25;
- map->s_partition_func = udf_get_pblock_meta25;
- mdata->s_meta_file_loc =
- le32_to_cpu(mdm->metadataFileLoc);
- mdata->s_mirror_file_loc =
- le32_to_cpu(mdm->metadataMirrorFileLoc);
- mdata->s_bitmap_file_loc =
- le32_to_cpu(mdm->metadataBitmapFileLoc);
- mdata->s_alloc_unit_size =
- le32_to_cpu(mdm->allocUnitSize);
- mdata->s_align_unit_size =
- le16_to_cpu(mdm->alignUnitSize);
- if (mdm->flags & 0x01)
- mdata->s_flags |= MF_DUPLICATE_MD;
- udf_debug("Metadata Ident suffix=0x%x\n",
- le16_to_cpu(*(__le16 *)
- mdm->partIdent.identSuffix));
- udf_debug("Metadata part num=%u\n",
- le16_to_cpu(mdm->partitionNum));
- udf_debug("Metadata part alloc unit size=%u\n",
- le32_to_cpu(mdm->allocUnitSize));
- udf_debug("Metadata file loc=%u\n",
- le32_to_cpu(mdm->metadataFileLoc));
- udf_debug("Mirror file loc=%u\n",
- le32_to_cpu(mdm->metadataMirrorFileLoc));
- udf_debug("Bitmap file loc=%u\n",
- le32_to_cpu(mdm->metadataBitmapFileLoc));
- udf_debug("Flags: %d %u\n",
- mdata->s_flags, mdm->flags);
- } else {
- udf_debug("Unknown ident: %s\n",
- upm2->partIdent.ident);
- continue;
- }
- map->s_volumeseqnum = le16_to_cpu(upm2->volSeqNum);
- map->s_partition_num = le16_to_cpu(upm2->partitionNum);
- }
- udf_debug("Partition (%d:%u) type %u on volume %u\n",
- i, map->s_partition_num, type, map->s_volumeseqnum);
- }
- if (fileset) {
- struct long_ad *la = (struct long_ad *)&(lvd->logicalVolContentsUse[0]);
- *fileset = lelb_to_cpu(la->extLocation);
- udf_debug("FileSet found in LogicalVolDesc at block=%u, partition=%u\n",
- fileset->logicalBlockNum,
- fileset->partitionReferenceNum);
- }
- if (lvd->integritySeqExt.extLength)
- udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
- ret = 0;
- if (!sbi->s_lvid_bh) {
- /* We can't generate unique IDs without a valid LVID */
- if (sb_rdonly(sb)) {
- UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
- } else {
- udf_warn(sb, "Damaged or missing LVID, forcing "
- "readonly mount\n");
- ret = -EACCES;
- }
- }
- out_bh:
- brelse(bh);
- return ret;
- }
- static bool udf_lvid_valid(struct super_block *sb,
- struct logicalVolIntegrityDesc *lvid)
- {
- u32 parts, impuselen;
- parts = le32_to_cpu(lvid->numOfPartitions);
- impuselen = le32_to_cpu(lvid->lengthOfImpUse);
- if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize ||
- sizeof(struct logicalVolIntegrityDesc) + impuselen +
- 2 * parts * sizeof(u32) > sb->s_blocksize)
- return false;
- return true;
- }
- /*
- * Find the prevailing Logical Volume Integrity Descriptor.
- */
- static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ad loc)
- {
- struct buffer_head *bh, *final_bh;
- uint16_t ident;
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct logicalVolIntegrityDesc *lvid;
- int indirections = 0;
- while (++indirections <= UDF_MAX_LVID_NESTING) {
- final_bh = NULL;
- while (loc.extLength > 0 &&
- (bh = udf_read_tagged(sb, loc.extLocation,
- loc.extLocation, &ident))) {
- if (ident != TAG_IDENT_LVID) {
- brelse(bh);
- break;
- }
- brelse(final_bh);
- final_bh = bh;
- loc.extLength -= sb->s_blocksize;
- loc.extLocation++;
- }
- if (!final_bh)
- return;
- lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data;
- if (udf_lvid_valid(sb, lvid)) {
- brelse(sbi->s_lvid_bh);
- sbi->s_lvid_bh = final_bh;
- } else {
- udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), "
- "ignoring.\n",
- le32_to_cpu(lvid->numOfPartitions),
- le32_to_cpu(lvid->lengthOfImpUse));
- }
- if (lvid->nextIntegrityExt.extLength == 0)
- return;
- loc = leea_to_cpu(lvid->nextIntegrityExt);
- }
- udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n",
- UDF_MAX_LVID_NESTING);
- brelse(sbi->s_lvid_bh);
- sbi->s_lvid_bh = NULL;
- }
- /*
- * Step for reallocation of table of partition descriptor sequence numbers.
- * Must be power of 2.
- */
- #define PART_DESC_ALLOC_STEP 32
- struct part_desc_seq_scan_data {
- struct udf_vds_record rec;
- u32 partnum;
- };
- struct desc_seq_scan_data {
- struct udf_vds_record vds[VDS_POS_LENGTH];
- unsigned int size_part_descs;
- unsigned int num_part_descs;
- struct part_desc_seq_scan_data *part_descs_loc;
- };
- static struct udf_vds_record *handle_partition_descriptor(
- struct buffer_head *bh,
- struct desc_seq_scan_data *data)
- {
- struct partitionDesc *desc = (struct partitionDesc *)bh->b_data;
- int partnum;
- int i;
- partnum = le16_to_cpu(desc->partitionNumber);
- for (i = 0; i < data->num_part_descs; i++)
- if (partnum == data->part_descs_loc[i].partnum)
- return &(data->part_descs_loc[i].rec);
- if (data->num_part_descs >= data->size_part_descs) {
- struct part_desc_seq_scan_data *new_loc;
- unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP);
- new_loc = kzalloc_objs(*new_loc, new_size);
- if (!new_loc)
- return ERR_PTR(-ENOMEM);
- memcpy(new_loc, data->part_descs_loc,
- data->size_part_descs * sizeof(*new_loc));
- kfree(data->part_descs_loc);
- data->part_descs_loc = new_loc;
- data->size_part_descs = new_size;
- }
- return &(data->part_descs_loc[data->num_part_descs++].rec);
- }
- static struct udf_vds_record *get_volume_descriptor_record(uint16_t ident,
- struct buffer_head *bh, struct desc_seq_scan_data *data)
- {
- switch (ident) {
- case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
- return &(data->vds[VDS_POS_PRIMARY_VOL_DESC]);
- case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
- return &(data->vds[VDS_POS_IMP_USE_VOL_DESC]);
- case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
- return &(data->vds[VDS_POS_LOGICAL_VOL_DESC]);
- case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
- return &(data->vds[VDS_POS_UNALLOC_SPACE_DESC]);
- case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
- return handle_partition_descriptor(bh, data);
- }
- return NULL;
- }
- /*
- * Process a main/reserve volume descriptor sequence.
- * @block First block of first extent of the sequence.
- * @lastblock Lastblock of first extent of the sequence.
- * @fileset There we store extent containing root fileset
- *
- * Returns <0 on error, 0 on success. -EAGAIN is special - try next descriptor
- * sequence
- */
- static noinline int udf_process_sequence(
- struct super_block *sb,
- sector_t block, sector_t lastblock,
- struct kernel_lb_addr *fileset)
- {
- struct buffer_head *bh = NULL;
- struct udf_vds_record *curr;
- struct generic_desc *gd;
- struct volDescPtr *vdp;
- bool done = false;
- uint32_t vdsn;
- uint16_t ident;
- int ret;
- unsigned int indirections = 0;
- struct desc_seq_scan_data data;
- unsigned int i;
- memset(data.vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
- data.size_part_descs = PART_DESC_ALLOC_STEP;
- data.num_part_descs = 0;
- data.part_descs_loc = kzalloc_objs(*data.part_descs_loc,
- data.size_part_descs);
- if (!data.part_descs_loc)
- return -ENOMEM;
- /*
- * Read the main descriptor sequence and find which descriptors
- * are in it.
- */
- for (; (!done && block <= lastblock); block++) {
- bh = udf_read_tagged(sb, block, block, &ident);
- if (!bh)
- break;
- /* Process each descriptor (ISO 13346 3/8.3-8.4) */
- gd = (struct generic_desc *)bh->b_data;
- vdsn = le32_to_cpu(gd->volDescSeqNum);
- switch (ident) {
- case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
- if (++indirections > UDF_MAX_TD_NESTING) {
- udf_err(sb, "too many Volume Descriptor "
- "Pointers (max %u supported)\n",
- UDF_MAX_TD_NESTING);
- brelse(bh);
- ret = -EIO;
- goto out;
- }
- vdp = (struct volDescPtr *)bh->b_data;
- block = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
- lastblock = le32_to_cpu(
- vdp->nextVolDescSeqExt.extLength) >>
- sb->s_blocksize_bits;
- lastblock += block - 1;
- /* For loop is going to increment 'block' again */
- block--;
- break;
- case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
- case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
- case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
- case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
- case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
- curr = get_volume_descriptor_record(ident, bh, &data);
- if (IS_ERR(curr)) {
- brelse(bh);
- ret = PTR_ERR(curr);
- goto out;
- }
- /* Descriptor we don't care about? */
- if (!curr)
- break;
- if (vdsn >= curr->volDescSeqNum) {
- curr->volDescSeqNum = vdsn;
- curr->block = block;
- }
- break;
- case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
- done = true;
- break;
- }
- brelse(bh);
- }
- /*
- * Now read interesting descriptors again and process them
- * in a suitable order
- */
- if (!data.vds[VDS_POS_PRIMARY_VOL_DESC].block) {
- udf_err(sb, "Primary Volume Descriptor not found!\n");
- ret = -EAGAIN;
- goto out;
- }
- ret = udf_load_pvoldesc(sb, data.vds[VDS_POS_PRIMARY_VOL_DESC].block);
- if (ret < 0)
- goto out;
- if (data.vds[VDS_POS_LOGICAL_VOL_DESC].block) {
- ret = udf_load_logicalvol(sb,
- data.vds[VDS_POS_LOGICAL_VOL_DESC].block,
- fileset);
- if (ret < 0)
- goto out;
- }
- /* Now handle prevailing Partition Descriptors */
- for (i = 0; i < data.num_part_descs; i++) {
- ret = udf_load_partdesc(sb, data.part_descs_loc[i].rec.block);
- if (ret < 0)
- goto out;
- }
- ret = 0;
- out:
- kfree(data.part_descs_loc);
- return ret;
- }
- /*
- * Load Volume Descriptor Sequence described by anchor in bh
- *
- * Returns <0 on error, 0 on success
- */
- static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
- struct kernel_lb_addr *fileset)
- {
- struct anchorVolDescPtr *anchor;
- sector_t main_s, main_e, reserve_s, reserve_e;
- int ret;
- anchor = (struct anchorVolDescPtr *)bh->b_data;
- /* Locate the main sequence */
- main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
- main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
- main_e = main_e >> sb->s_blocksize_bits;
- main_e += main_s - 1;
- /* Locate the reserve sequence */
- reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
- reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
- reserve_e = reserve_e >> sb->s_blocksize_bits;
- reserve_e += reserve_s - 1;
- /* Process the main & reserve sequences */
- /* responsible for finding the PartitionDesc(s) */
- ret = udf_process_sequence(sb, main_s, main_e, fileset);
- if (ret != -EAGAIN)
- return ret;
- udf_sb_free_partitions(sb);
- ret = udf_process_sequence(sb, reserve_s, reserve_e, fileset);
- if (ret < 0) {
- udf_sb_free_partitions(sb);
- /* No sequence was OK, return -EIO */
- if (ret == -EAGAIN)
- ret = -EIO;
- }
- return ret;
- }
- /*
- * Check whether there is an anchor block in the given block and
- * load Volume Descriptor Sequence if so.
- *
- * Returns <0 on error, 0 on success, -EAGAIN is special - try next anchor
- * block
- */
- static int udf_check_anchor_block(struct super_block *sb, sector_t block,
- struct kernel_lb_addr *fileset)
- {
- struct buffer_head *bh;
- uint16_t ident;
- int ret;
- bh = udf_read_tagged(sb, block, block, &ident);
- if (!bh)
- return -EAGAIN;
- if (ident != TAG_IDENT_AVDP) {
- brelse(bh);
- return -EAGAIN;
- }
- ret = udf_load_sequence(sb, bh, fileset);
- brelse(bh);
- return ret;
- }
- /*
- * Search for an anchor volume descriptor pointer.
- *
- * Returns < 0 on error, 0 on success. -EAGAIN is special - try next set
- * of anchors.
- */
- static int udf_scan_anchors(struct super_block *sb, udf_pblk_t *lastblock,
- struct kernel_lb_addr *fileset)
- {
- udf_pblk_t last[6];
- int i;
- struct udf_sb_info *sbi = UDF_SB(sb);
- int last_count = 0;
- int ret;
- /* First try user provided anchor */
- if (sbi->s_anchor) {
- ret = udf_check_anchor_block(sb, sbi->s_anchor, fileset);
- if (ret != -EAGAIN)
- return ret;
- }
- /*
- * according to spec, anchor is in either:
- * block 256
- * lastblock-256
- * lastblock
- * however, if the disc isn't closed, it could be 512.
- */
- ret = udf_check_anchor_block(sb, sbi->s_session + 256, fileset);
- if (ret != -EAGAIN)
- return ret;
- /*
- * The trouble is which block is the last one. Drives often misreport
- * this so we try various possibilities.
- */
- last[last_count++] = *lastblock;
- if (*lastblock >= 1)
- last[last_count++] = *lastblock - 1;
- last[last_count++] = *lastblock + 1;
- if (*lastblock >= 2)
- last[last_count++] = *lastblock - 2;
- if (*lastblock >= 150)
- last[last_count++] = *lastblock - 150;
- if (*lastblock >= 152)
- last[last_count++] = *lastblock - 152;
- for (i = 0; i < last_count; i++) {
- if (last[i] >= sb_bdev_nr_blocks(sb))
- continue;
- ret = udf_check_anchor_block(sb, last[i], fileset);
- if (ret != -EAGAIN) {
- if (!ret)
- *lastblock = last[i];
- return ret;
- }
- if (last[i] < 256)
- continue;
- ret = udf_check_anchor_block(sb, last[i] - 256, fileset);
- if (ret != -EAGAIN) {
- if (!ret)
- *lastblock = last[i];
- return ret;
- }
- }
- /* Finally try block 512 in case media is open */
- return udf_check_anchor_block(sb, sbi->s_session + 512, fileset);
- }
- /*
- * Check Volume Structure Descriptor, find Anchor block and load Volume
- * Descriptor Sequence.
- *
- * Returns < 0 on error, 0 on success. -EAGAIN is special meaning anchor
- * block was not found.
- */
- static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
- int silent, struct kernel_lb_addr *fileset)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- int nsr = 0;
- int ret;
- if (!sb_set_blocksize(sb, uopt->blocksize)) {
- if (!silent)
- udf_warn(sb, "Bad block size\n");
- return -EINVAL;
- }
- sbi->s_last_block = uopt->lastblock;
- if (!UDF_QUERY_FLAG(sb, UDF_FLAG_NOVRS)) {
- /* Check that it is NSR02 compliant */
- nsr = udf_check_vsd(sb);
- if (!nsr) {
- if (!silent)
- udf_warn(sb, "No VRS found\n");
- return -EINVAL;
- }
- if (nsr == -1)
- udf_debug("Failed to read sector at offset %d. "
- "Assuming open disc. Skipping validity "
- "check\n", VSD_FIRST_SECTOR_OFFSET);
- if (!sbi->s_last_block)
- sbi->s_last_block = udf_get_last_block(sb);
- } else {
- udf_debug("Validity check skipped because of novrs option\n");
- }
- /* Look for anchor block and load Volume Descriptor Sequence */
- sbi->s_anchor = uopt->anchor;
- ret = udf_scan_anchors(sb, &sbi->s_last_block, fileset);
- if (ret < 0) {
- if (!silent && ret == -EAGAIN)
- udf_warn(sb, "No anchor found\n");
- return ret;
- }
- return 0;
- }
- static void udf_finalize_lvid(struct logicalVolIntegrityDesc *lvid)
- {
- struct timespec64 ts;
- ktime_get_real_ts64(&ts);
- udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts);
- lvid->descTag.descCRC = cpu_to_le16(
- crc_itu_t(0, (char *)lvid + sizeof(struct tag),
- le16_to_cpu(lvid->descTag.descCRCLength)));
- lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
- }
- static void udf_open_lvid(struct super_block *sb)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct buffer_head *bh = sbi->s_lvid_bh;
- struct logicalVolIntegrityDesc *lvid;
- struct logicalVolIntegrityDescImpUse *lvidiu;
- if (!bh)
- return;
- lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
- lvidiu = udf_sb_lvidiu(sb);
- if (!lvidiu)
- return;
- mutex_lock(&sbi->s_alloc_mutex);
- lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
- lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
- if (le32_to_cpu(lvid->integrityType) == LVID_INTEGRITY_TYPE_CLOSE)
- lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
- else
- UDF_SET_FLAG(sb, UDF_FLAG_INCONSISTENT);
- udf_finalize_lvid(lvid);
- mark_buffer_dirty(bh);
- sbi->s_lvid_dirty = 0;
- mutex_unlock(&sbi->s_alloc_mutex);
- /* Make opening of filesystem visible on the media immediately */
- sync_dirty_buffer(bh);
- }
- static void udf_close_lvid(struct super_block *sb)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct buffer_head *bh = sbi->s_lvid_bh;
- struct logicalVolIntegrityDesc *lvid;
- struct logicalVolIntegrityDescImpUse *lvidiu;
- if (!bh)
- return;
- lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
- lvidiu = udf_sb_lvidiu(sb);
- if (!lvidiu)
- return;
- mutex_lock(&sbi->s_alloc_mutex);
- lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
- lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
- if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev))
- lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION);
- if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev))
- lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev);
- if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev))
- lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev);
- if (!UDF_QUERY_FLAG(sb, UDF_FLAG_INCONSISTENT))
- lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
- /*
- * We set buffer uptodate unconditionally here to avoid spurious
- * warnings from mark_buffer_dirty() when previous EIO has marked
- * the buffer as !uptodate
- */
- set_buffer_uptodate(bh);
- udf_finalize_lvid(lvid);
- mark_buffer_dirty(bh);
- sbi->s_lvid_dirty = 0;
- mutex_unlock(&sbi->s_alloc_mutex);
- /* Make closing of filesystem visible on the media immediately */
- sync_dirty_buffer(bh);
- }
- u64 lvid_get_unique_id(struct super_block *sb)
- {
- struct buffer_head *bh;
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct logicalVolIntegrityDesc *lvid;
- struct logicalVolHeaderDesc *lvhd;
- u64 uniqueID;
- u64 ret;
- bh = sbi->s_lvid_bh;
- if (!bh)
- return 0;
- lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
- lvhd = (struct logicalVolHeaderDesc *)lvid->logicalVolContentsUse;
- mutex_lock(&sbi->s_alloc_mutex);
- ret = uniqueID = le64_to_cpu(lvhd->uniqueID);
- if (!(++uniqueID & 0xFFFFFFFF))
- uniqueID += 16;
- lvhd->uniqueID = cpu_to_le64(uniqueID);
- udf_updated_lvid(sb);
- mutex_unlock(&sbi->s_alloc_mutex);
- return ret;
- }
- static int udf_fill_super(struct super_block *sb, struct fs_context *fc)
- {
- int ret = -EINVAL;
- struct inode *inode = NULL;
- struct udf_options *uopt = fc->fs_private;
- struct kernel_lb_addr rootdir, fileset;
- struct udf_sb_info *sbi;
- bool lvid_open = false;
- int silent = fc->sb_flags & SB_SILENT;
- sbi = kzalloc_obj(*sbi);
- if (!sbi)
- return -ENOMEM;
- sb->s_fs_info = sbi;
- mutex_init(&sbi->s_alloc_mutex);
- fileset.logicalBlockNum = 0xFFFFFFFF;
- fileset.partitionReferenceNum = 0xFFFF;
- sbi->s_flags = uopt->flags;
- sbi->s_uid = uopt->uid;
- sbi->s_gid = uopt->gid;
- sbi->s_umask = uopt->umask;
- sbi->s_fmode = uopt->fmode;
- sbi->s_dmode = uopt->dmode;
- sbi->s_nls_map = uopt->nls_map;
- uopt->nls_map = NULL;
- rwlock_init(&sbi->s_cred_lock);
- if (uopt->session == 0xFFFFFFFF)
- sbi->s_session = udf_get_last_session(sb);
- else
- sbi->s_session = uopt->session;
- udf_debug("Multi-session=%d\n", sbi->s_session);
- /* Fill in the rest of the superblock */
- sb->s_op = &udf_sb_ops;
- sb->s_export_op = &udf_export_ops;
- sb->s_magic = UDF_SUPER_MAGIC;
- sb->s_time_gran = 1000;
- if (uopt->flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) {
- ret = udf_load_vrs(sb, uopt, silent, &fileset);
- } else {
- uopt->blocksize = bdev_logical_block_size(sb->s_bdev);
- while (uopt->blocksize <= 4096) {
- ret = udf_load_vrs(sb, uopt, silent, &fileset);
- if (ret < 0) {
- if (!silent && ret != -EACCES) {
- pr_notice("Scanning with blocksize %u failed\n",
- uopt->blocksize);
- }
- brelse(sbi->s_lvid_bh);
- sbi->s_lvid_bh = NULL;
- /*
- * EACCES is special - we want to propagate to
- * upper layers that we cannot handle RW mount.
- */
- if (ret == -EACCES)
- break;
- } else
- break;
- uopt->blocksize <<= 1;
- }
- }
- if (ret < 0) {
- if (ret == -EAGAIN) {
- udf_warn(sb, "No partition found (1)\n");
- ret = -EINVAL;
- }
- goto error_out;
- }
- udf_debug("Lastblock=%u\n", sbi->s_last_block);
- if (sbi->s_lvid_bh) {
- struct logicalVolIntegrityDescImpUse *lvidiu =
- udf_sb_lvidiu(sb);
- uint16_t minUDFReadRev;
- uint16_t minUDFWriteRev;
- if (!lvidiu) {
- ret = -EINVAL;
- goto error_out;
- }
- minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev);
- minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev);
- if (minUDFReadRev > UDF_MAX_READ_VERSION) {
- udf_err(sb, "minUDFReadRev=%x (max is %x)\n",
- minUDFReadRev,
- UDF_MAX_READ_VERSION);
- ret = -EINVAL;
- goto error_out;
- } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) {
- if (!sb_rdonly(sb)) {
- ret = -EACCES;
- goto error_out;
- }
- UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
- }
- sbi->s_udfrev = minUDFWriteRev;
- if (minUDFReadRev >= UDF_VERS_USE_EXTENDED_FE)
- UDF_SET_FLAG(sb, UDF_FLAG_USE_EXTENDED_FE);
- if (minUDFReadRev >= UDF_VERS_USE_STREAMS)
- UDF_SET_FLAG(sb, UDF_FLAG_USE_STREAMS);
- }
- if (!sbi->s_partitions) {
- udf_warn(sb, "No partition found (2)\n");
- ret = -EINVAL;
- goto error_out;
- }
- if (sbi->s_partmaps[sbi->s_partition].s_partition_flags &
- UDF_PART_FLAG_READ_ONLY) {
- if (!sb_rdonly(sb)) {
- ret = -EACCES;
- goto error_out;
- }
- UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT);
- }
- ret = udf_find_fileset(sb, &fileset, &rootdir);
- if (ret < 0) {
- udf_warn(sb, "No fileset found\n");
- goto error_out;
- }
- if (!silent) {
- struct timestamp ts;
- udf_time_to_disk_stamp(&ts, sbi->s_record_time);
- udf_info("Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
- sbi->s_volume_ident,
- le16_to_cpu(ts.year), ts.month, ts.day,
- ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone));
- }
- if (!sb_rdonly(sb)) {
- udf_open_lvid(sb);
- lvid_open = true;
- }
- /* Assign the root inode */
- /* assign inodes by physical block number */
- /* perhaps it's not extensible enough, but for now ... */
- inode = udf_iget(sb, &rootdir);
- if (IS_ERR(inode)) {
- udf_err(sb, "Error in udf_iget, block=%u, partition=%u\n",
- rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
- ret = PTR_ERR(inode);
- goto error_out;
- }
- /* Allocate a dentry for the root inode */
- sb->s_root = d_make_root(inode);
- if (!sb->s_root) {
- udf_err(sb, "Couldn't allocate root dentry\n");
- ret = -ENOMEM;
- goto error_out;
- }
- sb->s_maxbytes = UDF_MAX_FILESIZE;
- sb->s_max_links = UDF_MAX_LINKS;
- return 0;
- error_out:
- iput(sbi->s_vat_inode);
- unload_nls(uopt->nls_map);
- if (lvid_open)
- udf_close_lvid(sb);
- brelse(sbi->s_lvid_bh);
- udf_sb_free_partitions(sb);
- kfree(sbi);
- sb->s_fs_info = NULL;
- return ret;
- }
- void _udf_err(struct super_block *sb, const char *function,
- const char *fmt, ...)
- {
- struct va_format vaf;
- va_list args;
- va_start(args, fmt);
- vaf.fmt = fmt;
- vaf.va = &args;
- pr_err("error (device %s): %s: %pV", sb->s_id, function, &vaf);
- va_end(args);
- }
- void _udf_warn(struct super_block *sb, const char *function,
- const char *fmt, ...)
- {
- struct va_format vaf;
- va_list args;
- va_start(args, fmt);
- vaf.fmt = fmt;
- vaf.va = &args;
- pr_warn("warning (device %s): %s: %pV", sb->s_id, function, &vaf);
- va_end(args);
- }
- static void udf_put_super(struct super_block *sb)
- {
- struct udf_sb_info *sbi;
- sbi = UDF_SB(sb);
- iput(sbi->s_vat_inode);
- unload_nls(sbi->s_nls_map);
- if (!sb_rdonly(sb))
- udf_close_lvid(sb);
- brelse(sbi->s_lvid_bh);
- udf_sb_free_partitions(sb);
- mutex_destroy(&sbi->s_alloc_mutex);
- kfree(sb->s_fs_info);
- sb->s_fs_info = NULL;
- }
- static int udf_sync_fs(struct super_block *sb, int wait)
- {
- struct udf_sb_info *sbi = UDF_SB(sb);
- mutex_lock(&sbi->s_alloc_mutex);
- if (sbi->s_lvid_dirty) {
- struct buffer_head *bh = sbi->s_lvid_bh;
- struct logicalVolIntegrityDesc *lvid;
- lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
- udf_finalize_lvid(lvid);
- /*
- * Blockdevice will be synced later so we don't have to submit
- * the buffer for IO
- */
- mark_buffer_dirty(bh);
- sbi->s_lvid_dirty = 0;
- }
- mutex_unlock(&sbi->s_alloc_mutex);
- return 0;
- }
- static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
- {
- struct super_block *sb = dentry->d_sb;
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct logicalVolIntegrityDescImpUse *lvidiu;
- u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
- lvidiu = udf_sb_lvidiu(sb);
- buf->f_type = UDF_SUPER_MAGIC;
- buf->f_bsize = sb->s_blocksize;
- buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len;
- buf->f_bfree = udf_count_free(sb);
- buf->f_bavail = buf->f_bfree;
- /*
- * Let's pretend each free block is also a free 'inode' since UDF does
- * not have separate preallocated table of inodes.
- */
- buf->f_files = (lvidiu != NULL ? (le32_to_cpu(lvidiu->numFiles) +
- le32_to_cpu(lvidiu->numDirs)) : 0)
- + buf->f_bfree;
- buf->f_ffree = buf->f_bfree;
- buf->f_namelen = UDF_NAME_LEN;
- buf->f_fsid = u64_to_fsid(id);
- return 0;
- }
- static unsigned int udf_count_free_bitmap(struct super_block *sb,
- struct udf_bitmap *bitmap)
- {
- struct buffer_head *bh = NULL;
- unsigned int accum = 0;
- int index;
- udf_pblk_t block = 0, newblock;
- struct kernel_lb_addr loc;
- uint32_t bytes;
- uint8_t *ptr;
- uint16_t ident;
- struct spaceBitmapDesc *bm;
- loc.logicalBlockNum = bitmap->s_extPosition;
- loc.partitionReferenceNum = UDF_SB(sb)->s_partition;
- bh = udf_read_ptagged(sb, &loc, 0, &ident);
- if (!bh) {
- udf_err(sb, "udf_count_free failed\n");
- goto out;
- } else if (ident != TAG_IDENT_SBD) {
- brelse(bh);
- udf_err(sb, "udf_count_free failed\n");
- goto out;
- }
- bm = (struct spaceBitmapDesc *)bh->b_data;
- bytes = le32_to_cpu(bm->numOfBytes);
- index = sizeof(struct spaceBitmapDesc); /* offset in first block only */
- ptr = (uint8_t *)bh->b_data;
- while (bytes > 0) {
- u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index);
- accum += bitmap_weight((const unsigned long *)(ptr + index),
- cur_bytes * 8);
- bytes -= cur_bytes;
- if (bytes) {
- brelse(bh);
- newblock = udf_get_lb_pblock(sb, &loc, ++block);
- bh = sb_bread(sb, newblock);
- if (!bh) {
- udf_debug("read failed\n");
- goto out;
- }
- index = 0;
- ptr = (uint8_t *)bh->b_data;
- }
- }
- brelse(bh);
- out:
- return accum;
- }
- static unsigned int udf_count_free_table(struct super_block *sb,
- struct inode *table)
- {
- unsigned int accum = 0;
- uint32_t elen;
- struct kernel_lb_addr eloc;
- struct extent_position epos;
- int8_t etype;
- mutex_lock(&UDF_SB(sb)->s_alloc_mutex);
- epos.block = UDF_I(table)->i_location;
- epos.offset = sizeof(struct unallocSpaceEntry);
- epos.bh = NULL;
- while (udf_next_aext(table, &epos, &eloc, &elen, &etype, 1) > 0)
- accum += (elen >> table->i_sb->s_blocksize_bits);
- brelse(epos.bh);
- mutex_unlock(&UDF_SB(sb)->s_alloc_mutex);
- return accum;
- }
- static unsigned int udf_count_free(struct super_block *sb)
- {
- unsigned int accum = 0;
- struct udf_sb_info *sbi = UDF_SB(sb);
- struct udf_part_map *map;
- unsigned int part = sbi->s_partition;
- int ptype = sbi->s_partmaps[part].s_partition_type;
- if (ptype == UDF_METADATA_MAP25) {
- part = sbi->s_partmaps[part].s_type_specific.s_metadata.
- s_phys_partition_ref;
- } else if (ptype == UDF_VIRTUAL_MAP15 || ptype == UDF_VIRTUAL_MAP20) {
- /*
- * Filesystems with VAT are append-only and we cannot write to
- * them. Let's just report 0 here.
- */
- return 0;
- }
- if (sbi->s_lvid_bh) {
- struct logicalVolIntegrityDesc *lvid =
- (struct logicalVolIntegrityDesc *)
- sbi->s_lvid_bh->b_data;
- if (le32_to_cpu(lvid->numOfPartitions) > part) {
- accum = le32_to_cpu(
- lvid->freeSpaceTable[part]);
- if (accum == 0xFFFFFFFF)
- accum = 0;
- }
- }
- if (accum)
- return accum;
- map = &sbi->s_partmaps[part];
- if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
- accum += udf_count_free_bitmap(sb,
- map->s_uspace.s_bitmap);
- }
- if (accum)
- return accum;
- if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) {
- accum += udf_count_free_table(sb,
- map->s_uspace.s_table);
- }
- return accum;
- }
- MODULE_AUTHOR("Ben Fennema");
- MODULE_DESCRIPTION("Universal Disk Format Filesystem");
- MODULE_LICENSE("GPL");
- module_init(init_udf_fs)
- module_exit(exit_udf_fs)
|