Whamcloud - gitweb
LU-1346 libcfs: cleanup libcfs atomic primitives
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-fs.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
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
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  */
34
35 # define DEBUG_SUBSYSTEM S_LNET
36
37 #include <libcfs/libcfs.h>
38
39 const CHAR *dos_file_prefix[] = {
40             "\\??\\", "\\DosDevices\\",
41             "\\SystemRoot\\", NULL};
42
43 /*
44  * filp_open
45  *     To open or create a file in kernel mode
46  *
47  * Arguments:
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
51  *   err:   error code
52  *
53  * Return Value:
54  *   the pointer to the struct file or NULL if it fails
55  *
56  * Notes:
57  *   N/A
58  */
59
60 #define is_drv_letter_valid(x) (((x) >= 0 && (x) <= 9) || \
61                 ( ((x)|0x20) <= 'z' && ((x)|0x20) >= 'a'))
62
63 struct file *filp_open(const char *name, int flags, int mode, int *err)
64 {
65         struct file *fp = NULL;
66
67     NTSTATUS            Status;
68
69     OBJECT_ATTRIBUTES   ObjectAttributes;
70     HANDLE              FileHandle;
71     IO_STATUS_BLOCK     IoStatus;
72     ACCESS_MASK         DesiredAccess;
73     ULONG               CreateDisposition;
74     ULONG               ShareAccess;
75     ULONG               CreateOptions;
76
77     USHORT              NameLength = 0;
78     USHORT              PrefixLength = 0;
79
80     UNICODE_STRING      UnicodeName;
81     PWCHAR              UnicodeString = NULL;
82
83     ANSI_STRING         AnsiName;
84     PUCHAR              AnsiString = NULL;
85
86     /* Analyze the flags settings */
87     if (cfs_is_flag_set(flags, O_WRONLY)) {
88         DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
89         ShareAccess = 0;
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;
93     } else {
94         DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
95         ShareAccess = FILE_SHARE_READ;
96     }
97
98     if (cfs_is_flag_set(flags, O_CREAT)) {
99         if (cfs_is_flag_set(flags, O_EXCL)) {
100             CreateDisposition = FILE_CREATE;
101         } else {
102             CreateDisposition = FILE_OPEN_IF;
103         }
104     } else {
105         CreateDisposition = FILE_OPEN;
106     }
107
108     if (cfs_is_flag_set(flags, O_TRUNC)) {
109         if (cfs_is_flag_set(flags, O_EXCL)) {
110             CreateDisposition = FILE_OVERWRITE;
111         } else {
112             CreateDisposition = FILE_OVERWRITE_IF;
113         }
114     }
115
116     CreateOptions = 0;
117
118     if (cfs_is_flag_set(flags, O_DIRECTORY)) {
119         cfs_set_flag(CreateOptions,  FILE_DIRECTORY_FILE);
120     }
121
122     if (cfs_is_flag_set(flags, O_SYNC)) {
123          cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
124     }
125
126     if (cfs_is_flag_set(flags, O_DIRECT)) {
127          cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
128     }
129
130     /* Initialize the unicode path name for the specified file */
131     NameLength = (USHORT)strlen(name);
132
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);
139                 }
140                 PrefixLength = (USHORT)strlen(dos_file_prefix[0]);
141         } else {
142                 int i, j;
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)
147                                 break;
148                 }
149                 if (i >= 3)
150                         return ERR_PTR(-EINVAL);
151         }
152
153         AnsiString = kmalloc(sizeof(CHAR) * (NameLength + PrefixLength + 1),
154                                 __GFP_ZERO);
155         if (NULL == AnsiString)
156                 return ERR_PTR(-ENOMEM);
157
158         UnicodeString =
159                 kmalloc(sizeof(WCHAR) * (NameLength + PrefixLength + 1),
160                           __GFP_ZERO);
161         if (NULL == UnicodeString) {
162                 kfree(AnsiString);
163                 return ERR_PTR(-ENOMEM);
164         }
165
166     if (PrefixLength) {
167         RtlCopyMemory(&AnsiString[0], dos_file_prefix[0], PrefixLength);
168     }
169
170     RtlCopyMemory(&AnsiString[PrefixLength], name, NameLength);
171     NameLength += PrefixLength;
172
173     AnsiName.MaximumLength = NameLength + 1;
174     AnsiName.Length = NameLength;
175     AnsiName.Buffer = AnsiString;
176
177     UnicodeName.MaximumLength = (NameLength + 1) * sizeof(WCHAR);
178     UnicodeName.Length = 0;
179     UnicodeName.Buffer = (PWSTR)UnicodeString;
180
181     RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
182
183     /* Setup the object attributes structure for the file. */
184     InitializeObjectAttributes(
185             &ObjectAttributes,
186             &UnicodeName,
187             OBJ_CASE_INSENSITIVE |
188             OBJ_KERNEL_HANDLE,
189             NULL,
190             NULL );
191
192     /* Now to open or create the file now */
193     Status = ZwCreateFile(
194             &FileHandle,
195             DesiredAccess,
196             &ObjectAttributes,
197             &IoStatus,
198             0,
199             FILE_ATTRIBUTE_NORMAL,
200             ShareAccess,
201             CreateDisposition,
202             CreateOptions,
203             NULL,
204             0 );
205
206         /* Check the returned status of IoStatus... */
207         if (!NT_SUCCESS(IoStatus.Status)) {
208                 kfree(UnicodeString);
209                 kfree(AnsiString);
210                 return ERR_PTR(cfs_error_code(IoStatus.Status));
211         }
212
213         /* Allocate the file_t: libcfs file object */
214         fp = kmalloc(sizeof(*fp) + NameLength, __GFP_ZERO);
215
216         if (NULL == fp) {
217                 Status = ZwClose(FileHandle);
218                 ASSERT(NT_SUCCESS(Status));
219                 kfree(UnicodeString);
220                 kfree(AnsiString);
221                 return ERR_PTR(-ENOMEM);
222         }
223
224     fp->f_handle = FileHandle;
225     strcpy(fp->f_name, name);
226     fp->f_flags = flags;
227     fp->f_mode  = (mode_t)mode;
228     fp->f_count = 1;
229
230         /* free the memory of temporary name strings */
231         kfree(UnicodeString);
232         kfree(AnsiString);
233
234         return fp;
235 }
236
237
238 /*
239  * filp_close
240  *     To close the opened file and release the filp structure
241  *
242  * Arguments:
243  *   fp:   the pointer of the file structure
244  *
245  * Return Value:
246  *   ZERO: on success
247  *   Non-Zero: on failure
248  *
249  * Notes:
250  *   N/A
251  */
252
253 int filp_close(file_t *fp, void *id)
254 {
255     NTSTATUS    Status;
256
257     ASSERT(fp != NULL);
258     ASSERT(fp->f_handle != NULL);
259
260     /* release the file handle */
261     Status = ZwClose(fp->f_handle);
262     ASSERT(NT_SUCCESS(Status));
263
264         /* free the file flip structure */
265         kfree(fp);
266         return 0;
267 }
268
269
270 NTSTATUS CompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
271 {
272     /* copy the IoStatus result */
273     if (Irp->UserIosb)
274         *Irp->UserIosb = Irp->IoStatus;
275     
276     /* singal the event we set */
277     KeSetEvent((PKEVENT) Context, 0, FALSE);
278    
279     /* free the Irp we allocated */
280     IoFreeIrp(Irp);
281     
282     return STATUS_MORE_PROCESSING_REQUIRED;
283 }
284
285
286 NTSTATUS cfs_nt_filp_io(HANDLE Handle, BOOLEAN Writing, PLARGE_INTEGER Offset,
287                         ULONG Length,  PUCHAR Buffer,   PULONG Bytes)
288 {
289     NTSTATUS                status;
290     IO_STATUS_BLOCK         iosb;
291
292     PIRP                    irp = NULL;
293     PIO_STACK_LOCATION      irpSp = NULL;
294
295     PFILE_OBJECT            fileObject = NULL;
296     PDEVICE_OBJECT          deviceObject;
297
298     KEVENT                  event;
299
300     KeInitializeEvent(&event, SynchronizationEvent, FALSE);
301
302     status = ObReferenceObjectByHandle( Handle,
303                                         Writing ? FILE_WRITE_DATA : 
304                                                   FILE_READ_DATA,
305                                         *IoFileObjectType,
306                                         KernelMode,
307                                         (PVOID *) &fileObject,
308                                         NULL );
309     if (!NT_SUCCESS(status)) {
310         goto errorout;
311     }
312
313     /* query the DeviceObject in case no input */
314     deviceObject = IoGetBaseFileSystemDeviceObject(fileObject);
315
316
317     /* allocate our own irp */
318     irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
319     if (NULL == irp) {
320         status = STATUS_INSUFFICIENT_RESOURCES;
321         goto errorout;
322     }
323
324     irp->Tail.Overlay.OriginalFileObject = fileObject;
325     irp->Tail.Overlay.Thread = PsGetCurrentThread();
326     irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;
327     irp->PendingReturned = FALSE;
328     irp->Cancel = FALSE;
329     irp->CancelRoutine = (PDRIVER_CANCEL) NULL;
330     irp->RequestorMode = KernelMode;
331     irp->UserIosb = &iosb;
332
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;
338
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) {
345
346         PMDL mdl = NULL;
347
348         mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, irp);
349         if (mdl == NULL) {
350             KsPrint((0, "cfs_nt_filp_io: failed to allocate MDL for %wZ .\n",
351                         &fileObject->FileName));
352             status = STATUS_INSUFFICIENT_RESOURCES;
353             goto errorout;
354         }
355
356         __try {
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;
364         }
365     } else {
366         irp->UserBuffer = Buffer;
367         irp->Flags = 0;
368     }
369
370     if (Writing) {
371         irp->Flags |= IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION;
372         irpSp->Parameters.Write.Length = Length;
373         irpSp->Parameters.Write.ByteOffset = *Offset;
374     } else {
375         irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;
376         irpSp->Parameters.Read.Length = Length;
377         irpSp->Parameters.Read.ByteOffset = *Offset;
378     }
379
380     /* set the Irp completion routine */
381     IoSetCompletionRoutine( irp, CompletionRoutine, 
382                             &event, TRUE, TRUE, TRUE);
383
384
385     /* issue the irp to the lower layer device */
386     status = IoCallDriver(deviceObject, irp);
387
388     /* Irp is to be cleaned up in the compleiton routine */
389     irp = NULL;
390
391     if (status == STATUS_PENDING) {
392
393         /* we need wait until operation is completed, then we can
394            get the returned status and information length */
395
396         status = KeWaitForSingleObject(
397                     &event,
398                     Executive,
399                     KernelMode,
400                     FALSE,
401                     NULL
402                     );
403         if (NT_SUCCESS(status)) {
404             status = iosb.Status;
405         }
406     }
407
408     if (NT_SUCCESS(status)) {
409         *Bytes = (ULONG)iosb.Information;
410     } else {
411         *Bytes = 0;
412     }
413
414 errorout:
415
416     if (fileObject) {
417         ObDereferenceObject(fileObject);
418     }
419
420     /* free the Irp in error case */
421     if (irp) {
422         IoFreeIrp(irp);
423     }
424
425     return status;
426 }
427
428 /*
429  * filp_read
430  *     To read data from the opened file
431  *
432  * Arguments:
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
438  *
439  * Return Value:
440  *   Actual size read into the buffer in success case
441  *   Error code in failure case
442  *
443  * Notes: 
444  *   N/A
445  */
446 int filp_read(struct file *fp, void *buf, size_t nbytes, loff_t *pos)
447 {
448     LARGE_INTEGER   offset;
449     NTSTATUS        status;
450     int             rc = 0;
451
452     /* Read data from the file into the specified buffer */
453     if (pos != NULL) {
454         offset.QuadPart = *pos;
455     } else {
456         offset.QuadPart = fp->f_pos;
457     }
458
459     status = cfs_nt_filp_io(fp->f_handle, 0, &offset,
460                             nbytes, buf, &rc);
461
462     if (!NT_SUCCESS(status)) {
463         rc = cfs_error_code(status);
464     }
465
466     if (rc > 0) {
467         fp->f_pos = offset.QuadPart + rc;
468         if (pos != NULL)
469             *pos = fp->f_pos;
470     }
471
472     return rc;
473 }
474
475 /*
476  * cfs_filp_wrtie
477  *     To write specified data to the opened file
478  *
479  * Arguments:
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
485  *
486  * Return Value:
487  *   Actual size written into the buffer in success case
488  *   Error code in failure case
489  *
490  * Notes: 
491  *   N/A
492  */
493
494 int filp_write(struct file *fp, void *buf, size_t nbytes, loff_t *pos)
495 {
496     LARGE_INTEGER   offset;
497     NTSTATUS        status;
498     int             rc = 0;
499
500     /* Read data from the file into the specified buffer */
501     if (pos != NULL) {
502         offset.QuadPart = *pos;
503     } else {
504         offset.QuadPart = fp->f_pos;
505     }
506
507     status = cfs_nt_filp_io(fp->f_handle, 1, &offset,
508                             nbytes, buf, &rc);
509
510     if (!NT_SUCCESS(status)) {
511         rc = cfs_error_code(status);
512     }
513
514     if (rc > 0) {
515         fp->f_pos = offset.QuadPart + rc;
516         if (pos != NULL)
517             *pos = fp->f_pos;
518     }
519
520     return rc;
521 }
522
523 /*
524  * filp_fsync
525  *     To sync the dirty data of the file to disk
526  *
527  * Arguments:
528  *   fp: the pointer of the file strcture
529  *
530  * Return Value:
531  *   Zero:  in success case
532  *   Error code: in failure case
533  *
534  * Notes: 
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
537  *   system driver.
538  */
539 int filp_fsync(struct file *fp)
540 {
541     PFILE_OBJECT            FileObject;
542     PDEVICE_OBJECT          DeviceObject;
543
544     NTSTATUS                Status;
545     PIRP                    Irp;
546     KEVENT                  Event;
547     IO_STATUS_BLOCK         IoSb;
548     PIO_STACK_LOCATION      IrpSp;
549
550     /* get the FileObject and the DeviceObject */
551     Status = ObReferenceObjectByHandle(
552                 fp->f_handle,
553                 FILE_WRITE_DATA,
554                 NULL,
555                 KernelMode,
556                 (PVOID*)&FileObject,
557                 NULL );
558
559     if (!NT_SUCCESS(Status)) {
560         return cfs_error_code(Status);
561     }
562
563     DeviceObject = IoGetRelatedDeviceObject(FileObject);
564
565     /* allocate a new Irp */
566     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
567     if (!Irp) {
568         ObDereferenceObject(FileObject);
569         return -ENOMEM;
570     }
571
572     /* intialize the event */
573     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
574
575     /* setup the Irp */
576     Irp->UserIosb = &IoSb;
577     Irp->RequestorMode = KernelMode;
578
579     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
580     Irp->Tail.Overlay.OriginalFileObject = FileObject;
581
582     /* setup the Irp stack location */
583     IrpSp = IoGetNextIrpStackLocation(Irp);
584
585     IrpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
586     IrpSp->DeviceObject = DeviceObject;
587     IrpSp->FileObject = FileObject;
588
589     IoSetCompletionRoutine( Irp, CompletionRoutine,
590                             &Event, TRUE, TRUE, TRUE);
591
592
593     /* issue the Irp to the underlying file system driver */
594     IoCallDriver(DeviceObject, Irp);
595
596     /* wait until it is finished */
597     KeWaitForSingleObject(&Event, Executive, KernelMode, TRUE, 0);
598
599     /* cleanup our reference on it */
600     ObDereferenceObject(FileObject);
601
602     Status = IoSb.Status;
603
604     return cfs_error_code(Status);
605 }
606
607 /*
608  * get_file
609  *     To increase the reference of the file object
610  *
611  * Arguments:
612  *   fp:   the pointer of the file strcture
613  *
614  * Return Value:
615  *   Zero:  in success case
616  *   Non-Zero: in failure case
617  *
618  * Notes: 
619  *   N/A
620  */
621
622 int get_file(struct file *fp)
623 {
624     InterlockedIncrement(&(fp->f_count));
625     return 0;
626 }
627
628
629 /*
630  * fput
631  *     To decrease the reference of the file object
632  *
633  * Arguments:
634  *   fp:   the pointer of the file strcture
635  *
636  * Return Value:
637  *   Zero:  in success case
638  *   Non-Zero: in failure case
639  *
640  * Notes:
641  *   N/A
642  */
643
644 int fput(struct file *fp)
645 {
646         if (InterlockedDecrement(&(fp->f_count)) == 0)
647                 filp_close(fp, NULL);
648
649         return 0;
650 }
651
652
653 /*
654  * file_count
655  *   To query the reference count of the file object
656  *
657  * Arguments:
658  *   fp:   the pointer of the file strcture
659  *
660  * Return Value:
661  *   the reference count of the file object
662  *
663  * Notes: 
664  *   N/A
665  */
666
667 int file_count(struct file *fp)
668 {
669         return (int)(fp->f_count);
670 }
671
672 struct dentry *dget(struct dentry *de)
673 {
674         if (de) {
675                 atomic_inc(&de->d_count);
676         }
677         return de;
678 }
679
680 void dput(struct dentry *de)
681 {
682     if (!de || atomic_read(&de->d_count) == 0) {
683         return;
684     }
685     if (atomic_dec_and_test(&de->d_count)) {
686         kfree(de);
687     }
688 }