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 struct file or NULL if it fails
60 #define is_drv_letter_valid(x) (((x) >= 0 && (x) <= 9) || \
61 ( ((x)|0x20) <= 'z' && ((x)|0x20) >= 'a'))
63 struct file *filp_open(const char *name, int flags, int mode, int *err)
65 struct file *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] != ':' ||
136 !is_drv_letter_valid(name[0])) {
137 /* invalid file path name */
138 return ERR_PTR(-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 &&
146 _strnicmp(dos_file_prefix[i], name, j) == 0)
150 return ERR_PTR(-EINVAL);
153 AnsiString = kmalloc(sizeof(CHAR) * (NameLength + PrefixLength + 1),
155 if (NULL == AnsiString)
156 return ERR_PTR(-ENOMEM);
159 kmalloc(sizeof(WCHAR) * (NameLength + PrefixLength + 1),
161 if (NULL == UnicodeString) {
163 return ERR_PTR(-ENOMEM);
167 RtlCopyMemory(&AnsiString[0], dos_file_prefix[0], PrefixLength);
170 RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
171 NameLength += PrefixLength;
173 AnsiName.MaximumLength = NameLength + 1;
174 AnsiName.Length = NameLength;
175 AnsiName.Buffer = AnsiString;
177 UnicodeName.MaximumLength = (NameLength + 1) * sizeof(WCHAR);
178 UnicodeName.Length = 0;
179 UnicodeName.Buffer = (PWSTR)UnicodeString;
181 RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
183 /* Setup the object attributes structure for the file. */
184 InitializeObjectAttributes(
187 OBJ_CASE_INSENSITIVE |
192 /* Now to open or create the file now */
193 Status = ZwCreateFile(
199 FILE_ATTRIBUTE_NORMAL,
206 /* Check the returned status of IoStatus... */
207 if (!NT_SUCCESS(IoStatus.Status)) {
208 kfree(UnicodeString);
210 return ERR_PTR(cfs_error_code(IoStatus.Status));
213 /* Allocate the file_t: libcfs file object */
214 fp = kmalloc(sizeof(*fp) + NameLength, __GFP_ZERO);
217 Status = ZwClose(FileHandle);
218 ASSERT(NT_SUCCESS(Status));
219 kfree(UnicodeString);
221 return ERR_PTR(-ENOMEM);
224 fp->f_handle = FileHandle;
225 strcpy(fp->f_name, name);
227 fp->f_mode = (mode_t)mode;
230 /* free the memory of temporary name strings */
231 kfree(UnicodeString);
240 * To close the opened file and release the filp structure
243 * fp: the pointer of the file structure
247 * Non-Zero: on failure
253 int filp_close(file_t *fp, void *id)
258 ASSERT(fp->f_handle != NULL);
260 /* release the file handle */
261 Status = ZwClose(fp->f_handle);
262 ASSERT(NT_SUCCESS(Status));
264 /* free the file flip structure */
270 NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
272 /* copy the IoStatus result */
274 *Irp->UserIosb = Irp->IoStatus;
276 /* singal the event we set */
277 KeSetEvent((PKEVENT) Context, 0, FALSE);
279 /* free the Irp we allocated */
282 return STATUS_MORE_PROCESSING_REQUIRED;
286 NTSTATUS cfs_nt_filp_io(HANDLE Handle, BOOLEAN Writing, PLARGE_INTEGER Offset,
287 ULONG Length, PUCHAR Buffer, PULONG Bytes)
290 IO_STATUS_BLOCK iosb;
293 PIO_STACK_LOCATION irpSp = NULL;
295 PFILE_OBJECT fileObject = NULL;
296 PDEVICE_OBJECT deviceObject;
300 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
302 status = ObReferenceObjectByHandle( Handle,
303 Writing ? FILE_WRITE_DATA :
307 (PVOID *) &fileObject,
309 if (!NT_SUCCESS(status)) {
313 /* query the DeviceObject in case no input */
314 deviceObject = IoGetBaseFileSystemDeviceObject(fileObject);
317 /* allocate our own irp */
318 irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
320 status = STATUS_INSUFFICIENT_RESOURCES;
324 irp->Tail.Overlay.OriginalFileObject = fileObject;
325 irp->Tail.Overlay.Thread = PsGetCurrentThread();
326 irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
327 irp->PendingReturned = FALSE;
329 irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
330 irp->RequestorMode = KernelMode;
331 irp->UserIosb = &iosb;
333 /* set up the next I/O stack location. */
334 irpSp = (PIO_STACK_LOCATION)IoGetNextIrpStackLocation(irp);
335 irpSp->MajorFunction = Writing ? IRP_MJ_WRITE : IRP_MJ_READ;
336 irpSp->FileObject = fileObject;
337 irpSp->DeviceObject = deviceObject;
339 if (deviceObject->Flags & DO_BUFFERED_IO) {
340 irp->AssociatedIrp.SystemBuffer = Buffer;
341 irp->UserBuffer = Buffer;
342 irp->Flags |= (ULONG) (IRP_BUFFERED_IO |
343 IRP_INPUT_OPERATION);
344 } else if (deviceObject->Flags & DO_DIRECT_IO) {
348 mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, irp);
350 KsPrint((0, "cfs_nt_filp_io: failed to allocate MDL for %wZ .\n",
351 &fileObject->FileName));
352 status = STATUS_INSUFFICIENT_RESOURCES;
357 MmProbeAndLockPages(mdl, KernelMode, Writing ? IoReadAccess : IoWriteAccess );
358 } __except(EXCEPTION_EXECUTE_HANDLER) {
359 KsPrint((0, "cfs_nt_filp_io: failed to lock buffer %p for %wZ .\n",
360 Buffer, &fileObject->FileName));
361 IoFreeMdl(irp->MdlAddress);
362 irp->MdlAddress = NULL;
363 status = STATUS_INSUFFICIENT_RESOURCES;
366 irp->UserBuffer = Buffer;
371 irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
372 irpSp->Parameters.Write.Length = Length;
373 irpSp->Parameters.Write.ByteOffset = *Offset;
375 irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
376 irpSp->Parameters.Read.Length = Length;
377 irpSp->Parameters.Read.ByteOffset = *Offset;
380 /* set the Irp completion routine */
381 IoSetCompletionRoutine( irp, CompletionRoutine,
382 &event, TRUE, TRUE, TRUE);
385 /* issue the irp to the lower layer device */
386 status = IoCallDriver(deviceObject, irp);
388 /* Irp is to be cleaned up in the compleiton routine */
391 if (status == STATUS_PENDING) {
393 /* we need wait until operation is completed, then we can
394 get the returned status and information length */
396 status = KeWaitForSingleObject(
403 if (NT_SUCCESS(status)) {
404 status = iosb.Status;
408 if (NT_SUCCESS(status)) {
409 *Bytes = (ULONG)iosb.Information;
417 ObDereferenceObject(fileObject);
420 /* free the Irp in error case */
430 * To read data from the opened file
433 * fp: the pointer of the file strcture
434 * buf: pointer to the buffer to contain the data
435 * nbytes: size in bytes to be read from the file
436 * pos: offset in file where reading starts, if pos
437 * NULL, then read from current file offset
440 * Actual size read into the buffer in success case
441 * Error code in failure case
446 int filp_read(struct file *fp, void *buf, size_t nbytes, loff_t *pos)
448 LARGE_INTEGER offset;
452 /* Read data from the file into the specified buffer */
454 offset.QuadPart = *pos;
456 offset.QuadPart = fp->f_pos;
459 status = cfs_nt_filp_io(fp->f_handle, 0, &offset,
462 if (!NT_SUCCESS(status)) {
463 rc = cfs_error_code(status);
467 fp->f_pos = offset.QuadPart + rc;
477 * To write specified data to the opened file
480 * fp: the pointer of the file strcture
481 * buf: pointer to the buffer containing the data
482 * nbytes: size in bytes to be written to the file
483 * pos: offset in file where writing starts, if pos
484 * NULL, then write to current file offset
487 * Actual size written into the buffer in success case
488 * Error code in failure case
494 int filp_write(struct file *fp, void *buf, size_t nbytes, loff_t *pos)
496 LARGE_INTEGER offset;
500 /* Read data from the file into the specified buffer */
502 offset.QuadPart = *pos;
504 offset.QuadPart = fp->f_pos;
507 status = cfs_nt_filp_io(fp->f_handle, 1, &offset,
510 if (!NT_SUCCESS(status)) {
511 rc = cfs_error_code(status);
515 fp->f_pos = offset.QuadPart + rc;
525 * To sync the dirty data of the file to disk
528 * fp: the pointer of the file strcture
531 * Zero: in success case
532 * Error code: in failure case
535 * Nt kernel doesn't export such a routine to flush a file,
536 * we must allocate our own Irp and issue it to the file
539 int filp_fsync(struct file *fp, loff_t start, loff_t end)
541 PFILE_OBJECT FileObject;
542 PDEVICE_OBJECT DeviceObject;
547 IO_STATUS_BLOCK IoSb;
548 PIO_STACK_LOCATION IrpSp;
550 /* get the FileObject and the DeviceObject */
551 Status = ObReferenceObjectByHandle(
559 if (!NT_SUCCESS(Status)) {
560 return cfs_error_code(Status);
563 DeviceObject = IoGetRelatedDeviceObject(FileObject);
565 /* allocate a new Irp */
566 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
568 ObDereferenceObject(FileObject);
572 /* intialize the event */
573 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
576 Irp->UserIosb = &IoSb;
577 Irp->RequestorMode = KernelMode;
579 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
580 Irp->Tail.Overlay.OriginalFileObject = FileObject;
582 /* setup the Irp stack location */
583 IrpSp = IoGetNextIrpStackLocation(Irp);
585 IrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
586 IrpSp->DeviceObject = DeviceObject;
587 IrpSp->FileObject = FileObject;
589 IoSetCompletionRoutine( Irp, CompletionRoutine,
590 &Event, TRUE, TRUE, TRUE);
593 /* issue the Irp to the underlying file system driver */
594 IoCallDriver(DeviceObject, Irp);
596 /* wait until it is finished */
597 KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
599 /* cleanup our reference on it */
600 ObDereferenceObject(FileObject);
602 Status = IoSb.Status;
604 return cfs_error_code(Status);
609 * To increase the reference of the file object
612 * fp: the pointer of the file strcture
615 * Zero: in success case
616 * Non-Zero: in failure case
622 int get_file(struct file *fp)
624 InterlockedIncrement(&(fp->f_count));
631 * To decrease the reference of the file object
634 * fp: the pointer of the file strcture
637 * Zero: in success case
638 * Non-Zero: in failure case
644 int fput(struct file *fp)
646 if (InterlockedDecrement(&(fp->f_count)) == 0)
647 filp_close(fp, NULL);
655 * To query the reference count of the file object
658 * fp: the pointer of the file strcture
661 * the reference count of the file object
667 int file_count(struct file *fp)
669 return (int)(fp->f_count);
672 struct dentry *dget(struct dentry *de)
675 atomic_inc(&de->d_count);
680 void dput(struct dentry *de)
682 if (!de || atomic_read(&de->d_count) == 0) {
685 if (atomic_dec_and_test(&de->d_count)) {