@@ -334,8 +334,7 @@ void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry
if (unlikely(dname_external(dentry))) {
atomic_inc(&external_name(dentry)->u.count);
} else {
- memcpy(name->inline_name, dentry->d_iname,
- dentry->d_name.len + 1);
+ name->inline_name_words = dentry->d_iname_words;
name->name.name = name->inline_name;
}
spin_unlock(&dentry->d_lock);
@@ -2729,9 +2728,8 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
* dentry:internal, target:external. Steal target's
* storage and make target internal.
*/
- memcpy(target->d_iname, dentry->d_name.name,
- dentry->d_name.len + 1);
dentry->d_name.name = target->d_name.name;
+ target->d_iname_words = dentry->d_iname_words;
target->d_name.name = target->d_iname;
}
} else {
@@ -2740,18 +2738,16 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
* dentry:external, target:internal. Give dentry's
* storage to target and make dentry internal
*/
- memcpy(dentry->d_iname, target->d_name.name,
- target->d_name.len + 1);
target->d_name.name = dentry->d_name.name;
+ dentry->d_iname_words = target->d_iname_words;
dentry->d_name.name = dentry->d_iname;
} else {
/*
* Both are internal.
*/
- for (int i = 0; i < DNAME_INLINE_WORDS; i++) {
- swap(((long *) &dentry->d_iname)[i],
- ((long *) &target->d_iname)[i]);
- }
+ for (int i = 0; i < DNAME_INLINE_WORDS; i++)
+ swap(dentry->d_iname_words.words[i],
+ target->d_iname_words.words[i]);
}
}
swap(dentry->d_name.hash_len, target->d_name.hash_len);
@@ -2766,8 +2762,7 @@ static void copy_name(struct dentry *dentry, struct dentry *target)
atomic_inc(&external_name(target)->u.count);
dentry->d_name = target->d_name;
} else {
- memcpy(dentry->d_iname, target->d_name.name,
- target->d_name.len + 1);
+ dentry->d_iname_words = target->d_iname_words;
dentry->d_name.name = dentry->d_iname;
dentry->d_name.hash_len = target->d_name.hash_len;
}
@@ -79,6 +79,10 @@ extern const struct qstr dotdot_name;
#define DNAME_INLINE_LEN (DNAME_INLINE_WORDS*sizeof(unsigned long))
+struct shortname_store {
+ unsigned long words[DNAME_INLINE_WORDS];
+};
+
#define d_lock d_lockref.lock
struct dentry {
@@ -90,7 +94,10 @@ struct dentry {
struct qstr d_name;
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
- unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
+ union {
+ unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
+ struct shortname_store d_iname_words;
+ };
/* --- cacheline 1 boundary (64 bytes) was 32 bytes ago --- */
/* Ref lookup also touches following */
@@ -591,7 +598,10 @@ static inline struct inode *d_real_inode(const struct dentry *dentry)
struct name_snapshot {
struct qstr name;
- unsigned char inline_name[DNAME_INLINE_LEN];
+ union {
+ unsigned char inline_name[DNAME_INLINE_LEN];
+ struct shortname_store inline_name_words;
+ };
};
void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
void release_dentry_name_snapshot(struct name_snapshot *);
... so that they can be copied with struct assignment (which generates better code) and accessed word-by-word. swap_names() used to do the latter already, using casts, etc.; now that can be done cleanly. Both dentry->d_iname and name_snapshot->inline_name got such treatment. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> --- fs/dcache.c | 19 +++++++------------ include/linux/dcache.h | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 14 deletions(-)