fs: change d_compare for rcu-walk

Change d_compare so it may be called from lock-free RCU lookups. This
does put significant restrictions on what may be done from the callback,
however there don't seem to have been any problems with in-tree fses.
If some strange use case pops up that _really_ cannot cope with the
rcu-walk rules, we can just add new rcu-unaware callbacks, which would
cause name lookup to drop out of rcu-walk mode.

For in-tree filesystems, this is just a mechanical change.

Signed-off-by: Nick Piggin <[email protected]>
This commit is contained in:
Nick Piggin 2011-01-07 17:49:27 +11:00
commit 621e155a35
23 changed files with 242 additions and 157 deletions

View file

@ -28,14 +28,26 @@
static int isofs_hashi(struct dentry *parent, struct qstr *qstr);
static int isofs_hash(struct dentry *parent, struct qstr *qstr);
static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
static int isofs_dentry_cmpi(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name);
static int isofs_dentry_cmp(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name);
#ifdef CONFIG_JOLIET
static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr);
static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr);
static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
static int isofs_dentry_cmpi_ms(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name);
static int isofs_dentry_cmp_ms(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name);
#endif
static void isofs_put_super(struct super_block *sb)
@ -206,49 +218,31 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
}
/*
* Case insensitive compare of two isofs names.
* Compare of two isofs names.
*/
static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a,
struct qstr *b, int ms)
static int isofs_dentry_cmp_common(
unsigned int len, const char *str,
const struct qstr *name, int ms, int ci)
{
int alen, blen;
/* A filename cannot end in '.' or we treat it like it has none */
alen = a->len;
blen = b->len;
alen = name->len;
blen = len;
if (ms) {
while (alen && a->name[alen-1] == '.')
while (alen && name->name[alen-1] == '.')
alen--;
while (blen && b->name[blen-1] == '.')
while (blen && str[blen-1] == '.')
blen--;
}
if (alen == blen) {
if (strnicmp(a->name, b->name, alen) == 0)
return 0;
}
return 1;
}
/*
* Case sensitive compare of two isofs names.
*/
static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a,
struct qstr *b, int ms)
{
int alen, blen;
/* A filename cannot end in '.' or we treat it like it has none */
alen = a->len;
blen = b->len;
if (ms) {
while (alen && a->name[alen-1] == '.')
alen--;
while (blen && b->name[blen-1] == '.')
blen--;
}
if (alen == blen) {
if (strncmp(a->name, b->name, alen) == 0)
return 0;
if (ci) {
if (strnicmp(name->name, str, alen) == 0)
return 0;
} else {
if (strncmp(name->name, str, alen) == 0)
return 0;
}
}
return 1;
}
@ -266,15 +260,19 @@ isofs_hashi(struct dentry *dentry, struct qstr *qstr)
}
static int
isofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b)
isofs_dentry_cmp(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name)
{
return isofs_dentry_cmp_common(dentry, a, b, 0);
return isofs_dentry_cmp_common(len, str, name, 0, 0);
}
static int
isofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b)
isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name)
{
return isofs_dentry_cmpi_common(dentry, a, b, 0);
return isofs_dentry_cmp_common(len, str, name, 0, 1);
}
#ifdef CONFIG_JOLIET
@ -291,15 +289,19 @@ isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr)
}
static int
isofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
isofs_dentry_cmp_ms(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name)
{
return isofs_dentry_cmp_common(dentry, a, b, 1);
return isofs_dentry_cmp_common(len, str, name, 1, 0);
}
static int
isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
isofs_dentry_cmpi_ms(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
unsigned int len, const char *str, const struct qstr *name)
{
return isofs_dentry_cmpi_common(dentry, a, b, 1);
return isofs_dentry_cmp_common(len, str, name, 1, 1);
}
#endif

View file

@ -37,7 +37,8 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
qstr.name = compare;
qstr.len = dlen;
return dentry->d_op->d_compare(dentry, &dentry->d_name, &qstr);
return dentry->d_op->d_compare(NULL, NULL, NULL, NULL,
dentry->d_name.len, dentry->d_name.name, &qstr);
}
/*