Skip to content

Commit

Permalink
Correct set/get basic for the 4 time members
Browse files Browse the repository at this point in the history
Handle the disable -1, and re-enable -2, support as well
as skipping Write and Change updates when required

Additionally add CTIME/ChangeTime as changeable in
setattr() as it is valid to do so in Windows.

Signed-off-by: Jorgen Lundman <[email protected]>
  • Loading branch information
lundman committed Aug 9, 2023
1 parent 0bbb4e8 commit e9881b3
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 19 deletions.
7 changes: 7 additions & 0 deletions include/os/windows/zfs/sys/zfs_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ extern PDEVICE_OBJECT fsDiskDeviceObject;

#define ZFS_HAVE_FASTIO

#define SKIP_CHANGE_TIME (1ULL << 0)
#define SKIP_WRITE_TIME (1ULL << 1)

// We have to remember "query directory" related items, like index and
// search pattern. This is attached in IRP_MJ_CREATE to fscontext2
#define ZFS_DIRLIST_MAGIC 0x6582feac
Expand All @@ -50,6 +53,10 @@ struct zfs_dirlist {

uint64_t cacheinit;
uint64_t real_file_id;
boolean_t user_set_creation_time;
boolean_t user_set_access_time;
boolean_t user_set_write_time;
boolean_t user_set_change_time;
};

typedef struct zfs_dirlist zfs_dirlist_t;
Expand Down
16 changes: 13 additions & 3 deletions module/os/windows/zfs/zfs_vnops_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -2338,13 +2338,23 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zidmap_t *mnt_ns)
} else if (mask != 0) {
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
&ctime, sizeof (ctime));
zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime, ctime);
/* Windows allow setting ChangeTime */
if (mask & ATTR_CTIME) {
ZFS_TIME_ENCODE(&vap->va_ctime, ctime);
} else {
zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime,
ctime);
}
if (attrzp) {
SA_ADD_BULK_ATTR(xattr_bulk, xattr_count,
SA_ZPL_CTIME(zfsvfs), NULL,
&ctime, sizeof (ctime));
zfs_tstamp_update_setup(attrzp, STATE_CHANGED,
mtime, ctime);
if (mask & ATTR_CTIME) {
ZFS_TIME_ENCODE(&vap->va_ctime, ctime);
} else {
zfs_tstamp_update_setup(attrzp, STATE_CHANGED,
mtime, ctime);
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions module/os/windows/zfs/zfs_vnops_windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -4792,6 +4792,11 @@ fs_write(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
zfs_uio_iovec_init(&uio, &iov, 1, byteOffset.QuadPart, UIO_SYSSPACE,
bufferLength, 0);

if (zccb->user_set_change_time)
uio.uio_extflg |= SKIP_CHANGE_TIME;
if (zccb->user_set_write_time)
uio.uio_extflg |= SKIP_WRITE_TIME;

// dprintf("%s: offset %llx size %lx\n", __func__,
// byteOffset.QuadPart, bufferLength);

Expand Down
105 changes: 91 additions & 14 deletions module/os/windows/zfs/zfs_vnops_windows_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2948,11 +2948,13 @@ set_file_basic_information(PDEVICE_OBJECT DeviceObject, PIRP Irp,
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;

if (IrpSp->FileObject == NULL || IrpSp->FileObject->FsContext == NULL)
if (IrpSp->FileObject == NULL || IrpSp->FileObject->FsContext == NULL ||
IrpSp->FileObject->FsContext == NULL)
return (STATUS_INVALID_PARAMETER);

PFILE_OBJECT FileObject = IrpSp->FileObject;
struct vnode *vp = FileObject->FsContext;
zfs_dirlist_t *zccb = FileObject->FsContext2;
mount_t *zmo = DeviceObject->DeviceExtension;
ULONG NotifyFilter = 0;

Expand All @@ -2971,19 +2973,74 @@ set_file_basic_information(PDEVICE_OBJECT DeviceObject, PIRP Irp,
vattr_t va = { 0 };
uint64_t unixtime[2] = { 0 };
znode_t *zp = VTOZ(vp);
boolean_t changed = FALSE;

if (fbi->FileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
!vnode_isdir(vp)) {
VN_RELE(vp);
return (STATUS_INVALID_PARAMETER);
}

/* Set to -1 to disable updating this time until CLOSE */
if (fbi->CreationTime.QuadPart == -1) {
fbi->CreationTime.QuadPart = 0;
zccb->user_set_creation_time = TRUE;
}
if (fbi->LastAccessTime.QuadPart == -1) {
fbi->LastAccessTime.QuadPart = 0;
zccb->user_set_access_time = TRUE;
}
if (fbi->LastWriteTime.QuadPart == -1) {
fbi->LastWriteTime.QuadPart = 0;
zccb->user_set_write_time = TRUE;
}
if (fbi->ChangeTime.QuadPart == -1) {
fbi->ChangeTime.QuadPart = 0;
zccb->user_set_change_time = TRUE;
}

/* Set to -2 to undo that disable, and update again */
if (fbi->CreationTime.QuadPart == -2) {
fbi->CreationTime.QuadPart = 0;
zccb->user_set_creation_time = FALSE;
}
if (fbi->LastAccessTime.QuadPart == -2) {
fbi->LastAccessTime.QuadPart = 0;
zccb->user_set_access_time = FALSE;
}
if (fbi->LastWriteTime.QuadPart == -2) {
fbi->LastWriteTime.QuadPart = 0;
zccb->user_set_write_time = FALSE;
}
if (fbi->ChangeTime.QuadPart == -2) {
fbi->ChangeTime.QuadPart = 0;
zccb->user_set_change_time = FALSE;
}

/*
* FastFAT will set ChangeTime, AccessTime, LastWrite "times"
* when IRP_CLOSE is received. If one, or all, are set to "-1"
* FastFAT will not change the corresponding values in this
* set_information() call, as well as, not update them
* at IRP_CLOSE. The same skip is applied when values
* are set here (since in FastFAT they would be automatically
* overwritten by IRP_CLOSE).
* ZFS updates most things as we go, so if they are set here
* then closed, those values will remain. But it seems you
* can then issue a IRP_WRITE, which should not update
* the time members, until IRP_CLOSE, or cleared with -2.
*/

// can request that the file system not update .. LastAccessTime,
// LastWriteTime, and ChangeTime .. setting the appropriate members to -1.
// ie, LastAccessTime = -1 -> atime = disabled - not implemented
// LastAccessTime = -2 -> cancel the disable (-1), return to normal.
// a value of "0" means to keep existing value.
if (fbi->ChangeTime.QuadPart > 0) {
TIME_WINDOWS_TO_UNIX(fbi->ChangeTime.QuadPart,
unixtime);
va.va_change_time.tv_sec = unixtime[0];
va.va_change_time.tv_nsec = unixtime[1];
va.va_active |= ATTR_CTIME;
// change time has no notify
changed = TRUE;
}

if (fbi->LastWriteTime.QuadPart > 0) {
TIME_WINDOWS_TO_UNIX(
fbi->LastWriteTime.QuadPart,
Expand All @@ -2992,42 +3049,62 @@ set_file_basic_information(PDEVICE_OBJECT DeviceObject, PIRP Irp,
va.va_modify_time.tv_nsec = unixtime[1];
va.va_active |= ATTR_MTIME;
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
changed = TRUE;
}

if (fbi->CreationTime.QuadPart > 0) {
TIME_WINDOWS_TO_UNIX(fbi->CreationTime.QuadPart,
unixtime);
va.va_create_time.tv_sec = unixtime[0];
va.va_create_time.tv_nsec = unixtime[1];
va.va_active |= ATTR_CRTIME; // ATTR_CRTIME
NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
changed = TRUE;
}

if (fbi->LastAccessTime.QuadPart > 0) {
TIME_WINDOWS_TO_UNIX(
fbi->LastAccessTime.QuadPart,
zp->z_atime);
NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
changed = TRUE;
}
if (fbi->FileAttributes)

if (fbi->FileAttributes != 0) {

if (!zccb->user_set_change_time) {
gethrestime(&va.va_change_time);
va.va_active |= ATTR_CTIME;
}

fbi->FileAttributes &= ~FILE_ATTRIBUTE_NORMAL;

if (zfs_setwinflags(VTOZ(vp),
fbi->FileAttributes)) {
va.va_active |= ATTR_MODE;
NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
}
Status = zfs_setattr(zp, &va, 0, NULL, NULL);
changed = TRUE;
}

if (changed) {
Status = zfs_setattr(zp, &va, 0, NULL, NULL);

// zfs_setattr will turn ARCHIVE back on, when perhaps
// it is set off by this call
if (fbi->FileAttributes)
zfs_setwinflags(zp, fbi->FileAttributes);
// zfs_setattr will turn ARCHIVE back on, when perhaps
// it is set off by this call
if (fbi->FileAttributes)
zfs_setwinflags(zp, fbi->FileAttributes);
}

if (NotifyFilter != 0)
if (NotifyFilter != 0) {
zfs_send_notify(zp->z_zfsvfs, zp->z_name_cache,
zp->z_name_offset,
NotifyFilter,
FILE_ACTION_MODIFIED);

}

VN_RELE(vp);
Status = STATUS_SUCCESS;
}

return (Status);
Expand Down
12 changes: 10 additions & 2 deletions module/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,16 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
sa_bulk_attr_t bulk[4];
int count = 0;
uint64_t mtime[2], ctime[2];
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &ctime, 16);

/* Windows addition, skip update of Write and Change if requested */
if (!(uio->uio_extflg & SKIP_WRITE_TIME)) {
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL,
&mtime, 16);
}
if (!(uio->uio_extflg & SKIP_CHANGE_TIME)) {
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL,
&ctime, 16);
}
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zfsvfs), NULL,
&zp->z_size, 8);
SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL,
Expand Down

0 comments on commit e9881b3

Please sign in to comment.