@@ -18,6 +18,8 @@ dentry_operations
prototypes::
int (*d_revalidate)(struct dentry *, unsigned int);
+ int (*d_revalidate_name)(struct dentry *, const struct qstr *,
+ unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, struct qstr *);
int (*d_compare)(const struct dentry *,
@@ -37,6 +39,7 @@ locking rules:
ops rename_lock ->d_lock may block rcu-walk
================== =========== ======== ============== ========
d_revalidate: no no yes (ref-walk) maybe
+d_revalidate_name: no no yes (ref-walk) maybe
d_weak_revalidate: no no yes no
d_hash no no no maybe
d_compare: yes no no maybe
@@ -1252,6 +1252,8 @@ defined:
struct dentry_operations {
int (*d_revalidate)(struct dentry *, unsigned int);
+ int (*d_revalidate_name)(struct dentry *, const struct qstr *,
+ unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, struct qstr *);
int (*d_compare)(const struct dentry *,
@@ -1288,6 +1290,16 @@ defined:
return
-ECHILD and it will be called again in ref-walk mode.
+``d_revalidate_name``
+ Variant of d_revalidate that also provides the name under look-up. Most
+ filesystems will keep it as NULL, unless there are particular semantics
+ for filenames encoding that need to be handled during dentry
+ revalidation.
+
+ When available, it is called in lieu of d_revalidate and has the same
+ locking rules and return semantics. Refer to d_revalidate for more
+ information.
+
``d_weak_revalidate``
called when the VFS needs to revalidate a "jumped" dentry. This
is called when a path-walk ends at dentry that was not acquired
@@ -1928,7 +1928,7 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
dentry->d_flags |= DCACHE_OP_HASH;
if (op->d_compare)
dentry->d_flags |= DCACHE_OP_COMPARE;
- if (op->d_revalidate)
+ if (op->d_revalidate || op->d_revalidate_name)
dentry->d_flags |= DCACHE_OP_REVALIDATE;
if (op->d_weak_revalidate)
dentry->d_flags |= DCACHE_OP_WEAK_REVALIDATE;
@@ -853,11 +853,16 @@ static bool try_to_unlazy_next(struct nameidata *nd, struct dentry *dentry)
return false;
}
-static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
+static inline int d_revalidate(struct dentry *dentry,
+ const struct qstr *name,
+ unsigned int flags)
{
- if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
+
+ if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
+ if (dentry->d_op->d_revalidate_name)
+ return dentry->d_op->d_revalidate_name(dentry, name, flags);
return dentry->d_op->d_revalidate(dentry, flags);
- else
+ } else
return 1;
}
@@ -1565,7 +1570,7 @@ static struct dentry *lookup_dcache(const struct qstr *name,
{
struct dentry *dentry = d_lookup(dir, name);
if (dentry) {
- int error = d_revalidate(dentry, flags);
+ int error = d_revalidate(dentry, name, flags);
if (unlikely(error <= 0)) {
if (!error)
d_invalidate(dentry);
@@ -1636,19 +1641,19 @@ static struct dentry *lookup_fast(struct nameidata *nd)
if (read_seqcount_retry(&parent->d_seq, nd->seq))
return ERR_PTR(-ECHILD);
- status = d_revalidate(dentry, nd->flags);
+ status = d_revalidate(dentry, &nd->last, nd->flags);
if (likely(status > 0))
return dentry;
if (!try_to_unlazy_next(nd, dentry))
return ERR_PTR(-ECHILD);
if (status == -ECHILD)
/* we'd been told to redo it in non-rcu mode */
- status = d_revalidate(dentry, nd->flags);
+ status = d_revalidate(dentry, &nd->last, nd->flags);
} else {
dentry = __d_lookup(parent, &nd->last);
if (unlikely(!dentry))
return NULL;
- status = d_revalidate(dentry, nd->flags);
+ status = d_revalidate(dentry, &nd->last, nd->flags);
}
if (unlikely(status <= 0)) {
if (!status)
@@ -1676,7 +1681,7 @@ static struct dentry *__lookup_slow(const struct qstr *name,
if (IS_ERR(dentry))
return dentry;
if (unlikely(!d_in_lookup(dentry))) {
- int error = d_revalidate(dentry, flags);
+ int error = d_revalidate(dentry, name, flags);
if (unlikely(error <= 0)) {
if (!error) {
d_invalidate(dentry);
@@ -3421,7 +3426,7 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
if (d_in_lookup(dentry))
break;
- error = d_revalidate(dentry, nd->flags);
+ error = d_revalidate(dentry, &nd->last, nd->flags);
if (likely(error > 0))
break;
if (error)
@@ -127,6 +127,7 @@ enum dentry_d_lock_class
struct dentry_operations {
int (*d_revalidate)(struct dentry *, unsigned int);
+ int (*d_revalidate_name)(struct dentry *, const struct qstr *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, struct qstr *);
int (*d_compare)(const struct dentry *,