Skip to content

Commit 86db35c

Browse files
snajpabehlendorf
authored andcommitted
Remove zpl_revalidate: fix snapshot rollback
Open files, which aren't present in the snapshot, which is being roll-backed to, need to disappear from the visible VFS image of the dataset. Kernel provides d_drop function to drop invalid entry from the dcache, but inode can be referenced by dentry multiple dentries. The introduced zpl_d_drop_aliases function walks and invalidates all aliases of an inode. Reviewed-by: Ryan Moeller <[email protected]> Reviewed-by: Alexander Motin <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Pavel Snajdr <[email protected]> Closes #9600 Closes #14070
1 parent e09fdda commit 86db35c

File tree

10 files changed

+59
-56
lines changed

10 files changed

+59
-56
lines changed

config/kernel-dentry-alias.m4

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
dnl #
2+
dnl # 3.18 API change
3+
dnl # Dentry aliases are in d_u struct dentry member
4+
dnl #
5+
AC_DEFUN([ZFS_AC_KERNEL_SRC_DENTRY_ALIAS_D_U], [
6+
ZFS_LINUX_TEST_SRC([dentry_alias_d_u], [
7+
#include <linux/fs.h>
8+
#include <linux/dcache.h>
9+
#include <linux/list.h>
10+
], [
11+
struct inode *inode __attribute__ ((unused)) = NULL;
12+
struct dentry *dentry __attribute__ ((unused)) = NULL;
13+
hlist_for_each_entry(dentry, &inode->i_dentry,
14+
d_u.d_alias) {
15+
d_drop(dentry);
16+
}
17+
])
18+
])
19+
20+
AC_DEFUN([ZFS_AC_KERNEL_DENTRY_ALIAS_D_U], [
21+
AC_MSG_CHECKING([whether dentry aliases are in d_u member])
22+
ZFS_LINUX_TEST_RESULT([dentry_alias_d_u], [
23+
AC_MSG_RESULT(yes)
24+
AC_DEFINE(HAVE_DENTRY_D_U_ALIASES, 1,
25+
[dentry aliases are in d_u member])
26+
],[
27+
AC_MSG_RESULT(no)
28+
])
29+
])
30+

config/kernel.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
9696
ZFS_AC_KERNEL_SRC_SETATTR_PREPARE
9797
ZFS_AC_KERNEL_SRC_INSERT_INODE_LOCKED
9898
ZFS_AC_KERNEL_SRC_DENTRY
99+
ZFS_AC_KERNEL_SRC_DENTRY_ALIAS_D_U
99100
ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE
100101
ZFS_AC_KERNEL_SRC_SECURITY_INODE
101102
ZFS_AC_KERNEL_SRC_FST_MOUNT
@@ -217,6 +218,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
217218
ZFS_AC_KERNEL_SETATTR_PREPARE
218219
ZFS_AC_KERNEL_INSERT_INODE_LOCKED
219220
ZFS_AC_KERNEL_DENTRY
221+
ZFS_AC_KERNEL_DENTRY_ALIAS_D_U
220222
ZFS_AC_KERNEL_TRUNCATE_SETSIZE
221223
ZFS_AC_KERNEL_SECURITY_INODE
222224
ZFS_AC_KERNEL_FST_MOUNT

include/os/linux/kernel/linux/dcache_compat.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,25 @@ d_clear_d_op(struct dentry *dentry)
6161
DCACHE_OP_REVALIDATE | DCACHE_OP_DELETE);
6262
}
6363

64+
/*
65+
* Walk and invalidate all dentry aliases of an inode
66+
* unless it's a mountpoint
67+
*/
68+
static inline void
69+
zpl_d_drop_aliases(struct inode *inode)
70+
{
71+
struct dentry *dentry;
72+
spin_lock(&inode->i_lock);
73+
#ifdef HAVE_DENTRY_D_U_ALIASES
74+
hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
75+
#else
76+
hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
77+
#endif
78+
if (!IS_ROOT(dentry) && !d_mountpoint(dentry) &&
79+
(dentry->d_inode == inode)) {
80+
d_drop(dentry);
81+
}
82+
}
83+
spin_unlock(&inode->i_lock);
84+
}
6485
#endif /* _ZFS_DCACHE_H */

include/os/linux/zfs/sys/trace_acl.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
6464
__field(boolean_t, z_is_sa)
6565
__field(boolean_t, z_is_mapped)
6666
__field(boolean_t, z_is_ctldir)
67-
__field(boolean_t, z_is_stale)
6867

6968
__field(uint32_t, i_uid)
7069
__field(uint32_t, i_gid)
@@ -99,7 +98,6 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
9998
__entry->z_is_sa = zn->z_is_sa;
10099
__entry->z_is_mapped = zn->z_is_mapped;
101100
__entry->z_is_ctldir = zn->z_is_ctldir;
102-
__entry->z_is_stale = zn->z_is_stale;
103101

104102
__entry->i_uid = KUID_TO_SUID(ZTOI(zn)->i_uid);
105103
__entry->i_gid = KGID_TO_SGID(ZTOI(zn)->i_gid);
@@ -121,9 +119,8 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
121119
"zn_prefetch %u blksz %u seq %u "
122120
"mapcnt %llu size %llu pflags %llu "
123121
"sync_cnt %u sync_writes_cnt %u async_writes_cnt %u "
124-
"mode 0x%x is_sa %d is_mapped %d "
125-
"is_ctldir %d is_stale %d inode { "
126-
"uid %u gid %u ino %lu nlink %u size %lli "
122+
"mode 0x%x is_sa %d is_mapped %d is_ctldir %d "
123+
"inode { uid %u gid %u ino %lu nlink %u size %lli "
127124
"blkbits %u bytes %u mode 0x%x generation %x } } "
128125
"ace { type %u flags %u access_mask %u } mask_matched %u",
129126
__entry->z_id, __entry->z_unlinked, __entry->z_atime_dirty,
@@ -132,7 +129,7 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
132129
__entry->z_pflags, __entry->z_sync_cnt,
133130
__entry->z_sync_writes_cnt, __entry->z_async_writes_cnt,
134131
__entry->z_mode, __entry->z_is_sa, __entry->z_is_mapped,
135-
__entry->z_is_ctldir, __entry->z_is_stale, __entry->i_uid,
132+
__entry->z_is_ctldir, __entry->i_uid,
136133
__entry->i_gid, __entry->i_ino, __entry->i_nlink,
137134
__entry->i_size, __entry->i_blkbits,
138135
__entry->i_bytes, __entry->i_mode, __entry->i_generation,

include/os/linux/zfs/sys/zpl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ extern const struct inode_operations zpl_inode_operations;
4545
extern const struct inode_operations zpl_dir_inode_operations;
4646
extern const struct inode_operations zpl_symlink_inode_operations;
4747
extern const struct inode_operations zpl_special_inode_operations;
48-
extern dentry_operations_t zpl_dentry_operations;
48+
49+
/* zpl_file.c */
4950
extern const struct address_space_operations zpl_address_space_operations;
5051
extern const struct file_operations zpl_file_operations;
5152
extern const struct file_operations zpl_dir_file_operations;

include/sys/zfs_znode.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ typedef struct znode {
190190
boolean_t z_is_sa; /* are we native sa? */
191191
boolean_t z_is_mapped; /* are we mmap'ed */
192192
boolean_t z_is_ctldir; /* are we .zfs entry */
193-
boolean_t z_is_stale; /* are we stale due to rollback? */
194193
boolean_t z_suspended; /* extra ref from a suspend? */
195194
uint_t z_blksz; /* block size in bytes */
196195
uint_t z_seq; /* modification sequence number */

module/os/linux/zfs/zfs_ctldir.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,6 @@ zfsctl_inode_alloc(zfsvfs_t *zfsvfs, uint64_t id,
487487
zp->z_is_sa = B_FALSE;
488488
zp->z_is_mapped = B_FALSE;
489489
zp->z_is_ctldir = B_TRUE;
490-
zp->z_is_stale = B_FALSE;
491490
zp->z_sa_hdl = NULL;
492491
zp->z_blksz = 0;
493492
zp->z_seq = 0;

module/os/linux/zfs/zfs_vfsops.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,7 +1522,6 @@ zfs_domount(struct super_block *sb, zfs_mnt_t *zm, int silent)
15221522
sb->s_op = &zpl_super_operations;
15231523
sb->s_xattr = zpl_xattr_handlers;
15241524
sb->s_export_op = &zpl_export_operations;
1525-
sb->s_d_op = &zpl_dentry_operations;
15261525

15271526
/* Set features for file system. */
15281527
zfs_set_fuid_feature(zfsvfs);
@@ -1881,8 +1880,8 @@ zfs_resume_fs(zfsvfs_t *zfsvfs, dsl_dataset_t *ds)
18811880
zp = list_next(&zfsvfs->z_all_znodes, zp)) {
18821881
err2 = zfs_rezget(zp);
18831882
if (err2) {
1883+
zpl_d_drop_aliases(ZTOI(zp));
18841884
remove_inode_hash(ZTOI(zp));
1885-
zp->z_is_stale = B_TRUE;
18861885
}
18871886

18881887
/* see comment in zfs_suspend_fs() */

module/os/linux/zfs/zfs_znode.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,6 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
552552
zp->z_atime_dirty = B_FALSE;
553553
zp->z_is_mapped = B_FALSE;
554554
zp->z_is_ctldir = B_FALSE;
555-
zp->z_is_stale = B_FALSE;
556555
zp->z_suspended = B_FALSE;
557556
zp->z_sa_hdl = NULL;
558557
zp->z_mapcnt = 0;

module/os/linux/zfs/zpl_inode.c

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -728,46 +728,6 @@ zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
728728
return (error);
729729
}
730730

731-
static int
732-
#ifdef HAVE_D_REVALIDATE_NAMEIDATA
733-
zpl_revalidate(struct dentry *dentry, struct nameidata *nd)
734-
{
735-
unsigned int flags = (nd ? nd->flags : 0);
736-
#else
737-
zpl_revalidate(struct dentry *dentry, unsigned int flags)
738-
{
739-
#endif /* HAVE_D_REVALIDATE_NAMEIDATA */
740-
/* CSTYLED */
741-
zfsvfs_t *zfsvfs = dentry->d_sb->s_fs_info;
742-
int error;
743-
744-
if (flags & LOOKUP_RCU)
745-
return (-ECHILD);
746-
747-
/*
748-
* After a rollback negative dentries created before the rollback
749-
* time must be invalidated. Otherwise they can obscure files which
750-
* are only present in the rolled back dataset.
751-
*/
752-
if (dentry->d_inode == NULL) {
753-
spin_lock(&dentry->d_lock);
754-
error = time_before(dentry->d_time, zfsvfs->z_rollback_time);
755-
spin_unlock(&dentry->d_lock);
756-
757-
if (error)
758-
return (0);
759-
}
760-
761-
/*
762-
* The dentry may reference a stale inode if a mounted file system
763-
* was rolled back to a point in time where the object didn't exist.
764-
*/
765-
if (dentry->d_inode && ITOZ(dentry->d_inode)->z_is_stale)
766-
return (0);
767-
768-
return (1);
769-
}
770-
771731
const struct inode_operations zpl_inode_operations = {
772732
.setattr = zpl_setattr,
773733
.getattr = zpl_getattr,
@@ -856,7 +816,3 @@ const struct inode_operations zpl_special_inode_operations = {
856816
.get_acl = zpl_get_acl,
857817
#endif /* CONFIG_FS_POSIX_ACL */
858818
};
859-
860-
dentry_operations_t zpl_dentry_operations = {
861-
.d_revalidate = zpl_revalidate,
862-
};

0 commit comments

Comments
 (0)