]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/fat/inode.c
fat: Cleanup FAT attribute stuff
[linux-2.6-omap-h63xx.git] / fs / fat / inode.c
index d12cdf2a0406695b43a85e8db5b7f0990d7d2c5a..7aaa21cf019a5ac4929643c35e39c5628640437c 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;
@@ -341,8 +337,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 
        if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
                inode->i_generation &= ~1;
-               inode->i_mode = MSDOS_MKMODE(de->attr,
-                       S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
+               inode->i_mode = fat_make_mode(sbi, de->attr, S_IRWXUGO);
                inode->i_op = sbi->dir_ops;
                inode->i_fop = &fat_dir_operations;
 
@@ -359,10 +354,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
                inode->i_nlink = fat_subdirs(inode);
        } else { /* not a directory */
                inode->i_generation |= 1;
-               inode->i_mode = MSDOS_MKMODE(de->attr,
-                   ((sbi->options.showexec && !is_exec(de->name + 8))
-                       ? S_IRUGO|S_IWUGO : S_IRWXUGO)
-                   & ~sbi->options.fs_fmask) | S_IFREG;
+               inode->i_mode = fat_make_mode(sbi, de->attr,
+                       ((sbi->options.showexec && !is_exec(de->name + 8))
+                        ? S_IRUGO|S_IWUGO : S_IRWXUGO));
                MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
                if (sbi->fat_bits == 32)
                        MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16);
@@ -378,25 +372,16 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
                if (sbi->options.sys_immutable)
                        inode->i_flags |= S_IMMUTABLE;
        }
-       MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
+       fat_save_attrs(inode, de->attr);
+
        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;
 
@@ -443,13 +428,8 @@ static void fat_delete_inode(struct inode *inode)
 
 static void fat_clear_inode(struct inode *inode)
 {
-       struct super_block *sb = inode->i_sb;
-       struct msdos_sb_info *sbi = MSDOS_SB(sb);
-
-       spin_lock(&sbi->inode_hash_lock);
        fat_cache_inval_inode(inode);
-       hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
-       spin_unlock(&sbi->inode_hash_lock);
+       fat_detach(inode);
 }
 
 static void fat_write_super(struct super_block *sb)
@@ -588,19 +568,17 @@ retry:
                raw_entry->size = 0;
        else
                raw_entry->size = cpu_to_le32(inode->i_size);
-       raw_entry->attr = fat_attr(inode);
+       raw_entry->attr = fat_make_attrs(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);
@@ -681,33 +659,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;
 }
 
@@ -754,15 +723,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);
 
@@ -1142,7 +1104,7 @@ static int fat_read_root(struct inode *inode)
        inode->i_gid = sbi->options.fs_gid;
        inode->i_version++;
        inode->i_generation = 0;
-       inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
+       inode->i_mode = fat_make_mode(sbi, ATTR_DIR, S_IRWXUGO);
        inode->i_op = sbi->dir_ops;
        inode->i_fop = &fat_dir_operations;
        if (sbi->fat_bits == 32) {
@@ -1159,7 +1121,7 @@ static int fat_read_root(struct inode *inode)
        MSDOS_I(inode)->i_logstart = 0;
        MSDOS_I(inode)->mmu_private = inode->i_size;
 
-       MSDOS_I(inode)->i_attrs = ATTR_NONE;
+       fat_save_attrs(inode, ATTR_DIR);
        inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
        inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
        inode->i_nlink = fat_subdirs(inode)+2;