4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
31 * This file is part of Lustre, http://www.lustre.org/
32 * Lustre is a trademark of Sun Microsystems, Inc.
35 # define DEBUG_SUBSYSTEM S_LNET
37 #include <libcfs/libcfs.h>
39 const CHAR *dos_file_prefix[] = {
40 "\\??\\", "\\DosDevices\\",
41 "\\SystemRoot\\", NULL};
45 * To open or create a file in kernel mode
48 * name: name of the file to be opened or created, no dos path prefix
49 * flags: open/creation attribute options
50 * mode: access mode/permission to open or create
54 * the pointer to the cfs_file_t or NULL if it fails
60 #define is_drv_letter_valid(x) (((x) >= 0 && (x) <= 9) || \
61 ( ((x)|0x20) <= 'z' && ((x)|0x20) >= 'a'))
63 cfs_file_t *cfs_filp_open(const char *name, int flags, int mode, int *err)
65 cfs_file_t * fp = NULL;
69 OBJECT_ATTRIBUTES ObjectAttributes;
71 IO_STATUS_BLOCK IoStatus;
72 ACCESS_MASK DesiredAccess;
73 ULONG CreateDisposition;
77 USHORT NameLength = 0;
78 USHORT PrefixLength = 0;
80 UNICODE_STRING UnicodeName;
81 PWCHAR UnicodeString = NULL;
84 PUCHAR AnsiString = NULL;
86 /* Analyze the flags settings */
87 if (cfs_is_flag_set(flags, O_WRONLY)) {
88 DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
90 } else if (cfs_is_flag_set(flags, O_RDWR)) {
91 DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
92 ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
94 DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
95 ShareAccess = FILE_SHARE_READ;
98 if (cfs_is_flag_set(flags, O_CREAT)) {
99 if (cfs_is_flag_set(flags, O_EXCL)) {
100 CreateDisposition = FILE_CREATE;
102 CreateDisposition = FILE_OPEN_IF;
105 CreateDisposition = FILE_OPEN;
108 if (cfs_is_flag_set(flags, O_TRUNC)) {
109 if (cfs_is_flag_set(flags, O_EXCL)) {
110 CreateDisposition = FILE_OVERWRITE;
112 CreateDisposition = FILE_OVERWRITE_IF;
118 if (cfs_is_flag_set(flags, O_DIRECTORY)) {
119 cfs_set_flag(CreateOptions, FILE_DIRECTORY_FILE);
122 if (cfs_is_flag_set(flags, O_SYNC)) {
123 cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
126 if (cfs_is_flag_set(flags, O_DIRECT)) {
127 cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
130 /* Initialize the unicode path name for the specified file */
131 NameLength = (USHORT)strlen(name);
133 /* Check file & path name */
134 if (name[0] != '\\') {
135 if (NameLength < 1 || name[1] != ':' || !is_drv_letter_valid(name[0])) {
136 /* invalid file path name */
137 if (err) *err = -EINVAL;
140 PrefixLength = (USHORT)strlen(dos_file_prefix[0]);
143 for (i=0; i < 3 && dos_file_prefix[i] != NULL; i++) {
144 j = strlen(dos_file_prefix[i]);
145 if (NameLength > j && _strnicmp(dos_file_prefix[i], name, j) == 0) {
150 if (err) *err = -EINVAL;
155 AnsiString = cfs_alloc( sizeof(CHAR) * (NameLength + PrefixLength + 1),
157 if (NULL == AnsiString) {
158 if (err) *err = -ENOMEM;
162 UnicodeString = cfs_alloc( sizeof(WCHAR) * (NameLength + PrefixLength + 1),
164 if (NULL == UnicodeString) {
165 if (err) *err = -ENOMEM;
166 cfs_free(AnsiString);
171 RtlCopyMemory(&AnsiString[0], dos_file_prefix[0], PrefixLength);
174 RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
175 NameLength += PrefixLength;
177 AnsiName.MaximumLength = NameLength + 1;
178 AnsiName.Length = NameLength;
179 AnsiName.Buffer = AnsiString;
181 UnicodeName.MaximumLength = (NameLength + 1) * sizeof(WCHAR);
182 UnicodeName.Length = 0;
183 UnicodeName.Buffer = (PWSTR)UnicodeString;
185 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
187 /* Setup the object attributes structure for the file. */
188 InitializeObjectAttributes(
191 OBJ_CASE_INSENSITIVE |
196 /* Now to open or create the file now */
197 Status = ZwCreateFile(
203 FILE_ATTRIBUTE_NORMAL,
210 /* Check the returned status of IoStatus... */
211 if (!NT_SUCCESS(IoStatus.Status)) {
213 *err = cfs_error_code(IoStatus.Status);
215 cfs_free(UnicodeString);
216 cfs_free(AnsiString);
220 /* Allocate the cfs_file_t: libcfs file object */
221 fp = cfs_alloc(sizeof(cfs_file_t) + NameLength, CFS_ALLOC_ZERO);
224 Status = ZwClose(FileHandle);
225 ASSERT(NT_SUCCESS(Status));
229 cfs_free(UnicodeString);
230 cfs_free(AnsiString);
234 fp->f_handle = FileHandle;
235 strcpy(fp->f_name, name);
237 fp->f_mode = (mode_t)mode;
243 /* free the memory of temporary name strings */
244 cfs_free(UnicodeString);
245 cfs_free(AnsiString);
253 * To close the opened file and release the filp structure
256 * fp: the pointer of the cfs_file_t strcture
260 * Non-Zero: on failure
266 int cfs_filp_close(cfs_file_t *fp)
271 ASSERT(fp->f_handle != NULL);
273 /* release the file handle */
274 Status = ZwClose(fp->f_handle);
275 ASSERT(NT_SUCCESS(Status));
277 /* free the file flip structure */
283 NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
285 /* copy the IoStatus result */
287 *Irp->UserIosb = Irp->IoStatus;
289 /* singal the event we set */
290 KeSetEvent((PKEVENT) Context, 0, FALSE);
292 /* free the Irp we allocated */
295 return STATUS_MORE_PROCESSING_REQUIRED;
299 NTSTATUS cfs_nt_filp_io(HANDLE Handle, BOOLEAN Writing, PLARGE_INTEGER Offset,
300 ULONG Length, PUCHAR Buffer, PULONG Bytes)
303 IO_STATUS_BLOCK iosb;
306 PIO_STACK_LOCATION irpSp = NULL;
308 PFILE_OBJECT fileObject = NULL;
309 PDEVICE_OBJECT deviceObject;
313 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
315 status = ObReferenceObjectByHandle( Handle,
316 Writing ? FILE_WRITE_DATA :
320 (PVOID *) &fileObject,
322 if (!NT_SUCCESS(status)) {
326 /* query the DeviceObject in case no input */
327 deviceObject = IoGetBaseFileSystemDeviceObject(fileObject);
330 /* allocate our own irp */
331 irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
333 status = STATUS_INSUFFICIENT_RESOURCES;
337 irp->Tail.Overlay.OriginalFileObject = fileObject;
338 irp->Tail.Overlay.Thread = PsGetCurrentThread();
339 irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
340 irp->PendingReturned = FALSE;
342 irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
343 irp->RequestorMode = KernelMode;
344 irp->UserIosb = &iosb;
346 /* set up the next I/O stack location. */
347 irpSp = (PIO_STACK_LOCATION)IoGetNextIrpStackLocation(irp);
348 irpSp->MajorFunction = Writing ? IRP_MJ_WRITE : IRP_MJ_READ;
349 irpSp->FileObject = fileObject;
350 irpSp->DeviceObject = deviceObject;
352 if (deviceObject->Flags & DO_BUFFERED_IO) {
353 irp->AssociatedIrp.SystemBuffer = Buffer;
354 irp->UserBuffer = Buffer;
355 irp->Flags |= (ULONG) (IRP_BUFFERED_IO |
356 IRP_INPUT_OPERATION);
357 } else if (deviceObject->Flags & DO_DIRECT_IO) {
361 mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, irp);
363 KsPrint((0, "cfs_nt_filp_io: failed to allocate MDL for %wZ .\n",
364 &fileObject->FileName));
365 status = STATUS_INSUFFICIENT_RESOURCES;
370 MmProbeAndLockPages(mdl, KernelMode, Writing ? IoReadAccess : IoWriteAccess );
371 } __except(EXCEPTION_EXECUTE_HANDLER) {
372 KsPrint((0, "cfs_nt_filp_io: failed to lock buffer %p for %wZ .\n",
373 Buffer, &fileObject->FileName));
374 IoFreeMdl(irp->MdlAddress);
375 irp->MdlAddress = NULL;
376 status = STATUS_INSUFFICIENT_RESOURCES;
379 irp->UserBuffer = Buffer;
384 irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
385 irpSp->Parameters.Write.Length = Length;
386 irpSp->Parameters.Write.ByteOffset = *Offset;
388 irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
389 irpSp->Parameters.Read.Length = Length;
390 irpSp->Parameters.Read.ByteOffset = *Offset;
393 /* set the Irp completion routine */
394 IoSetCompletionRoutine( irp, CompletionRoutine,
395 &event, TRUE, TRUE, TRUE);
398 /* issue the irp to the lower layer device */
399 status = IoCallDriver(deviceObject, irp);
401 /* Irp is to be cleaned up in the compleiton routine */
404 if (status == STATUS_PENDING) {
406 /* we need wait until operation is completed, then we can
407 get the returned status and information length */
409 status = KeWaitForSingleObject(
416 if (NT_SUCCESS(status)) {
417 status = iosb.Status;
421 if (NT_SUCCESS(status)) {
422 *Bytes = (ULONG)iosb.Information;
430 ObDereferenceObject(fileObject);
433 /* free the Irp in error case */
443 * To read data from the opened file
446 * fp: the pointer of the cfs_file_t strcture
447 * buf: pointer to the buffer to contain the data
448 * nbytes: size in bytes to be read from the file
449 * pos: offset in file where reading starts, if pos
450 * NULL, then read from current file offset
453 * Actual size read into the buffer in success case
454 * Error code in failure case
460 int cfs_filp_read(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
462 LARGE_INTEGER offset;
466 /* Read data from the file into the specified buffer */
468 offset.QuadPart = *pos;
470 offset.QuadPart = fp->f_pos;
473 status = cfs_nt_filp_io(fp->f_handle, 0, &offset,
476 if (!NT_SUCCESS(status)) {
477 rc = cfs_error_code(status);
481 fp->f_pos = offset.QuadPart + rc;
491 * To write specified data to the opened file
494 * fp: the pointer of the cfs_file_t strcture
495 * buf: pointer to the buffer containing the data
496 * nbytes: size in bytes to be written to the file
497 * pos: offset in file where writing starts, if pos
498 * NULL, then write to current file offset
501 * Actual size written into the buffer in success case
502 * Error code in failure case
508 int cfs_filp_write(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
510 LARGE_INTEGER offset;
514 /* Read data from the file into the specified buffer */
516 offset.QuadPart = *pos;
518 offset.QuadPart = fp->f_pos;
521 status = cfs_nt_filp_io(fp->f_handle, 1, &offset,
524 if (!NT_SUCCESS(status)) {
525 rc = cfs_error_code(status);
529 fp->f_pos = offset.QuadPart + rc;
539 * To sync the dirty data of the file to disk
542 * fp: the pointer of the cfs_file_t strcture
545 * Zero: in success case
546 * Error code: in failure case
549 * Nt kernel doesn't export such a routine to flush a file,
550 * we must allocate our own Irp and issue it to the file
554 int cfs_filp_fsync(cfs_file_t *fp)
557 PFILE_OBJECT FileObject;
558 PDEVICE_OBJECT DeviceObject;
563 IO_STATUS_BLOCK IoSb;
564 PIO_STACK_LOCATION IrpSp;
566 /* get the FileObject and the DeviceObject */
567 Status = ObReferenceObjectByHandle(
575 if (!NT_SUCCESS(Status)) {
576 return cfs_error_code(Status);
579 DeviceObject = IoGetRelatedDeviceObject(FileObject);
581 /* allocate a new Irp */
582 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
584 ObDereferenceObject(FileObject);
588 /* intialize the event */
589 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
592 Irp->UserIosb = &IoSb;
593 Irp->RequestorMode = KernelMode;
595 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
596 Irp->Tail.Overlay.OriginalFileObject = FileObject;
598 /* setup the Irp stack location */
599 IrpSp = IoGetNextIrpStackLocation(Irp);
601 IrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
602 IrpSp->DeviceObject = DeviceObject;
603 IrpSp->FileObject = FileObject;
605 IoSetCompletionRoutine( Irp, CompletionRoutine,
606 &Event, TRUE, TRUE, TRUE);
609 /* issue the Irp to the underlying file system driver */
610 IoCallDriver(DeviceObject, Irp);
612 /* wait until it is finished */
613 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
615 /* cleanup our reference on it */
616 ObDereferenceObject(FileObject);
618 Status = IoSb.Status;
620 return cfs_error_code(Status);
625 * To increase the reference of the file object
628 * fp: the pointer of the cfs_file_t strcture
631 * Zero: in success case
632 * Non-Zero: in failure case
638 int cfs_get_file(cfs_file_t *fp)
640 InterlockedIncrement(&(fp->f_count));
647 * To decrease the reference of the file object
650 * fp: the pointer of the cfs_file_t strcture
653 * Zero: in success case
654 * Non-Zero: in failure case
660 int cfs_put_file(cfs_file_t *fp)
662 if (InterlockedDecrement(&(fp->f_count)) == 0) {
672 * To query the reference count of the file object
675 * fp: the pointer of the cfs_file_t strcture
678 * the reference count of the file object
684 int cfs_file_count(cfs_file_t *fp)
686 return (int)(fp->f_count);
689 struct dentry *dget(struct dentry *de)
692 cfs_atomic_inc(&de->d_count);
697 void dput(struct dentry *de)
699 if (!de || cfs_atomic_read(&de->d_count) == 0) {
702 if (cfs_atomic_dec_and_test(&de->d_count)) {