Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 330133
b: refs/heads/master
c: 7669e8f
h: refs/heads/master
i:
  330131: 0ed917a
v: v3
  • Loading branch information
Steven J. Magnani authored and Linus Torvalds committed Oct 5, 2012
1 parent 18595a3 commit dd679ac
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 138 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 21b6633d516c4f5d03ec02ede6374e320191003f
refs/heads/master: 7669e8fb09da47dd45c07a51394f01031ea81da8
20 changes: 11 additions & 9 deletions trunk/fs/fat/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -872,21 +872,23 @@ static int fat_get_short_entry(struct inode *dir, loff_t *pos,
}

/*
* The ".." entry can not provide the "struct fat_slot_info" informations
* for inode. So, this function provide the some informations only.
* The ".." entry can not provide the "struct fat_slot_info" information
* for inode, nor a usable i_pos. So, this function provides some information
* only.
*
* Since this function walks through the on-disk inodes within a directory,
* callers are responsible for taking any locks necessary to prevent the
* directory from changing.
*/
int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos)
struct msdos_dir_entry **de)
{
loff_t offset;
loff_t offset = 0;

offset = 0;
*bh = NULL;
*de = NULL;
while (fat_get_short_entry(dir, &offset, bh, de) >= 0) {
if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) {
*i_pos = fat_make_i_pos(dir->i_sb, *bh, *de);
if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME))
return 0;
}
}
return -ENOENT;
}
Expand Down
27 changes: 12 additions & 15 deletions trunk/fs/fat/fat.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <linux/string.h>
#include <linux/nls.h>
#include <linux/fs.h>
#include <linux/hash.h>
#include <linux/mutex.h>
#include <linux/ratelimit.h>
#include <linux/msdos_fs.h>
Expand Down Expand Up @@ -46,7 +47,8 @@ struct fat_mount_options {
usefree:1, /* Use free_clusters for FAT32 */
tz_utc:1, /* Filesystem timestamps are in UTC */
rodir:1, /* allow ATTR_RO for directory */
discard:1; /* Issue discard requests on deletions */
discard:1, /* Issue discard requests on deletions */
nfs:1; /* Do extra work needed for NFS export */
};

#define FAT_HASH_BITS 8
Expand Down Expand Up @@ -88,6 +90,9 @@ struct msdos_sb_info {

spinlock_t inode_hash_lock;
struct hlist_head inode_hashtable[FAT_HASH_SIZE];

spinlock_t dir_hash_lock;
struct hlist_head dir_hashtable[FAT_HASH_SIZE];
};

#define FAT_CACHE_VALID 0 /* special case for valid cache */
Expand All @@ -110,6 +115,7 @@ struct msdos_inode_info {
int i_attrs; /* unused attribute bits */
loff_t i_pos; /* on-disk position of directory entry or 0 */
struct hlist_node i_fat_hash; /* hash by i_location */
struct hlist_node i_dir_hash; /* hash by i_logstart */
struct rw_semaphore truncate_lock; /* protect bmap against truncate */
struct inode vfs_inode;
};
Expand Down Expand Up @@ -262,7 +268,7 @@ extern int fat_subdirs(struct inode *dir);
extern int fat_scan(struct inode *dir, const unsigned char *name,
struct fat_slot_info *sinfo);
extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos);
struct msdos_dir_entry **de);
extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
struct fat_slot_info *sinfo);
Expand Down Expand Up @@ -341,18 +347,9 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent,

extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
struct inode *i2);
static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi,
struct inode *inode)
static inline unsigned long fat_dir_hash(int logstart)
{
loff_t i_pos;
#if BITS_PER_LONG == 32
spin_lock(&sbi->inode_hash_lock);
#endif
i_pos = MSDOS_I(inode)->i_pos;
#if BITS_PER_LONG == 32
spin_unlock(&sbi->inode_hash_lock);
#endif
return i_pos;
return hash_32(logstart, FAT_HASH_BITS);
}

/* fat/misc.c */
Expand Down Expand Up @@ -382,10 +379,10 @@ void fat_cache_destroy(void);

/* fat/nfs.c */
struct fid;
extern int fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp,
struct inode *parent);
extern struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type);
extern struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type);
extern struct dentry *fat_get_parent(struct dentry *child_dir);

/* helper for printk */
Expand Down
71 changes: 64 additions & 7 deletions trunk/fs/fat/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,15 +281,42 @@ static inline unsigned long fat_hash(loff_t i_pos)
return hash_32(i_pos, FAT_HASH_BITS);
}

static void dir_hash_init(struct super_block *sb)
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int i;

spin_lock_init(&sbi->dir_hash_lock);
for (i = 0; i < FAT_HASH_SIZE; i++)
INIT_HLIST_HEAD(&sbi->dir_hashtable[i]);
}

void fat_attach(struct inode *inode, loff_t i_pos)
{
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, head);
spin_unlock(&sbi->inode_hash_lock);
if (inode->i_ino != MSDOS_ROOT_INO) {
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, head);
spin_unlock(&sbi->inode_hash_lock);
}

/* If NFS support is enabled, cache the mapping of start cluster
* to directory inode. This is used during reconnection of
* dentries to the filesystem root.
*/
if (S_ISDIR(inode->i_mode) && sbi->options.nfs) {
struct hlist_head *d_head = sbi->dir_hashtable;
d_head += fat_dir_hash(MSDOS_I(inode)->i_logstart);

spin_lock(&sbi->dir_hash_lock);
hlist_add_head(&MSDOS_I(inode)->i_dir_hash, d_head);
spin_unlock(&sbi->dir_hash_lock);
}
}
EXPORT_SYMBOL_GPL(fat_attach);

Expand All @@ -300,6 +327,12 @@ void fat_detach(struct inode *inode)
MSDOS_I(inode)->i_pos = 0;
hlist_del_init(&MSDOS_I(inode)->i_fat_hash);
spin_unlock(&sbi->inode_hash_lock);

if (S_ISDIR(inode->i_mode) && sbi->options.nfs) {
spin_lock(&sbi->dir_hash_lock);
hlist_del_init(&MSDOS_I(inode)->i_dir_hash);
spin_unlock(&sbi->dir_hash_lock);
}
}
EXPORT_SYMBOL_GPL(fat_detach);

Expand Down Expand Up @@ -504,6 +537,7 @@ static void init_once(void *foo)
ei->cache_valid_id = FAT_CACHE_VALID + 1;
INIT_LIST_HEAD(&ei->cache_lru);
INIT_HLIST_NODE(&ei->i_fat_hash);
INIT_HLIST_NODE(&ei->i_dir_hash);
inode_init_once(&ei->vfs_inode);
}

Expand Down Expand Up @@ -562,6 +596,20 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}

static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi,
struct inode *inode)
{
loff_t i_pos;
#if BITS_PER_LONG == 32
spin_lock(&sbi->inode_hash_lock);
#endif
i_pos = MSDOS_I(inode)->i_pos;
#if BITS_PER_LONG == 32
spin_unlock(&sbi->inode_hash_lock);
#endif
return i_pos;
}

static int __fat_write_inode(struct inode *inode, int wait)
{
struct super_block *sb = inode->i_sb;
Expand Down Expand Up @@ -655,8 +703,8 @@ static const struct super_operations fat_sops = {
};

static const struct export_operations fat_export_ops = {
.encode_fh = fat_encode_fh,
.fh_to_dentry = fat_fh_to_dentry,
.fh_to_parent = fat_fh_to_parent,
.get_parent = fat_get_parent,
};

Expand Down Expand Up @@ -706,6 +754,8 @@ static int fat_show_options(struct seq_file *m, struct dentry *root)
seq_puts(m, ",usefree");
if (opts->quiet)
seq_puts(m, ",quiet");
if (opts->nfs)
seq_puts(m, ",nfs");
if (opts->showexec)
seq_puts(m, ",showexec");
if (opts->sys_immutable)
Expand Down Expand Up @@ -750,7 +800,7 @@ enum {
Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
Opt_err_panic, Opt_err_ro, Opt_discard, Opt_err,
Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_err,
};

static const match_table_t fat_tokens = {
Expand Down Expand Up @@ -779,6 +829,7 @@ static const match_table_t fat_tokens = {
{Opt_err_panic, "errors=panic"},
{Opt_err_ro, "errors=remount-ro"},
{Opt_discard, "discard"},
{Opt_nfs, "nfs"},
{Opt_obsolete, "conv=binary"},
{Opt_obsolete, "conv=text"},
{Opt_obsolete, "conv=auto"},
Expand Down Expand Up @@ -859,6 +910,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
opts->numtail = 1;
opts->usefree = opts->nocase = 0;
opts->tz_utc = 0;
opts->nfs = 0;
opts->errors = FAT_ERRORS_RO;
*debug = 0;

Expand Down Expand Up @@ -1023,6 +1075,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
case Opt_discard:
opts->discard = 1;
break;
case Opt_nfs:
opts->nfs = 1;
break;

/* obsolete mount options */
case Opt_obsolete:
Expand Down Expand Up @@ -1313,6 +1368,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,

/* set up enough so that it can read an inode */
fat_hash_init(sb);
dir_hash_init(sb);
fat_ent_access_init(sb);

/*
Expand Down Expand Up @@ -1367,6 +1423,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
}
error = -ENOMEM;
insert_inode_hash(root_inode);
fat_attach(root_inode, 0);
sb->s_root = d_make_root(root_inode);
if (!sb->s_root) {
fat_msg(sb, KERN_ERR, "get root inode failed");
Expand Down
5 changes: 2 additions & 3 deletions trunk/fs/fat/namei_msdos.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
struct inode *old_inode, *new_inode;
struct fat_slot_info old_sinfo, sinfo;
struct timespec ts;
loff_t dotdot_i_pos, new_i_pos;
loff_t new_i_pos;
int err, old_attrs, is_dir, update_dotdot, corrupt = 0;

old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
Expand All @@ -456,8 +456,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
is_dir = S_ISDIR(old_inode->i_mode);
update_dotdot = (is_dir && old_dir != new_dir);
if (update_dotdot) {
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
&dotdot_i_pos) < 0) {
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) {
err = -EIO;
goto out;
}
Expand Down
5 changes: 2 additions & 3 deletions trunk/fs/fat/namei_vfat.c
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *old_inode, *new_inode;
struct fat_slot_info old_sinfo, sinfo;
struct timespec ts;
loff_t dotdot_i_pos, new_i_pos;
loff_t new_i_pos;
int err, is_dir, update_dotdot, corrupt = 0;
struct super_block *sb = old_dir->i_sb;

Expand All @@ -929,8 +929,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
is_dir = S_ISDIR(old_inode->i_mode);
update_dotdot = (is_dir && old_dir != new_dir);
if (update_dotdot) {
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de,
&dotdot_i_pos) < 0) {
if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) {
err = -EIO;
goto out;
}
Expand Down
Loading

0 comments on commit dd679ac

Please sign in to comment.