Skip to content

Commit eeb4661

Browse files
committed
Persist z_seq across znode eviction
Commit 312bdab advertises STATX_ATTR_CHANGE_MONOTONIC and builds the NFSv4 change_cookie from (ctime.tv_sec << 32) | zp->z_seq. zp->z_seq is reset to a magic constant in zfs_znode_alloc(), so any event that drops the znode from cache (memory pressure, remount, reboot) leaves the cookie with the same ctime.tv_sec upper bits but a regressed z_seq in the lower bits, a backward step within the same second. NFSv4 clients that trust this contract treat a regressed cookie as evidence that the file's metadata cannot be relied on. VMware ESXi over NFSv4.1 surfaces this as "The file specified is not a virtual disk", and a VM stored on the affected NFS-exported ZFS dataset fails to power on. Persist z_seq via a new SA attribute SA_ZPL_SEQ. A new pflag bit ZFS_HAS_SEQ marks the file as carrying SA_ZPL_SEQ in its layout, mirroring the ZPL_PROJID/ZFS_PROJID pattern. The bit controls may_grow at SA tx-hold sites: B_TRUE on the first add per file, B_FALSE thereafter. A ZFS_PERSIST_SEQ() macro flips the bit and adds SEQ to the caller's bulk in one step, persisting both atomically alongside the file's other SA attributes. zfs_znode_alloc() restores z_seq from SA_ZPL_SEQ when ZFS_HAS_SEQ is set, treating a lookup failure on a file with the bit set as a fatal load error, matching ZFS_PROJID behavior. No on-disk format change requiring a feature flag is needed. Older binaries preserve the new attribute and pflag bit opaquely. The first modify by a patched binary lazily migrates each file. Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
1 parent 1576195 commit eeb4661

8 files changed

Lines changed: 127 additions & 40 deletions

File tree

include/sys/zfs_sa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ typedef enum zpl_attr {
7676
ZPL_DACL_ACES,
7777
ZPL_DXATTR,
7878
ZPL_PROJID,
79+
ZPL_SEQ,
7980
ZPL_END
8081
} zpl_attr_t;
8182

include/sys/zfs_znode.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ extern "C" {
8989
#define ZFS_ACL_AUTO_INHERIT 0x40 /* ACL should be inherited */
9090
#define ZFS_BONUS_SCANSTAMP 0x80 /* Scanstamp in bonus area */
9191
#define ZFS_NO_EXECS_DENIED 0x100 /* exec was given to everyone */
92+
#define ZFS_HAS_SEQ 0x200 /* SA_ZPL_SEQ in layout */
9293

9394
#define SA_ZPL_ATIME(z) z->z_attr_table[ZPL_ATIME]
9495
#define SA_ZPL_MTIME(z) z->z_attr_table[ZPL_MTIME]
@@ -112,6 +113,24 @@ extern "C" {
112113
#define SA_ZPL_DXATTR(z) z->z_attr_table[ZPL_DXATTR]
113114
#define SA_ZPL_PAD(z) z->z_attr_table[ZPL_PAD]
114115
#define SA_ZPL_PROJID(z) z->z_attr_table[ZPL_PROJID]
116+
#define SA_ZPL_SEQ(z) z->z_attr_table[ZPL_SEQ]
117+
118+
/*
119+
* Persist zp->z_seq into the SA bulk and mark the file as carrying
120+
* SA_ZPL_SEQ in its layout. No-op for legacy (non-SA-native) znodes
121+
* since SA_ZPL_SEQ cannot be added to their layout. Caller's bulk MUST
122+
* include SA_ZPL_FLAGS so the ZFS_HAS_SEQ bit reaches disk in the same
123+
* transaction.
124+
*/
125+
#define ZFS_PERSIST_SEQ(zp, bulk, count, seqp) \
126+
{ \
127+
if ((zp)->z_is_sa) { \
128+
*(seqp) = (zp)->z_seq; \
129+
(zp)->z_pflags |= ZFS_HAS_SEQ; \
130+
SA_ADD_BULK_ATTR((bulk), (count), SA_ZPL_SEQ(ZTOZSB(zp)), \
131+
NULL, (seqp), sizeof (uint64_t)); \
132+
} \
133+
}
115134

116135
/*
117136
* Is ID ephemeral?

module/os/linux/zfs/zfs_acl.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,8 +1359,8 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
13591359
dmu_object_type_t otype;
13601360
zfs_acl_locator_cb_t locate = { 0 };
13611361
uint64_t mode;
1362-
sa_bulk_attr_t bulk[5];
1363-
uint64_t ctime[2];
1362+
sa_bulk_attr_t bulk[6];
1363+
uint64_t ctime[2], change_seq;
13641364
int count = 0;
13651365
zfs_acl_phys_t acl_phys;
13661366

@@ -1501,6 +1501,7 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
15011501
zp->z_pflags |= ZFS_ACL_TRIVIAL;
15021502

15031503
zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime);
1504+
ZFS_PERSIST_SEQ(zp, bulk, count, &change_seq);
15041505
return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
15051506
}
15061507

module/os/linux/zfs/zfs_dir.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -617,9 +617,11 @@ zfs_purgedir(znode_t *dzp)
617617
S_ISLNK(ZTOI(xzp)->i_mode));
618618

619619
tx = dmu_tx_create(zfsvfs->z_os);
620-
dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
620+
dmu_tx_hold_sa(tx, dzp->z_sa_hdl,
621+
(dzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
621622
dmu_tx_hold_zap(tx, dzp->z_id, FALSE, zap->za_name);
622-
dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
623+
dmu_tx_hold_sa(tx, xzp->z_sa_hdl,
624+
(xzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
623625
dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
624626
/* Is this really needed ? */
625627
zfs_sa_upgrade_txholds(tx, xzp);
@@ -809,8 +811,8 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
809811
zfsvfs_t *zfsvfs = ZTOZSB(zp);
810812
uint64_t value;
811813
int zp_is_dir = S_ISDIR(ZTOI(zp)->i_mode);
812-
sa_bulk_attr_t bulk[5];
813-
uint64_t mtime[2], ctime[2];
814+
sa_bulk_attr_t bulk[6];
815+
uint64_t mtime[2], ctime[2], change_seq;
814816
uint64_t links;
815817
int count = 0;
816818
int error;
@@ -871,6 +873,7 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
871873
ctime, sizeof (ctime));
872874
zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime,
873875
ctime);
876+
ZFS_PERSIST_SEQ(zp, bulk, count, &change_seq);
874877
}
875878
error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
876879
ASSERT0(error);
@@ -894,6 +897,7 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
894897
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
895898
&dzp->z_pflags, sizeof (dzp->z_pflags));
896899
zfs_tstamp_update_setup(dzp, CONTENT_MODIFIED, mtime, ctime);
900+
ZFS_PERSIST_SEQ(dzp, bulk, count, &change_seq);
897901
error = sa_bulk_update(dzp->z_sa_hdl, bulk, count, tx);
898902
ASSERT0(error);
899903
mutex_exit(&dzp->z_lock);
@@ -955,8 +959,8 @@ zfs_drop_nlink_locked(znode_t *zp, dmu_tx_t *tx, boolean_t *unlinkedp)
955959
zfsvfs_t *zfsvfs = ZTOZSB(zp);
956960
int zp_is_dir = S_ISDIR(ZTOI(zp)->i_mode);
957961
boolean_t unlinked = B_FALSE;
958-
sa_bulk_attr_t bulk[3];
959-
uint64_t mtime[2], ctime[2];
962+
sa_bulk_attr_t bulk[4];
963+
uint64_t mtime[2], ctime[2], change_seq;
960964
uint64_t links;
961965
int count = 0;
962966
int error;
@@ -982,6 +986,7 @@ zfs_drop_nlink_locked(znode_t *zp, dmu_tx_t *tx, boolean_t *unlinkedp)
982986
NULL, &zp->z_pflags, sizeof (zp->z_pflags));
983987
zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime,
984988
ctime);
989+
ZFS_PERSIST_SEQ(zp, bulk, count, &change_seq);
985990
}
986991
links = ZTOI(zp)->i_nlink;
987992
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zfsvfs),
@@ -1032,8 +1037,8 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
10321037
zfsvfs_t *zfsvfs = ZTOZSB(dzp);
10331038
int zp_is_dir = S_ISDIR(ZTOI(zp)->i_mode);
10341039
boolean_t unlinked = B_FALSE;
1035-
sa_bulk_attr_t bulk[5];
1036-
uint64_t mtime[2], ctime[2];
1040+
sa_bulk_attr_t bulk[6];
1041+
uint64_t mtime[2], ctime[2], change_seq;
10371042
uint64_t links;
10381043
int count = 0;
10391044
int error;
@@ -1083,6 +1088,7 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
10831088
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs),
10841089
NULL, &dzp->z_pflags, sizeof (dzp->z_pflags));
10851090
zfs_tstamp_update_setup(dzp, CONTENT_MODIFIED, mtime, ctime);
1091+
ZFS_PERSIST_SEQ(dzp, bulk, count, &change_seq);
10861092
error = sa_bulk_update(dzp->z_sa_hdl, bulk, count, tx);
10871093
ASSERT0(error);
10881094
mutex_exit(&dzp->z_lock);

module/os/linux/zfs/zfs_vnops_os.c

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,8 @@ zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl,
732732
if (fuid_dirtied)
733733
zfs_fuid_txhold(zfsvfs, tx);
734734
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
735-
dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
735+
dmu_tx_hold_sa(tx, dzp->z_sa_hdl,
736+
(dzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
736737
if (!zfsvfs->z_use_sa &&
737738
acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) {
738739
dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
@@ -1063,7 +1064,10 @@ zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags)
10631064
obj = zp->z_id;
10641065
tx = dmu_tx_create(zfsvfs->z_os);
10651066
dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name);
1066-
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
1067+
dmu_tx_hold_sa(tx, zp->z_sa_hdl,
1068+
(zp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
1069+
dmu_tx_hold_sa(tx, dzp->z_sa_hdl,
1070+
(dzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
10671071
zfs_sa_upgrade_txholds(tx, zp);
10681072
zfs_sa_upgrade_txholds(tx, dzp);
10691073
if (may_delete_now) {
@@ -1080,7 +1084,8 @@ zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags)
10801084
error = zfs_zget(zfsvfs, xattr_obj, &xzp);
10811085
ASSERT0(error);
10821086
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
1083-
dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
1087+
dmu_tx_hold_sa(tx, xzp->z_sa_hdl,
1088+
(xzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
10841089
}
10851090

10861091
mutex_enter(&zp->z_lock);
@@ -1332,6 +1337,8 @@ zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap, znode_t **zpp,
13321337
tx = dmu_tx_create(zfsvfs->z_os);
13331338
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, dirname);
13341339
dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, FALSE, NULL);
1340+
dmu_tx_hold_sa(tx, dzp->z_sa_hdl,
1341+
(dzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
13351342
fuid_dirtied = zfsvfs->z_fuid_dirty;
13361343
if (fuid_dirtied)
13371344
zfs_fuid_txhold(zfsvfs, tx);
@@ -1484,7 +1491,10 @@ zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd, cred_t *cr,
14841491

14851492
tx = dmu_tx_create(zfsvfs->z_os);
14861493
dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name);
1487-
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
1494+
dmu_tx_hold_sa(tx, zp->z_sa_hdl,
1495+
(zp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
1496+
dmu_tx_hold_sa(tx, dzp->z_sa_hdl,
1497+
(dzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
14881498
dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
14891499
zfs_sa_upgrade_txholds(tx, zp);
14901500
zfs_sa_upgrade_txholds(tx, dzp);
@@ -1947,7 +1957,8 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zidmap_t *mnt_ns)
19471957
boolean_t fuid_dirtied = B_FALSE;
19481958
boolean_t handle_eadir = B_FALSE;
19491959
sa_bulk_attr_t *bulk, *xattr_bulk;
1950-
int count = 0, xattr_count = 0, bulks = 8;
1960+
int count = 0, xattr_count = 0, bulks = 9;
1961+
uint64_t change_seq;
19511962

19521963
if (mask == 0)
19531964
return (0);
@@ -2376,7 +2387,8 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zidmap_t *mnt_ns)
23762387
if (((mask & ATTR_XVATTR) &&
23772388
XVA_ISSET_REQ(xvap, XAT_AV_SCANSTAMP)) ||
23782389
(projid != ZFS_INVALID_PROJID &&
2379-
!(zp->z_pflags & ZFS_PROJID)))
2390+
!(zp->z_pflags & ZFS_PROJID)) ||
2391+
!(zp->z_pflags & ZFS_HAS_SEQ))
23802392
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);
23812393
else
23822394
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
@@ -2598,6 +2610,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zidmap_t *mnt_ns)
25982610
*/
25992611
if (!(mask & (ATTR_MODE | ATTR_SIZE)))
26002612
zp->z_seq++;
2613+
ZFS_PERSIST_SEQ(zp, bulk, count, &change_seq);
26012614
}
26022615

26032616
mutex_exit(&zp->z_lock);
@@ -3061,25 +3074,30 @@ zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp, char *tnm,
30613074
}
30623075

30633076
tx = dmu_tx_create(zfsvfs->z_os);
3064-
dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE);
3065-
dmu_tx_hold_sa(tx, sdzp->z_sa_hdl, B_FALSE);
3077+
dmu_tx_hold_sa(tx, szp->z_sa_hdl,
3078+
(szp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
3079+
dmu_tx_hold_sa(tx, sdzp->z_sa_hdl,
3080+
(sdzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
30663081
dmu_tx_hold_zap(tx, sdzp->z_id,
30673082
(rflags & RENAME_EXCHANGE) ? TRUE : FALSE, snm);
30683083
dmu_tx_hold_zap(tx, tdzp->z_id, TRUE, tnm);
30693084
if (sdzp != tdzp) {
3070-
dmu_tx_hold_sa(tx, tdzp->z_sa_hdl, B_FALSE);
3085+
dmu_tx_hold_sa(tx, tdzp->z_sa_hdl,
3086+
(tdzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
30713087
zfs_sa_upgrade_txholds(tx, tdzp);
30723088
}
30733089
if (tzp) {
3074-
dmu_tx_hold_sa(tx, tzp->z_sa_hdl, B_FALSE);
3090+
dmu_tx_hold_sa(tx, tzp->z_sa_hdl,
3091+
(tzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
30753092
zfs_sa_upgrade_txholds(tx, tzp);
30763093
}
30773094
if (rflags & RENAME_WHITEOUT) {
30783095
dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
30793096
ZFS_SA_BASE_ATTR_SIZE);
30803097

30813098
dmu_tx_hold_zap(tx, sdzp->z_id, TRUE, snm);
3082-
dmu_tx_hold_sa(tx, sdzp->z_sa_hdl, B_FALSE);
3099+
dmu_tx_hold_sa(tx, sdzp->z_sa_hdl,
3100+
(sdzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
30833101
if (!zfsvfs->z_use_sa &&
30843102
acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) {
30853103
dmu_tx_hold_write(tx, DMU_NEW_OBJECT,
@@ -3380,7 +3398,8 @@ zfs_symlink(znode_t *dzp, char *name, vattr_t *vap, char *link,
33803398
dmu_tx_hold_zap(tx, dzp->z_id, TRUE, name);
33813399
dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
33823400
ZFS_SA_BASE_ATTR_SIZE + len);
3383-
dmu_tx_hold_sa(tx, dzp->z_sa_hdl, B_FALSE);
3401+
dmu_tx_hold_sa(tx, dzp->z_sa_hdl,
3402+
(dzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
33843403
if (!zfsvfs->z_use_sa && acl_ids.z_aclp->z_acl_bytes > ZFS_ACE_SPACE) {
33853404
dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0,
33863405
acl_ids.z_aclp->z_acl_bytes);
@@ -3632,7 +3651,10 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr,
36323651
}
36333652

36343653
tx = dmu_tx_create(zfsvfs->z_os);
3635-
dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE);
3654+
dmu_tx_hold_sa(tx, szp->z_sa_hdl,
3655+
(szp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
3656+
dmu_tx_hold_sa(tx, tdzp->z_sa_hdl,
3657+
(tdzp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
36363658
dmu_tx_hold_zap(tx, tdzp->z_id, TRUE, name);
36373659
if (is_tmpfile)
36383660
dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL);
@@ -3771,8 +3793,9 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
37713793
caddr_t va;
37723794
int err = 0;
37733795
uint64_t mtime[2], ctime[2];
3796+
uint64_t change_seq;
37743797
inode_timespec_t tmp_ts;
3775-
sa_bulk_attr_t bulk[3];
3798+
sa_bulk_attr_t bulk[4];
37763799
int cnt = 0;
37773800
struct address_space *mapping;
37783801

@@ -3889,7 +3912,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
38893912

38903913
tx = dmu_tx_create(zfsvfs->z_os);
38913914
dmu_tx_hold_write(tx, zp->z_id, pgoff, pglen);
3892-
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
3915+
dmu_tx_hold_sa(tx, zp->z_sa_hdl,
3916+
(zp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
38933917
zfs_sa_upgrade_txholds(tx, zp);
38943918

38953919
err = dmu_tx_assign(tx, DMU_TX_WAIT);
@@ -3924,6 +3948,7 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
39243948
ZFS_TIME_ENCODE(&tmp_ts, ctime);
39253949
zp->z_atime_dirty = B_FALSE;
39263950
zp->z_seq++;
3951+
ZFS_PERSIST_SEQ(zp, bulk, cnt, &change_seq);
39273952

39283953
err = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx);
39293954

module/os/linux/zfs/zfs_znode_os.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
521521
uint64_t atime[2], mtime[2], ctime[2], btime[2];
522522
inode_timespec_t tmp_ts;
523523
uint64_t projid = ZFS_DEFAULT_PROJID;
524+
uint64_t change_seq;
524525
sa_bulk_attr_t bulk[12];
525526
int count = 0;
526527

@@ -566,13 +567,19 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
566567
if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0 || tmp_gen == 0 ||
567568
(dmu_objset_projectquota_enabled(zfsvfs->z_os) &&
568569
(zp->z_pflags & ZFS_PROJID) &&
569-
sa_lookup(zp->z_sa_hdl, SA_ZPL_PROJID(zfsvfs), &projid, 8) != 0)) {
570+
sa_lookup(zp->z_sa_hdl, SA_ZPL_PROJID(zfsvfs), &projid, 8) != 0) ||
571+
(zp->z_is_sa && (zp->z_pflags & ZFS_HAS_SEQ) &&
572+
sa_lookup(zp->z_sa_hdl, SA_ZPL_SEQ(zfsvfs),
573+
&change_seq, sizeof (change_seq)) != 0)) {
570574
if (hdl == NULL)
571575
sa_handle_destroy(zp->z_sa_hdl);
572576
zp->z_sa_hdl = NULL;
573577
goto error;
574578
}
575579

580+
if (zp->z_is_sa && (zp->z_pflags & ZFS_HAS_SEQ))
581+
zp->z_seq = (uint_t)change_seq;
582+
576583
zp->z_projid = projid;
577584
zp->z_mode = ip->i_mode = mode;
578585
ip->i_generation = (uint32_t)tmp_gen;
@@ -1753,8 +1760,8 @@ zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
17531760
zfsvfs_t *zfsvfs = ZTOZSB(zp);
17541761
zilog_t *zilog = zfsvfs->z_log;
17551762
uint64_t mode;
1756-
uint64_t mtime[2], ctime[2];
1757-
sa_bulk_attr_t bulk[3];
1763+
uint64_t mtime[2], ctime[2], change_seq;
1764+
sa_bulk_attr_t bulk[4];
17581765
int count = 0;
17591766
int error;
17601767

@@ -1780,7 +1787,8 @@ zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
17801787
goto out;
17811788
log:
17821789
tx = dmu_tx_create(zfsvfs->z_os);
1783-
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
1790+
dmu_tx_hold_sa(tx, zp->z_sa_hdl,
1791+
(zp->z_pflags & ZFS_HAS_SEQ) ? B_FALSE : B_TRUE);
17841792
zfs_sa_upgrade_txholds(tx, zp);
17851793
error = dmu_tx_assign(tx, DMU_TX_WAIT);
17861794
if (error) {
@@ -1793,6 +1801,7 @@ zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
17931801
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs),
17941802
NULL, &zp->z_pflags, 8);
17951803
zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime);
1804+
ZFS_PERSIST_SEQ(zp, bulk, count, &change_seq);
17961805
error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
17971806
ASSERT0(error);
17981807

module/zfs/zfs_sa.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ const sa_attr_reg_t zfs_attr_table[ZPL_END+1] = {
6868
{"ZPL_DACL_ACES", 0, SA_ACL, 0},
6969
{"ZPL_DXATTR", 0, SA_UINT8_ARRAY, 0},
7070
{"ZPL_PROJID", sizeof (uint64_t), SA_UINT64_ARRAY, 0},
71+
{"ZPL_SEQ", sizeof (uint64_t), SA_UINT64_ARRAY, 0},
7172
{NULL, 0, 0, 0}
7273
};
7374

@@ -270,8 +271,8 @@ zfs_sa_set_xattr(znode_t *zp, const char *name, const void *value, size_t vsize)
270271
dmu_tx_abort(tx);
271272
} else {
272273
int count = 0;
273-
sa_bulk_attr_t bulk[2];
274-
uint64_t ctime[2];
274+
sa_bulk_attr_t bulk[4];
275+
uint64_t ctime[2], change_seq;
275276

276277
if (logsaxattr)
277278
zfs_log_setsaxattr(zilog, tx, TX_SETSAXATTR, zp, name,
@@ -282,6 +283,9 @@ zfs_sa_set_xattr(znode_t *zp, const char *name, const void *value, size_t vsize)
282283
NULL, obj, size);
283284
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs),
284285
NULL, &ctime, 16);
286+
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs),
287+
NULL, &zp->z_pflags, 8);
288+
ZFS_PERSIST_SEQ(zp, bulk, count, &change_seq);
285289
VERIFY0(sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
286290

287291
dmu_tx_commit(tx);

0 commit comments

Comments
 (0)