]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/fat/inode.c
fat: improve fat_hash()
[linux-2.6-omap-h63xx.git] / fs / fat / inode.c
index 6d266d793e2caba12ef6b65501ab1db116c50574..f58cd48d98b8e09d352ed92e50792cb98630965e 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
-#include <linux/msdos_fs.h>
 #include <linux/pagemap.h>
 #include <linux/mpage.h>
 #include <linux/buffer_head.h>
@@ -27,7 +26,9 @@
 #include <linux/uio.h>
 #include <linux/writeback.h>
 #include <linux/log2.h>
+#include <linux/hash.h>
 #include <asm/unaligned.h>
+#include "fat.h"
 
 #ifndef CONFIG_FAT_DEFAULT_IOCHARSET
 /* if user don't select VFAT, this is undefined. */
@@ -175,7 +176,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
 
        if (rw == WRITE) {
                /*
-                * FIXME: blockdev_direct_IO() doesn't use ->prepare_write(),
+                * FIXME: blockdev_direct_IO() doesn't use ->write_begin(),
                 * so we need to update the ->mmu_private to block boundary.
                 *
                 * But we must fill the remaining area or hole by nul for
@@ -247,25 +248,21 @@ static void fat_hash_init(struct super_block *sb)
                INIT_HLIST_HEAD(&sbi->inode_hashtable[i]);
 }
 
-static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos)
+static inline unsigned long fat_hash(loff_t i_pos)
 {
-       unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb;
-       tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2);
-       return tmp & FAT_HASH_MASK;
+       return hash_32(i_pos, FAT_HASH_BITS);
 }
 
 void fat_attach(struct inode *inode, loff_t i_pos)
 {
-       struct super_block *sb = inode->i_sb;
-       struct msdos_sb_info *sbi = MSDOS_SB(sb);
+       struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+       struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos);
 
        spin_lock(&sbi->inode_hash_lock);
        MSDOS_I(inode)->i_pos = i_pos;
-       hlist_add_head(&MSDOS_I(inode)->i_fat_hash,
-                       sbi->inode_hashtable + fat_hash(sb, i_pos));
+       hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head);
        spin_unlock(&sbi->inode_hash_lock);
 }
-
 EXPORT_SYMBOL_GPL(fat_attach);
 
 void fat_detach(struct inode *inode)
@@ -276,13 +273,12 @@ void fat_detach(struct inode *inode)
        hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
        spin_unlock(&sbi->inode_hash_lock);
 }
-
 EXPORT_SYMBOL_GPL(fat_detach);
 
 struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
-       struct hlist_head *head = sbi->inode_hashtable + fat_hash(sb, i_pos);
+       struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos);
        struct hlist_node *_p;
        struct msdos_inode_info *i;
        struct inode *inode = NULL;
@@ -381,22 +377,12 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
        MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
        inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
                           & ~((loff_t)sbi->cluster_size - 1)) >> 9;
-       inode->i_mtime.tv_sec =
-               date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date),
-                             sbi->options.tz_utc);
-       inode->i_mtime.tv_nsec = 0;
+
+       fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0);
        if (sbi->options.isvfat) {
-               int secs = de->ctime_cs / 100;
-               int csecs = de->ctime_cs % 100;
-               inode->i_ctime.tv_sec  =
-                       date_dos2unix(le16_to_cpu(de->ctime),
-                                     le16_to_cpu(de->cdate),
-                                     sbi->options.tz_utc) + secs;
-               inode->i_ctime.tv_nsec = csecs * 10000000;
-               inode->i_atime.tv_sec =
-                       date_dos2unix(0, le16_to_cpu(de->adate),
-                                     sbi->options.tz_utc);
-               inode->i_atime.tv_nsec = 0;
+               fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime,
+                                 de->cdate, de->ctime_cs);
+               fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0);
        } else
                inode->i_ctime = inode->i_atime = inode->i_mtime;
 
@@ -562,26 +548,23 @@ static int fat_write_inode(struct inode *inode, int wait)
        struct buffer_head *bh;
        struct msdos_dir_entry *raw_entry;
        loff_t i_pos;
-       int err = 0;
+       int err;
 
 retry:
        i_pos = MSDOS_I(inode)->i_pos;
        if (inode->i_ino == MSDOS_ROOT_INO || !i_pos)
                return 0;
 
-       lock_super(sb);
        bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
        if (!bh) {
                printk(KERN_ERR "FAT: unable to read inode block "
                       "for updating (i_pos %lld)\n", i_pos);
-               err = -EIO;
-               goto out;
+               return -EIO;
        }
        spin_lock(&sbi->inode_hash_lock);
        if (i_pos != MSDOS_I(inode)->i_pos) {
                spin_unlock(&sbi->inode_hash_lock);
                brelse(bh);
-               unlock_super(sb);
                goto retry;
        }
 
@@ -594,24 +577,21 @@ retry:
        raw_entry->attr = fat_attr(inode);
        raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart);
        raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16);
-       fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time,
-                         &raw_entry->date, sbi->options.tz_utc);
+       fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time,
+                         &raw_entry->date, NULL);
        if (sbi->options.isvfat) {
                __le16 atime;
-               fat_date_unix2dos(inode->i_ctime.tv_sec, &raw_entry->ctime,
-                                 &raw_entry->cdate, sbi->options.tz_utc);
-               fat_date_unix2dos(inode->i_atime.tv_sec, &atime,
-                                 &raw_entry->adate, sbi->options.tz_utc);
-               raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 +
-                       inode->i_ctime.tv_nsec / 10000000;
+               fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime,
+                                 &raw_entry->cdate, &raw_entry->ctime_cs);
+               fat_time_unix2fat(sbi, &inode->i_atime, &atime,
+                                 &raw_entry->adate, NULL);
        }
        spin_unlock(&sbi->inode_hash_lock);
        mark_buffer_dirty(bh);
+       err = 0;
        if (wait)
                err = sync_dirty_buffer(bh);
        brelse(bh);
-out:
-       unlock_super(sb);
        return err;
 }
 
@@ -685,33 +665,24 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb,
                        inode = NULL;
                }
        }
-       if (!inode) {
-               /* For now, do nothing
-                * What we could do is:
-                * follow the file starting at fh[4], and record
-                * the ".." entry, and the name of the fh[2] entry.
-                * The follow the ".." file finding the next step up.
-                * This way we build a path to the root of
-                * the tree. If this works, we lookup the path and so
-                * get this inode into the cache.
-                * Finally try the fat_iget lookup again
-                * If that fails, then weare totally out of luck
-                * But all that is for another day
-                */
-       }
-       if (!inode)
-               return ERR_PTR(-ESTALE);
-
 
-       /* now to find a dentry.
-        * If possible, get a well-connected one
+       /*
+        * For now, do nothing if the inode is not found.
+        *
+        * What we could do is:
+        *
+        *      - follow the file starting at fh[4], and record the ".." entry,
+        *        and the name of the fh[2] entry.
+        *      - then follow the ".." file finding the next step up.
+        *
+        * This way we build a path to the root of the tree. If this works, we
+        * lookup the path and so get this inode into the cache.  Finally try
+        * the fat_iget lookup again.  If that fails, then we are totally out
+        * of luck.  But all that is for another day
         */
-       result = d_alloc_anon(inode);
-       if (result == NULL) {
-               iput(inode);
-               return ERR_PTR(-ENOMEM);
-       }
-       result->d_op = sb->s_root->d_op;
+       result = d_obtain_alias(inode);
+       if (!IS_ERR(result))
+               result->d_op = sb->s_root->d_op;
        return result;
 }
 
@@ -758,15 +729,8 @@ static struct dentry *fat_get_parent(struct dentry *child)
        }
        inode = fat_build_inode(sb, de, i_pos);
        brelse(bh);
-       if (IS_ERR(inode)) {
-               parent = ERR_CAST(inode);
-               goto out;
-       }
-       parent = d_alloc_anon(inode);
-       if (!parent) {
-               iput(inode);
-               parent = ERR_PTR(-ENOMEM);
-       }
+
+       parent = d_obtain_alias(inode);
 out:
        unlock_super(sb);
 
@@ -859,7 +823,7 @@ enum {
        Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err,
 };
 
-static match_table_t fat_tokens = {
+static const match_table_t fat_tokens = {
        {Opt_check_r, "check=relaxed"},
        {Opt_check_s, "check=strict"},
        {Opt_check_n, "check=normal"},
@@ -894,14 +858,14 @@ static match_table_t fat_tokens = {
        {Opt_tz_utc, "tz=UTC"},
        {Opt_err, NULL},
 };
-static match_table_t msdos_tokens = {
+static const match_table_t msdos_tokens = {
        {Opt_nodots, "nodots"},
        {Opt_nodots, "dotsOK=no"},
        {Opt_dots, "dots"},
        {Opt_dots, "dotsOK=yes"},
        {Opt_err, NULL}
 };
-static match_table_t vfat_tokens = {
+static const match_table_t vfat_tokens = {
        {Opt_charset, "iocharset=%s"},
        {Opt_shortname_lower, "shortname=lower"},
        {Opt_shortname_win95, "shortname=win95"},