]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/udf/super.c
udf: convert udf_stamp_to_time and udf_time_to_stamp to use timestamps
[linux-2.6-omap-h63xx.git] / fs / udf / super.c
index b10295865e5ac9fa5e8d4347ec6bb55fe78f9d97..4d2ecee1970b5313ad5c56cbd293bf58d9a7286b 100644 (file)
 #include <linux/vfs.h>
 #include <linux/vmalloc.h>
 #include <linux/errno.h>
+#include <linux/mount.h>
+#include <linux/seq_file.h>
+#include <linux/bitmap.h>
 #include <asm/byteorder.h>
 
-#include <linux/udf_fs.h>
 #include "udf_sb.h"
 #include "udf_i.h"
 
@@ -71,6 +73,8 @@
 #define VDS_POS_TERMINATING_DESC       6
 #define VDS_POS_LENGTH                 7
 
+#define UDF_DEFAULT_BLOCKSIZE 2048
+
 static char error_buf[1024];
 
 /* These are the "meat" - everything else is stuffing */
@@ -95,6 +99,9 @@ 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 vfsmount *);
+static void udf_error(struct super_block *sb, const char *function,
+                     const char *fmt, ...);
 
 struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi)
 {
@@ -181,6 +188,7 @@ static const struct super_operations udf_sb_ops = {
        .write_super    = udf_write_super,
        .statfs         = udf_statfs,
        .remount_fs     = udf_remount_fs,
+       .show_options   = udf_show_options,
 };
 
 struct udf_options {
@@ -247,6 +255,61 @@ static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count)
        return 0;
 }
 
+static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt)
+{
+       struct super_block *sb = mnt->mnt_sb;
+       struct udf_sb_info *sbi = UDF_SB(sb);
+
+       if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT))
+               seq_puts(seq, ",nostrict");
+       if (sb->s_blocksize != UDF_DEFAULT_BLOCKSIZE)
+               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_UID_IGNORE))
+               seq_puts(seq, ",uid=ignore");
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_FORGET))
+               seq_puts(seq, ",gid=forget");
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_IGNORE))
+               seq_puts(seq, ",gid=ignore");
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET))
+               seq_printf(seq, ",uid=%u", sbi->s_uid);
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET))
+               seq_printf(seq, ",gid=%u", sbi->s_gid);
+       if (sbi->s_umask != 0)
+               seq_printf(seq, ",umask=%o", sbi->s_umask);
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_SESSION_SET))
+               seq_printf(seq, ",session=%u", sbi->s_session);
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET))
+               seq_printf(seq, ",lastblock=%u", sbi->s_last_block);
+       /*
+        * s_anchor[2] could be zeroed out in case there is no anchor
+        * in the specified block, but then the "anchor=N" option
+        * originally given by the user wasn't effective, so it's OK
+        * if we don't show it.
+        */
+       if (sbi->s_anchor[2] != 0)
+               seq_printf(seq, ",anchor=%u", sbi->s_anchor[2]);
+       /*
+        * volume, partition, fileset and rootdir seem to be ignored
+        * currently
+        */
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
+               seq_puts(seq, ",utf8");
+       if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP) && sbi->s_nls_map)
+               seq_printf(seq, ",iocharset=%s", sbi->s_nls_map->charset);
+
+       return 0;
+}
+
 /*
  * udf_parse_options
  *
@@ -339,13 +402,14 @@ static match_table_t tokens = {
        {Opt_err,       NULL}
 };
 
-static int udf_parse_options(char *options, struct udf_options *uopt)
+static int udf_parse_options(char *options, struct udf_options *uopt,
+                            bool remount)
 {
        char *p;
        int option;
 
        uopt->novrs = 0;
-       uopt->blocksize = 2048;
+       uopt->blocksize = UDF_DEFAULT_BLOCKSIZE;
        uopt->partition = 0xFFFF;
        uopt->session = 0xFFFFFFFF;
        uopt->lastblock = 0;
@@ -415,11 +479,15 @@ static int udf_parse_options(char *options, struct udf_options *uopt)
                        if (match_int(args, &option))
                                return 0;
                        uopt->session = option;
+                       if (!remount)
+                               uopt->flags |= (1 << UDF_FLAG_SESSION_SET);
                        break;
                case Opt_lastblock:
                        if (match_int(args, &option))
                                return 0;
                        uopt->lastblock = option;
+                       if (!remount)
+                               uopt->flags |= (1 << UDF_FLAG_LASTBLOCK_SET);
                        break;
                case Opt_anchor:
                        if (match_int(args, &option))
@@ -497,7 +565,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        uopt.gid   = sbi->s_gid;
        uopt.umask = sbi->s_umask;
 
-       if (!udf_parse_options(options, &uopt))
+       if (!udf_parse_options(options, &uopt, true))
                return -EINVAL;
 
        sbi->s_flags = uopt.flags;
@@ -521,44 +589,6 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        return 0;
 }
 
-/*
- * udf_set_blocksize
- *
- * PURPOSE
- *     Set the block size to be used in all transfers.
- *
- * DESCRIPTION
- *     To allow room for a DMA transfer, it is best to guess big when unsure.
- *     This routine picks 2048 bytes as the blocksize when guessing. This
- *     should be adequate until devices with larger block sizes become common.
- *
- *     Note that the Linux kernel can currently only deal with blocksizes of
- *     512, 1024, 2048, 4096, and 8192 bytes.
- *
- * PRE-CONDITIONS
- *     sb                      Pointer to _locked_ superblock.
- *
- * POST-CONDITIONS
- *     sb->s_blocksize         Blocksize.
- *     sb->s_blocksize_bits    log2 of blocksize.
- *     <return>        0       Blocksize is valid.
- *     <return>        1       Blocksize is invalid.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
-static int udf_set_blocksize(struct super_block *sb, int bsize)
-{
-       if (!sb_min_blocksize(sb, bsize)) {
-               udf_debug("Bad block size (%d)\n", bsize);
-               printk(KERN_ERR "udf: bad block size (%d)\n", bsize);
-               return 0;
-       }
-
-       return sb->s_blocksize;
-}
-
 static int udf_vrs(struct super_block *sb, int silent)
 {
        struct volStructDesc *vsd = NULL;
@@ -908,24 +938,19 @@ static int udf_find_fileset(struct super_block *sb,
 static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
 {
        struct primaryVolDesc *pvoldesc;
-       time_t recording;
-       long recording_usec;
        struct ustr instr;
        struct ustr outstr;
 
        pvoldesc = (struct primaryVolDesc *)bh->b_data;
 
-       if (udf_stamp_to_time(&recording, &recording_usec,
-                             lets_to_cpu(pvoldesc->recordingDateAndTime))) {
+       if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time,
+                             pvoldesc->recordingDateAndTime)) {
                kernel_timestamp ts;
                ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
-               udf_debug("recording time %ld/%ld, %04u/%02u/%02u"
+               udf_debug("recording time %04u/%02u/%02u"
                          " %02u:%02u (%x)\n",
-                         recording, recording_usec,
                          ts.year, ts.month, ts.day, ts.hour,
                          ts.minute, ts.typeAndTimezone);
-               UDF_SB(sb)->s_record_time.tv_sec = recording;
-               UDF_SB(sb)->s_record_time.tv_nsec = recording_usec * 1000;
        }
 
        if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32))
@@ -959,10 +984,9 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
 int udf_compute_nr_groups(struct super_block *sb, u32 partition)
 {
        struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
-       return (map->s_partition_len +
-               (sizeof(struct spaceBitmapDesc) << 3) +
-               (sb->s_blocksize * 8) - 1) /
-               (sb->s_blocksize * 8);
+       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)
@@ -1447,44 +1471,45 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
        sbi = UDF_SB(sb);
 
        for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
-               if (sbi->s_anchor[i] &&
-                   (bh = udf_read_tagged(sb, sbi->s_anchor[i],
-                                         sbi->s_anchor[i], &ident))) {
-                       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;
-
-                       /* Locate the reserve sequence */
-                       reserve_s = le32_to_cpu(
+               if (!sbi->s_anchor[i])
+                       continue;
+               bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i],
+                                    &ident);
+               if (!bh)
+                       continue;
+
+               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;
+
+               /* Locate the reserve sequence */
+               reserve_s = le32_to_cpu(
                                anchor->reserveVolDescSeqExt.extLocation);
-                       reserve_e = le32_to_cpu(
+               reserve_e = le32_to_cpu(
                                anchor->reserveVolDescSeqExt.extLength);
-                       reserve_e = reserve_e >> sb->s_blocksize_bits;
-                       reserve_e += reserve_s;
+               reserve_e = reserve_e >> sb->s_blocksize_bits;
+               reserve_e += reserve_s;
 
-                       brelse(bh);
+               brelse(bh);
 
-                       /* Process the main & reserve sequences */
-                       /* responsible for finding the PartitionDesc(s) */
-                       if (!(udf_process_sequence(sb, main_s, main_e,
-                                                  fileset) &&
-                             udf_process_sequence(sb, reserve_s, reserve_e,
-                                                  fileset)))
-                               break;
-               }
+               /* Process the main & reserve sequences */
+               /* responsible for finding the PartitionDesc(s) */
+               if (!(udf_process_sequence(sb, main_s, main_e,
+                                          fileset) &&
+                     udf_process_sequence(sb, reserve_s, reserve_e,
+                                          fileset)))
+                       break;
        }
 
        if (i == ARRAY_SIZE(sbi->s_anchor)) {
                udf_debug("No Anchor block found\n");
                return 1;
-       } else
-               udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]);
+       }
+       udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]);
 
        for (i = 0; i < sbi->s_partitions; i++) {
                kernel_lb_addr uninitialized_var(ino);
@@ -1564,7 +1589,6 @@ 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;
        if (bh) {
-               kernel_timestamp cpu_time;
                struct logicalVolIntegrityDesc *lvid =
                                (struct logicalVolIntegrityDesc *)bh->b_data;
                struct logicalVolIntegrityDescImpUse *lvidiu =
@@ -1572,8 +1596,8 @@ static void udf_open_lvid(struct super_block *sb)
 
                lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
                lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
-               if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
-                       lvid->recordingDateAndTime = cpu_to_lets(cpu_time);
+               udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
+                                       CURRENT_TIME);
                lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN;
 
                lvid->descTag.descCRC = cpu_to_le16(
@@ -1588,7 +1612,6 @@ static void udf_open_lvid(struct super_block *sb)
 
 static void udf_close_lvid(struct super_block *sb)
 {
-       kernel_timestamp cpu_time;
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct buffer_head *bh = sbi->s_lvid_bh;
        struct logicalVolIntegrityDesc *lvid;
@@ -1603,8 +1626,8 @@ static void udf_close_lvid(struct super_block *sb)
                                                        udf_sb_lvidiu(sbi);
                lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
                lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
-               if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
-                       lvid->recordingDateAndTime = cpu_to_lets(cpu_time);
+               udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
+                                       CURRENT_TIME);
                if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev))
                        lvidiu->maxUDFWriteRev =
                                        cpu_to_le16(UDF_MAX_WRITE_VERSION);
@@ -1641,22 +1664,6 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
                vfree(bitmap);
 }
 
-/*
- * udf_read_super
- *
- * PURPOSE
- *     Complete the specified super block.
- *
- * PRE-CONDITIONS
- *     sb                      Pointer to superblock to complete - never NULL.
- *     sb->s_dev               Device to read suberblock from.
- *     options                 Pointer to mount options.
- *     silent                  Silent flag.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
 static int udf_fill_super(struct super_block *sb, void *options, int silent)
 {
        int i;
@@ -1678,7 +1685,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 
        mutex_init(&sbi->s_alloc_mutex);
 
-       if (!udf_parse_options((char *)options, &uopt))
+       if (!udf_parse_options((char *)options, &uopt, false))
                goto error_out;
 
        if (uopt.flags & (1 << UDF_FLAG_UTF8) &&
@@ -1709,8 +1716,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sbi->s_nls_map = uopt.nls_map;
 
        /* Set the block size for all transfers */
-       if (!udf_set_blocksize(sb, uopt.blocksize))
+       if (!sb_min_blocksize(sb, uopt.blocksize)) {
+               udf_debug("Bad block size (%d)\n", uopt.blocksize);
+               printk(KERN_ERR "udf: bad block size (%d)\n", uopt.blocksize);
                goto error_out;
+       }
 
        if (uopt.session == 0xFFFFFFFF)
                sbi->s_session = udf_get_last_session(sb);
@@ -1789,13 +1799,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        }
 
        if (!silent) {
-               kernel_timestamp ts;
-               udf_time_to_stamp(&ts, sbi->s_record_time);
-               udf_info("UDF %s (%s) Mounting volume '%s', "
+               timestamp ts;
+               udf_time_to_disk_stamp(&ts, sbi->s_record_time);
+               udf_info("UDF: Mounting volume '%s', "
                         "timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
-                        UDFFS_VERSION, UDFFS_DATE,
-                        sbi->s_volume_ident, ts.year, ts.month, ts.day,
-                        ts.hour, ts.minute, ts.typeAndTimezone);
+                        sbi->s_volume_ident, le16_to_cpu(ts.year), ts.month, ts.day,
+                        ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone));
        }
        if (!(sb->s_flags & MS_RDONLY))
                udf_open_lvid(sb);
@@ -1854,8 +1863,8 @@ error_out:
        return -EINVAL;
 }
 
-void udf_error(struct super_block *sb, const char *function,
-              const char *fmt, ...)
+static void udf_error(struct super_block *sb, const char *function,
+                     const char *fmt, ...)
 {
        va_list args;
 
@@ -1882,19 +1891,6 @@ void udf_warning(struct super_block *sb, const char *function,
               sb->s_id, function, error_buf);
 }
 
-/*
- * udf_put_super
- *
- * PURPOSE
- *     Prepare for destruction of the superblock.
- *
- * DESCRIPTION
- *     Called before the filesystem is unmounted.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
 static void udf_put_super(struct super_block *sb)
 {
        int i;
@@ -1930,19 +1926,6 @@ static void udf_put_super(struct super_block *sb)
        sb->s_fs_info = NULL;
 }
 
-/*
- * udf_stat_fs
- *
- * PURPOSE
- *     Return info about the filesystem.
- *
- * DESCRIPTION
- *     Called by sys_statfs()
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
 static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
@@ -1969,10 +1952,6 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
-static unsigned char udf_bitmap_lookup[16] = {
-       0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
-};
-
 static unsigned int udf_count_free_bitmap(struct super_block *sb,
                                          struct udf_bitmap *bitmap)
 {
@@ -1982,7 +1961,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
        int block = 0, newblock;
        kernel_lb_addr loc;
        uint32_t bytes;
-       uint8_t value;
        uint8_t *ptr;
        uint16_t ident;
        struct spaceBitmapDesc *bm;
@@ -2008,13 +1986,10 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
        ptr = (uint8_t *)bh->b_data;
 
        while (bytes > 0) {
-               while ((bytes > 0) && (index < sb->s_blocksize)) {
-                       value = ptr[index];
-                       accum += udf_bitmap_lookup[value & 0x0f];
-                       accum += udf_bitmap_lookup[value >> 4];
-                       index++;
-                       bytes--;
-               }
+               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);
@@ -2046,7 +2021,7 @@ static unsigned int udf_count_free_table(struct super_block *sb,
 
        lock_kernel();
 
-       epos.block = UDF_I_LOCATION(table);
+       epos.block = UDF_I(table)->i_location;
        epos.offset = sizeof(struct unallocSpaceEntry);
        epos.bh = NULL;