-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
+/*
* GPL HEADER START
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* GPL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*/
/*
#include <libcfs/libcfs.h>
-const CHAR *dos_file_prefix = "\\??\\";
+const CHAR *dos_file_prefix[] = {
+ "\\??\\", "\\DosDevices\\",
+ "\\SystemRoot\\", NULL};
/*
- * cfs_filp_open
+ * filp_open
* To open or create a file in kernel mode
*
* Arguments:
* err: error code
*
* Return Value:
- * the pointer to the cfs_file_t or NULL if it fails
+ * the pointer to the struct file or NULL if it fails
*
- * Notes:
+ * Notes:
* N/A
*/
-cfs_file_t *cfs_filp_open(const char *name, int flags, int mode, int *err)
+#define is_drv_letter_valid(x) (((x) >= 0 && (x) <= 9) || \
+ ( ((x)|0x20) <= 'z' && ((x)|0x20) >= 'a'))
+
+struct file *filp_open(const char *name, int flags, int mode, int *err)
{
- cfs_file_t * fp = NULL;
+ struct file *fp = NULL;
NTSTATUS Status;
PUCHAR AnsiString = NULL;
/* Analyze the flags settings */
-
if (cfs_is_flag_set(flags, O_WRONLY)) {
DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
ShareAccess = 0;
}
/* Initialize the unicode path name for the specified file */
-
NameLength = (USHORT)strlen(name);
- if (name[0] != '\\') {
- PrefixLength = (USHORT)strlen(dos_file_prefix);
- }
-
- AnsiString = cfs_alloc( sizeof(CHAR) * (NameLength + PrefixLength + 1),
- CFS_ALLOC_ZERO);
- if (NULL == AnsiString) {
- if (err) *err = -ENOMEM;
- return NULL;
- }
-
- UnicodeString = cfs_alloc( sizeof(WCHAR) * (NameLength + PrefixLength + 1),
- CFS_ALLOC_ZERO);
-
- if (NULL == UnicodeString) {
- if (err) *err = -ENOMEM;
- cfs_free(AnsiString);
- return NULL;
- }
+ /* Check file & path name */
+ if (name[0] != '\\') {
+ if (NameLength < 1 || name[1] != ':' ||
+ !is_drv_letter_valid(name[0])) {
+ /* invalid file path name */
+ return ERR_PTR(-EINVAL);
+ }
+ PrefixLength = (USHORT)strlen(dos_file_prefix[0]);
+ } else {
+ int i, j;
+ for (i = 0; i < 3 && dos_file_prefix[i] != NULL; i++) {
+ j = strlen(dos_file_prefix[i]);
+ if (NameLength > j &&
+ _strnicmp(dos_file_prefix[i], name, j) == 0)
+ break;
+ }
+ if (i >= 3)
+ return ERR_PTR(-EINVAL);
+ }
+
+ AnsiString = kmalloc(sizeof(CHAR) * (NameLength + PrefixLength + 1),
+ __GFP_ZERO);
+ if (NULL == AnsiString)
+ return ERR_PTR(-ENOMEM);
+
+ UnicodeString =
+ kmalloc(sizeof(WCHAR) * (NameLength + PrefixLength + 1),
+ __GFP_ZERO);
+ if (NULL == UnicodeString) {
+ kfree(AnsiString);
+ return ERR_PTR(-ENOMEM);
+ }
if (PrefixLength) {
- RtlCopyMemory(&AnsiString[0], dos_file_prefix , PrefixLength);
+ RtlCopyMemory(&AnsiString[0], dos_file_prefix[0], PrefixLength);
}
RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
/* Setup the object attributes structure for the file. */
-
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeName,
NULL );
/* Now to open or create the file now */
-
Status = ZwCreateFile(
&FileHandle,
DesiredAccess,
NULL,
0 );
- /* Check the returned status of IoStatus... */
-
- if (!NT_SUCCESS(IoStatus.Status)) {
- *err = cfs_error_code(IoStatus.Status);
- cfs_free(UnicodeString);
- cfs_free(AnsiString);
- return NULL;
- }
-
- /* Allocate the cfs_file_t: libcfs file object */
+ /* Check the returned status of IoStatus... */
+ if (!NT_SUCCESS(IoStatus.Status)) {
+ kfree(UnicodeString);
+ kfree(AnsiString);
+ return ERR_PTR(cfs_error_code(IoStatus.Status));
+ }
- fp = cfs_alloc(sizeof(cfs_file_t) + NameLength, CFS_ALLOC_ZERO);
+ /* Allocate the file_t: libcfs file object */
+ fp = kmalloc(sizeof(*fp) + NameLength, __GFP_ZERO);
- if (NULL == fp) {
- Status = ZwClose(FileHandle);
- ASSERT(NT_SUCCESS(Status));
- *err = -ENOMEM;
- cfs_free(UnicodeString);
- cfs_free(AnsiString);
- return NULL;
- }
+ if (NULL == fp) {
+ Status = ZwClose(FileHandle);
+ ASSERT(NT_SUCCESS(Status));
+ kfree(UnicodeString);
+ kfree(AnsiString);
+ return ERR_PTR(-ENOMEM);
+ }
fp->f_handle = FileHandle;
strcpy(fp->f_name, name);
fp->f_flags = flags;
fp->f_mode = (mode_t)mode;
fp->f_count = 1;
- *err = 0;
- /* free the memory of temporary name strings */
- cfs_free(UnicodeString);
- cfs_free(AnsiString);
+ /* free the memory of temporary name strings */
+ kfree(UnicodeString);
+ kfree(AnsiString);
- return fp;
+ return fp;
}
/*
- * cfs_filp_close
+ * filp_close
* To close the opened file and release the filp structure
*
* Arguments:
- * fp: the pointer of the cfs_file_t strcture
+ * fp: the pointer of the file structure
*
* Return Value:
* ZERO: on success
* Non-Zero: on failure
*
- * Notes:
+ * Notes:
* N/A
*/
-int cfs_filp_close(cfs_file_t *fp)
+int filp_close(file_t *fp, void *id)
{
NTSTATUS Status;
Status = ZwClose(fp->f_handle);
ASSERT(NT_SUCCESS(Status));
- /* free the file flip structure */
- cfs_free(fp);
- return 0;
+ /* free the file flip structure */
+ kfree(fp);
+ return 0;
}
+NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
+{
+ /* copy the IoStatus result */
+ if (Irp->UserIosb)
+ *Irp->UserIosb = Irp->IoStatus;
+
+ /* singal the event we set */
+ KeSetEvent((PKEVENT) Context, 0, FALSE);
+
+ /* free the Irp we allocated */
+ IoFreeIrp(Irp);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+
+NTSTATUS cfs_nt_filp_io(HANDLE Handle, BOOLEAN Writing, PLARGE_INTEGER Offset,
+ ULONG Length, PUCHAR Buffer, PULONG Bytes)
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK iosb;
+
+ PIRP irp = NULL;
+ PIO_STACK_LOCATION irpSp = NULL;
+
+ PFILE_OBJECT fileObject = NULL;
+ PDEVICE_OBJECT deviceObject;
+
+ KEVENT event;
+
+ KeInitializeEvent(&event, SynchronizationEvent, FALSE);
+
+ status = ObReferenceObjectByHandle( Handle,
+ Writing ? FILE_WRITE_DATA :
+ FILE_READ_DATA,
+ *IoFileObjectType,
+ KernelMode,
+ (PVOID *) &fileObject,
+ NULL );
+ if (!NT_SUCCESS(status)) {
+ goto errorout;
+ }
+
+ /* query the DeviceObject in case no input */
+ deviceObject = IoGetBaseFileSystemDeviceObject(fileObject);
+
+
+ /* allocate our own irp */
+ irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
+ if (NULL == irp) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ irp->Tail.Overlay.OriginalFileObject = fileObject;
+ irp->Tail.Overlay.Thread = PsGetCurrentThread();
+ irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
+ irp->PendingReturned = FALSE;
+ irp->Cancel = FALSE;
+ irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
+ irp->RequestorMode = KernelMode;
+ irp->UserIosb = &iosb;
+
+ /* set up the next I/O stack location. */
+ irpSp = (PIO_STACK_LOCATION)IoGetNextIrpStackLocation(irp);
+ irpSp->MajorFunction = Writing ? IRP_MJ_WRITE : IRP_MJ_READ;
+ irpSp->FileObject = fileObject;
+ irpSp->DeviceObject = deviceObject;
+
+ if (deviceObject->Flags & DO_BUFFERED_IO) {
+ irp->AssociatedIrp.SystemBuffer = Buffer;
+ irp->UserBuffer = Buffer;
+ irp->Flags |= (ULONG) (IRP_BUFFERED_IO |
+ IRP_INPUT_OPERATION);
+ } else if (deviceObject->Flags & DO_DIRECT_IO) {
+
+ PMDL mdl = NULL;
+
+ mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, irp);
+ if (mdl == NULL) {
+ KsPrint((0, "cfs_nt_filp_io: failed to allocate MDL for %wZ .\n",
+ &fileObject->FileName));
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ __try {
+ MmProbeAndLockPages(mdl, KernelMode, Writing ? IoReadAccess : IoWriteAccess );
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ KsPrint((0, "cfs_nt_filp_io: failed to lock buffer %p for %wZ .\n",
+ Buffer, &fileObject->FileName));
+ IoFreeMdl(irp->MdlAddress);
+ irp->MdlAddress = NULL;
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ } else {
+ irp->UserBuffer = Buffer;
+ irp->Flags = 0;
+ }
+
+ if (Writing) {
+ irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
+ irpSp->Parameters.Write.Length = Length;
+ irpSp->Parameters.Write.ByteOffset = *Offset;
+ } else {
+ irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
+ irpSp->Parameters.Read.Length = Length;
+ irpSp->Parameters.Read.ByteOffset = *Offset;
+ }
+
+ /* set the Irp completion routine */
+ IoSetCompletionRoutine( irp, CompletionRoutine,
+ &event, TRUE, TRUE, TRUE);
+
+
+ /* issue the irp to the lower layer device */
+ status = IoCallDriver(deviceObject, irp);
+
+ /* Irp is to be cleaned up in the compleiton routine */
+ irp = NULL;
+
+ if (status == STATUS_PENDING) {
+
+ /* we need wait until operation is completed, then we can
+ get the returned status and information length */
+
+ status = KeWaitForSingleObject(
+ &event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ if (NT_SUCCESS(status)) {
+ status = iosb.Status;
+ }
+ }
+
+ if (NT_SUCCESS(status)) {
+ *Bytes = (ULONG)iosb.Information;
+ } else {
+ *Bytes = 0;
+ }
+
+errorout:
+
+ if (fileObject) {
+ ObDereferenceObject(fileObject);
+ }
+
+ /* free the Irp in error case */
+ if (irp) {
+ IoFreeIrp(irp);
+ }
+
+ return status;
+}
+
/*
- * cfs_filp_read
+ * filp_read
* To read data from the opened file
*
* Arguments:
- * fp: the pointer of the cfs_file_t strcture
+ * fp: the pointer of the file strcture
* buf: pointer to the buffer to contain the data
* nbytes: size in bytes to be read from the file
* pos: offset in file where reading starts, if pos
* Notes:
* N/A
*/
-
-int cfs_filp_read(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
+int filp_read(struct file *fp, void *buf, size_t nbytes, loff_t *pos)
{
- LARGE_INTEGER address;
- NTSTATUS Status;
- IO_STATUS_BLOCK IoStatus;
-
+ LARGE_INTEGER offset;
+ NTSTATUS status;
int rc = 0;
/* Read data from the file into the specified buffer */
-
if (pos != NULL) {
- address.QuadPart = *pos;
+ offset.QuadPart = *pos;
} else {
- address.QuadPart = fp->f_pos;
+ offset.QuadPart = fp->f_pos;
}
- Status = ZwReadFile( fp->f_handle,
- 0,
- NULL,
- NULL,
- &IoStatus,
- buf,
- nbytes,
- &address,
- NULL );
-
- if (!NT_SUCCESS(IoStatus.Status)) {
- rc = cfs_error_code(IoStatus.Status);
- } else {
- rc = (int)IoStatus.Information;
- fp->f_pos = address.QuadPart + rc;
-
- if (pos != NULL) {
+ status = cfs_nt_filp_io(fp->f_handle, 0, &offset,
+ nbytes, buf, &rc);
+
+ if (!NT_SUCCESS(status)) {
+ rc = cfs_error_code(status);
+ }
+
+ if (rc > 0) {
+ fp->f_pos = offset.QuadPart + rc;
+ if (pos != NULL)
*pos = fp->f_pos;
- }
}
- return rc;
+ return rc;
}
-
/*
* cfs_filp_wrtie
* To write specified data to the opened file
*
* Arguments:
- * fp: the pointer of the cfs_file_t strcture
+ * fp: the pointer of the file strcture
* buf: pointer to the buffer containing the data
* nbytes: size in bytes to be written to the file
* pos: offset in file where writing starts, if pos
* N/A
*/
-int cfs_filp_write(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
+int filp_write(struct file *fp, void *buf, size_t nbytes, loff_t *pos)
{
- LARGE_INTEGER address;
- NTSTATUS Status;
- IO_STATUS_BLOCK IoStatus;
+ LARGE_INTEGER offset;
+ NTSTATUS status;
int rc = 0;
- /* Write user specified data into the file */
-
+ /* Read data from the file into the specified buffer */
if (pos != NULL) {
- address.QuadPart = *pos;
+ offset.QuadPart = *pos;
} else {
- address.QuadPart = fp->f_pos;
+ offset.QuadPart = fp->f_pos;
}
- Status = ZwWriteFile( fp->f_handle,
- 0,
- NULL,
- NULL,
- &IoStatus,
- buf,
- nbytes,
- &address,
- NULL );
+ status = cfs_nt_filp_io(fp->f_handle, 1, &offset,
+ nbytes, buf, &rc);
- if (!NT_SUCCESS(Status)) {
- rc = cfs_error_code(Status);
- } else {
- rc = (int)IoStatus.Information;
- fp->f_pos = address.QuadPart + rc;
-
- if (pos != NULL) {
+ if (!NT_SUCCESS(status)) {
+ rc = cfs_error_code(status);
+ }
+
+ if (rc > 0) {
+ fp->f_pos = offset.QuadPart + rc;
+ if (pos != NULL)
*pos = fp->f_pos;
- }
}
return rc;
}
-
-NTSTATUS
-CompletionRoutine(
- PDEVICE_OBJECT DeviceObject,
- PIRP Irp,
- PVOID Context)
-{
- /* copy the IoStatus result */
- *Irp->UserIosb = Irp->IoStatus;
-
- /* singal the event we set */
- KeSetEvent(Irp->UserEvent, 0, FALSE);
-
- /* free the Irp we allocated */
- IoFreeIrp(Irp);
-
- return STATUS_MORE_PROCESSING_REQUIRED;
-}
-
-
/*
- * cfs_filp_fsync
+ * filp_fsync
* To sync the dirty data of the file to disk
*
* Arguments:
- * fp: the pointer of the cfs_file_t strcture
+ * fp: the pointer of the file strcture
*
* Return Value:
* Zero: in success case
* we must allocate our own Irp and issue it to the file
* system driver.
*/
-
-int cfs_filp_fsync(cfs_file_t *fp)
+int filp_fsync(struct file *fp)
{
-
PFILE_OBJECT FileObject;
PDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION IrpSp;
/* get the FileObject and the DeviceObject */
-
Status = ObReferenceObjectByHandle(
fp->f_handle,
FILE_WRITE_DATA,
DeviceObject = IoGetRelatedDeviceObject(FileObject);
/* allocate a new Irp */
-
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-
if (!Irp) {
-
ObDereferenceObject(FileObject);
return -ENOMEM;
}
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
/* setup the Irp */
- Irp->UserEvent = &Event;
Irp->UserIosb = &IoSb;
Irp->RequestorMode = KernelMode;
IrpSp->DeviceObject = DeviceObject;
IrpSp->FileObject = FileObject;
- IoSetCompletionRoutine(Irp, CompletionRoutine, 0, TRUE, TRUE, TRUE);
+ IoSetCompletionRoutine( Irp, CompletionRoutine,
+ &Event, TRUE, TRUE, TRUE);
/* issue the Irp to the underlying file system driver */
}
/*
- * cfs_get_file
+ * get_file
* To increase the reference of the file object
*
* Arguments:
- * fp: the pointer of the cfs_file_t strcture
+ * fp: the pointer of the file strcture
*
* Return Value:
* Zero: in success case
* N/A
*/
-int cfs_get_file(cfs_file_t *fp)
+int get_file(struct file *fp)
{
InterlockedIncrement(&(fp->f_count));
return 0;
/*
- * cfs_put_file
+ * fput
* To decrease the reference of the file object
*
* Arguments:
- * fp: the pointer of the cfs_file_t strcture
+ * fp: the pointer of the file strcture
*
* Return Value:
* Zero: in success case
* Non-Zero: in failure case
*
- * Notes:
+ * Notes:
* N/A
*/
-int cfs_put_file(cfs_file_t *fp)
+int fput(struct file *fp)
{
- if (InterlockedDecrement(&(fp->f_count)) == 0) {
- cfs_filp_close(fp);
- }
+ if (InterlockedDecrement(&(fp->f_count)) == 0)
+ filp_close(fp, NULL);
- return 0;
+ return 0;
}
/*
- * cfs_file_count
+ * file_count
* To query the reference count of the file object
*
* Arguments:
- * fp: the pointer of the cfs_file_t strcture
+ * fp: the pointer of the file strcture
*
* Return Value:
* the reference count of the file object
* N/A
*/
-int cfs_file_count(cfs_file_t *fp)
+int file_count(struct file *fp)
+{
+ return (int)(fp->f_count);
+}
+
+struct dentry *dget(struct dentry *de)
{
- return (int)(fp->f_count);
+ if (de) {
+ atomic_inc(&de->d_count);
+ }
+ return de;
+}
+
+void dput(struct dentry *de)
+{
+ if (!de || atomic_read(&de->d_count) == 0) {
+ return;
+ }
+ if (atomic_dec_and_test(&de->d_count)) {
+ kfree(de);
+ }
}