diff --git a/.gitignore b/.gitignore index bb01378c..6579e59f 100644 --- a/.gitignore +++ b/.gitignore @@ -246,4 +246,3 @@ ModelManifest.xml .fake/ *.am - diff --git a/ZFSin.sln b/ZFSin.sln index 6258646e..ef1101e8 100644 --- a/ZFSin.sln +++ b/ZFSin.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27004.2005 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30204.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZFSin", "ZFSin\ZFSin.vcxproj", "{9AFC9A86-1D07-49E1-9296-F7A3979B751D}" EndProject @@ -95,7 +95,6 @@ Global {9AFC9A86-1D07-49E1-9296-F7A3979B751D}.Debug|ARM64.Deploy.0 = Debug|ARM64 {9AFC9A86-1D07-49E1-9296-F7A3979B751D}.Debug|x64.ActiveCfg = Debug|x64 {9AFC9A86-1D07-49E1-9296-F7A3979B751D}.Debug|x64.Build.0 = Debug|x64 - {9AFC9A86-1D07-49E1-9296-F7A3979B751D}.Debug|x64.Deploy.0 = Debug|x64 {9AFC9A86-1D07-49E1-9296-F7A3979B751D}.Debug|x86.ActiveCfg = Debug|Win32 {9AFC9A86-1D07-49E1-9296-F7A3979B751D}.Debug|x86.Build.0 = Debug|Win32 {9AFC9A86-1D07-49E1-9296-F7A3979B751D}.Debug|x86.Deploy.0 = Debug|Win32 diff --git a/ZFSin/ZFSin.vcxproj b/ZFSin/ZFSin.vcxproj index 61fc6c6f..1b7939fa 100644 --- a/ZFSin/ZFSin.vcxproj +++ b/ZFSin/ZFSin.vcxproj @@ -458,6 +458,7 @@ + @@ -643,6 +644,7 @@ + @@ -699,4 +701,4 @@ - \ No newline at end of file + diff --git a/ZFSin/zfs/cmd/zdb/zdb.c b/ZFSin/zfs/cmd/zdb/zdb.c index 65e20b90..e3d63e9d 100644 --- a/ZFSin/zfs/cmd/zdb/zdb.c +++ b/ZFSin/zfs/cmd/zdb/zdb.c @@ -2463,7 +2463,7 @@ static void dump_cachefile(const char *cachefile) { int fd; - struct stat statbuf; + struct _stat64 statbuf; char *buf; nvlist_t *config; @@ -2908,7 +2908,7 @@ dump_label(const char *dev) int fd; label_t labels[VDEV_LABELS]; char path[MAXPATHLEN]; - struct stat statbuf; + struct _stat64 statbuf; uint64_t psize, ashift; int l; boolean_t label_found = B_FALSE; diff --git a/ZFSin/zfs/cmd/zpool/zpool/runsdvui.cmd b/ZFSin/zfs/cmd/zpool/zpool/runsdvui.cmd new file mode 100644 index 00000000..6f0c4b32 --- /dev/null +++ b/ZFSin/zfs/cmd/zpool/zpool/runsdvui.cmd @@ -0,0 +1,2 @@ +cd /d "C:\zfs\ZFSin\zfs\cmd\zpool\zpool" &msbuild "zpool.vcxproj" /t:sdvViewer /p:configuration="Debug" /p:platform="x64" /p:SolutionDir="C:\zfs" +exit %errorlevel% \ No newline at end of file diff --git a/ZFSin/zfs/cmd/zpool/zpool_vdev.c b/ZFSin/zfs/cmd/zpool/zpool_vdev.c index ecd612cf..82940d3a 100644 --- a/ZFSin/zfs/cmd/zpool/zpool_vdev.c +++ b/ZFSin/zfs/cmd/zpool/zpool_vdev.c @@ -1477,7 +1477,7 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv) char vdev_path[MAX_PATH]; sprintf(vdev_path, "/dev/physicaldrive%lu", deviceNumber.DeviceNumber); - + /* * Update the path to refer to the partition. The presence of * the 'whole_disk' field indicates to the CLI that we should diff --git a/ZFSin/zfs/include/sys/fs/zfs.h b/ZFSin/zfs/include/sys/fs/zfs.h index edbd3f41..4cc467e6 100644 --- a/ZFSin/zfs/include/sys/fs/zfs.h +++ b/ZFSin/zfs/include/sys/fs/zfs.h @@ -805,7 +805,7 @@ typedef struct zpool_load_policy { * The location of the pool configuration repository, shared between kernel and * userland. */ -#define ZPOOL_CACHE "/etc/zfs/zpool.cache" +#define ZPOOL_CACHE "\\SystemRoot\\System32\\drivers\\zpool.cache" /* * vdev states are ordered from least to most healthy. diff --git a/ZFSin/zfs/include/sys/spa.h b/ZFSin/zfs/include/sys/spa.h index 7738112c..e12416aa 100644 --- a/ZFSin/zfs/include/sys/spa.h +++ b/ZFSin/zfs/include/sys/spa.h @@ -775,6 +775,12 @@ typedef enum { SPA_AUTOTRIM_ON } spa_autotrim_t; +typedef enum spa_mode { + SPA_MODE_UNINIT = 0, + SPA_MODE_READ = 1, + SPA_MODE_WRITE = 2, +} spa_mode_t; + /* * Reason TRIM command was issued, used internally for accounting purposes. */ diff --git a/ZFSin/zfs/include/sys/vdev_file.h b/ZFSin/zfs/include/sys/vdev_file.h index 7988cb41..2287053a 100644 --- a/ZFSin/zfs/include/sys/vdev_file.h +++ b/ZFSin/zfs/include/sys/vdev_file.h @@ -28,6 +28,7 @@ #define _SYS_VDEV_FILE_H #include +#include #ifdef __cplusplus extern "C" { @@ -42,6 +43,11 @@ extern "C" { } vdev_file_t; #endif +typedef struct vdev_file2 { + HANDLE vf_file; +} vdev_file_t2; + + #ifdef __cplusplus } #endif diff --git a/ZFSin/zfs/include/sys/zfs_file.h b/ZFSin/zfs/include/sys/zfs_file.h new file mode 100644 index 00000000..00546322 --- /dev/null +++ b/ZFSin/zfs/include/sys/zfs_file.h @@ -0,0 +1,58 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#ifndef _SYS_ZFS_FILE_H +#define _SYS_ZFS_FILE_H + +typedef HANDLE zfs_file_t; + +typedef struct zfs_file_attr { + ULONGLONG zfa_size; + DWORD zfa_type; +} zfs_file_attr_t; + +int zfs_file_open(const char *path, int flags, int mode, zfs_file_t *fp); +void zfs_file_close(zfs_file_t *fp); +int zfs_file_write(zfs_file_t *fp, const void *buf, size_t len, ssize_t *resid); +int zfs_file_getattr(zfs_file_t* fp, zfs_file_attr_t* zfattr); +int zfs_file_read(zfs_file_t *fp, void *buf, size_t len, ssize_t *resid); +int zfs_file_geomtery(zfs_file_t* hFile, zfs_file_attr_t* zattr); +int zfs_file_pread(zfs_file_t* hFile, void* buf, DWORD dwBytesToRead, DWORD* resid, DWORD offset); +//int zfs_file_pwrite(zfs_file_t *fp, const void *buf, size_t len, loff_t off, +// ssize_t *resid); +//int zfs_file_read(zfs_file_t *fp, void *buf, size_t len, ssize_t *resid); +//int zfs_file_pread(zfs_file_t *fp, void *buf, size_t len, loff_t off, +// ssize_t *resid); + +/* +int zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence); +int zfs_file_getattr(zfs_file_t *fp, zfs_file_attr_t *zfattr); +int zfs_file_fsync(zfs_file_t *fp, int flags); +int zfs_file_fallocate(zfs_file_t *fp, int mode, loff_t offset, loff_t len); +loff_t zfs_file_off(zfs_file_t *fp); +int zfs_file_unlink(const char *); + +int zfs_file_get(int fd, zfs_file_t **fp); +void zfs_file_put(int fd); +void *zfs_file_private(zfs_file_t *fp); +*/ + +#endif /* _SYS_ZFS_FILE_H */ diff --git a/ZFSin/zfs/lib/libspl/include/umem.h b/ZFSin/zfs/lib/libspl/include/umem.h index 7c552213..681e5a5d 100644 --- a/ZFSin/zfs/lib/libspl/include/umem.h +++ b/ZFSin/zfs/lib/libspl/include/umem.h @@ -132,6 +132,12 @@ umem_free(void *ptr, size_t size) free(ptr); } +static inline void +umem_free_align(void* ptr, size_t size) +{ + _aligned_free(ptr); +} + static inline void umem_nofail_callback(umem_nofail_callback_t *cb) {} @@ -189,8 +195,12 @@ umem_cache_free(umem_cache_t *cp, void *ptr) { if (cp->cache_destructor) cp->cache_destructor(ptr, cp->cache_private); - - umem_free(ptr, cp->cache_bufsize); + if (cp->cache_align != 0) + { + umem_free_align(ptr, cp->cache_bufsize); + } + else + umem_free(ptr, cp->cache_bufsize); } static inline void diff --git a/ZFSin/zfs/lib/libspl/include/wosix.h b/ZFSin/zfs/lib/libspl/include/wosix.h index 3832a74b..34e56cfe 100644 --- a/ZFSin/zfs/lib/libspl/include/wosix.h +++ b/ZFSin/zfs/lib/libspl/include/wosix.h @@ -96,8 +96,12 @@ extern FILE *wosix_fdopen(int fildes, const char *mode); #define pwrite64 wosix_pwrite #undef fstat #define fstat wosix_fstat +#undef _fstat64 +#define _fstat64 wosix_fstat #undef fstat_blk #define fstat_blk wosix_fstat_blk +#undef stat +#define stat wosix_stat #undef fdatasync #define fdatasync wosix_fdatasync #undef ftruncate @@ -109,4 +113,4 @@ extern FILE *wosix_fdopen(int fildes, const char *mode); #undef pipe #define pipe wosix_pipe -#endif /* WOSIX_HEADER */ \ No newline at end of file +#endif /* WOSIX_HEADER */ diff --git a/ZFSin/zfs/lib/libspl/posix.c b/ZFSin/zfs/lib/libspl/posix.c index 2406826a..7bbcf002 100644 --- a/ZFSin/zfs/lib/libspl/posix.c +++ b/ZFSin/zfs/lib/libspl/posix.c @@ -1034,6 +1034,16 @@ int wosix_mkdir(const char *path, mode_t mode) return _mkdir(path); } +int wosix_stat(char *path, struct _stat64 *st) +{ + int fd; + + fd = open(path, O_RDONLY); + if (fd == -1) + return -1; + return wosix_fstat(fd, st); +} + // Only fill in what we actually use in ZFS // Mostly used to test for existance, st_mode, st_size // also FIFO and BLK (fixme) diff --git a/ZFSin/zfs/lib/libuuid/gen_uuid.c b/ZFSin/zfs/lib/libuuid/gen_uuid.c index abd0f5fa..0c4a35c7 100644 --- a/ZFSin/zfs/lib/libuuid/gen_uuid.c +++ b/ZFSin/zfs/lib/libuuid/gen_uuid.c @@ -559,7 +559,7 @@ void uuid_generate_random(uuid_t out) */ static int have_random_source(void) { - struct stat s; + struct _stat64 s; return (!stat("/dev/random", &s) || !stat("/dev/urandom", &s)); } diff --git a/ZFSin/zfs/lib/libzpool/kernel.c b/ZFSin/zfs/lib/libzpool/kernel.c index 6f2c84eb..9aa2bf2a 100644 --- a/ZFSin/zfs/lib/libzpool/kernel.c +++ b/ZFSin/zfs/lib/libzpool/kernel.c @@ -52,6 +52,8 @@ #include #endif #include +#include +#include /* * Emulation of kernel services in userland. @@ -771,7 +773,7 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3) if (fd == -1) return (errno); - if (fstat_blk(fd, &st) == -1) { + if (fstat(fd, &st) == -1) { err = errno; close(fd); return (err); @@ -787,8 +789,247 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3) return (0); } +// create a new file if file not exist else open file on the basis of flags +int zfs_file_open(const char *path, int flags, int mode, zfs_file_t *fpp) +{ + wchar_t buf[PATH_MAX]; + UNICODE_STRING uniName; + DWORD desiredAccess = 0; + DWORD dwCreationDisposition; + mbstowcs(buf, path, sizeof(buf)); + if (flags == O_RDONLY) + { + desiredAccess = GENERIC_READ; + dwCreationDisposition = OPEN_EXISTING; + } + + if (flags == O_WRONLY) + { + desiredAccess = GENERIC_READ | GENERIC_WRITE; + dwCreationDisposition = OPEN_ALWAYS | FILE_OVERWRITE_IF; + } + + HANDLE hFile = CreateFileW( + buf, + desiredAccess, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (hFile == INVALID_HANDLE_VALUE) { + return E_FAIL; + } + *fpp = hFile; + return 0; +} + +// read from a file and write to buf update next unread bytes +int zfs_file_read(zfs_file_t* hFile, void* buf, DWORD dwBytesToRead, DWORD* resid) +{ + DWORD dwBytesRead; + HANDLE handle = hFile; + BOOL res = ReadFile( + *hFile, + buf, + dwBytesToRead, + &dwBytesRead, + NULL + ); + if (!res) + { + return E_FAIL; + } + if (resid) + { + *resid = dwBytesToRead - dwBytesRead; + } + else if (dwBytesRead != dwBytesToRead) + { + return E_FAIL; + } + return 0; +} + +int zfs_file_write(zfs_file_t* hFile, void* buf, DWORD dwBytesToWrite, DWORD* resid) +{ + DWORD dwBytesWritten; + BOOL res = WriteFile( + *hFile, + buf, + dwBytesToWrite, + &dwBytesWritten, + NULL + ); + if (!res) + { + return E_FAIL; + } + if (resid) + { + *resid = dwBytesToWrite - dwBytesWritten; + } + else if (dwBytesToWrite != dwBytesWritten) + { + return E_FAIL; + } + return 0; +} +/* + Stateless read -> fp doesn't change with read operation + this func can be used only in case synchronous i/o +*/ +int zfs_file_pread(zfs_file_t* hFile, void* buf, DWORD dwBytesToRead,DWORD* resid,DWORD offset) +{ + DWORD dwBytesRead; + OVERLAPPED ol = { .Offset = offset }; + BOOL res = ReadFile( + *hFile, + buf, + dwBytesToRead, + &dwBytesRead, + &ol + ); + if (!res) + { + return E_FAIL; + } + if (resid) + { + *resid = dwBytesToRead - dwBytesRead; + } + else if (dwBytesToRead != dwBytesRead) + { + return E_FAIL; + } + return 0; +} + +/* + stateless write -> write at a given offset and os internal pointer is not updated +*/ +int zfs_file_pwrite(zfs_file_t* hFile, const void* buf, DWORD dwBytesToWrite, DWORD* resid, DWORD offset) +{ + /* + * To simulate partial disk writes, we split writes into two + * system calls so that the process can be killed in between. + * This is used by ztest to simulate realistic failure modes. + */ + int sectors,split; + sectors = dwBytesToWrite >> SPA_MINBLOCKSHIFT; + split = (sectors > 0 ? rand() % sectors : 0) << SPA_MINBLOCKSHIFT; + DWORD dwBytesWritten; + OVERLAPPED ol = { .Offset = offset }; + BOOL res = WriteFile( + *hFile, + buf, + dwBytesToWrite, + &dwBytesWritten, + &ol + ); + if (res) + { + OVERLAPPED ol2 = { .Offset = offset+split }; + res = WriteFile( + *hFile, + (char*)buf+split, + dwBytesToWrite-split, + &dwBytesWritten, + &ol2 + ); + } + if (!res) + { + return E_FAIL; + } + if (resid) + { + *resid = dwBytesToWrite - dwBytesWritten; + } + else if (dwBytesToWrite != dwBytesWritten) + { + return E_FAIL; + } + return 0; +} +void zfs_file_close(zfs_file_t* hFile) +{ + CloseHandle(*hFile); +} /*ARGSUSED*/ + +DWORD zfs_file_off(zfs_file_t* hFile) // 1 +{ + PLONG lpDistanceToMoveHigh; + return SetFilePointer( + *hFile, + 0L, + &lpDistanceToMoveHigh, // this pointer is used for higher order 32 bits of the signed 64 bit distance to move, if set to NULL this won't be used + FILE_CURRENT + ); +} + +DWORD zfs_file_seek(zfs_file_t* hFile, LONG offset, DWORD dwMoveMethod) +{ + PLONG lpDistanceToMoveHigh; + return SetFilePointer( + *hFile, + offset, + &lpDistanceToMoveHigh, // this pointer is used for higher order 32 bits of the signed 64 bit distance to move + dwMoveMethod // FILE_BEGIN FILE_CURRENT FILE_END + ); +} + +BOOL zfs_file_flush(zfs_file_t* hFile,int flags) +{ + return FlushFileBuffers( + *hFile + ); +} + +int zfs_file_getattr(zfs_file_t *hFile, zfs_file_attr_t *zfattr) +{ + DWORD dwFileSize; + DWORD dwFileType; + LARGE_INTEGER fSize; + if (GetFileSizeEx(*hFile, &fSize)) + { + zfattr->zfa_size = fSize.QuadPart; + } + DWORD err = GetLastError(); + dwFileType = GetFileType(*hFile); + zfattr->zfa_type = dwFileType; + return 0; +} + +int zfs_file_geomtery(zfs_file_t* hFile, zfs_file_attr_t* zattr) +{ + BOOL bResult = FALSE; + DWORD junk = 0; + DISK_GEOMETRY pdg = { 0 }; + bResult = DeviceIoControl( + *hFile, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &pdg, + sizeof(pdg), + &junk, + (LPOVERLAPPED)NULL + ); + if (bResult) + { + ULONGLONG DiskSize = (ULONGLONG)pdg.Cylinders.QuadPart * (ULONGLONG)pdg.TracksPerCylinder * + (ULONGLONG)pdg.SectorsPerTrack * (ULONGLONG)pdg.BytesPerSector; + zattr->zfa_size = DiskSize; + zattr->zfa_type = GetFileType(*hFile); + return 0; + } + return GetLastError(); +} + int vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3, vnode_t *startvp/*, int fd*/) @@ -797,7 +1038,7 @@ vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int ret; ASSERT(startvp == rootdir); - (void) sprintf(realpath, "/%s", path); + (void) sprintf(realpath, "%s", path); /* fd ignored for now, need if want to simulate nbmand support */ ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3); diff --git a/ZFSin/zfs/module/zfs/abd.c b/ZFSin/zfs/module/zfs/abd.c index 8c426c5b..a1fb2280 100644 --- a/ZFSin/zfs/module/zfs/abd.c +++ b/ZFSin/zfs/module/zfs/abd.c @@ -866,7 +866,7 @@ abd_return_buf(abd_t *abd, void *buf, size_t n) mutex_exit(&abd->abd_mutex); ASSERT0(abd_cmp_buf(abd, buf, n)); mutex_enter(&abd->abd_mutex); - zio_buf_free(buf, n); + zio_buf_free(buf, n); // not able to free the buffer } (void) zfs_refcount_remove_many(&abd->abd_children, n, buf); diff --git a/ZFSin/zfs/module/zfs/spa.c b/ZFSin/zfs/module/zfs/spa.c index 8c44fa2a..3051b956 100644 --- a/ZFSin/zfs/module/zfs/spa.c +++ b/ZFSin/zfs/module/zfs/spa.c @@ -2922,7 +2922,7 @@ spa_ld_select_uberblock(spa_t *spa, spa_import_type_t type) /* * Find the best uberblock. */ - vdev_uberblock_load(rvd, ub, &label); + vdev_uberblock_load(rvd, ub, &label); // failing here couldn't find any uberblock /* * If we weren't able to find a single valid uberblock, return failure. diff --git a/ZFSin/zfs/module/zfs/spa_config.c b/ZFSin/zfs/module/zfs/spa_config.c index 26e47c1c..0c0ddd2f 100644 --- a/ZFSin/zfs/module/zfs/spa_config.c +++ b/ZFSin/zfs/module/zfs/spa_config.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef _KERNEL #include #include @@ -86,6 +87,9 @@ spa_config_load(void) char *pathname; struct _buf *file; uint64_t fsize; + zfs_file_t fp; + zfs_file_attr_t zfa; + int err; #ifdef _KERNEL if (zfs_autoimport_disable) @@ -100,22 +104,23 @@ spa_config_load(void) (void) snprintf(pathname, MAXPATHLEN, "%s%s", "", spa_config_path); - file = kobj_open_file(pathname); + err = zfs_file_open("C:\\WINDOWS\\System32\\drivers\\zpool.cache", O_RDONLY, 0, &fp); kmem_free(pathname, MAXPATHLEN); - if (file == (struct _buf *)-1) + if (err) return; - if (kobj_get_filesize(file, &fsize) != 0) + if (zfs_file_getattr(&fp, &zfa)) goto out; + fsize = zfa.zfa_size; buf = kmem_alloc(fsize, KM_SLEEP); /* * Read the nvlist from the file. */ - if (kobj_read_file(file, buf, fsize, 0) < 0) + if (zfs_file_read(&fp, buf, fsize, NULL) < 0) goto out; /* @@ -147,8 +152,7 @@ spa_config_load(void) out: if (buf != NULL) kmem_free(buf, fsize); - - kobj_close_file(file); + zfs_file_close(&fp); } static void @@ -158,10 +162,9 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) char *buf; vnode_t *vp; int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX; -#ifdef __linux__ - int error; -#endif + int err; char *temp; + zfs_file_t fp; /* * If the nvlist is empty (NULL), then remove the old cachefile. @@ -179,15 +182,32 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) * Pack the configuration into a buffer. */ buf = fnvlist_pack(nvl, &buflen); - temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); + //temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP); /* * Write the configuration to disk. We need to do the traditional * 'write to temporary file, sync, move over original' to make sure we * always have a consistent view of the data. */ - (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); + //(void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path); + +#ifdef _KERNEL + err = zfs_file_open(dp->scd_path, oflags, 0644, &fp); + if (err == 0) { + err = zfs_file_write(&fp, buf, buflen, NULL); + zfs_file_close(&fp); + } +#if 0 + if (err == 0) + err = zfs_file_fsync(fp, O_SYNC); + + zfs_file_close(fp); + if (err) + (void) spa_config_remove(dp); +#endif +#endif +#if 0 if (vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0) == 0) { if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL) == 0 && @@ -208,9 +228,9 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl) #else (void) vn_remove(temp, UIO_SYSSPACE, RMFILE); #endif - +#endif fnvlist_pack_free(buf, buflen); - kmem_free(temp, MAXPATHLEN); + //kmem_free(temp, MAXPATHLEN); } /* diff --git a/ZFSin/zfs/module/zfs/vdev.c b/ZFSin/zfs/module/zfs/vdev.c index 688b433d..229fe39c 100644 --- a/ZFSin/zfs/module/zfs/vdev.c +++ b/ZFSin/zfs/module/zfs/vdev.c @@ -894,7 +894,7 @@ vdev_free(vdev_t *vd) vdev_cache_fini(vd); if (vd->vdev_path) - spa_strfree(vd->vdev_path); + //spa_strfree(vd->vdev_path); if (vd->vdev_devid) spa_strfree(vd->vdev_devid); if (vd->vdev_physpath) @@ -1581,8 +1581,7 @@ vdev_set_deflate_ratio(vdev_t *vd) /* * Prepare a virtual device for access. */ -int -vdev_open(vdev_t *vd) +int vdev_open(vdev_t *vd) { spa_t *spa = vd->vdev_spa; int error; @@ -1712,11 +1711,11 @@ vdev_open(vdev_t *vd) /* * Make sure the allocatable size hasn't shrunk too much. */ - if (asize < vd->vdev_min_asize) { - vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN, - VDEV_AUX_BAD_LABEL); - return (SET_ERROR(EINVAL)); - } + //if (asize < vd->vdev_min_asize) { + // vdev_set_state(vd, B_TRUE, VDEV_STATE_CANT_OPEN, + // VDEV_AUX_BAD_LABEL); + // return (SET_ERROR(EINVAL)); + //} if (vd->vdev_asize == 0) { /* @@ -1840,7 +1839,7 @@ vdev_validate(vdev_t *vd) * any further validation. Otherwise, label I/O will fail and we will * overwrite the previous state. */ - if (!vd->vdev_ops->vdev_op_leaf || !vdev_readable(vd)) + if (!vd->vdev_ops->vdev_op_leaf || !vdev_readable(vd)) // vdev is readable therefore returned true return (0); /* diff --git a/ZFSin/zfs/module/zfs/vdev_file.c b/ZFSin/zfs/module/zfs/vdev_file.c index a7bcb07e..2f53dcd2 100644 --- a/ZFSin/zfs/module/zfs/vdev_file.c +++ b/ZFSin/zfs/module/zfs/vdev_file.c @@ -33,6 +33,7 @@ #include #include #include +#include /* * Virtual device vector for files. @@ -58,18 +59,276 @@ vdev_file_rele(vdev_t *vd) extern int VOP_GETATTR(struct vnode *vp, vattr_t *vap, int flags, void *x3, void *x4); #endif +//static int +//vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, +// uint64_t *ashift) +//{ +//#if _KERNEL +// static vattr_t vattr; +// vdev_file_t *vf; +//#endif +// int error = 0; +// +// dprintf("vdev_file_open %p\n", vd->vdev_tsd); +// /* Rotational optimizations only make sense on block devices */ +// vd->vdev_nonrot = B_TRUE; +// +// /* +// * Allow TRIM on file based vdevs. This may not always be supported, +// * since it depends on your kernel version and underlying filesystem +// * type but it is always safe to attempt. +// */ +// vd->vdev_has_trim = B_TRUE; +// +// /* +// * Disable secure TRIM on file based vdevs. There is no way to +// * request this behavior from the underlying filesystem. +// */ +// vd->vdev_has_securetrim = B_FALSE; +// +// /* +// * We must have a pathname, and it must be absolute. +// */ +// if (vd->vdev_path == NULL || (vd->vdev_path[0] != '/' && +// vd->vdev_path[0] != '\\')) { +// vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; +// return (SET_ERROR(EINVAL)); +// } +// +// /* +// * Reopen the device if it's not currently open. Otherwise, +// * just update the physical size of the device. +// */ +//#ifdef _KERNEL +// if (vd->vdev_tsd != NULL) { +// ASSERT(vd->vdev_reopening); +// vf = vd->vdev_tsd; +// goto skip_open; +// } +// +// vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); +//#endif +// +// /* +// * We always open the files from the root of the global zone, even if +// * we're in a local zone. If the user has gotten to this point, the +// * administrator has already decided that the pool should be available +// * to local zone users, so the underlying devices should be as well. +// */ +// ASSERT(vd->vdev_path != NULL && ( +// vd->vdev_path[0] == '/' || vd->vdev_path[0] == '\\')); +// +// /* +// vn_openat(char *pnamep, +// enum uio_seg seg, +// int filemode, +// int createmode, +// struct vnode **vpp, +// enum create crwhy, +// mode_t umask, +// struct vnode *startvp) +// extern int vn_openat(char *pnamep, enum uio_seg seg, int filemode, +// int createmode, struct vnode **vpp, enum create crwhy, +// mode_t umask, struct vnode *startvp); +// */ +// uint8_t *FileName = NULL; +// FileName = vd->vdev_path; +// +// if (!strncmp("\\\\?\\", FileName, 4)) { +// FileName[1] = '?'; +// } +// +// dprintf("%s: opening '%s'\n", __func__, FileName); +// +//#ifdef _KERNEL +// +// ANSI_STRING AnsiFilespec; +// UNICODE_STRING UnicodeFilespec; +// OBJECT_ATTRIBUTES ObjectAttributes; +// +// SHORT UnicodeName[PATH_MAX]; +// CHAR AnsiName[PATH_MAX]; +// USHORT NameLength = 0; +// NTSTATUS ntstatus; +// +// memset(UnicodeName, 0, sizeof(SHORT) * PATH_MAX); +// memset(AnsiName, 0, sizeof(UCHAR) * PATH_MAX); +// +// NameLength = strlen(FileName); +// ASSERT(NameLength < PATH_MAX); +// +// memmove(AnsiName, FileName, NameLength); +// +// AnsiFilespec.MaximumLength = AnsiFilespec.Length = NameLength; +// AnsiFilespec.Buffer = AnsiName; +// +// UnicodeFilespec.MaximumLength = PATH_MAX * 2; +// UnicodeFilespec.Length = 0; +// UnicodeFilespec.Buffer = (PWSTR)UnicodeName; +// +// RtlAnsiStringToUnicodeString(&UnicodeFilespec, &AnsiFilespec, FALSE); +// +// ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); +// ObjectAttributes.RootDirectory = NULL; +// ObjectAttributes.Attributes = /*OBJ_CASE_INSENSITIVE |*/ OBJ_KERNEL_HANDLE; +// ObjectAttributes.ObjectName = &UnicodeFilespec; +// ObjectAttributes.SecurityDescriptor = NULL; +// ObjectAttributes.SecurityQualityOfService = NULL; +// IO_STATUS_BLOCK iostatus; +// +// ntstatus = ZwCreateFile(&vf->vf_handle, +// spa_mode(vd->vdev_spa) == FREAD ? GENERIC_READ | SYNCHRONIZE : GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, +// &ObjectAttributes, +// &iostatus, +// 0, +// FILE_ATTRIBUTE_NORMAL, +// /* FILE_SHARE_WRITE | */ FILE_SHARE_READ, +// FILE_OPEN, +// FILE_SYNCHRONOUS_IO_NONALERT | (spa_mode(vd->vdev_spa) == FREAD ? 0 : FILE_NO_INTERMEDIATE_BUFFERING), +// NULL, +// 0); +// +// if (ntstatus == STATUS_SUCCESS) { +// error = 0; +// } else { +// vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; +// goto failed; +// } +// +// +// /* +// * Make sure it's a regular file. +// */ +// FILE_STANDARD_INFORMATION info; +// IO_STATUS_BLOCK iob; +// +// if ((ZwQueryInformationFile( +// vf->vf_handle, +// &iob, +// &info, +// sizeof(info), +// FileStandardInformation) != STATUS_SUCCESS) || +// (info.Directory != FALSE)) { +// vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; +// ZwClose(vf->vf_handle); +// error = ENOENT; +// goto failed; +// } +// +// // Since we will use DeviceObject and FileObject to do ioctl and IO +// // we grab them now and lock them in place. +// // Convert HANDLE to FileObject +// PFILE_OBJECT FileObject; +// PDEVICE_OBJECT DeviceObject; +// NTSTATUS status; +// +// // This adds a reference to FileObject +// status = ObReferenceObjectByHandle( +// vf->vf_handle, +// 0, +// *IoFileObjectType, +// KernelMode, +// &FileObject, +// NULL +// ); +// if (status != STATUS_SUCCESS) { +// ZwClose(vf->vf_handle); +// vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; +// error = EIO; +// goto failed; +// } +// +// // Convert FileObject to DeviceObject +// DeviceObject = IoGetRelatedDeviceObject(FileObject); +// +// // Grab a reference to DeviceObject +// ObReferenceObject(DeviceObject); +// +// vf->vf_FileObject = FileObject; +// vf->vf_DeviceObject = DeviceObject; +// +// // Change it to SPARSE, so TRIM might work +// status = ZwFsControlFile( +// vf->vf_handle, +// NULL, +// NULL, +// NULL, +// NULL, +// FSCTL_SET_SPARSE, +// NULL, +// 0, +// NULL, +// 0 +// ); +// dprintf("%s: set Sparse 0x%x.\n", __func__, status); +// +//#endif +// +//#if _KERNEL +//skip_open: +// /* +// * Determine the physical size of the file. +// */ +// //vattr.va_mask = AT_SIZE; +// //vn_lock(vf->vf_vnode, LK_SHARED | LK_RETRY); +// //error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL); +// //VN_UNLOCK(vf->vf_vnode); +//#endif +// +//#ifdef _KERNEL +// *max_psize = *psize = info.EndOfFile.QuadPart; +//#else +// /* userland's vn_open() will get the device size for us, so we can +// * just look it up - there is argument for a userland VOP_GETATTR to make +// * this function cleaner. */ +//// *max_psize = *psize = vp->v_size; +//#endif +// *ashift = SPA_MINBLOCKSHIFT; +// +// return (0); +// +//failed: +//#ifdef _KERNEL +// if (vf) { +// if (vf->vf_handle != NULL) { +// vf->vf_handle = NULL; +// } +// +// kmem_free(vf, sizeof(vdev_file_t)); +// vd->vdev_tsd = NULL; +// } +//#endif +// return error; +//} + +static mode_t vdev_file_open_mode(spa_mode_t spa_mode) +{ + mode_t mode = 0; + // TODO :- Add flags + if ((spa_mode & SPA_MODE_READ) && (spa_mode & SPA_MODE_WRITE)) { + mode = O_RDWR; + } + else if (spa_mode & SPA_MODE_READ) { + mode = O_RDONLY; + } + else if (spa_mode & SPA_MODE_WRITE) { + mode = O_WRONLY; + } + return mode; +} + static int -vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, - uint64_t *ashift) +vdev_file_open(vdev_t* vd, uint64_t* psize, uint64_t* max_psize, + uint64_t* ashift) { -#if _KERNEL - static vattr_t vattr; - vdev_file_t *vf; -#endif - int error = 0; + vdev_file_t2* vf; + zfs_file_t fp; + zfs_file_attr_t zfa; + int err; - dprintf("vdev_file_open %p\n", vd->vdev_tsd); - /* Rotational optimizations only make sense on block devices */ + /* + * Rotational optimizations only make sense on block devices. + */ vd->vdev_nonrot = B_TRUE; /* @@ -88,243 +347,97 @@ vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, /* * We must have a pathname, and it must be absolute. */ - if (vd->vdev_path == NULL || (vd->vdev_path[0] != '/' && - vd->vdev_path[0] != '\\')) { + + if (vd->vdev_path == NULL || (vd->vdev_path[0] != '/' && vd->vdev_path[0] != '\\')) { vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; return (SET_ERROR(EINVAL)); } - /* - * Reopen the device if it's not currently open. Otherwise, - * just update the physical size of the device. - */ -#ifdef _KERNEL if (vd->vdev_tsd != NULL) { ASSERT(vd->vdev_reopening); vf = vd->vdev_tsd; goto skip_open; } - vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); -#endif - - /* - * We always open the files from the root of the global zone, even if - * we're in a local zone. If the user has gotten to this point, the - * administrator has already decided that the pool should be available - * to local zone users, so the underlying devices should be as well. - */ + vf = vd->vdev_tsd = kmem_zalloc(sizeof(vdev_file_t2), KM_SLEEP); ASSERT(vd->vdev_path != NULL && ( vd->vdev_path[0] == '/' || vd->vdev_path[0] == '\\')); - /* - vn_openat(char *pnamep, - enum uio_seg seg, - int filemode, - int createmode, - struct vnode **vpp, - enum create crwhy, - mode_t umask, - struct vnode *startvp) - extern int vn_openat(char *pnamep, enum uio_seg seg, int filemode, - int createmode, struct vnode **vpp, enum create crwhy, - mode_t umask, struct vnode *startvp); - */ - uint8_t *FileName = NULL; - FileName = vd->vdev_path; - - if (!strncmp("\\\\?\\", FileName, 4)) { - FileName[1] = '?'; - } - - dprintf("%s: opening '%s'\n", __func__, FileName); - -#ifdef _KERNEL - - ANSI_STRING AnsiFilespec; - UNICODE_STRING UnicodeFilespec; - OBJECT_ATTRIBUTES ObjectAttributes; - - SHORT UnicodeName[PATH_MAX]; - CHAR AnsiName[PATH_MAX]; - USHORT NameLength = 0; - NTSTATUS ntstatus; - - memset(UnicodeName, 0, sizeof(SHORT) * PATH_MAX); - memset(AnsiName, 0, sizeof(UCHAR) * PATH_MAX); - - NameLength = strlen(FileName); - ASSERT(NameLength < PATH_MAX); - - memmove(AnsiName, FileName, NameLength); - - AnsiFilespec.MaximumLength = AnsiFilespec.Length = NameLength; - AnsiFilespec.Buffer = AnsiName; - - UnicodeFilespec.MaximumLength = PATH_MAX * 2; - UnicodeFilespec.Length = 0; - UnicodeFilespec.Buffer = (PWSTR)UnicodeName; - - RtlAnsiStringToUnicodeString(&UnicodeFilespec, &AnsiFilespec, FALSE); - - ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); - ObjectAttributes.RootDirectory = NULL; - ObjectAttributes.Attributes = /*OBJ_CASE_INSENSITIVE |*/ OBJ_KERNEL_HANDLE; - ObjectAttributes.ObjectName = &UnicodeFilespec; - ObjectAttributes.SecurityDescriptor = NULL; - ObjectAttributes.SecurityQualityOfService = NULL; - IO_STATUS_BLOCK iostatus; - - ntstatus = ZwCreateFile(&vf->vf_handle, - spa_mode(vd->vdev_spa) == FREAD ? GENERIC_READ | SYNCHRONIZE : GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, - &ObjectAttributes, - &iostatus, - 0, - FILE_ATTRIBUTE_NORMAL, - /* FILE_SHARE_WRITE | */ FILE_SHARE_READ, - FILE_OPEN, - FILE_SYNCHRONOUS_IO_NONALERT | (spa_mode(vd->vdev_spa) == FREAD ? 0 : FILE_NO_INTERMEDIATE_BUFFERING), - NULL, - 0); - - if (ntstatus == STATUS_SUCCESS) { - error = 0; - } else { - vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; - goto failed; - } - - - /* - * Make sure it's a regular file. - */ - FILE_STANDARD_INFORMATION info; - IO_STATUS_BLOCK iob; - - if ((ZwQueryInformationFile( - vf->vf_handle, - &iob, - &info, - sizeof(info), - FileStandardInformation) != STATUS_SUCCESS) || - (info.Directory != FALSE)) { + vd->vdev_path = "\\\\.\\PhysicalDrive1"; + err = zfs_file_open(vd->vdev_path, vdev_file_open_mode(spa_mode(vd->vdev_spa)), 0, &fp); + if (err) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; - ZwClose(vf->vf_handle); - error = ENOENT; - goto failed; + return (err); } - - // Since we will use DeviceObject and FileObject to do ioctl and IO - // we grab them now and lock them in place. - // Convert HANDLE to FileObject - PFILE_OBJECT FileObject; - PDEVICE_OBJECT DeviceObject; - NTSTATUS status; - - // This adds a reference to FileObject - status = ObReferenceObjectByHandle( - vf->vf_handle, - 0, - *IoFileObjectType, - KernelMode, - &FileObject, - NULL - ); - if (status != STATUS_SUCCESS) { - ZwClose(vf->vf_handle); + vf->vf_file = fp; + + //#ifdef _KERNEL + // /* + // * Make sure it's a regular file. + // */ + // if (zfs_file_getattr(fp, &zfa)) { + // return (SET_ERROR(ENODEV)); + // } + // if (!S_ISREG(zfa.zfa_mode)) { + // vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; + // return (SET_ERROR(ENODEV)); + // } + //#endif +skip_open: +#ifdef _KERNEL + err = zfs_file_getattr(vf->vf_file, &zfa); + if (err) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; - error = EIO; - goto failed; + return (err); } - - // Convert FileObject to DeviceObject - DeviceObject = IoGetRelatedDeviceObject(FileObject); - - // Grab a reference to DeviceObject - ObReferenceObject(DeviceObject); - - vf->vf_FileObject = FileObject; - vf->vf_DeviceObject = DeviceObject; - - // Change it to SPARSE, so TRIM might work - status = ZwFsControlFile( - vf->vf_handle, - NULL, - NULL, - NULL, - NULL, - FSCTL_SET_SPARSE, - NULL, - 0, - NULL, - 0 - ); - dprintf("%s: set Sparse 0x%x.\n", __func__, status); - -#endif - -#if _KERNEL -skip_open: - /* - * Determine the physical size of the file. - */ - //vattr.va_mask = AT_SIZE; - //vn_lock(vf->vf_vnode, LK_SHARED | LK_RETRY); - //error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL); - //VN_UNLOCK(vf->vf_vnode); -#endif - -#ifdef _KERNEL - *max_psize = *psize = info.EndOfFile.QuadPart; #else - /* userland's vn_open() will get the device size for us, so we can - * just look it up - there is argument for a userland VOP_GETATTR to make - * this function cleaner. */ -// *max_psize = *psize = vp->v_size; + err = zfs_file_geomtery(&fp, &zfa); #endif - *ashift = SPA_MINBLOCKSHIFT; - + * max_psize = *psize = zfa.zfa_size; + *ashift = SPA_MINBLOCKSHIFT; return (0); - -failed: -#ifdef _KERNEL - if (vf) { - if (vf->vf_handle != NULL) { - vf->vf_handle = NULL; - } - - kmem_free(vf, sizeof(vdev_file_t)); - vd->vdev_tsd = NULL; - } -#endif - return error; } -static void -vdev_file_close(vdev_t *vd) +//static void +//vdev_file_close(vdev_t *vd) +//{ +//#ifdef _KERNEL +// vdev_file_t *vf = vd->vdev_tsd; +// +// if (vd->vdev_reopening || vf == NULL) +// return; +// +// if (vf->vf_handle != NULL) { +// +// // Release our holds +// ObDereferenceObject(vf->vf_FileObject); +// ObDereferenceObject(vf->vf_DeviceObject); +// +// ZwClose(vf->vf_handle); +// } +// +// vf->vf_FileObject = NULL; +// vf->vf_DeviceObject = NULL; +// vf->vf_handle = NULL; +// vd->vdev_delayed_close = B_FALSE; +// kmem_free(vf, sizeof (vdev_file_t)); +// vd->vdev_tsd = NULL; +//#endif +//} + +static void vdev_file_close(vdev_t* vd) { -#ifdef _KERNEL - vdev_file_t *vf = vd->vdev_tsd; + vdev_file_t2* vf = vd->vdev_tsd; if (vd->vdev_reopening || vf == NULL) return; - if (vf->vf_handle != NULL) { - - // Release our holds - ObDereferenceObject(vf->vf_FileObject); - ObDereferenceObject(vf->vf_DeviceObject); - - ZwClose(vf->vf_handle); + if (vf->vf_file != NULL) { + (void)zfs_file_close(&vf->vf_file); } - - vf->vf_FileObject = NULL; - vf->vf_DeviceObject = NULL; - vf->vf_handle = NULL; vd->vdev_delayed_close = B_FALSE; - kmem_free(vf, sizeof (vdev_file_t)); + kmem_free(vf, sizeof(vdev_file_t2)); vd->vdev_tsd = NULL; -#endif } #ifdef _KERNEL @@ -405,6 +518,7 @@ vdev_file_io_intrxxx(PDEVICE_OBJECT DeviceObject, PIRP irp, PVOID Context) */ _Atomic uint64_t zfs_vdev_file_size_mismatch_cnt = 0; +// clear the changes static void vdev_file_io_start(zio_t *zio) { @@ -464,14 +578,17 @@ vdev_file_io_start(zio_t *zio) ASSERT(zio->io_size != 0); #ifdef _KERNEL - vdev_file_t *vf = vd->vdev_tsd; - + vdev_file_t* vf = vd->vdev_tsd; +#else + vdev_file_t2* vf = vd->vdev_tsd; +#endif // _KERNEL + LARGE_INTEGER offset; + offset.QuadPart = zio->io_offset + vd->vdev_win_offset; +#ifdef _KERNEL PIRP irp = NULL; PIO_STACK_LOCATION irpStack = NULL; IO_STATUS_BLOCK IoStatusBlock = { 0 }; - LARGE_INTEGER offset; - offset.QuadPart = zio->io_offset + vd->vdev_win_offset; /* Preallocate space for IoWorkItem, required for vdev_file_io_start_done callback */ vf_callback_t *vb = (vf_callback_t *)kmem_alloc(sizeof(vf_callback_t) + IoSizeofWorkItem(), KM_SLEEP); @@ -534,6 +651,45 @@ vdev_file_io_start(zio_t *zio) TRUE);// On Cancel IoCallDriver(vf->vf_DeviceObject, irp); +#else + void* data; + int err; + DWORD red; + HANDLE hFile = vf->vf_file; + + if (!SetFilePointerEx(hFile, offset, NULL, FILE_BEGIN)) + goto failed; + + if (zio->io_type == ZIO_TYPE_READ) { + ASSERT3S(zio->io_abd->abd_size, >= , zio->io_size); + //data = + // abd_borrow_buf(zio->io_abd, zio->io_abd->abd_size); + //ok = ReadFile(hFile, data, zio->io_size, &red, NULL); + //abd_return_buf_copy(zio->io_abd, data, zio->io_size); + data = abd_borrow_buf(zio->io_abd, zio->io_abd->abd_size); + //err = ReadFile(hFile, data, zio->io_size, &red, NULL); + err = zfs_file_pread(&hFile, data, zio->io_size, &red, zio->io_offset); + abd_return_buf_copy(zio->io_abd, data, zio->io_size); // see in kernel space what is happening + } + else { + ASSERT3S(zio->io_abd->abd_size, >= , zio->io_size); + data = + abd_borrow_buf_copy(zio->io_abd, zio->io_abd->abd_size); + err = WriteFile(hFile, data, zio->io_size, &red, NULL); + abd_return_buf_off(zio->io_abd, data, + 0, zio->io_size, zio->io_abd->abd_size); + } + +failed: + if (err) + zio->io_error = EIO; + else if (red) + zio->io_error = SET_ERROR(ENOSPC); + else + zio->io_error = 0; + + zio_delay_interrupt(zio); + return; #endif return; diff --git a/ZFSin/zfs/module/zfs/zfs_file.c b/ZFSin/zfs/module/zfs/zfs_file.c new file mode 100644 index 00000000..7248cb7a --- /dev/null +++ b/ZFSin/zfs/module/zfs/zfs_file.c @@ -0,0 +1,576 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#include +#include +#include +#include +//#include +//#include +//#include +#ifdef HAVE_FDTABLE_HEADER +#include +#endif + +/* + * Open file + * + * path - fully qualified path to file + * flags - file attributes O_READ / O_WRITE / O_EXCL + * fpp - pointer to return file pointer + * + * Returns 0 on success underlying error on failure. + */ +int +zfs_file_open(const char *path, int flags, int mode, zfs_file_t *fpp) +{ + vnode_t *vp; + wchar_t buf[PATH_MAX]; + UNICODE_STRING uniName; + OBJECT_ATTRIBUTES objAttr; + HANDLE handle; + NTSTATUS ntstatus; + IO_STATUS_BLOCK ioStatusBlock; + + mbstowcs(buf, path, sizeof (buf)); + RtlInitUnicodeString(&uniName, buf); + InitializeObjectAttributes(&objAttr, &uniName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, NULL); + + if(KeGetCurrentIrql() != PASSIVE_LEVEL) + return -1; + + ntstatus = ZwCreateFile(&handle, + GENERIC_WRITE, + &objAttr, &ioStatusBlock, NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OVERWRITE_IF, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, 0); + + if (ntstatus != STATUS_SUCCESS) { + return -1; + } + + *fpp = handle; + + return 0; +#if 0 + struct file *filp; + int saved_umask; + + if (!(flags & O_CREAT) && (flags & O_WRONLY)) + flags |= O_EXCL; + + if (flags & O_CREAT) + saved_umask = xchg(¤t->fs->umask, 0); + + filp = filp_open(path, flags, mode); + + if (flags & O_CREAT) + (void) xchg(¤t->fs->umask, saved_umask); + + if (IS_ERR(filp)) + return (-PTR_ERR(filp)); + + *fpp = filp; + return (0); +#endif +} + +void +zfs_file_close(zfs_file_t *fp) +{ + ZwClose(*fp); + //filp_close(fp, 0); +} + +// need to implement read,write,pread,pwrite + + + + +#if 0 +static ssize_t +zfs_file_write_impl(zfs_file_t *fp, const void *buf, size_t count, loff_t *off) +{ +#if defined(HAVE_KERNEL_WRITE_PPOS) + return (kernel_write(fp, buf, count, off)); +#else + mm_segment_t saved_fs; + ssize_t rc; + + saved_fs = get_fs(); + set_fs(KERNEL_DS); + + rc = vfs_write(fp, (__force const char __user __user *)buf, count, off); + + set_fs(saved_fs); + + return (rc); +#endif +} +#endif + +/* + * Stateful write - use os internal file pointer to determine where to + * write and update on successful completion. + * + * fp - pointer to file (pipe, socket, etc) to write to + * buf - buffer to write + * count - # of bytes to write + * resid - pointer to count of unwritten bytes (if short write) + * + * Returns 0 on success errno on failure. + */ +int +zfs_file_write(zfs_file_t *fp, const void *buf, size_t count, ssize_t *resid) +{ + NTSTATUS ntstatus; + IO_STATUS_BLOCK ioStatusBlock; + + ntstatus = ZwWriteFile(*fp, NULL, NULL, NULL, + &ioStatusBlock, buf, count, NULL, NULL); + + if (resid) + *resid = 0; + + if (STATUS_SUCCESS != ntstatus) + return (EIO); + return (0); +#if 0 + loff_t off = fp->f_pos; + ssize_t rc; + + rc = zfs_file_write_impl(fp, buf, count, &off); + if (rc < 0) + return (-rc); + + fp->f_pos = off; + + if (resid) { + *resid = count - rc; + } else if (rc != count) { + return (EIO); + } +#endif +} + + + + + +/* + * Stateful read - use os internal file pointer to determine where to + * read and update on successful completion. + * + * fp - pointer to file (pipe, socket, etc) to read from + * buf - buffer to write + * count - # of bytes to read + * resid - pointer to count of unread bytes (if short read) + * + * Returns 0 on success errno on failure. + */ +int zfs_file_read(zfs_file_t* fp, const void* buf, size_t count, ssize_t* resid) +{ + NTSTATUS ntstatus; + IO_STATUS_BLOCK ioStatusBlock; + ntstatus = ZwReadFile(*fp, NULL, NULL, NULL, &ioStatusBlock, buf, count, NULL, NULL); + if (STATUS_SUCCESS != ntstatus) + return (EIO); + if (resid) + { + *resid = 0; + } + return (0); +#if 0 + loff_t off = fp->f_pos; + ssize_t rc; + + rc = zfs_file_read_impl(fp, buf, count, &off); + if (rc < 0) + return (-rc); + + fp->f_pos = off; + + if (resid) { + *resid = count - rc; + } + else if (rc != count) { + return (EIO); + } + + return (0); +#endif +} + +/* + * Stateless write - os internal file pointer is not updated. + * + * fp - pointer to file (pipe, socket, etc) to write to + * buf - buffer to write + * count - # of bytes to write + * off - file offset to write to (only valid for seekable types) + * resid - pointer to count of unwritten bytes + * + * Returns 0 on success errno on failure. + */ +int +zfs_file_pwrite(zfs_file_t* fp, const void* buf, size_t count, loff_t off, + ssize_t* resid) +{ + NTSTATUS ntstatus; + IO_STATUS_BLOCK ioStatusBlock; + LARGE_INTEGER offset = { 0 }; + offset.LowPart = off; + ntstatus = ZwReadFile(fp, NULL, NULL, NULL, &ioStatusBlock, buf, count, &offset, NULL); + // reset fp to its original position + if (STATUS_SUCCESS != ntstatus) + return (EIO); + if (resid) + { + *resid = 0; + } + return (0); +#if 0 + ssize_t rc; + + rc = zfs_file_write_impl(fp, buf, count, &off); + if (rc < 0) + return (-rc); + + if (resid) { + *resid = count - rc; + } + else if (rc != count) { + return (EIO); + } + + return (0); +#endif +} + +/* + * Stateless read - os internal file pointer is not updated. + * + * fp - pointer to file (pipe, socket, etc) to read from + * buf - buffer to write + * count - # of bytes to write + * off - file offset to read from (only valid for seekable types) + * resid - pointer to count of unwritten bytes (if short write) + * + * Returns 0 on success errno on failure. + */ +int +zfs_file_pread(zfs_file_t* fp, void* buf, DWORD count, DWORD* resid, + DWORD off) +{ + NTSTATUS ntstatus; + IO_STATUS_BLOCK ioStatusBlock; + LARGE_INTEGER offset = { 0 }; + offset.LowPart = off; + /*FileInformationClass info; + ZwQueryInformationFile*/ + ntstatus = ZwReadFile(fp, NULL, NULL, NULL, &ioStatusBlock, buf, count, &offset, NULL); + if (STATUS_SUCCESS != ntstatus) + return (EIO); + if (resid) + { + *resid = 0; + } + return (0); +#if 0 + ssize_t rc; + + rc = zfs_file_read_impl(fp, buf, count, &off); + if (rc < 0) + return (-rc); + + if (resid) { + *resid = count - rc; + } + else if (rc != count) { + return (EIO); + } + + return (0); +#endif +} + +/* + * Sync file to disk + * + * filp - file pointer + * flags - O_SYNC and or O_DSYNC + * + * Returns 0 on success or error code of underlying sync call on failure. + */ +int +zfs_file_fsync(zfs_file_t* filp, int flags) +{ + if (KeGetCurrentIrql() != PASSIVE_LEVEL) + return -1; + IO_STATUS_BLOCK ioStatusBlock; + NTSTATUS ntStatus; + ntStatus = ZwFlushBuffersFile( + *filp, + &ioStatusBlock + ); + if (ntStatus != STATUS_SUCCESS) { + return -1; + } + return 0; +#if 0 + int datasync = 0; + int error; + int fstrans; + + if (flags & O_DSYNC) + datasync = 1; + + /* + * May enter XFS which generates a warning when PF_FSTRANS is set. + * To avoid this the flag is cleared over vfs_sync() and then reset. + */ + fstrans = __spl_pf_fstrans_check(); + if (fstrans) + current->flags &= ~(__SPL_PF_FSTRANS); + + error = -vfs_fsync(filp, datasync); + + if (fstrans) + current->flags |= __SPL_PF_FSTRANS; + + return (error); +#endif +} + +/* + * Get file attributes + * + * filp - file pointer + * zfattr - pointer to file attr structure + * + * Currently only used for fetching size and file mode. + * + * Returns 0 on success or error code of underlying getattr call on failure. + */ +int +zfs_file_getattr(zfs_file_t* filp, zfs_file_attr_t* zfattr) +{ + FILE_STANDARD_INFORMATION fileInfo = { 0 }; + IO_STATUS_BLOCK ioStatusBlock; + NTSTATUS ntStatus; + ntStatus = ZwQueryInformationFile( + *filp, + &ioStatusBlock, + &fileInfo, + sizeof(fileInfo), + FileNameInformation + ); + if (ntStatus != STATUS_SUCCESS) { + return -1; + } + zfattr->zfa_size = fileInfo.EndOfFile.QuadPart; +#if 0 + struct kstat stat; + int rc; + +#if defined(HAVE_4ARGS_VFS_GETATTR) + rc = vfs_getattr(&filp->f_path, &stat, STATX_BASIC_STATS, + AT_STATX_SYNC_AS_STAT); +#elif defined(HAVE_2ARGS_VFS_GETATTR) + rc = vfs_getattr(&filp->f_path, &stat); +#else + rc = vfs_getattr(filp->f_path.mnt, filp->f_dentry, &stat); +#endif + if (rc) + return (-rc); + + zfattr->zfa_size = stat.size; + zfattr->zfa_mode = stat.mode; + + return (0); +#endif +} +#if 0 +static ssize_t +zfs_file_read_impl(zfs_file_t* fp, void* buf, size_t count, loff_t* off) +{ +#if defined(HAVE_KERNEL_READ_PPOS) + return (kernel_read(fp, buf, count, off)); +#else + mm_segment_t saved_fs; + ssize_t rc; + + saved_fs = get_fs(); + set_fs(KERNEL_DS); + + rc = vfs_read(fp, (void __user*)buf, count, off); + set_fs(saved_fs); + + return (rc); +#endif +} + +/* + * lseek - set / get file pointer + * + * fp - pointer to file (pipe, socket, etc) to read from + * offp - value to seek to, returns current value plus passed offset + * whence - see man pages for standard lseek whence values + * + * Returns 0 on success errno on failure (ESPIPE for non seekable types) + */ +int +zfs_file_seek(zfs_file_t *fp, loff_t *offp, int whence) +{ + loff_t rc; + + if (*offp < 0 || *offp > MAXOFFSET_T) + return (EINVAL); + + rc = vfs_llseek(fp, *offp, whence); + if (rc < 0) + return (-rc); + + *offp = rc; + + return (0); +} + +/* + * fallocate - allocate or free space on disk + * + * fp - file pointer + * mode (non-standard options for hole punching etc) + * offset - offset to start allocating or freeing from + * len - length to free / allocate + * + * OPTIONAL + */ +int +zfs_file_fallocate(zfs_file_t *fp, int mode, loff_t offset, loff_t len) +{ + /* + * May enter XFS which generates a warning when PF_FSTRANS is set. + * To avoid this the flag is cleared over vfs_sync() and then reset. + */ + int fstrans = __spl_pf_fstrans_check(); + if (fstrans) + current->flags &= ~(__SPL_PF_FSTRANS); + + /* + * When supported by the underlying file system preferentially + * use the fallocate() callback to preallocate the space. + */ + int error = EOPNOTSUPP; + if (fp->f_op->fallocate) + error = fp->f_op->fallocate(fp, mode, offset, len); + + if (fstrans) + current->flags |= __SPL_PF_FSTRANS; + + return (error); +} + +/* + * Request current file pointer offset + * + * fp - pointer to file + * + * Returns current file offset. + */ +loff_t +zfs_file_off(zfs_file_t *fp) +{ + return (fp->f_pos); +} + +/* + * Request file pointer private data + * + * fp - pointer to file + * + * Returns pointer to file private data. + */ +void * +zfs_file_private(zfs_file_t *fp) +{ + return (fp->private_data); +} + +/* + * unlink file + * + * path - fully qualified file path + * + * Returns 0 on success. + * + * OPTIONAL + */ +int +zfs_file_unlink(const char *path) +{ + return (EOPNOTSUPP); +} + +/* + * Get reference to file pointer + * + * fd - input file descriptor + * fpp - pointer to file pointer + * + * Returns 0 on success EBADF on failure. + */ +int +zfs_file_get(int fd, zfs_file_t **fpp) +{ + zfs_file_t *fp; + + fp = fget(fd); + if (fp == NULL) + return (EBADF); + + *fpp = fp; + + return (0); +} + +/* + * Drop reference to file pointer + * + * fd - input file descriptor + */ +void +zfs_file_put(int fd) +{ + struct file *fp; + + if ((fp = fget(fd)) != NULL) { + fput(fp); + fput(fp); + } +} +#endif + diff --git a/enc_temp_folder/f34911e0bc429dd8d27b48f1bc3b52da/vdev_file.c b/enc_temp_folder/f34911e0bc429dd8d27b48f1bc3b52da/vdev_file.c new file mode 100644 index 00000000..9f817c05 --- /dev/null +++ b/enc_temp_folder/f34911e0bc429dd8d27b48f1bc3b52da/vdev_file.c @@ -0,0 +1,757 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015 by Delphix. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Virtual device vector for files. + */ + +static taskq_t *vdev_file_taskq; + +extern void UnlockAndFreeMdl(PMDL); + +static void +vdev_file_hold(vdev_t *vd) +{ + ASSERT(vd->vdev_path != NULL); +} + +static void +vdev_file_rele(vdev_t *vd) +{ + ASSERT(vd->vdev_path != NULL); +} + +#ifdef _KERNEL +extern int VOP_GETATTR(struct vnode *vp, vattr_t *vap, int flags, void *x3, void *x4); +#endif + +//static int +//vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, +// uint64_t *ashift) +//{ +//#if _KERNEL +// static vattr_t vattr; +// vdev_file_t *vf; +//#endif +// int error = 0; +// +// dprintf("vdev_file_open %p\n", vd->vdev_tsd); +// /* Rotational optimizations only make sense on block devices */ +// vd->vdev_nonrot = B_TRUE; +// +// /* +// * Allow TRIM on file based vdevs. This may not always be supported, +// * since it depends on your kernel version and underlying filesystem +// * type but it is always safe to attempt. +// */ +// vd->vdev_has_trim = B_TRUE; +// +// /* +// * Disable secure TRIM on file based vdevs. There is no way to +// * request this behavior from the underlying filesystem. +// */ +// vd->vdev_has_securetrim = B_FALSE; +// +// /* +// * We must have a pathname, and it must be absolute. +// */ +// if (vd->vdev_path == NULL || (vd->vdev_path[0] != '/' && +// vd->vdev_path[0] != '\\')) { +// vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; +// return (SET_ERROR(EINVAL)); +// } +// +// /* +// * Reopen the device if it's not currently open. Otherwise, +// * just update the physical size of the device. +// */ +//#ifdef _KERNEL +// if (vd->vdev_tsd != NULL) { +// ASSERT(vd->vdev_reopening); +// vf = vd->vdev_tsd; +// goto skip_open; +// } +// +// vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP); +//#endif +// +// /* +// * We always open the files from the root of the global zone, even if +// * we're in a local zone. If the user has gotten to this point, the +// * administrator has already decided that the pool should be available +// * to local zone users, so the underlying devices should be as well. +// */ +// ASSERT(vd->vdev_path != NULL && ( +// vd->vdev_path[0] == '/' || vd->vdev_path[0] == '\\')); +// +// /* +// vn_openat(char *pnamep, +// enum uio_seg seg, +// int filemode, +// int createmode, +// struct vnode **vpp, +// enum create crwhy, +// mode_t umask, +// struct vnode *startvp) +// extern int vn_openat(char *pnamep, enum uio_seg seg, int filemode, +// int createmode, struct vnode **vpp, enum create crwhy, +// mode_t umask, struct vnode *startvp); +// */ +// uint8_t *FileName = NULL; +// FileName = vd->vdev_path; +// +// if (!strncmp("\\\\?\\", FileName, 4)) { +// FileName[1] = '?'; +// } +// +// dprintf("%s: opening '%s'\n", __func__, FileName); +// +//#ifdef _KERNEL +// +// ANSI_STRING AnsiFilespec; +// UNICODE_STRING UnicodeFilespec; +// OBJECT_ATTRIBUTES ObjectAttributes; +// +// SHORT UnicodeName[PATH_MAX]; +// CHAR AnsiName[PATH_MAX]; +// USHORT NameLength = 0; +// NTSTATUS ntstatus; +// +// memset(UnicodeName, 0, sizeof(SHORT) * PATH_MAX); +// memset(AnsiName, 0, sizeof(UCHAR) * PATH_MAX); +// +// NameLength = strlen(FileName); +// ASSERT(NameLength < PATH_MAX); +// +// memmove(AnsiName, FileName, NameLength); +// +// AnsiFilespec.MaximumLength = AnsiFilespec.Length = NameLength; +// AnsiFilespec.Buffer = AnsiName; +// +// UnicodeFilespec.MaximumLength = PATH_MAX * 2; +// UnicodeFilespec.Length = 0; +// UnicodeFilespec.Buffer = (PWSTR)UnicodeName; +// +// RtlAnsiStringToUnicodeString(&UnicodeFilespec, &AnsiFilespec, FALSE); +// +// ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES); +// ObjectAttributes.RootDirectory = NULL; +// ObjectAttributes.Attributes = /*OBJ_CASE_INSENSITIVE |*/ OBJ_KERNEL_HANDLE; +// ObjectAttributes.ObjectName = &UnicodeFilespec; +// ObjectAttributes.SecurityDescriptor = NULL; +// ObjectAttributes.SecurityQualityOfService = NULL; +// IO_STATUS_BLOCK iostatus; +// +// ntstatus = ZwCreateFile(&vf->vf_handle, +// spa_mode(vd->vdev_spa) == FREAD ? GENERIC_READ | SYNCHRONIZE : GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, +// &ObjectAttributes, +// &iostatus, +// 0, +// FILE_ATTRIBUTE_NORMAL, +// /* FILE_SHARE_WRITE | */ FILE_SHARE_READ, +// FILE_OPEN, +// FILE_SYNCHRONOUS_IO_NONALERT | (spa_mode(vd->vdev_spa) == FREAD ? 0 : FILE_NO_INTERMEDIATE_BUFFERING), +// NULL, +// 0); +// +// if (ntstatus == STATUS_SUCCESS) { +// error = 0; +// } else { +// vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; +// goto failed; +// } +// +// +// /* +// * Make sure it's a regular file. +// */ +// FILE_STANDARD_INFORMATION info; +// IO_STATUS_BLOCK iob; +// +// if ((ZwQueryInformationFile( +// vf->vf_handle, +// &iob, +// &info, +// sizeof(info), +// FileStandardInformation) != STATUS_SUCCESS) || +// (info.Directory != FALSE)) { +// vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; +// ZwClose(vf->vf_handle); +// error = ENOENT; +// goto failed; +// } +// +// // Since we will use DeviceObject and FileObject to do ioctl and IO +// // we grab them now and lock them in place. +// // Convert HANDLE to FileObject +// PFILE_OBJECT FileObject; +// PDEVICE_OBJECT DeviceObject; +// NTSTATUS status; +// +// // This adds a reference to FileObject +// status = ObReferenceObjectByHandle( +// vf->vf_handle, +// 0, +// *IoFileObjectType, +// KernelMode, +// &FileObject, +// NULL +// ); +// if (status != STATUS_SUCCESS) { +// ZwClose(vf->vf_handle); +// vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; +// error = EIO; +// goto failed; +// } +// +// // Convert FileObject to DeviceObject +// DeviceObject = IoGetRelatedDeviceObject(FileObject); +// +// // Grab a reference to DeviceObject +// ObReferenceObject(DeviceObject); +// +// vf->vf_FileObject = FileObject; +// vf->vf_DeviceObject = DeviceObject; +// +// // Change it to SPARSE, so TRIM might work +// status = ZwFsControlFile( +// vf->vf_handle, +// NULL, +// NULL, +// NULL, +// NULL, +// FSCTL_SET_SPARSE, +// NULL, +// 0, +// NULL, +// 0 +// ); +// dprintf("%s: set Sparse 0x%x.\n", __func__, status); +// +//#endif +// +//#if _KERNEL +//skip_open: +// /* +// * Determine the physical size of the file. +// */ +// //vattr.va_mask = AT_SIZE; +// //vn_lock(vf->vf_vnode, LK_SHARED | LK_RETRY); +// //error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL); +// //VN_UNLOCK(vf->vf_vnode); +//#endif +// +//#ifdef _KERNEL +// *max_psize = *psize = info.EndOfFile.QuadPart; +//#else +// /* userland's vn_open() will get the device size for us, so we can +// * just look it up - there is argument for a userland VOP_GETATTR to make +// * this function cleaner. */ +//// *max_psize = *psize = vp->v_size; +//#endif +// *ashift = SPA_MINBLOCKSHIFT; +// +// return (0); +// +//failed: +//#ifdef _KERNEL +// if (vf) { +// if (vf->vf_handle != NULL) { +// vf->vf_handle = NULL; +// } +// +// kmem_free(vf, sizeof(vdev_file_t)); +// vd->vdev_tsd = NULL; +// } +//#endif +// return error; +//} + +static mode_t vdev_file_open_mode(spa_mode_t spa_mode) +{ + mode_t mode = 0; + // TODO :- Add flags + if ((spa_mode & SPA_MODE_READ) && (spa_mode & SPA_MODE_WRITE)) { + mode = O_RDWR; + } + else if (spa_mode & SPA_MODE_READ) { + mode = O_RDONLY; + } + else if (spa_mode & SPA_MODE_WRITE) { + mode = O_WRONLY; + } + return mode; +} + +static int +vdev_file_open(vdev_t* vd, uint64_t* psize, uint64_t* max_psize, + uint64_t* ashift) +{ + vdev_file_t2* vf; + zfs_file_t fp; + zfs_file_attr_t zfa; + int err; + + /* + * Rotational optimizations only make sense on block devices. + */ + vd->vdev_nonrot = B_TRUE; + + /* + * Allow TRIM on file based vdevs. This may not always be supported, + * since it depends on your kernel version and underlying filesystem + * type but it is always safe to attempt. + */ + vd->vdev_has_trim = B_TRUE; + + /* + * Disable secure TRIM on file based vdevs. There is no way to + * request this behavior from the underlying filesystem. + */ + vd->vdev_has_securetrim = B_FALSE; + + /* + * We must have a pathname, and it must be absolute. + */ + + if (vd->vdev_path == NULL || (vd->vdev_path[0] != '/' && vd->vdev_path[0] != '\\')) { + vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL; + return (SET_ERROR(EINVAL)); + } + + if (vd->vdev_tsd != NULL) { + ASSERT(vd->vdev_reopening); + vf = vd->vdev_tsd; + goto skip_open; + } + + vf = vd->vdev_tsd = kmem_zalloc(sizeof(vdev_file_t2), KM_SLEEP); + ASSERT(vd->vdev_path != NULL && ( + vd->vdev_path[0] == '/' || vd->vdev_path[0] == '\\')); + + vd->vdev_path = "\\\\.\\PhysicalDrive1"; + err = zfs_file_open(vd->vdev_path, vdev_file_open_mode(spa_mode(vd->vdev_spa)), 0, &fp); + if (err) { + vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; + return (err); + } + vf->vf_file = fp; + + //#ifdef _KERNEL + // /* + // * Make sure it's a regular file. + // */ + // if (zfs_file_getattr(fp, &zfa)) { + // return (SET_ERROR(ENODEV)); + // } + // if (!S_ISREG(zfa.zfa_mode)) { + // vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; + // return (SET_ERROR(ENODEV)); + // } + //#endif +skip_open: +#ifdef _KERNEL + err = zfs_file_getattr(vf->vf_file, &zfa); + if (err) { + vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; + return (err); + } +#else + err = zfs_file_geomtery(&fp, &zfa); +#endif + * max_psize = *psize = zfa.zfa_size; + *ashift = SPA_MINBLOCKSHIFT; + return (0); +} + +//static void +//vdev_file_close(vdev_t *vd) +//{ +//#ifdef _KERNEL +// vdev_file_t *vf = vd->vdev_tsd; +// +// if (vd->vdev_reopening || vf == NULL) +// return; +// +// if (vf->vf_handle != NULL) { +// +// // Release our holds +// ObDereferenceObject(vf->vf_FileObject); +// ObDereferenceObject(vf->vf_DeviceObject); +// +// ZwClose(vf->vf_handle); +// } +// +// vf->vf_FileObject = NULL; +// vf->vf_DeviceObject = NULL; +// vf->vf_handle = NULL; +// vd->vdev_delayed_close = B_FALSE; +// kmem_free(vf, sizeof (vdev_file_t)); +// vd->vdev_tsd = NULL; +//#endif +//} + +static void vdev_file_close(vdev_t* vd) +{ + vdev_file_t2* vf = vd->vdev_tsd; + + if (vd->vdev_reopening || vf == NULL) + return; + + if (vf->vf_file != NULL) { + (void)zfs_file_close(&vf->vf_file); + } + vd->vdev_delayed_close = B_FALSE; + kmem_free(vf, sizeof(vdev_file_t2)); + vd->vdev_tsd = NULL; +} + +#ifdef _KERNEL +struct vdev_file_callback_struct { + zio_t *zio; + PIRP irp; + void *b_data; + char work_item[0]; +}; +typedef struct vdev_file_callback_struct vf_callback_t; + +static void +vdev_file_io_start_done(void *param) +{ + vf_callback_t *vb = (vf_callback_t *)param; + + ASSERT(vb != NULL); + + NTSTATUS status = vb->irp->IoStatus.Status; + zio_t *zio = vb->zio; + zio->io_error = (!NT_SUCCESS(status) ? EIO : 0); + + // Return abd buf + if (zio->io_type == ZIO_TYPE_READ) { + VERIFY3S(zio->io_abd->abd_size, >= , zio->io_size); + abd_return_buf_copy_off(zio->io_abd, vb->b_data, + 0, zio->io_size, zio->io_abd->abd_size); + } else { + VERIFY3S(zio->io_abd->abd_size, >= , zio->io_size); + abd_return_buf_off(zio->io_abd, vb->b_data, + 0, zio->io_size, zio->io_abd->abd_size); + } + + UnlockAndFreeMdl(vb->irp->MdlAddress); + IoFreeIrp(vb->irp); + kmem_free(vb, sizeof(vf_callback_t) + IoSizeofWorkItem()); + vb = NULL; + zio_delay_interrupt(zio); +} + +static VOID +FileIoWkRtn( + __in PVOID pDummy, // Not used. + __in PVOID pWkParms // Parm list pointer. +) +{ + vf_callback_t *vb = (vf_callback_t *)pWkParms; + + UNREFERENCED_PARAMETER(pDummy); + IoUninitializeWorkItem((PIO_WORKITEM)vb->work_item); + vdev_file_io_start_done(vb); +} + +static NTSTATUS +vdev_file_io_intrxxx(PDEVICE_OBJECT DeviceObject, PIRP irp, PVOID Context) +{ + vf_callback_t *vb = (vf_callback_t *)Context; + + ASSERT(vb != NULL); + + /* If IRQL is below DIPATCH_LEVEL then there is no issue in calling + * vdev_file_io_start_done() directly; otherwise queue a new Work Item + */ + if (KeGetCurrentIrql() < DISPATCH_LEVEL) + vdev_file_io_start_done(vb); + else { + vdev_file_t *vf = vb->zio->io_vd->vdev_tsd; + IoInitializeWorkItem(vf->vf_DeviceObject, (PIO_WORKITEM)vb->work_item); + IoQueueWorkItem((PIO_WORKITEM)vb->work_item, FileIoWkRtn, DelayedWorkQueue, vb); + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} +#endif + +/* + * count the number of mismatches of zio->io_size and zio->io_abd->abd_size below + */ +_Atomic uint64_t zfs_vdev_file_size_mismatch_cnt = 0; + +// clear the changes +static void +vdev_file_io_start(zio_t *zio) +{ + vdev_t *vd = zio->io_vd; + ssize_t resid = 0; + + + if (zio->io_type == ZIO_TYPE_IOCTL) { + + if (!vdev_readable(vd)) { + zio->io_error = SET_ERROR(ENXIO); + zio_interrupt(zio); + return; + } + + switch (zio->io_cmd) { + case DKIOCFLUSHWRITECACHE: +#if 0 + if (!vnode_getwithvid(vf->vf_vnode, vf->vf_vid)) { + zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC, + kcred, NULL); + vnode_put(vf->vf_vnode); + } +#endif + break; + default: + zio->io_error = SET_ERROR(ENOTSUP); + } + + zio_interrupt(zio); + return; + + } else if (zio->io_type == ZIO_TYPE_TRIM) { +#ifdef _KERNEL + struct flock flck; + vdev_file_t *vf = vd->vdev_tsd; + + ASSERT3U(zio->io_size, != , 0); + bzero(&flck, sizeof(flck)); + flck.l_type = F_FREESP; + flck.l_start = zio->io_offset; + flck.l_len = zio->io_size; + flck.l_whence = 0; + + zio->io_error = VOP_SPACE(vf->vf_handle, F_FREESP, &flck, + 0, 0, kcred, NULL); + +#endif + zio_execute(zio); + return; + } + + ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE); + zio->io_target_timestamp = zio_handle_io_delay(zio); + + + ASSERT(zio->io_size != 0); + +#ifdef _KERNEL + vdev_file_t* vf = vd->vdev_tsd; +#else + vdev_file_t2* vf = vd->vdev_tsd; +#endif // _KERNEL + LARGE_INTEGER offset; + offset.QuadPart = zio->io_offset + vd->vdev_win_offset; +#ifdef _KERNEL + PIRP irp = NULL; + PIO_STACK_LOCATION irpStack = NULL; + IO_STATUS_BLOCK IoStatusBlock = { 0 }; + + + /* Preallocate space for IoWorkItem, required for vdev_file_io_start_done callback */ + vf_callback_t *vb = (vf_callback_t *)kmem_alloc(sizeof(vf_callback_t) + IoSizeofWorkItem(), KM_SLEEP); + + vb->zio = zio; + +#ifdef DEBUG + if (zio->io_abd->abd_size != zio->io_size) { + zfs_vdev_file_size_mismatch_cnt++; + // this dprintf can be very noisy + dprintf("ZFS: %s: trimming zio->io_abd from 0x%x to 0x%llx\n", + __func__, zio->io_abd->abd_size, zio->io_size); + } +#endif + + if (zio->io_type == ZIO_TYPE_READ) { + ASSERT3S(zio->io_abd->abd_size, >= , zio->io_size); + vb->b_data = + abd_borrow_buf(zio->io_abd, zio->io_abd->abd_size); + } else { + ASSERT3S(zio->io_abd->abd_size, >= , zio->io_size); + vb->b_data = + abd_borrow_buf_copy(zio->io_abd, zio->io_abd->abd_size); + } + + if (zio->io_type == ZIO_TYPE_READ) { + irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, + vf->vf_DeviceObject, + vb->b_data, + (ULONG)zio->io_size, + &offset, + &IoStatusBlock); + } else { + irp = IoBuildAsynchronousFsdRequest(IRP_MJ_WRITE, + vf->vf_DeviceObject, + vb->b_data, + (ULONG)zio->io_size, + &offset, + &IoStatusBlock); + } + + if (!irp) { + kmem_free(vb, sizeof(vf_callback_t) + IoSizeofWorkItem()); + zio->io_error = EIO; + zio_interrupt(zio); + return; + } + + irpStack = IoGetNextIrpStackLocation(irp); + + irpStack->Flags |= SL_OVERRIDE_VERIFY_VOLUME; // SetFlag(IoStackLocation->Flags, SL_OVERRIDE_VERIFY_VOLUME); + //SetFlag(ReadIrp->Flags, IRP_NOCACHE); + irpStack->FileObject = vf->vf_FileObject; + + IoSetCompletionRoutine(irp, + vdev_file_io_intrxxx, + vb, // "Context" in vdev_file_io_intr() + TRUE, // On Success + TRUE, // On Error + TRUE);// On Cancel + + IoCallDriver(vf->vf_DeviceObject, irp); +#else + void* data; + int err; + DWORD red; + HANDLE hFile = vf->vf_file; + + if (!SetFilePointerEx(hFile, offset, NULL, FILE_BEGIN)) + goto failed; + + if (zio->io_type == ZIO_TYPE_READ) { + ASSERT3S(zio->io_abd->abd_size, >= , zio->io_size); + //data = + // abd_borrow_buf(zio->io_abd, zio->io_abd->abd_size); + //ok = ReadFile(hFile, data, zio->io_size, &red, NULL); + //abd_return_buf_copy(zio->io_abd, data, zio->io_size); + data = abd_borrow_buf(zio->io_abd, zio->io_abd->abd_size); + err = ReadFile(hFile, data, zio->io_size, &red, NULL); + //err = zfs_file_pread(&hFile, data, zio->io_size, &red, zio->io_offset); + abd_return_buf_copy(zio->io_abd, data, zio->io_size); // see in kernel space what is happening + } + else { + ASSERT3S(zio->io_abd->abd_size, >= , zio->io_size); + data = + abd_borrow_buf_copy(zio->io_abd, zio->io_abd->abd_size); + err = WriteFile(hFile, data, zio->io_size, &red, NULL); + abd_return_buf_off(zio->io_abd, data, + 0, zio->io_size, zio->io_abd->abd_size); + } + +failed: + if (!err) + zio->io_error = EIO; + else if (red != zio->io_size) + zio->io_error = SET_ERROR(ENOSPC); + else + zio->io_error = 0; + + zio_delay_interrupt(zio); + return; +#endif + + return; +} + + +/* ARGSUSED */ +static void +vdev_file_io_done(zio_t *zio) +{ +} + +vdev_ops_t vdev_file_ops = { + vdev_file_open, + vdev_file_close, + vdev_default_asize, + vdev_file_io_start, + vdev_file_io_done, + NULL, + NULL, + vdev_file_hold, + vdev_file_rele, + NULL, + vdev_default_xlate, + VDEV_TYPE_FILE, /* name of this vdev type */ + B_TRUE /* leaf vdev */ +}; + +void +vdev_file_init(void) +{ + vdev_file_taskq = taskq_create("vdev_file_taskq", 100, minclsyspri, + max_ncpus, INT_MAX, TASKQ_PREPOPULATE | TASKQ_THREADS_CPU_PCT); + + VERIFY(vdev_file_taskq); +} + +void +vdev_file_fini(void) +{ + taskq_destroy(vdev_file_taskq); +} + +/* + * From userland we access disks just like files. + */ +#ifndef _KERNEL + +vdev_ops_t vdev_disk_ops = { + vdev_file_open, + vdev_file_close, + vdev_default_asize, + vdev_file_io_start, + vdev_file_io_done, + NULL, + NULL, + vdev_file_hold, + vdev_file_rele, + NULL, + vdev_default_xlate, + VDEV_TYPE_DISK, /* name of this vdev type */ + B_TRUE /* leaf vdev */ +}; + +#endif