diff options
-rw-r--r-- | module/zfs/zfs_vnops.c | 23 | ||||
-rw-r--r-- | module/zfs/zfs_znode.c | 156 | ||||
-rw-r--r-- | module/zfs/zpl_inode.c | 3 |
3 files changed, 110 insertions, 72 deletions
diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index b4ffd8d2a..3c3d587e8 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -3005,8 +3005,9 @@ top: } - if (mask & ATTR_ATIME) { - ZFS_TIME_ENCODE(&vap->va_atime, atime); + if ((mask & ATTR_ATIME) || zp->z_atime_dirty) { + zp->z_atime_dirty = 0; + ZFS_TIME_ENCODE(&ip->i_atime, atime); SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL, &atime, sizeof (atime)); } @@ -4128,7 +4129,7 @@ zfs_dirty_inode(struct inode *ip, int flags) dmu_tx_t *tx; uint64_t mode, atime[2], mtime[2], ctime[2]; sa_bulk_attr_t bulk[4]; - int error; + int error = 0; int cnt = 0; if (zfs_is_readonly(zsb) || dmu_objset_is_snapshot(zsb->z_os)) @@ -4137,6 +4138,20 @@ zfs_dirty_inode(struct inode *ip, int flags) ZFS_ENTER(zsb); ZFS_VERIFY_ZP(zp); +#ifdef I_DIRTY_TIME + /* + * This is the lazytime semantic indroduced in Linux 4.0 + * This flag will only be called from update_time when lazytime is set. + * (Note, I_DIRTY_SYNC will also set if not lazytime) + * Fortunately mtime and ctime are managed within ZFS itself, so we + * only need to dirty atime. + */ + if (flags == I_DIRTY_TIME) { + zp->z_atime_dirty = 1; + goto out; + } +#endif + tx = dmu_tx_create(zsb->z_os); dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE); @@ -4149,6 +4164,8 @@ zfs_dirty_inode(struct inode *ip, int flags) } mutex_enter(&zp->z_lock); + zp->z_atime_dirty = 0; + SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MODE(zsb), NULL, &mode, 8); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(zsb), NULL, &atime, 16); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(zsb), NULL, &mtime, 16); diff --git a/module/zfs/zfs_znode.c b/module/zfs/zfs_znode.c index f3662e272..39b2ba07a 100644 --- a/module/zfs/zfs_znode.c +++ b/module/zfs/zfs_znode.c @@ -492,6 +492,90 @@ zfs_inode_set_ops(zfs_sb_t *zsb, struct inode *ip) } } +void +zfs_set_inode_flags(znode_t *zp, struct inode *ip) +{ + /* + * Linux and Solaris have different sets of file attributes, so we + * restrict this conversion to the intersection of the two. + */ + + if (zp->z_pflags & ZFS_IMMUTABLE) + ip->i_flags |= S_IMMUTABLE; + else + ip->i_flags &= ~S_IMMUTABLE; + + if (zp->z_pflags & ZFS_APPENDONLY) + ip->i_flags |= S_APPEND; + else + ip->i_flags &= ~S_APPEND; +} + +/* + * Update the embedded inode given the znode. We should work toward + * eliminating this function as soon as possible by removing values + * which are duplicated between the znode and inode. If the generic + * inode has the correct field it should be used, and the ZFS code + * updated to access the inode. This can be done incrementally. + */ +static void +zfs_inode_update_impl(znode_t *zp, boolean_t new) +{ + zfs_sb_t *zsb; + struct inode *ip; + uint32_t blksize; + u_longlong_t i_blocks; + uint64_t atime[2], mtime[2], ctime[2]; + + ASSERT(zp != NULL); + zsb = ZTOZSB(zp); + ip = ZTOI(zp); + + /* Skip .zfs control nodes which do not exist on disk. */ + if (zfsctl_is_node(ip)) + return; + + sa_lookup(zp->z_sa_hdl, SA_ZPL_ATIME(zsb), &atime, 16); + sa_lookup(zp->z_sa_hdl, SA_ZPL_MTIME(zsb), &mtime, 16); + sa_lookup(zp->z_sa_hdl, SA_ZPL_CTIME(zsb), &ctime, 16); + + dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize, &i_blocks); + + spin_lock(&ip->i_lock); + ip->i_generation = zp->z_gen; + ip->i_uid = SUID_TO_KUID(zp->z_uid); + ip->i_gid = SGID_TO_KGID(zp->z_gid); + set_nlink(ip, zp->z_links); + ip->i_mode = zp->z_mode; + zfs_set_inode_flags(zp, ip); + ip->i_blkbits = SPA_MINBLOCKSHIFT; + ip->i_blocks = i_blocks; + + /* + * Only read atime from SA if we are newly created inode (or rezget), + * otherwise i_atime might be dirty. + */ + if (new) + ZFS_TIME_DECODE(&ip->i_atime, atime); + ZFS_TIME_DECODE(&ip->i_mtime, mtime); + ZFS_TIME_DECODE(&ip->i_ctime, ctime); + + i_size_write(ip, zp->z_size); + spin_unlock(&ip->i_lock); +} + +static void +zfs_inode_update_new(znode_t *zp) +{ + zfs_inode_update_impl(zp, B_TRUE); +} + +void +zfs_inode_update(znode_t *zp) +{ + zfs_inode_update_impl(zp, B_FALSE); +} + /* * Construct a znode+inode and initialize. * @@ -567,7 +651,7 @@ zfs_znode_alloc(zfs_sb_t *zsb, dmu_buf_t *db, int blksz, } ip->i_ino = obj; - zfs_inode_update(zp); + zfs_inode_update_new(zp); zfs_inode_set_ops(zsb, ip); /* @@ -594,73 +678,6 @@ error: return (NULL); } -void -zfs_set_inode_flags(znode_t *zp, struct inode *ip) -{ - /* - * Linux and Solaris have different sets of file attributes, so we - * restrict this conversion to the intersection of the two. - */ - - if (zp->z_pflags & ZFS_IMMUTABLE) - ip->i_flags |= S_IMMUTABLE; - else - ip->i_flags &= ~S_IMMUTABLE; - - if (zp->z_pflags & ZFS_APPENDONLY) - ip->i_flags |= S_APPEND; - else - ip->i_flags &= ~S_APPEND; -} - -/* - * Update the embedded inode given the znode. We should work toward - * eliminating this function as soon as possible by removing values - * which are duplicated between the znode and inode. If the generic - * inode has the correct field it should be used, and the ZFS code - * updated to access the inode. This can be done incrementally. - */ -void -zfs_inode_update(znode_t *zp) -{ - zfs_sb_t *zsb; - struct inode *ip; - uint32_t blksize; - u_longlong_t i_blocks; - uint64_t atime[2], mtime[2], ctime[2]; - - ASSERT(zp != NULL); - zsb = ZTOZSB(zp); - ip = ZTOI(zp); - - /* Skip .zfs control nodes which do not exist on disk. */ - if (zfsctl_is_node(ip)) - return; - - sa_lookup(zp->z_sa_hdl, SA_ZPL_ATIME(zsb), &atime, 16); - sa_lookup(zp->z_sa_hdl, SA_ZPL_MTIME(zsb), &mtime, 16); - sa_lookup(zp->z_sa_hdl, SA_ZPL_CTIME(zsb), &ctime, 16); - - dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize, &i_blocks); - - spin_lock(&ip->i_lock); - ip->i_generation = zp->z_gen; - ip->i_uid = SUID_TO_KUID(zp->z_uid); - ip->i_gid = SGID_TO_KGID(zp->z_gid); - set_nlink(ip, zp->z_links); - ip->i_mode = zp->z_mode; - zfs_set_inode_flags(zp, ip); - ip->i_blkbits = SPA_MINBLOCKSHIFT; - ip->i_blocks = i_blocks; - - ZFS_TIME_DECODE(&ip->i_atime, atime); - ZFS_TIME_DECODE(&ip->i_mtime, mtime); - ZFS_TIME_DECODE(&ip->i_ctime, ctime); - - i_size_write(ip, zp->z_size); - spin_unlock(&ip->i_lock); -} - /* * Safely mark an inode dirty. Inodes which are part of a read-only * file system or snapshot may not be dirtied. @@ -1220,7 +1237,8 @@ zfs_rezget(znode_t *zp) zp->z_unlinked = (zp->z_links == 0); zp->z_blksz = doi.doi_data_block_size; - zfs_inode_update(zp); + zp->z_atime_dirty = 0; + zfs_inode_update_new(zp); zfs_znode_hold_exit(zsb, zh); diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c index cbdab7d30..7cf62783f 100644 --- a/module/zfs/zpl_inode.c +++ b/module/zfs/zpl_inode.c @@ -335,6 +335,9 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia) vap->va_mtime = ia->ia_mtime; vap->va_ctime = ia->ia_ctime; + if (vap->va_mask & ATTR_ATIME) + ip->i_atime = ia->ia_atime; + cookie = spl_fstrans_mark(); error = -zfs_setattr(ip, vap, 0, cr); if (!error && (ia->ia_valid & ATTR_MODE)) |