1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
37 # define DEBUG_SUBSYSTEM S_LNET
39 #include <libcfs/libcfs.h>
41 const CHAR *dos_file_prefix[] = {
42 "\\??\\", "\\DosDevices\\",
43 "\\SystemRoot\\", NULL};
47 * To open or create a file in kernel mode
50 * name: name of the file to be opened or created, no dos path prefix
51 * flags: open/creation attribute options
52 * mode: access mode/permission to open or create
56 * the pointer to the cfs_file_t or NULL if it fails
62 #define is_drv_letter_valid(x) (((x) >= 0 && (x) <= 9) || \
63 ( ((x)|0x20) <= 'z' && ((x)|0x20) >= 'a'))
65 cfs_file_t *cfs_filp_open(const char *name, int flags, int mode, int *err)
67 cfs_file_t * fp = NULL;
71 OBJECT_ATTRIBUTES ObjectAttributes;
73 IO_STATUS_BLOCK IoStatus;
74 ACCESS_MASK DesiredAccess;
75 ULONG CreateDisposition;
79 USHORT NameLength = 0;
80 USHORT PrefixLength = 0;
82 UNICODE_STRING UnicodeName;
83 PWCHAR UnicodeString = NULL;
86 PUCHAR AnsiString = NULL;
88 /* Analyze the flags settings */
89 if (cfs_is_flag_set(flags, O_WRONLY)) {
90 DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
92 } else if (cfs_is_flag_set(flags, O_RDWR)) {
93 DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
94 ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
96 DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
97 ShareAccess = FILE_SHARE_READ;
100 if (cfs_is_flag_set(flags, O_CREAT)) {
101 if (cfs_is_flag_set(flags, O_EXCL)) {
102 CreateDisposition = FILE_CREATE;
104 CreateDisposition = FILE_OPEN_IF;
107 CreateDisposition = FILE_OPEN;
110 if (cfs_is_flag_set(flags, O_TRUNC)) {
111 if (cfs_is_flag_set(flags, O_EXCL)) {
112 CreateDisposition = FILE_OVERWRITE;
114 CreateDisposition = FILE_OVERWRITE_IF;
120 if (cfs_is_flag_set(flags, O_DIRECTORY)) {
121 cfs_set_flag(CreateOptions, FILE_DIRECTORY_FILE);
124 if (cfs_is_flag_set(flags, O_SYNC)) {
125 cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
128 if (cfs_is_flag_set(flags, O_DIRECT)) {
129 cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
132 /* Initialize the unicode path name for the specified file */
133 NameLength = (USHORT)strlen(name);
135 /* Check file & path name */
136 if (name[0] != '\\') {
137 if (NameLength < 1 || name[1] != ':' || !is_drv_letter_valid(name[0])) {
138 /* invalid file path name */
139 if (err) *err = -EINVAL;
142 PrefixLength = (USHORT)strlen(dos_file_prefix[0]);
145 for (i=0; i < 3 && dos_file_prefix[i] != NULL; i++) {
146 j = strlen(dos_file_prefix[i]);
147 if (NameLength > j && _strnicmp(dos_file_prefix[i], name, j) == 0) {
152 if (err) *err = -EINVAL;
157 AnsiString = cfs_alloc( sizeof(CHAR) * (NameLength + PrefixLength + 1),
159 if (NULL == AnsiString) {
160 if (err) *err = -ENOMEM;
164 UnicodeString = cfs_alloc( sizeof(WCHAR) * (NameLength + PrefixLength + 1),
166 if (NULL == UnicodeString) {
167 if (err) *err = -ENOMEM;
168 cfs_free(AnsiString);
173 RtlCopyMemory(&AnsiString[0], dos_file_prefix[0], PrefixLength);
176 RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
177 NameLength += PrefixLength;
179 AnsiName.MaximumLength = NameLength + 1;
180 AnsiName.Length = NameLength;
181 AnsiName.Buffer = AnsiString;
183 UnicodeName.MaximumLength = (NameLength + 1) * sizeof(WCHAR);
184 UnicodeName.Length = 0;
185 UnicodeName.Buffer = (PWSTR)UnicodeString;
187 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
189 /* Setup the object attributes structure for the file. */
190 InitializeObjectAttributes(
193 OBJ_CASE_INSENSITIVE |
198 /* Now to open or create the file now */
199 Status = ZwCreateFile(
205 FILE_ATTRIBUTE_NORMAL,
212 /* Check the returned status of IoStatus... */
213 if (!NT_SUCCESS(IoStatus.Status)) {
215 *err = cfs_error_code(IoStatus.Status);
217 cfs_free(UnicodeString);
218 cfs_free(AnsiString);
222 /* Allocate the cfs_file_t: libcfs file object */
223 fp = cfs_alloc(sizeof(cfs_file_t) + NameLength, CFS_ALLOC_ZERO);
226 Status = ZwClose(FileHandle);
227 ASSERT(NT_SUCCESS(Status));
231 cfs_free(UnicodeString);
232 cfs_free(AnsiString);
236 fp->f_handle = FileHandle;
237 strcpy(fp->f_name, name);
239 fp->f_mode = (mode_t)mode;
245 /* free the memory of temporary name strings */
246 cfs_free(UnicodeString);
247 cfs_free(AnsiString);
255 * To close the opened file and release the filp structure
258 * fp: the pointer of the cfs_file_t strcture
262 * Non-Zero: on failure
268 int cfs_filp_close(cfs_file_t *fp)
273 ASSERT(fp->f_handle != NULL);
275 /* release the file handle */
276 Status = ZwClose(fp->f_handle);
277 ASSERT(NT_SUCCESS(Status));
279 /* free the file flip structure */
285 NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
287 /* copy the IoStatus result */
289 *Irp->UserIosb = Irp->IoStatus;
291 /* singal the event we set */
292 KeSetEvent((PKEVENT) Context, 0, FALSE);
294 /* free the Irp we allocated */
297 return STATUS_MORE_PROCESSING_REQUIRED;
301 NTSTATUS cfs_nt_filp_io(HANDLE Handle, BOOLEAN Writing, PLARGE_INTEGER Offset,
302 ULONG Length, PUCHAR Buffer, PULONG Bytes)
305 IO_STATUS_BLOCK iosb;
308 PIO_STACK_LOCATION irpSp = NULL;
310 PFILE_OBJECT fileObject = NULL;
311 PDEVICE_OBJECT deviceObject;
315 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
317 status = ObReferenceObjectByHandle( Handle,
318 Writing ? FILE_WRITE_DATA :
322 (PVOID *) &fileObject,
324 if (!NT_SUCCESS(status)) {
328 /* query the DeviceObject in case no input */
329 deviceObject = IoGetBaseFileSystemDeviceObject(fileObject);
332 /* allocate our own irp */
333 irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
335 status = STATUS_INSUFFICIENT_RESOURCES;
339 irp->Tail.Overlay.OriginalFileObject = fileObject;
340 irp->Tail.Overlay.Thread = PsGetCurrentThread();
341 irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
342 irp->PendingReturned = FALSE;
344 irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
345 irp->RequestorMode = KernelMode;
346 irp->UserIosb = &iosb;
348 /* set up the next I/O stack location. */
349 irpSp = (PIO_STACK_LOCATION)IoGetNextIrpStackLocation(irp);
350 irpSp->MajorFunction = Writing ? IRP_MJ_WRITE : IRP_MJ_READ;
351 irpSp->FileObject = fileObject;
352 irpSp->DeviceObject = deviceObject;
354 if (deviceObject->Flags & DO_BUFFERED_IO) {
355 irp->AssociatedIrp.SystemBuffer = Buffer;
356 irp->UserBuffer = Buffer;
357 irp->Flags |= (ULONG) (IRP_BUFFERED_IO |
358 IRP_INPUT_OPERATION);
359 } else if (deviceObject->Flags & DO_DIRECT_IO) {
363 mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, irp);
365 KsPrint((0, "cfs_nt_filp_io: failed to allocate MDL for %wZ .\n",
366 &fileObject->FileName));
367 status = STATUS_INSUFFICIENT_RESOURCES;
372 MmProbeAndLockPages(mdl, KernelMode, Writing ? IoReadAccess : IoWriteAccess );
373 } __except(EXCEPTION_EXECUTE_HANDLER) {
374 KsPrint((0, "cfs_nt_filp_io: failed to lock buffer %p for %wZ .\n",
375 Buffer, &fileObject->FileName));
376 IoFreeMdl(irp->MdlAddress);
377 irp->MdlAddress = NULL;
378 status = STATUS_INSUFFICIENT_RESOURCES;
381 irp->UserBuffer = Buffer;
386 irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
387 irpSp->Parameters.Write.Length = Length;
388 irpSp->Parameters.Write.ByteOffset = *Offset;
390 irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
391 irpSp->Parameters.Read.Length = Length;
392 irpSp->Parameters.Read.ByteOffset = *Offset;
395 /* set the Irp completion routine */
396 IoSetCompletionRoutine( irp, CompletionRoutine,
397 &event, TRUE, TRUE, TRUE);
400 /* issue the irp to the lower layer device */
401 status = IoCallDriver(deviceObject, irp);
403 /* Irp is to be cleaned up in the compleiton routine */
406 if (status == STATUS_PENDING) {
408 /* we need wait until operation is completed, then we can
409 get the returned status and information length */
411 status = KeWaitForSingleObject(
418 if (NT_SUCCESS(status)) {
419 status = iosb.Status;
423 if (NT_SUCCESS(status)) {
424 *Bytes = (ULONG)iosb.Information;
432 ObDereferenceObject(fileObject);
435 /* free the Irp in error case */
445 * To read data from the opened file
448 * fp: the pointer of the cfs_file_t strcture
449 * buf: pointer to the buffer to contain the data
450 * nbytes: size in bytes to be read from the file
451 * pos: offset in file where reading starts, if pos
452 * NULL, then read from current file offset
455 * Actual size read into the buffer in success case
456 * Error code in failure case
462 int cfs_filp_read(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
464 LARGE_INTEGER offset;
468 /* Read data from the file into the specified buffer */
470 offset.QuadPart = *pos;
472 offset.QuadPart = fp->f_pos;
475 status = cfs_nt_filp_io(fp->f_handle, 0, &offset,
478 if (!NT_SUCCESS(status)) {
479 rc = cfs_error_code(status);
483 fp->f_pos = offset.QuadPart + rc;
493 * To write specified data to the opened file
496 * fp: the pointer of the cfs_file_t strcture
497 * buf: pointer to the buffer containing the data
498 * nbytes: size in bytes to be written to the file
499 * pos: offset in file where writing starts, if pos
500 * NULL, then write to current file offset
503 * Actual size written into the buffer in success case
504 * Error code in failure case
510 int cfs_filp_write(cfs_file_t *fp, void *buf, size_t nbytes, loff_t *pos)
512 LARGE_INTEGER offset;
516 /* Read data from the file into the specified buffer */
518 offset.QuadPart = *pos;
520 offset.QuadPart = fp->f_pos;
523 status = cfs_nt_filp_io(fp->f_handle, 1, &offset,
526 if (!NT_SUCCESS(status)) {
527 rc = cfs_error_code(status);
531 fp->f_pos = offset.QuadPart + rc;
541 * To sync the dirty data of the file to disk
544 * fp: the pointer of the cfs_file_t strcture
547 * Zero: in success case
548 * Error code: in failure case
551 * Nt kernel doesn't export such a routine to flush a file,
552 * we must allocate our own Irp and issue it to the file
556 int cfs_filp_fsync(cfs_file_t *fp)
559 PFILE_OBJECT FileObject;
560 PDEVICE_OBJECT DeviceObject;
565 IO_STATUS_BLOCK IoSb;
566 PIO_STACK_LOCATION IrpSp;
568 /* get the FileObject and the DeviceObject */
569 Status = ObReferenceObjectByHandle(
577 if (!NT_SUCCESS(Status)) {
578 return cfs_error_code(Status);
581 DeviceObject = IoGetRelatedDeviceObject(FileObject);
583 /* allocate a new Irp */
584 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
586 ObDereferenceObject(FileObject);
590 /* intialize the event */
591 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
594 Irp->UserIosb = &IoSb;
595 Irp->RequestorMode = KernelMode;
597 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
598 Irp->Tail.Overlay.OriginalFileObject = FileObject;
600 /* setup the Irp stack location */
601 IrpSp = IoGetNextIrpStackLocation(Irp);
603 IrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
604 IrpSp->DeviceObject = DeviceObject;
605 IrpSp->FileObject = FileObject;
607 IoSetCompletionRoutine( Irp, CompletionRoutine,
608 &Event, TRUE, TRUE, TRUE);
611 /* issue the Irp to the underlying file system driver */
612 IoCallDriver(DeviceObject, Irp);
614 /* wait until it is finished */
615 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
617 /* cleanup our reference on it */
618 ObDereferenceObject(FileObject);
620 Status = IoSb.Status;
622 return cfs_error_code(Status);
627 * To increase the reference of the file object
630 * fp: the pointer of the cfs_file_t strcture
633 * Zero: in success case
634 * Non-Zero: in failure case
640 int cfs_get_file(cfs_file_t *fp)
642 InterlockedIncrement(&(fp->f_count));
649 * To decrease the reference of the file object
652 * fp: the pointer of the cfs_file_t strcture
655 * Zero: in success case
656 * Non-Zero: in failure case
662 int cfs_put_file(cfs_file_t *fp)
664 if (InterlockedDecrement(&(fp->f_count)) == 0) {
674 * To query the reference count of the file object
677 * fp: the pointer of the cfs_file_t strcture
680 * the reference count of the file object
686 int cfs_file_count(cfs_file_t *fp)
688 return (int)(fp->f_count);
691 struct dentry *dget(struct dentry *de)
694 cfs_atomic_inc(&de->d_count);
699 void dput(struct dentry *de)
701 if (!de || cfs_atomic_read(&de->d_count) == 0) {
704 if (cfs_atomic_dec_and_test(&de->d_count)) {