Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 118459
b: refs/heads/master
c: 1b52467
h: refs/heads/master
i:
  118457: 47a376b
  118455: 2fe12a4
v: v3
  • Loading branch information
OGAWA Hirofumi authored and Linus Torvalds committed Nov 6, 2008
1 parent 8edec13 commit a311f9b
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 45 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: 068f5ae05c51d2cee6b31cb3da06775dd83bd348
refs/heads/master: 1b52467243c7167b3a267ddbcbb14d550f28eb4a
124 changes: 80 additions & 44 deletions trunk/fs/fat/namei_vfat.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,67 @@
#include <linux/namei.h>
#include "fat.h"

static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
/*
* If new entry was created in the parent, it could create the 8.3
* alias (the shortname of logname). So, the parent may have the
* negative-dentry which matches the created 8.3 alias.
*
* If it happened, the negative dentry isn't actually negative
* anymore. So, drop it.
*/
static int vfat_revalidate_shortname(struct dentry *dentry)
{
int ret = 1;

if (!dentry->d_inode &&
nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_CREATE))
/*
* negative dentry is dropped, in order to make sure
* to use the name which a user desires if this is
* create path.
*/
spin_lock(&dentry->d_lock);
if (dentry->d_time != dentry->d_parent->d_inode->i_version)
ret = 0;
else {
spin_lock(&dentry->d_lock);
if (dentry->d_time != dentry->d_parent->d_inode->i_version)
ret = 0;
spin_unlock(&dentry->d_lock);
}
spin_unlock(&dentry->d_lock);
return ret;
}

static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
{
/* This is not negative dentry. Always valid. */
if (dentry->d_inode)
return 1;
return vfat_revalidate_shortname(dentry);
}

static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
{
/*
* This is not negative dentry. Always valid.
*
* Note, rename() to existing directory entry will have ->d_inode,
* and will use existing name which isn't specified name by user.
*
* We may be able to drop this positive dentry here. But dropping
* positive dentry isn't good idea. So it's unsupported like
* rename("filename", "FILENAME") for now.
*/
if (dentry->d_inode)
return 1;

/*
* This may be nfsd (or something), anyway, we can't see the
* intent of this. So, since this can be for creation, drop it.
*/
if (!nd)
return 0;

/*
* Drop the negative dentry, in order to make sure to use the
* case sensitive name which is specified by user if this is
* for creation.
*/
if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) {
if (nd->flags & LOOKUP_CREATE)
return 0;
}

return vfat_revalidate_shortname(dentry);
}

/* returns the length of a struct qstr, ignoring trailing dots */
static unsigned int vfat_striptail_len(struct qstr *qstr)
{
Expand Down Expand Up @@ -126,25 +166,16 @@ static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
return 1;
}

static struct dentry_operations vfat_dentry_ops[4] = {
{
.d_hash = vfat_hashi,
.d_compare = vfat_cmpi,
},
{
.d_revalidate = vfat_revalidate,
.d_hash = vfat_hashi,
.d_compare = vfat_cmpi,
},
{
.d_hash = vfat_hash,
.d_compare = vfat_cmp,
},
{
.d_revalidate = vfat_revalidate,
.d_hash = vfat_hash,
.d_compare = vfat_cmp,
}
static struct dentry_operations vfat_ci_dentry_ops = {
.d_revalidate = vfat_revalidate_ci,
.d_hash = vfat_hashi,
.d_compare = vfat_cmpi,
};

static struct dentry_operations vfat_dentry_ops = {
.d_revalidate = vfat_revalidate,
.d_hash = vfat_hash,
.d_compare = vfat_cmp,
};

/* Characters that are undesirable in an MS-DOS file name */
Expand Down Expand Up @@ -685,45 +716,50 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
struct fat_slot_info sinfo;
struct inode *inode;
struct dentry *alias;
int err, table;
int err;

lock_super(sb);
table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0;
dentry->d_op = &vfat_dentry_ops[table];

err = vfat_find(dir, &dentry->d_name, &sinfo);
if (err) {
if (err == -ENOENT) {
table++;
inode = NULL;
goto out;
}
goto error;
}

inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
}

alias = d_find_alias(inode);
if (alias) {
if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
/*
* This inode has non DCACHE_DISCONNECTED dentry. This
* means, the user did ->lookup() by an another name
* (longname vs 8.3 alias of it) in past.
*
* Switch to new one for reason of locality if possible.
*/
if (d_invalidate(alias) == 0)
dput(alias);
else {
iput(inode);
unlock_super(sb);
return alias;
}

}
out:
unlock_super(sb);
dentry->d_op = &vfat_dentry_ops[table];
dentry->d_op = sb->s_root->d_op;
dentry->d_time = dentry->d_parent->d_inode->i_version;
dentry = d_splice_alias(inode, dentry);
if (dentry) {
dentry->d_op = &vfat_dentry_ops[table];
dentry->d_op = sb->s_root->d_op;
dentry->d_time = dentry->d_parent->d_inode->i_version;
}
return dentry;
Expand Down Expand Up @@ -1022,9 +1058,9 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent)
return res;

if (MSDOS_SB(sb)->options.name_check != 's')
sb->s_root->d_op = &vfat_dentry_ops[0];
sb->s_root->d_op = &vfat_ci_dentry_ops;
else
sb->s_root->d_op = &vfat_dentry_ops[2];
sb->s_root->d_op = &vfat_dentry_ops;

return 0;
}
Expand Down

0 comments on commit a311f9b

Please sign in to comment.