diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2016-06-30 02:53:27 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2016-06-30 02:53:27 -0400 |
commit | 2d902671ce1cd98cdc88d78c481889a1b2996101 (patch) | |
tree | 48c4bc8f90ee3209b7fba9b70169e8528b781eaa | |
parent | 4c2e07c6a29e0129e975727b9f57eede813eea85 (diff) |
vfs: merge .d_select_inode() into .d_real()
The two methods essentially do the same: find the real dentry/inode
belonging to an overlay dentry. The difference is in the usage:
vfs_open() uses ->d_select_inode() and expects the function to perform
copy-up if necessary based on the open flags argument.
file_dentry() uses ->d_real() passing in the overlay dentry as well as the
underlying inode.
vfs_rename() uses ->d_select_inode() but passes zero flags. ->d_real()
with a zero inode would have worked just as well here.
This patch merges the functionality of ->d_select_inode() into ->d_real()
by adding an 'open_flags' argument to the latter.
[Al Viro] Make the signature of d_real() match that of ->d_real() again.
And constify the inode argument, while we are at it.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r-- | fs/dcache.c | 3 | ||||
-rw-r--r-- | fs/namei.c | 2 | ||||
-rw-r--r-- | fs/open.c | 8 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 31 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 2 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 20 | ||||
-rw-r--r-- | include/linux/dcache.h | 28 | ||||
-rw-r--r-- | include/linux/fs.h | 7 |
8 files changed, 39 insertions, 62 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index d6847d7b123d..5405b89fe8ec 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1729,7 +1729,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1729 | DCACHE_OP_REVALIDATE | | 1729 | DCACHE_OP_REVALIDATE | |
1730 | DCACHE_OP_WEAK_REVALIDATE | | 1730 | DCACHE_OP_WEAK_REVALIDATE | |
1731 | DCACHE_OP_DELETE | | 1731 | DCACHE_OP_DELETE | |
1732 | DCACHE_OP_SELECT_INODE | | ||
1733 | DCACHE_OP_REAL)); | 1732 | DCACHE_OP_REAL)); |
1734 | dentry->d_op = op; | 1733 | dentry->d_op = op; |
1735 | if (!op) | 1734 | if (!op) |
@@ -1746,8 +1745,6 @@ void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) | |||
1746 | dentry->d_flags |= DCACHE_OP_DELETE; | 1745 | dentry->d_flags |= DCACHE_OP_DELETE; |
1747 | if (op->d_prune) | 1746 | if (op->d_prune) |
1748 | dentry->d_flags |= DCACHE_OP_PRUNE; | 1747 | dentry->d_flags |= DCACHE_OP_PRUNE; |
1749 | if (op->d_select_inode) | ||
1750 | dentry->d_flags |= DCACHE_OP_SELECT_INODE; | ||
1751 | if (op->d_real) | 1748 | if (op->d_real) |
1752 | dentry->d_flags |= DCACHE_OP_REAL; | 1749 | dentry->d_flags |= DCACHE_OP_REAL; |
1753 | 1750 | ||
diff --git a/fs/namei.c b/fs/namei.c index 70580ab1445c..bb7a2e0b959c 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -4328,7 +4328,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
4328 | * Check source == target. | 4328 | * Check source == target. |
4329 | * On overlayfs need to look at underlying inodes. | 4329 | * On overlayfs need to look at underlying inodes. |
4330 | */ | 4330 | */ |
4331 | if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0)) | 4331 | if (d_real_inode(old_dentry) == d_real_inode(new_dentry)) |
4332 | return 0; | 4332 | return 0; |
4333 | 4333 | ||
4334 | error = may_delete(old_dir, old_dentry, is_dir); | 4334 | error = may_delete(old_dir, old_dentry, is_dir); |
@@ -840,13 +840,13 @@ EXPORT_SYMBOL(file_path); | |||
840 | int vfs_open(const struct path *path, struct file *file, | 840 | int vfs_open(const struct path *path, struct file *file, |
841 | const struct cred *cred) | 841 | const struct cred *cred) |
842 | { | 842 | { |
843 | struct inode *inode = vfs_select_inode(path->dentry, file->f_flags); | 843 | struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags); |
844 | 844 | ||
845 | if (IS_ERR(inode)) | 845 | if (IS_ERR(dentry)) |
846 | return PTR_ERR(inode); | 846 | return PTR_ERR(dentry); |
847 | 847 | ||
848 | file->f_path = *path; | 848 | file->f_path = *path; |
849 | return do_dentry_open(file, inode, NULL, cred); | 849 | return do_dentry_open(file, d_backing_inode(dentry), NULL, cred); |
850 | } | 850 | } |
851 | 851 | ||
852 | struct file *dentry_open(const struct path *path, int flags, | 852 | struct file *dentry_open(const struct path *path, int flags, |
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 1dbeab6cf96e..e08cd94d7b26 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c | |||
@@ -325,36 +325,25 @@ static bool ovl_open_need_copy_up(int flags, enum ovl_path_type type, | |||
325 | return true; | 325 | return true; |
326 | } | 326 | } |
327 | 327 | ||
328 | struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags) | 328 | int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags) |
329 | { | 329 | { |
330 | int err; | 330 | int err = 0; |
331 | struct path realpath; | 331 | struct path realpath; |
332 | enum ovl_path_type type; | 332 | enum ovl_path_type type; |
333 | 333 | ||
334 | if (d_is_dir(dentry)) | ||
335 | return d_backing_inode(dentry); | ||
336 | |||
337 | type = ovl_path_real(dentry, &realpath); | 334 | type = ovl_path_real(dentry, &realpath); |
338 | if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) { | 335 | if (ovl_open_need_copy_up(file_flags, type, realpath.dentry)) { |
339 | err = ovl_want_write(dentry); | 336 | err = ovl_want_write(dentry); |
340 | if (err) | 337 | if (!err) { |
341 | return ERR_PTR(err); | 338 | if (file_flags & O_TRUNC) |
342 | 339 | err = ovl_copy_up_truncate(dentry); | |
343 | if (file_flags & O_TRUNC) | 340 | else |
344 | err = ovl_copy_up_truncate(dentry); | 341 | err = ovl_copy_up(dentry); |
345 | else | 342 | ovl_drop_write(dentry); |
346 | err = ovl_copy_up(dentry); | 343 | } |
347 | ovl_drop_write(dentry); | ||
348 | if (err) | ||
349 | return ERR_PTR(err); | ||
350 | |||
351 | ovl_path_upper(dentry, &realpath); | ||
352 | } | 344 | } |
353 | 345 | ||
354 | if (realpath.dentry->d_flags & DCACHE_OP_SELECT_INODE) | 346 | return err; |
355 | return realpath.dentry->d_op->d_select_inode(realpath.dentry, file_flags); | ||
356 | |||
357 | return d_backing_inode(realpath.dentry); | ||
358 | } | 347 | } |
359 | 348 | ||
360 | static const struct inode_operations ovl_file_inode_operations = { | 349 | static const struct inode_operations ovl_file_inode_operations = { |
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 4bd9b5ba8f42..6b9fd25c5ad4 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
@@ -179,7 +179,7 @@ ssize_t ovl_getxattr(struct dentry *dentry, struct inode *inode, | |||
179 | const char *name, void *value, size_t size); | 179 | const char *name, void *value, size_t size); |
180 | ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); | 180 | ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size); |
181 | int ovl_removexattr(struct dentry *dentry, const char *name); | 181 | int ovl_removexattr(struct dentry *dentry, const char *name); |
182 | struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags); | 182 | int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags); |
183 | 183 | ||
184 | struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, | 184 | struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, |
185 | struct ovl_entry *oe); | 185 | struct ovl_entry *oe); |
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index ce02f46029da..035c176edf00 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -304,7 +304,9 @@ static void ovl_dentry_release(struct dentry *dentry) | |||
304 | } | 304 | } |
305 | } | 305 | } |
306 | 306 | ||
307 | static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode) | 307 | static struct dentry *ovl_d_real(struct dentry *dentry, |
308 | const struct inode *inode, | ||
309 | unsigned int open_flags) | ||
308 | { | 310 | { |
309 | struct dentry *real; | 311 | struct dentry *real; |
310 | 312 | ||
@@ -314,6 +316,16 @@ static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode) | |||
314 | goto bug; | 316 | goto bug; |
315 | } | 317 | } |
316 | 318 | ||
319 | if (d_is_negative(dentry)) | ||
320 | return dentry; | ||
321 | |||
322 | if (open_flags) { | ||
323 | int err = ovl_open_maybe_copy_up(dentry, open_flags); | ||
324 | |||
325 | if (err) | ||
326 | return ERR_PTR(err); | ||
327 | } | ||
328 | |||
317 | real = ovl_dentry_upper(dentry); | 329 | real = ovl_dentry_upper(dentry); |
318 | if (real && (!inode || inode == d_inode(real))) | 330 | if (real && (!inode || inode == d_inode(real))) |
319 | return real; | 331 | return real; |
@@ -326,9 +338,7 @@ static struct dentry *ovl_d_real(struct dentry *dentry, struct inode *inode) | |||
326 | return real; | 338 | return real; |
327 | 339 | ||
328 | /* Handle recursion */ | 340 | /* Handle recursion */ |
329 | if (real->d_flags & DCACHE_OP_REAL) | 341 | return d_real(real, inode, open_flags); |
330 | return real->d_op->d_real(real, inode); | ||
331 | |||
332 | bug: | 342 | bug: |
333 | WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry, | 343 | WARN(1, "ovl_d_real(%pd4, %s:%lu\n): real dentry not found\n", dentry, |
334 | inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0); | 344 | inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0); |
@@ -378,13 +388,11 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags) | |||
378 | 388 | ||
379 | static const struct dentry_operations ovl_dentry_operations = { | 389 | static const struct dentry_operations ovl_dentry_operations = { |
380 | .d_release = ovl_dentry_release, | 390 | .d_release = ovl_dentry_release, |
381 | .d_select_inode = ovl_d_select_inode, | ||
382 | .d_real = ovl_d_real, | 391 | .d_real = ovl_d_real, |
383 | }; | 392 | }; |
384 | 393 | ||
385 | static const struct dentry_operations ovl_reval_dentry_operations = { | 394 | static const struct dentry_operations ovl_reval_dentry_operations = { |
386 | .d_release = ovl_dentry_release, | 395 | .d_release = ovl_dentry_release, |
387 | .d_select_inode = ovl_d_select_inode, | ||
388 | .d_real = ovl_d_real, | 396 | .d_real = ovl_d_real, |
389 | .d_revalidate = ovl_dentry_revalidate, | 397 | .d_revalidate = ovl_dentry_revalidate, |
390 | .d_weak_revalidate = ovl_dentry_weak_revalidate, | 398 | .d_weak_revalidate = ovl_dentry_weak_revalidate, |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index f53fa055021a..45b22de15ede 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -139,8 +139,7 @@ struct dentry_operations { | |||
139 | char *(*d_dname)(struct dentry *, char *, int); | 139 | char *(*d_dname)(struct dentry *, char *, int); |
140 | struct vfsmount *(*d_automount)(struct path *); | 140 | struct vfsmount *(*d_automount)(struct path *); |
141 | int (*d_manage)(struct dentry *, bool); | 141 | int (*d_manage)(struct dentry *, bool); |
142 | struct inode *(*d_select_inode)(struct dentry *, unsigned); | 142 | struct dentry *(*d_real)(struct dentry *, const struct inode *, unsigned int); |
143 | struct dentry *(*d_real)(struct dentry *, struct inode *); | ||
144 | } ____cacheline_aligned; | 143 | } ____cacheline_aligned; |
145 | 144 | ||
146 | /* | 145 | /* |
@@ -206,10 +205,8 @@ struct dentry_operations { | |||
206 | 205 | ||
207 | #define DCACHE_MAY_FREE 0x00800000 | 206 | #define DCACHE_MAY_FREE 0x00800000 |
208 | #define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ | 207 | #define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ |
209 | #define DCACHE_OP_SELECT_INODE 0x02000000 /* Unioned entry: dcache op selects inode */ | 208 | #define DCACHE_ENCRYPTED_WITH_KEY 0x02000000 /* dir is encrypted with a valid key */ |
210 | 209 | #define DCACHE_OP_REAL 0x04000000 | |
211 | #define DCACHE_ENCRYPTED_WITH_KEY 0x04000000 /* dir is encrypted with a valid key */ | ||
212 | #define DCACHE_OP_REAL 0x08000000 | ||
213 | 210 | ||
214 | #define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */ | 211 | #define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */ |
215 | #define DCACHE_DENTRY_CURSOR 0x20000000 | 212 | #define DCACHE_DENTRY_CURSOR 0x20000000 |
@@ -557,25 +554,16 @@ static inline struct dentry *d_backing_dentry(struct dentry *upper) | |||
557 | return upper; | 554 | return upper; |
558 | } | 555 | } |
559 | 556 | ||
560 | static inline struct dentry *d_real(struct dentry *dentry) | 557 | static inline struct dentry *d_real(struct dentry *dentry, |
558 | const struct inode *inode, | ||
559 | unsigned int flags) | ||
561 | { | 560 | { |
562 | if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) | 561 | if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) |
563 | return dentry->d_op->d_real(dentry, NULL); | 562 | return dentry->d_op->d_real(dentry, inode, flags); |
564 | else | 563 | else |
565 | return dentry; | 564 | return dentry; |
566 | } | 565 | } |
567 | 566 | ||
568 | static inline struct inode *vfs_select_inode(struct dentry *dentry, | ||
569 | unsigned open_flags) | ||
570 | { | ||
571 | struct inode *inode = d_inode(dentry); | ||
572 | |||
573 | if (inode && unlikely(dentry->d_flags & DCACHE_OP_SELECT_INODE)) | ||
574 | inode = dentry->d_op->d_select_inode(dentry, open_flags); | ||
575 | |||
576 | return inode; | ||
577 | } | ||
578 | |||
579 | /** | 567 | /** |
580 | * d_real_inode - Return the real inode | 568 | * d_real_inode - Return the real inode |
581 | * @dentry: The dentry to query | 569 | * @dentry: The dentry to query |
@@ -585,7 +573,7 @@ static inline struct inode *vfs_select_inode(struct dentry *dentry, | |||
585 | */ | 573 | */ |
586 | static inline struct inode *d_real_inode(struct dentry *dentry) | 574 | static inline struct inode *d_real_inode(struct dentry *dentry) |
587 | { | 575 | { |
588 | return d_backing_inode(d_real(dentry)); | 576 | return d_backing_inode(d_real(dentry, NULL, 0)); |
589 | } | 577 | } |
590 | 578 | ||
591 | 579 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index dd288148a6b1..bacc0733663c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1272,12 +1272,7 @@ static inline struct inode *file_inode(const struct file *f) | |||
1272 | 1272 | ||
1273 | static inline struct dentry *file_dentry(const struct file *file) | 1273 | static inline struct dentry *file_dentry(const struct file *file) |
1274 | { | 1274 | { |
1275 | struct dentry *dentry = file->f_path.dentry; | 1275 | return d_real(file->f_path.dentry, file_inode(file), 0); |
1276 | |||
1277 | if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) | ||
1278 | return dentry->d_op->d_real(dentry, file_inode(file)); | ||
1279 | else | ||
1280 | return dentry; | ||
1281 | } | 1276 | } |
1282 | 1277 | ||
1283 | static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) | 1278 | static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) |