diff --git a/.cproject b/.cproject index edb5d25..815670f 100644 --- a/.cproject +++ b/.cproject @@ -23,13 +23,13 @@ - - - - @@ -67,7 +67,7 @@ - + diff --git a/.gitignore b/.gitignore index 52e078a..9dd6869 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ t t.c *.o +*.so .depen* /sys/sde/objgfx40.cpp /sys/sde/ogFont.cpp diff --git a/.project b/.project index e87f5c8..cb35fff 100644 --- a/.project +++ b/.project @@ -8,6 +8,11 @@ + org.eclipse.mylyn.wikitext.ui.wikiTextValidationBuilder + + + + org.eclipse.wst.common.project.facet.core.builder @@ -31,5 +36,6 @@ org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature org.eclipse.wst.common.project.facet.core.nature + org.eclipse.mylyn.wikitext.ui.wikiTextNature diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..e167325 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/DEBUG.markdown=utf-8 diff --git a/.settings/org.eclipse.mylyn.team.ui.prefs b/.settings/org.eclipse.mylyn.team.ui.prefs new file mode 100644 index 0000000..d0cd1c0 --- /dev/null +++ b/.settings/org.eclipse.mylyn.team.ui.prefs @@ -0,0 +1,2 @@ +commit.comment.template=${task.key}\: ${task.description} \r\n\r\nTask-Url\: ${task.url} +eclipse.preferences.version=1 diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs new file mode 100644 index 0000000..314d147 --- /dev/null +++ b/.settings/org.eclipse.wst.validation.prefs @@ -0,0 +1,8 @@ +DELEGATES_PREFERENCE=delegateValidatorList +USER_BUILD_PREFERENCE=enabledBuildValidatorList +USER_MANUAL_PREFERENCE=enabledManualValidatorList +USER_PREFERENCE=overrideGlobalPreferencesfalse +eclipse.preferences.version=1 +override=false +suspend=false +vf.version=3 diff --git a/DEBUG.markdown b/DEBUG.markdown new file mode 100644 index 0000000..a7b9560 --- /dev/null +++ b/DEBUG.markdown @@ -0,0 +1,6 @@ +1. First ordered list item +2. Another item + ..* Unordered sub-list. +3. Actual numbers don't matter, just that it's a number + ..1. Ordered sub-list +4. And another item. diff --git a/DEBUG.md b/DEBUG.md new file mode 100644 index 0000000..d94528d --- /dev/null +++ b/DEBUG.md @@ -0,0 +1,6 @@ +#Debug Info + +##Defines +DEBUG_EXEC - Exec Debug +DEBUG_VFS - VFS DEBUG +DEBUG_SYSCTL - SYSCTL DEBUG diff --git a/Dump/Ubix-CLOUDNINE.flp b/Dump/Ubix-CLOUDNINE.flp new file mode 100644 index 0000000..d18d75f --- /dev/null +++ b/Dump/Ubix-CLOUDNINE.flp Binary files differ diff --git a/Dump/UbixOS-080504.flp b/Dump/UbixOS-080504.flp new file mode 100644 index 0000000..2462273 --- /dev/null +++ b/Dump/UbixOS-080504.flp Binary files differ diff --git a/Dump/hybos/Makefile b/Dump/hybos/Makefile new file mode 100644 index 0000000..d90ac30 --- /dev/null +++ b/Dump/hybos/Makefile @@ -0,0 +1,11 @@ +MAKEFILE=Makefile + +all: + make -f $(MAKEFILE) -C src + +install: + make -f $(MAKEFILE) -C src install + +clean: + make -f $(MAKEFILE) -C lib clean + make -f $(MAKEFILE) -C src clean diff --git a/Dump/hybos/README.txt b/Dump/hybos/README.txt new file mode 100644 index 0000000..4e5a00e --- /dev/null +++ b/Dump/hybos/README.txt @@ -0,0 +1,210 @@ +OSD demo code - Interim release (January, 2003) + +I am working a new set of kernels, but it's slow going, so here +are the old kernels with some bug fixes and improvements. + +Location of these files: http://www.execpc.com/~geezer/osd/code + +The GRUB bootloader is GPL, all other files are PUBLIC DOMAIN +(no copyright). You may do whatever you want with them. + +================================================================ +QUICK START +================================================================ +1. Make sure you have all the software tools you need. You need NASM: + http://nasm.sourceforge.net + + You need the GNU C compiler (GCC), including binutils, GNU Make, + and sed. Users of DOS and Win9x should get GCC for DOS (DJGPP): + http://www.delorie.com/djgpp + + Find a mirror site near you and download the following + packages (NNN is version number): + compiler v2gnu/gccNNNNb.zip + binutils v2gnu/bnuNNNNb.zip + libraries v2/djdevNNN.zip + Make v2gnu/makNNNNb.zip + sed v2gnu/sedNNb.zip + CWSDPMI v2misc/csdpmiN.zip + + Users of WinNT/Win2000/WinXP should get GCC for Win32 (MinGW): + http://mingw.sourceforge.net + + Users of Linux can use the GNU tools that come with Linux. If + they're not already installed, check the CD-ROMs or FTP site + from where you got Linux. + + DOS and Windows users also need John Fine's Partial Copy (PARTCOPY): + http://www.execpc.com/~geezer/johnfine/#zero + +2. Create a formatted floppy disk with the GRUB bootloader + installed on it. The procedure to do this is described below. + +3. Got your tools? Got your GRUB floppy? Then you're ready to + build and install the demo kernels. + + If you're using DJGPP, type make -f dj.mak install + + If you're using MinGW, type make -f ming.mak install + + If you're using Linux, type make -f linux.mak install + +Hopefully, everything will work properly. If it does, you'll be +left with a bootable GRUB floppy with 7 demo kernels on it +(OSD 3 - OSD 9). + +================================================================ +MAKING A BOOTABLE FLOPPY DISK WITH THE GRUB BOOTLOADER ON IT +================================================================ +GRUB is a GPLed bootloader. + +Home page: http://www.gnu.org/software/grub +Binaries: ftp://alpha.gnu.org/gnu/grub/grub-0.90-i386-pc.tar.gz +Source code: ftp://alpha.gnu.org/gnu/grub/grub-0.90.tar.gz +HOW-TOs: http://www.washingdishes.freeuk.com/grubtut.html + http://www.execpc.com/~geezer/osd/boot/grub-how.txt + +1. You will need + - Two 1.44 meg floppy disks, one of them formatted with a + filesystem that GRUB recognizes (e.g. FAT12 or ext2). + The other floppy (the "unformatted" floppy) may contain + a filesystem, but it will be destroyed. + - The GRUB binaries: files "stage1" and "stage2". These are + in the OSD distribution, in the directory "boot/grub". + - A "menu.lst" configuration file for GRUB. Again, this + is provided with OSD in the "boot/grub" directory. + +2. On the formatted floppy disk, create the subdirectory + "/boot/grub/", and copy the files "stage1", "stage2", and + "menu.lst" into this subdirectory. + +3. Concatenate the binary files "stage1" and "stage2" into a + single binary file named "boot": + (DOS/Windows): copy /b stage1 + stage2 boot + (Linux): cat stage1 stage2 >boot + +4. Write the file "boot" directly to the unformatted floppy. + This is a sector-level write that does not use (and will + destroy) any filesystem present on the disk: + (DOS/Windows): partcopy boot 0 168000 -f0 + (Linux): cat boot >/dev/fd0 + + PARTCOPY will display an error message because "boot" is + much shorter than 0x168000 bytes, but this is OK. + +5. Boot your PC from the unformatted floppy disk. + +6. After GRUB has started, eject the unformatted floppy and + insert the formatted floppy, containing the "stage1", + "stage2", and "menu.lst" files, all in the "/boot/grub/" + subdirectory. Type: + setup (fd0) + +7. The formatted floppy is now bootable. Do not move, modify, + or delete the file "/boot/grub/stage2" on this floppy. + +================================================================ +BUGS/GOTCHAS/"IT DOESN'T WORK!" +================================================================ +- DJGPP crashes under Windows XP + The DJGPP team is working on a way to fix this. If you have + any flavor of WindowsNT (including WindowsXP) use MinGW + instead of DJGPP. + +- Will CygWin work instead of MinGW? + Probably, but I haven't tested it. + +- 'make -f ming.mak clean' doesn't delete .o files in /lib/ + I know, but I can't figure out how to fix it. Make sure + these files get deleted if you switch between MinGW and + DJGPP. The linkers can't distinguish between DJGPP COFF + .o files and Win32 PE COFF .o files, but they ARE different, + and your kernels will crash if you mix the two COFF types. + +- BFD: Dwarf Error: Abbrev offset (1075154) greater than or + equal to .debug_abbrev size (3198). + This is a bug in new versions of DJGPP. It's ugly, but you + can ignore it. + +- Do not use MinGW GCC 2.x with NASM + MinGW based on GCC 2.95.2 stores the BSS size in the wrong + field of the section header. Because of this bug, this + version of MinGW will not interoperate with other toolchains, + including NASM, Microsoft compilers, and Borland compilers. + +- Screen fills with errors when compiling under Linux + There are two possible causes for this: + 1. Linux GCC chokes on DOS-style newlines in the source code. + Run all source code files and makefiles through 'fromdos' + to convert the DOS newlines (CR-LF) to UNIX newlines (LF). + 2. There is no newline at the very end of the file. + +- ld: krnl.x: Not enough room for program headers, try linking with -N + This error occurs if you do not use AT() in the linker script + when making an ELF kernel. + +- Exception 10 (bad TSS) + If the NT bit in the EFLAGS register is set, IRET will attempt + a TSS-based task-switch, instead of a normal IRET. Code was + added to osd9/kstart.asm to prevent this. (GRUB 0.90 leaves + the NT bit set when it jumps to the kernel.) + +- Errors from GRUB: + 'Error: Loading below 1M not supported' + 'Error 28: Selected item won't fit into memory' + These errors are usually caused by improperly-linked ELF + kernels. If your kernel is ELF, try this: + objdump --private-headers -h krnl.x + The vaddr and paddr fields for each program header (segment) + must be at or above 1 meg (00100000h) but smaller than your + RAM size. If you have readelf, you can also do this: + readelf --segments krnl.x + If you find a segment with bad values of VirtAddr or + PhysAddr, look at the section-to-segment mapping to see + which section is causing the problem. + +================================================================ +DEMO CODE OVERVIEW +================================================================ +osd3 mixing C and asm, C calling convention, underscores + (xxx - current code does not demonstrate these very well) + +osd4 putch() and kprintf() + +osd5 C library code moved to separate directory + +osd6 software interrupts, exception handlers in asm and C + +osd7 hardware interrupts, reprogramming the 8259 interrupt + controller chips, simple keyboard driver + +osd8 multitasking preliminaries: multiple (virtual) consoles + backed with video memory, ANSI/VT escapes for moving + the cursor and changing text color. Improved keyboard + driver; can press Ctrl+Alt+Del to reboot. + +osd9 cooperative multitasking with setjmp() and longjump() + (static tasks; linked into the kernel at compile-time) + +================================================================ +WHAT CHANGED? +================================================================ +- Updated GRUB to version 0.90 +- Wrote MinGW makefiles, and fixed code to work with MinGW + based on GCC 3.x (and generate error message for GCC 2.x) +- Fixed definition of MAKEFILE in lib/linux.mak +- BIG changes to linker script + - Unified ELF/DJGPP COFF/Win32 PE COFF linker scripts into one + - Added AT() statements so ELF kernels link properly, and + work properly + - Now handling .rodata section properly, so ELF kernels work + properly (including multiple .rodata sections with GCC 3.x) +- Rewrote setjmp() and longjmp() because they were buggy (though, + strangely enough, the bug did not manifest itself) +- Added code to osd9/kstart.asm to zero NT bit in EFLAGS, + preventing exception 10 +- Now enabling interrupts for each task in function init_tasks() + of osd9/sched.c. In previous code, interrupts were disabled + for all tasks except the idle task, making the blinking + character in the upper left corner of the screen appear to + blink much more slowly than 18 Hz. diff --git a/Dump/hybos/__experimental/README.txt b/Dump/hybos/__experimental/README.txt new file mode 100644 index 0000000..d2b1a8d --- /dev/null +++ b/Dump/hybos/__experimental/README.txt @@ -0,0 +1,87 @@ +Sector-level disk I/O code for various OSes + +This code is public domain (no copyright). +You can do whatever you want with it. + +Chris Giese http://www.execpc.com/~geezer + +================================================================ +BUILD +================================================================ +After a successful build, the executable is named 'diskio.exe' + +DOS - Turbo C++ 1.0 or Turbo C++ 3.0: + make + +DOS - Watcom C: + wmake /f watcom16.mak + +32-bit DOS - DJGPP: + make -f djgpp.mak + +32-bit DOS - Watcom C with CauseWay DOS extender: + wmake /f watcom32.mak + +NOTE: 32-bit code built with Watcom C does not yet work. + +Windows NT - MinGW or CygWin: + make -f win-nt.mak + +NOTE: Windows NT version is not tested. + +Linux - GCC: + xxx - to do + +If you have Windows9x, build and run this code as a DOS program, +not a Win32 program. + +================================================================ +API +================================================================ +/* disk_t, open_disk(), read_sector(), write_sector() */ +#include "diskio.h" + +int main(void) { + unsigned long lba_sector_num; + unsigned char buf[512]; + unsigned drive; + disk_t disk; + +/* drive values for floppies: + 0 for A:, 1 for B:, etc. +drive values for hard drives: + 0x80 for first hard drive, 0x81 for second hard drive, etc. */ + drive = 0; +/* read hard drive partition table or floppy boot sector */ + lba_sector_num = 0; + if(open_disk(&disk, drive) == 0) + if(read_sector(&disk, lba_sector_num, buf) == 0) + /* success */; + return 0; } + +================================================================ +TO DO +================================================================ +Test if code writes to disk properly + +Test Windows NT version +- See if the following work with Windows NT: + - 1.44 meg FAT12 floppy (my guess: YES) + - 1.68 meg FAT12 floppy (my guess: YES) + - 1.44 meg non-FAT (e.g. ext2) floppy (my guess: YES) + - 1.68 meg non-FAT floppy (my guess: NO) +- Is there a Windows NT ioctl() to get floppy disk geometry? + Does it work for non-FAT floppy disks? (How do I make NT read + a 1.68 meg non-FAT floppy?) + +Make it work with Linux + +Make it work with 32-bit Watcom C + +Maybe add a disk cache + +Maybe support disks with sector size other than 512 bytes +(e.g. 2048-byte CD-ROM sectors)? + +Any way to access CD-ROM with INT 13h functions? +WITHOUT booting from the CD-ROM? diff --git a/Dump/hybos/__experimental/demo.c b/Dump/hybos/__experimental/demo.c new file mode 100644 index 0000000..7704645 --- /dev/null +++ b/Dump/hybos/__experimental/demo.c @@ -0,0 +1,94 @@ +/***************************************************************************** +Sector-level disk I/O code for various OSes +This code is public domain (no copyright). +You can do whatever you want with it. +*****************************************************************************/ +#include /* printf(), putchar() */ +#include "diskio.h" +/***************************************************************************** +*****************************************************************************/ +#define BPERL 16 /* byte/line for dump */ + +static void dump(unsigned char *data, unsigned count) +{ + unsigned char byte1, byte2; + + while(count != 0) + { + for(byte1 = 0; byte1 < BPERL; byte1++) + { + if(count == 0) + break; + printf("%02X ", data[byte1]); + count--; + } + printf("\t"); + for(byte2 = 0; byte2 < byte1; byte2++) + { + if(data[byte2] < ' ') + putchar('.'); + else + putchar(data[byte2]); + } + printf("\n"); + data += BPERL; + } +} +/***************************************************************************** +*****************************************************************************/ +int main(void) +{ + unsigned char buf[512], *ptab_rec; + unsigned i = 0; + disk_t disk; + + printf("Looking for FAT (DOS) disk or partition...\n"); +/* check if floppy in A: drive */ + if(open_disk(&disk, 0) == 0) + { +/* read bootsector, check if FAT */ + if(read_sector(&disk, 0, buf) == 0) + { + if(is_fat_bootsector(buf)) + goto OK; + } + } +/* scan hard drives for FAT partition */ + for(i = 0x80; i < 0x82; i++) + { + if(open_disk(&disk, i) != 0) + continue; +/* read MBR */ + if(read_sector(&disk, 0, buf) != 0) + continue; +/* find FAT partition */ + for(i = 0; i < 4; i++) + { + ptab_rec = buf + 446 + 16 * i; +/* make sure it's FAT */ + if(ptab_rec[4] == 0x01 || /* FAT 12 */ + ptab_rec[4] == 0x04 || /* FAT 16 <32meg */ + ptab_rec[4] == 0x06 || /* FAT 16 >=32meg */ + ptab_rec[4] == 0x0E) /* LBA type 0x06 */ + { +/* xxx - note if FAT16 or FAT12 */ + disk.partition_start = LE32(ptab_rec + 8); + goto OK; + } + } + } + printf("No FAT partitions found on any disk\n"); + return 1; +OK: + if(disk.drive_num >= 0x80) + printf("Partition #%u on ", i); + printf("INT 13h disk number 0x%02X:\n", disk.drive_num); + if(read_sector(&disk, 0, buf) != 0) + printf("Error reading bootsector\n"); + else + { + printf("Hex dump of bootsector:\n"); + dump(buf, 64); + } + return 0; +} diff --git a/Dump/hybos/__experimental/diskio.h b/Dump/hybos/__experimental/diskio.h new file mode 100644 index 0000000..90247e3 --- /dev/null +++ b/Dump/hybos/__experimental/diskio.h @@ -0,0 +1,59 @@ +/***************************************************************************** +Sector-level disk I/O code for various OSes +This code is public domain (no copyright). +You can do whatever you want with it. + +EXPORTS (API): +DEBUG(), BPS, LE16(), LE32(), disk_t, +int read_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int write_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int is_fat_bootsector(unsigned char *buf); +int open_disk(disk_t *disk, unsigned drive_num); +*****************************************************************************/ +#ifndef __DISKIO_H +#define __DISKIO_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if 0 +#define DEBUG(X) X +#else +#define DEBUG(X) /* nothing */ +#endif + +#define BPS 512 /* bytes/sector */ + +/* these assume little endian CPU like x86 */ +#define LE16(X) *(uint16_t *)(X) +#define LE32(X) *(uint32_t *)(X) + +/* STDINT.H +these assume sizeof(short)==2 and sizeof(long)==4 */ +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; + +typedef struct +{ + unsigned char drive_num; +/* CHS disk geometry (heads and sectors are used only if use_lba==0) */ + unsigned use_lba : 1; + unsigned char heads; + unsigned char sectors; +/* LBA sector address of partition start (hard disk only) */ + unsigned long partition_start; +} disk_t; + +/* these are in DISKIO.C */ +int read_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int write_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int is_fat_bootsector(unsigned char *buf); +int open_disk(disk_t *disk, unsigned drive_num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/__experimental/djgpp.c b/Dump/hybos/__experimental/djgpp.c new file mode 100644 index 0000000..70f04b5 --- /dev/null +++ b/Dump/hybos/__experimental/djgpp.c @@ -0,0 +1,131 @@ +/***************************************************************************** +Sector-level disk I/O code for DOS, using DJGPP. +This code is public domain (no copyright). +You can do whatever you want with it. + +EXPORTS: +int lba_biosdisk(int cmd, int drive, unsigned long lba, + int nsects, void *buf); +int get_hd_geometry(disk_t *disk); +*****************************************************************************/ +#include /* dosmemget(), dosmemput() */ +#include /* memset() */ +#include /* printf() */ +#include /* _DISK_... */ +#include /* __dpmi_regs, __dpmi_int() */ +#include /* _go32_info_block, __tb */ +#include "diskio.h" +#include "dos.h" /* peekb() */ +/***************************************************************************** +*****************************************************************************/ +int lba_biosdisk(int cmd, int drive, unsigned long lba, int nsects, void *buf) +{ + struct + { + unsigned char pkt_len __attribute__((packed)); + unsigned char res0 __attribute__((packed)); + unsigned char nsects __attribute__((packed)); + unsigned char res1 __attribute__((packed)); + unsigned short buf_off __attribute__((packed)); + unsigned short buf_seg __attribute__((packed)); + unsigned long lba31_0 __attribute__((packed)); + unsigned long lba63_32 __attribute__((packed)); + } lba_cmd_pkt; + unsigned tries, err = 0; + __dpmi_regs regs; + + if(cmd != _DISK_READ && cmd != _DISK_WRITE) + return 0x100; +/* make sure the DJGPP transfer buffer (in conventional memory) +is big enough */ + if(BPS * nsects + sizeof(lba_cmd_pkt) > + _go32_info_block.size_of_transfer_buffer) + return 0x100; +/* make sure drive and BIOS support LBA */ + regs.x.bx = 0x55AA; + regs.h.dl = drive; + regs.h.ah = 0x41; + __dpmi_int(0x13, ®s); + if(regs.x.flags & 0x0001) /* carry bit (CY) is set */ + return 0x100; +/* fill out the INT 13h AH=4xh command packet */ + memset(&lba_cmd_pkt, 0, sizeof(lba_cmd_pkt)); + lba_cmd_pkt.pkt_len = sizeof(lba_cmd_pkt); + lba_cmd_pkt.nsects = nsects; +/* use start of transfer buffer for data transferred by BIOS disk I/O... */ + lba_cmd_pkt.buf_off = 0; + lba_cmd_pkt.buf_seg = __tb >> 4; + lba_cmd_pkt.lba31_0 = lba; +/* ...use end of transfer buffer for the command packet itself */ + dosmemput(&lba_cmd_pkt, sizeof(lba_cmd_pkt), + __tb + BPS * nsects); +/* fill out registers for INT 13h AH=4xh */ + regs.x.ds = (__tb + BPS * nsects) >> 4; + regs.x.si = (__tb + BPS * nsects) & 0x0F; + regs.h.dl = drive; +/* if writing, store the data */ + if(cmd == _DISK_WRITE) + dosmemput(buf, BPS * nsects, __tb); +/* make 3 attempts */ + for(tries = 3; tries != 0; tries--) + { + regs.h.ah = (cmd == _DISK_READ) ? 0x42 : 0x43; + __dpmi_int(0x13, ®s); + err = regs.h.ah; + if((regs.x.flags & 0x0001) == 0) + { +/* if reading, load the data */ + if(cmd == _DISK_READ) + dosmemget(__tb, BPS * nsects, buf); + return 0; + } +/* reset disk */ + regs.h.ah = _DISK_RESET; + __dpmi_int(0x13, ®s); + } + DEBUG(printf("lba_biosdisk(): error 0x%02X\n", err);) + return err; +} +/***************************************************************************** +*****************************************************************************/ +int get_hd_geometry(disk_t *disk) +{ + __dpmi_regs regs; + +/* make sure hard drive exists */ + if(disk->drive_num - 0x80 >= peekb(0x40, 0x75)) + { + printf("get_hd_geometry(): hd 0x%02X does not exist\n", + disk->drive_num); + return -1; + } +/* use LBA if drive and BIOS support it */ + regs.h.ah = 0x41; + regs.x.bx = 0x55AA; + regs.h.dl = disk->drive_num; + __dpmi_int(0x13, ®s); + if((regs.x.flags & 0x0001) == 0 && regs.x.bx == 0xAA55) + { + disk->use_lba = 1; + DEBUG(printf("get_hd_geometry(): using LBA for hd 0x%02X\n", + disk->drive_num);) + return 0; + } +/* get geometry from BIOS */ + regs.h.ah = 0x08; + regs.h.dl = disk->drive_num; + __dpmi_int(0x13, ®s); + if(regs.x.flags & 0x0001) + { + printf("get_hd_geometry(): error getting geometry " + "for hard drive 0x%02X\n", disk->drive_num); + return -1; + } + disk->heads = regs.h.dh + 1; + disk->sectors = regs.h.cl & 0x3F; + DEBUG(printf("get_hd_geometry() for hd 0x%02X: " + "CHS=?:%u:%u (from INT 13h AH=08h)\n", + disk->drive_num, + disk->heads, disk->sectors);) + return 0; +} diff --git a/Dump/hybos/__experimental/djgpp.mak b/Dump/hybos/__experimental/djgpp.mak new file mode 100644 index 0000000..b5d3d96 --- /dev/null +++ b/Dump/hybos/__experimental/djgpp.mak @@ -0,0 +1,28 @@ +# Makefile for 32-bit DOS - DJGPP + +# defines +# MAKEDEP =makefile +CC =gcc -g -O2 -Wall -W +LD =gcc -g +OBJS =demo.o dos.o djgpp.o + +# targets +all: diskio.exe + +clean: + deltree /y *.exe *.obj *.o *.err + +# implicit rules +.c.o: + $(CC) -c -o$@ $< + +# dependencies +demo.o: demo.c $(MAKEDEP) diskio.h + +dos.o: dos.c $(MAKEDEP) diskio.h dos.h + +djgpp.o: djgpp.c $(MAKEDEP) diskio.h dos.h + +# explicit rules +diskio.exe: $(OBJS) $(MAKEDEP) + $(LD) -o$@ $(OBJS) diff --git a/Dump/hybos/__experimental/dos.c b/Dump/hybos/__experimental/dos.c new file mode 100644 index 0000000..c101dae --- /dev/null +++ b/Dump/hybos/__experimental/dos.c @@ -0,0 +1,256 @@ +/***************************************************************************** +Sector-level disk I/O code for DOS. +This code is public domain (no copyright). +You can do whatever you want with it. + +EXPORTS: +int read_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int write_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int is_fat_bootsector(unsigned char *buf); +int open_disk(disk_t *disk, unsigned drive_num); +*****************************************************************************/ +#include /* printf() */ +/*#include */ /* _DISK_..., diskinfo_t, _bios_disk() */ +#include "diskio.h" +#include "dos.h" /* peekw() */ + +/* IMPORTS +from _16BIT.C, DJGPP, or ??? */ +int lba_biosdisk(int cmd, int drive, unsigned long lba, int nsects, void *buf); +int get_hd_geometry(disk_t *disk); + +/* xxx - I'm not sure of the Turbo C version where these were +introduced. They are present in Turbo C++ 3.0 (__TURBOC__ == 0x401) +but not in Turbo C++ 1.0 (__TURBOC__ == 0x296) */ +#if defined(__TURBOC__) +#if __TURBOC__<0x300 + +struct diskinfo_t +{ + unsigned drive, head, track, sector, nsectors; + void far *buffer; +}; + +unsigned _bios_disk(unsigned cmd, struct diskinfo_t *info) +{ + struct SREGS sregs; + union REGS regs; + +/* biosdisk() returns the 8-bit error code left in register AH by +the call to INT 13h. It does NOT return a combined, 16-bit error +code + number of sectors transferred, as described in the online help. + + return biosdisk(cmd, info->drive, info->head, info->track, + info->sector, info->nsectors, info->buffer); +*/ + regs.h.ah = cmd; + regs.h.al = info->nsectors; + regs.x.bx = FP_OFF(info->buffer); + regs.h.ch = info->track; + regs.h.cl = (info->track / 256) * 64 + (info->sector & 0x3F); + regs.h.dh = info->head; + regs.h.dl = info->drive; + sregs.es = FP_SEG(info->buffer); + int86x(0x13, ®s, ®s, &sregs); + return regs.x.ax; +} +#endif +#endif +/***************************************************************************** +*****************************************************************************/ +int read_sector(disk_t *disk, unsigned long lba, unsigned char *buf) +{ + struct diskinfo_t cmd; + unsigned tries, err; + + lba += disk->partition_start; + cmd.drive = disk->drive_num; +/* use LBA if available */ + if(disk->use_lba) + { + return lba_biosdisk(_DISK_READ, + disk->drive_num, lba, 1, buf); + } +/* use CHS _bios_disk() */ + cmd.sector = (unsigned)(lba % disk->sectors + 1); + cmd.head = (unsigned)((lba / disk->sectors) % disk->heads); + cmd.track = (unsigned)((lba / disk->sectors) / disk->heads); + cmd.nsectors = 1; + cmd.buffer = buf; +/* make 3 attempts */ + for(tries = 3; tries != 0; tries--) + { + err = _bios_disk(_DISK_READ, &cmd); + err >>= 8; +/* 0x11=="CRC/ECC corrected data error" */ + if(err == 0 || err == 0x11) + return 0; +/* reset disk */ + _bios_disk(_DISK_RESET, &cmd); + } + DEBUG(printf("read_sector(): error 0x%02X\n", err);) + return err; +} +/***************************************************************************** +*****************************************************************************/ +int write_sector(disk_t *disk, unsigned long lba, unsigned char *buf) +{ + struct diskinfo_t cmd; + unsigned tries, err; + + lba += disk->partition_start; + cmd.drive = disk->drive_num; +/* use LBA if available */ + if(disk->use_lba) + { + return lba_biosdisk(_DISK_WRITE, + disk->drive_num, lba, 1, buf); + } +/* use CHS _bios_disk() */ + cmd.sector = (unsigned)(lba % disk->sectors + 1); + cmd.head = (unsigned)((lba / disk->sectors) % disk->heads); + cmd.track = (unsigned)((lba / disk->sectors) / disk->heads); + cmd.nsectors = 1; + cmd.buffer = buf; +/* make 3 attempts */ + for(tries = 3; tries != 0; tries--) + { + err = _bios_disk(_DISK_WRITE, &cmd); + err >>= 8; +/* 0x11=="CRC/ECC corrected data error" */ + if(err == 0 || err == 0x11) + return 0; +/* reset disk */ + _bios_disk(_DISK_RESET, &cmd); + } + DEBUG(printf("write_sector(): error 0x%02X\n", err);) + return err; +} +/***************************************************************************** +*****************************************************************************/ +int is_fat_bootsector(unsigned char *buf) +{ + int temp, ok = 1; + + DEBUG(printf("check_if_fat_bootsector:\n");) +/* must start with 16-bit JMP or 8-bit JMP plus NOP */ + if(buf[0] == 0xE9) + /* OK */; + else if(buf[0] == 0xEB && buf[2] == 0x90) + /* OK */; + else + { + DEBUG(printf("\tMissing JMP/NOP\n");) + ok = 0; + } + temp = buf[13]; + if(temp == 0 || ((temp - 1) & temp) != 0) + { + DEBUG(printf("\tSectors per cluster (%u) " + "is not a power of 2\n", temp);) + ok = 0; + } + temp = buf[16]; + temp = LE16(buf + 24); + if(temp == 0 || temp > 63) + { + DEBUG(printf("\tInvalid number of sectors (%u)\n", temp);) + ok = 0; + } + temp = LE16(buf + 26); + if(temp == 0 || temp > 255) + { + DEBUG(printf("\tInvalid number of heads (%u)\n", temp);) + ok = 0; + } + return ok; +} +/***************************************************************************** +*****************************************************************************/ +static void probe_floppy_geometry(disk_t *disk) +{ + unsigned sectors, heads; + unsigned char buf[BPS]; + +/* scan upwards for sector number where read fails */ + disk->sectors = 64 + 1; + for(sectors = 1; sectors <= 64; sectors++) + { + if(read_sector(disk, sectors - 1, buf) != 0) + break; + } + disk->sectors = sectors - 1; +#if 1 +disk->heads = 2; +#else +/* scan upwards for head number where read fails +xxx - this probing for number of heads doesn't work */ + disk->heads = 16 + 1; + for(heads = 1; heads < 16; heads++) + { + if(read_sector(disk, heads * disk->sectors, buf) != 0) + break; + } + disk->heads = heads; +#endif +/* reset drive by reading sector 0 */ + (void)read_sector(disk, 0, buf); + DEBUG(printf("probe_floppy_geometry() for fd 0x%02X: " + "CHS=?:%u:%u\n", disk->drive_num, + disk->heads, disk->sectors);) +} +/***************************************************************************** +*****************************************************************************/ +int open_disk(disk_t *disk, unsigned drive_num) +{ + unsigned char buf[BPS]; + unsigned num_fds; + int err; + + disk->drive_num = drive_num; + disk->partition_start = 0; /* assume floppy */ + disk->use_lba = 0; /* assume CHS */ +/* hard disk */ + if(disk->drive_num >= 0x80) + return get_hd_geometry(disk); +/* make sure floppy drive exists */ + num_fds = peekw(0x40, 0x10); + if(num_fds & 0x0001) + num_fds = ((num_fds / 64) & 3) + 1; + else + num_fds = 0; + if(disk->drive_num >= num_fds) + { + printf("open_disk(): fd 0x%02X does not exist\n", + disk->drive_num); + return -1; + } +/* temporary values to make read_sector(0) work */ + disk->heads = disk->sectors = 1; + err = read_sector(disk, 0, buf); + if(err != 0) + return err; +/* if it's a FAT (DOS) disk, we get can reliable geometry info +from the BIOS parameter block (BPB) in the bootsector */ + if(is_fat_bootsector(buf)) + { + disk->heads = LE16(buf + 26); + disk->sectors = LE16(buf + 24); + DEBUG(printf("open_disk() for fd 0x%02X: " + "CHS=?:%u:%u (from BPB)\n", + disk->drive_num, + disk->heads, disk->sectors);) + return 0; + } +#if 0 +/* ...otherwise, do slow probe */ + probe_floppy_geometry(disk); +#else +/* ...or just assume some values */ + disk->heads = 2; + disk->sectors = 18; + DEBUG(printf("open_disk() for fd 0x%02X: " + "assuming CHS=?:2:18\n", disk->drive_num);) +#endif + return 0; +} diff --git a/Dump/hybos/__experimental/dos.c~ b/Dump/hybos/__experimental/dos.c~ new file mode 100644 index 0000000..0ce7f4a --- /dev/null +++ b/Dump/hybos/__experimental/dos.c~ @@ -0,0 +1,256 @@ +/***************************************************************************** +Sector-level disk I/O code for DOS. +This code is public domain (no copyright). +You can do whatever you want with it. + +EXPORTS: +int read_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int write_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int is_fat_bootsector(unsigned char *buf); +int open_disk(disk_t *disk, unsigned drive_num); +*****************************************************************************/ +#include /* printf() */ +#include /* _DISK_..., diskinfo_t, _bios_disk() */ +#include "diskio.h" +#include "dos.h" /* peekw() */ + +/* IMPORTS +from _16BIT.C, DJGPP, or ??? */ +int lba_biosdisk(int cmd, int drive, unsigned long lba, int nsects, void *buf); +int get_hd_geometry(disk_t *disk); + +/* xxx - I'm not sure of the Turbo C version where these were +introduced. They are present in Turbo C++ 3.0 (__TURBOC__ == 0x401) +but not in Turbo C++ 1.0 (__TURBOC__ == 0x296) */ +#if defined(__TURBOC__) +#if __TURBOC__<0x300 + +struct diskinfo_t +{ + unsigned drive, head, track, sector, nsectors; + void far *buffer; +}; + +unsigned _bios_disk(unsigned cmd, struct diskinfo_t *info) +{ + struct SREGS sregs; + union REGS regs; + +/* biosdisk() returns the 8-bit error code left in register AH by +the call to INT 13h. It does NOT return a combined, 16-bit error +code + number of sectors transferred, as described in the online help. + + return biosdisk(cmd, info->drive, info->head, info->track, + info->sector, info->nsectors, info->buffer); +*/ + regs.h.ah = cmd; + regs.h.al = info->nsectors; + regs.x.bx = FP_OFF(info->buffer); + regs.h.ch = info->track; + regs.h.cl = (info->track / 256) * 64 + (info->sector & 0x3F); + regs.h.dh = info->head; + regs.h.dl = info->drive; + sregs.es = FP_SEG(info->buffer); + int86x(0x13, ®s, ®s, &sregs); + return regs.x.ax; +} +#endif +#endif +/***************************************************************************** +*****************************************************************************/ +int read_sector(disk_t *disk, unsigned long lba, unsigned char *buf) +{ + struct diskinfo_t cmd; + unsigned tries, err; + + lba += disk->partition_start; + cmd.drive = disk->drive_num; +/* use LBA if available */ + if(disk->use_lba) + { + return lba_biosdisk(_DISK_READ, + disk->drive_num, lba, 1, buf); + } +/* use CHS _bios_disk() */ + cmd.sector = (unsigned)(lba % disk->sectors + 1); + cmd.head = (unsigned)((lba / disk->sectors) % disk->heads); + cmd.track = (unsigned)((lba / disk->sectors) / disk->heads); + cmd.nsectors = 1; + cmd.buffer = buf; +/* make 3 attempts */ + for(tries = 3; tries != 0; tries--) + { + err = _bios_disk(_DISK_READ, &cmd); + err >>= 8; +/* 0x11=="CRC/ECC corrected data error" */ + if(err == 0 || err == 0x11) + return 0; +/* reset disk */ + _bios_disk(_DISK_RESET, &cmd); + } + DEBUG(printf("read_sector(): error 0x%02X\n", err);) + return err; +} +/***************************************************************************** +*****************************************************************************/ +int write_sector(disk_t *disk, unsigned long lba, unsigned char *buf) +{ + struct diskinfo_t cmd; + unsigned tries, err; + + lba += disk->partition_start; + cmd.drive = disk->drive_num; +/* use LBA if available */ + if(disk->use_lba) + { + return lba_biosdisk(_DISK_WRITE, + disk->drive_num, lba, 1, buf); + } +/* use CHS _bios_disk() */ + cmd.sector = (unsigned)(lba % disk->sectors + 1); + cmd.head = (unsigned)((lba / disk->sectors) % disk->heads); + cmd.track = (unsigned)((lba / disk->sectors) / disk->heads); + cmd.nsectors = 1; + cmd.buffer = buf; +/* make 3 attempts */ + for(tries = 3; tries != 0; tries--) + { + err = _bios_disk(_DISK_WRITE, &cmd); + err >>= 8; +/* 0x11=="CRC/ECC corrected data error" */ + if(err == 0 || err == 0x11) + return 0; +/* reset disk */ + _bios_disk(_DISK_RESET, &cmd); + } + DEBUG(printf("write_sector(): error 0x%02X\n", err);) + return err; +} +/***************************************************************************** +*****************************************************************************/ +int is_fat_bootsector(unsigned char *buf) +{ + int temp, ok = 1; + + DEBUG(printf("check_if_fat_bootsector:\n");) +/* must start with 16-bit JMP or 8-bit JMP plus NOP */ + if(buf[0] == 0xE9) + /* OK */; + else if(buf[0] == 0xEB && buf[2] == 0x90) + /* OK */; + else + { + DEBUG(printf("\tMissing JMP/NOP\n");) + ok = 0; + } + temp = buf[13]; + if(temp == 0 || ((temp - 1) & temp) != 0) + { + DEBUG(printf("\tSectors per cluster (%u) " + "is not a power of 2\n", temp);) + ok = 0; + } + temp = buf[16]; + temp = LE16(buf + 24); + if(temp == 0 || temp > 63) + { + DEBUG(printf("\tInvalid number of sectors (%u)\n", temp);) + ok = 0; + } + temp = LE16(buf + 26); + if(temp == 0 || temp > 255) + { + DEBUG(printf("\tInvalid number of heads (%u)\n", temp);) + ok = 0; + } + return ok; +} +/***************************************************************************** +*****************************************************************************/ +static void probe_floppy_geometry(disk_t *disk) +{ + unsigned sectors, heads; + unsigned char buf[BPS]; + +/* scan upwards for sector number where read fails */ + disk->sectors = 64 + 1; + for(sectors = 1; sectors <= 64; sectors++) + { + if(read_sector(disk, sectors - 1, buf) != 0) + break; + } + disk->sectors = sectors - 1; +#if 1 +disk->heads = 2; +#else +/* scan upwards for head number where read fails +xxx - this probing for number of heads doesn't work */ + disk->heads = 16 + 1; + for(heads = 1; heads < 16; heads++) + { + if(read_sector(disk, heads * disk->sectors, buf) != 0) + break; + } + disk->heads = heads; +#endif +/* reset drive by reading sector 0 */ + (void)read_sector(disk, 0, buf); + DEBUG(printf("probe_floppy_geometry() for fd 0x%02X: " + "CHS=?:%u:%u\n", disk->drive_num, + disk->heads, disk->sectors);) +} +/***************************************************************************** +*****************************************************************************/ +int open_disk(disk_t *disk, unsigned drive_num) +{ + unsigned char buf[BPS]; + unsigned num_fds; + int err; + + disk->drive_num = drive_num; + disk->partition_start = 0; /* assume floppy */ + disk->use_lba = 0; /* assume CHS */ +/* hard disk */ + if(disk->drive_num >= 0x80) + return get_hd_geometry(disk); +/* make sure floppy drive exists */ + num_fds = peekw(0x40, 0x10); + if(num_fds & 0x0001) + num_fds = ((num_fds / 64) & 3) + 1; + else + num_fds = 0; + if(disk->drive_num >= num_fds) + { + printf("open_disk(): fd 0x%02X does not exist\n", + disk->drive_num); + return -1; + } +/* temporary values to make read_sector(0) work */ + disk->heads = disk->sectors = 1; + err = read_sector(disk, 0, buf); + if(err != 0) + return err; +/* if it's a FAT (DOS) disk, we get can reliable geometry info +from the BIOS parameter block (BPB) in the bootsector */ + if(is_fat_bootsector(buf)) + { + disk->heads = LE16(buf + 26); + disk->sectors = LE16(buf + 24); + DEBUG(printf("open_disk() for fd 0x%02X: " + "CHS=?:%u:%u (from BPB)\n", + disk->drive_num, + disk->heads, disk->sectors);) + return 0; + } +#if 0 +/* ...otherwise, do slow probe */ + probe_floppy_geometry(disk); +#else +/* ...or just assume some values */ + disk->heads = 2; + disk->sectors = 18; + DEBUG(printf("open_disk() for fd 0x%02X: " + "assuming CHS=?:2:18\n", disk->drive_num);) +#endif + return 0; +} diff --git a/Dump/hybos/__experimental/dos.h b/Dump/hybos/__experimental/dos.h new file mode 100644 index 0000000..a7493ba --- /dev/null +++ b/Dump/hybos/__experimental/dos.h @@ -0,0 +1,65 @@ +/***************************************************************************** +Sector-level disk I/O code for DOS. +This code is public domain (no copyright). +You can do whatever you want with it. + +EXPORTS: +peekb(), peekw() +*****************************************************************************/ +#ifndef __DISKIO_DOS_H +#define __DISKIO_DOS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************* TURBO C **********************************/ +#if defined(__TURBOC__) +#include /* peekb(), peek() */ + +#define peekw(S,O) peek(S,O) + +/* xxx - I'm not sure of the Turbo C version where these were +introduced. They are present in Turbo C++ 3.0 (__TURBOC__ == 0x401) +but not in Turbo C++ 1.0 (__TURBOC__ == 0x296) */ +#if __TURBOC__<0x300 +#define _DISK_RESET 0 /* controller hard reset */ +#define _DISK_STATUS 1 /* status of last operation */ +#define _DISK_READ 2 /* read sectors */ +#define _DISK_WRITE 3 /* write sectors */ +#define _DISK_VERIFY 4 /* verify sectors */ +#define _DISK_FORMAT 5 /* format track */ +#endif + +/********************************* DJGPP ************************************/ +#elif defined(__DJGPP__) +#include /* _farpeek[b|w]() */ +#include /* _dos_ds */ + +#define peekb(S,O) _farpeekb(_dos_ds, 16uL * (S) + (O)) +#define peekw(S,O) _farpeekw(_dos_ds, 16uL * (S) + (O)) + +/******************************** WATCOM C **********************************/ +#elif defined(__WATCOMC__) + +#if defined(__386__) +/* CauseWay DOS extender only */ +#define peekb(S,O) *(unsigned char *)(16uL * (S) + (O)) +#define peekw(S,O) *(unsigned short *)(16uL * (S) + (O)) +#else +#include /* MK_FP() */ +#define peekb(S,O) *(unsigned char far *)MK_FP(S,O) +#define peekw(S,O) *(unsigned short far *)MK_FP(S,O) +#endif + +/****************************************************************************/ +#else +#error Not Turbo C, not DJGPP, not Watcom C. Sorry. +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/__experimental/dos16.c b/Dump/hybos/__experimental/dos16.c new file mode 100644 index 0000000..0499ad2 --- /dev/null +++ b/Dump/hybos/__experimental/dos16.c @@ -0,0 +1,114 @@ +/***************************************************************************** +Sector-level disk I/O code for DOS, using 16-bit compiler. +This code is public domain (no copyright). +You can do whatever you want with it. + +EXPORTS: +int lba_biosdisk(int cmd, int drive, unsigned long lba, + int nsects, void *buf); +int get_hd_geometry(disk_t *disk); +*****************************************************************************/ +#include /* memset() */ +#include /* printf() */ +#include /* _DISK_... */ +/* union REGS, struct SREGS, int86(), int86x() */ +#include /* FP_SEG(), FP_OFF() */ +#include "diskio.h" +#include "dos.h" /* peekb() */ +/***************************************************************************** +*****************************************************************************/ +int lba_biosdisk(int cmd, int drive, unsigned long lba, int nsects, void *buf) +{ + struct + { + unsigned char pkt_len; + unsigned char res0; + unsigned char nsects; + unsigned char res1; + unsigned short buf_off; + unsigned short buf_seg; + unsigned long lba31_0; + unsigned long lba63_32; + } lba_cmd_pkt; + unsigned tries, err = 0; + struct SREGS sregs; + union REGS regs; + + if(cmd != _DISK_READ && cmd != _DISK_WRITE) + return 0x100; +/* make sure drive and BIOS support LBA */ + regs.x.bx = 0x55AA; + regs.h.dl = drive; + regs.h.ah = 0x41; + int86x(0x13, ®s, ®s, &sregs); + if(regs.x.cflag) + return 0x100; +/* fill out the INT 13h AH=4xh command packet */ + memset(&lba_cmd_pkt, 0, sizeof(lba_cmd_pkt)); + lba_cmd_pkt.pkt_len = sizeof(lba_cmd_pkt); + lba_cmd_pkt.nsects = nsects; + lba_cmd_pkt.buf_off = FP_OFF(buf); + lba_cmd_pkt.buf_seg = FP_SEG(buf); + lba_cmd_pkt.lba31_0 = lba; +/* fill out registers for INT 13h AH=4xh */ + sregs.ds = FP_SEG(&lba_cmd_pkt); + regs.x.si = FP_OFF(&lba_cmd_pkt); + regs.h.dl = drive; +/* make 3 attempts */ + for(tries = 3; tries != 0; tries--) + { + regs.h.ah = (cmd == _DISK_READ) ? 0x42 : 0x43; + int86x(0x13, ®s, ®s, &sregs); + err = regs.h.ah; + if(!regs.x.cflag) + return 0; +/* reset disk */ + regs.h.ah = _DISK_RESET; + int86x(0x13, ®s, ®s, &sregs); + } + DEBUG(printf("lba_biosdisk(): error 0x%02X\n", err);) + return err; +} +/***************************************************************************** +*****************************************************************************/ +int get_hd_geometry(disk_t *disk) +{ + union REGS regs; + +/* make sure hard drive exists */ + if(disk->drive_num - 0x80 >= peekb(0x40, 0x75)) + { + printf("get_hd_geometry(): hd 0x%02X does not exist\n", + disk->drive_num); + return -1; + } +/* use LBA if drive and BIOS support it */ + regs.h.ah = 0x41; + regs.x.bx = 0x55AA; + regs.h.dl = disk->drive_num; + int86(0x13, ®s, ®s); + if(!regs.x.cflag && regs.x.bx == 0xAA55) + { + disk->use_lba = 1; + DEBUG(printf("get_hd_geometry(): using LBA for hd 0x%02X\n", + disk->drive_num);) + return 0; + } +/* get geometry from BIOS */ + regs.h.ah = 0x08; + regs.h.dl = disk->drive_num; + int86(0x13, ®s, ®s); + if(regs.x.cflag) + { + printf("get_hd_geometry(): error getting geometry " + "for hard drive 0x%02X\n", disk->drive_num); + return -1; + } + disk->heads = regs.h.dh + 1; + disk->sectors = regs.h.cl & 0x3F; + DEBUG(printf("get_hd_geometry() for hd 0x%02X: " + "CHS=?:%u:%u (from INT 13h AH=08h)\n", + disk->drive_num, + disk->heads, disk->sectors);) + return 0; +} diff --git a/Dump/hybos/__experimental/makefile b/Dump/hybos/__experimental/makefile new file mode 100644 index 0000000..abe55e0 --- /dev/null +++ b/Dump/hybos/__experimental/makefile @@ -0,0 +1,32 @@ +# Makefile for Turbo C++ 1.0 +# For old Turbo MAKE 3.0, this file MUST be named 'makefile' + +# defines +# MAKEDEP =makefile +MODEL =s +CC =tcc -v -m$(MODEL) -w -O2 -d -Z -vi -1 +LIBDIR =c:\tc\lib +LD =tlink /v /x +OBJS =demo.obj dos.obj dos16.obj + +# targets +all: diskio.exe + +clean: + deltree /y *.exe *.obj *.o *.err + +# implicit rules +.c.obj: + $(CC) -c -o$*.obj $< + +# dependencies +demo.o: demo.c $(MAKEDEP) diskio.h + +dos.o: dos.c $(MAKEDEP) diskio.h dos.h + +dos16.o: dos16.c $(MAKEDEP) diskio.h dos.h + +# explicit rules +diskio.exe: $(OBJS) $(MAKEDEP) + $(LD) $(LIBDIR)\c0$(MODEL).obj $(OBJS),$.,,$(LIBDIR)\c$(MODEL).lib + diff --git a/Dump/hybos/__experimental/watcom16.mak b/Dump/hybos/__experimental/watcom16.mak new file mode 100644 index 0000000..56693c3 --- /dev/null +++ b/Dump/hybos/__experimental/watcom16.mak @@ -0,0 +1,28 @@ +# Makefile for DOS - Watcom C + +# defines +# MAKEDEP =watcom16.mak +CC =wcc -3 -s -d2 -hw -ox -w=9 -zc -ms +OBJS =demo.obj dos.obj dos16.obj + +# targets +all: diskio.exe + +clean: + deltree /y *.exe *.obj *.o *.err + +# implicit rules +.c.obj: + $(CC) -fo=$@ $[. + +# dependencies +demo.o: demo.c $(MAKEDEP) diskio.h + +dos.o: dos.c $(MAKEDEP) diskio.h dos.h + +dos16.o: dos16.c $(MAKEDEP) diskio.h dos.h + +# explicit rules +diskio.exe: $(OBJS) $(MAKEDEP) + wlink D W A SYSTEM dos NAME $@ FILE demo.obj FILE dos.obj FILE dos16.obj + diff --git a/Dump/hybos/__experimental/watcom32.c b/Dump/hybos/__experimental/watcom32.c new file mode 100644 index 0000000..921a8af --- /dev/null +++ b/Dump/hybos/__experimental/watcom32.c @@ -0,0 +1,117 @@ +/***************************************************************************** +Sector-level disk I/O code for DOS, using 32-bit Watcom C +with CauseWay DOS extender. +This code is public domain (no copyright). +You can do whatever you want with it. + +xxx - This code doesn't work + +EXPORTS: +int lba_biosdisk(int cmd, int drive, unsigned long lba, + int nsects, void *buf); +int get_hd_geometry(disk_t *disk); +*****************************************************************************/ +#include /* memset() */ +#include /* printf() */ +#include /* _DISK_... */ +/* union REGS, struct SREGS, int386(), int386x() */ +#include /* FP_SEG(), FP_OFF() */ +#include "diskio.h" +#include "dos.h" /* peekb() */ +/***************************************************************************** +*****************************************************************************/ +int lba_biosdisk(int cmd, int drive, unsigned long lba, int nsects, void *buf) +{ + struct + { + unsigned char pkt_len; + unsigned char res0; + unsigned char nsects; + unsigned char res1; + unsigned short buf_off; + unsigned short buf_seg; + unsigned long lba31_0; + unsigned long lba63_32; + } lba_cmd_pkt; + unsigned tries, err = 0; + struct SREGS sregs; + union REGS regs; + + if(cmd != _DISK_READ && cmd != _DISK_WRITE) + return 0x100; +/* make sure drive and BIOS support LBA */ + regs.w.bx = 0x55AA; + regs.h.dl = drive; + regs.h.ah = 0x41; + int386x(0x13, ®s, ®s, &sregs); + if(regs.w.cflag) + return 0x100; +/* fill out the INT 13h AH=4xh command packet */ + memset(&lba_cmd_pkt, 0, sizeof(lba_cmd_pkt)); + lba_cmd_pkt.pkt_len = sizeof(lba_cmd_pkt); + lba_cmd_pkt.nsects = nsects; + lba_cmd_pkt.buf_off = FP_OFF(buf); + lba_cmd_pkt.buf_seg = FP_SEG(buf); + lba_cmd_pkt.lba31_0 = lba; +/* fill out registers for INT 13h AH=4xh */ + sregs.ds = FP_SEG(&lba_cmd_pkt); + regs.w.si = FP_OFF(&lba_cmd_pkt); + regs.h.dl = drive; +/* make 3 attempts */ + for(tries = 3; tries != 0; tries--) + { + regs.h.ah = (cmd == _DISK_READ) ? 0x42 : 0x43; + int386x(0x13, ®s, ®s, &sregs); + err = regs.h.ah; + if(!regs.w.cflag) + return 0; +/* reset disk */ + regs.h.ah = _DISK_RESET; + int386x(0x13, ®s, ®s, &sregs); + } + DEBUG(printf("lba_biosdisk(): error 0x%02X\n", err);) + return err; +} +/***************************************************************************** +*****************************************************************************/ +int get_hd_geometry(disk_t *disk) +{ + union REGS regs; + +/* make sure hard drive exists */ + if(disk->drive_num - 0x80 >= peekb(0x40, 0x75)) + { + printf("get_hd_geometry(): hd 0x%02X does not exist\n", + disk->drive_num); + return -1; + } +/* use LBA if drive and BIOS support it */ + regs.h.ah = 0x41; + regs.w.bx = 0x55AA; + regs.h.dl = disk->drive_num; + int386(0x13, ®s, ®s); + if(!regs.w.cflag && regs.w.bx == 0xAA55) + { + disk->use_lba = 1; + DEBUG(printf("get_hd_geometry(): using LBA for hd 0x%02X\n", + disk->drive_num);) + return 0; + } +/* get geometry from BIOS */ + regs.h.ah = 0x08; + regs.h.dl = disk->drive_num; + int386(0x13, ®s, ®s); + if(!regs.w.cflag) + { + printf("get_hd_geometry(): error getting geometry " + "for hard drive 0x%02X\n", disk->drive_num); + return -1; + } + disk->heads = regs.h.dh + 1; + disk->sectors = regs.h.cl & 0x3F; + DEBUG(printf("get_hd_geometry() for hd 0x%02X: " + "CHS=?:%u:%u (from INT 13h AH=08h)\n", + disk->drive_num, + disk->heads, disk->sectors);) + return 0; +} diff --git a/Dump/hybos/__experimental/watcom32.mak b/Dump/hybos/__experimental/watcom32.mak new file mode 100644 index 0000000..842bda8 --- /dev/null +++ b/Dump/hybos/__experimental/watcom32.mak @@ -0,0 +1,30 @@ +# Makefile for 32-bit DOS - Watcom C +# (using CauseWay DOS extender) +# xxx - the resulting DISKIO.EXE doesn't work (!) + +# defines +# MAKEDEP =watcom32.mak +CC =wcc386 -3 -s -d2 -hw -ox -w=9 -zc -mf +OBJS =demo.obj dos.obj watcom32.obj + +# targets +all: diskio.exe + +clean: + deltree /y *.exe *.obj *.o *.err + +# implicit rules +.c.obj: + $(CC) -fo=$@ $[. + +# dependencies +demo.o: demo.c $(MAKEDEP) diskio.h + +dos.o: dos.c $(MAKEDEP) diskio.h dos.h + +watcom32.o: watcom32.c $(MAKEDEP) diskio.h dos.h + +# explicit rules +diskio.exe: $(OBJS) $(MAKEDEP) + wlink D W A SYSTEM causeway NAME $@ FILE demo.obj FILE dos.obj FILE watcom32.obj + diff --git a/Dump/hybos/__experimental/win-nt.c b/Dump/hybos/__experimental/win-nt.c new file mode 100644 index 0000000..d8705c3 --- /dev/null +++ b/Dump/hybos/__experimental/win-nt.c @@ -0,0 +1,125 @@ +/***************************************************************************** +Sector-level disk I/O code for Windows NT. +This code is public domain (no copyright). +You can do whatever you want with it. + +EXPORTS: +int read_sector(disk_t *disk, unsigned long lba, unsigned char *buf); +int open_disk(disk_t *disk, unsigned drive_num); +int is_fat_bootsector(unsigned char *buf); + +Tim Robinson helped with this code. +(Bugs are due to Giese :) +*****************************************************************************/ +#include +/* FILE, fopen(), setvbuf(), fseek(), fread(), fclose(), printf(), sprintf() */ +#include +#include "diskio.h" +/***************************************************************************** +*****************************************************************************/ +static FILE *do_open(unsigned drive_num) +{ + char dev_name[64]; + FILE *f; + +/* form internal drive name */ + if(drive_num < 0x80) + sprintf(dev_name, "\\\\.\\%c:", drive_num + 'A'); + else + sprintf(dev_name, "\\\\.\\PhysicalDrive%u", + drive_num - 0x80); +/* open the drive */ + f = fopen(dev_name, "r+b"); + if(f == NULL) + printf("do_open(): drive 0x%02X (%s) does not exist\n", + drive_num, dev_name); + return f; +} +/***************************************************************************** +*****************************************************************************/ +int read_sector(disk_t *disk, unsigned long lba, unsigned char *buf) +{ + unsigned err; + FILE *f; + + lba += disk->partition_start; + f = do_open(disk->drive_num); + if(f == NULL) + return -1; +/* seek, read, close */ + setvbuf(f, NULL, _IOFBF, BPS); + fseek(f, lba * BPS, SEEK_SET); + err = fread(buf, 1, BPS, f); + fclose(f); + return (err == BPS) ? 0 : -1; +} +/***************************************************************************** +*****************************************************************************/ +int open_disk(disk_t *disk, unsigned drive_num) +{ + OSVERSIONINFO win_version; + unsigned char buf[BPS]; + unsigned err = 0; + FILE *f; + +/* check for NT */ + win_version.dwOSVersionInfoSize = sizeof(win_version); + GetVersionEx(&win_version); + if(win_version.dwPlatformId != VER_PLATFORM_WIN32_NT) + { + printf("Sorry, Windows NT required\n" + "Windows 9x users should use the " + "DOS version of this program\n\n"); + return -1; + } + disk->drive_num = drive_num; + disk->partition_start = 0; /* assume floppy */ + disk->use_lba = 0; /* assume CHS */ +/* open the drive, to make sure it exists */ + f = do_open(disk->drive_num); + if(f == NULL) + return -1; + fclose(f); +/* no CHS geometry - NT uses LBA for everything */ + return 0; +} +/***************************************************************************** +is_fat_bootsector() is not used in this file, but still used in DEMO.C +*****************************************************************************/ +int is_fat_bootsector(unsigned char *buf) +{ + int temp, ok = 1; + + DEBUG(printf("check_if_fat_bootsector:\n");) +/* must start with 16-bit JMP or 8-bit JMP plus NOP */ + if(buf[0] == 0xE9) + /* OK */; + else if(buf[0] == 0xEB && buf[2] == 0x90) + /* OK */; + else + { + DEBUG(printf("\tMissing JMP/NOP\n");) + ok = 0; + } + temp = buf[13]; + if(temp == 0 || ((temp - 1) & temp) != 0) + { + DEBUG(printf("\tSectors per cluster (%u) " + "is not a power of 2\n", temp);) + ok = 0; + } + temp = buf[16]; + temp = LE16(buf + 24); + if(temp == 0 || temp > 63) + { + DEBUG(printf("\tInvalid number of sectors (%u)\n", temp);) + ok = 0; + } + temp = LE16(buf + 26); + if(temp == 0 || temp > 255) + { + DEBUG(printf("\tInvalid number of heads (%u)\n", temp);) + ok = 0; + } + return ok; +} diff --git a/Dump/hybos/__experimental/win-nt.mak b/Dump/hybos/__experimental/win-nt.mak new file mode 100644 index 0000000..e647cc5 --- /dev/null +++ b/Dump/hybos/__experimental/win-nt.mak @@ -0,0 +1,26 @@ +# Makefile for Windows NT - MinGW/CygWin + +# defines +# MAKEDEP =makefile +CC =gcc -g -O2 -Wall -W +LD =gcc -g +OBJS =demo.o win-nt.o + +# targets +all: diskio.exe + +clean: + deltree /y *.exe *.obj *.o *.err + +# implicit rules +.c.o: + $(CC) -c -o$@ $< + +# dependencies +demo.o: demo.c $(MAKEDEP) diskio.h + +win-nt.o: win-nt.c $(MAKEDEP) diskio.h + +# explicit rules +diskio.exe: $(OBJS) $(MAKEDEP) + $(LD) -o$@ $(OBJS) diff --git a/Dump/hybos/boot/grub/mbchk.c b/Dump/hybos/boot/grub/mbchk.c new file mode 100644 index 0000000..f0ae915 --- /dev/null +++ b/Dump/hybos/boot/grub/mbchk.c @@ -0,0 +1,166 @@ +/***************************************************************************** +This was lifted from the GRUB source code. +GRUB is available under the GNU general public license from + http://www.gnu.org/software/grub + ftp://alpha.gnu.org/gnu/grub +*****************************************************************************/ +#include "mltiboot.h" +#include + +static int quiet; +/***************************************************************************** +*****************************************************************************/ +static int +check_multiboot (const char *filename, FILE *fp) +{ + multiboot_header_t *mbh = 0; + int i; + char buf[8192]; + + if (fread (buf, 1, 8192, fp) < 0) + { + fprintf (stderr, "%s: Read error.\n", filename); + return 0; + } + + for (i = 0; i < 8192 - sizeof (multiboot_header_t); i++) + { + unsigned long magic = *((unsigned long *) (buf + i)); + + if (magic == MULTIBOOT_HEADER_MAGIC) + { + mbh = (multiboot_header_t *) (buf + i); + break; + } + } + + if (! mbh) + { + fprintf (stderr, "%s: No Multiboot header.\n", filename); + return 0; + } + + if (! quiet) + printf ("%s: The Multiboot header is found at the offset %d.\n", + filename, i); + + /* Check for the checksum. */ + if (mbh->magic + mbh->flags + mbh->checksum != 0) + { + fprintf (stderr, + "%s: Bad checksum (0x%lx).\n", + filename, mbh->checksum); + return 0; + } + + /* Reserved flags must be zero. */ + if (mbh->flags & ~0x00010003) + { + fprintf (stderr, + "%s: Non-zero is found in reserved flags (0x%lx).\n", + filename, mbh->flags); + return 0; + } + + if (! quiet) + { + printf ("%s: Page alignment is turned %s.\n", + filename, (mbh->flags & 0x1)? "on" : "off"); + printf ("%s: Memory information is turned %s.\n", + filename, (mbh->flags & 0x2)? "on" : "off"); + printf ("%s: Address fields is turned %s.\n", + filename, (mbh->flags & 0x10000)? "on" : "off"); + } + + /* Check for the address fields. */ + if (mbh->flags & 0x10000) + { + +printf("header_addr = 0x%lX\n", mbh->header_addr); +printf("load_addr = 0x%lX\n", mbh->load_addr); +printf("load_end_addr = 0x%lX\n", mbh->load_end_addr); +printf("bss_end_addr = 0x%lX\n", mbh->bss_end_addr); +printf("entry_addr = 0x%lX\n", mbh->entry_addr); + + if (mbh->header_addr < mbh->load_addr) + { + fprintf (stderr, + "%s: header_addr is less than " + "load_addr (0x%lx > 0x%lx).\n", + filename, mbh->header_addr, mbh->load_addr); + return 0; + } + + if (mbh->load_addr >= mbh->load_end_addr) + { + fprintf (stderr, + "%s: load_addr is not less than load_end_addr" + " (0x%lx >= 0x%lx).\n", + filename, mbh->load_addr, mbh->load_end_addr); + return 0; + } + + if (mbh->load_end_addr > mbh->bss_end_addr) + { + fprintf (stderr, + "%s: load_end_addr is greater than bss_end_addr" + " (0x%lx > 0x%lx).\n", + filename, mbh->load_end_addr, mbh->bss_end_addr); + return 0; + } + + if (mbh->load_addr > mbh->entry_addr) + { + fprintf (stderr, + "%s: load_addr is greater than entry_addr" + " (0x%lx > 0x%lx).\n", + filename, mbh->load_addr, mbh->entry_addr); + return 0; + } + + if (mbh->load_end_addr <= mbh->entry_addr) + { + fprintf (stderr, + "%s: load_end_addr is not less than entry_addr" + " (0x%lx <= 0x%lx).\n", + filename, mbh->load_end_addr, mbh->entry_addr); + return 0; + } + + /* This is a GRUB-specific limitation. */ + if (mbh->load_addr < 0x100000) + { + fprintf (stderr, + "%s: Cannot be loaded at less than 1MB by GRUB" + " (0x%lx).\n", + filename, mbh->load_addr); + return 0; + } + } + + if (! quiet) + printf ("%s: All checks passed.\n", filename); + + return 1; +} +/***************************************************************************** +*****************************************************************************/ +int main(unsigned arg_c, char *arg_v[]) +{ + FILE *file; + + if(arg_c < 2) + { + printf("Checks if file is Multiboot compatible\n"); + return 1; + } + file = fopen(arg_v[1], "rb"); + if(file == NULL) + { + printf("Can't open file '%s'\n", arg_v[1]); + return 2; + } + check_multiboot(arg_v[1], file); + fclose(file); + return 0; +} diff --git a/Dump/hybos/boot/grub/menu.lst b/Dump/hybos/boot/grub/menu.lst new file mode 100644 index 0000000..ea308ac --- /dev/null +++ b/Dump/hybos/boot/grub/menu.lst @@ -0,0 +1,39 @@ +# boot the first entry by default +# default 0 +# if there's a problem booting the default entry, boot the second entry +# fallback 1 +# boot default after 30 sec +# timeout 30 + +title OSD 3 + root (fd0) + kernel /osd3.x + +title OSD 4 + root (fd0) + kernel /osd4.x + +title OSD 5 + root (fd0) + kernel /osd5.x + +title OSD 6 + root (fd0) + kernel /osd6.x + +title OSD 7 + root (fd0) + kernel /osd7.x + +title OSD 8 + root (fd0) + kernel /osd8.x + +title OSD 9 + root (fd0) + kernel /osd9.x + +title Boot from C: drive + root (hd0,1) + makeactive + chainloader +1 diff --git a/Dump/hybos/boot/grub/mltiboot.h b/Dump/hybos/boot/grub/mltiboot.h new file mode 100644 index 0000000..f8afac9 --- /dev/null +++ b/Dump/hybos/boot/grub/mltiboot.h @@ -0,0 +1,115 @@ +/* multiboot.h - the header for Multiboot */ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Macros. */ + +/* The magic number for the Multiboot header. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* The flags for the Multiboot header. */ +#define MULTIBOOT_HEADER_FLAGS 0x00010003 + +/* The magic number passed by a Multiboot-compliant boot loader. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* The size of our stack (16KB). */ +#define STACK_SIZE 0x4000 + +/* C symbol format. HAVE_ASM_USCORE is defined by configure. */ +#ifdef HAVE_ASM_USCORE +# define EXT_C(sym) _ ## sym +#else +# define EXT_C(sym) sym +#endif + +#ifndef ASM +/* Do not include here in boot.S. */ + +/* Types. */ + +/* The Multiboot header. */ +typedef struct multiboot_header +{ + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +} multiboot_header_t; + +/* The symbol table for a.out. */ +typedef struct aout_symbol_table +{ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long reserved; +} aout_symbol_table_t; + +/* The section header table for ELF. */ +typedef struct elf_section_header_table +{ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; +} elf_section_header_table_t; + +/* The Multiboot information. */ +typedef struct multiboot_info +{ + unsigned long flags; + unsigned long mem_lower; + unsigned long mem_upper; + unsigned long boot_device; + unsigned long cmdline; + unsigned long mods_count; + unsigned long mods_addr; + union + { + aout_symbol_table_t aout_sym; + elf_section_header_table_t elf_sec; + } u; + unsigned long mmap_length; + unsigned long mmap_addr; +} multiboot_info_t; + +/* The module structure. */ +typedef struct module +{ + unsigned long mod_start; + unsigned long mod_end; + unsigned long string; + unsigned long reserved; +} module_t; + +/* The memory map. Be careful that the offset 0 is base_addr_low + but no size. */ +typedef struct memory_map +{ + unsigned long size; + unsigned long base_addr_low; + unsigned long base_addr_high; + unsigned long length_low; + unsigned long length_high; + unsigned long type; +} memory_map_t; + +#endif /* ! ASM */ diff --git a/Dump/hybos/boot/grub/stage1 b/Dump/hybos/boot/grub/stage1 new file mode 100644 index 0000000..1cd1292 --- /dev/null +++ b/Dump/hybos/boot/grub/stage1 Binary files differ diff --git a/Dump/hybos/boot/grub/stage2 b/Dump/hybos/boot/grub/stage2 new file mode 100644 index 0000000..25094fe --- /dev/null +++ b/Dump/hybos/boot/grub/stage2 Binary files differ diff --git a/Dump/hybos/boot/kernel.bin b/Dump/hybos/boot/kernel.bin new file mode 100644 index 0000000..3ff90a0 --- /dev/null +++ b/Dump/hybos/boot/kernel.bin Binary files differ diff --git a/Dump/hybos/include/._malloc.h.swp b/Dump/hybos/include/._malloc.h.swp new file mode 100644 index 0000000..3a93866 --- /dev/null +++ b/Dump/hybos/include/._malloc.h.swp Binary files differ diff --git a/Dump/hybos/include/.ctype.h.swp b/Dump/hybos/include/.ctype.h.swp new file mode 100644 index 0000000..3191f8d --- /dev/null +++ b/Dump/hybos/include/.ctype.h.swp Binary files differ diff --git a/Dump/hybos/include/.fat.h.swp b/Dump/hybos/include/.fat.h.swp new file mode 100644 index 0000000..ab6de14 --- /dev/null +++ b/Dump/hybos/include/.fat.h.swp Binary files differ diff --git a/Dump/hybos/include/.keyboard.h.swp b/Dump/hybos/include/.keyboard.h.swp new file mode 100644 index 0000000..b1505f1 --- /dev/null +++ b/Dump/hybos/include/.keyboard.h.swp Binary files differ diff --git a/Dump/hybos/include/.stdarg.h.swp b/Dump/hybos/include/.stdarg.h.swp new file mode 100644 index 0000000..3c895d7 --- /dev/null +++ b/Dump/hybos/include/.stdarg.h.swp Binary files differ diff --git a/Dump/hybos/include/.x86.h.swp b/Dump/hybos/include/.x86.h.swp new file mode 100644 index 0000000..4a4a828 --- /dev/null +++ b/Dump/hybos/include/.x86.h.swp Binary files differ diff --git a/Dump/hybos/include/__nocompile_fcntl.h b/Dump/hybos/include/__nocompile_fcntl.h new file mode 100644 index 0000000..832446e --- /dev/null +++ b/Dump/hybos/include/__nocompile_fcntl.h @@ -0,0 +1,79 @@ +/** + * fcntl.h + * + * access constants for _open. Note that this file is not complete + * and should not be used (yet) + */ + +#ifndef __STRICT_ANSI__ +#ifndef _FCNTL_H + +#define _FCNTL_H + +/** + * File access modes + */ +#define _O_RDONLY 0 /* read only */ +#define _O_WRONLY 1 /* write only */ +#define _O_RDWR 2 /* read and write */ + +/** + * Mask for access mode bits in the _open flags + */ +#define _O_ACCMODE (_O_RDONLY|_O_WRONLY|_O_RDWR) +#define _O_APPEND 0x0008 /* append output to end of file */ +#define _O_RANDOM 0x0010 +#define _O_SEQUENTIAL 0x0020 +#define _O_TEMPORARY 0x0040 /* make the file dissappear after closing */ +#define _O_NOINHERIT 0x0080 +#define _O_CREAT 0x0100 /* create file if it doesn't exist */ +#define _O_TRUNC 0x0200 /* truncate file to zero bytes if it exists */ +#define _O_EXCL 0x0400 /* open only if the file does not exist */ + +#define _O_SHORT_LIVED 0x1000 + +#define _O_TEXT 0x4000 /* crlf in file == lf in memory (\r\n == \n) */ +#define _O_BINARY 0x8000 /* input and output is not translated */ +#define _O_RAW _O_BINARY /* compatability */ + +/** + * XXX + * The following special mode(s) are only available to the + * kernel. Modules (even kernel-level modules) and other + * binaries will never be allowed to use these special modes. + * + * Modules which are compiled into the kernel may use these + * special modes (mainly at boot). + */ +#define _O_DEV 0x9000 /* XXX: special device links (files) */ +#define _O_SWAP 0x9100 /* swap */ + +#ifndef _NO_OLDNAMES + +/** + * POSIX/Non-ANSI names for increased portability + */ +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDWR +#define O_ACCMODE _O_ACCMODE +#define O_APPEND _O_APPEND +#define O_CREAT _O_CREAT +#define O_TRUNC _O_TRUNC +#define O_EXCL _O_EXCL +#define O_TEXT _O_TEXT +#define O_BINARY _O_BINARY +#define O_TEMPORARY _O_TEMPORARY +#define O_NOINHERIT _O_NOINHERIT +#define O_SEQUENTIAL _O_SEQUENTIAL +#define O_RANDOM _O_RANDOM + +#define O_DEV _O_DEV +#define O_SWAP _O_SWAP + +#endif /* ! _NO_OLDNAMES */ + +#endif /* ! _FCNTL_H */ + +#endif /* ! __STRICT_ANSI__ */ + diff --git a/Dump/hybos/include/__nocompile_signal.h b/Dump/hybos/include/__nocompile_signal.h new file mode 100644 index 0000000..6e23448 --- /dev/null +++ b/Dump/hybos/include/__nocompile_signal.h @@ -0,0 +1,83 @@ +/** + * fcntl.h + * + * access constants for _open. Note that this file is not complete + * and should not be used (yet) + */ + +#ifndef _SIGNAL_H +#define _SIGNAL_H + +/** + * The actual signal values. Using other values with signal + * produces a SIG_ERR return value. + * + * NOTE: SIGINT is produced when the user presses Ctrl-C + * SIGILL has not been tested + * SIGFPE + * SIGSEGV + * SIGTERM comes from what kind of termination request exactly? + * SIGBREAK is produced by pressing Ctrl-Break + * SIGABRT is produced by calling abort + */ +#define SIGINT 2 /* Interactive attention */ +#define SIGILL 4 /* Illegal instruction */ +#define SIGFPE 8 /* Floating point error */ +#define SIGSEGV 11 /* Segmentation violation */ +#define SIGTERM 15 /* Termination request */ +#define SIGBREAK 21 /* Ctrl-Break */ +#define SIGABRT 22 /* Abnormal termination (abort) */ + +#define NSIG 23 /* maximum signal number + 1 */ + +#ifndef RC_INVOKED +#ifndef _SIG_ATOMIC_T_DEFINED +typedef int sig_atomic_t; +#define _SIG_ATOMIC_T_DEFINED +#endif /* ! _SIG_ATOMIC_T_DEFINED */ + +/** + * The prototypes (below) are the easy part. The hard part is figuring + * out what signals are available and what numbers they are assigned + * along with appropriate values of SIG_DFL and SIG_IGN. + */ + +/** + * A pointer to a signal handler function. A signal handler takes a + * single int, which is the signal it handles. + */ +typedef void (*__p_sig_fn_t)(int); + +/** + * These are special values of signal handler pointers which are + * used to send a signal to the default handler (SIG_DFL), ignore + * the signal (SIG_IGN), or indicate an error return (SIG_ERR). + */ +#define SIG_DFL ((__p_sig_fn_t) 0) +#define SIG_IGN ((__p_sig_fn_t) 1) +#define SIG_ERR ((__p_sig_fn_t) -1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Call signal to set the signal handler for signal sig to the + * function pointed to by handler. Returns a pointer to the + * previous handler, or SIG_ERR if an error occurs. Initially + * unhandled signals defined above will return SIG_DFL. + */ +_CRTIMP __p_sig_fn_t __cdecl signal(int, __p_sig_fn_t); + +/** + * Raise the signal indicated by sig. Returns non-zero on success. + */ +_CRTIMP int __cdecl raise (int); + +#ifdef __cplusplus +} +#endif + +#endif /* ! RC_INVOKED */ +#endif /* ! _SIGNAL_H */ + diff --git a/Dump/hybos/include/_malloc.h b/Dump/hybos/include/_malloc.h new file mode 100644 index 0000000..63699dc --- /dev/null +++ b/Dump/hybos/include/_malloc.h @@ -0,0 +1,37 @@ +#ifndef __TL__MALLOC_H +#define __TL__MALLOC_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* 500K */ +#define HEAP_SIZE 500000uL + +#include <_size_t.h> +/*#include <_null.h>*/ + +#define MALLOC_MAGIC 0x6D92 /* must be < 0x8000 */ + +typedef struct _malloc /* Turbo C DJGPP */ +{ + size_t size; /* 2 bytes 4 bytes */ + struct _malloc *next; /* 2 bytes 4 bytes */ + unsigned magic : 15; /* 2 bytes total 4 bytes total */ + unsigned used : 1; +} malloc_t; /* total 6 bytes 12 bytes */ + +extern malloc_t *_heap_bot, *_heap_top; + +static void dump_heap(void); +static void *kbrk(int *delta); +void *kmalloc(size_t size); +void kfree(void *blk); +void *krealloc(void *blk, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/include/_null.h_ b/Dump/hybos/include/_null.h_ new file mode 100644 index 0000000..2385d95 --- /dev/null +++ b/Dump/hybos/include/_null.h_ @@ -0,0 +1,18 @@ +#ifndef __TL__NULL_H +#define __TL__NULL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef _NULL +#define _NULL +#define NULL 0 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/include/_printf.h b/Dump/hybos/include/_printf.h new file mode 100644 index 0000000..77217b7 --- /dev/null +++ b/Dump/hybos/include/_printf.h @@ -0,0 +1,19 @@ +#ifndef __TL__PRINTF_H +#define __TL__PRINTF_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <_va_list.h> + +typedef int (*fnptr_t)(unsigned c, void **helper); + +int do_printf(const char *fmt, va_list args, fnptr_t fn, void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/include/_size_t.h b/Dump/hybos/include/_size_t.h new file mode 100644 index 0000000..8f4dc5a --- /dev/null +++ b/Dump/hybos/include/_size_t.h @@ -0,0 +1,18 @@ +#ifndef __TL__SIZE_T_H +#define __TL__SIZE_T_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned size_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/include/_va_list.h b/Dump/hybos/include/_va_list.h new file mode 100644 index 0000000..c62f7c4 --- /dev/null +++ b/Dump/hybos/include/_va_list.h @@ -0,0 +1,15 @@ +#ifndef __TL__VA_LIST_H +#define __TL__VA_LIST_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef unsigned char *va_list; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/include/asm.inc b/Dump/hybos/include/asm.inc new file mode 100644 index 0000000..694d8cf --- /dev/null +++ b/Dump/hybos/include/asm.inc @@ -0,0 +1,30 @@ +%ifndef __TL_ASM_INC +%define __TL_ASM_INC 1 + +; macros to handle leading underscores added by DOS/Windows compilers +%macro IMP 1 +%ifdef UNDERBARS + EXTERN _%1 + %define %1 _%1 +%else + EXTERN %1 +%endif +%endmacro + +%macro EXP 1 + GLOBAL $_%1 + $_%1: + GLOBAL $%1 + $%1: +%endmacro + +DS_MAGIC equ 3544DA2Ah + +MULTIBOOT_PAGE_ALIGN equ 1<<0 +MULTIBOOT_MEMORY_INFO equ 1<<1 +MULTIBOOT_AOUT_KLUDGE equ 1<<16 +MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 +MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE +MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) + +%endif diff --git a/Dump/hybos/include/char.h b/Dump/hybos/include/char.h new file mode 100644 index 0000000..3e5b50b --- /dev/null +++ b/Dump/hybos/include/char.h @@ -0,0 +1,24 @@ +#ifndef _CHAR_H +#define _CHAR_H + +#include + +long atoi(const char *nptr); +bool isalnum(const char c); +bool isalpha(const char c); +bool isascii(const unsigned char c); +bool iscsym(const char c); +bool iscsymf(const char c); +bool isctrl(const char c); +bool isdigit(const char c); +bool isgraph(const unsigned char c); +bool islowwer(const char c); +bool isprint(const char c); +bool ispunct(const char c); +bool isspace(const char c); +bool isupper(const char c); +bool isxdigit(const char c); +int tolower(int c); +int toupper(int c); + +#endif /* !defined(_CHAR_H) */ diff --git a/Dump/hybos/include/conio.h b/Dump/hybos/include/conio.h new file mode 100644 index 0000000..0368744 --- /dev/null +++ b/Dump/hybos/include/conio.h @@ -0,0 +1,60 @@ +#ifndef __TL_CONIO_H +#define __TL_CONIO_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* "bucky bits" +0x0100 is reserved for non-ASCII keys, so start with 0x200 */ +#define KBD_META_ALT 0x0200 /* Alt is pressed */ +#define KBD_META_CTRL 0x0400 /* Ctrl is pressed */ +#define KBD_META_SHIFT 0x0800 /* Shift is pressed */ +#define KBD_META_ANY (KBD_META_ALT | KBD_META_CTRL | KBD_META_SHIFT) +#define KBD_META_CAPS 0x1000 /* CapsLock is on */ +#define KBD_META_NUM 0x2000 /* NumLock is on */ +#define KBD_META_SCRL 0x4000 /* ScrollLock is on */ + +/* "ASCII" values for non-ASCII keys. All of these are user-defined. + +Hrrm. Unicode defines code pages for pseudographics (e.g. box-drawing +characters). I wonder it defines anything for keys like these? + +function keys: */ +#define KEY_F1 0x80 +#define KEY_F2 (KEY_F1 + 1) +#define KEY_F3 (KEY_F2 + 1) +#define KEY_F4 (KEY_F3 + 1) +#define KEY_F5 (KEY_F4 + 1) +#define KEY_F6 (KEY_F5 + 1) +#define KEY_F7 (KEY_F6 + 1) +#define KEY_F8 (KEY_F7 + 1) +#define KEY_F9 (KEY_F8 + 1) +#define KEY_F10 (KEY_F9 + 1) +#define KEY_F11 (KEY_F10 + 1) +#define KEY_F12 (KEY_F11 + 1) +/* cursor keys */ +#define KEY_INS 0x90 +#define KEY_DEL (KEY_INS + 1) +#define KEY_HOME (KEY_DEL + 1) +#define KEY_END (KEY_HOME + 1) +#define KEY_PGUP (KEY_END + 1) +#define KEY_PGDN (KEY_PGUP + 1) +#define KEY_LFT (KEY_PGDN + 1) +#define KEY_UP (KEY_LFT + 1) +#define KEY_DN (KEY_UP + 1) +#define KEY_RT (KEY_DN + 1) +/* print screen/sys rq and pause/break */ +#define KEY_PRNT (KEY_RT + 1) +#define KEY_PAUSE (KEY_PRNT + 1) +/* these return a value but they could also act as additional bucky keys */ +#define KEY_LWIN (KEY_PAUSE + 1) +#define KEY_RWIN (KEY_LWIN + 1) +#define KEY_MENU (KEY_RWIN + 1) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/include/ctype.h b/Dump/hybos/include/ctype.h new file mode 100644 index 0000000..76b980d --- /dev/null +++ b/Dump/hybos/include/ctype.h @@ -0,0 +1,44 @@ +#ifndef __TL_CTYPE_H +#define __TL_CTYPE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern char _ctype[]; + +typedef enum {false = 0, true = !0} bool; + +#define CT_UP 0x01 /* upper case */ +#define CT_LOW 0x02 /* lower case */ +#define CT_DIG 0x04 /* digit */ +#define CT_CTL 0x08 /* control */ +#define CT_PUN 0x10 /* punctuation */ +#define CT_WHT 0x20 /* white space (space/cr/lf/tab) */ +#define CT_HEX 0x40 /* hex digit */ +#define CT_SP 0x80 /* hard space (0x20) */ + +/* without the cast to unsigned, DJGPP complains (using -Wall) */ +#define isalnum(c) ((_ctype + 1)[(unsigned)(c)] & (CT_UP | CT_LOW | CT_DIG)) +#define isalpha(c) ((_ctype + 1)[(unsigned)(c)] & (CT_UP | CT_LOW)) +#define iscntrl(c) ((_ctype + 1)[(unsigned)(c)] & (CT_CTL)) +#define isdigit(c) ((_ctype + 1)[(unsigned)(c)] & (CT_DIG)) +#define isgraph(c) ((_ctype + 1)[(unsigned)(c)] & (CT_PUN | CT_UP | CT_LOW | CT_DIG)) +#define islower(c) ((_ctype + 1)[(unsigned)(c)] & (CT_LOW)) +#define isprint(c) ((_ctype + 1)[(unsigned)(c)] & (CT_PUN | CT_UP | CT_LOW | CT_DIG | CT_SP)) +#define ispunct(c) ((_ctype + 1)[(unsigned)(c)] & (CT_PUN)) +#define isspace(c) ((_ctype + 1)[(unsigned)(c)] & (CT_WHT)) +#define isupper(c) ((_ctype + 1)[(unsigned)(c)] & (CT_UP)) +#define isxdigit(c) ((_ctype + 1)[(unsigned)(c)] & (CT_DIG | CT_HEX)) +#define isascii(c) ((unsigned)(c) <= 0x7F) +#define toascii(c) ((unsigned)(c) & 0x7F) + +#define tolower(c) (isupper(c) ? c + 'a' - 'A' : c) +#define toupper(c) (islower(c) ? c + 'A' - 'a' : c) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/include/e2fs.h b/Dump/hybos/include/e2fs.h new file mode 100644 index 0000000..edf72f3 --- /dev/null +++ b/Dump/hybos/include/e2fs.h @@ -0,0 +1,290 @@ +/* e2fs.h */ +#ifndef E2FS_H +#define E2FS_H + +/* + * This code is a complete rewrite of the read-only part of E2FS + * library, done to reduce code size and memory requirements, and + * also increase speed in my particular conditions. + * + * So I need to include this for the common structure description: + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * And I also have to point to the complete e2fsprogs suite + * at: http://sourceforge.net/projects/e2fsprogs/ + * or: http://e2fsprogs.sourceforge.net + * by Theodore Ts'o (http://thunk.org/tytso/) (tytso@mit.edu). + * + * This rewrite is based on the structure found in e2fsprogs-1.26. + * + * Note that some parts of e2fsprogs may be available under LGPL, + * my added work is only available under the GPL - not LGPL. + */ + +/* Gujin is a bootloader, it loads a Linux kernel from cold boot or DOS. + * Copyright (C) 1999-2003 Etienne Lorrain, fingerprint (2D3AF3EA): + * 2471 DF64 9DEE 41D4 C8DB 9667 E448 FF8C 2D3A F3EA + * E-Mail: etienne.lorrain@masroudeau.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +typedef unsigned char __u8; +typedef short __s16; +typedef unsigned short __u16; +typedef int __s32; +typedef unsigned int __u32; + +/* + * Where the master copy of the superblock is located, and how big + * superblocks are supposed to be. We define SUPERBLOCK_SIZE because + * the size of the superblock structure is not necessarily trustworthy + * (some versions have the padding set up so that the superblock is + * 1032 bytes long). + */ +#define SUPERBLOCK_OFFSET 1024 +#define SUPERBLOCK_SIZE 1024 +#define EXT2_MIN_BLOCK_SIZE 1024 +#define EXT2_MAX_BLOCK_SIZE 4096 + +/* + * Special inodes numbers + */ +#define EXT2_BAD_INO 1 /* Bad blocks inode */ +#define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT2_ACL_IDX_INO 3 /* ACL inode */ +#define EXT2_ACL_DATA_INO 4 /* ACL inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */ +#define EXT2_JOURNAL_INO 8 /* Journal inode */ + +/* + * First non-reserved inode for old ext2 filesystems + */ +#define EXT2_GOOD_OLD_FIRST_INO 11 + +/* + * The second extended file system magic number + */ +#define EXT2_SUPER_MAGIC 0xEF53 + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV +#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV + +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +#define EXT2_NAME_LEN 255 + +/* + * Structure of the super block + */ +typedef struct { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + struct feature_compat_str { + unsigned dir_prealloc : 1; + unsigned imagic_inode : 1; + unsigned has_journal : 1; + unsigned ext_attr : 1; + unsigned resize_inode : 1; + unsigned dir_index : 1; + unsigned reserved : 26; + } __attribute__ ((packed)) s_feature_compat; /* compatible feature set */ + struct feature_incompat_str { + unsigned compression : 1; + unsigned filetype : 1; + unsigned recover : 1; + unsigned journal_dev : 1; + unsigned reserved : 28; + } __attribute__ ((packed)) s_feature_incompat; /* incompatible feature set */ + struct feature_ro_compat_str { + unsigned sparse_super : 1; + unsigned large_file : 1; + unsigned btree_dir : 1; + unsigned reserved : 27; + } __attribute__ ((packed)) s_feature_ro_compat; /* readonly-compatible feature set */ + __u8 s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + /* + * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. + */ + __u8 s_journal_uuid[16]; /* uuid of journal superblock */ + __u32 s_journal_inum; /* inode number of journal file */ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ + + __u32 s_reserved[197]; /* Padding to the end of the block */ + } E2FS_super_block; + +/* + * Structure of an inode on the disk + */ +typedef struct { + struct i_mode_str { +#if 0 + struct { + unsigned short execute : 1; + unsigned short write : 1; + unsigned short read : 1; + } __attribute__ ((packed)) other, group, user; +#else + unsigned short execute_other : 1; + unsigned short write_other : 1; + unsigned short read_other : 1; + unsigned short execute_group : 1; + unsigned short write_group : 1; + unsigned short read_group : 1; + unsigned short execute_user : 1; + unsigned short write_user : 1; + unsigned short read_user : 1; +#endif + unsigned short vtx : 1; + unsigned short gid : 1; + unsigned short uid : 1; + enum { + fmt_fifo = 1, + fmt_chr = 2, + fmt_dir = 4, + fmt_blk = 6, + fmt_reg = 8, + fmt_lnk = 10, + fmt_sock = 12 + } fmt : 4; + } __attribute__ ((packed)) i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + /* OS dependent 1: */ + __u32 i_translator; /* Only HURD, else reserved */ + /* end OS dependent 1 */ + __u32 i_direct_block[12]; + __u32 i_simple_indirect_block; + __u32 i_double_indirect_block; + __u32 i_triple_indirect_block; + __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_size_high; /* was i_dir_acl, i.e. Directory ACL */ + __u32 i_faddr; /* Fragment address */ + /* OS dependent 2: */ + __u8 i_frag; /* Fragment number */ + __u8 i_fsize; /* Fragment size */ + __u16 i_mode_high; /* Only HURD, else padding */ + /* Following is reserved for masix: */ + __u16 i_uid_high; + __u16 i_gid_high; + __u32 i_author; /* Only HURD, else reserved */ + /* end OS dependent 2 */ + } __attribute__ ((packed)) E2FS_inode; + +typedef struct { + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __u32 bg_reserved[3]; + } E2FS_group_desc; + +typedef struct { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + enum E2FS_file_type { + e2fs_ft_unknown = 0, + e2fs_ft_reg_file = 1, + e2fs_ft_dir = 2, + e2fs_ft_chrdev = 3, + e2fs_ft_blkdev = 4, + e2fs_ft_fifo = 5, + e2fs_ft_sock = 6, + e2fs_ft_symlink = 7 + } file_type : 8; + char name[EXT2_NAME_LEN]; /* File name (variable array) */ + } E2FS_dir_entry; + +#endif /* E2FS_H */ + diff --git a/Dump/hybos/include/esh/esh.h b/Dump/hybos/include/esh/esh.h new file mode 100644 index 0000000..5e71d8e --- /dev/null +++ b/Dump/hybos/include/esh/esh.h @@ -0,0 +1,33 @@ +/** + * esh.h + */ + +#ifndef _ESH_H +#define _ESH_H + +#define MAX_LEN 512 /* maximum length of a command */ +#define MAX_PARAMS 20 /* maximum ammount of parameters a command may have */ +#define COMMAND_COUNT 6 /* number of commands supported */ + +typedef struct ESHELL_COMMANDS +{ + int minparams; /* number of required parameters */ + int maxparams; /* number of maximum parameters supported */ + char command[MAX_LEN]; /* command entry */ + char params[MAX_PARAMS][MAX_LEN]; /* parameters for command [index]["entry"] */ + char description[MAX_LEN]; +} ESHCOMMANDS; + +typedef struct ESHELL_CURR_COMMAND +{ + int count; + char param[MAX_PARAMS][MAX_LEN]; + char value[MAX_PARAMS][MAX_LEN]; +} ESHCURRCOMMAND; + +void keyDown(unsigned key); +void keyUp(unsigned key); +void processCommand(char *line, int count); + +#endif /* _ESH_H */ + diff --git a/Dump/hybos/include/esh/esh.h~ b/Dump/hybos/include/esh/esh.h~ new file mode 100644 index 0000000..06508e7 --- /dev/null +++ b/Dump/hybos/include/esh/esh.h~ @@ -0,0 +1,32 @@ +/** + * esh.h + */ + +#ifndef _ESH_H +#define _ESH_H + +#define MAX_LEN 512 /* maximum length of a command */ +#define MAX_PARAMS 20 /* maximum ammount of parameters a command may have */ +#define COMMAND_COUNT 6 /* number of commands supported */ + +typedef struct ESHELL_COMMANDS +{ + int minparams; /* number of required parameters */ + int maxparams; /* number of maximum parameters supported */ + char command[MAX_LEN]; /* command entry */ + char params[MAX_PARAMS][MAX_LEN]; /* parameters for command [index]["entry"] */ +} ESHCOMMANDS; + +typedef struct ESHELL_CURR_COMMAND +{ + int count; + char param[MAX_PARAMS][MAX_LEN]; + char value[MAX_PARAMS][MAX_LEN]; +} ESHCURRCOMMAND; + +void keyDown(unsigned key); +void keyUp(unsigned key); +void processCommand(char *line, int count); + +#endif /* _ESH_H */ + diff --git a/Dump/hybos/include/fat.h b/Dump/hybos/include/fat.h new file mode 100644 index 0000000..aa9454d --- /dev/null +++ b/Dump/hybos/include/fat.h @@ -0,0 +1,84 @@ +#ifndef _FAT_H +#define _FAT_H + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; + +/** + * FAT12 and FAT16 bootsector + */ +typedef struct __FAT_BOOTSECTOR /* MUST be packed */ +{ + uint8_t jump[3]; /* 16-bit JMP to boot code, or 8-bit JMP + NOP */ + uint8_t oem_id[8]; /* e.g., 'MSWIN4.0' */ + uint16_t bytes_per_sector; /* typically 512 */ + uint8_t sectors_per_cluster; + uint16_t num_boot_sectors; /* typically 1 */ + uint8_t num_fats; /* typically 2 */ + uint16_t num_root_dir_ents; + uint16_t total_sectors; /* 16-bit; 0 if num sectors > 65535 */ + uint8_t media_ID_byte; /* typically 0F0h */ + uint16_t sectors_per_fat; + uint16_t sectors_per_track; + uint16_t heads; + uint32_t hidden_sectors; /* LBA partition start */ + uint32_t total_sectors_large; /* 32-bit; 0 if num sectors < 65536 */ + uint8_t boot_code[474]; + uint8_t magic[2]; /* 55h, 0AAh */ +} FAT_BOOTSECTOR; /* 512 bytes total */ + +/** + * FAT directory entries + * + * As far as I know, this should be valid for FAT12/16/32 + * Entries are 32 bytes long + */ +typedef struct __FAT_DIRSTRUCT /* MUST be packed */ +{ + uint8_t name[8]; /* all caps, pad right with spaces */ + uint8_t ext[3]; /* all caps, pad right with spaces */ + uint8_t attrib; /* attribute byte */ + uint8_t reserved; /* 0 */ + uint8_t ctime_ms; /* file creation time, 10ms units */ + uint16_t ctime; /* file creation time, in DOS format */ + uint16_t cdate; /* file creation date, in DOS format */ + uint16_t adate; /* DOS date of last file access */ + uint16_t st_clust_msw; /* high 16 bits of starting cluster (FAT32) */ + uint16_t mtime; /* DOS time of last file modification */ + uint16_t mdate; /* DOS date of last file modification */ + uint16_t st_clust; /* starting cluster */ + uint32_t file_size; /* in bytes */ +} FAT_DIRSTRUCT; /* 32 bytes total */ + +/** + * DOS time and date structs + */ +typedef struct __DOS_TIME /* MUST be packed */ +{ + unsigned two_secs : 5; /* low 5 bits: 2-second increments */ + unsigned minutes : 6; /* middle 6 bits: minutes */ + unsigned hours : 5; /* high 5 bits: hours (0-23) */ +} DOS_TIME; /* 2 bytes total */ + +typedef struct __DOS_DATE /* MUST be packed */ +{ + unsigned date : 5; /* low 5 bits: date (1-31) */ + unsigned month : 4; /* middle 4 bits: month (1-12) */ + unsigned year : 7; /* high 7 bits: year - 1980 */ +} DOS_DATE; /* 2 bytes total */ + +/** + * DOS File attributes + */ +typedef struct __DOS_ATTRIB /* MUST be packed */ +{ + int read_only : 1; /* b0 */ + int hidden : 1; + int system : 1; + int volume_label : 1; + int directory : 1; + int reserved : 2; /* b6, b7 */ +} DOS_ATTRIB; /* 1 byte total */ + +#endif /* ! _FAT_H */ diff --git a/Dump/hybos/include/keyboard.h b/Dump/hybos/include/keyboard.h new file mode 100644 index 0000000..872788c --- /dev/null +++ b/Dump/hybos/include/keyboard.h @@ -0,0 +1,415 @@ +#ifndef _KEYBOARD_H +#define _KEYBOARD_H + +/** + * For now we will default to __KB_IBM_PC_XT + */ +#define __KB_IBM_PC_XT + + +/** + * Just in case we were defined someplace else + */ +#ifdef __KB_IBM_PC_XT +#undef __KB_IBM_PC_AT +#undef __KB_IBM_PS2 +#elif defined(__KB_IBM_PC_AT) +#undef __KB_IBM_PC_XT +#undef __KB_IBM_PS2 +#else +#undef __KB_IBM_PC_AT +#undef __KB_IBM_PC_XT +#define __KB_IBM_PC_XT +#endif + + +#ifdef __KB_IBM_PC_XT +/** + * Set 1 Scancodes + * + * IBM PC XT + * + * __KB_IBM_PC_XT must be defined to use these + */ +#define KEY_ESC 0x01 +#define KEY_F1 0x3B +#define KEY_F2 0x3C +#define KEY_F3 0x3D +#define KEY_F4 0x3E +#define KEY_F5 0x3F +#define KEY_F6 0x40 +#define KEY_F7 0x41 +#define KEY_F8 0x42 +#define KEY_F9 0x43 +#define KEY_F10 0x44 +#define KEY_F11 0x57 +#define KEY_F12 0x58 +#define KEY_TILDA 0x29 +#define KEY_1 0x02 +#define KEY_2 0x03 +#define KEY_3 0x04 +#define KEY_4 0x05 +#define KEY_5 0x06 +#define KEY_6 0x07 +#define KEY_7 0x08 +#define KEY_8 0x09 +#define KEY_9 0x0A +#define KEY_0 0x0B +#define KEY_MINUS 0x0C +#define KEY_PLUS 0x0D +#define KEY_BKSLASH 0x2B +#define KEY_BKSPACE 0x0E +#define KEY_TAB 0x0F +#define KEY_Q 0x10 +#define KEY_W 0x11 +#define KEY_E 0x12 +#define KEY_R 0x13 +#define KEY_T 0x14 +#define KEY_Y 0x15 +#define KEY_U 0x16 +#define KEY_I 0x17 +#define KEY_O 0x18 +#define KEY_P 0x19 +#define KEY_LBRACKET 0x1A +#define KEY_RBRACKET 0x1B +#define KEY_ENTER 0x1C +#define KEY_CAPS 0x3A +#define KEY_A 0x1E +#define KEY_S 0x1F +#define KEY_D 0x20 +#define KEY_F 0x21 +#define KEY_G 0x22 +#define KEY_H 0x23 +#define KEY_J 0x24 +#define KEY_K 0x25 +#define KEY_L 0x26 +#define KEY_SEMICOLON 0x27 +#define KEY_QUOTE 0x28 +#define KEY_LSHIFT 0x2A +#define KEY_Z 0x2C +#define KEY_X 0x2D +#define KEY_C 0x2E +#define KEY_V 0x2F +#define KEY_B 0x30 +#define KEY_N 0x31 +#define KEY_M 0x32 +#define KEY_COMMA 0x33 +#define KEY_PERIOD 0x34 +#define KEY_SLASH 0x35 +#define KEY_RSHIFT 0x36 +#define KEY_LCTRL 0x1D +#define KEY_LWIN 0x5B +#define KEY_LALT 0x38 +#define KEY_SPACE 0x39 +#define KEY_RALT 0x38 +#define KEY_RWIN 0x5C +#define KEY_MENU 0x5D +#define KEY_RCTRL 0x1D +#define KEY_SCRLCK 0x46 /* scroll lock */ + +/** + * Keypad + */ +#define KEYP_NUMLCK 0x45 +#define KEYP_SLASH 0x35 +#define KEYP_ASTERISK 0x37 +#define KEYP_MINUS 0x4A +#define KEYP_7 0x47 +#define KEYP_8 0x48 +#define KEYP_9 0x49 +#define KEYP_PLUS 0x4E +#define KEYP_4 0x4B +#define KEYP_5 0x4C +#define KEYP_6 0x4D +#define KEYP_1 0x4F +#define KEYP_2 0x50 +#define KEYP_3 0x51 +#define KEYP_ENTER 0x1C +#define KEYP_0 0x52 +#define KEYP_PERIOD 0x53 + +/** + * Insert, Home, Page Up cluster + */ +#define KEY_INSERT 0x52 +#define KEY_HOME 0x47 +#define KEY_PGUP 0x49 +#define KEY_DEL 0x53 +#define KEY_END 0x4F +#define KEY_PGDOWN 0x51 + +/** + * Arrow key cluster + */ +#define KEY_UP 0x48 +#define KEY_LEFT 0x4B +#define KEY_DOWN 0x50 +#define KEY_RIGHT 0x4D + +/** + * FIXME: Experimental + */ +//#define KEY_PRTSCR 0xE02AE037 /* print screen */ +//#define KEY_PAUSE 0xE11D45E19DC5 /* pause/break */ + +#endif /* defined(__KB_IBM_PC_XT) */ + +#ifdef __KB_IBM_PC_AT +/** + * Set 2 Scancodes + * + * IBM PC AT + * + * __KB_IBM_PC_AT must be defined to use these + */ +#define KEY_ESC 0x76 +#define KEY_F1 0x05 +#define KEY_F2 0x06 +#define KEY_F3 0x04 +#define KEY_F4 0x0C +#define KEY_F5 0x03 +#define KEY_F6 0x0B +#define KEY_F7 0x83 +#define KEY_F8 0x0A +#define KEY_F9 0x01 +#define KEY_F10 0x09 +#define KEY_F11 0x78 +#define KEY_F12 0x07 +#define KEY_TILDA 0x0E +#define KEY_1 0x16 +#define KEY_2 0x1E +#define KEY_3 0x26 +#define KEY_4 0x25 +#define KEY_5 0x2E +#define KEY_6 0x36 +#define KEY_7 0x3D +#define KEY_8 0x3E +#define KEY_9 0x46 +#define KEY_0 0x45 +#define KEY_MINUS 0x4E +#define KEY_PLUS 0x55 +#define KEY_BKSLASH 0x5D +#define KEY_BKSPACE 0x66 +#define KEY_TAB 0x0D +#define KEY_Q 0x15 +#define KEY_W 0x1D +#define KEY_E 0x24 +#define KEY_R 0x2D +#define KEY_T 0x2C +#define KEY_Y 0x35 +#define KEY_U 0x3C +#define KEY_I 0x43 +#define KEY_O 0x44 +#define KEY_P 0x4D +#define KEY_LBRACKET 0x54 +#define KEY_RBRACKET 0x5B +#define KEY_ENTER 0x5A +#define KEY_CAPS 0x58 +#define KEY_A 0x1C +#define KEY_S 0x1B +#define KEY_D 0x23 +#define KEY_F 0x2B +#define KEY_G 0x34 +#define KEY_H 0x33 +#define KEY_J 0x3B +#define KEY_K 0x42 +#define KEY_L 0x4B +#define KEY_SEMICOLON 0x4C +#define KEY_QUOTE 0x52 +#define KEY_LSHIFT 0x12 +#define KEY_Z 0x1A +#define KEY_X 0x22 +#define KEY_C 0x21 +#define KEY_V 0x2A +#define KEY_B 0x32 +#define KEY_N 0x31 +#define KEY_M 0x3A +#define KEY_COMMA 0x41 +#define KEY_PERIOD 0x49 +#define KEY_SLASH 0x4A +#define KEY_RSHIFT 0x59 +#define KEY_LCTRL 0x14 +#define KEY_LWIN 0xE01F +#define KEY_LALT 0x11 +#define KEY_SPACE 0x29 +#define KEY_RALT 0xE011 +#define KEY_RWIN 0xE027 +#define KEY_MENU 0xE02F +#define KEY_RCTRL 0xE014 +#define KEY_SCRLCK 0x7E /* scroll lock */ + +/** + * Keypad + */ +#define KEYP_NUMLCK 0x77 +#define KEYP_SLASH 0xE04A +#define KEYP_ASTERISK 0x7C +#define KEYP_MINUS 0x7B +#define KEYP_7 0x6C +#define KEYP_8 0x75 +#define KEYP_9 0x7D +#define KEYP_PLUS 0x79 +#define KEYP_4 0x6B +#define KEYP_5 0x73 +#define KEYP_6 0x74 +#define KEYP_1 0x69 +#define KEYP_2 0x72 +#define KEYP_3 0x7A +#define KEYP_ENTER 0xE05A +#define KEYP_0 0x70 +#define KEYP_PERIOD 0x71 + +/** + * Insert, Home, Page Up cluster + */ +#define KEY_INSERT 0xE070 +#define KEY_HOME 0xE06C +#define KEY_PGUP 0xE07D +#define KEY_DEL 0xE071 +#define KEY_END 0xE069 +#define KEY_PGDOWN 0xE07A + +/** + * Arrow key cluster + */ +#define KEY_UP 0xE075 +#define KEY_LEFT 0xE06B +#define KEY_DOWN 0xE072 +#define KEY_RIGHT 0xE074 + +/** + * FIXME: Experimental + */ +#define KEY_PRTSCR 0xE012E07C /* print screen */ +#define KEY_PAUSE 0xE11477E1F014F077 /* pause/break */ + +#endif /* defined(__KB_IBM_PC_AT) */ + +#ifdef __KB_IBM_PS2 +/** + * Set 1 Scancodes + * + * IBM PC XT + * + * __KB_IBM_PS2 must be defined to use these + */ +#define KEY_ESC 0x08 +#define KEY_F1 0x07 +#define KEY_F2 0x0F +#define KEY_F3 0x17 +#define KEY_F4 0x1F +#define KEY_F5 0x27 +#define KEY_F6 0x2F +#define KEY_F7 0x37 +#define KEY_F8 0x3F +#define KEY_F9 0x47 +#define KEY_F10 0x4F +#define KEY_F11 0x56 +#define KEY_F12 0x5E +#define KEY_TILDA 0x0E +#define KEY_1 0x16 +#define KEY_2 0x1E +#define KEY_3 0x26 +#define KEY_4 0x25 +#define KEY_5 0x2E +#define KEY_6 0x36 +#define KEY_7 0x3D +#define KEY_8 0x3E +#define KEY_9 0x46 +#define KEY_0 0x45 +#define KEY_MINUS 0x4E +#define KEY_PLUS 0x55 +#define KEY_BKSLASH 0x5C +#define KEY_BKSPACE 0x66 +#define KEY_TAB 0x0D +#define KEY_Q 0x15 +#define KEY_W 0x1D +#define KEY_E 0x24 +#define KEY_R 0x2D +#define KEY_T 0x2C +#define KEY_Y 0x35 +#define KEY_U 0x3C +#define KEY_I 0x43 +#define KEY_O 0x44 +#define KEY_P 0x4D +#define KEY_LBRACKET 0x54 +#define KEY_RBRACKET 0x5B +#define KEY_ENTER 0x5A +#define KEY_CAPS 0x14 +#define KEY_A 0x1C +#define KEY_S 0x1B +#define KEY_D 0x23 +#define KEY_F 0x2B +#define KEY_G 0x34 +#define KEY_H 0x33 +#define KEY_J 0x3B +#define KEY_K 0x42 +#define KEY_L 0x4B +#define KEY_SEMICOLON 0x4C +#define KEY_QUOTE 0x52 +#define KEY_LSHIFT 0x12 +#define KEY_Z 0x1A +#define KEY_X 0x22 +#define KEY_C 0x21 +#define KEY_V 0x2A +#define KEY_B 0x32 +#define KEY_N 0x31 +#define KEY_M 0x3A +#define KEY_COMMA 0x41 +#define KEY_PERIOD 0x49 +#define KEY_SLASH 0x4A +#define KEY_RSHIFT 0x59 +#define KEY_LCTRL 0x11 +#define KEY_LWIN 0x8B +#define KEY_LALT 0x19 +#define KEY_SPACE 0x29 +#define KEY_RALT 0x39 +#define KEY_RWIN 0x8C +#define KEY_MENU 0x8D +#define KEY_RCTRL 0x58 +#define KEY_SCRLCK 0x5F /* scroll lock */ +#define KEY_PRTSCR 0x57 /* print screen */ +#define KEY_PAUSE 0x62 /* pause/break */ + +/** + * Keypad + */ +#define KEYP_NUMLCK 0x76 +#define KEYP_SLASH 0x77 +#define KEYP_ASTERISK 0x7E +#define KEYP_MINUS 0x84 +#define KEYP_7 0x6C +#define KEYP_8 0x75 +#define KEYP_9 0x7D +#define KEYP_PLUS 0x7C +#define KEYP_4 0x6B +#define KEYP_5 0x73 +#define KEYP_6 0x74 +#define KEYP_1 0x69 +#define KEYP_2 0x72 +#define KEYP_3 0x7A +#define KEYP_ENTER 0x79 +#define KEYP_0 0x70 +#define KEYP_PERIOD 0x71 + +/** + * Insert, Home, Page Up cluster + */ +#define KEY_INSERT 0x67 +#define KEY_HOME 0x6E +#define KEY_PGUP 0x6F +#define KEY_DEL 0x64 +#define KEY_END 0x65 +#define KEY_PGDOWN 0x6D + +/** + * Arrow key cluster + */ +#define KEY_UP 0x63 +#define KEY_LEFT 0x61 +#define KEY_DOWN 0x60 +#define KEY_RIGHT 0x6A + +#endif /* defined(__KB_IBM_PS2) */ + +#endif /* ! _KEYBOARD_H */ diff --git a/Dump/hybos/include/keymap.h b/Dump/hybos/include/keymap.h new file mode 100644 index 0000000..0194ba8 --- /dev/null +++ b/Dump/hybos/include/keymap.h @@ -0,0 +1,142 @@ +/* keymap.h - defines for keymapping Author: Marcus Hampel + */ +#ifndef _SYS__KEYMAP_H +#define _SYS__KEYMAP_H + +#define C(c) ((c) & 0x1F) /* Map to control code */ +#define A(c) ((c) | 0x80) /* Set eight bit (ALT) */ +#define CA(c) A(C(c)) /* Control-Alt */ +#define L(c) ((c) | HASCAPS) /* Add "Caps Lock has effect" attribute */ + +#define EXT 0x0100 /* Normal function keys */ +#define CTRL 0x0200 /* Control key */ +#define SHIFT 0x0400 /* Shift key */ +#define ALT 0x0800 /* Alternate key */ +#define EXTKEY 0x1000 /* extended keycode */ +#define HASCAPS 0x8000 /* Caps Lock has effect */ + +/* Numeric keypad */ +#define HOME (0x01 + EXT) +#define END (0x02 + EXT) +#define UP (0x03 + EXT) +#define DOWN (0x04 + EXT) +#define LEFT (0x05 + EXT) +#define RIGHT (0x06 + EXT) +#define PGUP (0x07 + EXT) +#define PGDN (0x08 + EXT) +#define MID (0x09 + EXT) +#define NMIN (0x0A + EXT) +#define PLUS (0x0B + EXT) +#define INSRT (0x0C + EXT) + +/* Alt + Numeric keypad */ +#define AHOME (0x01 + ALT) +#define AEND (0x02 + ALT) +#define AUP (0x03 + ALT) +#define ADOWN (0x04 + ALT) +#define ALEFT (0x05 + ALT) +#define ARIGHT (0x06 + ALT) +#define APGUP (0x07 + ALT) +#define APGDN (0x08 + ALT) +#define AMID (0x09 + ALT) +#define ANMIN (0x0A + ALT) +#define APLUS (0x0B + ALT) +#define AINSRT (0x0C + ALT) + +/* Ctrl + Numeric keypad */ +#define CHOME (0x01 + CTRL) +#define CEND (0x02 + CTRL) +#define CUP (0x03 + CTRL) +#define CDOWN (0x04 + CTRL) +#define CLEFT (0x05 + CTRL) +#define CRIGHT (0x06 + CTRL) +#define CPGUP (0x07 + CTRL) +#define CPGDN (0x08 + CTRL) +#define CMID (0x09 + CTRL) +#define CNMIN (0x0A + CTRL) +#define CPLUS (0x0B + CTRL) +#define CINSRT (0x0C + CTRL) + +/* Lock keys */ +#define CALOCK (0x0D + EXT) /* caps lock */ +#define NLOCK (0x0E + EXT) /* number lock */ +#define SLOCK (0x0F + EXT) /* scroll lock */ + +/* Function keys */ +#define F1 (0x10 + EXT) +#define F2 (0x11 + EXT) +#define F3 (0x12 + EXT) +#define F4 (0x13 + EXT) +#define F5 (0x14 + EXT) +#define F6 (0x15 + EXT) +#define F7 (0x16 + EXT) +#define F8 (0x17 + EXT) +#define F9 (0x18 + EXT) +#define F10 (0x19 + EXT) +#define F11 (0x1A + EXT) +#define F12 (0x1B + EXT) + +/* Alt+Fn */ +#define AF1 (0x10 + ALT) +#define AF2 (0x11 + ALT) +#define AF3 (0x12 + ALT) +#define AF4 (0x13 + ALT) +#define AF5 (0x14 + ALT) +#define AF6 (0x15 + ALT) +#define AF7 (0x16 + ALT) +#define AF8 (0x17 + ALT) +#define AF9 (0x18 + ALT) +#define AF10 (0x19 + ALT) +#define AF11 (0x1A + ALT) +#define AF12 (0x1B + ALT) + +/* Ctrl+Fn */ +#define CF1 (0x10 + CTRL) +#define CF2 (0x11 + CTRL) +#define CF3 (0x12 + CTRL) +#define CF4 (0x13 + CTRL) +#define CF5 (0x14 + CTRL) +#define CF6 (0x15 + CTRL) +#define CF7 (0x16 + CTRL) +#define CF8 (0x17 + CTRL) +#define CF9 (0x18 + CTRL) +#define CF10 (0x19 + CTRL) +#define CF11 (0x1A + CTRL) +#define CF12 (0x1B + CTRL) + +/* Shift+Fn */ +#define SF1 (0x10 + SHIFT) +#define SF2 (0x11 + SHIFT) +#define SF3 (0x12 + SHIFT) +#define SF4 (0x13 + SHIFT) +#define SF5 (0x14 + SHIFT) +#define SF6 (0x15 + SHIFT) +#define SF7 (0x16 + SHIFT) +#define SF8 (0x17 + SHIFT) +#define SF9 (0x18 + SHIFT) +#define SF10 (0x19 + SHIFT) +#define SF11 (0x1A + SHIFT) +#define SF12 (0x1B + SHIFT) + +/* Alt+Shift+Fn */ +#define ASF1 (0x10 + ALT + SHIFT) +#define ASF2 (0x11 + ALT + SHIFT) +#define ASF3 (0x12 + ALT + SHIFT) +#define ASF4 (0x13 + ALT + SHIFT) +#define ASF5 (0x14 + ALT + SHIFT) +#define ASF6 (0x15 + ALT + SHIFT) +#define ASF7 (0x16 + ALT + SHIFT) +#define ASF8 (0x17 + ALT + SHIFT) +#define ASF9 (0x18 + ALT + SHIFT) +#define ASF10 (0x19 + ALT + SHIFT) +#define ASF11 (0x1A + ALT + SHIFT) +#define ASF12 (0x1B + ALT + SHIFT) + +#define MAP_COLS 6 /* Number of columns in keymap */ +#define NR_SCAN_CODES 0x80 /* Number of scan codes (rows in keymap) */ + +typedef unsigned short keymap_t[NR_SCAN_CODES * MAP_COLS]; + +#define KEY_MAGIC "KMAZ" /* Magic number of keymap file */ + +#endif /* _SYS__KEYMAP_H */ diff --git a/Dump/hybos/include/mmzone.h b/Dump/hybos/include/mmzone.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Dump/hybos/include/mmzone.h diff --git a/Dump/hybos/include/setjmp.h b/Dump/hybos/include/setjmp.h new file mode 100644 index 0000000..ab44eed --- /dev/null +++ b/Dump/hybos/include/setjmp.h @@ -0,0 +1,24 @@ +#ifndef __TL_SETJMP_H +#define __TL_SETJMP_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef struct +{ +/* setjmp() and longjmp() rely on the order of these registers, +so do not re-arrange them */ + unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax; + unsigned eip, eflags; +} jmp_buf[1]; + +int setjmp(jmp_buf b); +void longjmp(jmp_buf b, int ret_val); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/include/signal.h b/Dump/hybos/include/signal.h new file mode 100644 index 0000000..178e074 --- /dev/null +++ b/Dump/hybos/include/signal.h @@ -0,0 +1,52 @@ +/** + * signal.h + */ + +#ifndef _SIGNAL_H +#define _SIGNAL_H + +typedef int sig_atomic_t; + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 /* interrupt (DEL) */ +#define SIGQUIT 3 /* quit (ASCII FS) */ +#define SIGILL 4 /* illegal instruction */ +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGABRT 6 /* IOT instruction */ +#define SIGBUS 7 +#define SIGEMT 7 +#define SIGFPE 8 /* floating point exception */ +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGUSR1 10 /* user defined signal 1 */ +#define SIGSEGV 11 /* segmentation violation */ +#define SIGUSR2 12 /* user defined signal 2 */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#define SIGALRM 14 /* alarm clock */ +#define SIGTERM 15 /* software termination signal from kill */ + +/** + * For POSIX compliance + */ +#define SIGCHLD 17 /* child process terminated or stopped */ +#define SIGCONT 18 /* continue if stopped */ +#define SIGSTOP 19 /* stop signal */ +#define SIGTSTP 20 /* interactive stop signal */ +#define SIGTTIN 21 /* background process requesting read */ +#define SIGTTOU 22 /* background process requesting write */ + +#if 0 +#define SIG_ERR ((__sighandler_t) -1) /* error return */ +#define SIG_DFL ((__sighandler_t) 0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t) 1) /* ignore signal */ +#endif /* 0 */ + +#define _NSIG 23 + +#if 0 +int raise(int sig); +__sighandler_t signal(int sig, __sighandler_t func); +int kill(pid_t pid, int sig); +#endif /* 0 */ + +#endif /* _SIGNAL_H */ + diff --git a/Dump/hybos/include/signal.h~ b/Dump/hybos/include/signal.h~ new file mode 100644 index 0000000..d70f0a6 --- /dev/null +++ b/Dump/hybos/include/signal.h~ @@ -0,0 +1,50 @@ +/** + * signal.h + */ + +#ifndef _SIGNAL_H +#define _SIGNAL_H + +typedef int sig_atomic_t; + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 /* interrupt (DEL) */ +#define SIGQUIT 3 /* quit (ASCII FS) */ +#define SIGILL 4 /* illegal instruction */ +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGABRT 6 /* IOT instruction */ +#define SIGBUS 7 +#define SIGEMT 7 +#define SIGFPE 8 /* floating point exception */ +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGUSR1 10 /* user defined signal 1 */ +#define SIGSEGV 11 /* segmentation violation */ +#define SIGUSR2 12 /* user defined signal 2 */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#define SIGALRM 14 /* alarm clock */ +#define SIGTERM 15 /* software termination signal from kill */ + +/** + * For POSIX compliance + */ +#define SIGCHLD 17 /* child process terminated or stopped */ +#define SIGCONT 18 /* continue if stopped */ +#define SIGSTOP 19 /* stop signal */ +#define SIGTSTP 20 /* interactive stop signal */ +#define SIGTTIN 21 /* background process requesting read */ +#define SIGTTOU 22 /* background process requesting write */ + +#if 0 +#define SIG_ERR ((__sighandler_t) -1) /* error return */ +#define SIG_DFL ((__sighandler_t) 0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t) 1) /* ignore signal */ +#endif /* 0 */ + +#define _NSIG 23 + +int raise(int sig); +__sighandler_t signal(int sig, __sighandler_t func); +int kill(pid_t pid, int sig); + +#endif /* _SIGNAL_H */ + diff --git a/Dump/hybos/include/stdarg.h b/Dump/hybos/include/stdarg.h new file mode 100644 index 0000000..8394b00 --- /dev/null +++ b/Dump/hybos/include/stdarg.h @@ -0,0 +1,35 @@ +#ifndef __TL_STDARG_H +#define __TL_STDARG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <_va_list.h> + +/* width of stack == width of int */ +#define STACKITEM int + +/* round up width of objects pushed on stack. The expression before the +& ensures that we get 0 for objects of size 0. */ +#define VA_SIZE(TYPE) \ + ((sizeof(TYPE) + sizeof(STACKITEM) - 1) \ + & ~(sizeof(STACKITEM) - 1)) + +/* &(LASTARG) points to the LEFTMOST argument of the function call +(before the ...) */ +#define va_start(AP, LASTARG) \ + (AP=((va_list)&(LASTARG) + VA_SIZE(LASTARG))) + +#define va_end(AP) /* nothing */ + +#define va_arg(AP, TYPE) \ + (AP += VA_SIZE(TYPE), *((TYPE *)(AP - VA_SIZE(TYPE)))) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Dump/hybos/include/stdbool.h b/Dump/hybos/include/stdbool.h new file mode 100644 index 0000000..05084b9 --- /dev/null +++ b/Dump/hybos/include/stdbool.h @@ -0,0 +1,6 @@ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +typedef enum {false = 0, true = !0} bool; + +#endif /* !defined(_STDBOOL_H) */ diff --git a/Dump/hybos/include/stddef.h b/Dump/hybos/include/stddef.h new file mode 100644 index 0000000..049d0e7 --- /dev/null +++ b/Dump/hybos/include/stddef.h @@ -0,0 +1,11 @@ +#ifndef _STDDEF_H +#define _STDDEF_H + +#define NULL ((void *)0) + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#endif /* _STDDEF_H */ diff --git a/Dump/hybos/include/stdint.h b/Dump/hybos/include/stdint.h new file mode 100644 index 0000000..02e7645 --- /dev/null +++ b/Dump/hybos/include/stdint.h @@ -0,0 +1,166 @@ +#ifndef _STDINT_H +#define _STDINT_H + +/* 7.18.1.1 Exact-width integer types */ +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +/* 7.18.1.2 Minimum-width integer types */ +typedef signed char int_least8_t; +typedef unsigned char uint_least8_t; +typedef short int_least16_t; +typedef unsigned short uint_least16_t; +typedef int int_least32_t; +typedef unsigned uint_least32_t; +typedef long long int_least64_t; +typedef unsigned long long uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types + * Not actually guaranteed to be fastest for all purposes + * Here we use the exact-width types for 8 and 16-bit ints. + */ +typedef char int_fast8_t; +typedef unsigned char uint_fast8_t; +typedef short int_fast16_t; +typedef unsigned short uint_fast16_t; +typedef int int_fast32_t; +typedef unsigned int uint_fast32_t; +typedef long long int_fast64_t; +typedef unsigned long long uint_fast64_t; + +/* 7.18.1.4 Integer types capable of holding object pointers */ +typedef int intptr_t; +typedef unsigned uintptr_t; + +/* 7.18.1.5 Greatest-width integer types */ +typedef long long intmax_t; +typedef unsigned long long uintmax_t; + +/* 7.18.2 Limits of specified-width integer types */ +#if !defined ( __cplusplus) || defined (__STDC_LIMIT_MACROS) + +/* 7.18.2.1 Limits of exact-width integer types */ +#define INT8_MIN (-128) +#define INT16_MIN (-32768) +#define INT32_MIN (-2147483647 - 1) +#define INT64_MIN (-9223372036854775807LL - 1) + +#define INT8_MAX 127 +#define INT16_MAX 32767 +#define INT32_MAX 2147483647 +#define INT64_MAX 9223372036854775807LL + +#define UINT8_MAX 0xff /* 255U */ +#define UINT16_MAX 0xffff /* 65535U */ +#define UINT32_MAX 0xffffffff /* 4294967295U */ +#define UINT64_MAX 0xffffffffffffffffULL /* 18446744073709551615ULL */ + +/* 7.18.2.2 Limits of minimum-width integer types */ +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST64_MIN INT64_MIN + +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MAX INT64_MAX + +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +/* 7.18.2.3 Limits of fastest minimum-width integer types */ +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST64_MIN INT64_MIN + +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MAX INT64_MAX + +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +/* 7.18.2.4 Limits of integer types capable of holding + object pointers */ +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX + +/* 7.18.2.5 Limits of greatest-width integer types */ +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +/* 7.18.3 Limits of other integer types */ +#define PTRDIFF_MIN INT32_MIN +#define PTRDIFF_MAX INT32_MAX + +#define SIG_ATOMIC_MIN INT32_MIN +#define SIG_ATOMIC_MAX INT32_MAX + +#define SIZE_MAX UINT32_MAX + +#ifndef WCHAR_MIN /* also in wchar.h */ +#define WCHAR_MIN 0 +#define WCHAR_MAX ((wchar_t)-1) /* UINT16_MAX */ +#endif + +/* + * wint_t is unsigned short for compatibility with MS runtime + */ +#define WINT_MIN 0 +#define WINT_MAX ((wint_t)-1) /* UINT16_MAX */ + +#endif /* !defined ( __cplusplus) || defined __STDC_LIMIT_MACROS */ + + +/* 7.18.4 Macros for integer constants */ +#if !defined ( __cplusplus) || defined (__STDC_CONSTANT_MACROS) + +/* 7.18.4.1 Macros for minimum-width integer constants + + Accoding to Douglas Gwyn : + "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC + 9899:1999 as initially published, the expansion was required + to be an integer constant of precisely matching type, which + is impossible to accomplish for the shorter types on most + platforms, because C99 provides no standard way to designate + an integer constant with width less than that of type int. + TC1 changed this to require just an integer constant + *expression* with *promoted* type." + + The trick used here is from Clive D W Feather. +*/ + +#define INT8_C(val) (INT_LEAST8_MAX-INT_LEAST8_MAX+(val)) +#define INT16_C(val) (INT_LEAST16_MAX-INT_LEAST16_MAX+(val)) +#define INT32_C(val) (INT_LEAST32_MAX-INT_LEAST32_MAX+(val)) +/* The 'trick' doesn't work in C89 for long long because, without + suffix, (val) will be evaluated as int, not intmax_t */ +#define INT64_C(val) val##LL + +#define UINT8_C(val) (UINT_LEAST8_MAX-UINT_LEAST8_MAX+(val)) +#define UINT16_C(val) (UINT_LEAST16_MAX-UINT_LEAST16_MAX+(val)) +#define UINT32_C(val) (UINT_LEAST32_MAX-UINT_LEAST32_MAX+(val)) +#define UINT64_C(val) val##ULL + +/* 7.18.4.2 Macros for greatest-width integer constants */ +#define INTMAX_C(val) val##LL +#define UINTMAX_C(val) val##ULL + +#endif /* !defined ( __cplusplus) || defined __STDC_CONSTANT_MACROS */ + +#endif /* !defined(_STDINT_H) */ diff --git a/Dump/hybos/include/stdio.h b/Dump/hybos/include/stdio.h new file mode 100644 index 0000000..54f5ada --- /dev/null +++ b/Dump/hybos/include/stdio.h @@ -0,0 +1,79 @@ +/** + * stdio.h + * + * Input/output functions + */ + +#ifndef _STDIO_H +#define _STDIO_H + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#ifndef _NULL +#define NULL ((void *)0) +#endif +#define EOF (-1) + +#define FOPEN_MAX 20 +#define FILENAME_MAX 14 +#define TMP_MAX 999 + +typedef long int fpos_t; + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +/*int remove(const char *_filename);*/ +/*int rename(const char *_old, const char *_new);*/ +/*FILE *tmpfile(void);*/ +/*char *tmpnam(char *_s);*/ +/*int fclose(FILE *_stream);*/ +/*int fflush(FILE *_stream);*/ +/*FILE *fopen(const char *_filename, const char *_mode);*/ +/*FILE *freopen(const char *_filename, const char *_mode, FILE *_stream);*/ +/*void setbuf(FILE *_stream, char *_buf);*/ +/*int setvbuf(FILE *_stream, char *_buf, int _mode, size_t _size);*/ +/*int fprintf(FILE *_stream, const char *_format, ...);*/ +/*int printf(const char *fmt, ...);*/ +void printf(const char *format, ...); +int sprintf(char *s, const char *format, ...); +/*int vfprintf(FILE *_stream, const char *_format, char *_arg);*/ +/*int vprintf(const char *_format, char *_arg);*/ +int vsprintf(char *s, const char *format, ...); +/*int fscanf(FILE *_stream, const char *_format, ...);*/ +/*int scanf(const char *_format, ...);*/ +/*int sscanf(const char *_s, const char *_format, ...);*/ +/*#define vfscanf _doscan*/ +/*int vfscanf(FILE *_stream, const char *_format, char *_arg);*/ +/*int vscanf(const char *_format, char *_arg);*/ +/*int vsscanf(const char *_s, const char *_format, char *_arg);*/ +/*int fgetc(FILE *_stream);*/ +/*char *fgets(char *_s, int _n, FILE *_stream);*/ +/*int fputc(int _c, FILE *_stream);*/ +/*int fputs(const char *_s, FILE *_stream);*/ +/*int getc(FILE *_stream);*/ +/*int getchar(void);*/ +/*char *gets(char *_s);*/ +/*int putc(int _c, FILE *_stream);*/ +/*int putchar(int _c);*/ +/*int puts(const char *_s);*/ +/*int ungetc(int _c, FILE *_stream);*/ +/*size_t fread(void *_ptr, size_t _size, size_t _nmemb, FILE *_stream);*/ +/*size_t fwrite(const void *_ptr, size_t _size, size_t _nmemb, FILE *_stream);*/ +/*int fgetpos(FILE *_stream, fpos_t *_pos);*/ +/*int fseek(FILE *_stream, long _offset, int _whence);*/ +/*int fsetpos(FILE *_stream, fpos_t *_pos);*/ +/*long ftell(FILE *_stream);*/ +/*void rewind(FILE *_stream);*/ +/*void clearerr(FILE *_stream);*/ +/*int feof(FILE *_stream);*/ +/*int ferror(FILE *_stream);*/ +/*void perror(const char *_s);*/ +/*int __fillbuf(FILE *_stream);*/ +/*int __flushbuf(int _c, FILE *_stream);*/ + +#endif /* _STDIO_H */ diff --git a/Dump/hybos/include/stdlib.h b/Dump/hybos/include/stdlib.h new file mode 100644 index 0000000..f26dce9 --- /dev/null +++ b/Dump/hybos/include/stdlib.h @@ -0,0 +1,58 @@ +/** + * stdlib.h + * + * Defines certain common macros, types, and functions + */ + +#ifndef _STDLIB_H +#define _STDLIB_H + +#ifndef _NULL +#define NULL ((void *)0) +#endif + +#define EXIT_FAILURE 1 /* standard error returned from exit() */ +#define EXIT_SUCCESS 0 /* successfull return from exit() */ +#define RAND_MAX 32767 /* largest value generated by rand() */ +#define MB_CUR_MAX 1 /* maximum value of multibyte character */ + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#ifndef _WCHAR_T +#define _WCHAR_T +typedef char wchar_t; +#endif + +/*void abort(void);*/ +int abs(int number); +/*int atexit(void (*_func)(void));*/ +/*double atof(const char *_nptr);*/ +int atoi(const char *nptr); +/*long atol(const char *_nptr);*/ +/*void *calloc(size_t _nmemb, size_t _size);*/ +/*div_t div(int _numer, int _denom);*/ +/*void exit(int _status);*/ +void free(void *blk); +/*char *getenv(const char *_name);*/ +/*long labs(long _j);*/ +/*ldiv_t ldiv(long _numer, long _denom);*/ +void *malloc(size_t _size); +/*int mblen(const char *_s, size_t _n);*/ +/*size_t mbstowcs(wchar_t *_pwcs, const char *_s, size_t _n);*/ +/*int mbtowc(wchar_t *_pwc, const char *_s, size_t _n);*/ +void *realloc(void *blk, size_t size); +/*double strtod(const char *_nptr, char **_endptr);*/ +/*long strtol(const char *_nptr, char **_endptr, int _base);*/ +/*int system(const char *_string);*/ +/*size_t wcstombs(char *_s, const wchar_t *_pwcs, size_t _n);*/ +/*int wctomb(char *_s, wchar_t _wchar);*/ +/*void *bsearch(const void *_key, const void *_base, size_t _nmemb, size_t _size, int (*compar) (const void *, const void *));*/ +/*void qsort(void *_base, size_t _nmemb, size_t _size, int (*compar) (const void *, const void *));*/ +int rand(void); +void srand(unsigned int seed); +/*unsigned long int strtoul(const char *_nptr, char **_endptr, int _base);*/ + +#endif /* _STDLIB_H */ diff --git a/Dump/hybos/include/string.h b/Dump/hybos/include/string.h new file mode 100644 index 0000000..2637730 --- /dev/null +++ b/Dump/hybos/include/string.h @@ -0,0 +1,26 @@ +#ifndef __TL_STRING_H +#define __TL_STRING_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*#include <_size_t.h>*/ +/*#include <_null.h>*/ +#include + +void *memcpy(void *dst_ptr, const void *src_ptr, size_t count); +void *memsetw(void *dst, int val, size_t count); +size_t strlen(const char *str); +int strcmp(const char * src, const char * dst); +int strncmp(const char * first, const char * last, size_t count); +char *strcpy(char *s, const char *t); +char *strncpy(char * dest, const char * source, size_t count); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Dump/hybos/include/sys/dir.h b/Dump/hybos/include/sys/dir.h new file mode 100644 index 0000000..8c9e071 --- /dev/null +++ b/Dump/hybos/include/sys/dir.h @@ -0,0 +1,19 @@ +#ifndef _DIR_H +#define _DIR_H + +/** + * Size of directory block + */ +#define DIRBLKSIZE 512 + +#ifndef DIRSIZ +#define DIRSIZ 14 +#endif + +typedef struct __DIR__DIRECT_ +{ + unsigned int d_ino; /* defined as __kernel_ino_t in posix_types.h */ + char d_name[DIRSIZ]; +} direct; + +#endif /* _DIR_H */ diff --git a/Dump/hybos/include/time.h b/Dump/hybos/include/time.h new file mode 100644 index 0000000..efcc0b3 --- /dev/null +++ b/Dump/hybos/include/time.h @@ -0,0 +1,52 @@ +/** + * time.h + */ + +#ifndef _TIME_H +#define _TIME_H + +#define CLOCKS_PER_SEC 60 /* 60 Hz */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#ifndef _TIME_T +#define _TIME_T +typedef long time_t; /* time in seconds since January 1, 1970 0000 GMT */ +#endif + +#ifndef _CLOCK_T +#define _CLOCK_T +typedef long clock_t; /* time in ticks since process started */ +#endif + +typedef struct __TIME_H_TIME +{ + int tm_sec; /* seconds after the minute [0, 59] */ + int tm_min; /* minutes after the hour [0, 59] */ + int tm_hour; /* hours since midnight [0, 23] */ + int tm_mday; /* day of the month [1, 31] */ + int tm_mon; /* months since January [0, 11] */ + int tm_year; /* years since 1900 */ + int tm_wday; /* days since Sunday [0, 6] */ + int tm_yday; /* days since January 1 [0, 365] */ + int tm_isdst; /* Daylight Saving Time flag */ +} dm, TIME; + +clock_t clock(void); +double difftime(time_t time1, time_t time0); +time_t mktime(struct tm *pTime); +time_t time(time_t *pTime); +char *asctime(const struct tm *pTime); +char *ctime(const time_t *pTimer); +struct tm *gmtime(const time_t *pTimer); +size_t strftime(char *s, size_t max, const char *format, const struct tm *pTime); + +#endif /* _TIME_H */ + diff --git a/Dump/hybos/include/x86.h b/Dump/hybos/include/x86.h new file mode 100644 index 0000000..4373723 --- /dev/null +++ b/Dump/hybos/include/x86.h @@ -0,0 +1,26 @@ +#ifndef __TL_X86_H +#define __TL_X86_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * 16 bit MSB: segment, 16 bit LSB: offset + */ +//typedef unsigned farptr; + +unsigned inportb(unsigned short port); +void outportb(unsigned port, unsigned val); +unsigned inportw(unsigned short port); +void outportw(unsigned port, unsigned val); +unsigned disable(void); +void enable(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Dump/hybos/lib/Makefile b/Dump/hybos/lib/Makefile new file mode 100644 index 0000000..0b91a38 --- /dev/null +++ b/Dump/hybos/lib/Makefile @@ -0,0 +1,33 @@ +#MAKEFILE=ming.mak +MAKEFILE =Makefile + +OBJS =objects/*.o + +all: + make -f $(MAKEFILE) -C char + make -f $(MAKEFILE) -C config + make -f $(MAKEFILE) -C convert + make -f $(MAKEFILE) -C ctype + make -f $(MAKEFILE) -C math + make -f $(MAKEFILE) -C mem + make -f $(MAKEFILE) -C setjmp + make -f $(MAKEFILE) -C stdio + make -f $(MAKEFILE) -C string + make -f $(MAKEFILE) -C util + make -f $(MAKEFILE) -C x86 + ar rcs libc.a $(OBJS) + +clean: + make -f $(MAKEFILE) -C char clean + make -f $(MAKEFILE) -C config clean + make -f $(MAKEFILE) -C convert clean + make -f $(MAKEFILE) -C ctype clean + make -f $(MAKEFILE) -C math clean + make -f $(MAKEFILE) -C mem clean + make -f $(MAKEFILE) -C setjmp clean + make -f $(MAKEFILE) -C stdio clean + make -f $(MAKEFILE) -C string clean + make -f $(MAKEFILE) -C util clean + make -f $(MAKEFILE) -C x86 clean + del libc.a + diff --git a/Dump/hybos/lib/char/Makefile b/Dump/hybos/lib/char/Makefile new file mode 100644 index 0000000..654c46f --- /dev/null +++ b/Dump/hybos/lib/char/Makefile @@ -0,0 +1,71 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +CHAR =isalnum.o \ + isalpha.o \ + isascii.o \ + iscsym.o \ + iscsymf.o \ + isctrl.o \ + isdigit.o \ + isgraph.o \ + islower.o \ + isprint.o \ + ispunct.o \ + isspace.o \ + isupper.o \ + isxdigit.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(CHAR) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\isalnum.o + del ..\$(OBJ_DIR)\isalpha.o + del ..\$(OBJ_DIR)\isascii.o + del ..\$(OBJ_DIR)\iscsym.o + del ..\$(OBJ_DIR)\iscsymf.o + del ..\$(OBJ_DIR)\isctrl.o + del ..\$(OBJ_DIR)\isdigit.o + del ..\$(OBJ_DIR)\isgraph.o + del ..\$(OBJ_DIR)\islower.o + del ..\$(OBJ_DIR)\isprint.o + del ..\$(OBJ_DIR)\ispunct.o + del ..\$(OBJ_DIR)\isspace.o + del ..\$(OBJ_DIR)\isupper.o + del ..\$(OBJ_DIR)\isxdigit.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +isalnum.o: isalnum.c $(MAKEDEP) +isalpha.o: isalpha.c $(MAKEDEP) +isascii.o: isascii.c $(MAKEDEP) +iscsym.o: iscsym.c $(MAKEDEP) +iscsymf.o: iscsymf.c $(MAKEDEP) +isctrl.o: isctrl.c $(MAKEDEP) +isdigit.o: isdigit.c $(MAKEDEP) +isgraph.o: isgraph.c $(MAKEDEP) +islower.o: islower.c $(MAKEDEP) +isprint.o: isprint.c $(MAKEDEP) +ispunct.o: ispunct.c $(MAKEDEP) +isspace.o: isspace.c $(MAKEDEP) +isupper.o: isupper.c $(MAKEDEP) +isxdigit.o: isxdigit.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/char/isalnum.c b/Dump/hybos/lib/char/isalnum.c new file mode 100644 index 0000000..b985767 --- /dev/null +++ b/Dump/hybos/lib/char/isalnum.c @@ -0,0 +1,6 @@ +#include + +bool isalnum(const char c) +{ + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '1' && c <= '9')); +} diff --git a/Dump/hybos/lib/char/isalpha.c b/Dump/hybos/lib/char/isalpha.c new file mode 100644 index 0000000..7397c02 --- /dev/null +++ b/Dump/hybos/lib/char/isalpha.c @@ -0,0 +1,6 @@ +#include + +bool isalpha(const char c) +{ + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); +} diff --git a/Dump/hybos/lib/char/isascii.c b/Dump/hybos/lib/char/isascii.c new file mode 100644 index 0000000..27ed32c --- /dev/null +++ b/Dump/hybos/lib/char/isascii.c @@ -0,0 +1,6 @@ +#include + +bool isascii(const unsigned char c) +{ + return (c >= 0x00 && c <= 0x7F); +} diff --git a/Dump/hybos/lib/char/iscsym.c b/Dump/hybos/lib/char/iscsym.c new file mode 100644 index 0000000..ec3d9a3 --- /dev/null +++ b/Dump/hybos/lib/char/iscsym.c @@ -0,0 +1,6 @@ +#include + +bool iscsym(const char c) +{ + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '_')); +} diff --git a/Dump/hybos/lib/char/iscsymf.c b/Dump/hybos/lib/char/iscsymf.c new file mode 100644 index 0000000..b37e422 --- /dev/null +++ b/Dump/hybos/lib/char/iscsymf.c @@ -0,0 +1,6 @@ +#include + +bool iscsymf(const char c) +{ + return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_')); +} diff --git a/Dump/hybos/lib/char/isctrl.c b/Dump/hybos/lib/char/isctrl.c new file mode 100644 index 0000000..9b9ba01 --- /dev/null +++ b/Dump/hybos/lib/char/isctrl.c @@ -0,0 +1,6 @@ +#include + +bool isctrl(const char c) +{ + return (!(c >= ' ' && c <= '~')); +} diff --git a/Dump/hybos/lib/char/isdigit.c b/Dump/hybos/lib/char/isdigit.c new file mode 100644 index 0000000..dfe5951 --- /dev/null +++ b/Dump/hybos/lib/char/isdigit.c @@ -0,0 +1,6 @@ +#include + +bool isdigit(const char c) +{ + return (c >= '0' && c <= '9'); +} diff --git a/Dump/hybos/lib/char/isgraph.c b/Dump/hybos/lib/char/isgraph.c new file mode 100644 index 0000000..5c0a5ed --- /dev/null +++ b/Dump/hybos/lib/char/isgraph.c @@ -0,0 +1,6 @@ +#include + +bool isgraph(const unsigned char c) +{ + return (!(c >= 0x00 && c <= 0x7F)); +} diff --git a/Dump/hybos/lib/char/islower.c b/Dump/hybos/lib/char/islower.c new file mode 100644 index 0000000..2fee8c8 --- /dev/null +++ b/Dump/hybos/lib/char/islower.c @@ -0,0 +1,6 @@ +#include + +bool islowwer(const char c) +{ + return (c >= 'a' && c <= 'z'); +} diff --git a/Dump/hybos/lib/char/isprint.c b/Dump/hybos/lib/char/isprint.c new file mode 100644 index 0000000..b6be32b --- /dev/null +++ b/Dump/hybos/lib/char/isprint.c @@ -0,0 +1,6 @@ +#include + +bool isprint(const char c) +{ + return (c >= ' ' && c <= '~'); +} diff --git a/Dump/hybos/lib/char/ispunct.c b/Dump/hybos/lib/char/ispunct.c new file mode 100644 index 0000000..7c826ce --- /dev/null +++ b/Dump/hybos/lib/char/ispunct.c @@ -0,0 +1,6 @@ +#include + +bool ispunct(const char c) +{ + return ((c >= '!' && c<= '/') || (c >= ':' && c<= '@') || (c >= '[' && c<= '`') || (c >= '{' && c<= '~')); +} diff --git a/Dump/hybos/lib/char/isspace.c b/Dump/hybos/lib/char/isspace.c new file mode 100644 index 0000000..1d9800d --- /dev/null +++ b/Dump/hybos/lib/char/isspace.c @@ -0,0 +1,6 @@ +#include + +bool isspace(const char c) +{ + return (c == ' ' || (c >= 0x09 && c <= 0x0D)); +} diff --git a/Dump/hybos/lib/char/isupper.c b/Dump/hybos/lib/char/isupper.c new file mode 100644 index 0000000..5838170 --- /dev/null +++ b/Dump/hybos/lib/char/isupper.c @@ -0,0 +1,6 @@ +#include + +bool isupper(const char c) +{ + return (c >= 'A' && c <= 'Z'); +} diff --git a/Dump/hybos/lib/char/isxdigit.c b/Dump/hybos/lib/char/isxdigit.c new file mode 100644 index 0000000..50592fe --- /dev/null +++ b/Dump/hybos/lib/char/isxdigit.c @@ -0,0 +1,6 @@ +#include + +bool isxdigit(const char c) +{ + return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +} diff --git a/Dump/hybos/lib/config/Makefile b/Dump/hybos/lib/config/Makefile new file mode 100644 index 0000000..2bd4b3d --- /dev/null +++ b/Dump/hybos/lib/config/Makefile @@ -0,0 +1,32 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +CONFIG =config.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(CONFIG) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\config.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +config.o: config.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/config/config.c b/Dump/hybos/lib/config/config.c new file mode 100644 index 0000000..7c8b764 --- /dev/null +++ b/Dump/hybos/lib/config/config.c @@ -0,0 +1,36 @@ +/** + * Compiler configuration + */ + +#ifdef __GNUC__ +#define COMPILER "GNU C Compiler " __VERSION__ +typedef enum {false = 0, true = !0} bool; +typedef unsigned size_t; +typedef signed char __int8; +typedef signed short int __int16; +typedef signed int __int32; +typedef signed long long int __int64; + +#define int8 __int8 +#define int16 __int16 +#define int32 __int32 +#define int64 __int64 + +typedef unsigned char uint8; +typedef unsigned short int uint16; +typedef unsigned int uint32; +typedef unsigned long long int uint64; + +#define uint8 __uint8 +#define uint16 __uint16 +#define uint32 __uint32 +#define uint64 __uint64 + +/*typedef void* pointer;*/ +/*typedef unsigned char string;*/ + +#define discardable +#else +#error "Compiler not supported" +#endif /* __GNUC__ */ + diff --git a/Dump/hybos/lib/convert/Makefile b/Dump/hybos/lib/convert/Makefile new file mode 100644 index 0000000..a2a4409 --- /dev/null +++ b/Dump/hybos/lib/convert/Makefile @@ -0,0 +1,56 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +CONVERT =atoi16.o \ + atoi32.o \ + atoi64.o \ + atoi.o \ + i16toa.o \ + i32toa.o \ + i64toa.o \ + itoa.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(CONVERT) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\atoi16.o + del ..\$(OBJ_DIR)\atoi32.o + del ..\$(OBJ_DIR)\atoi64.o + del ..\$(OBJ_DIR)\atoi.o + del ..\$(OBJ_DIR)\i16toa.o + del ..\$(OBJ_DIR)\i32toa.o + del ..\$(OBJ_DIR)\i64toa.o + del ..\$(OBJ_DIR)\itoa.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +atoi.o: atoi.c $(MAKEDEP) +itoa.o: itoa.c $(MAKEDEP) +atoi16.o: atoi16.c $(MAKEDEP) +atoi32.o: atoi32.c $(MAKEDEP) +atoi64.o: atoi64.c $(MAKEDEP) +i16toa.o: i16toa.c $(MAKEDEP) +i32toa.o: i32toa.c $(MAKEDEP) +i64toa.o: i64toa.c $(MAKEDEP) +u16toa.o: u16toa.c $(MAKEDEP) +u32toa.o: u32toa.c $(MAKEDEP) +u64toa.o: u64toa.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/convert/atoi.c b/Dump/hybos/lib/convert/atoi.c new file mode 100644 index 0000000..7bdc127 --- /dev/null +++ b/Dump/hybos/lib/convert/atoi.c @@ -0,0 +1,33 @@ +#include + +long atoi(const char *nptr) +{ + int c; /* current char */ + long total; /* current total */ + int sign; /* if '-', then negative, otherwise positive */ + + /* skip whitespace */ + while(isspace((int)(unsigned char)*nptr)) + ++nptr; + + c = (int)(unsigned char)*nptr++; + sign = c; /* save sign indication */ + + /* skip sign */ + if(c == '-' || c == '+') + c = (int)(unsigned char)*nptr++; + + total = 0; + + while(isdigit(c)) + { + total = 10 * total + (c - '0'); /* accumulate digit */ + c = (int)(unsigned char)*nptr++; /* get next char */ + } + + /* return result, negated if necessary */ + if(sign == '-') + return -total; + else + return total; +} diff --git a/Dump/hybos/lib/convert/atoi16.c b/Dump/hybos/lib/convert/atoi16.c new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Dump/hybos/lib/convert/atoi16.c @@ -0,0 +1 @@ + diff --git a/Dump/hybos/lib/convert/atoi32.c b/Dump/hybos/lib/convert/atoi32.c new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Dump/hybos/lib/convert/atoi32.c @@ -0,0 +1 @@ + diff --git a/Dump/hybos/lib/convert/atoi64.c b/Dump/hybos/lib/convert/atoi64.c new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Dump/hybos/lib/convert/atoi64.c @@ -0,0 +1 @@ + diff --git a/Dump/hybos/lib/convert/i16toa.c b/Dump/hybos/lib/convert/i16toa.c new file mode 100644 index 0000000..0e31625 --- /dev/null +++ b/Dump/hybos/lib/convert/i16toa.c @@ -0,0 +1,39 @@ +#include + +void i16toa(int16_t value, char *string, uint8_t radix) +{ + char *i, *s, t, d; + + i = string; + + if(value < 0) + { + *i++ = '-'; + value = -value; + } + + s = i; + + do + { + d = value % radix; + value /= radix; + + if(d > 9) + *i++ = d + 'A' - 10; + else + *i++ = d + '0'; + } while (value > 0); + + *i-- = '\0'; + + do + { + t = *i; + *i = *s; + *s = t; + + --i; + ++s; + } while (s < i); +} diff --git a/Dump/hybos/lib/convert/i32toa.c b/Dump/hybos/lib/convert/i32toa.c new file mode 100644 index 0000000..09f65ea --- /dev/null +++ b/Dump/hybos/lib/convert/i32toa.c @@ -0,0 +1,39 @@ +#include + +void i32toa(int32_t value, char *string, uint8_t radix) +{ + char *i, *s, t, d; + + i = string; + + if(value < 0) + { + *i++ = '-'; + value = -value; + } + + s = i; + + do + { + d = value % radix; + value /= radix; + + if (d > 9) + *i++ = d + 'A' - 10; + else + *i++ = d + '0'; + } while (value > 0); + + *i-- = '\0'; + + do + { + t = *i; + *i = *s; + *s = t; + + --i; + ++s; + } while (s < i); +} diff --git a/Dump/hybos/lib/convert/i64toa.c b/Dump/hybos/lib/convert/i64toa.c new file mode 100644 index 0000000..0f93b27 --- /dev/null +++ b/Dump/hybos/lib/convert/i64toa.c @@ -0,0 +1,39 @@ +#include + +void i64toa(int64_t value, char *string, uint8_t radix) +{ + char *i, *s, t, d; + + i = string; + + if(value < 0) + { + *i++ = '-'; + value = -value; + } + + s = i; + + do + { + d = value % radix; + value /= radix; + + if(d > 9) + *i++ = d + 'A' - 10; + else + *i++ = d + '0'; + } while (value > 0); + + *i-- = '\0'; + + do + { + t = *i; + *i = *s; + *s = t; + + --i; + ++s; + } while (s < i); +} diff --git a/Dump/hybos/lib/convert/itoa.c b/Dump/hybos/lib/convert/itoa.c new file mode 100644 index 0000000..3fc6ce7 --- /dev/null +++ b/Dump/hybos/lib/convert/itoa.c @@ -0,0 +1,104 @@ +/*** +*xtoa.c - convert integers/longs to ASCII string +* +* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* The module has code to convert integers/longs to ASCII strings. See +* +*******************************************************************************/ + + +/*** +*char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII +* string +* +*Purpose: +* Converts an int to a character string. +* +*Entry: +* val - number to be converted (int, long or unsigned long) +* int radix - base to convert into +* char *buf - ptr to buffer to place result +* +*Exit: +* fills in space pointed to by buf with string result +* returns a pointer to this buffer +* +*Exceptions: +* +*******************************************************************************/ + +/* helper routine that does the main job. */ + +static void xtoa(unsigned long val, char *buf, unsigned radix, int is_neg) +{ + char *p; /* pointer to traverse string */ + char *firstdig; /* pointer to first digit */ + char temp; /* temp char */ + unsigned digval; /* value of digit */ + + p = buf; + + if(is_neg) + { + /* negative, so output '-' and negate */ + *p++ = '-'; + val = (unsigned long)(-(long)val); + } + + firstdig = p; /* save pointer to first digit */ + + do + { + digval = (unsigned) (val % radix); + val /= radix; /* get next digit */ + + /* convert to ascii and store */ + if (digval > 9) + *p++ = (char) (digval - 10 + 'a'); /* a letter */ + else + *p++ = (char) (digval + '0'); /* a digit */ + } while (val > 0); + + /** + * We now have the digit of the number in the buffer, but in reverse + * order. Thus we reverse them now. + */ + + *p-- = '\0'; /* terminate string; p points to last digit */ + + do + { + temp = *p; + *p = *firstdig; + *firstdig = temp; /* swap *p and *firstdig */ + --p; + ++firstdig; /* advance to next two digits */ + } while (firstdig < p); /* repeat until halfway */ +} + +/** + * Actual functions just call conversion helper with neg flag set correctly, + * and return pointer to buffer. + */ +char * _itoa(int val, char *buf, int radix) +{ + if(radix == 10 && val < 0) + xtoa((unsigned long)val, buf, radix, 1); + else + xtoa((unsigned long)(unsigned int)val, buf, radix, 0); + return buf; +} + +char * _ltoa(long val, char *buf, int radix) +{ + xtoa((unsigned long)val, buf, radix, (radix == 10 && val < 0)); + return buf; +} + +char * _ultoa(unsigned long val, char *buf, int radix) +{ + xtoa(val, buf, radix, 0); + return buf; +} diff --git a/Dump/hybos/lib/convert/u16toa.c b/Dump/hybos/lib/convert/u16toa.c new file mode 100644 index 0000000..e9075ab --- /dev/null +++ b/Dump/hybos/lib/convert/u16toa.c @@ -0,0 +1,29 @@ +void u16toa(unt16 value, char *string, unt8 radix) +{ + char *i, *s, t, d; + + s = i = string; + + do + { + d = value % radix; + value /= radix; + + if(d > 9) + *i++ = d + 'A' - 10; + else + *i++ = d + '0'; + } while (value > 0); + + *i-- = '\0'; + + do + { + t = *i; + *i = *s; + *s = t; + + --i; + ++s; + } while (s < i); +} diff --git a/Dump/hybos/lib/convert/u32toa.c b/Dump/hybos/lib/convert/u32toa.c new file mode 100644 index 0000000..06a34f7 --- /dev/null +++ b/Dump/hybos/lib/convert/u32toa.c @@ -0,0 +1,29 @@ +void u32toa(unt32 value, char *string, unt8 radix) +{ + char *i, *s, t, d; + + s = i = string; + + do + { + d = value % radix; + value /= radix; + + if(d > 9) + *i++ = d + 'A' - 10; + else + *i++ = d + '0'; + } while (value > 0); + + *i-- = '\0'; + + do + { + t = *i; + *i = *s; + *s = t; + + --i; + ++s; + } while (s < i); +} diff --git a/Dump/hybos/lib/convert/u64toa.c b/Dump/hybos/lib/convert/u64toa.c new file mode 100644 index 0000000..d41fe9d --- /dev/null +++ b/Dump/hybos/lib/convert/u64toa.c @@ -0,0 +1,29 @@ +void u64toa(unt64 value, char *string, unt8 radix) +{ + char *i, *s, t, d; + + s = i = string; + + do + { + d = value % radix; + value /= radix; + + if(d > 9) + *i++ = d + 'A' - 10; + else + *i++ = d + '0'; + } while (value > 0); + + *i-- = '\0'; + + do + { + t = *i; + *i = *s; + *s = t; + + --i; + ++s; + } while (s < i); +} diff --git a/Dump/hybos/lib/ctype/Makefile b/Dump/hybos/lib/ctype/Makefile new file mode 100644 index 0000000..5f7fddd --- /dev/null +++ b/Dump/hybos/lib/ctype/Makefile @@ -0,0 +1,32 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +CTYPE =ctype.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(CTYPE) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\ctype.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +ctype.o: ctype.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/ctype/ctype.c b/Dump/hybos/lib/ctype/ctype.c new file mode 100644 index 0000000..0bf4150 --- /dev/null +++ b/Dump/hybos/lib/ctype/ctype.c @@ -0,0 +1,46 @@ +#include + +char _ctype[] = +{ + 0x00, +/* 0 */ CT_CTL, CT_CTL, CT_CTL, CT_CTL, + CT_CTL, CT_CTL, CT_CTL, CT_CTL, +/* 8 */ CT_CTL, CT_CTL | CT_WHT, CT_CTL | CT_WHT, CT_CTL | CT_WHT, + CT_CTL | CT_WHT, CT_CTL | CT_WHT, CT_CTL, CT_CTL, +/* 16 */CT_CTL, CT_CTL, CT_CTL, CT_CTL, + CT_CTL, CT_CTL, CT_CTL, CT_CTL, +/* 24 */CT_CTL, CT_CTL, CT_CTL, CT_CTL, + CT_CTL, CT_CTL, CT_CTL, CT_CTL, +/* ' ' */CT_WHT | CT_SP, CT_PUN, CT_PUN, CT_PUN, + CT_PUN, CT_PUN, CT_PUN, CT_PUN, +/* '(' */CT_PUN, CT_PUN, CT_PUN, CT_PUN, + CT_PUN, CT_PUN, CT_PUN, CT_PUN, +/* '0' */CT_DIG, CT_DIG, CT_DIG, CT_DIG, + CT_DIG, CT_DIG, CT_DIG, CT_DIG, +/* '8' */CT_DIG, CT_DIG, CT_PUN, CT_PUN, + CT_PUN, CT_PUN, CT_PUN, CT_PUN, +/* '@' */CT_PUN, CT_UP | CT_HEX, CT_UP | CT_HEX, CT_UP | CT_HEX, + CT_UP | CT_HEX, CT_UP | CT_HEX, CT_UP | CT_HEX, CT_UP, +/* 'H' */CT_UP, CT_UP, CT_UP, CT_UP, + CT_UP, CT_UP, CT_UP, CT_UP, +/* 'P' */CT_UP, CT_UP, CT_UP, CT_UP, + CT_UP, CT_UP, CT_UP, CT_UP, +/* 'X' */CT_UP, CT_UP, CT_UP, CT_PUN, + CT_PUN, CT_PUN, CT_PUN, CT_PUN, +/* '`' */CT_PUN, CT_LOW | CT_HEX, CT_LOW | CT_HEX, CT_LOW | CT_HEX, + CT_LOW | CT_HEX, CT_LOW | CT_HEX, CT_LOW | CT_HEX, CT_LOW, +/* h' */CT_LOW, CT_LOW, CT_LOW, CT_LOW, + CT_LOW, CT_LOW, CT_LOW, CT_LOW, +/* 'p' */CT_LOW, CT_LOW, CT_LOW, CT_LOW, + CT_LOW, CT_LOW, CT_LOW, CT_LOW, +/* 'x' */CT_LOW, CT_LOW, CT_LOW, CT_PUN, + CT_PUN, CT_PUN, CT_PUN, CT_CTL, +/* 128 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 144 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 160 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 176 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 192 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 208 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 224 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 240 */0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; diff --git a/Dump/hybos/lib/libc.a b/Dump/hybos/lib/libc.a new file mode 100644 index 0000000..68b8fcb --- /dev/null +++ b/Dump/hybos/lib/libc.a Binary files differ diff --git a/Dump/hybos/lib/math/Makefile b/Dump/hybos/lib/math/Makefile new file mode 100644 index 0000000..9e7bf8e --- /dev/null +++ b/Dump/hybos/lib/math/Makefile @@ -0,0 +1,44 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +MATH =abs.o \ + max.o \ + min.o \ + rotl.o \ + rotr.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(MATH) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\abs.o + del ..\$(OBJ_DIR)\max.o + del ..\$(OBJ_DIR)\min.o + del ..\$(OBJ_DIR)\rotl.o + del ..\$(OBJ_DIR)\rotr.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +abs.o: abs.c $(MAKEDEP) +max.o: max.c $(MAKEDEP) +min.o: min.c $(MAKEDEP) +rotl.o: rotl.c $(MAKEDEP) +rotr.o: rotr.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/math/abs.c b/Dump/hybos/lib/math/abs.c new file mode 100644 index 0000000..5d91f95 --- /dev/null +++ b/Dump/hybos/lib/math/abs.c @@ -0,0 +1,32 @@ +/*** +*abs.c - find absolute value +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines abs() - find the absolute value of an int. +* +*******************************************************************************/ + + +/*** +*int abs(number) - find absolute value of number +* +*Purpose: +* Returns the absolute value of number (if number >= 0, returns number, +* else returns -number). +* +*Entry: +* int number - number to find absolute value of +* +*Exit: +* returns the aboslute value of number +* +*Exceptions: +* +*******************************************************************************/ + +int abs(int number) +{ + return( number>=0 ? number : -number ); +} diff --git a/Dump/hybos/lib/math/max.c b/Dump/hybos/lib/math/max.c new file mode 100644 index 0000000..500e2ae --- /dev/null +++ b/Dump/hybos/lib/math/max.c @@ -0,0 +1,4 @@ +int max(int a, int b) +{ + return (a > b) ? a : b; +} diff --git a/Dump/hybos/lib/math/min.c b/Dump/hybos/lib/math/min.c new file mode 100644 index 0000000..2d7d2fd --- /dev/null +++ b/Dump/hybos/lib/math/min.c @@ -0,0 +1,4 @@ +int min(int a, int b) +{ + return (a < b) ? a : b; +} diff --git a/Dump/hybos/lib/math/rotl.c b/Dump/hybos/lib/math/rotl.c new file mode 100644 index 0000000..836d415 --- /dev/null +++ b/Dump/hybos/lib/math/rotl.c @@ -0,0 +1,49 @@ +/*** +*rotl.c - rotate an unsigned integer left +* +* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _rotl() - performs a rotate left on an unsigned integer. +* +*******************************************************************************/ + + +/*** +*unsigned _rotl(val, shift) - int rotate left +* +*Purpose: +* Performs a rotate left on an unsigned integer. +* +* [Note: The _lrotl entry is based on the assumption +* that sizeof(int) == sizeof(long).] +*Entry: +* unsigned val: value to rotate +* int shift: number of bits to shift by +* +*Exit: +* returns rotated value +* +*Exceptions: +* None. +* +*******************************************************************************/ + +unsigned rotl(unsigned val, int shift) +{ + register unsigned hibit; /* non-zero means hi bit set */ + register unsigned num = val; /* number to rotate */ + + shift &= 0x1f; /* modulo 32 -- this will also make + negative shifts work */ + + while(shift--) + { + hibit = num & 0x80000000; /* get high bit */ + num <<= 1; /* shift left one bit */ + if(hibit) + num |= 1; /* set lo bit if hi bit was set */ + } + + return num; +} diff --git a/Dump/hybos/lib/math/rotr.c b/Dump/hybos/lib/math/rotr.c new file mode 100644 index 0000000..5b9295f --- /dev/null +++ b/Dump/hybos/lib/math/rotr.c @@ -0,0 +1,52 @@ +/*** +*rotr.c - rotate an unsigned integer right +* +* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _rotr() - performs a rotate right on an unsigned integer. +* +*******************************************************************************/ + + + + +/*** +*unsigned _rotr(val, shift) - int rotate right +* +*Purpose: +* Performs a rotate right on an unsigned integer. +* +* [Note: The _lrotl entry is based on the assumption +* that sizeof(int) == sizeof(long).] +*Entry: +* unsigned val: value to rotate +* int shift: number of bits to shift by +* +*Exit: +* returns rotated value +* +*Exceptions: +* None. +* +*******************************************************************************/ + + +unsigned rotr(unsigned val, int shift) +{ + register unsigned lobit; /* non-zero means lo bit set */ + register unsigned num = val; /* number to rotate */ + + shift &= 0x1f; /* modulo 32 -- this will also make + negative shifts work */ + + while(shift--) + { + lobit = num & 1; /* get high bit */ + num >>= 1; /* shift right one bit */ + if(lobit) + num |= 0x80000000; /* set hi bit if lo bit was set */ + } + + return num; +} diff --git a/Dump/hybos/lib/mem/Makefile b/Dump/hybos/lib/mem/Makefile new file mode 100644 index 0000000..0cdbee4 --- /dev/null +++ b/Dump/hybos/lib/mem/Makefile @@ -0,0 +1,59 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +MEM =memccpy.o \ + memchr.o \ + memcmp.o \ + memcpy.o \ + memcpybw.o \ + memicmp.o \ + memmove.o \ + memset.o \ + memsetw.o \ + swab.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(MEM) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\memccpy.o + del ..\$(OBJ_DIR)\memchr.o + del ..\$(OBJ_DIR)\memcmp.o + del ..\$(OBJ_DIR)\memcpy.o + del ..\$(OBJ_DIR)\memcpybw.o + del ..\$(OBJ_DIR)\memicmp.o + del ..\$(OBJ_DIR)\memmove.o + del ..\$(OBJ_DIR)\memset.o + del ..\$(OBJ_DIR)\memsetw.o + del ..\$(OBJ_DIR)\swab.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +memccpy.o: memccpy.c $(MAKEDEP) +memchr.o: memchr.c $(MAKEDEP) +memcmp.o: memcmp.c $(MAKEDEP) +memcpy.o: memcpy.c $(MAKEDEP) +memcpybw.o: memcpybw.c $(MAKEDEP) +memicmp.o: memicmp.c $(MAKEDEP) +memmove.o: memmove.c $(MAKEDEP) +memset.o: memset.c $(MAKEDEP) +memsetw.o: memsetw.c $(MAKEDEP) +swab.o: swab.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/mem/memccpy.c b/Dump/hybos/lib/mem/memccpy.c new file mode 100644 index 0000000..2cd7167 --- /dev/null +++ b/Dump/hybos/lib/mem/memccpy.c @@ -0,0 +1,41 @@ +/*** +*memccpy.c - copy bytes until a character is found +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _memccpy() - copies bytes until a specifed character +* is found, or a maximum number of characters have been copied. +* +*******************************************************************************/ + + +/*** +*char *_memccpy(dest, src, c, count) - copy bytes until character found +* +*Purpose: +* Copies bytes from src to dest until count bytes have been +* copied, or up to and including the character c, whichever +* comes first. +* +*Entry: +* void *dest - pointer to memory to receive copy +* void *src - source of bytes +* int c - character to stop copy at +* unsigned int count - max number of bytes to copy +* +*Exit: +* returns pointer to byte immediately after c in dest +* returns NULL if c was never found +* +*Exceptions: +* +*******************************************************************************/ + +void *memccpy(void *dest, const void *src, int c, unsigned count) +{ + while(count && (*((char *)(dest = (char *)dest + 1) - 1) = *((char *)(src = (char *)src + 1) - 1)) != (char)c ) + count--; + + return count ? dest : 0; +} diff --git a/Dump/hybos/lib/mem/memchr.c b/Dump/hybos/lib/mem/memchr.c new file mode 100644 index 0000000..e2ead5c --- /dev/null +++ b/Dump/hybos/lib/mem/memchr.c @@ -0,0 +1,43 @@ +/*** +*memchr.c - search block of memory for a given character +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines memchr() - search memory until a character is +* found or a limit is reached. +* +*******************************************************************************/ + + +/*** +*char *memchr(buf, chr, cnt) - search memory for given character. +* +*Purpose: +* Searches at buf for the given character, stopping when chr is +* first found or cnt bytes have been searched through. +* +*Entry: +* void *buf - memory buffer to be searched +* int chr - character to search for +* size_t cnt - max number of bytes to search +* +*Exit: +* returns pointer to first occurence of chr in buf +* returns NULL if chr not found in the first cnt bytes +* +*Exceptions: +* +*******************************************************************************/ +#include <_size_t.h> + +void *memchr(const void * buf, int chr, size_t cnt) +{ + while( cnt && (*(unsigned char *)buf != (unsigned char)chr)) + { + buf = (unsigned char *)buf + 1; + cnt--; + } + + return cnt ? (void *)buf : 0; +} diff --git a/Dump/hybos/lib/mem/memcmp.c b/Dump/hybos/lib/mem/memcmp.c new file mode 100644 index 0000000..c05d451 --- /dev/null +++ b/Dump/hybos/lib/mem/memcmp.c @@ -0,0 +1,46 @@ +/*** +*memcmp.c - compare two blocks of memory +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines memcmp() - compare two memory blocks lexically and +* find their order. +* +*******************************************************************************/ + + +/*** +*int memcmp(buf1, buf2, count) - compare memory for lexical order +* +*Purpose: +* Compares count bytes of memory starting at buf1 and buf2 +* and find if equal or which one is first in lexical order. +* +*Entry: +* void *buf1, *buf2 - pointers to memory sections to compare +* size_t count - length of sections to compare +* +*Exit: +* returns < 0 if buf1 < buf2 +* returns 0 if buf1 == buf2 +* returns > 0 if buf1 > buf2 +* +*Exceptions: +* +*******************************************************************************/ +#include <_size_t.h> + +int memcmp(const void *buf1, const void *buf2, size_t count) +{ + if(!count) + return(0); + + while(--count && *(char *)buf1 == *(char *)buf2) + { + buf1 = (char *)buf1 + 1; + buf2 = (char *)buf2 + 1; + } + + return *((unsigned char *)buf1) - *((unsigned char *)buf2); +} diff --git a/Dump/hybos/lib/mem/memcpy.c b/Dump/hybos/lib/mem/memcpy.c new file mode 100644 index 0000000..39b3383 --- /dev/null +++ b/Dump/hybos/lib/mem/memcpy.c @@ -0,0 +1,13 @@ +void *memcpy(void *s, const void *t, unsigned n) +{ + void *ret = s; + + while(n--) + { + *(char *)s = *(char *)t; + s = (char *)s + 1; + t = (char *)t + 1; + } + + return ret; +} diff --git a/Dump/hybos/lib/mem/memcpybw.c b/Dump/hybos/lib/mem/memcpybw.c new file mode 100644 index 0000000..9f3d2b0 --- /dev/null +++ b/Dump/hybos/lib/mem/memcpybw.c @@ -0,0 +1,13 @@ +void *memcpybw(void *s, void *t, unsigned n) +{ + void *ret = s; + + while(n--) + { + *(char *)s = *(char *)t; + s = (char *)s + 2; + t = (char *)t + 1; + } + + return ret; +} diff --git a/Dump/hybos/lib/mem/memicmp.c b/Dump/hybos/lib/mem/memicmp.c new file mode 100644 index 0000000..38e4a49 --- /dev/null +++ b/Dump/hybos/lib/mem/memicmp.c @@ -0,0 +1,58 @@ +/*** +*memicmp.c - compare memory, ignore case +* +* Copyright (c) 1988-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _memicmp() - compare two blocks of memory for lexical +* order. Case is ignored in the comparison. +* +*******************************************************************************/ + + +#define _TOLOWER(c) ( ((c) >= 'A') && ((c) <= 'Z') ? ((c) - 'A' + 'a') :\ + (c) ) + +/*** +*int _memicmp(first, last, count) - compare two blocks of memory, ignore case +* +*Purpose: +* Compares count bytes of the two blocks of memory stored at first +* and last. The characters are converted to lowercase before +* comparing (not permanently), so case is ignored in the search. +* +*Entry: +* char *first, *last - memory buffers to compare +* unsigned count - maximum length to compare +* +*Exit: +* returns < 0 if first < last +* returns 0 if first == last +* returns > 0 if first > last +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +int _memicmp(const void * first, const void * last, unsigned int count) +{ + int f = 0; + int l = 0; + + while(count--) + { + if((*(unsigned char *)first == *(unsigned char *)last) || + ((f = _TOLOWER( *(unsigned char *)first)) == + (l = _TOLOWER( *(unsigned char *)last)))) + { + first = (char *)first + 1; + last = (char *)last + 1; + } + else + break; + } + + return (f - l); +} diff --git a/Dump/hybos/lib/mem/memmove.c b/Dump/hybos/lib/mem/memmove.c new file mode 100644 index 0000000..32bfad3 --- /dev/null +++ b/Dump/hybos/lib/mem/memmove.c @@ -0,0 +1,68 @@ +/*** +*memmove.c - contains memmove routine +* +* Copyright (c) 1988-1997, Microsoft Corporation. All right reserved. +* +*Purpose: +* memmove() copies a source memory buffer to a destination buffer. +* Overlapping buffers are treated specially, to avoid propogation. +* +*******************************************************************************/ + +/*** +*memmove - Copy source buffer to destination buffer +* +*Purpose: +* memmove() copies a source memory buffer to a destination memory buffer. +* This routine recognize overlapping buffers to avoid propogation. +* For cases where propogation is not a problem, memcpy() can be used. +* +*Entry: +* void *dst = pointer to destination buffer +* const void *src = pointer to source buffer +* size_t count = number of bytes to copy +* +*Exit: +* Returns a pointer to the destination buffer +* +*Exceptions: +*******************************************************************************/ +#include <_size_t.h> + +void *memmove(void *dst, const void *src, size_t count) +{ + void *ret = dst; + + + if(dst <= src || (char *)dst >= ((char *)src + count)) + { + /* + * Non-Overlapping Buffers + * copy from lower addresses to higher addresses + */ + while(count--) + { + *(char *)dst = *(char *)src; + dst = (char *)dst + 1; + src = (char *)src + 1; + } + } + else + { + /* + * Overlapping Buffers + * copy from higher addresses to lower addresses + */ + dst = (char *)dst + count - 1; + src = (char *)src + count - 1; + + while(count--) + { + *(char *)dst = *(char *)src; + dst = (char *)dst - 1; + src = (char *)src - 1; + } + } + + return ret; +} diff --git a/Dump/hybos/lib/mem/memset.c b/Dump/hybos/lib/mem/memset.c new file mode 100644 index 0000000..f385108 --- /dev/null +++ b/Dump/hybos/lib/mem/memset.c @@ -0,0 +1,12 @@ +void *memset(void *s, int i, unsigned n) +{ + void *start = s; + + while(n--) + { + *(char *)s = (char)i; + s = (char *)s + 1; + } + + return start; +} diff --git a/Dump/hybos/lib/mem/memsetw.c b/Dump/hybos/lib/mem/memsetw.c new file mode 100644 index 0000000..2c55f1d --- /dev/null +++ b/Dump/hybos/lib/mem/memsetw.c @@ -0,0 +1,13 @@ + +void *memsetw(void *s, short i, unsigned n) +{ + void *start = s; + + while(n--) + { + *(short *)s = (short)i; + s = (short *)s + 1; + } + + return(start); +} diff --git a/Dump/hybos/lib/mem/swab.c b/Dump/hybos/lib/mem/swab.c new file mode 100644 index 0000000..3a7eb8e --- /dev/null +++ b/Dump/hybos/lib/mem/swab.c @@ -0,0 +1,44 @@ +/*** +*swab.c - block copy, while swapping even/odd bytes +* +* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* This module contains the routine _swab() which swaps the odd/even +* bytes of words during a block copy. +* +*******************************************************************************/ + +/*** +*void _swab(srcptr, dstptr, nbytes) - swap ODD/EVEN bytes during word move +* +*Purpose: +* This routine copys a block of words and swaps the odd and even +* bytes. nbytes must be > 0, otherwise nothing is copied. If +* nbytes is odd, then only (nbytes-1) bytes are copied. +* +*Entry: +* srcptr = pointer to the source block +* dstptr = pointer to the destination block +* nbytes = number of bytes to swap +* +*Returns: +* None. +* +*Exceptions: +* +*******************************************************************************/ + +void swab(char *src, char *dest, int nbytes) +{ + char b1, b2; + + while(nbytes > 1) + { + b1 = *src++; + b2 = *src++; + *dest++ = b2; + *dest++ = b1; + nbytes -= 2; + } +} diff --git a/Dump/hybos/lib/setjmp/Makefile b/Dump/hybos/lib/setjmp/Makefile new file mode 100644 index 0000000..258ee28 --- /dev/null +++ b/Dump/hybos/lib/setjmp/Makefile @@ -0,0 +1,35 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +SETJMP =longjmp.o \ + setjmp.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(SETJMP) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\longjmp.o + del ..\$(OBJ_DIR)\setjmp.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +setjmp.o: setjmp.asm $(MAKEDEP) +longjmp.o: longjmp.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/setjmp/longjmp.c b/Dump/hybos/lib/setjmp/longjmp.c new file mode 100644 index 0000000..0f40418 --- /dev/null +++ b/Dump/hybos/lib/setjmp/longjmp.c @@ -0,0 +1,78 @@ +#include /* jmp_buf */ +/***************************************************************************** +To use setjmp() and longjmp() for asynchronous (interrupt-driven; +pre-emptive) task-switching, we want to enable interrupts simultaneous +with jumping to the task. In other words, we want the EFLAGS and EIP +registers loaded at the same time. + +The only instruction that can do this is IRET, which also loads the CS +register. Changing CS is done in code that uses far pointers, and it's +also done when changing address spaces, and when changing privilege levels. +We're not interested in any of those, so just push the current CS value +on the stack and let IRET use that. + +Three distinct stack pointer (ESP) values are used in this routine: +- 'Old' or 'current' stack pointer value, which is discarded by + this routine (use setjmp() to save it) +- ESP is made to point, briefly, to the jmp_buf struct itself +- 'New' ESP value; stored in jmp_buf.esp + +Register values are restored from the jmp_buf as follows: +1. Push jmp_buf.eflags, the current CS value, and jmp_buf.eip + onto the 'new' stack +2. Make ESP point to the jmp_buf struct itself, then use the POPA + instruction to pop the 7 general purpose registers (ESP is not + loaded by POPA). The use of POPA means that registers in the + jmp_buf MUST be stored in the order that POPA expects. + (Maybe use MOVs instead, to eliminate this restriction? + Might have to rewrite entire function in asm, instead of C.) +3. Load ESP with the 'new' stack pointer, from jmp_buf.esp +4. Use IRET to pop EIP, CS, and EFLAGS from the 'new' stack +5. ??? +6. Profit! <--- obligatory Slashdot joke + +This code does NOT save the floating-point state of the CPU. Either: +1. Don't use floating point, or +2. Don't use floating point in more than one thread, or +3. Rewrite this code so it DOES save the floating-point state, or +4. Save/restore the floating-point state when entering/leaving + the kernel (protected OS only) +*****************************************************************************/ +void longjmp(jmp_buf buf, int ret_val) +{ + unsigned *esp; + +/* make sure return value is not 0 */ + if(ret_val == 0) + ret_val++; +/* EAX is used for return values, so store it in jmp_buf.EAX */ + buf->eax = ret_val; +/* get ESP for new stack */ + esp = (unsigned *)buf->esp; +/* push EFLAGS on the new stack */ + esp--; + *esp = buf->eflags; +/* push current CS on the new stack */ + esp--; + __asm__ __volatile__( + "mov %%cs,%0\n" + : "=m"(*esp)); +/* push EIP on the new stack */ + esp--; + *esp = buf->eip; +/* new ESP is 12 bytes lower; update jmp_buf.ESP */ + buf->esp = (unsigned)esp; +/* now, briefly, make the jmp_buf struct our stack */ + __asm__ __volatile__( + "movl %0,%%esp\n" +/* ESP now points to 8 general-purpose registers stored in jmp_buf +Pop them */ + "popa\n" +/* load new stack pointer from jmp_buf */ + "movl -20(%%esp),%%esp\n" +/* ESP now points to new stack, with the IRET frame (EIP, CS, EFLAGS) +we created just above. Pop these registers: */ + "iret\n" + : + : "m"(buf)); +} diff --git a/Dump/hybos/lib/setjmp/setjmp.asm b/Dump/hybos/lib/setjmp/setjmp.asm new file mode 100644 index 0000000..e56d3b1 --- /dev/null +++ b/Dump/hybos/lib/setjmp/setjmp.asm @@ -0,0 +1,35 @@ +%include "asm.inc" + +SECTION .text + +EXP setjmp + push ebx + mov ebx,[8 + esp] + + mov [0 + ebx],edi ; buf->edi == 0(ebx) == EDI + mov [4 + ebx],esi ; buf->esi == 4(ebx) == ESI + mov [8 + ebx],ebp ; buf->ebp == 8(ebx) == EBP + + mov [20 + ebx],edx ; buf->edx == 20(ebx) == EDX + mov [24 + ebx],ecx ; buf->ecx == 24(ebx) == ECX + mov [28 + ebx],eax ; buf->eax == 28(ebx) == EAX + +; use EBX value saved on stack; not the current value + mov eax,[esp] + mov [16 + ebx],eax ; buf->ebx == 16(ebx) == EBX + +; use ESP value after RET; not the current value + lea eax,[8 + esp] + mov [12 + ebx],eax ; buf->esp == 32(ebx) == ESP + +; use return address of this routine (EIP value saved on stack); +; not the current value + mov eax,[4 + esp] + mov [32 + ebx],eax ; buf->eip == 36(ebx) == EIP + +; none of the PUSH or MOV instructions changed EFLAGS! + pushf + pop dword [36 + ebx] ; buf->eflags == 40(ebx) == EFLAGS + pop ebx + xor eax,eax + ret diff --git a/Dump/hybos/lib/stdio/.doprintf.c.swp b/Dump/hybos/lib/stdio/.doprintf.c.swp new file mode 100644 index 0000000..7956be6 --- /dev/null +++ b/Dump/hybos/lib/stdio/.doprintf.c.swp Binary files differ diff --git a/Dump/hybos/lib/stdio/Makefile b/Dump/hybos/lib/stdio/Makefile new file mode 100644 index 0000000..4d6994b --- /dev/null +++ b/Dump/hybos/lib/stdio/Makefile @@ -0,0 +1,38 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +STDIO =doprintf.o \ + sprintf.o \ + printf.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(STDIO) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\doprintf.o + del ..\$(OBJ_DIR)\sprintf.o + del ..\$(OBJ_DIR)\printf.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +doprintf.o: doprintf.c $(MAKEDEP) +sprintf.o: sprintf.c $(MAKEDEP) +printf.o: printf.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/stdio/doprintf.c b/Dump/hybos/lib/stdio/doprintf.c new file mode 100644 index 0000000..5f281da --- /dev/null +++ b/Dump/hybos/lib/stdio/doprintf.c @@ -0,0 +1,357 @@ +#include <_printf.h> /* fnptr_t */ +#include /* strlen() */ +#include /* va_list, va_arg() */ +/***************************************************************************** +Revised Jan 28, 2002 +- changes to make characters 0x80-0xFF display properly + +Revised June 10, 2001 +- changes to make vsprintf() terminate string with '\0' + +Revised May 12, 2000 +- math in DO_NUM is now unsigned, as it should be +- %0 flag (pad left with zeroes) now works +- actually did some TESTING, maybe fixed some other bugs + + name: do_printf + action: minimal subfunction for ?printf, calls function + 'fn' with arg 'ptr' for each character to be output + returns:total number of characters output + + %[flag][width][.prec][mod][conv] + flag: - left justify, pad right w/ blanks DONE + 0 pad left w/ 0 for numerics DONE + + always print sign, + or - no + ' ' (blank) no + # (???) no + + width: (field width) DONE + + prec: (precision) no + + conv: d,i decimal int DONE + u decimal unsigned DONE + o octal DONE + x,X hex DONE + f,e,g,E,G float no + c char DONE + s string DONE + p ptr DONE + + mod: N near ptr DONE + F far ptr no + h short (16-bit) int DONE + l long (32-bit) int DONE + L long long (64-bit) int no +*****************************************************************************/ +/* flags used in processing format string */ +#define PR_LJ 0x01 /* left justify */ +#define PR_CA 0x02 /* use A-F instead of a-f for hex */ +#define PR_SG 0x04 /* signed numeric conversion (%d vs. %u) */ +#define PR_32 0x08 /* long (32-bit) numeric conversion */ +#define PR_16 0x10 /* short (16-bit) numeric conversion */ +#define PR_WS 0x20 /* PR_SG set and num was < 0 */ +#define PR_LZ 0x40 /* pad left with '0' instead of ' ' */ +#define PR_FP 0x80 /* pointers are far */ + +/* largest number handled is 2^32-1, lowest radix handled is 8. +2^32-1 in base 8 has 11 digits (add 5 for trailing NUL and for slop) */ +#define PR_BUFLEN 16 + +int do_printf(const char *fmt, va_list args, fnptr_t fn, void *ptr) +{ + unsigned state, flags, radix, actual_wd, count, given_wd; + unsigned char *where, buf[PR_BUFLEN]; + long num; + + state = flags = count = given_wd = 0; +/* begin scanning format specifier list */ + for(; *fmt; fmt++) + { + switch(state) + { +/* STATE 0: AWAITING % */ + case 0: + if(*fmt != '%') /* not %... */ + { + fn(*fmt, &ptr); /* ...just echo it */ + count++; + break; + } +/* found %, get next char and advance state to check if next char is a flag */ + state++; + fmt++; + /* FALL THROUGH */ +/* STATE 1: AWAITING FLAGS (%-0) */ + case 1: + if(*fmt == '%') /* %% */ + { + fn(*fmt, &ptr); + count++; + state = flags = given_wd = 0; + break; + } + if(*fmt == '-') + { + if(flags & PR_LJ)/* %-- is illegal */ + state = flags = given_wd = 0; + else + flags |= PR_LJ; + break; + } +/* not a flag char: advance state to check if it's field width */ + state++; +/* check now for '%0...' */ + if(*fmt == '0') + { + flags |= PR_LZ; + fmt++; + } + /* FALL THROUGH */ +/* STATE 2: AWAITING (NUMERIC) FIELD WIDTH */ + case 2: + if(*fmt >= '0' && *fmt <= '9') + { + given_wd = 10 * given_wd + + (*fmt - '0'); + break; + } +/* not field width: advance state to check if it's a modifier */ + state++; + /* FALL THROUGH */ +/* STATE 3: AWAITING MODIFIER CHARS (FNlh) */ + case 3: + if(*fmt == 'F') + { + flags |= PR_FP; + break; + } + if(*fmt == 'N') + break; + if(*fmt == 'l') + { + flags |= PR_32; + break; + } + if(*fmt == 'h') + { + flags |= PR_16; + break; + } +/* not modifier: advance state to check if it's a conversion char */ + state++; + /* FALL THROUGH */ +/* STATE 4: AWAITING CONVERSION CHARS (Xxpndiuocs) */ + case 4: + where = buf + PR_BUFLEN - 1; + *where = '\0'; + switch(*fmt) + { + case 'X': + flags |= PR_CA; + /* FALL THROUGH */ +/* xxx - far pointers (%Fp, %Fn) not yet supported */ + case 'x': + case 'p': + case 'n': + radix = 16; + goto DO_NUM; + case 'd': + case 'i': + flags |= PR_SG; + /* FALL THROUGH */ + case 'u': + radix = 10; + goto DO_NUM; + case 'o': + radix = 8; +/* load the value to be printed. l=long=32 bits: */ +DO_NUM: if(flags & PR_32) + num = va_arg(args, unsigned long); +/* h=short=16 bits (signed or unsigned) */ + else if(flags & PR_16) + { + if(flags & PR_SG) + num = va_arg(args, short); + else + num = va_arg(args, unsigned short); + } +/* no h nor l: sizeof(int) bits (signed or unsigned) */ + else + { + if(flags & PR_SG) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + } +/* take care of sign */ + if(flags & PR_SG) + { + if(num < 0) + { + flags |= PR_WS; + num = -num; + } + } +/* convert binary to octal/decimal/hex ASCII +OK, I found my mistake. The math here is _always_ unsigned */ + do + { + unsigned long temp; + + temp = (unsigned long)num % radix; + where--; + if(temp < 10) + *where = temp + '0'; + else if(flags & PR_CA) + *where = temp - 10 + 'A'; + else + *where = temp - 10 + 'a'; + num = (unsigned long)num / radix; + } + while(num != 0); + goto EMIT; + case 'c': +/* disallow pad-left-with-zeroes for %c */ + flags &= ~PR_LZ; + where--; + *where = (unsigned char)va_arg(args, + unsigned char); + actual_wd = 1; + goto EMIT2; + case 's': +/* disallow pad-left-with-zeroes for %s */ + flags &= ~PR_LZ; + where = va_arg(args, unsigned char *); +EMIT: + actual_wd = strlen(where); + if(flags & PR_WS) + actual_wd++; +/* if we pad left with ZEROES, do the sign now */ + if((flags & (PR_WS | PR_LZ)) == + (PR_WS | PR_LZ)) + { + fn('-', &ptr); + count++; + } +/* pad on left with spaces or zeroes (for right justify) */ +EMIT2: if((flags & PR_LJ) == 0) + { + while(given_wd > actual_wd) + { + fn(flags & PR_LZ ? '0' : + ' ', &ptr); + count++; + given_wd--; + } + } +/* if we pad left with SPACES, do the sign now */ + if((flags & (PR_WS | PR_LZ)) == PR_WS) + { + fn('-', &ptr); + count++; + } +/* emit string/char/converted number */ + while(*where != '\0') + { + fn(*where++, &ptr); + count++; + } +/* pad on right with spaces (for left justify) */ + if(given_wd < actual_wd) + given_wd = 0; + else given_wd -= actual_wd; + for(; given_wd; given_wd--) + { + fn(' ', &ptr); + count++; + } + break; + default: + break; + } + default: + state = flags = given_wd = 0; + break; + } + } + return count; +} +#if 0 /* testing */ +/***************************************************************************** +SPRINTF +*****************************************************************************/ +int vsprintf_help(unsigned c, void **ptr) +{ + char *dst; + + dst = *ptr; + *dst++ = c; + *ptr = dst; + return 0 ; +} +/***************************************************************************** +*****************************************************************************/ +int vsprintf(char *buffer, const char *fmt, va_list args) +{ + int ret_val; + + ret_val = do_printf(fmt, args, vsprintf_help, (void *)buffer); + buffer[ret_val] = '\0'; + return ret_val; +} +/***************************************************************************** +*****************************************************************************/ +int sprintf(char *buffer, const char *fmt, ...) +{ + va_list args; + int ret_val; + + va_start(args, fmt); + ret_val = vsprintf(buffer, fmt, args); + va_end(args); + return ret_val; +} +/***************************************************************************** +PRINTF +You must write your own putchar() +*****************************************************************************/ +int vprintf_help(unsigned c, void **ptr) +{ + putchar(c); + return 0 ; +} +/***************************************************************************** +*****************************************************************************/ +int vprintf(const char *fmt, va_list args) +{ + return do_printf(fmt, args, vprintf_help, NULL); +} +/***************************************************************************** +*****************************************************************************/ +int printf(const char *fmt, ...) +{ + va_list args; + int ret_val; + + va_start(args, fmt); + ret_val = vprintf(fmt, args); + va_end(args); + return ret_val; +} +/***************************************************************************** +*****************************************************************************/ +int main(void) +{ + char buf[64]; + + sprintf(buf, "%u score and %i years ago...\n", 4, -7); + puts(buf); + + sprintf(buf, "-1L == 0x%lX == octal %lo\n", -1L, -1L); + puts(buf); + + printf("<%-08s> and <%08s> justified strings\n", "left", "right"); + return 0; +} +#endif diff --git a/Dump/hybos/lib/stdio/printf.c b/Dump/hybos/lib/stdio/printf.c new file mode 100644 index 0000000..9265c3c --- /dev/null +++ b/Dump/hybos/lib/stdio/printf.c @@ -0,0 +1,32 @@ +/** + * printf.c + * + */ + +#include /* va_* */ +#include <_printf.h> /* fnptr_t */ +#include + +int do_printf(const char *fmt, va_list args, fnptr_t fn, void *ptr); +void putch(unsigned c); + +int printf_help(unsigned c, void **ptr) +{ + /** + * Leave this for now + */ + ptr = ptr; + + putch(c); + return 0; +} + +void printf(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + (void)do_printf(fmt, args, printf_help, NULL); + va_end(args); +} + diff --git a/Dump/hybos/lib/stdio/sprintf.c b/Dump/hybos/lib/stdio/sprintf.c new file mode 100644 index 0000000..358cc4d --- /dev/null +++ b/Dump/hybos/lib/stdio/sprintf.c @@ -0,0 +1,19 @@ +/** + * sprintf.c + * + */ + +#include /* va_* */ + +int vsprintf_help(unsigned c, void **ptr); + +int sprintf(char *buffer, const char *fmt, ...) +{ + va_list args; + int ret_val; + + va_start(args, fmt); + ret_val = vsprintf(buffer, fmt, args); + va_end(args); + return ret_val; +} diff --git a/Dump/hybos/lib/string/Makefile b/Dump/hybos/lib/string/Makefile new file mode 100644 index 0000000..4fd1d3c --- /dev/null +++ b/Dump/hybos/lib/string/Makefile @@ -0,0 +1,92 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +STRING =strcat.o \ + strchr.o \ + strcmp.o \ + strcpy.o \ + strcspn.o \ + stricmp.o \ + strlen.o \ + strncmp.o \ + strncpy.o \ + strnicmp.o \ + strnpst.o \ + strnset.o \ + strpbrk.o \ + strpst.o \ + strrchr.o \ + strrev.o \ + strset.o \ + strspn.o \ + strstr.o \ + tolower.o \ + toupper.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(STRING) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\strcat.o + del ..\$(OBJ_DIR)\strchr.o + del ..\$(OBJ_DIR)\strcmp.o + del ..\$(OBJ_DIR)\strcpy.o + del ..\$(OBJ_DIR)\strcspn.o + del ..\$(OBJ_DIR)\stricmp.o + del ..\$(OBJ_DIR)\strlen.o + del ..\$(OBJ_DIR)\strncmp.o + del ..\$(OBJ_DIR)\strncpy.o + del ..\$(OBJ_DIR)\strnicmp.o + del ..\$(OBJ_DIR)\strnpst.o + del ..\$(OBJ_DIR)\strnset.o + del ..\$(OBJ_DIR)\strpbrk.o + del ..\$(OBJ_DIR)\strpst.o + del ..\$(OBJ_DIR)\strrchr.o + del ..\$(OBJ_DIR)\strrev.o + del ..\$(OBJ_DIR)\strset.o + del ..\$(OBJ_DIR)\strspn.o + del ..\$(OBJ_DIR)\strstr.o + del ..\$(OBJ_DIR)\tolower.o + del ..\$(OBJ_DIR)\toupper.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +strcat.o: strcat.c $(MAKEDEP) +strchr.o: strchr.c $(MAKEDEP) +strcmp.o: strcmp.c $(MAKEDEP) +strcpy.o: strcpy.c $(MAKEDEP) +strcspn.o: strcspn.c $(MAKEDEP) +stricmp.o: stricmp.c $(MAKEDEP) +strlen.o: strlen.c $(MAKEDEP) +strcmp.o: strcmp.c $(MAKEDEP) +strncpy.o: strncpy.c $(MAKEDEP) +strnicmp.o: strnicmp.c $(MAKEDEP) +strnpst.o: strnpst.c $(MAKEDEP) +strnset.o: strnset.c $(MAKEDEP) +strpbrk.o: strpbrk.c $(MAKEDEP) +strpst.o: strpst.c $(MAKEDEP) +strrchr.o: strrchr.c $(MAKEDEP) +strrev.o: strrev.c $(MAKEDEP) +strset.o: strset.c $(MAKEDEP) +strspn.o: strspn.c $(MAKEDEP) +strstr.o: strstr.c $(MAKEDEP) +tolower.o: tolower.c $(MAKEDEP) +toupper.o: toupper.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/string/strcat.c b/Dump/hybos/lib/string/strcat.c new file mode 100644 index 0000000..04cc832 --- /dev/null +++ b/Dump/hybos/lib/string/strcat.c @@ -0,0 +1,90 @@ +/*** +*strncat.c - append n chars of string to new string +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines strncat() - appends n characters of string onto +* end of other string +* +*******************************************************************************/ + + +/*** +*char *strncat(front, back, count) - append count chars of back onto front +* +*Purpose: +* Appends at most count characters of the string back onto the +* end of front, and ALWAYS terminates with a null character. +* If count is greater than the length of back, the length of back +* is used instead. (Unlike strncpy, this routine does not pad out +* to count characters). +* +*Entry: +* char *front - string to append onto +* char *back - string to append +* unsigned count - count of max characters to append +* +*Exit: +* returns a pointer to string appended onto (front). +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ +#include <_size_t.h> + +/******************************************************************************/ +/* strcat - Concatenate String */ +/* */ +/* This fuction concatenates two strings (add the source string to the end of */ +/* the destination string. It assumes there is enough space in the */ +/* destination to add the source string to it. */ +/* */ +/* s The destination string. */ +/* t The source string. */ +/* @ The destination string. */ +/******************************************************************************/ +char *strcat(char *s, const char *t) +{ + char *c = s; + + /* Find the end of the destination string. */ + while (*s) s++; + + /* Copy the source sting to the destination string. */ + while ((*s++ = *t++)); + + return (c); +} + +/******************************************************************************/ +/* strncat - Concatenate String up to n Characters */ +/* */ +/* This fuction concatenates two strings (add the source string to the end of */ +/* the destination string. It assumes there is enough space in the */ +/* destination to add the source string to it. The total lenght of the */ +/* concatened string may not be larger than n characters. This includes the */ +/* NULL charecter. */ +/* */ +/* s The destination string. */ +/* t The source string. */ +/* n The maximum lenght of the concatednated string. */ +/* @ The destination string. */ +/******************************************************************************/ + +char *strncat(char *front, const char *back, size_t count) +{ + char *start = front; + + while(*front++); + front--; + + while(count--) + if(!(*front++ = *back++)) + return(start); + + *front = '\0'; + return(start); +} diff --git a/Dump/hybos/lib/string/strcat.c~ b/Dump/hybos/lib/string/strcat.c~ new file mode 100644 index 0000000..a05385e --- /dev/null +++ b/Dump/hybos/lib/string/strcat.c~ @@ -0,0 +1,90 @@ +/*** +*strncat.c - append n chars of string to new string +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines strncat() - appends n characters of string onto +* end of other string +* +*******************************************************************************/ + + +/*** +*char *strncat(front, back, count) - append count chars of back onto front +* +*Purpose: +* Appends at most count characters of the string back onto the +* end of front, and ALWAYS terminates with a null character. +* If count is greater than the length of back, the length of back +* is used instead. (Unlike strncpy, this routine does not pad out +* to count characters). +* +*Entry: +* char *front - string to append onto +* char *back - string to append +* unsigned count - count of max characters to append +* +*Exit: +* returns a pointer to string appended onto (front). +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ +#include <_size_t.h> + +/******************************************************************************/ +/* strcat - Concatenate String */ +/* */ +/* This fuction concatenates two strings (add the source string to the end of */ +/* the destination string. It assumes there is enough space in the */ +/* destination to add the source string to it. */ +/* */ +/* s The destination string. */ +/* t The source string. */ +/* @ The destination string. */ +/******************************************************************************/ +char *strcat(char *s, const char *t) +{ + char *c = s; + + /* Find the end of the destination string. */ + while (*s) s++; + + /* Copy the source sting to the destination string. */ + while (*s++ = *t++); + + return (c); +} + +/******************************************************************************/ +/* strncat - Concatenate String up to n Characters */ +/* */ +/* This fuction concatenates two strings (add the source string to the end of */ +/* the destination string. It assumes there is enough space in the */ +/* destination to add the source string to it. The total lenght of the */ +/* concatened string may not be larger than n characters. This includes the */ +/* NULL charecter. */ +/* */ +/* s The destination string. */ +/* t The source string. */ +/* n The maximum lenght of the concatednated string. */ +/* @ The destination string. */ +/******************************************************************************/ + +char *strncat(char *front, const char *back, size_t count) +{ + char *start = front; + + while(*front++); + front--; + + while(count--) + if(!(*front++ = *back++)) + return(start); + + *front = '\0'; + return(start); +} diff --git a/Dump/hybos/lib/string/strchr.c b/Dump/hybos/lib/string/strchr.c new file mode 100644 index 0000000..881fbff --- /dev/null +++ b/Dump/hybos/lib/string/strchr.c @@ -0,0 +1,39 @@ +/*** +*strchr.c - search a string for a given character +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines strchr() - search a string for a character +* +*******************************************************************************/ + +/*** +*char *strchr(string, c) - search a string for a character +* +*Purpose: +* Searches a string for a given character, which may be the +* null character '\0'. +* +*Entry: +* char *string - string to search in +* char c - character to search for +* +*Exit: +* returns pointer to the first occurence of c in string +* returns NULL if c does not occur in string +* +*Exceptions: +* +*******************************************************************************/ + +char *strchr(const char * string, int ch) +{ + while(*string && *string != (char)ch) + string++; + + if(*string == (char)ch) + return((char *)string); + + return(0); +} diff --git a/Dump/hybos/lib/string/strcmp.c b/Dump/hybos/lib/string/strcmp.c new file mode 100644 index 0000000..39f5432 --- /dev/null +++ b/Dump/hybos/lib/string/strcmp.c @@ -0,0 +1,14 @@ +int strcmp(const char * src, const char * dst) +{ + int ret = 0 ; + + while(!(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) + ++src, ++dst; + + if(ret < 0) + ret = -1 ; + else if(ret > 0) + ret = 1 ; + + return(ret); +} diff --git a/Dump/hybos/lib/string/strcpy.c b/Dump/hybos/lib/string/strcpy.c new file mode 100644 index 0000000..379519a --- /dev/null +++ b/Dump/hybos/lib/string/strcpy.c @@ -0,0 +1,7 @@ + +char *strcpy(char *s, const char *t) +{ + while((*(s++) = *(t++))); + + return s; +} diff --git a/Dump/hybos/lib/string/strcspn.c b/Dump/hybos/lib/string/strcspn.c new file mode 100644 index 0000000..c6ac9d9 --- /dev/null +++ b/Dump/hybos/lib/string/strcspn.c @@ -0,0 +1,69 @@ +/*** +*strspn.c - find length of initial substring of chars from a control string +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines strspn() - finds the length of the initial substring of +* a string consisting entirely of characters from a control string. +* +* defines strcspn()- finds the length of the initial substring of +* a string consisting entirely of characters not in a control string. +* +* defines strpbrk()- finds the index of the first character in a string +* that is not in a control string +* +*******************************************************************************/ +#include +/*** +*int strcspn(string, control) - search for init substring w/o control chars +* +*Purpose: +* returns the index of the first character in string that belongs +* to the set of characters specified by control. This is equivalent +* to the length of the length of the initial substring of string +* composed entirely of characters not in control. Null chars not +* considered. +* +*Entry: +* char *string - string to search +* char *control - set of characters not allowed in init substring +* +*Exit: +* returns the index of the first char in string +* that is in the set of characters specified by control. +* +*Exceptions: +* +*******************************************************************************/ + +size_t strcspn(const char * string, const char * control) +{ + const unsigned char *str = (unsigned char *)string; + const unsigned char *ctrl = (unsigned char *)control; + + unsigned char map[32]; + int count; + + /* Clear out bit map */ + for(count=0; count<32; count++) + map[count] = 0; + + /* Set bits in control map */ + while(*ctrl) + { + map[*ctrl >> 3] |= (1 << (*ctrl & 7)); + ctrl++; + } + + /* 1st char in control map stops search */ + count=0; + map[0] |= 1; /* null chars not considered */ + while(!(map[*str >> 3] & (1 << (*str & 7)))) + { + count++; + str++; + } + + return count; +} diff --git a/Dump/hybos/lib/string/stricmp.c b/Dump/hybos/lib/string/stricmp.c new file mode 100644 index 0000000..5413b7f --- /dev/null +++ b/Dump/hybos/lib/string/stricmp.c @@ -0,0 +1,49 @@ +/*** +*stricmp.c - contains case-insensitive string comp routine _stricmp/_strcmpi +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* contains _stricmp(), also known as _strcmpi() +* +*******************************************************************************/ + + +/*** +*int _stricmp(dst, src), _strcmpi(dst, src) - compare strings, ignore case +* +*Purpose: +* _stricmp/_strcmpi perform a case-insensitive string comparision. +* For differences, upper case letters are mapped to lower case. +* Thus, "abc_" < "ABCD" since "_" < "d". +* +*Entry: +* char *dst, *src - strings to compare +* +*Return: +* <0 if dst < src +* 0 if dst = src +* >0 if dst > src +* +*Exceptions: +* +*******************************************************************************/ + +/* strcmpi */ + +int stricmp(const char *dst, const char *src) +{ + int f,l; + + do + { + if(((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z')) + f -= ('A' - 'a'); + + if(((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z')) + l -= ('A' - 'a'); + } while ( f && (f == l) ); + + + return (f - l); +} diff --git a/Dump/hybos/lib/string/strlen.c b/Dump/hybos/lib/string/strlen.c new file mode 100644 index 0000000..5245a59 --- /dev/null +++ b/Dump/hybos/lib/string/strlen.c @@ -0,0 +1,11 @@ +#include /* size_t */ +/***************************************************************************** +*****************************************************************************/ +size_t strlen(const char *str) +{ + size_t ret_val; + + for(ret_val = 0; *str != '\0'; str++) + ret_val++; + return ret_val; +} diff --git a/Dump/hybos/lib/string/strncmp.c b/Dump/hybos/lib/string/strncmp.c new file mode 100644 index 0000000..50a3ab3 --- /dev/null +++ b/Dump/hybos/lib/string/strncmp.c @@ -0,0 +1,15 @@ +#include + +int strncmp(const char * first, const char * last, size_t count) +{ + if(!count) + return(0); + + while(--count && *first && *first == *last) + { + first++; + last++; + } + + return( *(unsigned char *)first - *(unsigned char *)last ); +} diff --git a/Dump/hybos/lib/string/strncpy.c b/Dump/hybos/lib/string/strncpy.c new file mode 100644 index 0000000..81ef428 --- /dev/null +++ b/Dump/hybos/lib/string/strncpy.c @@ -0,0 +1,15 @@ +#include /* size_t */ + +char *strncpy(char * dest, const char * source, size_t count) +{ + char *start = dest; + + while(count && (*dest++ = *source++)) /* copy string */ + count--; + + if(count) /* pad out with zeroes */ + while(--count) + *dest++ = '\0'; + + return(start); +} diff --git a/Dump/hybos/lib/string/strnicmp.c b/Dump/hybos/lib/string/strnicmp.c new file mode 100644 index 0000000..c2a26f4 --- /dev/null +++ b/Dump/hybos/lib/string/strnicmp.c @@ -0,0 +1,56 @@ +/*** +*strnicmp.c - compare n chars of strings, ignoring case +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _strnicmp() - Compares at most n characters of two strings, +* without regard to case. +* +*******************************************************************************/ + +/*** +*int _strnicmp(first, last, count) - compares count char of strings, ignore case +* +*Purpose: +* Compare the two strings for lexical order. Stops the comparison +* when the following occurs: (1) strings differ, (2) the end of the +* strings is reached, or (3) count characters have been compared. +* For the purposes of the comparison, upper case characters are +* converted to lower case. +* +*Entry: +* char *first, *last - strings to compare +* size_t count - maximum number of characters to compare +* +*Exit: +* returns <0 if first < last +* returns 0 if first == last +* returns >0 if first > last +* +*Exceptions: +* +*******************************************************************************/ + +#include <_size_t.h> /* size_t */ + +int strnicmp(const char *first, const char *last, size_t count) +{ + int f,l; + + if(!count) + return 0; + + do + { + if(((f = (unsigned char)(*(first++))) >= 'A') && (f <= 'Z')) + f -= 'A' - 'a'; + + if(((l = (unsigned char)(*(last++))) >= 'A') && (l <= 'Z')) + l -= 'A' - 'a'; + + } while ( --count && f && (f == l) ); + + + return (f - l); +} diff --git a/Dump/hybos/lib/string/strnpst.c b/Dump/hybos/lib/string/strnpst.c new file mode 100644 index 0000000..c8a971d --- /dev/null +++ b/Dump/hybos/lib/string/strnpst.c @@ -0,0 +1,11 @@ + +char *strnpst(char *s, const char *t, unsigned n) +{ + while(*t && n) + { + *(s++) = *(t++); + n--; + }; + + return s; +} diff --git a/Dump/hybos/lib/string/strnset.c b/Dump/hybos/lib/string/strnset.c new file mode 100644 index 0000000..51ee8b6 --- /dev/null +++ b/Dump/hybos/lib/string/strnset.c @@ -0,0 +1,11 @@ +#include /* size_t */ + +char *_strnset(char * string, int val, size_t count) +{ + char *start = string; + + while(count-- && *string) + *string++ = (char)val; + + return start; +} diff --git a/Dump/hybos/lib/string/strpbrk.c b/Dump/hybos/lib/string/strpbrk.c new file mode 100644 index 0000000..b277061 --- /dev/null +++ b/Dump/hybos/lib/string/strpbrk.c @@ -0,0 +1,70 @@ +/*** +*strspn.c - find length of initial substring of chars from a control string +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines strspn() - finds the length of the initial substring of +* a string consisting entirely of characters from a control string. +* +* defines strcspn()- finds the length of the initial substring of +* a string consisting entirely of characters not in a control string. +* +* defines strpbrk()- finds the index of the first character in a string +* that is not in a control string +* +*******************************************************************************/ + + + +/*** +*char *strpbrk(string, control) - scans string for a character from control +* +*Purpose: +* Finds the first occurence in string of any character from +* the control string. +* +*Entry: +* char *string - string to search in +* char *control - string containing characters to search for +* +*Exit: +* returns a pointer to the first character from control found +* in string. +* returns NULL if string and control have no characters in common. +* +*Exceptions: +* +*******************************************************************************/ + + +char *strpbrk(const char * string, const char * control) +{ + const unsigned char *str = (unsigned char *)string; + const unsigned char *ctrl = (unsigned char *)control; + + unsigned char map[32]; + int count; + + /* Clear out bit map */ + for(count=0; count<32; count++) + map[count] = 0; + + /* Set bits in control map */ + while(*ctrl) + { + map[*ctrl >> 3] |= (1 << (*ctrl & 7)); + ctrl++; + } + + /* 1st char in control map stops search */ + while(*str) + { + if(map[*str >> 3] & (1 << (*str & 7))) + return((char *)str); + + str++; + } + + return 0; +} diff --git a/Dump/hybos/lib/string/strpst.c b/Dump/hybos/lib/string/strpst.c new file mode 100644 index 0000000..051cd3a --- /dev/null +++ b/Dump/hybos/lib/string/strpst.c @@ -0,0 +1,10 @@ + +char *strpst(char *s, const char *t) +{ + while(*t) + { + *(s++) = *(t++); + }; + + return s; +} diff --git a/Dump/hybos/lib/string/strrchr.c b/Dump/hybos/lib/string/strrchr.c new file mode 100644 index 0000000..c1c1b65 --- /dev/null +++ b/Dump/hybos/lib/string/strrchr.c @@ -0,0 +1,46 @@ +/*** +*strrchr.c - find last occurrence of character in string +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines strrchr() - find the last occurrence of a given character +* in a string. +* +*******************************************************************************/ + + +/*** +*char *strrchr(string, ch) - find last occurrence of ch in string +* +*Purpose: +* Finds the last occurrence of ch in string. The terminating +* null character is used as part of the search. +* +*Entry: +* char *string - string to search in +* char ch - character to search for +* +*Exit: +* returns a pointer to the last occurrence of ch in the given +* string +* returns NULL if ch does not occurr in the string +* +*Exceptions: +* +*******************************************************************************/ + +char *strrchr(const char * string, int ch) +{ + char *start = (char *)string; + + while(*string++); /* find end of string */ + + /* search towards front */ + while(--string != start && *string != (char)ch); + + if(*string == (char)ch) /* char found ? */ + return (char *)string; + + return 0; +} diff --git a/Dump/hybos/lib/string/strrev.c b/Dump/hybos/lib/string/strrev.c new file mode 100644 index 0000000..aaa84d1 --- /dev/null +++ b/Dump/hybos/lib/string/strrev.c @@ -0,0 +1,47 @@ +/*** +*strrev.c - reverse a string in place +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines _strrev() - reverse a string in place (not including +* '\0' character) +* +*******************************************************************************/ + +/*** +*char *_strrev(string) - reverse a string in place +* +*Purpose: +* Reverses the order of characters in the string. The terminating +* null character remains in place. +* +*Entry: +* char *string - string to reverse +* +*Exit: +* returns string - now with reversed characters +* +*Exceptions: +* +*******************************************************************************/ + +char *_strrev(char *string) +{ + char *start = string; + char *left = string; + char ch; + + while(*string++); /* find end of string */ + + string -= 2; + + while(left < string) + { + ch = *left; + *left++ = *string; + *string-- = ch; + } + + return start; +} diff --git a/Dump/hybos/lib/string/strset.c b/Dump/hybos/lib/string/strset.c new file mode 100644 index 0000000..6a338c3 --- /dev/null +++ b/Dump/hybos/lib/string/strset.c @@ -0,0 +1,10 @@ + +char *_strset(char *string, int val) +{ + char *start = string; + + while(*string) + *string++ = (char)val; + + return start; +} diff --git a/Dump/hybos/lib/string/strspn.c b/Dump/hybos/lib/string/strspn.c new file mode 100644 index 0000000..86a6889 --- /dev/null +++ b/Dump/hybos/lib/string/strspn.c @@ -0,0 +1,75 @@ +/*** +*strspn.c - find length of initial substring of chars from a control string +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines strspn() - finds the length of the initial substring of +* a string consisting entirely of characters from a control string. +* +* defines strcspn()- finds the length of the initial substring of +* a string consisting entirely of characters not in a control string. +* +* defines strpbrk()- finds the index of the first character in a string +* that is not in a control string +* +*******************************************************************************/ + + +/*** +*int strspn(string, control) - find init substring of control chars +* +*Purpose: +* Finds the index of the first character in string that does belong +* to the set of characters specified by control. This is +* equivalent to the length of the initial substring of string that +* consists entirely of characters from control. The '\0' character +* that terminates control is not considered in the matching process. +* +*Entry: +* char *string - string to search +* char *control - string containing characters not to search for +* +*Exit: +* returns index of first char in string not in control +* +*Exceptions: +* +*******************************************************************************/ + +#include /* size_t */ + +size_t strspn(const char *string, const char *control) +{ + const unsigned char *str = (unsigned char *)string; + const unsigned char *ctrl = (unsigned char *)control; + + unsigned char map[32]; + int count; + + /* Clear out bit map */ + for(count=0; count<32; count++) + map[count] = 0; + + /* Set bits in control map */ + while(*ctrl) + { + map[*ctrl >> 3] |= (1 << (*ctrl & 7)); + ctrl++; + } + + /* 1st char NOT in control map stops search */ + if(*str) + { + count=0; + while(map[*str >> 3] & (1 << (*str & 7))) + { + count++; + str++; + } + + return count; + } + + return 0; +} diff --git a/Dump/hybos/lib/string/strstr.c b/Dump/hybos/lib/string/strstr.c new file mode 100644 index 0000000..3bd097b --- /dev/null +++ b/Dump/hybos/lib/string/strstr.c @@ -0,0 +1,54 @@ +/*** +*strstr.c - search for one string inside another +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines strstr() - search for one string inside another +* +*******************************************************************************/ + +/*** +*char *strstr(string1, string2) - search for string2 in string1 +* +*Purpose: +* finds the first occurrence of string2 in string1 +* +*Entry: +* char *string1 - string to search in +* char *string2 - string to search for +* +*Exit: +* returns a pointer to the first occurrence of string2 in +* string1, or NULL if string2 does not occur in string1 +* +*Uses: +* +*Exceptions: +* +*******************************************************************************/ + +char *strstr(const char * str1, const char * str2) +{ + char *cp = (char *)str1; + char *s1, *s2; + + if(!*str2 ) + return (char *)str1; + + while(*cp) + { + s1 = cp; + s2 = (char *)str2; + + while(*s1 && *s2 && !(*s1-*s2)) + s1++, s2++; + + if(!*s2) + return cp; + + cp++; + } + + return 0; +} diff --git a/Dump/hybos/lib/string/tolower.c b/Dump/hybos/lib/string/tolower.c new file mode 100644 index 0000000..3cdd733 --- /dev/null +++ b/Dump/hybos/lib/string/tolower.c @@ -0,0 +1,9 @@ + +char *tolower(char* s) +{ + while(*s++) + if(*s >= 'A' && *s <= 'Z') + *s += 'a' - 'A'; + + return s; +} diff --git a/Dump/hybos/lib/string/toupper.c b/Dump/hybos/lib/string/toupper.c new file mode 100644 index 0000000..b5e3395 --- /dev/null +++ b/Dump/hybos/lib/string/toupper.c @@ -0,0 +1,10 @@ + +char *toupper(char *s) +{ + char *c = '\0'; + while(*s++) + if(*s >= 'a' && *s <= 'z') + *s += 'A' - 'a'; + + return c; +} diff --git a/Dump/hybos/lib/util/Makefile b/Dump/hybos/lib/util/Makefile new file mode 100644 index 0000000..483190c --- /dev/null +++ b/Dump/hybos/lib/util/Makefile @@ -0,0 +1,32 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +UTIL =rand.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(UTIL) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\rand.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +rand.o: rand.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/util/rand.c b/Dump/hybos/lib/util/rand.c new file mode 100644 index 0000000..b81e73f --- /dev/null +++ b/Dump/hybos/lib/util/rand.c @@ -0,0 +1,56 @@ +/*** +*rand.c - random number generator +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +*Purpose: +* defines rand(), srand() - random number generator +* +*******************************************************************************/ + +static long holdrand = 1L; + + +/*** +*void srand(seed) - seed the random number generator +* +*Purpose: +* Seeds the random number generator with the int given. Adapted from the +* BASIC random number generator. +* +*Entry: +* unsigned seed - seed to seed rand # generator with +* +*Exit: +* None. +* +*Exceptions: +* +*******************************************************************************/ + +void srand(unsigned int seed) +{ + holdrand = (long)seed; +} + + +/*** +*int rand() - returns a random number +* +*Purpose: +* returns a pseudo-random number 0 through 32767. +* +*Entry: +* None. +* +*Exit: +* Returns a pseudo-random number 0 through 32767. +* +*Exceptions: +* +*******************************************************************************/ + +int rand(void) +{ + return (((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff); +} diff --git a/Dump/hybos/lib/x86/.inportb.c.swp b/Dump/hybos/lib/x86/.inportb.c.swp new file mode 100644 index 0000000..6532e11 --- /dev/null +++ b/Dump/hybos/lib/x86/.inportb.c.swp Binary files differ diff --git a/Dump/hybos/lib/x86/Makefile b/Dump/hybos/lib/x86/Makefile new file mode 100644 index 0000000..9039ed2 --- /dev/null +++ b/Dump/hybos/lib/x86/Makefile @@ -0,0 +1,47 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) + +X86 =disable.o \ + enable.o \ + inportb.o \ + outportb.o \ + inportw.o \ + outportw.o + +# This will be one level above where we are now +OBJ_DIR =objects + +OBJS =$(X86) + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\disable.o + del ..\$(OBJ_DIR)\enable.o + del ..\$(OBJ_DIR)\inportb.o + del ..\$(OBJ_DIR)\outportb.o + del ..\$(OBJ_DIR)\inportw.o + del ..\$(OBJ_DIR)\outportw.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +disable.o: disable.c $(MAKEDEP) +enable.o: enable.c $(MAKEDEP) +inportb.o: inportb.c $(MAKEDEP) +outportb.o: outportb.c $(MAKEDEP) +inportw.o: inportw.c $(MAKEDEP) +outportw.o: outportw.c $(MAKEDEP) + diff --git a/Dump/hybos/lib/x86/disable.c b/Dump/hybos/lib/x86/disable.c new file mode 100644 index 0000000..bd6cd30 --- /dev/null +++ b/Dump/hybos/lib/x86/disable.c @@ -0,0 +1,13 @@ +/***************************************************************************** +*****************************************************************************/ +unsigned disable(void) +{ + unsigned ret_val; + + __asm__ __volatile__("pushfl\n" + "popl %0\n" + "cli" + : "=a"(ret_val) + :); + return ret_val; +} diff --git a/Dump/hybos/lib/x86/enable.c b/Dump/hybos/lib/x86/enable.c new file mode 100644 index 0000000..54f88f3 --- /dev/null +++ b/Dump/hybos/lib/x86/enable.c @@ -0,0 +1,9 @@ +/***************************************************************************** +*****************************************************************************/ +void enable(void) +{ + __asm__ __volatile__("sti" + : + : + ); +} diff --git a/Dump/hybos/lib/x86/inportb.c b/Dump/hybos/lib/x86/inportb.c new file mode 100644 index 0000000..6ba4ea9 --- /dev/null +++ b/Dump/hybos/lib/x86/inportb.c @@ -0,0 +1,11 @@ +/***************************************************************************** +*****************************************************************************/ +unsigned inportb(unsigned short port) +{ + unsigned char ret_val; + + __asm__ __volatile__("inb %1,%0" + : "=a"(ret_val) + : "d"(port)); + return ret_val; +} diff --git a/Dump/hybos/lib/x86/inportw.c b/Dump/hybos/lib/x86/inportw.c new file mode 100644 index 0000000..796e319 --- /dev/null +++ b/Dump/hybos/lib/x86/inportw.c @@ -0,0 +1,13 @@ +unsigned short inportw(int port) +{ + register unsigned short r; + + __asm__ __volatile__ + ( + "inw %%dx, %%ax\n" + : "=a" (r) + : "d" (port) + ); + + return r; +} diff --git a/Dump/hybos/lib/x86/outportb.c b/Dump/hybos/lib/x86/outportb.c new file mode 100644 index 0000000..a429606 --- /dev/null +++ b/Dump/hybos/lib/x86/outportb.c @@ -0,0 +1,8 @@ +/***************************************************************************** +*****************************************************************************/ +void outportb(unsigned port, unsigned val) +{ + __asm__ __volatile__("outb %b0,%w1" + : + : "a"(val), "d"(port)); +} diff --git a/Dump/hybos/lib/x86/outportw.c b/Dump/hybos/lib/x86/outportw.c new file mode 100644 index 0000000..b55a822 --- /dev/null +++ b/Dump/hybos/lib/x86/outportw.c @@ -0,0 +1,9 @@ +void outportw(int port, unsigned short data) +{ + __asm__ __volatile__ + ( + "outw %%ax, %%dx\n\t" + : + : "a" (data), "d" (port) + ); +} diff --git a/Dump/hybos/src/._krnl.h.swp b/Dump/hybos/src/._krnl.h.swp new file mode 100644 index 0000000..b54106a --- /dev/null +++ b/Dump/hybos/src/._krnl.h.swp Binary files differ diff --git a/Dump/hybos/src/.debug.c.swp b/Dump/hybos/src/.debug.c.swp new file mode 100644 index 0000000..d6738a0 --- /dev/null +++ b/Dump/hybos/src/.debug.c.swp Binary files differ diff --git a/Dump/hybos/src/.kbd.c.swp b/Dump/hybos/src/.kbd.c.swp new file mode 100644 index 0000000..977b87d --- /dev/null +++ b/Dump/hybos/src/.kbd.c.swp Binary files differ diff --git a/Dump/hybos/src/.krnl1m.ld.swp b/Dump/hybos/src/.krnl1m.ld.swp new file mode 100644 index 0000000..f95cad1 --- /dev/null +++ b/Dump/hybos/src/.krnl1m.ld.swp Binary files differ diff --git a/Dump/hybos/src/.main.c.swp b/Dump/hybos/src/.main.c.swp new file mode 100644 index 0000000..1dd3750 --- /dev/null +++ b/Dump/hybos/src/.main.c.swp Binary files differ diff --git a/Dump/hybos/src/.ming.mak.swp b/Dump/hybos/src/.ming.mak.swp new file mode 100644 index 0000000..feda0c7 --- /dev/null +++ b/Dump/hybos/src/.ming.mak.swp Binary files differ diff --git a/Dump/hybos/src/.sched.c.swp b/Dump/hybos/src/.sched.c.swp new file mode 100644 index 0000000..c75ddf3 --- /dev/null +++ b/Dump/hybos/src/.sched.c.swp Binary files differ diff --git a/Dump/hybos/src/.tasks.c.swp b/Dump/hybos/src/.tasks.c.swp new file mode 100644 index 0000000..abe0e47 --- /dev/null +++ b/Dump/hybos/src/.tasks.c.swp Binary files differ diff --git a/Dump/hybos/src/.video.c.swp b/Dump/hybos/src/.video.c.swp new file mode 100644 index 0000000..50cb716 --- /dev/null +++ b/Dump/hybos/src/.video.c.swp Binary files differ diff --git a/Dump/hybos/src/Makefile b/Dump/hybos/src/Makefile new file mode 100644 index 0000000..ab24d4d --- /dev/null +++ b/Dump/hybos/src/Makefile @@ -0,0 +1,18 @@ +#MAKEFILE=ming.mak +MAKEFILE=Makefile + +all: + make -f $(MAKEFILE) -C kernel + make -f $(MAKEFILE) -C mm + make -f $(MAKEFILE) -C esh + +install: + make -f $(MAKEFILE) -C mm + make -f $(MAKEFILE) -C esh + make -f $(MAKEFILE) -C kernel install + +clean: + make -f $(MAKEFILE) -C kernel clean + make -f $(MAKEFILE) -C mm clean + make -f $(MAKEFILE) -C esh clean + diff --git a/Dump/hybos/src/README b/Dump/hybos/src/README new file mode 100644 index 0000000..ed86715 --- /dev/null +++ b/Dump/hybos/src/README @@ -0,0 +1,20 @@ +Directory structure layout for HybOS + +kernel + HybOS kernel source +keymaps + Keyboard keymaps +objects + .o files +fs + Filesystem source +etc + /etc entries for installed system +test + Various system tests +mm + Memory management source +osh + OpenSHell source +esh + ESHell (HybOS Emergency Shell) source diff --git a/Dump/hybos/src/esh/Makefile b/Dump/hybos/src/esh/Makefile new file mode 100644 index 0000000..48f19d4 --- /dev/null +++ b/Dump/hybos/src/esh/Makefile @@ -0,0 +1,34 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +LDSCRIPT =../../krnl1m.ld +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) +LD =ld -g -T $(LDSCRIPT) -nostdlib +LIBC =../../lib/libc.a + +OBJS =esh.o + +OBJS_DEP =*.o + +OBJ_DIR =objects + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\esh.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +esh.o: esh.c $(MAKEDEP) + diff --git a/Dump/hybos/src/esh/esh.c b/Dump/hybos/src/esh/esh.c new file mode 100644 index 0000000..bebce77 --- /dev/null +++ b/Dump/hybos/src/esh/esh.c @@ -0,0 +1,372 @@ +/** + * esh.c + * + * Error SHell for HybOS + * + * Exports: + * None. + * + * Imports: + * None. + * + * Description: + * Since esh is called on a new thread in user-space and not in + * kernel-space, imports and exports are not necessary. All the + * kernel needs to know is what functions to call when the + * keyboard buffer has been filled (this even happens when the + * user presses the EOL key, which is the ENTER key on either + * the keypad or the "normal" keyboard). + */ + +#include +#include +#include +#include +#include + +void dumpheapk(void); + +ESHCOMMANDS eshCommands[COMMAND_COUNT]; + + +/** + * keyDown() + * + * This function is called when a key is pressed and is called + * on a new thread which resides in user-space so that esh + * cannot lock up the kernel. + * + * @param unsigned Which key was pressed. See keyboard.h + * + * @return void + */ +void keyDown(unsigned key) +{ + key = key; /* to shut gcc up */ +} + +/** + * keyUp() + * + * This function is called when a key is released. + * + * @param unsigned Which key was released. See keyboard.h + * + * @return void + */ +void keyUp(unsigned key) +{ + key = key; /* to shut gcc up */ +} + +void initCommands(void) +{ + eshCommands[0].minparams = 0; + eshCommands[0].maxparams = 0; + strcpy(eshCommands[0].command, "dumpheap\0"); + strcpy(eshCommands[0].params[0], "-h\0"); + strcpy(eshCommands[0].description, "Print listing of heap usage and status.\0"); + + eshCommands[1].minparams = 1; + eshCommands[1].maxparams = MAX_PARAMS; + strcpy(eshCommands[1].params[0], "-h\0"); + strcpy(eshCommands[1].command, "echo\0"); + strcpy(eshCommands[1].description, "Echo a line of text to the terminal.\0"); + + /*this will be called with either "help" or "help command" */ + eshCommands[2].minparams = 0; + eshCommands[2].maxparams = 1; + strcpy(eshCommands[2].params[0], "-h\0"); + strcpy(eshCommands[2].command, "help\0"); + strcpy(eshCommands[2].description, "Displays general help menu or help on specific command.\0"); + + /* -r|-h [time] */ + eshCommands[3].minparams = 1; + eshCommands[3].maxparams = 2; + strcpy(eshCommands[3].command, "shutdown\0"); + strcpy(eshCommands[3].params[0], "-r\0"); + strcpy(eshCommands[3].params[1], "-h\0"); + strcpy(eshCommands[3].params[2], "NOW\0"); + strcpy(eshCommands[3].description, "Halt or restart the system.\0"); + + /* clear screen */ + eshCommands[4].minparams = 0; + eshCommands[4].maxparams = 0; + strcpy(eshCommands[4].params[0], "-h\0"); + strcpy(eshCommands[4].command, "cls\0"); + strcpy(eshCommands[4].description, "Clears the terminal of all output.\0"); + + /* print working directory */ + eshCommands[5].minparams = 0; + eshCommands[5].maxparams = 0; + strcpy(eshCommands[5].params[0], "-h\0"); + strcpy(eshCommands[5].command, "pwd\0"); + strcpy(eshCommands[5].description, "Prints the current working directory.\0"); +} + +/** + * mapCommand() + * + * Used internally by esh to map a command to it's zero-based + * index of commands. + * + * @param char * the entire line of the command + * + * @return int index of command entry if found, otherwise -1 + */ +int mapCommand(char *cmd) +{ + int i; /* for our loops */ + int params; /* number of parameters found for the command */ + int previdx; /* previous index */ + char cmdName[MAX_LEN]; /* name of the command */ + + i = 0; + previdx = 0; + params = 0; + + /** + * Loop while cmd[i] is not a space + */ + i = 0; + for(i = 0; i < (int)strlen(cmd); i++) + { + if(cmd[i] == ' ') + break; + } + + strncpy(cmdName, cmd, i); + cmdName[i] = '\0'; + + for(i = 0; i < COMMAND_COUNT; i++) + { + if(!strcmp(eshCommands[i].command, cmdName)) + return i; + } + + return -1; +} + +/** + * isParam() + * + * Determines if the supplied parameter is valid for the + * given command. + * + * @param int index of command + * @param char * command string + * + * @return bool true if parameter is valid, false otherwise + */ +bool isParam(int argc, char *argv) +{ + int i; + + for(i = 0; i < MAX_PARAMS; i++) + { + if(!strcmp(eshCommands[argc].params[i], argv)) + return true; + } + + return false; +} + +/** + * mapParams() + * + * Maps each parameter to the pars struct + * + * @param char * Buffer from the command line + * @param struct Parameter structure + * + * @return int Number of command line parameters (arguments) parsed + */ +int mapParams(char *buf, ESHCURRCOMMAND *pars) +{ + int i; /* for our loops */ + int previdx; /* previous index */ + int idx; /* current index */ + int j; /* loops */ + + i = 0; + j = 0; + previdx = 0; + pars->count = 0; + + previdx = mapCommand(buf); + + if(previdx == -1) + return 0; + + strcpy(pars->param[0], eshCommands[previdx].command); + j++; + pars->count++; + + i = 0; + idx = 0; + + for(i = 0; i < (int)strlen(buf); i++) + { + /* we have encountered a seperator */ + if(buf[i] == ' ') + { + if(j > MAX_PARAMS) + break; + + i++; /* skip one space */ + + idx = i; + + if(buf[i] == '"') + { + i++; + idx++; + + while(buf[i] != '"' && i != (int)strlen(buf)) + i++; + + strncpy(pars->param[j], &buf[idx], (i - idx)); + pars->param[j][i - idx] = '\0'; + + idx = i; + j++; + pars->count++; + } + else + { + while(buf[i] != ' ' && i != (int)strlen(buf)) + i++; + + strncpy(pars->param[j], &buf[idx], i - idx); + pars->param[j][i - idx] = '\0'; + i = idx; + j++; + pars->count++; + } + } + } + + return pars->count; +} + +/** + * processCommand() + * + * This function is called when the user has pressed + * the ENTER key. + * + * @param char * The contents of the current buffer or NULL if empty + * @param int Size of the buffer (number of characters) + * + * @return void + */ +void processCommand(char *line, int count) +{ + int i; + int cmd; /* stores the numeric index of the command */ + ESHCURRCOMMAND params; + + count = count; /* to shut gcc up */ + + /*for(i = 0; i < MAX_PARAMS; i++) + params.param[i][0] = '\0';*/ + params.param[0][0] = '\0'; + + initCommands(); + + cmd = mapCommand(line); + mapParams(line, ¶ms); + + switch(cmd) + { + case 0: /* dumpheap */ + dumpheapk(); + //testheap(); + break; + case 1: /* echo */ + for(i = 1; i < params.count; i++) + printf("%s", params.param[i]); + + printf("\n"); + break; + case 2: /* help */ + if(params.count == 1) + { + printf("HybOS EShell Commands:\n"); + for(i = 0; i < COMMAND_COUNT; i++) + if(strlen(eshCommands[i].command) > 0) + printf("%10s %-s\n", eshCommands[i].command, eshCommands[i].description); + } + else + { + cmd = mapCommand(params.param[0]); + mapParams(params.param[1], ¶ms); + + //if(isParam(cmd, params.param[1])) + if(cmd != -1) + { + printf("Usage: %s %s\n", params.param[0], eshCommands[cmd].params[1]); + } + else + printf("esh: '%s' not found.\n", params.param[1]); + } + break; + default: + if(strlen(params.param[0]) > 0 && strcmp(params.param[0], "help")) + printf("esh: '%s' not found.\n", params.param[0]); + else + printf("esh: '%s' not found.\n", &line[0]); + break; + } + + /*for(i = 0; i < params.count; i++) + printf("param[%i]: %s\n", i, params.param[i]);*/ + + //if(isParam(3, ¶ms.param[1])) + // printf("valid parameter\n"); + //else + // printf("invalid parameter\n"); + + return; + + if(!strcmp(line, "dumpheap")) + dumpheapk(); + else if(!strncmp(line, "echo", 4)) + printf("%s\n", line[4] == ' ' ? &line[5] : &line[4]); + else if(!strcmp(line, "help")) + { + printf("HybOS EShell Commands:\n"); + printf("dumpheap\tPrint listing of heap usage and status\n"); + printf("testheap\tTest the heap and print out results\n"); + printf("shutdown -r\tRestart the system.\n"); + printf("pwd\t\tPrint the current working directory.\n"); + } + else if(!strncmp(line, "shutdown", 8)) + { + if(strlen(line) > 9 && !strncmp(&line[9], "-r", 2)) + { + printf("\nSystem shutdown from vtty%u\n", get_current_vc()); + printf("Restarting..."); + //reboot(); + } + else + { + if((strlen(line) > 9) && (strlen(&line[9]) > 0)) + printf("shutdown: Invalid argument \"%s\".\n", &line[9]); + else + printf("Usage: shutdown -r\n"); + } + } + else if((strlen(line) > 0) && (!strcmp(line, "cls"))) + { + printf("\x1B[2J"); + } + else if((strlen(line) >= 8) && (!strcmp(line, "testheap"))) + { + //testheap(); + } + else if((strlen(line) > 0) && (!strcmp(line, "pwd"))) + printf("/\n"); + else if(strlen(line) > 0) + printf("eshell: \"%s\" not found.\n", line); +} diff --git a/Dump/hybos/src/etc/fstab b/Dump/hybos/src/etc/fstab new file mode 100644 index 0000000..8df5be8 --- /dev/null +++ b/Dump/hybos/src/etc/fstab @@ -0,0 +1,4 @@ +# Poor man's File System Table. + +root=/dev/ROOT +usr=/dev/USR diff --git a/Dump/hybos/src/etc/group b/Dump/hybos/src/etc/group new file mode 100644 index 0000000..fed5047 --- /dev/null +++ b/Dump/hybos/src/etc/group @@ -0,0 +1,10 @@ +operator:*:0: +daemon:*:1: +bin:*:2: +other:*:3: +tty:*:4: +uucp:*:5: +news:*:6: +ftp:*:7: +kmem:*:8: +nogroup:*:99: diff --git a/Dump/hybos/src/etc/passwd b/Dump/hybos/src/etc/passwd new file mode 100644 index 0000000..1855a55 --- /dev/null +++ b/Dump/hybos/src/etc/passwd @@ -0,0 +1,8 @@ +root:##root:0:0::/: +daemon:*:1:1::/etc: +bin:##root:2:0:Binaries:/usr/src:/usr/bin/ash +uucp:*:5:5:UNIX to UNIX copy:/usr/spool/uucp:/usr/bin/uucico +news:*:6:6:Usenet news:/usr/spool/news: +ftp:*:7:7:Anonymous FTP:/usr/ftp: +nobody:*:9999:99::/tmp: +ast:*:8:3:Andrew S. Tanenbaum:/usr/ast: diff --git a/Dump/hybos/src/etc/profile b/Dump/hybos/src/etc/profile new file mode 100644 index 0000000..dd8f13d --- /dev/null +++ b/Dump/hybos/src/etc/profile @@ -0,0 +1,3 @@ +# Set timezone for Middle European Time. + +TZ='MET-1MET DST,M3.5.0/2,M9.5.0/3' export TZ diff --git a/Dump/hybos/src/etc/protocols b/Dump/hybos/src/etc/protocols new file mode 100644 index 0000000..1726ef5 --- /dev/null +++ b/Dump/hybos/src/etc/protocols @@ -0,0 +1,19 @@ +# +# Internet (IP) protocols +# +# @(#)protocols 8.1 (Berkeley) 6/9/93 +# +ip 0 IP # internet protocol, pseudo protocol number +icmp 1 ICMP # internet control message protocol +igmp 2 IGMP # internet group management protocol +ggp 3 GGP # gateway-gateway protocol +tcp 6 TCP # transmission control protocol +egp 8 EGP # exterior gateway protocol +pup 12 PUP # PARC universal packet protocol +udp 17 UDP # user datagram protocol +hmp 20 HMP # host monitoring protocol +xns-idp 22 XNS-IDP # Xerox NS IDP +rdp 27 RDP # reliable data protocol +iso-tp4 29 ISO-TP4 # ISO Transport Protocol Class 4 +iso-ip 80 ISO-IP # ISO Internet Protocol +encap 98 ENCAP # RFC1241 encapsulation diff --git a/Dump/hybos/src/etc/rc b/Dump/hybos/src/etc/rc new file mode 100644 index 0000000..ee3adc5 --- /dev/null +++ b/Dump/hybos/src/etc/rc @@ -0,0 +1,24 @@ +# This file performs various system initializations. + +umask 022 +PATH=/usr/local/bin:/bin:/usr/bin +export PATH + +# National keyboard? +test -f /etc/keymap && loadkeys /etc/keymap + +# Set timezone. (If the clock tells GMT then put this after 'date'.) +. /etc/profile + +# Try to read the hardware real-time clock, if there is one, to set the date +date `readclock` + +# Initialize files. +printroot >/etc/mtab # /etc/mtab keeps track of mounts +>/etc/utmp # /etc/utmp keeps track of logins + +# /etc/fstab lists the root, tmp and usr devices. +. /etc/fstab + +# Any messages? +test -f /etc/issue && cat /etc/issue diff --git a/Dump/hybos/src/etc/services b/Dump/hybos/src/etc/services new file mode 100644 index 0000000..0407095 --- /dev/null +++ b/Dump/hybos/src/etc/services @@ -0,0 +1,85 @@ +# +# Network services, Internet style +# +# @(#)services 8.1 (Berkeley) 6/9/93 +# +tcpmux 1/tcp # TCP port multiplexer (RFC1078) +echo 7/tcp +echo 7/udp +discard 9/tcp sink null +discard 9/udp sink null +systat 11/tcp users +daytime 13/tcp +daytime 13/udp +netstat 15/tcp +qotd 17/tcp quote +chargen 19/tcp ttytst source +chargen 19/udp ttytst source +ftp 21/tcp +telnet 23/tcp +smtp 25/tcp mail +time 37/tcp timserver +time 37/udp timserver +rlp 39/udp resource # resource location +nameserver 42/tcp name # IEN 116 +whois 43/tcp nicname +domain 53/tcp nameserver # name-domain server +domain 53/udp nameserver +mtp 57/tcp # deprecated +# Bootp experimental (sellgren@vangogh) +bootp 67/udp # bootp server +#bootpc 68/udp # bootp client +# +tftp 69/udp +rje 77/tcp netrjs +finger 79/tcp +http 80/tcp # World Wide Web +link 87/tcp ttylink +supdup 95/tcp +hostnames 101/tcp hostname # usually from sri-nic +tsap 102/tcp # part of ISODE. +#csnet-cs 105/? +pop 110/tcp postoffice +sunrpc 111/tcp +sunrpc 111/udp +auth 113/tcp authentication +sftp 115/tcp +uucp-path 117/tcp +nntp 119/tcp readnews untp # USENET News Transfer Protocol +ntp 123/udp +snmp 161/udp +snmp-trap 162/udp +# +# UNIX specific services +# +exec 512/tcp +biff 512/udp comsat +login 513/tcp +who 513/udp whod +shell 514/tcp cmd # no passwords used +syslog 514/udp +printer 515/tcp spooler # line printer spooler +talk 517/udp +ntalk 518/udp +route 520/udp router routed +timed 525/udp timeserver +tempo 526/tcp newdate +courier 530/tcp rpc +conference 531/tcp chat +netnews 532/tcp readnews +netwall 533/udp # -for emergency broadcasts +uucp 540/tcp uucpd # uucp daemon +rdist 541/tcp rdistd # rdist daemon +remotefs 556/tcp rfs_server rfs # Brunhoff remote filesystem + +ingreslock 1524/tcp +# +# Kerberos (Project Athena/MIT) services +# +kerberos 750/udp kdc # Kerberos (server) udp +kerberos 750/tcp kdc # Kerberos (server) tcp +krbupdate 760/tcp kreg # Kerberos registration +kpasswd 761/tcp kpwd # Kerberos "passwd" +klogin 543/tcp # Kerberos rlogin +eklogin 2105/tcp # Kerberos encrypted rlogin +kshell 544/tcp krcmd # Kerberos remote shell diff --git a/Dump/hybos/src/etc/shadow b/Dump/hybos/src/etc/shadow new file mode 100644 index 0000000..3895e9e --- /dev/null +++ b/Dump/hybos/src/etc/shadow @@ -0,0 +1 @@ +root::0:0::: diff --git a/Dump/hybos/src/etc/termcap b/Dump/hybos/src/etc/termcap new file mode 100644 index 0000000..b9bde3b --- /dev/null +++ b/Dump/hybos/src/etc/termcap @@ -0,0 +1,64 @@ +mx|minix|minix console:\ + :am:xn:bs:\ + :co#80:li#25:\ + :is=\E[0m:\ + :cd=\E[0J:cl=\E[H\E[0J:\ + :so=\E[7m:se=\E[0m:\ + :us=\E[4m:ue=\E[0m:\ + :mb=\E[5m:md=\E[1m:\ + :mr=\E[7m:me=\E[0m:\ + :sr=\EM:\ + :cm=\E[%i%d;%dH:\ + :ho=\E[H:\ + :al=\E[L:AL=\E[%dL:\ + :ce=\E[K:\ + :DC=\E[%dP:dc=\E[P:\ + :DL=\E[%dM:dl=\E[M:\ + :DO=\E[%dB:do=\E[B:\ + :IC=\E[%d@:ic=\E[@:\ + :it#8:\ + :le=^H:LE=\E[%dD:nd=\E[C:\ + :ri=\E[C:RI=\E[%dC:\ + :up=\E[A:UP=\E[%dA:\ + :ku=\E[A:kd=\E[B:\ + :kl=\E[D:kr=\E[C:\ + :kh=\E[H:\ + :k0=\E[Y:l0=End:\ + :k1=\E[V:l1=PgUp:\ + :k2=\E[U:l2=PgDn:\ + :k3=\E[T:l3=Num +:\ + :k4=\E[S:l4=Num -:\ + :k5=\E[G:l5=Num 5: +du|dialup|Dialup line:\ + :bs:co#80:li#24: +db|dumb|Really dumb terminal:\ + :bs:co#80:li#24: +lp|lp|Line Printer:\ + :co#80:li#66: +li|ansi|Ansi standard crt:\ + :am:bs:cd=\E[J:ce=\E[K:cl=\E[2J\E[H:cm=\E[%i%d;%dH:co#80:\ + :dn=\E[B:me=\E[0m:mb=\E[5m:mr=\E[7m:md=\E[1m:ho=\E[H:li#24:\ + :nd=\E[C:ms:pt:so=\E[7m:se=\E[0m:us=\E[4m:ue=\E[0m:up=\E[A:\ + :kb=^h:ku=\E[A:kd=\E[B:kl=\E[D:kr=\E[C: +vs|xterm|xterms|vs100|xterm terminal emulator (X window system):\ + :am:cr=^M:do=^J:nl=^J:bl=^G:le=^H:ho=\E[H:\ + :co#80:li#24:cl=\E[H\E[2J:bs:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :md=\E[1m:mr=\E[7m:me=\E[m:\ + :ku=\E[A:kd=\E[B:kr=\E[C:kl=\E[D:kb=^H:\ + :k1=\E[P:k2=\E[Q:k3=\E[R:k4=\E[S:ta=^I:pt:sf=\n:sr=\EM:\ + :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P:\ + :MT:ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :is=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l:\ + :rs=\E[r\E<\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l:xn:\ + :AL=\E[%dL:DL=\E[%dM:IC=\E[%d@:DC=\E[%dP:\ + :hs:ts=\E]2;:fs=^G:ds=\E]2;^G: +d0|vt100|vt100-am|vt100am|dec-vt100|dec vt100:\ + :do=^J:co#80:li#24:cl=\E[;H\E[2J:sf=\ED:\ + :le=^H:bs:am:cm=\E[%i%d;%dH:nd=\E[C:up=\E[A:\ + :ce=\E[K:cd=\E[J:so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ + :md=\E[1m:mr=\E[7m:mb=\E[5m:me=\E[m:is=\E[1;24r\E[24;1H:\ + :rs=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h:ks=\E[?1h\E=:ke=\E[?1l\E>:\ + :ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=^H:\ + :ho=\E[H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:pt:sr=\EM:vt#3:xn:\ + :sc=\E7:rc=\E8:cs=\E[%i%d;%dr: diff --git a/Dump/hybos/src/etc/ttytab b/Dump/hybos/src/etc/ttytab new file mode 100644 index 0000000..791c116 --- /dev/null +++ b/Dump/hybos/src/etc/ttytab @@ -0,0 +1,13 @@ +# ttytab - terminals +# +# Device Type Program Init +console hybos getty +ttyc1 hybos getty +ttyc2 hybos getty +ttyc3 hybos getty +tty00 unknown +tty01 unknown +ttyp0 network +ttyp1 network +ttyp2 network +ttyp3 network diff --git a/Dump/hybos/src/fs/buf.h b/Dump/hybos/src/fs/buf.h new file mode 100644 index 0000000..5e66342 --- /dev/null +++ b/Dump/hybos/src/fs/buf.h @@ -0,0 +1,31 @@ +#ifndef _BUF_H +#define _BUF_H + +#include + +typedef struct buf +{ + union + { + char b__data[BLOCK_SIZE]; /* ordinary user data */ + direct b__dir[NR_DIR_ENTRIES]; /* directory block */ + zone1_t b__v1_ind[V1_INDIRECTS]; /* V1 indirect block */ + zone_t b__v2_ind[V2_INDIRECTS]; /* V2 indirect block */ + d1_inode b__v1_ino[V1_INODES_PER_BLOCK]; /* V1 inode block */ + d2_inode b__v2_ino[V2_INODES_PER_BLOCK]; /* V2 inode block */ + bitchunk_t b__bitmap[BITMAP_CHUNKS]; /* bit map block */ + } b; + + /** + * Header portion of the buffer + */ + struct buf *b_next; /* used to link all free bufs in a chain */ + struct buf *b_prev; /* used to link all free bufs the other way */ + struct buf *b_hash; /* used to link all bufs on hash chains */ + block_t b_blocknr; /* block number of its (minor) device */ + dev_t b_dev; /* major | minor device where block resides */ + char b_dirt; /* CLEAN or DIRTY */ + char b_count; /* number of users of this buffer */ +} buf[NR_BUFFS]; + +#endif /* _BUF_H */ diff --git a/Dump/hybos/src/kernel/Makefile b/Dump/hybos/src/kernel/Makefile new file mode 100644 index 0000000..5e7a2d1 --- /dev/null +++ b/Dump/hybos/src/kernel/Makefile @@ -0,0 +1,73 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +LDSCRIPT =../krnl1m.ld +NASM =nasm -f elf -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) +LD =ld -g -T $(LDSCRIPT) -nostdlib +#LD =D:/cygwin/usr/cross/bin/i586-elf-ld.exe -g -T $(LDSCRIPT) -nostdlib +LIBC =../../lib/libc.a + +OBJS =debug.o \ + main.o \ + kstart.o \ + keyboard.o \ + sched.o \ + tasks.o \ + video.o \ + bootlog.o +# cpu.o +OBJS_DEP =*.o + +OBJ_DIR =objects + +# targets +all: kernel.bin + +install: kernel.bin + copy ..\..\boot\kernel.bin a:\kernel.bin + +clean: + del ..\$(OBJ_DIR)\debug.o + del ..\$(OBJ_DIR)\keyboard.o + del ..\$(OBJ_DIR)\kstart.o + del ..\$(OBJ_DIR)\main.o + del ..\$(OBJ_DIR)\sched.o + del ..\$(OBJ_DIR)\tasks.o + del ..\$(OBJ_DIR)\video.o + del ..\..\boot\kernel.bin + del ..\$(OBJ_DIR)\kernel.dis + del ..\$(OBJ_DIR)\kernel.sym + del ..\$(OBJ_DIR)\bootlog.o +# del ..\$(OBJ_DIR)\cpu.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +kstart.o: kstart.asm $(MAKEDEP) +main.o: main.c $(MAKEDEP) +video.o: video.c $(MAKEDEP) +debug.o: debug.c $(MAKEDEP) +kbd.o: kbd.c $(MAKEDEP) +sched.o: sched.c $(MAKEDEP) +tasks.o: tasks.c $(MAKEDEP) +bootlog.o: bootlog.c $(MAKEDEP) +#cpu.o: cpu.c $(MAKEDEP) + +# explicit rules +$(LIBC): ../../lib/$(MAKEFILE) + make -C ../../lib -f $(MAKEFILE) + +kernel.bin: $(OBJS) $(LDSCRIPT) $(LIBC) $(MAKEDEP) + $(LD) -o../../boot/$@ ../$(OBJ_DIR)/*.o $(LIBC) + objdump --source ../../boot/$@ >../$(OBJ_DIR)/kernel.dis + nm --line-numbers ../../boot/$@ | sort >../$(OBJ_DIR)/kernel.sym + strip ../../boot/$@ diff --git a/Dump/hybos/src/kernel/_krnl.h b/Dump/hybos/src/kernel/_krnl.h new file mode 100644 index 0000000..e268bd9 --- /dev/null +++ b/Dump/hybos/src/kernel/_krnl.h @@ -0,0 +1,131 @@ +#ifndef __TL__KRNL_H +#define __TL__KRNL_H + +//#ifdef __cplusplus +//extern "C" +//{ +//#endif + +#include /* jmp_buf */ + +#define MAX_VC 12 /* maximum number of virtual terminals */ + +/** + * CPU error codes + */ +#define _K_CPU_DBZ 0 /* Divide by zero */ +#define _K_CPU_SS 1 /* Single Step */ +#define _K_CPU_NMI 2 /* Non-maskable (NMI) */ +#define _K_CPU_BPX 3 /* Breakpoint */ +#define _K_CPU_OFT 4 /* Overflow trap */ +#define _K_CPU_BND 5 /* BOUND range exceeded */ +#define _K_CPU_IOP 6 /* Invalid opcode */ +#define _K_CPU_CNA 7 /* Coprocessor not available */ +#define _K_CPU_DFE 8 /* Double fault exception */ +#define _K_CPU_CSO 9 /* Coprocessor segment overrun */ +#define _K_CPU_CPE 10 /* Coprocessor error */ +#define _K_CPU_ITS 0x0A /* Invalid task state management */ +#define _K_CPU_SNP 0x0B /* Segment not present */ +#define _K_CPU_SEX 0x0C /* Stack exception (or illicit sex) */ +#define _K_CPU_GPF 0x0D /* General protection exception */ +#define _K_CPU_PGF 0x0E /* Page fault */ + +/** + * Interrupt table + */ +#define _K_IRQ_TIMER 0x08 /* timer (55ms intervals, 18.21590/sec) */ +#define _K_IRQ_KEYBOARD 0x09 /* keyboard service required */ +#define _K_IRQ_S8259 0x0A /* slave 8259 or EGA/VGA vertical retrace */ +#define _K_IRQ_COM2 0x0B /* COM2 service required (PS/2 MCA COM3-COM8) */ +#define _K_IRQ_COM1 0x0C /* COM1 service required */ +#define _K_IRQ_HDDREQ 0x0D /* fixed disk or data request from LPT2 */ +#define _K_IRQ_FDDSERV 0x0E /* floppy disk service required */ +#define _K_IRQ_LPT1REQ 0x0F /* data request from LPT1 */ +#define _K_IRQ_VIDEO 0x10 /* video (int 10h) */ +#define _K_IRQ_EQPDET 0x11 /* equipment determination (int 11h) */ +#define _K_IRQ_MEMORY 0x12 /* memory size (int 12h) */ +#define _K_IRQ_DIO 0x13 /* disk I/O service (int 13h) */ +#define _K_IRQ_SERIAL 0x14 /* serial communications (int 14h) */ +#define _K_IRQ_SYSTEM 0x15 /* system services, cassette (int 15h) */ +#define _K_IRQ_KBDSERV 0x16 /* keyboard services (int 16h) */ +#define _K_IRQ_LPT 0x17 /* parallel printer (int 17h) */ +#define _K_IRQ_ROM 0x18 /* ROM BASIC loader */ +#define _K_IRQ_BTSTRAP 0x19 /* bootstrap loader (unreliable, int 19h) */ +#define _K_IRQ_TOD 0x1A /* time of day (int 1A) */ +#define _K_IRQ_CBREAK 0x1B /* user defined ctrl-break handler (int 1B) */ +#define _K_IRQ_TICK 0x1C /* user defined clock tick handler (int 1C) */ +#define _K_IRQ_VIDEOP 0x1D /* 6845 video parameter pointer */ +#define _K_IRQ_DISKPARAM 0x1E /* diskette parameter pointer (base table) */ +#define _K_IRQ_GCHTBL 0x1F /* graphics character table */ +#define _K_IRQ_HDD 0x40 /* hard disk */ +#define _K_IRQ_FIXEDD0 0x41 /* fixed disk 0 parameters pointer (int 13h, int 9h) */ +#define _K_IRQ_RELVID 0x42 /* relocated video handler (EGA/VGA/PS) */ +#define _K_IRQ_UFT 0x43 /* user font table (EGA/VGA/PS) */ +#define _K_IRQ_GRAPH 0x44 /* first 128 graphics characters (also Netware) */ +#define _K_IRQ_FIXED1 0x46 /* fixed disk 1 parameters ptr (int 13h, int 9h/int 41h) */ +#define _K_IRQ_PCJR 0x48 /* PCjr cordless keyboard translation */ +#define _K_IRQ_PCJRSCAN 0x49 /* PCjr non-keyboard scancode translation table */ +#define _K_IRQ_USERALARM 0x4A /* user alarm (int 4A) */ +#define _K_IRQ_PALARM 0x50 /* periodic alarm timer (PS/2) */ +#define _K_IRQ_GSS 0x59 /* GSS computer graphics interface */ +#define _K_IRQ_BIOSEP 0x5A /* cluster adapter BIOS entry point */ +#define _K_IRQ_CADAPBT 0x5B /* cluster adapter boot */ +#define _K_IRQ_NETBIOS 0x5C /* NETBIOS interface, TOPS interface */ +#define _K_IRQ_EMS 0x67 /* LIM/EMS specifications (int 67h) */ +#define _K_IRQ_APPC 0x68 /* APPC */ +#define _K_IRQ_RTC 0x70 /* real time clock (int 15h) */ +#define _K_IRQ_REDIRIRQ2 0x71 /* software redirected to IRQ2 */ +#define _K_IRQ_MOUSE 0x74 /* mouse interrupt */ +#define _K_IRQ_HDC 0x76 /* fixed disk controller */ + +/* the code for setvect() and getvect() in +KSTART.ASM depends on the layout of this structure */ +typedef struct +{ + unsigned access_byte, eip; +} vector_t; + +/* the layout of this structure must match the order of registers +pushed and popped by the exception handlers in KSTART.ASM */ +typedef struct +{ +/* pushed by pusha */ + unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax; +/* pushed separately */ + unsigned ds, es, fs, gs; + unsigned which_int, err_code; +/* pushed by exception. Exception may also push err_code. +user_esp and user_ss are pushed only if a privilege change occurs. */ + unsigned eip, cs, eflags, user_esp, user_ss; +} regs_t; + +typedef struct /* circular queue */ +{ + unsigned char *data; + unsigned size, in_base, in_ptr/*, out_base*/, out_ptr; +} queue_t; + +typedef struct +{ +/* virtual console input */ + queue_t keystrokes; +/* virtual console output */ + unsigned esc, attrib, csr_x, csr_y, esc1, esc2, esc3; + unsigned short *fb_adr; +} console_t; + +typedef struct +{ + console_t *vc; + jmp_buf state; + enum + { + TS_RUNNABLE = 1, TS_BLOCKED = 2, TS_ZOMBIE = 3 + } status; +} task_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Dump/hybos/src/kernel/bootlog.c b/Dump/hybos/src/kernel/bootlog.c new file mode 100644 index 0000000..18f87fd --- /dev/null +++ b/Dump/hybos/src/kernel/bootlog.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include <_printf.h> /* do_printf() */ +#include "_krnl.h" +#include "bootlog.h" + +void klog(char *proc, char *entry, KLOGRESULT result, console_t *vtty0) +{ + unsigned oldattrib; + int i = 0; + int offset = 69; /* -4 for the "[ ]" part, -2 for the ": " part, -1 for space at end, and -4 for the status */ + char status[4]; + va_list args; + + args = args; + status[0] = '\0'; + + /** + * Save our old color attributes + */ + oldattrib = vtty0->attrib; + + if(result == K_KLOG_SUCCESS) + { + /** + * Successfull initialization of something. + * Write "..Ok" then leave + */ + vtty0->attrib = 8; + printf("\b\b\b\b.."); + vtty0->attrib = 2; + printf("Ok\n"); + vtty0->attrib = oldattrib; + + return; + } + else if(result == K_KLOG_FAILURE) + { + /** + * Unsuccessfull initialization of something. + * Write "Fail" then leave + */ + vtty0->attrib = 4; + printf("\b\b\b\bFail\n"); + vtty0->attrib = oldattrib; + + return; + } + + /** + * FIXME + * + * Should "wrap" the line instead + */ + if(strlen(entry) + 8 > 80) + return; + + vtty0->attrib = 8; + printf("[ "); + vtty0->attrib = 15; + printf("%s: %s", proc, entry); + vtty0->attrib = 8; + printf(" ]"); + + offset -= strlen(proc); + offset -= strlen(entry); + + for(i = 0; i < offset; i++) + printf("."); + + vtty0->attrib = 8; + printf("Wait"); + + vtty0->attrib = oldattrib; +} + diff --git a/Dump/hybos/src/kernel/bootlog.h b/Dump/hybos/src/kernel/bootlog.h new file mode 100644 index 0000000..4acee94 --- /dev/null +++ b/Dump/hybos/src/kernel/bootlog.h @@ -0,0 +1,15 @@ +#ifndef _BOOTLOG_H +#define _BOOTLOG_H +#include +#include +#include "_krnl.h" + +typedef unsigned KLOGRESULT; + +#define K_KLOG_SUCCESS 0x00 /* successfull completion of task, finish log message */ +#define K_KLOG_PENDING 0x01 /* task hasn't completed yet, delay logging status */ +#define K_KLOG_FAILURE 0x02 /* unsuccessfull completion of task, finish log message */ + +void klog(char *proc, char *entry, KLOGRESULT result, console_t *vtty0); + +#endif /* !defined(_BOOTLOG_H) */ diff --git a/Dump/hybos/src/kernel/cpu.c b/Dump/hybos/src/kernel/cpu.c new file mode 100644 index 0000000..f559d9c --- /dev/null +++ b/Dump/hybos/src/kernel/cpu.c @@ -0,0 +1,1351 @@ +/** + * Processor Management + */ + +/** + * Processor Identification + */ + +/** + * Name Title Revision + * ---------------------------------------------------------------------------------------------------- + * AMD AMD-K6 Processor Model 6 Revision Guide G 1998 August + * AMD AMD-K6 Processor Model 7 Revision Guide H 1999 June + * AMD AMD-K6-2 Processor Model 8 Revision Guide F 1999 June + * AMD AMD-K6-III Processor Model 9 Revision Guide C 1999 July + * AMD AMD Athlon Processor Model 1 & Model 2 Revision Guide D 2000 August + * AMD AMD Duron Processor Model 3 Revision Guide I 2002 December + * AMD AMD Athlon Processor Model 4 Revision Guide I 2002 December + * AMD AMD Athlon Processor Model 6 Revision Guide E 2002 December + * AMD AMD Duron Processor Model 7 Revision Guide C 2002 December + * AMD AMD Athlon Processor Model 8 Revision Guide C 2002 December + * + * Intel Intel386 CX/SXSA Microprocessor Specification Update 002 1997 January + * Intel Intel386 DX Processor Specification Update 002 1997 January + * Intel Intel386 EX Embedded Processor Specification Update 010 1998 October + * Intel 60- and 66-MHz Pentium Processor Specification Update 001 1997 February + * Intel Pentium Processor Specification Update 041 1999 January + * Intel Pentium Pro Processor Specification Update 039 1999 January + * Intel Mobile Intel Celeron Processor at 466 MHz, ... Specification Update 038 2002 November + * Intel Mobile Intel Pentium II Processor Specification Update 046 2002 November + * Intel Intel Pentium II Xeon Processor Specification Update 032 2002 January + * Intel Intel Pentium II Processor Specification Update 049 2002 July + * Intel Intel Celeron Processor Specification Update 047 2002 October + * Intel Intel Pentium III Processor Specification Update 045 2002 November + * Intel Mobile Intel Celeron Processor (0.18� and 0.13�) Specification Update 030 2002 August + * Intel Mobile Intel Pentium III Processor and ... Specification Update 036 2002 November + * Intel Intel Pentium III Xeon Processor Specification Update 037 2002 July + * Intel Intel Pentium 4 Processor Specification Update 029 2002 November + * Intel Mobile Intel Pentium 4 Processor-M Specification Update 008 2002 November + * Intel Intel Celeron Processor in the 478-Pin Package Specification Update 005 2002 November + * Intel Mobile Intel Celeron Processor on .13 Micron ... Specification Update 002 2002 August + * Intel Intel Xeon Processor Specification Update 020 2002 November + * Intel Intel Xeon Processor MP Specification Updata 009 2002 November + * Intel Low Voltage Intel Xeon Processor Specification Update 003 2002 November + * Intel Intel Pentium M Processor 001 2003 March + * Intel Intel Itanium Processor Specification Update 008 2003 January + * Intel Intel Itanium 2 Processor Specification Update 007 2003 January + * AMD AMD Processor Recognition W-1 2002 November + * Intel Intel Processor Identification and the CPUID Instruction 023 2003 March + * Intel Intel Processor Serial Number 001 1999 March + * IDT IDT WinChip C6 Data Sheet 1.10 1998 March + */ + +/** + * Mobile Athlon Detection + * + * Problems with CPU identication: + * 1) How much information? + * 2) Getting the information + * + * CPU identification has two purposes: OS information and user information. Since this module wil be + * used in TriOS we'll only need OS information (ident upto stepping for erratas) No process size, + * packaging or voltage info. I can be found withofficial name and codename. To prevent user confusion + * we need to show the diff between Celeron / Pentium / Xeon. Cache info is important for some memory + * defragmentation and alignment algorithms, perhaps. + * + * OLD CPUS: + * + * i4004 / i4040 + * i8008 / i8080 / i8080A / Zilog Z80 / i8085A / i8085AH + * + * 2.13 Contemporary CPUs + * Contemporary 16 bit CPUs to 8086/8088 were Zilog Z8000 CPU, Fairchild 9445 CPU, Texas Instruments TI9900 CPU and Mil-Std 1750A CPU. Last is reason DOD (Department Of Defence) contractors were not interested in 8086/8088. Mil-Std 1750A CPU was specified in all contracts of 1979 - 1984 period. + * Texas Instruments TI9900 CPU was probably the best of the lot, but Texas Instruments considered it a closed architecture, so no-one used it. + * + * 8086 - 80368 Intel Only + * 80486 Lots of manufacturers, almost no stpping info + * 80586 Lots of incorrect information and processors that were never sold, no stepping info + * 80686 Celeron / Pentium / Xeon // !Mobile! (Inel realy srewed up the names here) + * 80786 VERY WELL DONE BY INTEL (at least names are a bit more consistant) + * 80886 Not officialy realeasd at the moment + * + * Intel detection: AAA xxh doesn't #UD + * Cyrix Detection: Read the chipset data, but I heard there was a better one + * AMD Detection If there not TI, IBM, UMC, Cyrix or Intel, must be AMD, need sometin' better + * UMC Detection support CPUID I believe + * Texas Detection Models do not real conflic (aren't those things the same as IBM have to check) + * IBM Detection Ax or 8x as family (but there are exceptions) and models do not conflict + * + * CYRIX/TI/IBM Identificaton through Chipset Data (I/O 22h and 23h) + * + * Not about the use of stepping and revision: + * + * Stepping is used always. I try to change this into: Stepping = A0 / Revision = 3h + * Intel also calls the revion Stepping ID + * + * 386 Reset Data + * 0- 3 Minor Stepping Revision + * 4- 7 Major Stepping Model + * 8-11 Family Family + * 12-15 Type DX/SX/SL and TI/IBM/Intel + * + * 486+ Reset Data + * 0- 3 Revision + * 4- 7 Model + * 8-11 Family + * 12-13 Type 0 = Normal, 1 = OverDrive, 2 = Second Processor, 3 = Reserved + * 14-15 Reserved + * 16-19 Extended Model + * 20-27 Extended Family + * 28-30 Reserved + * 31 Reserved Has Serial Number + * + * All over drives could also have type 0 if they are an errata (whatever that means) + * + * Legal Mumbo Jumbo: In the CPUID Documentation, Intel says the PSN could be reported wrongly, for + * example if the voltage or frequency is wrong. It doesn't say it's corec when the processor is + * working on the correct voltage and frequency... + * + * IF HighetExtened CPUID Fucntion > 0x80000000 Brand String is supported, even if 0x800000001 or 2 ??? + * + * Should OverDrives just be ignored? According to Intel internal caches or execution times may vary + * According to Intel CPUID is unreliable in V86 Mode + * According to Intel MSRs vary between different Models of the Pentium (P5 that is) + * PSN is not guaranteed to be unique + * Intel PSN Style: XXXX-XXXX-XXXX-XXXX-XXXX-XXXX (96 bit) + * Transmeta PSN S: XXXXXXXX:XXXXXXXX:XXXXXXXX:XXXXXXXX (128 bit) + * + * Intel says apps need to use the BRAND STRING to identify the processor (ARE THEY CRAZY???) + * Intel says apps need to use the BRAND ID to identify the processor (not crazy, but useless) + * + * DAZ DAZ DAZ DAZ DAZ DAZ DAZ + * + * 11 DENORMALS ARE ZERO + * With the introduction of the SSE2 extensions, some Intel Architecture processors have the ability to convert SSE + * and SSE2 source operand denormal numbers to zero. This feature is referred to as Denormals -Are-Zero (DAZ). The + * DAZ mode is not compatible with IEEE Standard 754. The DAZ mode is provided to improve processor + * performance for applications such as streaming media processing, where rounding a denormal operand to zero does + * not appreciably affect the quality of the processed data. + * Some processor steppings support SSE2 but do not support the DAZ mode. To determine if a processor supports the + * DAZ mode, software must perform the following steps. + * 1. Execute the CPUID instruction with an input value of EAX=0 and ensure the vendor-ID string returned is �GenuineIntel�. + * 2. Execute the CPUID instruction with EAX=1. This will load the EDX register with the feature flags. + * 3. Ensure that the FXSR feature flag (EDX bit 24) is set. This indicates the processor supports the FXSAVE and FXRSTOR + * instructions. + * 4. Ensure that the XMM feature flag (EDX bit 25) or the EMM feature flag (EDX bit 26) is set. This indicates that the + * processor supports at least one of the SSE/SSE2 instruction sets and its MXCSR control register. + * 5. Zero a 16-byte aligned, 512-byte area of memory. This is necessary since some implementations of FXSAVE do not modify + * reserved areas within the image. + * 6. Execute an FXSAVE into the cleared area. + * 7. Bytes 28-31 of the FXSAVE image are defined to contain the MXCSR_MASK. If this value is 0, then the processor's + * MXCSR_MASK is 0xFFBF, otherwise MXCSR_MASK is the value of this dword. + * 8. If bit 6 of the MXCSR_MASK is set, then DAZ is supported. + * After completing this algorithm, if DAZ is supported, software can enable DAZ mode by setting bit 6 in the + * MXCSR register save area and executing the FXRSTOR instruction. Alternately software can enable DAZ mode by + * setting bit 6 in the MXCSR by executing the LDMXCSR instruction. Refer to the chapter titled �Programming with + * the Streaming SIMD Extensions (SSE)� in the Intel Architecture Software Developer�s Manual volume 1: Basic + * Architecture. + * + * DAZ DAZ DAZ DAZ DAZ DAZ DAZ + * + * Legacy detecyion + * 8086 EFLAGS 12-15 are always set + * 80286 EFLAGS 12-15 are clear in RM + * 80366 EFLAGS 18 Cant be set, if it can it a 486+ + * 80848 EFLAGS 21 Can't be set, if it can use CPUID + * + * FPU If control/status word can be saved it's present + * 27/387 Infinity control Rounding Stuff + * 487 486 with coproc + * + * What about the Xeon DP???? + * + * CMXCHG8B Disabled because of Stuoid MSWinNT bug (studpid. Microsft not diabling. stupid) + * + * sAVE bRAND sTRING BEFRORE s3 POWER DOWN + * + * NSC Geode!!!! + * + * "The iAPX 286 will push a different value on the stack for PUSH SP than the iAPX 86/88." + * "When a word write is performed at offset FFFFh in a segment, the 8086 will write one byte at offset + * FFFFh, and the other at offset 0, while an 80186 family processor will write one byte at offset + * FFFFh, and the other at offset 10000h (one byte beyond the end of the segment)." + * + * A finalty note: I'm looking for some information on the Intel Timna (Intel's MediaGX). The project + * was abandonned so Intel never published any useful material on this. It was based on the P-III. + * Also some info in the Microsoft X-Box' special P-III would help + */ + +#include +#include "bootlog.h" + +typedef struct { + unsigned n; + char* i; + char* v; +} VENDORLIST; + +VENDORLIST VendorList[] = +{ + {0x0001, "ThinkTrinary", "Trinary Technologies"}, + {0x0002, "GenuineIntel", "Intel"}, + {0x0003, "AuthenticAMD", "AMD"}, + {0x0003, "AMD ISBETTER", "AMD"}, + {0x0004, "CentaurHauls", "Centaur (IDT / VIA)"}, + {0x0005, "CyrixInstead", "Cyrix (VIA)"}, + {0x0006, "GenuineTMx86", "Transmeta"}, + {0x0007, "Geode by NSC", "National Semiconductor"}, + {0x0008, "NexGenDriven", "NexGen"}, + {0x0009, "RiseRiseRise", "Rise"}, + {0x000A, "SiS SiS SiS ", "SiS"}, + {0x000B, "UMC UMC UMC ", "UMC"}, +}; + +typedef struct { + long long id; + bool verified; + char* name; +} PROCLIST; + + + +PROCLIST ProcessorList[] = +{ + {0x00FFFFFF, false, "Unknown x86 Processor"}, + {0x0000FFFF, false, "Unknown 8086 Compatible Processor"}, + {0x0001FFFF, false, "Unknown 186 Compatible Processor"}, + {0x0002FFFF, false, "Unknown 286 Compatible Processor"}, + {0x0003FFFF, false, "Unknown 386 Compatible Processor"}, + {0x0004FFFF, false, "Unknown 486 Compatible Processor"}, + {0x0005FFFF, false, "Unknown 586 Compatible Processor"}, + {0x0006FFFF, false, "Unknown 686 Compatible Processor"}, + {0x02FFFFFF, false, "Unknown Intel Processor"}, + {0x0203FFFF, false, "Unknown Intel i386 Processor"}, + {0x0204FFFF, false, "Unknown Intel i486 Processor"}, + {0x0205FFFF, false, "Unknown Intel Pentium Processor"}, + {0x020501FF, false, "Intel Pentium Classic"}, + {0x020502FF, false, "Intel Pentium"}, + {0x020503FF, false, "Intel Pentium OverDrive"}, + {0x020504FF, false, "Intel Pentium MMX"}, + {0x020507FF, false, "Intel Pentium Mobile"}, + {0x020508FF, false, "Intel Pentium MMX Mobile 'Tillamook'"}, + {0x0206FFFF, false, "Unknown Intel P6 Processor"}, + {0x020601FF, false, "Intel Pentium Pro"}, + {0x020603FF, false, "Unknown Intel Pentium II"}, + {0x02060301, false, "Intel Pentium II 'Klamath'"}, /* 0512 - 0512 */ + {0x02060305, false, "Intel Pentium II OverDrive"}, /* OVERDRIVE */ + {0x020605FF, false, "Unknown Intel Pentium II"}, + {0x02060500, false, "Intel Celeron II 'Covington'"}, /* 0000 - 0000 */ + {0x02060501, false, "Intel Pentium II 'Deschutes'"}, /* 0512 - 0512 */ + {0x02060502, false, "Intel Xeon II 'Drake'"}, /* 0512 - 2048 */ + {0x02060504, false, "Intel Pentium II Mobile 'Tonga'"}, /* 0512 - 0512 */ + {0x020606FF, false, "Unknown Intel Pentium II"}, + {0x02060600, false, "Intel Celeron II 'Mendocino'"}, /* 0128 - 0128 */ +/**/ {0x02060603, false, "Intel Celeron II Mobile"}, /* 0128 - 0128 (A) */ + {0x02060604, false, "Intel Pentium II Mobile 'Dixon'"}, /* 0256 - 0256 (A) */ + {0x020607FF, false, "Unknown Intel Pentium III"}, + {0x02060701, false, "Intel Pentium III 'Katmai'"}, /* 0512 - 0512 */ + {0x02060702, false, "Intel Xeon III 'Tanner'"}, /* 0512 - 2048 */ + {0x020608FF, false, "Unknown Intel Pentium III"}, + {0x02060801, false, "Intel Celeron III 'Coppermine'"}, + {0x02060802, false, "Intel Pentium III (Mobile) 'Coppermine'"}, + {0x02060803, false, "Intel Xeon III 'Cascades'"}, + {0x020609FF, false, "Unknown Intel Pentium M"}, + {0x02060916, false, "Intel Pentium M 'Banias'"}, + {0x02060AFF, false, "Unknown Intel Pentium III"}, + {0x02060A03, false, "Intel Xeon III 'Cascades'"}, + {0x02060BFF, false, "Unknown Intel Pentium III"}, + {0x02060B03, false, "Intel Celeron III 'Tualatin'"}, + {0x02060B04, false, "Intel Pentium III 'Coppermine'"}, + {0x02060B06, false, "Intel Pentium III Mobile 'Geyserville'"}, + {0x02060B07, false, "Intel Celeron III Mobile 'Geyserville'"}, + {0x0207FFFF, false, "Unknown Intel Itanium"}, + {0x020FFFFF, false, "Unknown Intel NetBurst Processor"}, + {0x020F0008, false, "Intel Pentium 4 'Willamette'"}, + {0x020F000E, false, "Intel Xeon 4 'Foster'"}, + {0x020F0108, false, "Intel Pentium 4 'Willamette'"}, + {0x020F0109, false, "Intel Pentium 4 'Willamette'"}, + {0x020F010A, false, "Intel Celeron 4 'Willamette'"}, + {0x020F010B, false, "Intel Xeon 4 MP 'Foster'"}, + {0x020F010E, false, "Intel Xeon 4 'Foster'"}, + {0x020F020C, false, "Intel Xeon 4 MP 'Gallatin'"}, + {0x020F0208, false, "Intel Celeron 4 Mobile 'Northwood'"}, + {0x020F0209, false, "Intel Pentium 4 'Northwood'"}, + {0x020F020B, false, "Intel Xeon 4 'Prestonia'"}, + {0x020F020E, false, "Intel Pentium 4 Mobile 'Northwood'"}, + {0x020F020A, false, "Intel Celeron 4 'Northwood'"}, + {0x0210FFFF, false, "Unknown Intel Itanium 2"}, + {0x03FFFFFF, false, "Unknown AMD Processor"}, + {0x0306FFFF, false, "Unknown AMD Athlon Processor"}, + {0x030601FF, false, "AMD Athlon 'Pluto'"}, + {0x030602FF, false, "AMD Athlon 'Argon'"}, + {0x030603FF, false, "AMD Duron 'Spitfire'"}, + {0x030604FF, false, "AMD Athlon 'Thunderbird'"}, + {0x030605FF, false, "AMD Athlon Ultra 'Mustang'"}, + {0x030606FF, false, "AMD Athlon MP 'Palomino'"}, + {0x030606FF, false, "AMD Athlon XP/MP 'Palomino'"}, + {0x030606FF, false, "AMD Athlon 4 Mobile 'Palomino'"}, + {0x030607FF, false, "AMD Duron 'Morgan'"}, + {0x030607FF, false, "AMD Duron MP 'Morgan'"}, + {0x030607FF, false, "AMD Duron Mobile 'Morgan'"}, + {0x030608FF, false, "AMD Athlon XP 'Thoroughbred'"}, + {0x030608FF, false, "AMD Athlon MP 'Thoroughbred'"}, + {0x030608FF, false, "AMD Athlon XP Mobile 'Thoroughbred'"}, + {0x030609FF, false, "AMD Duron 'Appaloosa'"}, + {0x030609FF, false, "AMD Duron MP 'Appaloosa'"}, + {0x030609FF, false, "AMD Duron Mobile 'Appaloosa'"}, + {0x03060AFF, false, "AMD Athlon XP 'Barton'"}, + {0x03060AFF, false, "AMD Athlon MP 'Barton'"}, + {0x04FFFFFF, false, "Unknown IDT / VIA Processor"}, + {0x0405FFFF, false, "Unknown IDT WinChip"}, + {0x040504FF, false, "IDT WinChip C6"}, + {0x040508FF, false, "IDT WinChip 2"}, + {0x040509FF, false, "IDT WinChip 3"}, + {0x0406FFFF, false, "Unknown VIA C3"}, + {0x040606FF, false, "VIA C3 'Samuel 1' / VIA Eden 4000"}, + {0x040607FF, false, "VIA C3 'Samuel 2 / Ezra' / VIA Eden 5000 / VIA Eden 6000"}, /* 0-7 / 8-F */ + {0x040608FF, false, "VIA C3 'Ezra-T' (VIA Eden 7000)"}, +// {0x040609FF, false, "VIA C3 'Nehalem VIA Eden 8000"}, + {0x05FFFFFF, false, "Unknown Cyrix Processor"}, + {0x0506FFFF, false, "Unknown VIA Cyrix III"}, + {0x050605FF, false, "VIA Cyrix III 'Joshua'"}, + {0x06FFFFFF, false, "Unknown Transmeta Processor"}, + {0x0604FFFF, false, "Transmeta Crusoe 3x00 / 5x00 Processor"}, + {0x08FFFFFF, false, "Unknown NexGen Processor"}, + {0x0805FFFF, false, "Unknown NexGen Nx586 / Nx686 Processor"}, + {0x080500FF, false, "Unknown NexGen Nx586"}, + {0x08050000, false, "NexGen Nx586"}, + {0x08050001, false, "NexGen Nx586FP"}, + //{0x0805??FF, false, "Unknown NexGen Nx686"}, + {0x0CFFFFFF, false, "Unknown UMC Processor"}, + {0x0C04FFFF, false, "Unknown UMC 486 Processor"}, + {0x0C0401FF, false, "UMC U5SD"}, + {0x0C0402FF, false, "UMC U5S"}, + {0x0C0403FF, false, "UMC U486DX2"}, + {0x0C0405FF, false, "UMC U486SX2"}, + + + + + + + + + {0xABCDABCD, false, "XXX"} +}; + + +#if 0 + /**********************************************************************************************/ +// {"GenuineIntel", 0x05, 0x00, 0x0?, 0, false, "Intel Pentium Classic (A*)"}, +// {"GenuineIntel", 0x05, 0x01, 0x02, 0, false, "Intel Pentium Classic (B*)"}, +// {"GenuineIntel", 0x05, 0x01, 0x04, 0, false, "Intel Pentium Classic (B2)"}, +// {"GenuineIntel", 0x05, 0x04, 0x01, 0, false, "Intel Pentium MMX (A1)"}, +// {"GenuineIntel", 0x05, 0x04, 0x02, 0, false, "Intel Pentium MMX (A2)"}, +// {"GenuineIntel", 0x05, 0x05, 0x0?, 0, false, "Intel Pentium MMX OverDrive"}, +// {"GenuineIntel", 0x05, 0x06, 0x0?, 0, false, "Intel Pentium MMX OverDrive"}, +// {"GenuineIntel", 0x06, 0x00, 0x0?, 0, false, "Intel Pentium Pro (A0)"}, +// {"GenuineIntel", 0x06, 0x04, 0x0?, 0, false, "Intel Pentium II OverDrive (?)"}, +// {"GenuineIntel", 0x0F, 0x02, 0x07, 0x0E, false, "Intel Pentium 4 Mobile (C1)"}, +// {"AuthenticAMD", 0x06, 4, 4, 0, false, "AMD Athlon 'Thunderbird' Model 4 (B0)"}, //??Grzegorz +// {"AuthenticAMD", 0x06,5?, ?, 0, false, "AMD Athlon Ultra 'Mustang' Model 5? (??)"}, /* CANCELED */ + +// {"GenuineIntel",F?,3?, ?, ?, "Intel Pentium 4 'Prescott' (??)"}, //.09 +// {"GenuineIntel",F?,3?, ?, ?, "Intel Xeon 4 'Nocona' (??)"}, //.09 +// {"GenuineIntel",F?,4?, ?, ?, "Intel Pentium 4 'Tyler' (??)"}, +// {"GenuineIntel",F?,4?, ?, ?, "Intel Pentium 4 'Tejas' (??)"}, +// {"GenuineIntel",F?,4?, ?, ?, "Intel Xeon 4 'Potomac' (??)"}, + +//GI Nehalem Pentium 5 + + +// {"GenuineIntel", ?,?, ?, ?, "Intel Mobillium 'Banias' (??)"}, +// {"GenuineIntel", ?,?, ?, ?, "Intel Mobillium 'Dothan' (??)"}, +// {"GenuineIntel", ?,?, ?, ?, "Intel Mobillium 'Morem' (??)"}, /* Next GEN!!!! */ +// {"GenuineIntel", ?,?, ?, ?, "Intel Mobillium 'Gilo' (??)"}, /* Next GEN!!!! */ +// Intel's truly mobile processor. Intel says this is a completly new processor. Sources say it's just +// a rework of the PIII or P4. I don't believe this, beacause it has SSE2 (not in PIII) and is faster +// than the P4. I guess they just shortened the enormous 20 stage P4 pipeline a bit, which is too long +// to be used effecivly. More backup is provided for the fact that the Pentium 5 will be based upon +// this chip. And another thing many sources will tell you this chip will be called 'Intel Banias', +// didn't Intel call the Pentium III, Intel Katmai for a very long time. With this in mind it wouldn't +// even surprise me if this processor is goin to be called Pentium 5. Sorry but I have to go one now +// I'm brainstorming. The mobile part of it might not even be used for mobile computers, but for +// desktops and servers as well, because cooling has become almost impossible today. If speeds are +// going to get even higher the next couple of years, the processor cores will just melt. Because +// AMD's processors get even hotter and isn't working on a similar project Intel might even regain +// it's market monopoly (wheter this is good or bad, I don't know?) +// {"GenuineIntel",F?,?, ?, ?, "Intel Pentium 5 'Nehalem' (??)"}, +// This is just a rumor. It's supposed to come out in 2006, run at 6Ghz and have a bus speed of +// 1.5Ghz. It COULD be using the Intel Banias core. Suggesting the Banias is a Pentium 5 and that it +// IS completely new. IF you read the note above this could also be the Pentium 6 or something. +// {"GenuineIntel", 7, 6, 4, 0, "Intel Itanium 'Merced' (C0)"}, //0007000604 +// {"GenuineIntel", 7, 7, 4, 0, "Intel Itanium 'Merced' (C1)"}, //0007000704 +// {"GenuineIntel", 7, 7, 4, 0, "Intel Itanium 'Merced' (C2)"}, //0007000804 +// {"GenuineIntel", 0x10, 0, ?, 0, "Intel Itanium 2 'McKinley' (B3)"}, //001F000704 +// {"GenuineIntel",A?, ?, ?, ?, ???, "Intel Itanium 2 'Madison' (??)"}, +// {"GenuineIntel",A?, ?, ?, ?, ???, "Intel Itanium 2 'Deerfield' (??)"},XXX +// {"GenuineIntel",A?, ?, ?, ?, ???, "Intel Itanium 2 'Montecito' (??)"} +// {"GenuineIntel",A?, ?, ?, ?, ???, "Intel Itanium 2 'Shavano' (??)"}, +// {"GenuineIntel",A?, ?, ?, ?, ???, "Intel Itanium 2? 'Yosemite' (??)"}, +// {"GenuineIntel",A?, ?, ?, ?, ???, "Intel Itanium 2? 'Tanglewood' (??)"}, + +// {"AuthenticAMD", ?, ?, ?, ?, "AMD Athlon XP64 / Hammer 'Clawhammer' (??)"}, +// {"AuthenticAMD", ?, ?, ?, ?, "AMD Athlon XP64 / Hammer 'San Diego' (??)"}, +// {"AuthenticAMD", ?, ?, ?, ?, "AMD Athlon XP64 / Hammer Mobile 'Odessa' (??)"}, +// {"AuthenticAMD", ?, ?, ?, ?, "AMD Opteron 'Sledgehammer' (??)"}, +// {"AuthenticAMD", ?, ?, ?, ?, "AMD Opteron 'Athens' (??)"}, +// {"CentaurHauls", 0x05, 0x08, 0x01, 0x00, false, "IDT WinChip 2"}, +// {"CentaurHauls", 6, 0xA, ?, 0, "IDT WinChip 4"}, //PROBABLY DOESN'T EXIST! -> Is a VIA C3!!! + + /** Intel 8086 / 8088 (Includes model manufactured by AMD, Harris, Siemens, Hitachi) ************/ + + //I belive there an alroithm to identify the diff between HMOS and CMOS models + {"GenuineIntel", 1, 0, 0, 0, false, "Intel 8088"}, + {"GenuineIntel", 1, 0, 0, 1, false, "Intel 8086"}, + {"GenuineIntel", 1, 0, 0, 2, false, "Intel 80C88"}, + {"GenuineIntel", 1, 0, 0, 3, false, "Intel 80C86"}, + {"GenuineIntel", 1, 0, 0, 4, false, "Intel 80188"}, //XL/EA/EB/EC AMD/Siemens + {"GenuineIntel", 1, 0, 0, 5, false, "Intel 80186"}, //XL/EA/EB/EC AMD/Siemens + {"GenuineIntel", 1, 0, 0, 6, false, "NEC V20"}, //V20H/V25/V25 Plus/V25 Softwae Guard/V40/V40H//V45 + {"GenuineIntel", 1, 0, 0, 7, false, "NEC V30"}, //V30H/V35/V35 Plus/V35 Softwae Guard/V50/V50H//V55 + //Intel 80886??? + + {"GenuineIntel", 2, 0, 0, 0, false, "Intel 80286"},//amd/harris/siemens/fujitsu/kruger + + + /** Intel 386 ***********************************************************************************/ + + + //The 386 use a very different format: Family (8-bits!) + Revision (8-bits! Model+Stepping) + //Not to myself: The high four bits of the family should coume in the extra field + //These chips were also munufactured by AMD!!! They are affected by the POPAD bug???? + //Old (sigma-pi) i386 have 32-bit multipy bug + //C&T 38600DX do not have POPAD bug. IBM 386SLC unknwon + //AMD 386DX & DXL hav Intel microcode + //AMD 386DXLV & SXLV hav UMOV??? + //Nx586 has no AC has 386 instr set + + //Erly modles (A stepping) as Famuly: 0, Revision: ??? (In Intel Docs! Support the 'Bit Instrucs') + //0300 + // * Intel i386DX : F0 + {"GenuineIntel", 3, 0, 3, 0, false, "Intel i386DX (B0/B1/B2/B3/B4/B5/B6/B7/B8/B9/B10)"}, + {"GenuineIntel", 3, 0, 4, 0, false, "Intel i386DX (C???)"}, // Stepping not confiremed + {"GenuineIntel", 3, 0, 5, 0, false, "Intel i386DX (D0)"}, + {"GenuineIntel", 3, 0, 8, 0, false, "Intel i386DX (D1/D2/E0/E1/F0)"}, //E0/E1/F0 coulld also be 9!!! + + //The family 23 could also simply be 3 (I don't know were the 2 stands for???) Officialy not part + //Difference between DX and SX perhaps (I hope so) + // * Intel i386CX/SXSA : A2 / B + // * Intel i386EX : A0 / B1 / B2 + {"GenuineIntel",23, 0, 4, 0, false, "Intel i386SX (A0)"}, + {"GenuineIntel",23, 0, 5, 0, false, "Intel i386SX (B)"}, + {"GenuineIntel",23, 0, 8, 0, false, "Intel i386SX (C/D/E)"}, + {"GenuineIntel",23, 0, 8, 0, false, "Intel i386CXSA/B (A) / i386EX (A) / i386SXSA (?)"}, //A || B + {"GenuineIntel",23, 0, 9, 0, false, "Intel i386SX (?)"}, //EMBEDDED (CX/FX + {"GenuineIntel",23, 0, 9, 0, false, "Intel i386EX (A0/B1/C1)"}, + + //Dito for 33 (376 perhaps) + {"GenuineIntel",33, 0, 5, 0, false, "Intel i376 (A0)"}, //Never used in PC because they only work in PM + {"GenuineIntel",33, 0, 8, 0, false, "Intel i376 (B)"}, //... + + //And againt for 43 (386SL) + //have a signatur register @ 30e + //step level A0: 0x4300, + //step level A1: 0x4300, + //step level A2: 0x4301, + //step level A3: 0x4302, + //step level B0: 0x4310, + //step level B1: 0x4311. +// {"GenuineIntel",43, 0, 5, ?, false, "Intel i386SL (B)"}, +// {"GenuineIntel",43, 0, 5, ?, false, "Intel i386SL (A0/A1/A2/A3)"}, //Not sure about this +// {"GenuineIntel",43, 1, 0, 0, false, "Intel i386SL (A0/A1/A2/A3)"}, +// {"GenuineIntel",43, 1, 1, 0, false, "Intel i386SL (B0/B1)"}, + + //RapidCADs are not so familiar to me, where they ever used in PCs??? + {"GenuineIntel", 3, 4, 0, 0, false, "Intel RapidCAD (A)"}, + {"GenuineIntel", 3, 4, 1, 0, false, "Intel RapidCAD (B)"}, + + + /** Intel 486 ***********************************************************************************/ + + //According to Intel only SL Enhanced and WB Enhanced processors support CPUID + + {"GenuineIntel", 4, 0, 0, 0, false, "Intel i486DX (A0/A1)"}, + {"GenuineIntel", 4, 0, 1, 0, false, "Intel i486DX (B2/B3/B4/B5/B6)"}, + {"GenuineIntel", 4, 0, 2, 0, false, "Intel i486DX (C0)"}, + {"GenuineIntel", 4, 0, 3, 0, false, "Intel i486DX (C1)"}, + {"GenuineIntel", 4, 0, 4, 0, false, "Intel i486DX (D0)"}, +// {"GenuineIntel", 4, 0, ?, 0, false, "Intel i486DX"}, + + {"GenuineIntel", 4, 1, 0, 0, false, "Intel i486DX (cA2/cA3)"}, + {"GenuineIntel", 4, 1, 1, 0, false, "Intel i486DX (cB0/cB1)"}, + {"GenuineIntel", 4, 1, 3, 0, false, "Intel i486DX (cC0)"}, + {"GenuineIntel", 4, 1, 4, 0, false, "Intel i486DX (aA0/aA1)"}, //SL Enhanced + {"GenuineIntel", 4, 1, 5, 0, false, "Intel i486DX (aB0)"}, //SL Enhanced +// {"GenuineIntel", 4, 1, ?, 0, false, "Intel i486DX"}, + + {"GenuineIntel", 4, 2, 0, 0, false, "Intel i486SX / i487SX (A0)"}, //Should 487 be model 3 + {"GenuineIntel", 4, 2, 1, 0, false, "Intel i487SX (B0)"}, //Should 487 be model 3 + {"GenuineIntel", 4, 2, 2, 0, false, "Intel i486SX (B0)"}, + {"GenuineIntel", 4, 2, 3, 0, false, "Intel i486SX (bBx)"}, //SL Enhanced and... CPUID + {"GenuineIntel", 4, 2, 4, 0, false, "Intel i486SX (gAx)"}, + {"GenuineIntel", 4, 2, 7, 0, false, "Intel i486SX (cA0)"}, + {"GenuineIntel", 4, 2, 8, 0, false, "Intel i486SX (cB0)"}, + {"GenuineIntel", 4, 2, 0xA, 0, false, "Intel i486SX (aA0/aA1)"}, //SL Enhanced + {"GenuineIntel", 4, 2, 0xB, 0, false, "Intel i486SX (aB0/aC0)"}, //SL Enhanced + {"GenuineIntel", 4, 2, 0xE, 0, false, "Intel i486SX (E)"}, //SL Enhanced??? Grzegorz +// {"GenuineIntel", 4, 2, ?, 0, false, "Intel i486SX"}, + +// {"GenuineIntel", 4, 3, ?, 0, false, "Intel i486DX2 / i486DX2 OverDrive / i487"}, + {"GenuineIntel", 4, 3, 2, 0, false, "Intel i486DX2 (A0/A1/A2)"}, + {"GenuineIntel", 4, 3, 3, 0, false, "Intel i486DX2 (B1)"}, + {"GenuineIntel", 4, 3, 4, 0, false, "Intel i486DX2 (aA0/aA1)"}, //SL Enhanced + {"GenuineIntel", 4, 3, 5, 0, false, "Intel i486DX2 (aB0/aC0)"}, //SL Enhanced + {"GenuineIntel", 4, 3, 6, 0, false, "Intel i486DX2"}, //Possibly as WB in WT Mode + + {"GenuineIntel", 4, 4, 0, 0, false, "Intel i486SL (A)"}, + {"GenuineIntel", 4, 4, 1, 0, false, "Intel i486SL (?)"}, + {"GenuineIntel", 4, 4, 3, 0, false, "Intel i486SL (?)"}, //In Intel Docs, saupoosed to support CPUID +// {"GenuineIntel", 4, 4, ?, 0, false, "Intel i486SL"}, + +// {"GenuineIntel", 4, 5, ?, 0, false, "Intel i486SX2"}, + {"GenuineIntel", 4, 5, 0xB, 0, false, "Intel i486SX2 (aC0)"}, //SL Enhanced + + {"GenuineIntel", 4, 7, 0, 0, false, "Intel i486DX2-WB (A)"}, + {"GenuineIntel", 4, 7, 3, 0, false, "Intel i486DX2-WB (?)"}, //In Intel Docs, saupoosed to support CPUID +// {"GenuineIntel", 4, 7, ?, 0, false, "Intel i486DX2-WB"}, + + {"GenuineIntel", 4, 8, 0, 0, false, "Intel i486DX4 (A)"}, + {"GenuineIntel", 4, 8, 0, 1, false, "Intel i486DX4 OverDrive (A)"}, + {"GenuineIntel", 4, 8, 3, 0, false, "Intel i486DX4 (A)"}, //Possibly as WB in WT Mode, Support CPUID +// {"GenuineIntel", 4, 8, ?, 0, false, "Intel i486DX4 / i486DX4 OverDrive"}, + + {"GenuineIntel", 4, 9, 0, 0, false, "Intel i486DX4-WB (A)"}, //(Do not exist according to Intel CPUID Inf) +// {"GenuineIntel", 4, 9, ?, 0, false, "Intel i486DX4-WB"}, + + + /** AMD *****************************************************************************************/ + + {"AuthenticAMD", 4, 1, 2, 0, false, "AMD 486DX"}, + {"AuthenticAMD", 4, 3, 2, 0, false, "AMD 486DX/2"}, //DX4 (WT2x) toooo && DXL2 / DX4NV8T + {"AuthenticAMD", 4, 3, 4, 0, false, "AMD 486DX/2"}, //DX4 (WT2x) toooo && DXL2 / DX4SV8B +// {"AuthenticAMD", 4, 7, ?, 0, false, "AMD 486DX/2-WB"}, //DX4 (WB2x) + {"AuthenticAMD", 4, 7, 4, 0, false, "AMD SV8B (WT)"}, +// {"AuthenticAMD", 4, 8, ?, 0, false, "AMD 486DX/4"}, //5x86 toooo + {"AuthenticAMD", 4, 8, 4, 0, false, "AMD 486DX/4"}, //3xWT + {"AuthenticAMD", 4, 9, 4, 0, false, "AMD 486DX/4-WB"}, //3xWB + {"AuthenticAMD", 4, 0xE, 4, 0, false, "AMD Am5x86-WT"}, //AMD Enhanced 486 + {"AuthenticAMD", 4, 0xF, 4, 0, false, "AMD Am5x86-WB (4)"}, //AMD Enhanced 486 + + //cores: 5.0 / 5.0 (MMX) / 5.1 / 5.2 + {"AuthenticAMD", 5, 0, 0, 0, false, "AMD K5 SSA/5 (E)"}, //??? Stepping Name + {"AuthenticAMD", 5, 0, 1, 0, false, "AMD K5 SSA/5 (F)"}, //??? Stepping Name +// {"AuthenticAMD", 5, 0, ?, 0, false, "AMD K5 SSA/5 (?)"}, //??? Stepping Name +// {"AuthenticAMD", 5, 1, ?, 0, false, "AMD K5 5k86 Model 1 (?)"}, //??? Stepping Name + {"AuthenticAMD", 5, 1, 1, 0, false, "AMD K5 5k86 Model 1 (?)"}, //??? Stepping Name + {"AuthenticAMD", 5, 1, 2, 0, false, "AMD K5 5k86 Model 1 (?)"}, //??? Stepping Name + {"AuthenticAMD", 5, 1, 4, 0, false, "AMD K5 5k86 Model 1 (?)"}, //CLKMUL=1.5 +// {"AuthenticAMD", 5, 2, ?, 0, false, "AMD K5 5k86 Model 1 (?)"}, //??? Stepping Name + {"AuthenticAMD", 5, 2, 4, 0, false, "AMD K5 5k86 Model 2 (?)"}, //CLKMUL=1.75 +// {"AuthenticAMD", 5, 3, ?, 0, false, "AMD K5 5k86 Model 3 (?)"}, //??? Stepping Name (NOT RELEASED) + {"AuthenticAMD", 5, 3, 4, 0, false, "AMD K5 5k86 Model 1 (?)"}, //CLKMUL=2.0 + + + //Missing: MobileS (= k6-7!!!) / K6-2+ n/ K6-III+ + {"AuthenticAMD", 5, 6, 1, 0, false, "AMD-K6 Model 6 (B)"}, + {"AuthenticAMD", 5, 6, 2, 0, false, "AMD-K6 Model 6 (C)"}, + {"AuthenticAMD", 5, 7, 0, 0, false, "AMD-K6 Model 7 'Little Foot' (A)"}, + {"AuthenticAMD", 5, 8, 0, 0, false, "AMD-K6-2 Model 8 'Chomper' (A0)"}, //doesnt CXT stnd fr Chomber XT +// {"AuthenticAMD", 5, 8, 8, 0, false, "AMD-K6-2 Model 8 'Chomper' (AC)"}, //In Recognition < CXT + {"AuthenticAMD", 5, 8, 0xC, 0, false, "AMD-K6-2 Model 8 'Chomper' (AC)"}, //CXT Core (Write COmbining) I believe YES!!! avvording to Chase + {"AuthenticAMD", 5, 9, 1, 0, false, "AMD-K6-III 'Sharptooth' Model 9 (B)"}, +// {"AuthenticAMD", 5, 0xD, ?, 0, false, "AMD-K6-2+ / K6-III+ 'Sharptooth' (?)"}, //Not doced by AMD (3DNow!+) + +//* {"AuthenticAMD", 6, 0, ?, 0, "AMD K7 [ES]"}, //UNDOCUMENTED!?! + + + /* Cyrix **************************************************************************************/ + + //My sources are unreliable at best for these suckers, so I list them all + //Also I belive the names aren't entire ly correct, confused codename/ actualt name and extensions + + {"CyrixInstead", 0, 0, 5, 0, false, "Cyrix M5 Cx486S/D"}, //No CPUID I believe (is family correct?) + {"CyrixInstead", 0, 0, 6, 0, false, "Cyrix M6 Cx486DX"}, //... + {"CyrixInstead", 0, 0, 7, 0, false, "Cyrix M7 Cx486DX2"}, //... + {"CyrixInstead", 0, 0, 8, 0, false, "Cyrix M8 Cx486DX4"}, + //... + + {"CyrixInstead", 4, 1, 0, 0, false, "Cyrix 4x86SLC"}, +// {"CyrixInstead", 4, 2, ?, 0, false, "Cyrix 5x86"}, + {"CyrixInstead", 4, 2, 9, 0, false, "Cyrix 5x86 (Rev 1-)"}, //Bus *2 + {"CyrixInstead", 4, 2, 0xB, 0, false, "Cyrix 5x86 (Rev 1-)"}, //Bus *2 + {"CyrixInstead", 4, 2, 0xD, 0, false, "Cyrix 5x86 (Rev 1-)"}, //Bus *3 + {"CyrixInstead", 4, 2, 0xF, 0, false, "Cyrix 5x86 (Rev 1-)"}, //Bus *3 +// {"CyrixInstead", 4, 4, ?, 0, false, "Cyrix MediaGX"}, + {"CyrixInstead", 4, 9, 0, 0, false, "Cyrix 5x86 (Rev 2+)"}, +// {"CyrixInstead", 4, 9, ?, 0, false, "Cyrix 5x86"}, + + +// IBM ID=15h Top (65 KB JPG) and Bottom (104 KB JPG) +// IBM ID=17h Top (71 KB JPG) and Bottom (110 KB JPG) +// Cyrix ID=17h Top (63 KB JPG) and Bottom (102 KB JPG) +// IBM ID=22h Top (82 KB JPG) and Bottom (99 KB JPG) +// {"CyrixInstead", 5, 0, ?, 0, false, "Cyrix M1 (6x86)"}, //Grzegorz + {"CyrixInstead", 5, 2, 0, 0, false, "Cyrix M1 (6x86)"}, //Early Models (L / non-L versions???? (LV too)) +// {"CyrixInstead", 5, 2, ?, 0, false, "Cyrix M1 (6x86)"}, //Early Models (L / non-L versions???? (LV too)) + {"CyrixInstead", 5, 3, 0, 0, false, "Cyrix M1 (6x86)"}, //1.0x Bus Ratio + {"CyrixInstead", 5, 3, 1, 0, false, "Cyrix M1 (6x86)"}, //2.0x Bus Ratio + {"CyrixInstead", 5, 3, 2, 0, false, "Cyrix M1 (6x86)"}, //1.0x Bus Ratio + {"CyrixInstead", 5, 3, 3, 0, false, "Cyrix M1 (6x86)"}, //2.0x Bus Ratio + {"CyrixInstead", 5, 3, 4, 0, false, "Cyrix M1 (6x86)"}, //3.0x Bus Ratio + {"CyrixInstead", 5, 3, 5, 0, false, "Cyrix M1 (6x86)"}, //4.0x Bus Ratio + {"CyrixInstead", 5, 3, 6, 0, false, "Cyrix M1 (6x86)"}, //3.0x Bus Ratio + {"CyrixInstead", 5, 3, 7, 0, false, "Cyrix M1 (6x86)"}, //4.0x Bus Ratio +// {"CyrixInstead", 5, 4, ?, 0, false, "Cyrix MediaGX MMX"}, + + +// ID=02h Top (73 KB JPG) and Bottom (100 KB JPG) +// ID=04h Top (79 KB JPG) and Bottom (106 KB JPG) +// ID=08h Top (66 KB JPG) and Bottom (101 KB JPG) +// ID=53 07 + {"CyrixInstead", 6, 0, 0, 0, false, "Cyrix MII (6x86MX)"}, +// {"CyrixInstead", 6, 0, ?, 0, "Cyrix MII (6x86MX)"}, + + //These guys are actualy a Cyrix M2 with minor enhancemets (3DNow! / better FPU), but who cares, + //they were never taken into procuvtion. Although VIA C3 probalby stands for Cyrix M3 and not, + //Centaur WinChip 3. THey got a WinChip 4 core. Josua was nOT released! Start with samual and Samual 2 then Ezra and Ezra-T + // {"CyrixInstead", 6, 5, 1, 0, false, "VIA Cyrix III 'Joshua'"}, //2.0x Bus Ratio + + //Other names heard: Cyrix M-III 'Mojave' (Chase, so reliable never produced!) + // Cayenne / Gobi / Jalapeno + // Cayenne, then Gobi, then Joshua + + //THE VIA Series!!!!! + //New models : C4 'Nehemia' Has SSE instead of #dnOW! newer modles will be Esther + // CZA is a P4 clone + + /************************************************************************************************/ + + + + + +// I'm not sure about the CNs +// {"RiseRiseRise", 5, 0, ?, 0, "Rise mP6 iDragon '6401?' (Model 0)"}, //0.25 +// {"RiseRiseRise", 5, 0, 4, 0, "Rise mP6 iDragon '6401?' (Model 0)"}, //0.25 +// {"RiseRiseRise", 5, 1, ?, 0, "Rise mP6 iDragon 'Kirin?' (Model 1)"}, +// {"RiseRiseRise", 5, 2, ?, 0, "Rise mP6 iDragon 'Lynx?' (Model 2)"}, //0.18 +// {"RiseRiseRise", 5, 8, ?, 0, "Rise mP6 iDragon II"}, +// {"RiseRiseRise", 5, 9, ?, 0, "Rise mP6 iDragon II"}, +// Rise Tiger = MMX+SSE Unknown Nmae + + +#endif /* 0 */ + +typedef struct __CPU___PROCINFORMATION__ +{ + bool pCertified; + char *pName; + + uint32_t vFamily; + uint32_t vModel; + uint32_t vStepping; + uint32_t vType; + uint32_t vBrand; + char vVendor[13]; + char *vName; + + bool iFloatingPoint; + bool iTranscedental; + bool iCompareExchange64; + bool iConditionalMove; + bool iCLFLUSH; + bool iMMX; + bool iSSE; + bool iSSE2; + bool iSSE3; + bool iMonitor; + bool iFastSystemCall; + bool iFXSR; + bool fVirtualModeExtensions; + bool fDebuggingExtensions; + bool fPageSizeExtensions; + bool fTimeStampCounter; + bool fModelSpecificRegisters; + bool fPhysicalAddressExtension; + bool fMachineCheckException; + bool fLocalAPIC; + bool fMemoryTypeRangeRegisters; + bool fPageGlobalEnable; + bool fMachineCheckArchitecture; + bool fPageAttributeTable; + bool fPageSizeExtension; + bool fProcessorSerialNumber; + bool fDebugStore; + bool fACPI; + bool fSelfSnoop; + bool fHyperThreading; + bool fThermalMonitor; + bool fIA64; + bool fSignalBreakOnFERR; + bool fQualifiedDebugStore; + bool fThermalMonitor2; + bool fContextID; + + uint32_t cLineSize; + uint32_t cL1CodeCacheSize; + uint32_t cL1CodeCacheAssociativity; + uint32_t cL1CodeCacheLineSize; + uint32_t cL1CodeCacheLinesPerTag; + uint32_t cL1DataCacheSize; + uint32_t cL1DataCacheAssociativity; + uint32_t cL1DataCacheLineSize; + uint32_t cL1DataCacheLinesPerTag; + uint32_t cL1UnifiedCacheSize; + uint32_t cL1UnifiedCacheAssociativity; + uint32_t cL1UnifiedCacheLineSize; + uint32_t cL1UnifiedCacheLinesPerTag; + uint32_t cL1CodeTLB4KEntries; + uint32_t cL1CodeTLB2MEntries; + uint32_t cL1DataTLB2MEntries; + uint32_t cL1CodeTLB4MEntries; + uint32_t cL1DataTLB4KEntries; + uint32_t cL1DataTLB4MEntries; + uint32_t cL2UnifiedCacheSize; + uint32_t cL2UnifiedCacheAssociativity; + uint32_t cL2UnifiedCacheLineSize; + uint32_t cL2UnifiedCacheLinesPerTag; + uint32_t cL2CodeTLB4KEntries; + uint32_t cL2CodeTLB2MEntries; + uint32_t cL2CodeTLB4MEntries; + uint32_t cL2DataTLB4KEntries; + uint32_t cL2DataTLB2MEntries; + uint32_t cL2DataTLB4MEntries; + uint32_t cL2UnifiedTLB4KEntries; + uint32_t cL2UnifiedTLB2MEntries; + uint32_t cL2UnifiedTLB4MEntries; + uint32_t cL3UnifiedCacheSize; + uint32_t cL3UnifiedCacheAssociativity; + uint32_t cL3UnifiedCacheLineSize; + uint32_t cL3UnifiedCacheLinesPerTag; + + int32_t cL1CodeTLB4KAssociativity; + int32_t cL1CodeTLB2MAssociativity; + int32_t cL1CodeTLB4MAssociativity; + int32_t cL1DataTLB4KAssociativity; + int32_t cL1DataTLB2MAssocitivity; + int32_t cL1DataTLB4MAssociativity; + int32_t cL2CodeTLB4KAssociativity; + int32_t cL2CodeTLB2MAssociativity; + int32_t cL2CodeTLB4MAssociativity; + int32_t cL2DataTLB4KAssociativity; + int32_t cL2DataTLB2MAssociativity; + int32_t cL2DataTLB4MAssociativity; + int32_t cL2UnifiedTLB4KAssociativity; + int32_t cL2UnifiedTLB2MAssociativity; + int32_t cL2UnifiedTLB4MAssociativity; + + bool cTraceCachePresent; + + uint32_t cTraceCacheMicroOps; + uint32_t cTraceCacheAssociativity; + uint32_t uOnChipFPU; + uint32_t uLogicalProcessorCount; + uint32_t uAPICID; + + bool rFeature10; + bool rFeature20; + bool rFeature33; + bool rFeature34; + bool rFeature37; + bool rFeature38; + bool rFeature39; + bool rFeature41; + bool rFeature42; + bool rFeature43; + bool rFeature44; + bool rFeature45; + bool rFeature46; + bool rFeature47; + bool rFeature48; + bool rFeature49; + bool rFeature50; + bool rFeature51; + bool rFeature52; + bool rFeature53; + bool rFeature54; + bool rFeature55; + bool rFeature56; + bool rFeature57; + bool rFeature58; + bool rFeature59; + bool rFeature60; + bool rFeature61; + bool rFeature62; + bool rFeature63; + +} prcInformation; + +void prcInit(void); +void prcIdentify(uint64_t processor, prcInformation* information); +void prcCPUID(uint64_t processor, uint32_t function, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d); +void IdentifyIntelCache(prcInformation* information, int descriptor); +void IdentifyProcessor(prcInformation* information, int Extra); + +typedef union __CPU___PROCINFORMATIONDATA__ +{ + unsigned int d; + unsigned short w[2]; + unsigned char b[4]; +} prcIdentificationData; + +void printf(const char *fmt, ...); + +void init_cpu(void) +{ + prcInformation information; + prcIdentify(0, &information); + //logStatus(logSuccess); + //logSubItem("Processor #0", information.pName); + //logSubItem("MMX", information.iMMX ? "Yes" : "No"); + printf("Proccessor: %s MMX %s", information.pName, information.iMMX ? "Yes" : "No"); +} + +void prcIdentify(uint64_t processor, prcInformation* information) +{ + uint32_t a, b, c, d; + uint32_t highestStandard, highestExtended; + int i, n, Extra; + + /*** 0x00000000 - Vendor **********************/ + prcCPUID(processor, 0x00000000, &a, &b, &c, &d); + + highestStandard = a; + + *((uint32_t*)(information->vVendor + 0)) = b; + *((uint32_t*)(information->vVendor + 4)) = d; + *((uint32_t*)(information->vVendor + 8)) = c; + information->vVendor[12] = '\0'; + + + /*** 0x00000001 - Version and Features ********/ + prcCPUID(processor, 0x00000001, &a, &b, &c, &d); + + information->vStepping = (a & 0x0000000F) >> 0; + information->vModel = (a & 0x000000F0) >> 4; + information->vFamily = (a & 0x00000F00) >> 8; + information->vType = (a & 0x00003000) >> 12; + + if(information->vModel == 0xF) information->vModel += (a & 0x000F0000) >> 16; + if(information->vFamily == 0xF) information->vFamily += (a & 0x0FF00000) >> 20; + + information->uOnChipFPU = (d >> 0) & 0x00000001; + information->fVirtualModeExtensions = (d >> 1) & 0x00000001; + information->fDebuggingExtensions = (d >> 2) & 0x00000001; + information->fPageSizeExtension = (d >> 3) & 0x00000001; + information->fTimeStampCounter = (d >> 4) & 0x00000001; + information->fModelSpecificRegisters = (d >> 5) & 0x00000001; + information->fPhysicalAddressExtension = (d >> 6) & 0x00000001; + information->fMachineCheckException = (d >> 7) & 0x00000001; + information->iCompareExchange64 = (d >> 8) & 0x00000001; + information->fLocalAPIC = (d >> 9) & 0x00000001; + information->rFeature10 = (d >> 10) & 0x00000001; + information->iFastSystemCall = (d >> 11) & 0x00000001; + information->fMemoryTypeRangeRegisters = (d >> 12) & 0x00000001; + information->fPageGlobalEnable = (d >> 13) & 0x00000001; + information->fMachineCheckArchitecture = (d >> 14) & 0x00000001; + information->iConditionalMove = (d >> 15) & 0x00000001; + information->fPageAttributeTable = (d >> 16) & 0x00000001; + information->fPageSizeExtension = (d >> 17) & 0x00000001; + information->fProcessorSerialNumber = (d >> 18) & 0x00000001; + information->iCLFLUSH = (d >> 19) & 0x00000001; + information->rFeature20 = (d >> 20) & 0x00000001; + information->fDebugStore = (d >> 21) & 0x00000001; + information->fACPI = (d >> 22) & 0x00000001; + information->iMMX = (d >> 23) & 0x00000001; + information->iFXSR = (d >> 24) & 0x00000001; + information->iSSE = (d >> 25) & 0x00000001; + information->iSSE2 = (d >> 26) & 0x00000001; + information->fSelfSnoop = (d >> 27) & 0x00000001; + information->fHyperThreading = (d >> 28) & 0x00000001; + information->fThermalMonitor = (d >> 29) & 0x00000001; + information->fIA64 = (d >> 30) & 0x00000001; + information->fSignalBreakOnFERR = (d >> 31) & 0x00000001; + + information->iSSE3 = (c >> 0) & 0x00000001; + information->rFeature33 = (c >> 1) & 0x00000001; + information->rFeature34 = (c >> 2) & 0x00000001; + information->iMonitor = (c >> 3) & 0x00000001; + information->fQualifiedDebugStore = (c >> 4) & 0x00000001; + information->rFeature37 = (c >> 5) & 0x00000001; + information->rFeature38 = (c >> 6) & 0x00000001; + information->rFeature39 = (c >> 7) & 0x00000001; + information->fThermalMonitor2 = (c >> 8) & 0x00000001; + information->rFeature41 = (c >> 9) & 0x00000001; + information->fContextID = (c >> 10) & 0x00000001; + information->rFeature43 = (c >> 11) & 0x00000001; + information->rFeature44 = (c >> 12) & 0x00000001; + information->rFeature45 = (c >> 13) & 0x00000001; + information->rFeature46 = (c >> 14) & 0x00000001; + information->rFeature47 = (c >> 15) & 0x00000001; + information->rFeature48 = (c >> 16) & 0x00000001; + information->rFeature49 = (c >> 17) & 0x00000001; + information->rFeature50 = (c >> 18) & 0x00000001; + information->rFeature51 = (c >> 19) & 0x00000001; + information->rFeature52 = (c >> 20) & 0x00000001; + information->rFeature53 = (c >> 21) & 0x00000001; + information->rFeature54 = (c >> 22) & 0x00000001; + information->rFeature55 = (c >> 23) & 0x00000001; + information->rFeature56 = (c >> 24) & 0x00000001; + information->rFeature57 = (c >> 25) & 0x00000001; + information->rFeature58 = (c >> 26) & 0x00000001; + information->rFeature59 = (c >> 27) & 0x00000001; + information->rFeature60 = (c >> 28) & 0x00000001; + information->rFeature61 = (c >> 29) & 0x00000001; + information->rFeature62 = (c >> 30) & 0x00000001; + information->rFeature63 = (c >> 31) & 0x00000001; + + information->vBrand = (b & 0x000000FF) >> 0; + if(information->iCLFLUSH) + information->cLineSize = (b & 0x0000FF00) >> 8; + if(information->fHyperThreading) + information->uLogicalProcessorCount = (b & 0x00FF0000) >> 16; + if(information->vFamily >= 0xF) + information->uAPICID = (b & 0xFF000000) >> 24; + + /*** 0x00000002 - Cache Descriptors ***********/ + n = 1; + + for(i = 0; i < n; i++) + { + prcCPUID(processor, 0x00000002, &a, &b, &c, &d); + + n = a & 0x000000FF; + + if(!(a & 0x80000000)) + { + IdentifyIntelCache(information, (a >> 8) & 0x000000FF); + IdentifyIntelCache(information, (a >> 16) & 0x000000FF); + IdentifyIntelCache(information, (a >> 24) & 0x000000FF); + } + + if(!(b & 0x80000000)) + { + IdentifyIntelCache(information, (b >> 0) & 0x000000FF); + IdentifyIntelCache(information, (b >> 8) & 0x000000FF); + IdentifyIntelCache(information, (b >> 16) & 0x000000FF); + IdentifyIntelCache(information, (b >> 24) & 0x000000FF); + } + + if(!(c & 0x80000000)) + { + IdentifyIntelCache(information, (c >> 0) & 0x000000FF); + IdentifyIntelCache(information, (c >> 8) & 0x000000FF); + IdentifyIntelCache(information, (c >> 16) & 0x000000FF); + IdentifyIntelCache(information, (c >> 24) & 0x000000FF); + } + + if(!(d & 0x80000000)) + { + IdentifyIntelCache(information, (d >> 0) & 0x000000FF); + IdentifyIntelCache(information, (d >> 8) & 0x000000FF); + IdentifyIntelCache(information, (d >> 16) & 0x000000FF); + IdentifyIntelCache(information, (d >> 24) & 0x000000FF); + } + } + + /*** 0x00000003 - Serial Number ***************/ + + /*** 0x00000004 - Cache Parameters ************/ + + /*** 0x00000005 - Monitor *********************/ + + /** + * THE EXTRA NUMBER + * Type + * Pentium II + III Cache + * Pentium III + 4 Brand ID + * Athlon Multi Processing / Cache + */ + + Extra = information->vType; + + if(!strcmp(information->vVendor, "GenuineIntel") + && information->vFamily == 6 + && information->vModel >= 3 + && information->vModel <= 7) + { + Extra = information->cL2UnifiedCacheSize; + } + + if(!strcmp(information->vVendor, "GenuineIntel") + && information->vFamily == 6 + && information->vModel >= 8) + { + Extra = information->vBrand; + } + + if(!strcmp(information->vVendor, "GenuineIntel") + && information->vFamily == 0xF) + { + Extra = information->vBrand; + } + + if(!strcmp(information->vVendor, "AuthenticAMD") + && information->vFamily == 6) + { + Extra = 0; + } + + IdentifyProcessor(information, Extra); +} + +void prcCPUID(uint64_t processor, uint32_t function, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) +{ + asm + ( + "cpuid" + : "=a" (*a), "=b" (*b), "=c" (*c), "=d" (*d) + : "a" (function) + ); +} + +void IdentifyIntelCache(prcInformation* information, int descriptor) +{ + switch(descriptor) + { + case 0x00: + return; + case 0x40: + return; + case 0x01: + information->cL1CodeTLB4KEntries = 32; + information->cL1CodeTLB4KAssociativity = 4; + return; + case 0x02: + information->cL1CodeTLB4MEntries = 2; + information->cL1CodeTLB4MAssociativity = -1; + return; + case 0x03: + information->cL1DataTLB4KEntries = 64; + information->cL1DataTLB4KAssociativity = 4; + return; + case 0x04: + information->cL1DataTLB4MEntries = 8; + information->cL1DataTLB4MAssociativity = 4; + return; + case 0x06: + information->cL1CodeCacheSize = 8; + information->cL1CodeCacheAssociativity = 4; + information->cL1CodeCacheLineSize = 32; + information->cL1CodeCacheLinesPerTag = -1; + return; + case 0x08: + information->cL1CodeCacheSize = 16; + information->cL1CodeCacheAssociativity = 4; + information->cL1CodeCacheLineSize = 32; + information->cL1CodeCacheLinesPerTag = -1; + return; + case 0x0A: + information->cL1DataCacheSize = 8; + information->cL1DataCacheAssociativity = 2; + information->cL1DataCacheLineSize = 32; + information->cL1DataCacheLinesPerTag = -1; + return; + case 0x0C: + information->cL1DataCacheSize = 16; + information->cL1DataCacheAssociativity = 4; + information->cL1DataCacheLineSize = 32; + information->cL1DataCacheLinesPerTag = -1; + return; + case 0x22: + information->cL3UnifiedCacheSize = 512; + information->cL3UnifiedCacheAssociativity = 4; + information->cL3UnifiedCacheLineSize = 64; + information->cL3UnifiedCacheLinesPerTag = -1; + return; + case 0x23: + information->cL3UnifiedCacheSize = 1024; + information->cL3UnifiedCacheAssociativity = 8; + information->cL3UnifiedCacheLineSize = 64; + information->cL3UnifiedCacheLinesPerTag = -1; + return; + case 0x25: + information->cL3UnifiedCacheSize = 2048; + information->cL3UnifiedCacheAssociativity = 8; + information->cL3UnifiedCacheLineSize = 64; + information->cL3UnifiedCacheLinesPerTag = -1; + return; + case 0x29: + information->cL3UnifiedCacheSize = 4096; + information->cL3UnifiedCacheAssociativity = 8; + information->cL3UnifiedCacheLineSize = 64; + information->cL3UnifiedCacheLinesPerTag = -1; + return; + case 0x39: + information->cL2UnifiedCacheSize = 128; + information->cL2UnifiedCacheAssociativity = 4; + information->cL2UnifiedCacheLineSize = 64; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x3B: + information->cL2UnifiedCacheSize = 128; + information->cL2UnifiedCacheAssociativity = 2; + information->cL2UnifiedCacheLineSize = 64; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x3C: + information->cL2UnifiedCacheSize = 256; + information->cL2UnifiedCacheAssociativity = 4; + information->cL2UnifiedCacheLineSize = 64; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x41: + information->cL2UnifiedCacheSize = 128; + information->cL2UnifiedCacheAssociativity = 4; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x42: + information->cL2UnifiedCacheSize = 256; + information->cL2UnifiedCacheAssociativity = 4; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x43: + information->cL2UnifiedCacheSize = 512; + information->cL2UnifiedCacheAssociativity = 4; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x44: + information->cL2UnifiedCacheSize = 1024; + information->cL2UnifiedCacheAssociativity = 4; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x45: + information->cL2UnifiedCacheSize = 2048; + information->cL2UnifiedCacheAssociativity = 4; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x50: + information->cL1CodeTLB4KEntries = 64; + information->cL1CodeTLB4KAssociativity = -1; + information->cL1CodeTLB2MEntries = 64; + information->cL1CodeTLB2MAssociativity = -1; + information->cL1CodeTLB4MEntries = 64; + information->cL1CodeTLB4MAssociativity = -1; + return; + case 0x51: + information->cL1CodeTLB4KEntries = 128; + information->cL1CodeTLB4KAssociativity = -1; + information->cL1CodeTLB2MEntries = 128; + information->cL1CodeTLB2MAssociativity = -1; + information->cL1CodeTLB4MEntries = 128; + information->cL1CodeTLB4MAssociativity = -1; + return; + case 0x52: + information->cL1CodeTLB4KEntries = 256; + information->cL1CodeTLB4KAssociativity = -1; + information->cL1CodeTLB2MEntries = 256; + information->cL1CodeTLB2MAssociativity = -1; + information->cL1CodeTLB4MEntries = 256; + information->cL1CodeTLB4MAssociativity = -1; + return; + case 0x5B: + information->cL1DataTLB4KEntries = 64; + information->cL1DataTLB4KAssociativity = -1; + information->cL1DataTLB4MEntries = 64; + information->cL1DataTLB4MAssociativity = -1; + return; + case 0x5C: + information->cL1DataTLB4KEntries = 128; + information->cL1DataTLB4KAssociativity = -1; + information->cL1DataTLB4MEntries = 128; + information->cL1DataTLB4MAssociativity = -1; + return; + case 0x5D: + information->cL1DataTLB4KEntries = 256; + information->cL1DataTLB4KAssociativity = -1; + information->cL1DataTLB4MEntries = 256; + information->cL1DataTLB4MAssociativity = -1; + return; + case 0x66: + information->cL1DataCacheSize = 8; + information->cL1DataCacheAssociativity = 4; + information->cL1DataCacheLineSize = 64; + information->cL1DataCacheLinesPerTag = -1; + return; + case 0x67: + information->cL1DataCacheSize = 16; + information->cL1DataCacheAssociativity = 4; + information->cL1DataCacheLineSize = 64; + information->cL1DataCacheLinesPerTag = -1; + return; + case 0x68: + information->cL1DataCacheSize = 32; + information->cL1DataCacheAssociativity = 4; + information->cL1DataCacheLineSize = 64; + information->cL1DataCacheLinesPerTag = -1; + return; + case 0x70: + information->cTraceCacheMicroOps = 12; + information->cTraceCacheAssociativity = 8; + return; + case 0x71: + information->cTraceCacheMicroOps = 16; + information->cTraceCacheAssociativity = 8; + return; + case 0x72: + information->cTraceCacheMicroOps = 32; + information->cTraceCacheAssociativity = 8; + return; + case 0x77: + information->cL1CodeCacheSize = 16; + information->cL1CodeCacheAssociativity = 4; + information->cL1CodeCacheLineSize = 64; + information->cL1CodeCacheLinesPerTag = -1; + return; + case 0x79: + information->cL2UnifiedCacheSize = 128; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 64; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x7A: + information->cL2UnifiedCacheSize = 256; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 64; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x7B: + information->cL2UnifiedCacheSize = 512; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 64; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x7C: + information->cL2UnifiedCacheSize = 1024; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 64; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x7E: + information->cL2UnifiedCacheSize = 256; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 128; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x82: + information->cL2UnifiedCacheSize = 128; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x83: + information->cL2UnifiedCacheSize = 256; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x84: + information->cL2UnifiedCacheSize = 512; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x85: + information->cL2UnifiedCacheSize = 1024; + information->cL2UnifiedCacheAssociativity = 8; + information->cL2UnifiedCacheLineSize = 32; + information->cL2UnifiedCacheLinesPerTag = -1; + return; + case 0x8D: + information->cL3UnifiedCacheSize = 3072; + information->cL3UnifiedCacheAssociativity = 12; + information->cL3UnifiedCacheLineSize = 128; + information->cL3UnifiedCacheLinesPerTag = -1; + return; + } + + /*printf("Unknown Intel Cache Descriptor: %x\n", CacheDescriptor);*/ +} + +int AMDAssociativity(int Value) +{ + switch (Value) + { + case 0x00: return 0; + case 0x01: return 1; + case 0x02: return 2; + case 0x04: return 4; + case 0x06: return 8; + case 0x08: return 16; + case 0x0F: return -1; + } + + /*puts("Unknown AMD Cache Descriptor");*/ + return -1; +} + +void IdentifyProcessor(prcInformation* information, int Extra) +{ + int i; + + for(i = 0; i < (sizeof(ProcessorList) / sizeof(PROCLIST)); i++) + { + if(ProcessorList[i].id == 0x02000000 + (information->vFamily << 16) + (information->vModel << 8) + Extra) + { + information->pName = ProcessorList[i].name; + information->pCertified = ProcessorList[i].verified; + return; + } + } + + for(i = 0; i < (sizeof(ProcessorList) / sizeof(PROCLIST)); i++) + { + if(ProcessorList[i].id == 0x020000FF + (information->vFamily << 16) + (information->vModel << 8)) + { + information->pName = ProcessorList[i].name; + information->pCertified = ProcessorList[i].verified; + return; + } + } + + for(i = 0; i < (sizeof(ProcessorList) / sizeof(PROCLIST)); i++) + { + if(ProcessorList[i].id == 0x0200FFFF + (information->vFamily << 16)) + { + information->pName = ProcessorList[i].name; + information->pCertified = ProcessorList[i].verified; + return; + } + } + + for(i = 0; i < (sizeof(ProcessorList) / sizeof(PROCLIST)); i++) + { + if(ProcessorList[i].id == 0x02FFFFFF) + { + information->pName = ProcessorList[i].name; + information->pCertified = ProcessorList[i].verified; + return; + } + } + + information->pName = "Unknown Processor"; + information->pCertified = false; +} diff --git a/Dump/hybos/src/kernel/debug.c b/Dump/hybos/src/kernel/debug.c new file mode 100644 index 0000000..3e74795 --- /dev/null +++ b/Dump/hybos/src/kernel/debug.c @@ -0,0 +1,54 @@ +/*============================================================================ +DEBUG FUNCTIONS + +EXPORTS: +void dump_regs(regs_t *regs); +============================================================================*/ +#include "_krnl.h" + +/* IMPORTS +from MAIN.C */ +void printf(const char *fmt, ...); +/***************************************************************************** +*****************************************************************************/ +#define BPERL 16 /* byte/line for dump */ + +void dump(unsigned char *data, unsigned count) +{ + unsigned char byte1, byte2; + + while(count != 0) + { + for(byte1 = 0; byte1 < BPERL; byte1++) + { + if(count == 0) + break; + printf("%02X ", data[byte1]); + count--; + } + printf("\t"); + for(byte2 = 0; byte2 < byte1; byte2++) + { + if(data[byte2] < ' ') + printf("%c", '.'); + else + printf("%c", data[byte2]); + } + printf("\n"); + data += BPERL; + } +} +/***************************************************************************** +*****************************************************************************/ +void dump_regs(regs_t *regs) +{ + printf("EDI=%08X ESI=%08X EBP=%08X ESP=%08X\n", + regs->edi, regs->esi, regs->ebp, regs->esp); + printf("EBX=%08X EDX=%08X ECX=%08X EAX=%08X\n", + regs->ebx, regs->edx, regs->ecx, regs->eax); + printf(" DS=%08X ES=%08X FS=%08X GS=%08X\n", + regs->ds, regs->es, regs->fs, regs->gs); + printf("int=%08X err=%08X EIP=%08X CS=%08X\n", + regs->which_int, regs->err_code, regs->eip, regs->cs); + printf("uSP=%08X uSS=%08X\n", regs->user_esp, regs->user_ss); +} diff --git a/Dump/hybos/src/kernel/keyboard.c b/Dump/hybos/src/kernel/keyboard.c new file mode 100644 index 0000000..cd03cdf --- /dev/null +++ b/Dump/hybos/src/kernel/keyboard.c @@ -0,0 +1,585 @@ +/** + * keyboard.c + * + * Main keyboard handling routines. + * + * Exports: + * keyboard_irq(); + * init_keyboard(); + * + * Imports: + * video.c console_t _vc[]; + * video.c select_vc(); + * video.c putch(); + * main.c printf(); + * main.c printk(); + */ + +//#include /* key scancode definitions */ +#include +#include /* outportb, inportb(), etc */ +#include +#include /* shell commands */ +#include "_krnl.h" /* MAX_VC */ +#include "bootlog.h" /* klog() */ + +#define KBD_BUF_SIZE 64 + +/** + * Imports + */ +extern console_t _vc[]; +void select_vc(unsigned which_vc); +void putch(unsigned c); +void printf(const char *fmt, ...); +void printk(int type, const char *fmt, ...); +void dumpheapk(void); +void testheap(void); + +unsigned get_current_vc(); + +static int rawkey, keys[128]; +static int numkeysbuffer; + +static char szInBuf[KBD_BUF_SIZE]; + +/** + * 0 if not set + * 1 if make code + * 2 if break code + */ +static int makebreak; + +/** + * reboot() + * + */ +static void reboot(void) +{ + unsigned temp; + + disable(); + + /** + * flush the keyboard controller + */ + do + { + temp = inportb(0x64); + if((temp & 0x01) != 0) + { + (void)inportb(0x60); + continue; + } + } while((temp & 0x02) != 0); + + /** + * now pulse the cpu reset line + */ + outportb(0x64, 0xFE); + + /** + * if that didn't work, just halt + */ + while(1); +} + +/** + * XXX + * + * I'm not even sure if we need the following functions yet, + * however they are here just in case. Leave them alone. + */ + +/** + * _write_kb() + * + */ +static void _write_kb(unsigned adr, unsigned d) +{ + unsigned long t; + unsigned s; + + for(t = 5000000L; t != 0; t--) + { + s = inportb(0x64); + + /** + * loop until 8042 input buffer is empty + */ + if((s & 0x02) == 0) + break; + } + + if(t != 0) + outportb(adr, d); +} + +/** + * _kb_wait() + * + */ +static inline void _kb_wait(void) +{ + int i; + + for(i = 0; i < 0x1000000; i++) + if((inportb(0x64) & 0x02) == 0) + return; + + printk(0, "Keyboard timeout\n"); +} + +/** + * _kb_send() + * + */ +static inline void _kb_send(unsigned char c) +{ + _kb_wait(); + outportb(c, 0x64); +} + +/** + * _translate_sc() + * + * Translates a scancode from the keyboard + */ +unsigned _translate_sc(unsigned k) +{ + unsigned c; + static unsigned altk; + unsigned donefirst = 0; + + if(k == KEY_BKSPACE) + { + if(numkeysbuffer - 1 < 0) + { + numkeysbuffer = 0; + return 0; + } + } + + switch(k) + { + case 0xE0: + altk = 1; c = 0; donefirst = 1; break; + case KEY_TILDA: /* ` or ~ */ + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 126 : 126; break; + case KEY_END: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 49; break; + case KEY_1: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 33 : 49; break; + case KEY_DOWN: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 50; break; + case KEY_2: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 64 : 50; break; + case KEY_PGDOWN: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 51; break; + case KEY_3: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 35 : 51; break; + case KEY_LEFT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 52; break; + case KEY_4: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 36 : 52; break; + case KEYP_5: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 53; break; + case KEY_5: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 35 : 53; break; + case KEY_RIGHT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 54; break; + case KEY_6: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 94 : 54; break; + case KEY_HOME: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 55; break; + case KEY_7: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 38 : 55; break; + case KEY_UP: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 56; break; + case KEYP_ASTERISK: c = 42; break; + case KEY_8: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 42 : 56; break; + case KEY_PGUP: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 57; break; + case KEY_9: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 40 : 57; break; + case KEY_INSERT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 48; break; + case KEY_0: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 41 : 48; break; + case KEYP_MINUS: c = 45; break; + case KEY_MINUS: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 95 : 45; break; + case KEYP_PLUS: c = 43; break; + case KEY_PLUS: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 61 : 43; break; + case KEY_BKSLASH: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 124 : 92; break; + case KEY_Q: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 81 : 113; break; + case KEY_W: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 87 : 119; break; + case KEY_E: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 69 : 101; break; + case KEY_R: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 82 : 114; break; + case KEY_T: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 84 : 116; break; + case KEY_Y: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 89 : 121; break; + case KEY_U: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 85 : 117; break; + case KEY_I: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 73 : 105; break; + case KEY_O: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 79 : 111; break; + case KEY_P: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 80 : 112; break; + case KEY_LBRACKET: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 123 : 91; break; + case KEY_RBRACKET: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 125 : 93; break; + case KEY_ENTER: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 10 : 10; break; + case KEY_A: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 65 : 97; break; + case KEY_S: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 83 : 115; break; + case KEY_D: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 68 : 100; break; + case KEY_F: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 70 : 102; break; + case KEY_G: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 71 : 103; break; + case KEY_H: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 72 : 104; break; + case KEY_J: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 74 : 106; break; + case KEY_K: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 75 : 107; break; + case KEY_L: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 76 : 108; break; + case KEY_SEMICOLON: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 58 : 59; break; + case KEY_QUOTE: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 34 : 39; break; + case KEY_Z: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 90 : 122; break; + case KEY_X: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 88 : 120; break; + case KEY_C: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 67 : 99; break; + case KEY_V: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 86 : 118; break; + case KEY_B: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 66 : 98; break; + case KEY_N: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 78 : 110; break; + case KEY_M: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 77 : 109; break; + case KEY_COMMA: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 60 : 44; break; + case KEY_DEL: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 46; break; + case KEY_PERIOD: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 62 : 46; break; + case KEY_SLASH: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 63 : 47; break; + case KEY_SPACE: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 32 : 32; break; + case KEY_BKSPACE: c = '\b'; break; /* just for now */ + default: + c = 0; + } + + if(donefirst == 0) + altk = 0; + + if(keys[KEY_CAPS]) + { + if(keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) + { + if(c >= 'A' && c <= 'Z') + c += 32; + } + else + { + if(c >= 'a' && c <= 'z') + c -= 32; + } + } + + /** + * Simple shell for now + */ + if(c != 0 && c != '\n' && c != '\b') + { + if((numkeysbuffer - 1) == KBD_BUF_SIZE) + { + numkeysbuffer = 0; + szInBuf[0] = '\0'; + + szInBuf[numkeysbuffer] = c; + numkeysbuffer++; + } + else + { + szInBuf[numkeysbuffer] = c; + numkeysbuffer++; + } + } + else if(c == '\n') + { + printf("\n"); + /** + * Make it a real string + */ + szInBuf[numkeysbuffer] = '\0'; + + /** + * Process command + */ + processCommand(&szInBuf[0], numkeysbuffer - 1); + + /** + * Clear buffer + */ + numkeysbuffer = 0; + szInBuf[0] = '\0'; + + /** + * Print "line" + */ + printf("$ "); + + c = 0; + } + else if(c == '\b') + { + szInBuf[numkeysbuffer] = '\0'; + numkeysbuffer--; + printf("\b \b"); + + c = 0; + } + + return c; +} + +/** + * handle_meta_key() + * + * I'll pretty this up later + */ +void handle_meta_key(unsigned k) +{ + int i; + k = k; /* to shut gcc up */ + + /** + * Check for the infamous three finger salute + */ + if((keys[KEY_RCTRL] || keys[KEY_LCTRL]) && + (keys[KEY_RALT] || keys[KEY_LALT]) && + keys[KEY_DEL]) + { + /** + * FIXME + * + * This should call _send_signal() + */ + reboot(); + } + + /** + * Check for Alt + F1-F12 for virtual terminals + */ + for(i = 0; i < 10; i++) + { + if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[i + KEY_F1]) + { + select_vc(i); + return; + } + } + + if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[KEY_F11]) + { + select_vc(10); + return; + } + + if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[KEY_F12]) + { + select_vc(11); + return; + } +} + +/** + * keyboard_irq() + * + * Called when a keyboard interrupt is generated. + */ +void keyboard_irq(void) +{ + register char a; + unsigned c; + unsigned short kbdstat; + + rawkey = inportb(0x60); + outportb(0x61, (a=inportb(0x61)|0x82)); + outportb(0x61, a & 0x7F); + + /** + * If it's less than 0x80 then it's definatelly + * a make code or a repeat code + */ + if(rawkey < 0x80) + { + /** + * We don't want to gunk up the numlock key + * because we will define it's state in the + * break code a bit later + */ + if((rawkey != KEYP_NUMLCK) && (rawkey != KEY_SCRLCK) && (rawkey != KEY_CAPS)) + keys[rawkey] = 1; + + keyDown(rawkey); + } + else /* rawkey >= 0x80 */ + { + if(rawkey == 0xE0) + { + /** + * It's either a make code, break code, or repeat code + */ + rawkey = inportb(0x60); + outportb(0x61, (a=inportb(0x61)|0x82)); + outportb(0x61, a & 0x7F); + + if(rawkey < 0x80) + { + /** + * Ok, it's a make code or repeat code for the numeric + * keypad (gray keys) + */ + + keys[rawkey] = 1; + + keyDown(rawkey); + } + else /* rawkey >= 0x80 */ + { + /** + * It's either a make code for the numeric keypad or + * a break code for the numeric keypad. + */ + if(rawkey == 0x2A) + { + /** + * Ok, we have a make code for the numeric keypad + * and NUMLOCK is on. The second byte is what we + * want since what we have so far is this: + * + * 0xE0 0x2A + */ + rawkey = inportb(0x60); + outportb(0x61, (a=inportb(0x61)|0x82)); + outportb(0x61, a & 0x7F); + + rawkey = inportb(0x60); + outportb(0x61, (a=inportb(0x61)|0x82)); + outportb(0x61, a & 0x7F); + + keys[rawkey] = 1; + + keyDown(rawkey); + } + else + { + /** + * It's a break code from the numeric keypad. + */ + keys[rawkey] = 0; + + keyUp(rawkey); + } + } + } + else /* rawkey != 0xE0 */ + { + /** + * It's a break code + * + * Make sure we toggle the numlock, scroll lock, and caps lock key. + */ + if(((rawkey - 0x80) == KEYP_NUMLCK) || + ((rawkey - 0x80) == KEY_SCRLCK) || + ((rawkey - 0x80) == KEY_CAPS)) + { + keys[rawkey - 0x80] = !keys[rawkey - 0x80]; + + kbdstat = 0; + if(keys[KEY_SCRLCK]) + kbdstat |= 1; + if(keys[KEYP_NUMLCK]) + kbdstat |= 2; + if(keys[KEY_CAPS]) + kbdstat |= 4; + + _write_kb(0x60, 0xED); + _write_kb(0x60, kbdstat); + outportb(0x20, 0x20); + + keyUp(rawkey); + return; + } + + keys[rawkey - 0x80] = 0; + + keyUp(rawkey); + } + } + + c = _translate_sc(rawkey); + + if(c != 0) + printf("%c", c); + else + { + /** + * We need to check for meta-key-crap here + */ + handle_meta_key(rawkey); + } + + //enable(); + outportb(0x20, 0x20); +} + +/** + * init_keyboard() + * + */ +void init_keyboard(void) +{ + static unsigned char buffers[KBD_BUF_SIZE * MAX_VC]; + + int i; + + //klog("init", "keyboard %2u buf, %2ub each", K_KLOG_PENDING, &_vc[0]); + for(i = 0; i < MAX_VC; i++) + { + _vc[i].keystrokes.data = buffers + KBD_BUF_SIZE * i; + _vc[i].keystrokes.size = KBD_BUF_SIZE; + } + + for(i = 0; i < 128; i++) + keys[i] = 0; + + makebreak = 0; + //klog(NULL, K_KLOG_SUCCESS, &_vc[0], NULL); + //kprintf("init_kbd: %u buffers, %u bytes each\n", + // MAX_VC, KBD_BUF_SIZE); + + //kprintf("[ Entering Runlevel 0 ].......................................................Ok"); + _vc[0].attrib = 8; + printf("[ "); + _vc[0].attrib = 15; + printf("init: keyboard %2u buf, %2ub each ", MAX_VC, KBD_BUF_SIZE); + _vc[0].attrib = 8; + printf("]..........................................."); + _vc[0].attrib = 2; + printf("Ok"); + _vc[0].attrib = 7; +} diff --git a/Dump/hybos/src/kernel/kstart.asm b/Dump/hybos/src/kernel/kstart.asm new file mode 100644 index 0000000..371e822 --- /dev/null +++ b/Dump/hybos/src/kernel/kstart.asm @@ -0,0 +1,391 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; 32-bit kernel startup code +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +%include "asm.inc" + +SECTION .text +;SEGMENT _TEXT USE32 CLASS=CODE +;BITS 32 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; entry point +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +GLOBAL entry +entry: +; check if data segment linked, located, and loaded properly + mov eax,[ds_magic] + cmp eax,DS_MAGIC + je ds_ok + +; display a blinking white-on-blue 'D' and freeze + mov word [0B8000h],9F44h + jmp short $ +ds_ok: + +; stop using bootloader GDT, and load new GDT + lgdt [gdt_ptr] + + mov ax,LINEAR_DATA_SEL + mov ds,ax + mov es,ax + mov ss,ax + mov fs,ax + mov gs,ax + jmp LINEAR_CODE_SEL:sbat +sbat: + +; zero the C language BSS +; 'bss' and 'end' are defined in the linker script file +EXTERN bss, end + mov edi,bss + mov ecx,end + sub ecx,edi + xor eax,eax + rep stosb + + mov esp,stack + +; set up interrupt handlers, then load IDT register + mov ecx,(idt_end - idt) >> 3 ; number of exception handlers + mov edi,idt + mov esi,isr0 +do_idt: + mov eax,esi ; EAX=offset of entry point + mov [edi],ax ; set low 16 bits of gate offset + shr eax,16 + mov [edi + 6],ax ; set high 16 bits of gate offset + add edi,8 ; 8 bytes/interrupt gate + add esi,(isr1 - isr0) ; bytes/stub + loop do_idt + + lidt [idt_ptr] + +; GRUB 0.90 leaves the NT bit set in EFLAGS. The first IRET we attempt +; will cause a TSS-based task-switch, which will cause Exception 10. +; Let's prevent that: + push dword 2 + popf + +IMP main + call main ; call C code + jmp $ ; freeze + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Multiboot header for GRUB bootloader. This must be in the first 8K +; of the kernel file. We use the aout kludge so it works with ELF, +; DJGPP COFF, Win32 PE, or other formats. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; these are in the linker script file +EXTERN code, bss, end + +ALIGN 4 +mboot: + dd MULTIBOOT_HEADER_MAGIC + dd MULTIBOOT_HEADER_FLAGS + dd MULTIBOOT_CHECKSUM +; aout kludge. These must be PHYSICAL addresses + dd mboot + dd code + dd bss + dd end + dd entry + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt/exception handlers +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +IMP fault + +; I shouldn't have to do this! +%macro PUSHB 1 + db 6Ah + db %1 +%endmacro + +%macro INTR 1 ; (byte offset from start of stub) +isr%1: + push byte 0 ; ( 0) fake error code + PUSHB %1 ; ( 2) exception number + push gs ; ( 4) push segment registers + push fs ; ( 6) + push es ; ( 8) + push ds ; ( 9) + pusha ; (10) push GP registers + mov ax,LINEAR_DATA_SEL ; (11) put known-good values... + mov ds,eax ; (15) ...in segment registers + mov es,eax ; (17) + mov fs,eax ; (19) + mov gs,eax ; (21) + mov eax,esp ; (23) + push eax ; (25) push pointer to regs_t +.1: +; setvect() changes the operand of the CALL instruction at run-time, +; so we need its location = 27 bytes from start of stub. We also want +; the CALL to use absolute addressing instead of EIP-relative, so: + mov eax,fault ; (26) + call eax ; (31) + jmp all_ints ; (33) +%endmacro ; (38) + +%macro INTR_EC 1 +isr%1: + nop ; error code already pushed + nop ; nop+nop=same length as push byte + PUSHB %1 ; ( 2) exception number + push gs ; ( 4) push segment registers + push fs ; ( 6) + push es ; ( 8) + push ds ; ( 9) + pusha ; (10) push GP registers + mov ax,LINEAR_DATA_SEL ; (11) put known-good values... + mov ds,eax ; (15) ...in segment registers + mov es,eax ; (17) + mov fs,eax ; (19) + mov gs,eax ; (21) + mov eax,esp ; (23) + push eax ; (25) push pointer to regs_t +.1: +; setvect() changes the operand of the CALL instruction at run-time, +; so we need its location = 27 bytes from start of stub. We also want +; the CALL to use absolute addressing instead of EIP-relative, so: + mov eax,fault ; (26) + call eax ; (31) + jmp all_ints ; (33) +%endmacro ; (38) + +; the vector within the stub (operand of the CALL instruction) +; is at (isr0.1 - isr0 + 1) + +all_ints: + pop eax + popa ; pop GP registers + pop ds ; pop segment registers + pop es + pop fs + pop gs + add esp,8 ; drop exception number and error code + iret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; name: getvect +; action: reads interrupt vector +; in: [EBP + 12] = vector number +; out: vector stored at address given by [EBP + 8] +; modifies: EAX, EDX +; minimum CPU: '386+ +; notes: C prototype: +; typedef struct +; { unsigned access_byte, eip; } vector_t; +; getvect(vector_t *v, unsigned vect_num); +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +EXP getvect + push ebp + mov ebp,esp + push esi + push ebx + mov esi,[ebp + 8] + +; get access byte from IDT[i] + xor ebx,ebx + mov bl,[ebp + 12] + shl ebx,3 + mov al,[idt + ebx + 5] + mov [esi + 0],eax + +; get handler address from stub + mov eax,isr1 + sub eax,isr0 ; assume stub size < 256 bytes + mul byte [ebp + 12] + mov ebx,eax + add ebx,isr0 + mov eax,[ebx + (isr0.1 - isr0 + 1)] + mov [esi + 4],eax + pop ebx + pop esi + pop ebp + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; name: setvect +; action: writes interrupt vector +; in: [EBP + 12] = vector number, +; vector stored at address given by [EBP + 8] +; out: (nothing) +; modifies: EAX, EDX +; minimum CPU: '386+ +; notes: C prototype: +; typedef struct +; { unsigned access_byte, eip; } vector_t; +; getvect(vector_t *v, unsigned vect_num); +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +EXP setvect + push ebp + mov ebp,esp + push esi + push ebx + mov esi,[ebp + 8] + +; store access byte in IDT[i] + mov eax,[esi + 0] + xor ebx,ebx + mov bl,[ebp + 12] + shl ebx,3 + mov [idt + ebx + 5],al + +; store handler address in stub + mov eax,isr1 + sub eax,isr0 ; assume stub size < 256 bytes + mul byte [ebp + 12] + mov ebx,eax + add ebx,isr0 + mov eax,[esi + 4] + mov [ebx + (isr0.1 - isr0 + 1)],eax + pop ebx + pop esi + pop ebp + ret + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; interrupt/exception stubs +; *** CAUTION: these must be consecutive, and must all be the same size. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + INTR 0 ; zero divide (fault) + INTR 1 ; debug/single step + INTR 2 ; non-maskable interrupt (trap) + INTR 3 ; INT3 (trap) + INTR 4 ; INTO (trap) + INTR 5 ; BOUND (fault) + INTR 6 ; invalid opcode (fault) + INTR 7 ; coprocessor not available (fault) + INTR_EC 8 ; double fault (abort w/ error code) + INTR 9 ; coproc segment overrun (abort; 386/486SX only) + INTR_EC 0Ah ; bad TSS (fault w/ error code) + INTR_EC 0Bh ; segment not present (fault w/ error code) + INTR_EC 0Ch ; stack fault (fault w/ error code) + INTR_EC 0Dh ; GPF (fault w/ error code) + INTR_EC 0Eh ; page fault + INTR 0Fh ; reserved + INTR 10h ; FP exception/coprocessor error (trap) + INTR 11h ; alignment check (trap; 486+ only) + INTR 12h ; machine check (Pentium+ only) + INTR 13h + INTR 14h + INTR 15h + INTR 16h + INTR 17h + INTR 18h + INTR 19h + INTR 1Ah + INTR 1Bh + INTR 1Ch + INTR 1Dh + INTR 1Eh + INTR 1Fh + +; isr20 through isr2F are hardware interrupts. The 8259 programmable +; interrupt controller (PIC) chips must be reprogrammed to make these work. + INTR 20h ; IRQ 0/timer interrupt + INTR 21h ; IRQ 1/keyboard interrupt + INTR 22h + INTR 23h + INTR 24h + INTR 25h + INTR 26h ; IRQ 6/floppy interrupt + INTR 27h + INTR 28h ; IRQ 8/real-time clock interrupt + INTR 29h + INTR 2Ah + INTR 2Bh + INTR 2Ch + INTR 2Dh ; IRQ 13/math coprocessor interrupt + INTR 2Eh ; IRQ 14/primary ATA ("IDE") drive interrupt + INTR 2Fh ; IRQ 15/secondary ATA drive interrupt + +; syscall software interrupt + INTR 30h + +; the other 207 vectors are undefined + +%assign i 31h +%rep (0FFh - 30h) + + INTR i + +%assign i (i + 1) +%endrep + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +SECTION .data +;SEGMENT _DATA USE32 CLASS=DATA + +ds_magic: + dd DS_MAGIC + +gdt: +; NULL descriptor + dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + +; unused descriptor + dw 0 + dw 0 + db 0 + db 0 + db 0 + db 0 + +LINEAR_DATA_SEL equ $-gdt + dw 0FFFFh + dw 0 + db 0 + db 92h ; present, ring 0, data, expand-up, writable + db 0CFh ; page-granular (4 gig limit), 32-bit + db 0 + +LINEAR_CODE_SEL equ $-gdt + dw 0FFFFh + dw 0 + db 0 + db 9Ah ; present,ring 0,code,non-conforming,readable + db 0CFh ; page-granular (4 gig limit), 32-bit + db 0 +gdt_end: + +gdt_ptr: + dw gdt_end - gdt - 1 + dd gdt + +; 256 ring 0 interrupt gates + +idt: +%rep 256 + dw 0 ; offset 15:0 + dw LINEAR_CODE_SEL ; selector + db 0 ; (always 0 for interrupt gates) + db 8Eh ; present,ring 0,'386 interrupt gate + dw 0 ; offset 31:16 +%endrep +idt_end: + +idt_ptr: + dw idt_end - idt - 1 ; IDT limit + dd idt ; linear adr of IDT + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +SECTION .bss +;SEGMENT _BSS USE32 CLASS=BSS + + resd 1024 +stack: diff --git a/Dump/hybos/src/kernel/main.c b/Dump/hybos/src/kernel/main.c new file mode 100644 index 0000000..a92ee9b --- /dev/null +++ b/Dump/hybos/src/kernel/main.c @@ -0,0 +1,728 @@ +/** + * main.c + * + * Main code for HybOS. + * + * I spent a lot of time cleaning this damned thing up, so if you + * are even REMOTELY thinking of modifying it, you better make + * sure you follow the same design pattern as you see now. I am sick + * of cleaning up c-style comments because some dumbass is too fucking + * lazy to use the PROPER c89-style comments. This is C people, not C++. + * + * Exports: + * void printf(const char *fmt, ...); + * int main(void); + * + * Imports: + * kstart.asm getvect(); + * kstart.asm setvect(); + * video.c console_t _vc[]; + * video.c blink(); + * video.c init_video(); + * kbd.c keyboard_irq(); + * kbd.c kbd_hw_init(); + * kbd.c init_keyboard(); + * sched.c schedule(); + * sched.c init_tasks(); + * debug.c dump_regs(); + * + * FIXME: + * needs to be renamed to kernel.c + */ +#include /* va_list, va_start(), va_end() */ +/*#include */ /* NULL */ +#include /* NULL */ +#include /* disable() */ +#include <_printf.h> /* do_printf() */ +#include <_malloc.h> +#include +#include +#include +#include "_krnl.h" /* regs_t */ +#include "bootlog.h" /* klog() */ + +/** + * FIXME + * + * These externs and declares are a fucking mess and + * need to be ported to their own headers for portability + */ + +/** + * Imports + */ +void getvect(vector_t *v, unsigned vect_num); +void setvect(vector_t *v, unsigned vect_num); +extern console_t _vc[]; +void blink(void); +void putch(unsigned c); +void init_video(void); +void keyboard_irq(void); +//void kbd_hw_int(void); +void init_keyboard(void); +void schedule(void); +void init_tasks(void); +void dump_regs(regs_t *regs); + +void _mm_physical_init(void); +unsigned _mm_physical_alloc(void); +void _mm_physical_free(unsigned page); +void _mm_page_copy_byte(uint32_t dest, uint32_t src); +void _mm_page_copy_word(uint32_t dest, uint32_t src); +void _mm_page_copy_dword(uint32_t dest, uint32_t src); + +/*void init_cpu(void);*/ + +/** + * printf/kprintf helper + */ +static int kprintf_help(unsigned c, void **ptr) +{ + /** + * Leave this for now + */ + ptr = ptr; + + putch(c); + return 0; +} + +/** + * Format output and print it to stdout (vtty0) + * Just like on any other operating system + */ +/*void printf(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + (void)do_printf(fmt, args, kprintf_help, NULL); + va_end(args); +}*/ + +void kprintf(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + (void)do_printf(fmt, args, kprintf_help, NULL); + va_end(args); +} + +/** + * Format output and print it to stdout (vtty0) + * Just like on any other operating system + */ +void printk(const char *fmt, ...) +{ + va_list args; + + /** + * TODO + * + * Select vtty0 + */ + va_start(args, fmt); + (void)do_printf(fmt, args, kprintf_help, NULL); + va_end(args); +} + +/** + * Oh yeah, the fun function ;) + */ +void panic(const char *fmt, ...) +{ + va_list args; + + disable(); /* interrupts off */ + va_start(args, fmt); + _vc[0].attrib = 15; + printf("\n\npanic: "); + (void)do_printf(fmt, args, kprintf_help, NULL); + + printf("\n\nSystem halted."); + __asm__ __volatile__ ("hlt"); + + while(1) + /* freeze */; +} + +/** + * Called when a kernel fault is detected. This does not + * (normally) get called when something goes awry in + * user-space, therefore it is designed for kernel-space + */ +void fault(regs_t *regs) +{ + struct exception + { + char *message; + int signal; + int processor; + }; + + static const struct exception ex[] = + { + {"Divide error", SIGFPE, 86}, + {"Debug exception", SIGTRAP, 86}, + {"Nonmaskable interrupt (NMI)", SIGBUS, 86}, + {"Breakpoint (INT3)", SIGEMT, 86}, + {"Overflow (INTO)", SIGFPE, 186}, + {"Bounds check", SIGFPE, 186}, + {"Invalid opcode", SIGILL, 186}, + {"Coprocessor not available", SIGFPE, 186}, + {"Double fault", SIGBUS, 286}, + {"Coprocessor segment overrun", SIGSEGV, 286}, + {"Invalid TSS", SIGSEGV, 286}, + {"Segment not present", SIGSEGV, 286}, + {"Stack exception", SIGSEGV, 286}, + {"General Protection Fault", SIGSEGV, 286}, + {"Page fault", SIGSEGV, 386}, + {NULL, SIGILL, 0}, + {"Coprocessor error", SIGFPE, 386}, + {"Alignment check",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"IRQ0",0,0}, + {"IRQ1",0,0}, + {"IRQ2",0,0}, + {"IRQ3",0,0}, + {"IRQ4",0,0}, + {"IRQ5",0,0}, + {"IRQ6",0,0}, + {"IRQ7",0,0}, + {"IRQ8",0,0}, + {"IRQ9",0,0}, + {"IRQ10",0,0}, + {"IRQ11",0,0}, + {"IRQ12",0,0}, + {"IRQ13",0,0}, + {"IRQ14",0,0}, + {"IRQ15",0,0}, + {"syscall",0,0} + }; + + + switch(regs->which_int) + { + /** + * this handler installed at compile-time + * Keyboard handler is installed at run-time (see below) + */ + case 0x20: /* timer IRQ 0 */ + //blink(); + /** + * reset hardware interrupt at 8259 chip + */ + outportb(0x20, 0x20); + break; + default: + _vc[0].attrib = 15; + printf("\n\npanic: Exception 0x%08X", regs->which_int); + if(regs->which_int <= sizeof(ex) / sizeof(ex[0].message)) + printf(" (%s)", ex[regs->which_int].message); + printf("\n"); + dump_regs(regs); + printf("\n\nSystem halted."); + __asm__ __volatile__ ("hlt"); + break; + } +} + +/** + * ?? + */ +static void init_8259s(void) +{ + static const unsigned irq0_int = 0x20, irq8_int = 0x28; + + /** + * Initialization Control Word #1 (ICW1) + */ + outportb(0x20, 0x11); + outportb(0xA0, 0x11); + + /** + * ICW2: + * route IRQs 0-7 to INTs 20h-27h + */ + outportb(0x21, irq0_int); + + /** + * route IRQs 8-15 to INTs 28h-2Fh + */ + outportb(0xA1, irq8_int); + + /** + * ICW3 + */ + outportb(0x21, 0x04); + outportb(0xA1, 0x02); + + /** + * ICW4 + */ + outportb(0x21, 0x01); + outportb(0xA1, 0x01); + + /** + * enable IRQ0 (timer) and IRQ1 (keyboard) + */ + outportb(0x21, ~0x03); + outportb(0xA1, ~0x00); +} + +/** + * MinGW32 + */ +#ifdef __WIN32__ +#if __GNUC__<3 +#error Do not use MinGW GCC 2.x with NASM +#endif + int __main(void) { return 0; } + void _alloca(void) { } +#endif + +/** + * malloc, realloc, free, etc + */ +static char *g_heap_bot, *g_kbrk, *g_heap_top; +static void dump_heap(void) +{ + unsigned blks_used = 0, blks_free = 0; + size_t bytes_used = 0, bytes_free = 0; + malloc_t *m; + int total; + + kprintf("===============================================\n"); + for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next) + { + printk("block %5p: %6u bytes %s\n", m, + m->size, m->used ? "used" : "free"); + if(m->used) + { + blks_used++; + bytes_used += m->size; + } + else + { + blks_free++; + bytes_free += m->size; + } + } + kprintf("blocks: %6u used, %6u free, %6u total\n", blks_used, + blks_free, blks_used + blks_free); + kprintf(" bytes: %6u used, %6u free, %6u total\n", bytes_used, + bytes_free, bytes_used + bytes_free); + kprintf("g_heap_bot=0x%p, g_kbrk=0x%p, g_heap_top=0x%p\n", + g_heap_bot, g_kbrk, g_heap_top); + total = (bytes_used + bytes_free) + + (blks_used + blks_free) * sizeof(malloc_t); + if(total != g_kbrk - g_heap_bot) + kprintf("*** some heap memory is not accounted for\n"); + kprintf("===============================================\n"); +} + +void dumpheapk(void) +{ + dump_heap(); +} + +/** + * POSIX sbrk() looks like this + * void *sbrk(int incr); + * + * Mine is a bit different so I can signal the calling function + * if more memory than desired was allocated (e.g. in a system with paging) + * If your kbrk()/sbrk() always allocates the amount of memory you ask for, + * this code can be easily changed. + * + * int brk( void *sbrk( void *kbrk( + * function void *adr); int delta); int *delta); + * ---------------------- ------------ ------------ ------------- + * POSIX? yes yes NO + * return value if error -1 -1 NULL + * get break value . sbrk(0) int x=0; kbrk(&x); + * set break value to X brk(X) sbrk(X - sbrk(0)) int x=X, y=0; kbrk(&x) - kbrk(&y); + * enlarge heap by N bytes . sbrk(+N) int x=N; kbrk(&x); + * shrink heap by N bytes . sbrk(-N) int x=-N; kbrk(&x); + * can you tell if you're + * given more memory + * than you wanted? no no yes + */ +static void *kbrk(int *delta) +{ + static char heap[HEAP_SIZE]; + char *new_brk, *old_brk; + + /** + * heap doesn't exist yet + */ + if(g_heap_bot == NULL) + { + g_heap_bot = g_kbrk = heap; + g_heap_top = g_heap_bot + HEAP_SIZE; + } + new_brk = g_kbrk + (*delta); + + /** + * too low: return NULL + */ + if(new_brk < g_heap_bot) + return NULL; + + /** + * too high: return NULL + */ + if(new_brk >= g_heap_top) + return NULL; + + /** + * success: adjust brk value... + */ + old_brk = g_kbrk; + g_kbrk = new_brk; + + /** + * ...return actual delta... (for this sbrk(), they are the same) + * (*delta) = (*delta); + * ...return old brk value + */ + return old_brk; +} + +/** + * malloc() and free() use g_heap_bot, but not g_kbrk nor g_heap_top + */ +void *kmalloc(size_t size) +{ + unsigned total_size; + malloc_t *m, *n; + int delta; + + if(size == 0) + return NULL; + total_size = size + sizeof(malloc_t); + + /** + * search heap for free block (FIRST FIT) + */ + m = (malloc_t *)g_heap_bot; + + /** + * g_heap_bot == 0 == NULL if heap does not yet exist + */ + if(m != NULL) + { + if(m->magic != MALLOC_MAGIC) + { + /*printf("*** kernel heap is corrupt in kmalloc()\n");*/ + panic("kernel heap is corrupt in malloc()"); + return NULL; + } + for(; m->next != NULL; m = m->next) + { + if(m->used) + continue; + + /** + * size == m->size is a perfect fit + */ + if(size == m->size) + m->used = 1; + else + { + /** + * otherwise, we need an extra sizeof(malloc_t) bytes for the header + * of a second, free block + */ + if(total_size > m->size) + continue; + + /** + * create a new, smaller free block after this one + */ + n = (malloc_t *)((char *)m + total_size); + n->size = m->size - total_size; + n->next = m->next; + n->magic = MALLOC_MAGIC; + n->used = 0; + + /** + * reduce the size of this block and mark it used + */ + m->size = size; + m->next = n; + m->used = 1; + } + return (char *)m + sizeof(malloc_t); + } + } + + /** + * use kbrk() to enlarge (or create!) heap + */ + delta = total_size; + n = kbrk(&delta); + + /** + * uh-oh + */ + if(n == NULL) + return NULL; + + if(m != NULL) + m->next = n; + + n->size = size; + n->magic = MALLOC_MAGIC; + n->used = 1; + + /** + * did kbrk() return the exact amount of memory we wanted? + * cast to make "gcc -Wall -W ..." shut the hell up + */ + if((int)total_size == delta) + n->next = NULL; + else + { + + /** + * it returned more than we wanted (it will never return less): + * create a new, free block + */ + m = (malloc_t *)((char *)n + total_size); + m->size = delta - total_size - sizeof(malloc_t); + m->next = NULL; + m->magic = MALLOC_MAGIC; + m->used = 0; + + n->next = m; + } + return (char *)n + sizeof(malloc_t); +} + +void kfree(void *blk) +{ + malloc_t *m, *n; + + /** + * get address of header + */ + m = (malloc_t *)((char *)blk - sizeof(malloc_t)); + if(m->magic != MALLOC_MAGIC) + { + /*printf("*** attempt to kfree() block at 0x%p with bad magic value\n", blk);*/ + panic("attempt to free() block at 0x%p with bad magic value", blk); + return; + } + + /** + * find this block in the heap + */ + n = (malloc_t *)g_heap_bot; + if(n->magic != MALLOC_MAGIC) + { + /*printf("*** kernel heap is corrupt in kfree()\n");*/ + panic("kernel heap is corrupt in free()"); + return; + } + for(; n != NULL; n = n->next) + { + if(n == m) + break; + } + + /** + * not found? bad pointer or no heap or something else? + */ + if(n == NULL) + { + /*printf("*** attempt to kfree() block at 0x%p that is not in the heap\n", blk);*/ + panic("attempt to free() block at 0x%p that is not in the heap", blk); + return; + } + + /** + * free the block + */ + m->used = 0; + + /** + * coalesce adjacent free blocks + * Hard to spell, hard to do + */ + for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next) + { + while(!m->used && m->next != NULL && !m->next->used) + { + /** + * resize this block + */ + m->size += sizeof(malloc_t) + m->next->size; + + /** + * merge with next block + */ + m->next = m->next->next; + } + } +} + +void testheap(void) +{ + //int i; + //char *t; + //kprintf("before char *t = kmalloc((size_t *)25):\n"); + //dump_heap(); + //t = kmalloc(25); + //strcpy(t, "123456789012345678901234"); + //kprintf("after char *t = kmalloc((size_t *)25):\n"); + //dump_heap(); + //kfree(t); + //kprintf("after kfree(t):\n"); + //dump_heap(); + //kprintf("before char *t = kmalloc((size_t *)25):\n"); + + kprintf("Unable to run testheap -- kmalloc() is broken.\n"); +} + +void *krealloc(void *blk, size_t size) +{ + void *new_blk; + malloc_t *m; + + /** + * size == 0: free block + */ + if(size == 0) + { + if(blk != NULL) + kfree(blk); + new_blk = NULL; + } + else + { + /** + * allocate new block + */ + new_blk = kmalloc(size); + + /** + * if allocation OK, and if old block exists, copy old block to new + */ + if(new_blk != NULL && blk != NULL) + { + m = (malloc_t *)((char *)blk - sizeof(malloc_t)); + if(m->magic != MALLOC_MAGIC) + { + /*printf("*** attempt to krealloc() block at 0x%p with bad magic value\n", blk);*/ + panic("attempt to realloc() block at 0x%p with bad magic value", blk); + return NULL; + } + + /** + * copy minimum of old and new block sizes + */ + if(size > m->size) + size = m->size; + memcpy(new_blk, blk, size); + + /** + * free the old block + */ + kfree(blk); + } + } + return new_blk; +} + +void keyboardISR(void); + +int main(void) +{ + /** + * keyboard interrupt init + */ + vector_t v; + unsigned i; + + init_video(); + init_keyboard(); + init_8259s(); + + /** + * XXX: + * i know this is a very ugly way of doing this, + * however it is the only way it can be done for now. + * in the future, i will implement a kprintf function + * whose sole purpose will be writing boot messages. + * + * Also, the color codes need to be mapped to constants + * in order to make using them a hell of a lot easier. + */ + + klog("init", "Installing keyboard interrupt handler", K_KLOG_PENDING, &_vc[0]); + /* we don't save the old vector */ + v.eip = (unsigned)keyboard_irq; + v.access_byte = 0x8E; /* present, ring 0, '386 interrupt gate */ + setvect(&v, 0x21); + klog(NULL, NULL, K_KLOG_SUCCESS, &_vc[0]); + + /*init_tasks();*/ + + klog("init", "Enabling hardware interrupts", K_KLOG_PENDING, &_vc[0]); + enable(); + /*for(i = 0; i < 0xFFFFFFF; i++);*/ + klog(NULL, NULL, K_KLOG_SUCCESS, &_vc[0]); + + /** + * Initialize memory management + */ + /*_mm_init();*/ + + /** + * finished init, time for some gooey ;) + */ + printf(" _ _ _ _ ____ _____ ___ "); + printf(" ( )_( )( \\/ )( _ \\( _ )/ __) "); + printf(" ) _ ( \\ / ) _ < )(_)( \\__ \\ "); + printf(" (_) (_) (__) (____/(_____)(___/ \n"); + + printf(" Hybrid Operating System (HybOS) \n"); + + /** + * XXX: debug only + */ + printf("ALT + F1 - F8 for virtual terminals\n"); + printf("Three finger salute to restart\n"); + printf("More work needs to be done\n"); + printf("$ "); + + /** + * fork (kfork()) control over to a shell + */ + /*init_shell();*/ + + /** + * idle task/thread + */ + while(1) + { + schedule(); + } + + return 0; +} diff --git a/Dump/hybos/src/kernel/sched.c b/Dump/hybos/src/kernel/sched.c new file mode 100644 index 0000000..ed1b60f --- /dev/null +++ b/Dump/hybos/src/kernel/sched.c @@ -0,0 +1,189 @@ +/** + * schedule.c + * + * Task creation and scheduling + * + * Exports: + * task_t *_current_task; + * schedule(); + * init_tasks(); + * + * Imports: + * main.c printf(); + * video.c console_t _vc[]; + */ + +#include /* setjmp(), longjmp() */ +#include +#include "_krnl.h" /* console_t */ +#include "bootlog.h" /* klog() */ + +/** + * Imports + */ +void printf(const char *fmt, ...); +extern console_t _vc[]; +void task1(void); +void task2(void); +void task3(void); +void task4(void); + +#define MAX_TASK 16 +#define USER_STACK_SIZE 512 + +/** + * jmp_buf (E)IP and (E)SP register names for various environments + */ + +/** + * Tinylib (default) + * These should work for most compilers - The HybOS + * compiler (modified gcc) uses this as the default. + * Your mileage may vary. + */ +#define JMPBUF_IP eip +#define JMPBUF_SP esp +#define JMPBUF_FLAGS eflags + +#if 0 +/** + * TurboC + * + * These should work with all versions of TurboC's + * compiler. + */ +#define JMPBUF_IP j_ip +#define JMPBUF_SP j_sp +#define JMPBUF_FLAGS j_flag + +/** + * DJGPP + * + * These should work with the DJGPP compiler + */ +#define JMPBUF_IP __eip +#define JMPBUF_SP __esp +#define JMPBUF_FLAGS __eflags + +#define JMPBUF_IP __pc +#define JMPBUF_SP __sp +#define JMPBUF_FLAGS ???????? + +/** + * glibc5 + * + * I have no idea what the register name is + * for JMPBUF_FLAGS. Good luck. + */ +#define JMPBUF_IP eip +#define JMPBUF_SP esp +#define JMPBUF_FLAGS eflags +#endif /* 0 */ + +task_t *_curr_task; +static task_t _tasks[MAX_TASK]; + +/** + * schedule() + * + */ +void schedule(void) +{ + static unsigned current; + + /** + * If setjmp() returns non-zero it means that we came here through + * hyperspace from our call to longjmp() below, so just return + */ +/** UBU + if(setjmp(_curr_task->state) != 0) + return; +**/ + + /** + * Try to find the next runnable task + */ + do + { + current++; + if(current >= MAX_TASK) + current = 0; + _curr_task = _tasks + current; + } while(_curr_task->status != TS_RUNNABLE); + + /** + * Jump to the new task + */ + longjmp(_curr_task->state, 1); +} +/***************************************************************************** +*****************************************************************************/ +#define NUM_TASKS 0 + +/** + * init_tasks() + * + */ +void init_tasks(void) +{ + static unsigned char stacks[NUM_TASKS][USER_STACK_SIZE]; + /*static unsigned entry[NUM_TASKS] = + { + 0, (unsigned)task1, + (unsigned)task2, (unsigned)task3, + (unsigned)task4 + };*/ + static unsigned entry[NUM_TASKS]; + + unsigned adr, i; + + klog("init", "task handler", K_KLOG_PENDING, &_vc[0]); + + /** + * For user taskes, initialize the saved state + */ + for(i = 1; i < NUM_TASKS; i++) + { + (void)setjmp(_tasks[i].state); + + /** + * especially the stack pointer + */ + adr = (unsigned)(stacks[i] + USER_STACK_SIZE); + _tasks[i].state[0].JMPBUF_SP = adr; + + /** + * and program counter + */ + _tasks[i].state[0].JMPBUF_IP = entry[i]; + + /** + * enable interrupts (by setting EFLAGS value) + */ + _tasks[i].state[0].JMPBUF_FLAGS = 0x200; + + /** + * allocate a virtual console to this task + */ + _tasks[i].vc = _vc + i; + + /** + * and mark it as runnable + */ + _tasks[i].status = TS_RUNNABLE; + } + + /** + * mark task 0 runnable (idle task) + */ + _tasks[0].status = TS_RUNNABLE; + + /** + * set _curr_task so schedule() will save state + * of task 0 + */ + _curr_task = _tasks + 0; + + klog(NULL, NULL, K_KLOG_SUCCESS, &_vc[0]); +} + diff --git a/Dump/hybos/src/kernel/tasks.c b/Dump/hybos/src/kernel/tasks.c new file mode 100644 index 0000000..624d142 --- /dev/null +++ b/Dump/hybos/src/kernel/tasks.c @@ -0,0 +1,136 @@ +/** + * tasks.c + * + * ?? + * + * Exports: + * task1() + * task2() + * task3() + * task4() + * + * Imports: + * video.c putch_help(); + * sched.c task_t *_curr_task; + */ + +#include "_krnl.h" + +/** + * Imports + */ +void putch_help(console_t *con, unsigned c); +extern task_t *_curr_task; +void schedule(void); + +/** + * write() + * + */ +static int write(const unsigned char *str, unsigned len) +{ + unsigned i; + + for(i = 0; i < len; i++) + { + putch_help(_curr_task->vc, *str); + str++; + } + return i; +} + +/** + * yield() + * + */ +static void yield(void) +{ + schedule(); +} + +#define WAIT 0xFFFFFL + +/** + * wait() + */ +static void wait(void) +{ + unsigned long wait; + + for(wait = WAIT; wait != 0; wait--) + /* nothing */; +} + +/** + * task1() + * + */ +void task1(void) +{ + //static const unsigned char msg_a[] = "root@hybos $ "; +/**/ + + //write(msg_a, sizeof(msg_a)); + wait(); + while(1) + { + /* so we can process other events */ + yield(); + wait(); + } +} + +/** + * task2() + * + */ +void task2(void) +{ + //static const unsigned char msg_a[] = "root@hybos $ "; +/**/ + + //write(msg_a, sizeof(msg_a)); + wait(); + while(1) + { + yield(); + wait(); + } +} + +/** + * task3() + * + */ +void task3(void) +{ + //static const unsigned char msg_a[] = "root@hybos $ "; +/**/ + + //write(msg_a, sizeof(msg_a)); + wait(); + while(1) + { + yield(); + wait(); + } +} + +/** + * task4() + * + */ +void task4(void) +{ + //static const unsigned char msg_a[] = "root@hybos $ "; +/**/ + + //write(msg_a, sizeof(msg_a)); + wait(); + while(1) + { + yield(); + wait(); + } +} + diff --git a/Dump/hybos/src/kernel/video.c b/Dump/hybos/src/kernel/video.c new file mode 100644 index 0000000..1cde91e --- /dev/null +++ b/Dump/hybos/src/kernel/video.c @@ -0,0 +1,445 @@ +/** + * video.c + * + * Text video routines + * + * Exports: + * blink(); + * select_vc() + * putch_help() + * putch() + * init_video(); + * + * Imports: + * main.c printf(); + */ + +/** + * TODO + * + * Fuck me with a blind melon...when the screen scrolls + * too much, it generates a panic of type invalid opcode. + */ + +#include /* memcpy(), memsetw() */ +#include /* isdigit() */ +#include /* outportb(), inportb() */ +#include +#include "_krnl.h" /* MAX_VC, console_t */ + +/** + * Imports + */ +void printf(const char *fmt, ...); + +#define VGA_MISC_READ 0x3CC + +console_t _vc[MAX_VC]; +static unsigned _num_vcs; +static console_t *_curr_vc; + +static unsigned short *_vga_fb_adr; +static unsigned _crtc_io_adr, _vc_width, _vc_height; + +unsigned curr_vtty; + +/** + * blink() + * + */ +void blink(void) +{ + (*(unsigned char *)_vga_fb_adr)++; +} + +/** + * get_current_vc() + * + */ +unsigned get_current_vc() +{ + return curr_vtty; +} + +/** + * scroll() + * + */ +static void scroll(console_t *con) +{ + unsigned short *fb_adr; + unsigned blank, temp; + + blank = 0x20 | ((unsigned)con->attrib << 8); + fb_adr = con->fb_adr; + + /** + * scroll up + */ + if(con->csr_y >= _vc_height) + { + temp = con->csr_y - _vc_height + 1; + memcpy(fb_adr, fb_adr + temp * _vc_width, + (_vc_height - temp) * _vc_width * 2); + + /** + * blank bottom line of screen + */ + memsetw(fb_adr + (_vc_height - temp) * _vc_width, + blank, _vc_width); + con->csr_y = _vc_height - 1; + } + + //for(i = 0; i < 0x1000000; i++) ; +} + +/** + * set_attrib() + * + */ +static void set_attrib(console_t *con, unsigned att) +{ + static const unsigned ansi_to_vga[] = + { + 0, 4, 2, 6, 1, 5, 3, 7 + }; + + unsigned new_att; + + new_att = con->attrib; + if(att == 0) + new_att &= ~0x08; /* bold off */ + else if(att == 1) + new_att |= 0x08; /* bold on */ + else if(att >= 30 && att <= 37) + { + att = ansi_to_vga[att - 30]; + new_att = (new_att & ~0x07) | att;/* fg color */ + } + else if(att >= 40 && att <= 47) + { + att = ansi_to_vga[att - 40] << 4; + new_att = (new_att & ~0x70) | att;/* bg color */ + } + con->attrib = new_att; +} + +/** + * move_csr() + * + */ +static void move_csr(void) +{ + unsigned temp; + + temp = (_curr_vc->csr_y * _vc_width + _curr_vc->csr_x) + + (_curr_vc->fb_adr - _vga_fb_adr); + outportb(_crtc_io_adr + 0, 14); + outportb(_crtc_io_adr + 1, temp >> 8); + outportb(_crtc_io_adr + 0, 15); + outportb(_crtc_io_adr + 1, temp); +} + + +/** + * select_vc() + * + */ +void select_vc(unsigned which_vc) +{ + unsigned i; + + if(which_vc >= _num_vcs) + return; + _curr_vc = _vc + which_vc; + i = _curr_vc->fb_adr - _vga_fb_adr; + outportb(_crtc_io_adr + 0, 12); + outportb(_crtc_io_adr + 1, i >> 8); + outportb(_crtc_io_adr + 0, 13); + outportb(_crtc_io_adr + 1, i); + + curr_vtty = which_vc; + + move_csr(); +} + +/** + * putch_help() + * + */ +void putch_help(console_t *con, unsigned c) +{ + unsigned short *fb_adr; + unsigned att; + + att = (unsigned)con->attrib << 8; + fb_adr = con->fb_adr; + + /** + * state machine to handle escape sequences + * + * ESC + */ + if(con->esc == 1) + { + if(c == '[') + { + con->esc++; + con->esc1 = 0; + return; + } + /* else fall-through: zero esc and print c */ + } + + /** + * ESC[ + */ + else if(con->esc == 2) + { + if(isdigit(c)) + { + con->esc1 = con->esc1 * 10 + c - '0'; + return; + } + else if(c == ';') + { + con->esc++; + con->esc2 = 0; + return; + } + + /** + * ESC[2J (clear screen) + */ + else if(c == 'J') + { + if(con->esc1 == 2) + { + memsetw(fb_adr, ' ' | att, + _vc_height * _vc_width); + con->csr_x = con->csr_y = 0; + } + } + + /** + * ESC[num1m (set attribute num1) + */ + else if(c == 'm') + set_attrib(con, con->esc1); + con->esc = 0; /* anything else with one numeric arg */ + return; + } + + /** + * ESC[num1 + */ + else if(con->esc == 3) + { + if(isdigit(c)) + { + con->esc2 = con->esc2 * 10 + c - '0'; + return; + } + else if(c == ';') + { + con->esc++; /* ESC[num1;num2; */ + con->esc3 = 0; + return; + } + + /** + * ESC[num1;num2H (move cursor to num1,num2) + */ + else if(c == 'H') + { + if(con->esc2 < _vc_width) + con->csr_x = con->esc2; + if(con->esc1 < _vc_height) + con->csr_y = con->esc1; + } + + /** + * ESC[num1;num2m (set attributes num1,num2) + */ + else if(c == 'm') + { + set_attrib(con, con->esc1); + set_attrib(con, con->esc2); + } + con->esc = 0; + return; + } + /** + * ESC[num1;num2;num3 + */ + else if(con->esc == 4) + { + if(isdigit(c)) + { + con->esc3 = con->esc3 * 10 + c - '0'; + return; + } + /** + * ESC[num1;num2;num3m (set attributes num1,num2,num3) + */ + else if(c == 'm') + { + set_attrib(con, con->esc1); + set_attrib(con, con->esc2); + set_attrib(con, con->esc3); + } + con->esc = 0; + return; + } + con->esc = 0; + + /** + * escape character + */ + if(c == 0x1B) + { + con->esc = 1; + return; + } + /** + * backspace + */ + if(c == 0x08) + { + if(con->csr_x != 0) + con->csr_x--; + } + /** + * tab + */ + else if(c == 0x09) + con->csr_x = (con->csr_x + 8) & ~(8 - 1); + /** + * carriage return + */ + else if(c == '\r') /* 0x0D */ + con->csr_x = 0; + /** + * line feed + */ +/* else if(c == '\n') *//* 0x0A */ +/* con->csr_y++;*/ + /** + * CR/LF + */ + else if(c == '\n') /* ### - 0x0A again */ + { + con->csr_x = 0; + con->csr_y++; + } + /** + * printable ASCII + */ + else if(c >= ' ') + { + unsigned short *where; + + where = fb_adr + (con->csr_y * _vc_width + con->csr_x); + *where = (c | att); + con->csr_x++; + } + if(con->csr_x >= _vc_width) + { + con->csr_x = 0; + con->csr_y++; + } + scroll(con); + + /** + * move cursor only if the VC we're writing is the current VC + */ + if(_curr_vc == con) + move_csr(); +} + +/** + * putch() + * + */ +void putch(unsigned c) +{ +/* all kernel messages to VC #0 */ +// putch_help(_vc + 0, c); +/* all kernel messages to current VC */ + putch_help(_curr_vc, c); +} + +/** + * init_video() + * + */ +void init_video(void) +{ + unsigned i; + + /** + * check for monochrome or color VGA emulation + */ + if((inportb(VGA_MISC_READ) & 0x01) != 0) + { + _vga_fb_adr = (unsigned short *)0xB8000L; + _crtc_io_adr = 0x3D4; + } + else + { + _vga_fb_adr = (unsigned short *)0xB0000L; + _crtc_io_adr = 0x3B4; + } + + /** + * read current screen size from BIOS data segment (addresses 400-4FF) + */ + _vc_width = *(unsigned short *)0x44A; + _vc_height = *(unsigned char *)0x484 + 1; + + /** + * figure out how many VCs we can have with 32K of display memory. + * Use INTEGER division to round down. + */ + _num_vcs = 32768L / (_vc_width * _vc_height * 2); + if(_num_vcs > MAX_VC) + _num_vcs = MAX_VC; + + /** + * init VCs, with a different foreground color for each + */ + for(i = 0; i < _num_vcs; i++) + { + _curr_vc = _vc + i; + //_curr_vc->attrib = i + 1; + + /* terminal foreground color */ + _curr_vc->attrib = 7; + _curr_vc->fb_adr = _vga_fb_adr + + _vc_width * _vc_height * i; + + /** + * ESC[2J clears the screen + */ + //kprintf("\x1B[2J this is VC#%u (of 0-%u)\n", + // i, _num_vcs - 1); + printf("\x1B[2J"); + + if(i != 0) + printf("$ "); + } + select_vc(0); + curr_vtty = 0; + + _curr_vc->attrib = 8; + printf("[ "); + _curr_vc->attrib = 15; + printf("init: video %5s emulation, %2ux%2u, framebuffer at 0x%1X ", + (_crtc_io_adr == 0x3D4) ? "color" : "mono", + _vc_width, _vc_height, _vga_fb_adr); + _curr_vc->attrib = 8; + printf("]................"); + _curr_vc->attrib = 2; + printf("Ok"); + _curr_vc->attrib = 7; +} diff --git a/Dump/hybos/src/keymaps/us-std.h b/Dump/hybos/src/keymaps/us-std.h new file mode 100644 index 0000000..f5f2e4a --- /dev/null +++ b/Dump/hybos/src/keymaps/us-std.h @@ -0,0 +1,136 @@ +/* Keymap for US MF-2 keyboard. */ +#include + +uint16_t keymap[NR_SCAN_CODES * MAP_COLS] = { + +/* scan-code !Shift Shift Alt1 Alt2 Alt+Sh Ctrl */ +/* ==================================================================== */ +/* 00 - none */ 0, 0, 0, 0, 0, 0, +/* 01 - ESC */ C('['), C('['), CA('['),CA('['),CA('['),C('['), +/* 02 - '1' */ '1', '!', A('1'), A('1'), A('!'), C('A'), +/* 03 - '2' */ '2', '@', A('2'), A('2'), A('@'), C('@'), +/* 04 - '3' */ '3', '#', A('3'), A('3'), A('#'), C('C'), +/* 05 - '4' */ '4', '$', A('4'), A('4'), A('$'), C('D'), +/* 06 - '5' */ '5', '%', A('5'), A('5'), A('%'), C('E'), +/* 07 - '6' */ '6', '^', A('6'), A('6'), A('^'), C('^'), +/* 08 - '7' */ '7', '&', A('7'), A('7'), A('&'), C('G'), +/* 09 - '8' */ '8', '*', A('8'), A('8'), A('*'), C('H'), +/* 10 - '9' */ '9', '(', A('9'), A('9'), A('('), C('I'), +/* 11 - '0' */ '0', ')', A('0'), A('0'), A(')'), C('@'), +/* 12 - '-' */ '-', '_', A('-'), A('-'), A('_'), C('_'), +/* 13 - '=' */ '=', '+', A('='), A('='), A('+'), C('@'), +/* 14 - BS */ C('H'), C('H'), CA('H'),CA('H'),CA('H'),0177, +/* 15 - TAB */ C('I'), C('I'), CA('I'),CA('I'),CA('I'),C('I'), +/* 16 - 'q' */ L('q'), 'Q', A('q'), A('q'), A('Q'), C('Q'), +/* 17 - 'w' */ L('w'), 'W', A('w'), A('w'), A('W'), C('W'), +/* 18 - 'e' */ L('e'), 'E', A('e'), A('e'), A('E'), C('E'), +/* 19 - 'r' */ L('r'), 'R', A('r'), A('r'), A('R'), C('R'), +/* 20 - 't' */ L('t'), 'T', A('t'), A('t'), A('T'), C('T'), +/* 21 - 'y' */ L('y'), 'Y', A('y'), A('y'), A('Y'), C('Y'), +/* 22 - 'u' */ L('u'), 'U', A('u'), A('u'), A('U'), C('U'), +/* 23 - 'i' */ L('i'), 'I', A('i'), A('i'), A('I'), C('I'), +/* 24 - 'o' */ L('o'), 'O', A('o'), A('o'), A('O'), C('O'), +/* 25 - 'p' */ L('p'), 'P', A('p'), A('p'), A('P'), C('P'), +/* 26 - '[' */ '[', '{', A('['), A('['), A('{'), C('['), +/* 27 - ']' */ ']', '}', A(']'), A(']'), A('}'), C(']'), +/* 28 - CR/LF */ C('M'), C('M'), CA('M'),CA('M'),CA('M'),C('J'), +/* 29 - Ctrl */ CTRL, CTRL, CTRL, CTRL, CTRL, CTRL, +/* 30 - 'a' */ L('a'), 'A', A('a'), A('a'), A('A'), C('A'), +/* 31 - 's' */ L('s'), 'S', A('s'), A('s'), A('S'), C('S'), +/* 32 - 'd' */ L('d'), 'D', A('d'), A('d'), A('D'), C('D'), +/* 33 - 'f' */ L('f'), 'F', A('f'), A('f'), A('F'), C('F'), +/* 34 - 'g' */ L('g'), 'G', A('g'), A('g'), A('G'), C('G'), +/* 35 - 'h' */ L('h'), 'H', A('h'), A('h'), A('H'), C('H'), +/* 36 - 'j' */ L('j'), 'J', A('j'), A('j'), A('J'), C('J'), +/* 37 - 'k' */ L('k'), 'K', A('k'), A('k'), A('K'), C('K'), +/* 38 - 'l' */ L('l'), 'L', A('l'), A('l'), A('L'), C('L'), +/* 39 - ';' */ ';', ':', A(';'), A(';'), A(':'), C('@'), +/* 40 - '\'' */ '\'', '"', A('\''),A('\''),A('"'), C('@'), +/* 41 - '`' */ '`', '~', A('`'), A('`'), A('~'), C('@'), +/* 42 - l. SHIFT*/ SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, +/* 43 - '\\' */ '\\', '|', A('\\'),A('\\'),A('|'), C('\\'), +/* 44 - 'z' */ L('z'), 'Z', A('z'), A('z'), A('Z'), C('Z'), +/* 45 - 'x' */ L('x'), 'X', A('x'), A('x'), A('X'), C('X'), +/* 46 - 'c' */ L('c'), 'C', A('c'), A('c'), A('C'), C('C'), +/* 47 - 'v' */ L('v'), 'V', A('v'), A('v'), A('V'), C('V'), +/* 48 - 'b' */ L('b'), 'B', A('b'), A('b'), A('B'), C('B'), +/* 49 - 'n' */ L('n'), 'N', A('n'), A('n'), A('N'), C('N'), +/* 50 - 'm' */ L('m'), 'M', A('m'), A('m'), A('M'), C('M'), +/* 51 - ',' */ ',', '<', A(','), A(','), A('<'), C('@'), +/* 52 - '.' */ '.', '>', A('.'), A('.'), A('>'), C('@'), +/* 53 - '/' */ '/', '?', A('/'), A('/'), A('?'), C('@'), +/* 54 - r. SHIFT*/ SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, +/* 55 - '*' */ '*', '*', A('*'), A('*'), A('*'), C('@'), +/* 56 - ALT */ ALT, ALT, ALT, ALT, ALT, ALT, +/* 57 - ' ' */ ' ', ' ', A(' '), A(' '), A(' '), C('@'), +/* 58 - CapsLck */ CALOCK, CALOCK, CALOCK, CALOCK, CALOCK, CALOCK, +/* 59 - F1 */ F1, SF1, AF1, AF1, ASF1, CF1, +/* 60 - F2 */ F2, SF2, AF2, AF2, ASF2, CF2, +/* 61 - F3 */ F3, SF3, AF3, AF3, ASF3, CF3, +/* 62 - F4 */ F4, SF4, AF4, AF4, ASF4, CF4, +/* 63 - F5 */ F5, SF5, AF5, AF5, ASF5, CF5, +/* 64 - F6 */ F6, SF6, AF6, AF6, ASF6, CF6, +/* 65 - F7 */ F7, SF7, AF7, AF7, ASF7, CF7, +/* 66 - F8 */ F8, SF8, AF8, AF8, ASF8, CF8, +/* 67 - F9 */ F9, SF9, AF9, AF9, ASF9, CF9, +/* 68 - F10 */ F10, SF10, AF10, AF10, ASF10, CF10, +/* 69 - NumLock */ NLOCK, NLOCK, NLOCK, NLOCK, NLOCK, NLOCK, +/* 70 - ScrLock */ SLOCK, SLOCK, SLOCK, SLOCK, SLOCK, SLOCK, +/* 71 - Home */ HOME, '7', AHOME, AHOME, A('7'), CHOME, +/* 72 - CurUp */ UP, '8', AUP, AUP, A('8'), CUP, +/* 73 - PgUp */ PGUP, '9', APGUP, APGUP, A('9'), CPGUP, +/* 74 - '-' */ NMIN, '-', ANMIN, ANMIN, A('-'), CNMIN, +/* 75 - Left */ LEFT, '4', ALEFT, ALEFT, A('4'), CLEFT, +/* 76 - MID */ MID, '5', AMID, AMID, A('5'), CMID, +/* 77 - Right */ RIGHT, '6', ARIGHT, ARIGHT, A('6'), CRIGHT, +/* 78 - '+' */ PLUS, '+', APLUS, APLUS, A('+'), CPLUS, +/* 79 - End */ END, '1', AEND, AEND, A('1'), CEND, +/* 80 - Down */ DOWN, '2', ADOWN, ADOWN, A('2'), CDOWN, +/* 81 - PgDown */ PGDN, '3', APGDN, APGDN, A('3'), CPGDN, +/* 82 - Insert */ INSRT, '0', AINSRT, AINSRT, A('0'), CINSRT, +/* 83 - Delete */ 0177, '.', A(0177),A(0177),A('.'), 0177, +/* 84 - Enter */ C('M'), C('M'), CA('M'),CA('M'),CA('M'),C('J'), +/* 85 - ??? */ 0, 0, 0, 0, 0, 0, +/* 86 - ??? */ '<', '>', A('<'), A('|'), A('>'), C('@'), +/* 87 - F11 */ F11, SF11, AF11, AF11, ASF11, CF11, +/* 88 - F12 */ F12, SF12, AF12, AF12, ASF12, CF12, +/* 89 - ??? */ 0, 0, 0, 0, 0, 0, +/* 90 - ??? */ 0, 0, 0, 0, 0, 0, +/* 91 - ??? */ 0, 0, 0, 0, 0, 0, +/* 92 - ??? */ 0, 0, 0, 0, 0, 0, +/* 93 - ??? */ 0, 0, 0, 0, 0, 0, +/* 94 - ??? */ 0, 0, 0, 0, 0, 0, +/* 95 - ??? */ 0, 0, 0, 0, 0, 0, +/* 96 - EXT_KEY */ EXTKEY, EXTKEY, EXTKEY, EXTKEY, EXTKEY, EXTKEY, +/* 97 - ??? */ 0, 0, 0, 0, 0, 0, +/* 98 - ??? */ 0, 0, 0, 0, 0, 0, +/* 99 - ??? */ 0, 0, 0, 0, 0, 0, +/*100 - ??? */ 0, 0, 0, 0, 0, 0, +/*101 - ??? */ 0, 0, 0, 0, 0, 0, +/*102 - ??? */ 0, 0, 0, 0, 0, 0, +/*103 - ??? */ 0, 0, 0, 0, 0, 0, +/*104 - ??? */ 0, 0, 0, 0, 0, 0, +/*105 - ??? */ 0, 0, 0, 0, 0, 0, +/*106 - ??? */ 0, 0, 0, 0, 0, 0, +/*107 - ??? */ 0, 0, 0, 0, 0, 0, +/*108 - ??? */ 0, 0, 0, 0, 0, 0, +/*109 - ??? */ 0, 0, 0, 0, 0, 0, +/*110 - ??? */ 0, 0, 0, 0, 0, 0, +/*111 - ??? */ 0, 0, 0, 0, 0, 0, +/*112 - ??? */ 0, 0, 0, 0, 0, 0, +/*113 - ??? */ 0, 0, 0, 0, 0, 0, +/*114 - ??? */ 0, 0, 0, 0, 0, 0, +/*115 - ??? */ 0, 0, 0, 0, 0, 0, +/*116 - ??? */ 0, 0, 0, 0, 0, 0, +/*117 - ??? */ 0, 0, 0, 0, 0, 0, +/*118 - ??? */ 0, 0, 0, 0, 0, 0, +/*119 - ??? */ 0, 0, 0, 0, 0, 0, +/*120 - ??? */ 0, 0, 0, 0, 0, 0, +/*121 - ??? */ 0, 0, 0, 0, 0, 0, +/*122 - ??? */ 0, 0, 0, 0, 0, 0, +/*123 - ??? */ 0, 0, 0, 0, 0, 0, +/*124 - ??? */ 0, 0, 0, 0, 0, 0, +/*125 - ??? */ 0, 0, 0, 0, 0, 0, +/*126 - ??? */ 0, 0, 0, 0, 0, 0, +/*127 - ??? */ 0, 0, 0, 0, 0, 0 +}; diff --git a/Dump/hybos/src/krnl1m.ld b/Dump/hybos/src/krnl1m.ld new file mode 100644 index 0000000..36aa3bb --- /dev/null +++ b/Dump/hybos/src/krnl1m.ld @@ -0,0 +1,55 @@ +/* let the linker use its 'native' format (ELF/COFF/PE) +OUTPUT_FORMAT("coff-go32") */ +/* no leading underscore for symbols handled in asm: */ +ENTRY(entry) +LS_Phys = 0x100000; /* 1 meg = load (physical) address */ +LS_Virt = 0x100000; /* 1 meg = virtual address */ +/*LS_Phys = 0x300000;*/ /* 3 meg = load (physical) address */ +/*LS_Virt = 0x300000;*/ /* 3 meg = virtual address */ + +SECTIONS +{ + .text LS_Virt : AT(LS_Phys) + { + LS_Code = .; +/* symbols to mark start of code segment */ + code = .; _code = .; +/* kernel code */ + *(.text) +/* .rodata is the ELF constant data section */ + *(.rodata*) + . = ALIGN(4096); + } + .data : AT(LS_Phys + (LS_Data - LS_Code)) + { + LS_Data = .; +/* symbols to mark start of data segment */ + data = .; _data = .; +/* kernel data */ +/* OLD: . = ALIGN(4096) */ + *(.data) + . = ALIGN(4096); + } + .bss : AT(LS_Phys + (LS_Bss - LS_Code)) + { + LS_Bss = .; +/* symbols to mark start of BSS segment */ + bss = .; _bss = .; +/* kernel BSS */ + *(.bss) + *(COMMON) /* "common" variables */ + . = ALIGN(4096); + } +/* bug in MinGW? I get a bad executable file unless these +sections are here... */ + .stab : + { + *(.stab) + } + .stabstr : + { + *(.stabstr) + } +/* symbols to mark end of kernel */ + end = .; _end = .; +} diff --git a/Dump/hybos/src/mm/Makefile b/Dump/hybos/src/mm/Makefile new file mode 100644 index 0000000..d0329f1 --- /dev/null +++ b/Dump/hybos/src/mm/Makefile @@ -0,0 +1,34 @@ +.SUFFIXES: .asm + +# defines +MAKEFILE =Makefile +MAKEDEP =$(MAKEFILE) +INCDIR =../../include +LDSCRIPT =../../krnl1m.ld +NASM =nasm -f win32 -dUNDERBARS=1 -i$(INCDIR)/ +CC =gcc -g -Wall -W -O2 -nostdinc -fno-builtin -I$(INCDIR) +LD =ld -g -T $(LDSCRIPT) -nostdlib +LIBC =../../lib/libc.a + +OBJS =memory.o + +OBJS_DEP =*.o + +OBJ_DIR =objects + +# targets +all: $(OBJS) $(MAKEDEP) + +clean: + del ..\$(OBJ_DIR)\memory.o + +# implicit rules +.asm.o: + $(NASM) -o../$(OBJ_DIR)/$@ $< + +.c.o: + $(CC) -c -o../$(OBJ_DIR)/$@ $< + +# dependencies +memory.o: memory.c $(MAKEDEP) + diff --git a/Dump/hybos/src/mm/memory.c b/Dump/hybos/src/mm/memory.c new file mode 100644 index 0000000..d533fd7 --- /dev/null +++ b/Dump/hybos/src/mm/memory.c @@ -0,0 +1,118 @@ +#include +#include "../kernel/bootlog.h" + +extern console_t _vc[]; + +unsigned *buffer; +unsigned *bufferIterator; + +#define PAGESIZE 4096 + +char ts[4096*3]; +char td[4096*3]; + +void _mm_physical_init(void); +unsigned _mm_physical_alloc(void); +void _mm_physical_free(unsigned page); +void _mm_page_copy_byte(uint32_t dest, uint32_t src); +void _mm_page_copy_word(uint32_t dest, uint32_t src); +void _mm_page_copy_dword(uint32_t dest, uint32_t src); +void _mm_virtual_init(void); + +void _mm_init(void) +{ + klog("init", "Initializing memory management", K_KLOG_PENDING, &_vc[0]); + _mm_physical_init(); + _mm_virtual_init(); + klog((void *)0, (void *)0, K_KLOG_SUCCESS, &_vc[0]); +} + +void _mm_physical_init(void) +{ + unsigned i; + unsigned size = 16 * 1024 * 1024; + + size /= PAGESIZE; + size++; + size /= 32; + + buffer = (unsigned *)0x40000; + bufferIterator = (unsigned *)0x40000; + + for(i = 0; i < 72; i++) + buffer[i] = 0xFFFFFFFF; + + for(i = 72; i < size; i++) + buffer[i] = 0x00000000; +} + +unsigned _mm_physical_alloc(void) +{ + unsigned mask = 0x00000001; + unsigned bit = 0; + + /** + * Search for a free space + */ + while(*bufferIterator == 0xFFFFFFFF) + bufferIterator++; + + /** + * Search for a bit that indicates a free page + */ + while(*bufferIterator & mask) + { + mask <<= 1; + bit++; + } + + *bufferIterator |= mask; + + return 32 * (bufferIterator - buffer) + bit; +} + +void _mm_physical_free(unsigned page) +{ + buffer[page >> 5] &= ~(1 << (page & 0x1F)); /* confused yet?!? */ +} + +void _mm_virtual_init(void) +{ +} + +void _mm_page_copy_byte(uint32_t dest, uint32_t src) +{ + __asm__ __volatile__ + ( + "cld;" + "rep; movsb;" + : + : "c" (1024*1024), "D" (dest), "S" (src) + : "memory" + ); +} + +void _mm_page_copy_word(uint32_t dest, uint32_t src) +{ + __asm__ __volatile__ + ( + "cld;" + "rep; movsw;" + : + : "c" (512*1024), "D" (dest), "S" (src) + : "memory" + ); +} + +void _mm_page_copy_dword(uint32_t dest, uint32_t src) +{ + __asm__ __volatile__ + ( + "cld;" + "rep; movsl;" + : + : "c" (256*1024), "D" (dest), "S" (src) + : "memory" + ); +} + diff --git a/Dump/hybos/src/objects/kernel.dis b/Dump/hybos/src/objects/kernel.dis new file mode 100644 index 0000000..2ad6eb5 --- /dev/null +++ b/Dump/hybos/src/objects/kernel.dis @@ -0,0 +1,12860 @@ + +../../boot/kernel.bin: file format elf32-i386-freebsd + +Disassembly of section .text: + +00100000 : +#include "_krnl.h" +#include "bootlog.h" + +void klog(char *proc, char *entry, KLOGRESULT result, console_t *vtty0) +{ + 100000: 55 push %ebp + 100001: 89 e5 mov %esp,%ebp + 100003: 57 push %edi + 100004: 56 push %esi + 100005: 53 push %ebx + 100006: 83 ec 0c sub $0xc,%esp + 100009: 8b 45 10 mov 0x10(%ebp),%eax + 10000c: 8b 5d 14 mov 0x14(%ebp),%ebx + unsigned oldattrib; + int i = 0; + 10000f: 31 f6 xor %esi,%esi + int offset = 69; /* -4 for the "[ ]" part, -2 for the ": " part, -1 for space at end, and -4 for the status */ + char status[4]; + va_list args; + + args = args; + status[0] = '\0'; + + /** + * Save our old color attributes + */ + oldattrib = vtty0->attrib; + + if(result == K_KLOG_SUCCESS) + 100011: 85 c0 test %eax,%eax + 100013: c7 45 f0 45 00 00 00 movl $0x45,0xfffffff0(%ebp) + 10001a: 8b 7b 18 mov 0x18(%ebx),%edi + 10001d: 0f 84 d5 00 00 00 je 1000f8 + { + /** + * Successfull initialization of something. + * Write "..Ok" then leave + */ + vtty0->attrib = 8; + printf("\b\b\b\b.."); + vtty0->attrib = 2; + printf("Ok\n"); + vtty0->attrib = oldattrib; + + return; + } + else if(result == K_KLOG_FAILURE) + 100023: 83 f8 02 cmp $0x2,%eax + 100026: 0f 84 b8 00 00 00 je 1000e4 + { + /** + * Unsuccessfull initialization of something. + * Write "Fail" then leave + */ + vtty0->attrib = 4; + printf("\b\b\b\bFail\n"); + vtty0->attrib = oldattrib; + + return; + } + + /** + * FIXME + * + * Should "wrap" the line instead + */ + if(strlen(entry) + 8 > 80) + 10002c: 83 ec 0c sub $0xc,%esp + 10002f: ff 75 0c pushl 0xc(%ebp) + 100032: e8 21 51 00 00 call 105158 + 100037: 83 c0 08 add $0x8,%eax + 10003a: 83 c4 10 add $0x10,%esp + 10003d: 83 f8 50 cmp $0x50,%eax + 100040: 76 0a jbe 10004c + return; + + vtty0->attrib = 8; + printf("[ "); + vtty0->attrib = 15; + printf("%s: %s", proc, entry); + vtty0->attrib = 8; + printf(" ]"); + + offset -= strlen(proc); + offset -= strlen(entry); + + for(i = 0; i < offset; i++) + printf("."); + + vtty0->attrib = 8; + printf("Wait"); + + vtty0->attrib = oldattrib; +} + 100042: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 100045: 5b pop %ebx + 100046: 5e pop %esi + 100047: 5f pop %edi + 100048: c9 leave + 100049: c3 ret + 10004a: 89 f6 mov %esi,%esi + 10004c: 83 ec 0c sub $0xc,%esp + 10004f: c7 43 18 08 00 00 00 movl $0x8,0x18(%ebx) + 100056: 68 b6 51 10 00 push $0x1051b6 + 10005b: e8 74 50 00 00 call 1050d4 + 100060: 83 c4 0c add $0xc,%esp + 100063: c7 43 18 0f 00 00 00 movl $0xf,0x18(%ebx) + 10006a: ff 75 0c pushl 0xc(%ebp) + 10006d: ff 75 08 pushl 0x8(%ebp) + 100070: 68 b9 51 10 00 push $0x1051b9 + 100075: e8 5a 50 00 00 call 1050d4 + 10007a: c7 43 18 08 00 00 00 movl $0x8,0x18(%ebx) + 100081: c7 04 24 c0 51 10 00 movl $0x1051c0,(%esp,1) + 100088: e8 47 50 00 00 call 1050d4 + 10008d: 5a pop %edx + 10008e: ff 75 08 pushl 0x8(%ebp) + 100091: e8 c2 50 00 00 call 105158 + 100096: 29 45 f0 sub %eax,0xfffffff0(%ebp) + 100099: 58 pop %eax + 10009a: ff 75 0c pushl 0xc(%ebp) + 10009d: e8 b6 50 00 00 call 105158 + 1000a2: 29 45 f0 sub %eax,0xfffffff0(%ebp) + 1000a5: 83 c4 10 add $0x10,%esp + 1000a8: 3b 75 f0 cmp 0xfffffff0(%ebp),%esi + 1000ab: 7d 16 jge 1000c3 + 1000ad: 8b 75 f0 mov 0xfffffff0(%ebp),%esi + 1000b0: 83 ec 0c sub $0xc,%esp + 1000b3: 68 1a 63 10 00 push $0x10631a + 1000b8: e8 17 50 00 00 call 1050d4 + 1000bd: 83 c4 10 add $0x10,%esp + 1000c0: 4e dec %esi + 1000c1: 75 ed jne 1000b0 + 1000c3: 83 ec 0c sub $0xc,%esp + 1000c6: c7 43 18 08 00 00 00 movl $0x8,0x18(%ebx) + 1000cd: 68 c3 51 10 00 push $0x1051c3 + 1000d2: 89 f6 mov %esi,%esi + 1000d4: e8 fb 4f 00 00 call 1050d4 + 1000d9: 89 7b 18 mov %edi,0x18(%ebx) + 1000dc: e9 61 ff ff ff jmp 100042 + 1000e1: 8d 76 00 lea 0x0(%esi),%esi + 1000e4: 83 ec 0c sub $0xc,%esp + 1000e7: c7 43 18 04 00 00 00 movl $0x4,0x18(%ebx) + 1000ee: 68 c8 51 10 00 push $0x1051c8 + 1000f3: eb df jmp 1000d4 + 1000f5: 8d 76 00 lea 0x0(%esi),%esi + 1000f8: 83 ec 0c sub $0xc,%esp + 1000fb: c7 43 18 08 00 00 00 movl $0x8,0x18(%ebx) + 100102: 68 d2 51 10 00 push $0x1051d2 + 100107: e8 c8 4f 00 00 call 1050d4 + 10010c: c7 43 18 02 00 00 00 movl $0x2,0x18(%ebx) + 100113: c7 04 24 d9 51 10 00 movl $0x1051d9,(%esp,1) + 10011a: eb b8 jmp 1000d4 + +0010011c : +*****************************************************************************/ +#define BPERL 16 /* byte/line for dump */ + +void dump(unsigned char *data, unsigned count) +{ + 10011c: 55 push %ebp + 10011d: 89 e5 mov %esp,%ebp + 10011f: 57 push %edi + 100120: 56 push %esi + 100121: 53 push %ebx + 100122: 83 ec 0c sub $0xc,%esp + 100125: 8b 75 0c mov 0xc(%ebp),%esi + unsigned char byte1, byte2; + + while(count != 0) + 100128: 85 f6 test %esi,%esi + 10012a: 0f 84 86 00 00 00 je 1001b6 + { + for(byte1 = 0; byte1 < BPERL; byte1++) + 100130: 31 ff xor %edi,%edi + 100132: 8b 5d 08 mov 0x8(%ebp),%ebx + 100135: 8d 76 00 lea 0x0(%esi),%esi + { + if(count == 0) + 100138: 85 f6 test %esi,%esi + 10013a: 74 1d je 100159 + break; + printf("%02X ", data[byte1]); + 10013c: 83 ec 08 sub $0x8,%esp + 10013f: 0f b6 03 movzbl (%ebx),%eax + 100142: 50 push %eax + 100143: 68 dd 51 10 00 push $0x1051dd + 100148: 47 inc %edi + 100149: e8 86 4f 00 00 call 1050d4 + 10014e: 89 f8 mov %edi,%eax + count--; + 100150: 4e dec %esi + 100151: 83 c4 10 add $0x10,%esp + 100154: 43 inc %ebx + 100155: 3c 0f cmp $0xf,%al + 100157: 76 df jbe 100138 + } + printf("\t"); + 100159: 83 ec 0c sub $0xc,%esp + 10015c: 68 e3 51 10 00 push $0x1051e3 + 100161: e8 6e 4f 00 00 call 1050d4 + for(byte2 = 0; byte2 < byte1; byte2++) + 100166: 31 db xor %ebx,%ebx + 100168: 89 fa mov %edi,%edx + 10016a: 83 c4 10 add $0x10,%esp + 10016d: 38 d3 cmp %dl,%bl + 10016f: 73 29 jae 10019a + 100171: 8d 76 00 lea 0x0(%esi),%esi + { + if(data[byte2] < ' ') + 100174: 0f b6 c3 movzbl %bl,%eax + 100177: 8b 55 08 mov 0x8(%ebp),%edx + 10017a: 8a 04 10 mov (%eax,%edx,1),%al + 10017d: 3c 1f cmp $0x1f,%al + 10017f: 77 3f ja 1001c0 + printf("%c", '.'); + 100181: 83 ec 08 sub $0x8,%esp + 100184: 6a 2e push $0x2e + 100186: 68 e5 51 10 00 push $0x1051e5 + 10018b: e8 44 4f 00 00 call 1050d4 + 100190: 43 inc %ebx + 100191: 89 f8 mov %edi,%eax + else + printf("%c", data[byte2]); + 100193: 83 c4 10 add $0x10,%esp + 100196: 38 c3 cmp %al,%bl + 100198: 72 da jb 100174 + } + printf("\n"); + 10019a: 83 ec 0c sub $0xc,%esp + 10019d: 68 f8 5a 10 00 push $0x105af8 + 1001a2: e8 2d 4f 00 00 call 1050d4 + data += BPERL; + 1001a7: 83 45 08 10 addl $0x10,0x8(%ebp) + 1001ab: 83 c4 10 add $0x10,%esp + 1001ae: 85 f6 test %esi,%esi + 1001b0: 0f 85 7a ff ff ff jne 100130 + } +} + 1001b6: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 1001b9: 5b pop %ebx + 1001ba: 5e pop %esi + 1001bb: 5f pop %edi + 1001bc: c9 leave + 1001bd: c3 ret + 1001be: 89 f6 mov %esi,%esi + 1001c0: 83 ec 08 sub $0x8,%esp + 1001c3: 0f b6 c0 movzbl %al,%eax + 1001c6: 50 push %eax + 1001c7: eb bd jmp 100186 + 1001c9: 8d 76 00 lea 0x0(%esi),%esi + +001001cc : +/***************************************************************************** +*****************************************************************************/ +void dump_regs(regs_t *regs) +{ + 1001cc: 55 push %ebp + 1001cd: 89 e5 mov %esp,%ebp + 1001cf: 53 push %ebx + 1001d0: 83 ec 10 sub $0x10,%esp + 1001d3: 8b 5d 08 mov 0x8(%ebp),%ebx + printf("EDI=%08X ESI=%08X EBP=%08X ESP=%08X\n", + 1001d6: ff 73 0c pushl 0xc(%ebx) + 1001d9: ff 73 08 pushl 0x8(%ebx) + 1001dc: ff 73 04 pushl 0x4(%ebx) + 1001df: ff 33 pushl (%ebx) + 1001e1: 68 00 52 10 00 push $0x105200 + 1001e6: e8 e9 4e 00 00 call 1050d4 + regs->edi, regs->esi, regs->ebp, regs->esp); + printf("EBX=%08X EDX=%08X ECX=%08X EAX=%08X\n", + 1001eb: 83 c4 14 add $0x14,%esp + 1001ee: ff 73 1c pushl 0x1c(%ebx) + 1001f1: ff 73 18 pushl 0x18(%ebx) + 1001f4: ff 73 14 pushl 0x14(%ebx) + 1001f7: ff 73 10 pushl 0x10(%ebx) + 1001fa: 68 40 52 10 00 push $0x105240 + 1001ff: e8 d0 4e 00 00 call 1050d4 + regs->ebx, regs->edx, regs->ecx, regs->eax); + printf(" DS=%08X ES=%08X FS=%08X GS=%08X\n", + 100204: 83 c4 14 add $0x14,%esp + 100207: ff 73 2c pushl 0x2c(%ebx) + 10020a: ff 73 28 pushl 0x28(%ebx) + 10020d: ff 73 24 pushl 0x24(%ebx) + 100210: ff 73 20 pushl 0x20(%ebx) + 100213: 68 80 52 10 00 push $0x105280 + 100218: e8 b7 4e 00 00 call 1050d4 + regs->ds, regs->es, regs->fs, regs->gs); + printf("int=%08X err=%08X EIP=%08X CS=%08X\n", + 10021d: 83 c4 14 add $0x14,%esp + 100220: ff 73 3c pushl 0x3c(%ebx) + 100223: ff 73 38 pushl 0x38(%ebx) + 100226: ff 73 34 pushl 0x34(%ebx) + 100229: ff 73 30 pushl 0x30(%ebx) + 10022c: 68 c0 52 10 00 push $0x1052c0 + 100231: e8 9e 4e 00 00 call 1050d4 + regs->which_int, regs->err_code, regs->eip, regs->cs); + printf("uSP=%08X uSS=%08X\n", regs->user_esp, regs->user_ss); + 100236: 83 c4 1c add $0x1c,%esp + 100239: ff 73 48 pushl 0x48(%ebx) + 10023c: ff 73 44 pushl 0x44(%ebx) + 10023f: 68 e8 51 10 00 push $0x1051e8 + 100244: e8 8b 4e 00 00 call 1050d4 +} + 100249: 8b 5d fc mov 0xfffffffc(%ebp),%ebx + 10024c: c9 leave + 10024d: c3 ret + ... + +00100250 : + * + * @return void + */ +void keyDown(unsigned key) +{ + 100250: 55 push %ebp + 100251: 89 e5 mov %esp,%ebp + key = key; /* to shut gcc up */ +} + 100253: c9 leave + 100254: c3 ret + 100255: 8d 76 00 lea 0x0(%esi),%esi + +00100258 : + +/** + * keyUp() + * + * This function is called when a key is released. + * + * @param unsigned Which key was released. See keyboard.h + * + * @return void + */ +void keyUp(unsigned key) +{ + 100258: 55 push %ebp + 100259: 89 e5 mov %esp,%ebp + key = key; /* to shut gcc up */ +} + 10025b: c9 leave + 10025c: c3 ret + 10025d: 8d 76 00 lea 0x0(%esi),%esi + +00100260 : + +void initCommands(void) +{ + 100260: 55 push %ebp + 100261: 89 e5 mov %esp,%ebp + 100263: 83 ec 10 sub $0x10,%esp + eshCommands[0].minparams = 0; + eshCommands[0].maxparams = 0; + strcpy(eshCommands[0].command, "dumpheap\0"); + 100266: 68 00 53 10 00 push $0x105300 + 10026b: 68 48 3a 18 00 push $0x183a48 + 100270: c7 05 40 3a 18 00 00 movl $0x0,0x183a40 + 100277: 00 00 00 + 10027a: c7 05 44 3a 18 00 00 movl $0x0,0x183a44 + 100281: 00 00 00 + 100284: e8 b3 4e 00 00 call 10513c + strcpy(eshCommands[0].params[0], "-h\0"); + 100289: 58 pop %eax + 10028a: 5a pop %edx + 10028b: 68 0a 53 10 00 push $0x10530a + 100290: 68 48 3c 18 00 push $0x183c48 + 100295: e8 a2 4e 00 00 call 10513c + strcpy(eshCommands[0].description, "Print listing of heap usage and status.\0"); + 10029a: 59 pop %ecx + 10029b: 58 pop %eax + 10029c: 68 20 53 10 00 push $0x105320 + 1002a1: 68 48 64 18 00 push $0x186448 + 1002a6: e8 91 4e 00 00 call 10513c + + eshCommands[1].minparams = 1; + eshCommands[1].maxparams = MAX_PARAMS; + strcpy(eshCommands[1].params[0], "-h\0"); + 1002ab: 58 pop %eax + 1002ac: 5a pop %edx + 1002ad: 68 0a 53 10 00 push $0x10530a + 1002b2: 68 50 68 18 00 push $0x186850 + 1002b7: c7 05 48 66 18 00 01 movl $0x1,0x186648 + 1002be: 00 00 00 + 1002c1: c7 05 4c 66 18 00 14 movl $0x14,0x18664c + 1002c8: 00 00 00 + 1002cb: e8 6c 4e 00 00 call 10513c + strcpy(eshCommands[1].command, "echo\0"); + 1002d0: 59 pop %ecx + 1002d1: 58 pop %eax + 1002d2: 68 49 53 10 00 push $0x105349 + 1002d7: 68 50 66 18 00 push $0x186650 + 1002dc: e8 5b 4e 00 00 call 10513c + strcpy(eshCommands[1].description, "Echo a line of text to the terminal.\0"); + 1002e1: 58 pop %eax + 1002e2: 5a pop %edx + 1002e3: 68 60 53 10 00 push $0x105360 + 1002e8: 68 50 90 18 00 push $0x189050 + 1002ed: e8 4a 4e 00 00 call 10513c + + /*this will be called with either "help" or "help command" */ + eshCommands[2].minparams = 0; + eshCommands[2].maxparams = 1; + strcpy(eshCommands[2].params[0], "-h\0"); + 1002f2: 59 pop %ecx + 1002f3: 58 pop %eax + 1002f4: 68 0a 53 10 00 push $0x10530a + 1002f9: 68 58 94 18 00 push $0x189458 + 1002fe: c7 05 50 92 18 00 00 movl $0x0,0x189250 + 100305: 00 00 00 + 100308: c7 05 54 92 18 00 01 movl $0x1,0x189254 + 10030f: 00 00 00 + 100312: e8 25 4e 00 00 call 10513c + strcpy(eshCommands[2].command, "help\0"); + 100317: 58 pop %eax + 100318: 5a pop %edx + 100319: 68 86 53 10 00 push $0x105386 + 10031e: 68 58 92 18 00 push $0x189258 + 100323: e8 14 4e 00 00 call 10513c + strcpy(eshCommands[2].description, "Displays general help menu or help on specific command.\0"); + 100328: 59 pop %ecx + 100329: 58 pop %eax + 10032a: 68 a0 53 10 00 push $0x1053a0 + 10032f: 68 58 bc 18 00 push $0x18bc58 + 100334: e8 03 4e 00 00 call 10513c + + /* -r|-h [time] */ + eshCommands[3].minparams = 1; + eshCommands[3].maxparams = 2; + strcpy(eshCommands[3].command, "shutdown\0"); + 100339: 58 pop %eax + 10033a: 5a pop %edx + 10033b: 68 d9 53 10 00 push $0x1053d9 + 100340: 68 60 be 18 00 push $0x18be60 + 100345: c7 05 58 be 18 00 01 movl $0x1,0x18be58 + 10034c: 00 00 00 + 10034f: c7 05 5c be 18 00 02 movl $0x2,0x18be5c + 100356: 00 00 00 + 100359: e8 de 4d 00 00 call 10513c + strcpy(eshCommands[3].params[0], "-r\0"); + 10035e: 59 pop %ecx + 10035f: 58 pop %eax + 100360: 68 e3 53 10 00 push $0x1053e3 + 100365: 68 60 c0 18 00 push $0x18c060 + 10036a: e8 cd 4d 00 00 call 10513c + strcpy(eshCommands[3].params[1], "-h\0"); + 10036f: 58 pop %eax + 100370: 5a pop %edx + 100371: 68 0a 53 10 00 push $0x10530a + 100376: 68 60 c2 18 00 push $0x18c260 + 10037b: e8 bc 4d 00 00 call 10513c + strcpy(eshCommands[3].params[2], "NOW\0"); + 100380: 59 pop %ecx + 100381: 58 pop %eax + 100382: 68 e7 53 10 00 push $0x1053e7 + 100387: 68 60 c4 18 00 push $0x18c460 + 10038c: e8 ab 4d 00 00 call 10513c + strcpy(eshCommands[3].description, "Halt or restart the system.\0"); + 100391: 58 pop %eax + 100392: 5a pop %edx + 100393: 68 ec 53 10 00 push $0x1053ec + 100398: 68 60 e8 18 00 push $0x18e860 + 10039d: e8 9a 4d 00 00 call 10513c + + /* clear screen */ + eshCommands[4].minparams = 0; + eshCommands[4].maxparams = 0; + strcpy(eshCommands[4].params[0], "-h\0"); + 1003a2: 59 pop %ecx + 1003a3: 58 pop %eax + 1003a4: 68 0a 53 10 00 push $0x10530a + 1003a9: 68 68 ec 18 00 push $0x18ec68 + 1003ae: c7 05 60 ea 18 00 00 movl $0x0,0x18ea60 + 1003b5: 00 00 00 + 1003b8: c7 05 64 ea 18 00 00 movl $0x0,0x18ea64 + 1003bf: 00 00 00 + 1003c2: e8 75 4d 00 00 call 10513c + strcpy(eshCommands[4].command, "cls\0"); + 1003c7: 58 pop %eax + 1003c8: 5a pop %edx + 1003c9: 68 09 54 10 00 push $0x105409 + 1003ce: 68 68 ea 18 00 push $0x18ea68 + 1003d3: e8 64 4d 00 00 call 10513c + strcpy(eshCommands[4].description, "Clears the terminal of all output.\0"); + 1003d8: 59 pop %ecx + 1003d9: 58 pop %eax + 1003da: 68 20 54 10 00 push $0x105420 + 1003df: 68 68 14 19 00 push $0x191468 + 1003e4: e8 53 4d 00 00 call 10513c + + /* print working directory */ + eshCommands[5].minparams = 0; + eshCommands[5].maxparams = 0; + strcpy(eshCommands[5].params[0], "-h\0"); + 1003e9: 58 pop %eax + 1003ea: 5a pop %edx + 1003eb: 68 0a 53 10 00 push $0x10530a + 1003f0: 68 70 18 19 00 push $0x191870 + 1003f5: c7 05 68 16 19 00 00 movl $0x0,0x191668 + 1003fc: 00 00 00 + 1003ff: c7 05 6c 16 19 00 00 movl $0x0,0x19166c + 100406: 00 00 00 + 100409: e8 2e 4d 00 00 call 10513c + strcpy(eshCommands[5].command, "pwd\0"); + 10040e: 59 pop %ecx + 10040f: 58 pop %eax + 100410: 68 44 54 10 00 push $0x105444 + 100415: 68 70 16 19 00 push $0x191670 + 10041a: e8 1d 4d 00 00 call 10513c + strcpy(eshCommands[5].description, "Prints the current working directory.\0"); + 10041f: 58 pop %eax + 100420: 5a pop %edx + 100421: 68 60 54 10 00 push $0x105460 + 100426: 68 70 40 19 00 push $0x194070 + 10042b: e8 0c 4d 00 00 call 10513c +} + 100430: c9 leave + 100431: c3 ret + 100432: 89 f6 mov %esi,%esi + +00100434 : + +/** + * mapCommand() + * + * Used internally by esh to map a command to it's zero-based + * index of commands. + * + * @param char * the entire line of the command + * + * @return int index of command entry if found, otherwise -1 + */ +int mapCommand(char *cmd) +{ + 100434: 55 push %ebp + 100435: 89 e5 mov %esp,%ebp + 100437: 57 push %edi + 100438: 56 push %esi + 100439: 53 push %ebx + 10043a: 81 ec 0c 02 00 00 sub $0x20c,%esp + 100440: 8b 75 08 mov 0x8(%ebp),%esi + int i; /* for our loops */ + int params; /* number of parameters found for the command */ + int previdx; /* previous index */ + char cmdName[MAX_LEN]; /* name of the command */ + + i = 0; + 100443: 31 db xor %ebx,%ebx + 100445: 8d 76 00 lea 0x0(%esi),%esi + previdx = 0; + params = 0; + + /** + * Loop while cmd[i] is not a space + */ + i = 0; + for(i = 0; i < (int)strlen(cmd); i++) + 100448: 83 ec 0c sub $0xc,%esp + 10044b: 56 push %esi + 10044c: e8 07 4d 00 00 call 105158 + 100451: 83 c4 10 add $0x10,%esp + 100454: 39 c3 cmp %eax,%ebx + 100456: 7d 09 jge 100461 + { + if(cmd[i] == ' ') + 100458: 80 3c 33 20 cmpb $0x20,(%ebx,%esi,1) + 10045c: 74 03 je 100461 + 10045e: 43 inc %ebx + 10045f: eb e7 jmp 100448 + break; + } + + strncpy(cmdName, cmd, i); + 100461: 51 push %ecx + 100462: 53 push %ebx + 100463: 56 push %esi + 100464: 8d bd e8 fd ff ff lea 0xfffffde8(%ebp),%edi + 10046a: 57 push %edi + 10046b: e8 04 4d 00 00 call 105174 + cmdName[i] = '\0'; + + for(i = 0; i < COMMAND_COUNT; i++) + 100470: be 48 3a 18 00 mov $0x183a48,%esi + 100475: c6 84 2b e8 fd ff ff movb $0x0,0xfffffde8(%ebx,%ebp,1) + 10047c: 00 + 10047d: 83 c4 10 add $0x10,%esp + 100480: 31 db xor %ebx,%ebx + 100482: 89 f6 mov %esi,%esi + { + if(!strcmp(eshCommands[i].command, cmdName)) + 100484: 83 ec 08 sub $0x8,%esp + 100487: 57 push %edi + 100488: 56 push %esi + 100489: e8 62 4c 00 00 call 1050f0 + 10048e: 83 c4 10 add $0x10,%esp + 100491: 85 c0 test %eax,%eax + 100493: 89 da mov %ebx,%edx + 100495: 74 11 je 1004a8 + 100497: 43 inc %ebx + 100498: 81 c6 08 2c 00 00 add $0x2c08,%esi + 10049e: 83 fb 05 cmp $0x5,%ebx + 1004a1: 7e e1 jle 100484 + return i; + } + + return -1; + 1004a3: ba ff ff ff ff mov $0xffffffff,%edx +} + 1004a8: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 1004ab: 5b pop %ebx + 1004ac: 5e pop %esi + 1004ad: 89 d0 mov %edx,%eax + 1004af: 5f pop %edi + 1004b0: c9 leave + 1004b1: c3 ret + 1004b2: 89 f6 mov %esi,%esi + +001004b4 : + +/** + * isParam() + * + * Determines if the supplied parameter is valid for the + * given command. + * + * @param int index of command + * @param char * command string + * + * @return bool true if parameter is valid, false otherwise + */ +bool isParam(int argc, char *argv) +{ + 1004b4: 55 push %ebp + 1004b5: 89 e5 mov %esp,%ebp + 1004b7: 57 push %edi + 1004b8: 56 push %esi + 1004b9: 53 push %ebx + 1004ba: 83 ec 0c sub $0xc,%esp + 1004bd: 8b 55 08 mov 0x8(%ebp),%edx + int i; + + for(i = 0; i < MAX_PARAMS; i++) + 1004c0: 8d 04 92 lea (%edx,%edx,4),%eax + 1004c3: 8d 04 42 lea (%edx,%eax,2),%eax + 1004c6: c1 e0 07 shl $0x7,%eax + 1004c9: 01 d0 add %edx,%eax + 1004cb: 8b 7d 0c mov 0xc(%ebp),%edi + 1004ce: 31 f6 xor %esi,%esi + 1004d0: 8d 1c c5 48 3c 18 00 lea 0x183c48(,%eax,8),%ebx + 1004d7: 90 nop + { + if(!strcmp(eshCommands[argc].params[i], argv)) + 1004d8: 83 ec 08 sub $0x8,%esp + 1004db: 57 push %edi + 1004dc: 53 push %ebx + 1004dd: e8 0e 4c 00 00 call 1050f0 + 1004e2: 83 c4 10 add $0x10,%esp + 1004e5: 85 c0 test %eax,%eax + 1004e7: ba 01 00 00 00 mov $0x1,%edx + 1004ec: 74 0e je 1004fc + 1004ee: 46 inc %esi + 1004ef: 81 c3 00 02 00 00 add $0x200,%ebx + 1004f5: 83 fe 13 cmp $0x13,%esi + 1004f8: 7e de jle 1004d8 + return true; + } + + return false; + 1004fa: 31 d2 xor %edx,%edx +} + 1004fc: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 1004ff: 5b pop %ebx + 100500: 5e pop %esi + 100501: 89 d0 mov %edx,%eax + 100503: 5f pop %edi + 100504: c9 leave + 100505: c3 ret + 100506: 89 f6 mov %esi,%esi + +00100508 : + +/** + * mapParams() + * + * Maps each parameter to the pars struct + * + * @param char * Buffer from the command line + * @param struct Parameter structure + * + * @return int Number of command line parameters (arguments) parsed + */ +int mapParams(char *buf, ESHCURRCOMMAND *pars) +{ + 100508: 55 push %ebp + 100509: 89 e5 mov %esp,%ebp + 10050b: 57 push %edi + 10050c: 56 push %esi + 10050d: 53 push %ebx + 10050e: 83 ec 18 sub $0x18,%esp + 100511: 8b 7d 08 mov 0x8(%ebp),%edi + int i; /* for our loops */ + int previdx; /* previous index */ + int idx; /* current index */ + int j; /* loops */ + + i = 0; + j = 0; + previdx = 0; + pars->count = 0; + 100514: 8b 45 0c mov 0xc(%ebp),%eax + 100517: c7 00 00 00 00 00 movl $0x0,(%eax) + + previdx = mapCommand(buf); + 10051d: 57 push %edi + 10051e: e8 11 ff ff ff call 100434 + 100523: 89 c2 mov %eax,%edx + 100525: 31 f6 xor %esi,%esi + + if(previdx == -1) + 100527: 83 c4 10 add $0x10,%esp + 10052a: 31 c0 xor %eax,%eax + 10052c: 83 fa ff cmp $0xffffffff,%edx + 10052f: 0f 84 0d 01 00 00 je 100642 + return 0; + + strcpy(pars->param[0], eshCommands[previdx].command); + 100535: 8d 04 92 lea (%edx,%edx,4),%eax + 100538: 8d 04 42 lea (%edx,%eax,2),%eax + 10053b: c1 e0 07 shl $0x7,%eax + 10053e: 01 d0 add %edx,%eax + 100540: 83 ec 08 sub $0x8,%esp + 100543: 8d 04 c5 48 3a 18 00 lea 0x183a48(,%eax,8),%eax + 10054a: 50 push %eax + 10054b: 8b 45 0c mov 0xc(%ebp),%eax + 10054e: 83 c0 04 add $0x4,%eax + 100551: 50 push %eax + 100552: e8 e5 4b 00 00 call 10513c + j++; + pars->count++; + 100557: 8b 55 0c mov 0xc(%ebp),%edx + 10055a: ff 02 incl (%edx) + + i = 0; + idx = 0; + + for(i = 0; i < (int)strlen(buf); i++) + 10055c: 83 c4 10 add $0x10,%esp + 10055f: 81 c2 00 02 00 00 add $0x200,%edx + 100565: c7 45 ec 01 00 00 00 movl $0x1,0xffffffec(%ebp) + 10056c: 89 55 e8 mov %edx,0xffffffe8(%ebp) + 10056f: 90 nop + 100570: 83 ec 0c sub $0xc,%esp + 100573: 57 push %edi + 100574: e8 df 4b 00 00 call 105158 + 100579: 83 c4 10 add $0x10,%esp + 10057c: 39 c6 cmp %eax,%esi + 10057e: 0f 8d b9 00 00 00 jge 10063d + { + /* we have encountered a seperator */ + if(buf[i] == ' ') + 100584: 80 3c 3e 20 cmpb $0x20,(%esi,%edi,1) + 100588: 74 06 je 100590 + 10058a: 46 inc %esi + 10058b: eb e3 jmp 100570 + 10058d: 8d 76 00 lea 0x0(%esi),%esi + { + if(j > MAX_PARAMS) + 100590: 83 7d ec 14 cmpl $0x14,0xffffffec(%ebp) + 100594: 0f 8f a3 00 00 00 jg 10063d + break; + + i++; /* skip one space */ + 10059a: 46 inc %esi + + idx = i; + 10059b: 89 75 f0 mov %esi,0xfffffff0(%ebp) + + if(buf[i] == '"') + 10059e: 8a 04 3e mov (%esi,%edi,1),%al + 1005a1: 3c 22 cmp $0x22,%al + 1005a3: 74 57 je 1005fc + 1005a5: 8d 76 00 lea 0x0(%esi),%esi + 1005a8: 3c 20 cmp $0x20,%al + 1005aa: 74 16 je 1005c2 + 1005ac: 83 ec 0c sub $0xc,%esp + 1005af: 57 push %edi + 1005b0: e8 a3 4b 00 00 call 105158 + 1005b5: 83 c4 10 add $0x10,%esp + 1005b8: 39 c6 cmp %eax,%esi + 1005ba: 74 06 je 1005c2 + { + i++; + idx++; + + while(buf[i] != '"' && i != (int)strlen(buf)) + i++; + + strncpy(pars->param[j], &buf[idx], (i - idx)); + pars->param[j][i - idx] = '\0'; + + idx = i; + j++; + pars->count++; + } + else + { + while(buf[i] != ' ' && i != (int)strlen(buf)) + i++; + 1005bc: 46 inc %esi + 1005bd: 8a 04 3e mov (%esi,%edi,1),%al + 1005c0: eb e6 jmp 1005a8 + + strncpy(pars->param[j], &buf[idx], i - idx); + 1005c2: 53 push %ebx + 1005c3: 89 f3 mov %esi,%ebx + 1005c5: 2b 5d f0 sub 0xfffffff0(%ebp),%ebx + 1005c8: 8b 55 f0 mov 0xfffffff0(%ebp),%edx + 1005cb: 53 push %ebx + 1005cc: 8d 04 3a lea (%edx,%edi,1),%eax + 1005cf: 50 push %eax + 1005d0: 8b 45 e8 mov 0xffffffe8(%ebp),%eax + 1005d3: 83 c0 04 add $0x4,%eax + 1005d6: 50 push %eax + 1005d7: e8 98 4b 00 00 call 105174 + pars->param[j][i - idx] = '\0'; + 1005dc: 8b 45 e8 mov 0xffffffe8(%ebp),%eax + 1005df: c6 44 03 04 00 movb $0x0,0x4(%ebx,%eax,1) + i = idx; + 1005e4: 8b 75 f0 mov 0xfffffff0(%ebp),%esi + j++; + 1005e7: 05 00 02 00 00 add $0x200,%eax + pars->count++; + 1005ec: 8b 55 0c mov 0xc(%ebp),%edx + 1005ef: ff 45 ec incl 0xffffffec(%ebp) + 1005f2: 89 45 e8 mov %eax,0xffffffe8(%ebp) + 1005f5: ff 02 incl (%edx) + 1005f7: 83 c4 10 add $0x10,%esp + 1005fa: eb 8e jmp 10058a + 1005fc: 46 inc %esi + 1005fd: ff 45 f0 incl 0xfffffff0(%ebp) + 100600: 80 3c 3e 22 cmpb $0x22,(%esi,%edi,1) + 100604: 74 13 je 100619 + 100606: 83 ec 0c sub $0xc,%esp + 100609: 57 push %edi + 10060a: e8 49 4b 00 00 call 105158 + 10060f: 83 c4 10 add $0x10,%esp + 100612: 39 c6 cmp %eax,%esi + 100614: 74 03 je 100619 + 100616: 46 inc %esi + 100617: eb e7 jmp 100600 + 100619: 89 f3 mov %esi,%ebx + 10061b: 2b 5d f0 sub 0xfffffff0(%ebp),%ebx + 10061e: 8b 55 f0 mov 0xfffffff0(%ebp),%edx + 100621: 50 push %eax + 100622: 53 push %ebx + 100623: 8d 04 3a lea (%edx,%edi,1),%eax + 100626: 50 push %eax + 100627: 8b 45 e8 mov 0xffffffe8(%ebp),%eax + 10062a: 83 c0 04 add $0x4,%eax + 10062d: 50 push %eax + 10062e: e8 41 4b 00 00 call 105174 + 100633: 8b 45 e8 mov 0xffffffe8(%ebp),%eax + 100636: c6 44 03 04 00 movb $0x0,0x4(%ebx,%eax,1) + 10063b: eb aa jmp 1005e7 + } + } + } + + return pars->count; + 10063d: 8b 55 0c mov 0xc(%ebp),%edx + 100640: 8b 02 mov (%edx),%eax +} + 100642: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 100645: 5b pop %ebx + 100646: 5e pop %esi + 100647: 5f pop %edi + 100648: c9 leave + 100649: c3 ret + 10064a: 89 f6 mov %esi,%esi + +0010064c : + +/** + * processCommand() + * + * This function is called when the user has pressed + * the ENTER key. + * + * @param char * The contents of the current buffer or NULL if empty + * @param int Size of the buffer (number of characters) + * + * @return void + */ +void processCommand(char *line, int count) +{ + 10064c: 55 push %ebp + 10064d: 89 e5 mov %esp,%ebp + 10064f: 57 push %edi + 100650: 56 push %esi + 100651: 53 push %ebx + 100652: 81 ec 1c 50 00 00 sub $0x501c,%esp + 100658: 8b 75 08 mov 0x8(%ebp),%esi + int i; + int cmd; /* stores the numeric index of the command */ + ESHCURRCOMMAND params; + + count = count; /* to shut gcc up */ + + /*for(i = 0; i < MAX_PARAMS; i++) + params.param[i][0] = '\0';*/ + params.param[0][0] = '\0'; + 10065b: c6 85 dc af ff ff 00 movb $0x0,0xffffafdc(%ebp) + + initCommands(); + 100662: e8 f9 fb ff ff call 100260 + + cmd = mapCommand(line); + 100667: 83 ec 0c sub $0xc,%esp + 10066a: 56 push %esi + 10066b: e8 c4 fd ff ff call 100434 + mapParams(line, ¶ms); + 100670: 5f pop %edi + 100671: 89 c3 mov %eax,%ebx + 100673: 8d bd d8 af ff ff lea 0xffffafd8(%ebp),%edi + 100679: 58 pop %eax + 10067a: 57 push %edi + 10067b: 56 push %esi + 10067c: e8 87 fe ff ff call 100508 + + switch(cmd) + 100681: 83 c4 10 add $0x10,%esp + 100684: 83 fb 01 cmp $0x1,%ebx + 100687: 0f 84 13 01 00 00 je 1007a0 + 10068d: 83 fb 01 cmp $0x1,%ebx + 100690: 0f 8e f6 00 00 00 jle 10078c + 100696: 83 fb 02 cmp $0x2,%ebx + 100699: 74 4a je 1006e5 + { + case 0: /* dumpheap */ + dumpheapk(); + //testheap(); + break; + case 1: /* echo */ + for(i = 1; i < params.count; i++) + printf("%s", params.param[i]); + + printf("\n"); + break; + case 2: /* help */ + if(params.count == 1) + { + printf("HybOS EShell Commands:\n"); + for(i = 0; i < COMMAND_COUNT; i++) + if(strlen(eshCommands[i].command) > 0) + printf("%10s %-s\n", eshCommands[i].command, eshCommands[i].description); + } + else + { + cmd = mapCommand(params.param[0]); + mapParams(params.param[1], ¶ms); + + //if(isParam(cmd, params.param[1])) + if(cmd != -1) + { + printf("Usage: %s %s\n", params.param[0], eshCommands[cmd].params[1]); + } + else + printf("esh: '%s' not found.\n", params.param[1]); + } + break; + default: + if(strlen(params.param[0]) > 0 && strcmp(params.param[0], "help")) + 10069b: 83 ec 0c sub $0xc,%esp + 10069e: 8d 9d dc af ff ff lea 0xffffafdc(%ebp),%ebx + 1006a4: 53 push %ebx + 1006a5: e8 ae 4a 00 00 call 105158 + 1006aa: 83 c4 10 add $0x10,%esp + 1006ad: 85 c0 test %eax,%eax + 1006af: 74 15 je 1006c6 + 1006b1: 83 ec 08 sub $0x8,%esp + 1006b4: 68 87 54 10 00 push $0x105487 + 1006b9: 53 push %ebx + 1006ba: e8 31 4a 00 00 call 1050f0 + 1006bf: 83 c4 10 add $0x10,%esp + 1006c2: 85 c0 test %eax,%eax + 1006c4: 75 19 jne 1006df + printf("esh: '%s' not found.\n", params.param[0]); + else + printf("esh: '%s' not found.\n", &line[0]); + 1006c6: 83 ec 08 sub $0x8,%esp + 1006c9: 56 push %esi + 1006ca: 68 8c 54 10 00 push $0x10548c + 1006cf: e8 00 4a 00 00 call 1050d4 + 1006d4: 83 c4 10 add $0x10,%esp + break; + } + + /*for(i = 0; i < params.count; i++) + printf("param[%i]: %s\n", i, params.param[i]);*/ + + //if(isParam(3, ¶ms.param[1])) + // printf("valid parameter\n"); + //else + // printf("invalid parameter\n"); + + return; + + if(!strcmp(line, "dumpheap")) + dumpheapk(); + else if(!strncmp(line, "echo", 4)) + printf("%s\n", line[4] == ' ' ? &line[5] : &line[4]); + else if(!strcmp(line, "help")) + { + printf("HybOS EShell Commands:\n"); + printf("dumpheap\tPrint listing of heap usage and status\n"); + printf("testheap\tTest the heap and print out results\n"); + printf("shutdown -r\tRestart the system.\n"); + printf("pwd\t\tPrint the current working directory.\n"); + } + else if(!strncmp(line, "shutdown", 8)) + { + if(strlen(line) > 9 && !strncmp(&line[9], "-r", 2)) + { + printf("\nSystem shutdown from vtty%u\n", get_current_vc()); + printf("Restarting..."); + //reboot(); + } + else + { + if((strlen(line) > 9) && (strlen(&line[9]) > 0)) + printf("shutdown: Invalid argument \"%s\".\n", &line[9]); + else + printf("Usage: shutdown -r\n"); + } + } + else if((strlen(line) > 0) && (!strcmp(line, "cls"))) + { + printf("\x1B[2J"); + } + else if((strlen(line) >= 8) && (!strcmp(line, "testheap"))) + { + //testheap(); + } + else if((strlen(line) > 0) && (!strcmp(line, "pwd"))) + printf("/\n"); + else if(strlen(line) > 0) + printf("eshell: \"%s\" not found.\n", line); +} + 1006d7: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 1006da: 5b pop %ebx + 1006db: 5e pop %esi + 1006dc: 5f pop %edi + 1006dd: c9 leave + 1006de: c3 ret + 1006df: 83 ec 08 sub $0x8,%esp + 1006e2: 53 push %ebx + 1006e3: eb e5 jmp 1006ca + 1006e5: 83 bd d8 af ff ff 01 cmpl $0x1,0xffffafd8(%ebp) + 1006ec: 74 4a je 100738 + 1006ee: 83 ec 0c sub $0xc,%esp + 1006f1: 8d 85 dc af ff ff lea 0xffffafdc(%ebp),%eax + 1006f7: 50 push %eax + 1006f8: e8 37 fd ff ff call 100434 + 1006fd: 89 c3 mov %eax,%ebx + 1006ff: 58 pop %eax + 100700: 5a pop %edx + 100701: 57 push %edi + 100702: 8d b5 dc b1 ff ff lea 0xffffb1dc(%ebp),%esi + 100708: 56 push %esi + 100709: e8 fa fd ff ff call 100508 + 10070e: 83 c4 10 add $0x10,%esp + 100711: 83 fb ff cmp $0xffffffff,%ebx + 100714: 74 b0 je 1006c6 + 100716: 50 push %eax + 100717: 8d 04 9b lea (%ebx,%ebx,4),%eax + 10071a: 8d 04 43 lea (%ebx,%eax,2),%eax + 10071d: c1 e0 07 shl $0x7,%eax + 100720: 01 d8 add %ebx,%eax + 100722: 8d 04 c5 48 3e 18 00 lea 0x183e48(,%eax,8),%eax + 100729: 50 push %eax + 10072a: 8d 85 dc af ff ff lea 0xffffafdc(%ebp),%eax + 100730: 50 push %eax + 100731: 68 a2 54 10 00 push $0x1054a2 + 100736: eb 97 jmp 1006cf + 100738: 83 ec 0c sub $0xc,%esp + 10073b: 68 b0 54 10 00 push $0x1054b0 + 100740: e8 8f 49 00 00 call 1050d4 + 100745: 31 ff xor %edi,%edi + 100747: 83 c4 10 add $0x10,%esp + 10074a: be 05 00 00 00 mov $0x5,%esi + 10074f: 90 nop + 100750: 83 ec 0c sub $0xc,%esp + 100753: 8d 9f 48 3a 18 00 lea 0x183a48(%edi),%ebx + 100759: 53 push %ebx + 10075a: e8 f9 49 00 00 call 105158 + 10075f: 83 c4 10 add $0x10,%esp + 100762: 85 c0 test %eax,%eax + 100764: 75 0e jne 100774 + 100766: 81 c7 08 2c 00 00 add $0x2c08,%edi + 10076c: 4e dec %esi + 10076d: 79 e1 jns 100750 + 10076f: e9 63 ff ff ff jmp 1006d7 + 100774: 8d 87 48 64 18 00 lea 0x186448(%edi),%eax + 10077a: 51 push %ecx + 10077b: 50 push %eax + 10077c: 53 push %ebx + 10077d: 68 c8 54 10 00 push $0x1054c8 + 100782: e8 4d 49 00 00 call 1050d4 + 100787: 83 c4 10 add $0x10,%esp + 10078a: eb da jmp 100766 + 10078c: 85 db test %ebx,%ebx + 10078e: 0f 85 07 ff ff ff jne 10069b + 100794: e8 83 38 00 00 call 10401c + 100799: e9 39 ff ff ff jmp 1006d7 + 10079e: 89 f6 mov %esi,%esi + 1007a0: 3b 9d d8 af ff ff cmp 0xffffafd8(%ebp),%ebx + 1007a6: be 01 00 00 00 mov $0x1,%esi + 1007ab: 7d 27 jge 1007d4 + 1007ad: 8d 9d dc b1 ff ff lea 0xffffb1dc(%ebp),%ebx + 1007b3: 90 nop + 1007b4: 83 ec 08 sub $0x8,%esp + 1007b7: 53 push %ebx + 1007b8: 68 bd 51 10 00 push $0x1051bd + 1007bd: 46 inc %esi + 1007be: e8 11 49 00 00 call 1050d4 + 1007c3: 81 c3 00 02 00 00 add $0x200,%ebx + 1007c9: 83 c4 10 add $0x10,%esp + 1007cc: 3b b5 d8 af ff ff cmp 0xffffafd8(%ebp),%esi + 1007d2: 7c e0 jl 1007b4 + 1007d4: 83 ec 0c sub $0xc,%esp + 1007d7: 68 f8 5a 10 00 push $0x105af8 + 1007dc: e9 ee fe ff ff jmp 1006cf + 1007e1: 00 00 add %al,(%eax) + ... + +001007e4 : + * reboot() + * + */ +static void reboot(void) +{ + 1007e4: 55 push %ebp + 1007e5: 89 e5 mov %esp,%ebp + 1007e7: 53 push %ebx + 1007e8: 50 push %eax + unsigned temp; + + disable(); + 1007e9: e8 da 44 00 00 call 104cc8 + + /** + * flush the keyboard controller + */ + do + { + temp = inportb(0x64); + 1007ee: 83 ec 0c sub $0xc,%esp + 1007f1: 6a 64 push $0x64 + 1007f3: e8 1c 48 00 00 call 105014 + if((temp & 0x01) != 0) + 1007f8: 83 c4 10 add $0x10,%esp + 1007fb: a8 01 test $0x1,%al + 1007fd: 89 c3 mov %eax,%ebx + 1007ff: 75 19 jne 10081a + { + (void)inportb(0x60); + continue; + } + } while((temp & 0x02) != 0); + 100801: 83 e3 02 and $0x2,%ebx + 100804: 75 e8 jne 1007ee + + /** + * now pulse the cpu reset line + */ + outportb(0x64, 0xFE); + 100806: 83 ec 08 sub $0x8,%esp + 100809: 68 fe 00 00 00 push $0xfe + 10080e: 6a 64 push $0x64 + 100810: e8 9f 48 00 00 call 1050b4 + + /** + * if that didn't work, just halt + */ + while(1); + 100815: 83 c4 10 add $0x10,%esp + 100818: eb fe jmp 100818 + 10081a: 83 ec 0c sub $0xc,%esp + 10081d: 6a 60 push $0x60 + 10081f: e8 f0 47 00 00 call 105014 + 100824: 83 c4 10 add $0x10,%esp + 100827: eb d8 jmp 100801 + 100829: 8d 76 00 lea 0x0(%esi),%esi + +0010082c <_write_kb>: +} + +/** + * XXX + * + * I'm not even sure if we need the following functions yet, + * however they are here just in case. Leave them alone. + */ + +/** + * _write_kb() + * + */ +static void _write_kb(unsigned adr, unsigned d) +{ + 10082c: 55 push %ebp + 10082d: 89 e5 mov %esp,%ebp + 10082f: 57 push %edi + 100830: 56 push %esi + 100831: 53 push %ebx + 100832: 83 ec 0c sub $0xc,%esp + 100835: 8b 7d 08 mov 0x8(%ebp),%edi + 100838: 8b 75 0c mov 0xc(%ebp),%esi + unsigned long t; + unsigned s; + + for(t = 5000000L; t != 0; t--) + 10083b: bb 40 4b 4c 00 mov $0x4c4b40,%ebx + { + s = inportb(0x64); + 100840: 83 ec 0c sub $0xc,%esp + 100843: 6a 64 push $0x64 + 100845: e8 ca 47 00 00 call 105014 + + /** + * loop until 8042 input buffer is empty + */ + if((s & 0x02) == 0) + 10084a: 83 c4 10 add $0x10,%esp + 10084d: a8 02 test $0x2,%al + 10084f: 74 0b je 10085c <_write_kb+0x30> + 100851: 4b dec %ebx + 100852: 75 ec jne 100840 <_write_kb+0x14> + break; + } + + if(t != 0) + outportb(adr, d); +} + 100854: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 100857: 5b pop %ebx + 100858: 5e pop %esi + 100859: 5f pop %edi + 10085a: c9 leave + 10085b: c3 ret + 10085c: 85 db test %ebx,%ebx + 10085e: 74 f4 je 100854 <_write_kb+0x28> + 100860: 89 75 0c mov %esi,0xc(%ebp) + 100863: 89 7d 08 mov %edi,0x8(%ebp) + 100866: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 100869: 5b pop %ebx + 10086a: 5e pop %esi + 10086b: 5f pop %edi + 10086c: c9 leave + 10086d: e9 42 48 00 00 jmp 1050b4 + 100872: 89 f6 mov %esi,%esi + +00100874 <_translate_sc>: + +/** + * _kb_wait() + * + */ +static inline void _kb_wait(void) +{ + int i; + + for(i = 0; i < 0x1000000; i++) + if((inportb(0x64) & 0x02) == 0) + return; + + printk(0, "Keyboard timeout\n"); +} + +/** + * _kb_send() + * + */ +static inline void _kb_send(unsigned char c) +{ + _kb_wait(); + outportb(c, 0x64); +} + +/** + * _translate_sc() + * + * Translates a scancode from the keyboard + */ +unsigned _translate_sc(unsigned k) +{ + 100874: 55 push %ebp + 100875: 89 e5 mov %esp,%ebp + 100877: 83 ec 08 sub $0x8,%esp + 10087a: 8b 45 08 mov 0x8(%ebp),%eax + unsigned c; + static unsigned altk; + unsigned donefirst = 0; + + if(k == KEY_BKSPACE) + 10087d: 83 f8 0e cmp $0xe,%eax + 100880: 0f 84 f2 09 00 00 je 101278 <_translate_sc+0xa04> + { + if(numkeysbuffer - 1 < 0) + { + numkeysbuffer = 0; + return 0; + } + } + + switch(k) + 100886: 3d e0 00 00 00 cmp $0xe0,%eax + 10088b: 0f 87 d3 09 00 00 ja 101264 <_translate_sc+0x9f0> + 100891: ff 24 85 dc 54 10 00 jmp *0x1054dc(,%eax,4) + { + case 0xE0: + altk = 1; c = 0; donefirst = 1; break; + 100898: 31 d2 xor %edx,%edx + 10089a: c7 05 00 80 10 00 01 movl $0x1,0x108000 + 1008a1: 00 00 00 + case KEY_TILDA: /* ` or ~ */ + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 126 : 126; break; + case KEY_END: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 49; break; + case KEY_1: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 33 : 49; break; + case KEY_DOWN: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 50; break; + case KEY_2: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 64 : 50; break; + case KEY_PGDOWN: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 51; break; + case KEY_3: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 35 : 51; break; + case KEY_LEFT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 52; break; + case KEY_4: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 36 : 52; break; + case KEYP_5: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 53; break; + case KEY_5: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 35 : 53; break; + case KEY_RIGHT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 54; break; + case KEY_6: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 94 : 54; break; + case KEY_HOME: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 55; break; + case KEY_7: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 38 : 55; break; + case KEY_UP: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 56; break; + case KEYP_ASTERISK: c = 42; break; + case KEY_8: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 42 : 56; break; + case KEY_PGUP: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 57; break; + case KEY_9: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 40 : 57; break; + case KEY_INSERT: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 48; break; + case KEY_0: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 41 : 48; break; + case KEYP_MINUS: c = 45; break; + case KEY_MINUS: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 95 : 45; break; + case KEYP_PLUS: c = 43; break; + case KEY_PLUS: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 61 : 43; break; + case KEY_BKSLASH: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 124 : 92; break; + case KEY_Q: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 81 : 113; break; + case KEY_W: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 87 : 119; break; + case KEY_E: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 69 : 101; break; + case KEY_R: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 82 : 114; break; + case KEY_T: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 84 : 116; break; + case KEY_Y: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 89 : 121; break; + case KEY_U: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 85 : 117; break; + case KEY_I: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 73 : 105; break; + case KEY_O: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 79 : 111; break; + case KEY_P: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 80 : 112; break; + case KEY_LBRACKET: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 123 : 91; break; + case KEY_RBRACKET: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 125 : 93; break; + case KEY_ENTER: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 10 : 10; break; + case KEY_A: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 65 : 97; break; + case KEY_S: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 83 : 115; break; + case KEY_D: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 68 : 100; break; + case KEY_F: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 70 : 102; break; + case KEY_G: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 71 : 103; break; + case KEY_H: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 72 : 104; break; + case KEY_J: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 74 : 106; break; + case KEY_K: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 75 : 107; break; + case KEY_L: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 76 : 108; break; + case KEY_SEMICOLON: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 58 : 59; break; + case KEY_QUOTE: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 34 : 39; break; + case KEY_Z: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 90 : 122; break; + case KEY_X: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 88 : 120; break; + case KEY_C: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 67 : 99; break; + case KEY_V: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 86 : 118; break; + case KEY_B: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 66 : 98; break; + case KEY_N: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 78 : 110; break; + case KEY_M: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 77 : 109; break; + case KEY_COMMA: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 60 : 44; break; + case KEY_DEL: c = 0; if(keys[KEYP_NUMLCK] && altk == 0) c = 46; break; + case KEY_PERIOD: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 62 : 46; break; + case KEY_SLASH: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 63 : 47; break; + case KEY_SPACE: + c = (keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) ? 32 : 32; break; + case KEY_BKSPACE: c = '\b'; break; /* just for now */ + default: + c = 0; + } + + if(donefirst == 0) + altk = 0; + + if(keys[KEY_CAPS]) + 1008a4: a1 28 84 10 00 mov 0x108428,%eax + 1008a9: 85 c0 test %eax,%eax + 1008ab: 74 23 je 1008d0 <_translate_sc+0x5c> + { + if(keys[KEY_LSHIFT] || keys[KEY_RSHIFT]) + 1008ad: a1 e8 83 10 00 mov 0x1083e8,%eax + 1008b2: 85 c0 test %eax,%eax + 1008b4: 75 0d jne 1008c3 <_translate_sc+0x4f> + 1008b6: a1 18 84 10 00 mov 0x108418,%eax + 1008bb: 85 c0 test %eax,%eax + 1008bd: 0f 84 bd 00 00 00 je 100980 <_translate_sc+0x10c> + { + if(c >= 'A' && c <= 'Z') + 1008c3: 8d 42 bf lea 0xffffffbf(%edx),%eax + 1008c6: 83 f8 19 cmp $0x19,%eax + 1008c9: 77 05 ja 1008d0 <_translate_sc+0x5c> + c += 32; + 1008cb: 83 c2 20 add $0x20,%edx + 1008ce: 89 f6 mov %esi,%esi + } + else + { + if(c >= 'a' && c <= 'z') + c -= 32; + } + } + + /** + * Simple shell for now + */ + if(c != 0 && c != '\n' && c != '\b') + 1008d0: 85 d2 test %edx,%edx + 1008d2: 74 38 je 10090c <_translate_sc+0x98> + 1008d4: 83 fa 0a cmp $0xa,%edx + 1008d7: 74 63 je 10093c <_translate_sc+0xc8> + 1008d9: 83 fa 08 cmp $0x8,%edx + 1008dc: 74 2e je 10090c <_translate_sc+0x98> + { + if((numkeysbuffer - 1) == KBD_BUF_SIZE) + 1008de: a1 40 85 10 00 mov 0x108540,%eax + 1008e3: 83 f8 41 cmp $0x41,%eax + 1008e6: 74 10 je 1008f8 <_translate_sc+0x84> + { + numkeysbuffer = 0; + szInBuf[0] = '\0'; + + szInBuf[numkeysbuffer] = c; + numkeysbuffer++; + } + else + { + szInBuf[numkeysbuffer] = c; + 1008e8: 88 90 60 85 10 00 mov %dl,0x108560(%eax) + numkeysbuffer++; + 1008ee: 40 inc %eax + 1008ef: a3 40 85 10 00 mov %eax,0x108540 + } + } + else if(c == '\n') + { + printf("\n"); + /** + * Make it a real string + */ + szInBuf[numkeysbuffer] = '\0'; + + /** + * Process command + */ + processCommand(&szInBuf[0], numkeysbuffer - 1); + + /** + * Clear buffer + */ + numkeysbuffer = 0; + szInBuf[0] = '\0'; + + /** + * Print "line" + */ + printf("$ "); + + c = 0; + } + else if(c == '\b') + { + szInBuf[numkeysbuffer] = '\0'; + numkeysbuffer--; + printf("\b \b"); + + c = 0; + } + + return c; + 1008f4: 89 d0 mov %edx,%eax +} + 1008f6: c9 leave + 1008f7: c3 ret + 1008f8: 88 15 60 85 10 00 mov %dl,0x108560 + 1008fe: c7 05 40 85 10 00 01 movl $0x1,0x108540 + 100905: 00 00 00 + 100908: eb ea jmp 1008f4 <_translate_sc+0x80> + 10090a: 89 f6 mov %esi,%esi + 10090c: 83 fa 0a cmp $0xa,%edx + 10090f: 74 2b je 10093c <_translate_sc+0xc8> + 100911: 83 fa 08 cmp $0x8,%edx + 100914: 75 de jne 1008f4 <_translate_sc+0x80> + 100916: a1 40 85 10 00 mov 0x108540,%eax + 10091b: c6 80 60 85 10 00 00 movb $0x0,0x108560(%eax) + 100922: 83 ec 0c sub $0xc,%esp + 100925: 48 dec %eax + 100926: a3 40 85 10 00 mov %eax,0x108540 + 10092b: 68 d2 54 10 00 push $0x1054d2 + 100930: e8 9f 47 00 00 call 1050d4 + 100935: 31 d2 xor %edx,%edx + 100937: 83 c4 10 add $0x10,%esp + 10093a: eb b8 jmp 1008f4 <_translate_sc+0x80> + 10093c: 83 ec 0c sub $0xc,%esp + 10093f: 68 f8 5a 10 00 push $0x105af8 + 100944: e8 8b 47 00 00 call 1050d4 + 100949: a1 40 85 10 00 mov 0x108540,%eax + 10094e: 5a pop %edx + 10094f: 59 pop %ecx + 100950: c6 80 60 85 10 00 00 movb $0x0,0x108560(%eax) + 100957: 48 dec %eax + 100958: 50 push %eax + 100959: 68 60 85 10 00 push $0x108560 + 10095e: e8 e9 fc ff ff call 10064c + 100963: c7 05 40 85 10 00 00 movl $0x0,0x108540 + 10096a: 00 00 00 + 10096d: c6 05 60 85 10 00 00 movb $0x0,0x108560 + 100974: c7 04 24 d6 54 10 00 movl $0x1054d6,(%esp,1) + 10097b: eb b3 jmp 100930 <_translate_sc+0xbc> + 10097d: 8d 76 00 lea 0x0(%esi),%esi + 100980: 8d 42 9f lea 0xffffff9f(%edx),%eax + 100983: 83 f8 19 cmp $0x19,%eax + 100986: 0f 87 44 ff ff ff ja 1008d0 <_translate_sc+0x5c> + 10098c: 83 ea 20 sub $0x20,%edx + 10098f: e9 3c ff ff ff jmp 1008d0 <_translate_sc+0x5c> + 100994: a1 e8 83 10 00 mov 0x1083e8,%eax + 100999: 85 c0 test %eax,%eax + 10099b: 75 09 jne 1009a6 <_translate_sc+0x132> + 10099d: a1 18 84 10 00 mov 0x108418,%eax + 1009a2: 85 c0 test %eax,%eax + 1009a4: 74 15 je 1009bb <_translate_sc+0x147> + 1009a6: ba 21 00 00 00 mov $0x21,%edx + 1009ab: 90 nop + 1009ac: c7 05 00 80 10 00 00 movl $0x0,0x108000 + 1009b3: 00 00 00 + 1009b6: e9 e9 fe ff ff jmp 1008a4 <_translate_sc+0x30> + 1009bb: ba 31 00 00 00 mov $0x31,%edx + 1009c0: eb ea jmp 1009ac <_translate_sc+0x138> + 1009c2: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 1009c8: 85 d2 test %edx,%edx + 1009ca: 75 09 jne 1009d5 <_translate_sc+0x161> + 1009cc: a1 18 84 10 00 mov 0x108418,%eax + 1009d1: 85 c0 test %eax,%eax + 1009d3: 74 07 je 1009dc <_translate_sc+0x168> + 1009d5: ba 40 00 00 00 mov $0x40,%edx + 1009da: eb d0 jmp 1009ac <_translate_sc+0x138> + 1009dc: ba 32 00 00 00 mov $0x32,%edx + 1009e1: eb c9 jmp 1009ac <_translate_sc+0x138> + 1009e3: a1 e8 83 10 00 mov 0x1083e8,%eax + 1009e8: 85 c0 test %eax,%eax + 1009ea: 75 09 jne 1009f5 <_translate_sc+0x181> + 1009ec: a1 18 84 10 00 mov 0x108418,%eax + 1009f1: 85 c0 test %eax,%eax + 1009f3: 74 07 je 1009fc <_translate_sc+0x188> + 1009f5: ba 23 00 00 00 mov $0x23,%edx + 1009fa: eb b0 jmp 1009ac <_translate_sc+0x138> + 1009fc: ba 33 00 00 00 mov $0x33,%edx + 100a01: eb a9 jmp 1009ac <_translate_sc+0x138> + 100a03: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100a09: 85 d2 test %edx,%edx + 100a0b: 75 09 jne 100a16 <_translate_sc+0x1a2> + 100a0d: a1 18 84 10 00 mov 0x108418,%eax + 100a12: 85 c0 test %eax,%eax + 100a14: 74 07 je 100a1d <_translate_sc+0x1a9> + 100a16: ba 24 00 00 00 mov $0x24,%edx + 100a1b: eb 8f jmp 1009ac <_translate_sc+0x138> + 100a1d: ba 34 00 00 00 mov $0x34,%edx + 100a22: eb 88 jmp 1009ac <_translate_sc+0x138> + 100a24: a1 e8 83 10 00 mov 0x1083e8,%eax + 100a29: 85 c0 test %eax,%eax + 100a2b: 75 09 jne 100a36 <_translate_sc+0x1c2> + 100a2d: a1 18 84 10 00 mov 0x108418,%eax + 100a32: 85 c0 test %eax,%eax + 100a34: 74 0a je 100a40 <_translate_sc+0x1cc> + 100a36: ba 23 00 00 00 mov $0x23,%edx + 100a3b: e9 6c ff ff ff jmp 1009ac <_translate_sc+0x138> + 100a40: ba 35 00 00 00 mov $0x35,%edx + 100a45: e9 62 ff ff ff jmp 1009ac <_translate_sc+0x138> + 100a4a: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100a50: 85 d2 test %edx,%edx + 100a52: 75 09 jne 100a5d <_translate_sc+0x1e9> + 100a54: a1 18 84 10 00 mov 0x108418,%eax + 100a59: 85 c0 test %eax,%eax + 100a5b: 74 0a je 100a67 <_translate_sc+0x1f3> + 100a5d: ba 5e 00 00 00 mov $0x5e,%edx + 100a62: e9 45 ff ff ff jmp 1009ac <_translate_sc+0x138> + 100a67: ba 36 00 00 00 mov $0x36,%edx + 100a6c: e9 3b ff ff ff jmp 1009ac <_translate_sc+0x138> + 100a71: a1 e8 83 10 00 mov 0x1083e8,%eax + 100a76: 85 c0 test %eax,%eax + 100a78: 75 09 jne 100a83 <_translate_sc+0x20f> + 100a7a: a1 18 84 10 00 mov 0x108418,%eax + 100a7f: 85 c0 test %eax,%eax + 100a81: 74 0a je 100a8d <_translate_sc+0x219> + 100a83: ba 26 00 00 00 mov $0x26,%edx + 100a88: e9 1f ff ff ff jmp 1009ac <_translate_sc+0x138> + 100a8d: ba 37 00 00 00 mov $0x37,%edx + 100a92: e9 15 ff ff ff jmp 1009ac <_translate_sc+0x138> + 100a97: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100a9d: 85 d2 test %edx,%edx + 100a9f: 75 09 jne 100aaa <_translate_sc+0x236> + 100aa1: a1 18 84 10 00 mov 0x108418,%eax + 100aa6: 85 c0 test %eax,%eax + 100aa8: 74 0a je 100ab4 <_translate_sc+0x240> + 100aaa: ba 2a 00 00 00 mov $0x2a,%edx + 100aaf: e9 f8 fe ff ff jmp 1009ac <_translate_sc+0x138> + 100ab4: ba 38 00 00 00 mov $0x38,%edx + 100ab9: e9 ee fe ff ff jmp 1009ac <_translate_sc+0x138> + 100abe: a1 e8 83 10 00 mov 0x1083e8,%eax + 100ac3: 85 c0 test %eax,%eax + 100ac5: 75 09 jne 100ad0 <_translate_sc+0x25c> + 100ac7: a1 18 84 10 00 mov 0x108418,%eax + 100acc: 85 c0 test %eax,%eax + 100ace: 74 0a je 100ada <_translate_sc+0x266> + 100ad0: ba 28 00 00 00 mov $0x28,%edx + 100ad5: e9 d2 fe ff ff jmp 1009ac <_translate_sc+0x138> + 100ada: ba 39 00 00 00 mov $0x39,%edx + 100adf: e9 c8 fe ff ff jmp 1009ac <_translate_sc+0x138> + 100ae4: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100aea: 85 d2 test %edx,%edx + 100aec: 75 09 jne 100af7 <_translate_sc+0x283> + 100aee: a1 18 84 10 00 mov 0x108418,%eax + 100af3: 85 c0 test %eax,%eax + 100af5: 74 0a je 100b01 <_translate_sc+0x28d> + 100af7: ba 29 00 00 00 mov $0x29,%edx + 100afc: e9 ab fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b01: ba 30 00 00 00 mov $0x30,%edx + 100b06: e9 a1 fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b0b: a1 e8 83 10 00 mov 0x1083e8,%eax + 100b10: 85 c0 test %eax,%eax + 100b12: 75 09 jne 100b1d <_translate_sc+0x2a9> + 100b14: a1 18 84 10 00 mov 0x108418,%eax + 100b19: 85 c0 test %eax,%eax + 100b1b: 74 0a je 100b27 <_translate_sc+0x2b3> + 100b1d: ba 5f 00 00 00 mov $0x5f,%edx + 100b22: e9 85 fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b27: ba 2d 00 00 00 mov $0x2d,%edx + 100b2c: e9 7b fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b31: a1 e8 83 10 00 mov 0x1083e8,%eax + 100b36: 85 c0 test %eax,%eax + 100b38: 75 09 jne 100b43 <_translate_sc+0x2cf> + 100b3a: a1 18 84 10 00 mov 0x108418,%eax + 100b3f: 85 c0 test %eax,%eax + 100b41: 74 0a je 100b4d <_translate_sc+0x2d9> + 100b43: ba 3d 00 00 00 mov $0x3d,%edx + 100b48: e9 5f fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b4d: ba 2b 00 00 00 mov $0x2b,%edx + 100b52: e9 55 fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b57: ba 08 00 00 00 mov $0x8,%edx + 100b5c: e9 4b fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b61: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100b67: 85 d2 test %edx,%edx + 100b69: 75 09 jne 100b74 <_translate_sc+0x300> + 100b6b: a1 18 84 10 00 mov 0x108418,%eax + 100b70: 85 c0 test %eax,%eax + 100b72: 74 0a je 100b7e <_translate_sc+0x30a> + 100b74: ba 51 00 00 00 mov $0x51,%edx + 100b79: e9 2e fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b7e: ba 71 00 00 00 mov $0x71,%edx + 100b83: e9 24 fe ff ff jmp 1009ac <_translate_sc+0x138> + 100b88: a1 e8 83 10 00 mov 0x1083e8,%eax + 100b8d: 85 c0 test %eax,%eax + 100b8f: 75 09 jne 100b9a <_translate_sc+0x326> + 100b91: a1 18 84 10 00 mov 0x108418,%eax + 100b96: 85 c0 test %eax,%eax + 100b98: 74 0a je 100ba4 <_translate_sc+0x330> + 100b9a: ba 57 00 00 00 mov $0x57,%edx + 100b9f: e9 08 fe ff ff jmp 1009ac <_translate_sc+0x138> + 100ba4: ba 77 00 00 00 mov $0x77,%edx + 100ba9: e9 fe fd ff ff jmp 1009ac <_translate_sc+0x138> + 100bae: a1 e8 83 10 00 mov 0x1083e8,%eax + 100bb3: 85 c0 test %eax,%eax + 100bb5: 75 09 jne 100bc0 <_translate_sc+0x34c> + 100bb7: a1 18 84 10 00 mov 0x108418,%eax + 100bbc: 85 c0 test %eax,%eax + 100bbe: 74 0a je 100bca <_translate_sc+0x356> + 100bc0: ba 45 00 00 00 mov $0x45,%edx + 100bc5: e9 e2 fd ff ff jmp 1009ac <_translate_sc+0x138> + 100bca: ba 65 00 00 00 mov $0x65,%edx + 100bcf: e9 d8 fd ff ff jmp 1009ac <_translate_sc+0x138> + 100bd4: a1 e8 83 10 00 mov 0x1083e8,%eax + 100bd9: 85 c0 test %eax,%eax + 100bdb: 75 0a jne 100be7 <_translate_sc+0x373> + 100bdd: 8b 0d 18 84 10 00 mov 0x108418,%ecx + 100be3: 85 c9 test %ecx,%ecx + 100be5: 74 0a je 100bf1 <_translate_sc+0x37d> + 100be7: ba 52 00 00 00 mov $0x52,%edx + 100bec: e9 bb fd ff ff jmp 1009ac <_translate_sc+0x138> + 100bf1: ba 72 00 00 00 mov $0x72,%edx + 100bf6: e9 b1 fd ff ff jmp 1009ac <_translate_sc+0x138> + 100bfb: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100c01: 85 d2 test %edx,%edx + 100c03: 75 09 jne 100c0e <_translate_sc+0x39a> + 100c05: a1 18 84 10 00 mov 0x108418,%eax + 100c0a: 85 c0 test %eax,%eax + 100c0c: 74 0a je 100c18 <_translate_sc+0x3a4> + 100c0e: ba 54 00 00 00 mov $0x54,%edx + 100c13: e9 94 fd ff ff jmp 1009ac <_translate_sc+0x138> + 100c18: ba 74 00 00 00 mov $0x74,%edx + 100c1d: e9 8a fd ff ff jmp 1009ac <_translate_sc+0x138> + 100c22: a1 e8 83 10 00 mov 0x1083e8,%eax + 100c27: 85 c0 test %eax,%eax + 100c29: 75 09 jne 100c34 <_translate_sc+0x3c0> + 100c2b: a1 18 84 10 00 mov 0x108418,%eax + 100c30: 85 c0 test %eax,%eax + 100c32: 74 0a je 100c3e <_translate_sc+0x3ca> + 100c34: ba 59 00 00 00 mov $0x59,%edx + 100c39: e9 6e fd ff ff jmp 1009ac <_translate_sc+0x138> + 100c3e: ba 79 00 00 00 mov $0x79,%edx + 100c43: e9 64 fd ff ff jmp 1009ac <_translate_sc+0x138> + 100c48: a1 e8 83 10 00 mov 0x1083e8,%eax + 100c4d: 85 c0 test %eax,%eax + 100c4f: 75 09 jne 100c5a <_translate_sc+0x3e6> + 100c51: a1 18 84 10 00 mov 0x108418,%eax + 100c56: 85 c0 test %eax,%eax + 100c58: 74 0a je 100c64 <_translate_sc+0x3f0> + 100c5a: ba 55 00 00 00 mov $0x55,%edx + 100c5f: e9 48 fd ff ff jmp 1009ac <_translate_sc+0x138> + 100c64: ba 75 00 00 00 mov $0x75,%edx + 100c69: e9 3e fd ff ff jmp 1009ac <_translate_sc+0x138> + 100c6e: a1 e8 83 10 00 mov 0x1083e8,%eax + 100c73: 85 c0 test %eax,%eax + 100c75: 75 0a jne 100c81 <_translate_sc+0x40d> + 100c77: 8b 0d 18 84 10 00 mov 0x108418,%ecx + 100c7d: 85 c9 test %ecx,%ecx + 100c7f: 74 0a je 100c8b <_translate_sc+0x417> + 100c81: ba 49 00 00 00 mov $0x49,%edx + 100c86: e9 21 fd ff ff jmp 1009ac <_translate_sc+0x138> + 100c8b: ba 69 00 00 00 mov $0x69,%edx + 100c90: e9 17 fd ff ff jmp 1009ac <_translate_sc+0x138> + 100c95: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100c9b: 85 d2 test %edx,%edx + 100c9d: 75 09 jne 100ca8 <_translate_sc+0x434> + 100c9f: a1 18 84 10 00 mov 0x108418,%eax + 100ca4: 85 c0 test %eax,%eax + 100ca6: 74 0a je 100cb2 <_translate_sc+0x43e> + 100ca8: ba 4f 00 00 00 mov $0x4f,%edx + 100cad: e9 fa fc ff ff jmp 1009ac <_translate_sc+0x138> + 100cb2: ba 6f 00 00 00 mov $0x6f,%edx + 100cb7: e9 f0 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100cbc: a1 e8 83 10 00 mov 0x1083e8,%eax + 100cc1: 85 c0 test %eax,%eax + 100cc3: 75 09 jne 100cce <_translate_sc+0x45a> + 100cc5: a1 18 84 10 00 mov 0x108418,%eax + 100cca: 85 c0 test %eax,%eax + 100ccc: 74 0a je 100cd8 <_translate_sc+0x464> + 100cce: ba 50 00 00 00 mov $0x50,%edx + 100cd3: e9 d4 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100cd8: ba 70 00 00 00 mov $0x70,%edx + 100cdd: e9 ca fc ff ff jmp 1009ac <_translate_sc+0x138> + 100ce2: a1 e8 83 10 00 mov 0x1083e8,%eax + 100ce7: 85 c0 test %eax,%eax + 100ce9: 75 09 jne 100cf4 <_translate_sc+0x480> + 100ceb: a1 18 84 10 00 mov 0x108418,%eax + 100cf0: 85 c0 test %eax,%eax + 100cf2: 74 0a je 100cfe <_translate_sc+0x48a> + 100cf4: ba 7b 00 00 00 mov $0x7b,%edx + 100cf9: e9 ae fc ff ff jmp 1009ac <_translate_sc+0x138> + 100cfe: ba 5b 00 00 00 mov $0x5b,%edx + 100d03: e9 a4 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100d08: a1 e8 83 10 00 mov 0x1083e8,%eax + 100d0d: 85 c0 test %eax,%eax + 100d0f: 75 0a jne 100d1b <_translate_sc+0x4a7> + 100d11: 8b 0d 18 84 10 00 mov 0x108418,%ecx + 100d17: 85 c9 test %ecx,%ecx + 100d19: 74 0a je 100d25 <_translate_sc+0x4b1> + 100d1b: ba 7d 00 00 00 mov $0x7d,%edx + 100d20: e9 87 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100d25: ba 5d 00 00 00 mov $0x5d,%edx + 100d2a: e9 7d fc ff ff jmp 1009ac <_translate_sc+0x138> + 100d2f: ba 0a 00 00 00 mov $0xa,%edx + 100d34: e9 73 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100d39: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100d3f: 85 d2 test %edx,%edx + 100d41: 75 09 jne 100d4c <_translate_sc+0x4d8> + 100d43: a1 18 84 10 00 mov 0x108418,%eax + 100d48: 85 c0 test %eax,%eax + 100d4a: 74 0a je 100d56 <_translate_sc+0x4e2> + 100d4c: ba 41 00 00 00 mov $0x41,%edx + 100d51: e9 56 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100d56: ba 61 00 00 00 mov $0x61,%edx + 100d5b: e9 4c fc ff ff jmp 1009ac <_translate_sc+0x138> + 100d60: a1 e8 83 10 00 mov 0x1083e8,%eax + 100d65: 85 c0 test %eax,%eax + 100d67: 75 09 jne 100d72 <_translate_sc+0x4fe> + 100d69: a1 18 84 10 00 mov 0x108418,%eax + 100d6e: 85 c0 test %eax,%eax + 100d70: 74 0a je 100d7c <_translate_sc+0x508> + 100d72: ba 53 00 00 00 mov $0x53,%edx + 100d77: e9 30 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100d7c: ba 73 00 00 00 mov $0x73,%edx + 100d81: e9 26 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100d86: a1 e8 83 10 00 mov 0x1083e8,%eax + 100d8b: 85 c0 test %eax,%eax + 100d8d: 75 09 jne 100d98 <_translate_sc+0x524> + 100d8f: a1 18 84 10 00 mov 0x108418,%eax + 100d94: 85 c0 test %eax,%eax + 100d96: 74 0a je 100da2 <_translate_sc+0x52e> + 100d98: ba 44 00 00 00 mov $0x44,%edx + 100d9d: e9 0a fc ff ff jmp 1009ac <_translate_sc+0x138> + 100da2: ba 64 00 00 00 mov $0x64,%edx + 100da7: e9 00 fc ff ff jmp 1009ac <_translate_sc+0x138> + 100dac: a1 e8 83 10 00 mov 0x1083e8,%eax + 100db1: 85 c0 test %eax,%eax + 100db3: 75 0a jne 100dbf <_translate_sc+0x54b> + 100db5: 8b 0d 18 84 10 00 mov 0x108418,%ecx + 100dbb: 85 c9 test %ecx,%ecx + 100dbd: 74 0a je 100dc9 <_translate_sc+0x555> + 100dbf: ba 46 00 00 00 mov $0x46,%edx + 100dc4: e9 e3 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100dc9: ba 66 00 00 00 mov $0x66,%edx + 100dce: e9 d9 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100dd3: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100dd9: 85 d2 test %edx,%edx + 100ddb: 75 09 jne 100de6 <_translate_sc+0x572> + 100ddd: a1 18 84 10 00 mov 0x108418,%eax + 100de2: 85 c0 test %eax,%eax + 100de4: 74 0a je 100df0 <_translate_sc+0x57c> + 100de6: ba 47 00 00 00 mov $0x47,%edx + 100deb: e9 bc fb ff ff jmp 1009ac <_translate_sc+0x138> + 100df0: ba 67 00 00 00 mov $0x67,%edx + 100df5: e9 b2 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100dfa: a1 e8 83 10 00 mov 0x1083e8,%eax + 100dff: 85 c0 test %eax,%eax + 100e01: 75 09 jne 100e0c <_translate_sc+0x598> + 100e03: a1 18 84 10 00 mov 0x108418,%eax + 100e08: 85 c0 test %eax,%eax + 100e0a: 74 0a je 100e16 <_translate_sc+0x5a2> + 100e0c: ba 48 00 00 00 mov $0x48,%edx + 100e11: e9 96 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100e16: ba 68 00 00 00 mov $0x68,%edx + 100e1b: e9 8c fb ff ff jmp 1009ac <_translate_sc+0x138> + 100e20: a1 e8 83 10 00 mov 0x1083e8,%eax + 100e25: 85 c0 test %eax,%eax + 100e27: 75 09 jne 100e32 <_translate_sc+0x5be> + 100e29: a1 18 84 10 00 mov 0x108418,%eax + 100e2e: 85 c0 test %eax,%eax + 100e30: 74 0a je 100e3c <_translate_sc+0x5c8> + 100e32: ba 4a 00 00 00 mov $0x4a,%edx + 100e37: e9 70 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100e3c: ba 6a 00 00 00 mov $0x6a,%edx + 100e41: e9 66 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100e46: a1 e8 83 10 00 mov 0x1083e8,%eax + 100e4b: 85 c0 test %eax,%eax + 100e4d: 75 0a jne 100e59 <_translate_sc+0x5e5> + 100e4f: 8b 0d 18 84 10 00 mov 0x108418,%ecx + 100e55: 85 c9 test %ecx,%ecx + 100e57: 74 0a je 100e63 <_translate_sc+0x5ef> + 100e59: ba 4b 00 00 00 mov $0x4b,%edx + 100e5e: e9 49 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100e63: ba 6b 00 00 00 mov $0x6b,%edx + 100e68: e9 3f fb ff ff jmp 1009ac <_translate_sc+0x138> + 100e6d: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100e73: 85 d2 test %edx,%edx + 100e75: 75 09 jne 100e80 <_translate_sc+0x60c> + 100e77: a1 18 84 10 00 mov 0x108418,%eax + 100e7c: 85 c0 test %eax,%eax + 100e7e: 74 0a je 100e8a <_translate_sc+0x616> + 100e80: ba 4c 00 00 00 mov $0x4c,%edx + 100e85: e9 22 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100e8a: ba 6c 00 00 00 mov $0x6c,%edx + 100e8f: e9 18 fb ff ff jmp 1009ac <_translate_sc+0x138> + 100e94: a1 e8 83 10 00 mov 0x1083e8,%eax + 100e99: 85 c0 test %eax,%eax + 100e9b: 75 09 jne 100ea6 <_translate_sc+0x632> + 100e9d: a1 18 84 10 00 mov 0x108418,%eax + 100ea2: 85 c0 test %eax,%eax + 100ea4: 74 0a je 100eb0 <_translate_sc+0x63c> + 100ea6: ba 3a 00 00 00 mov $0x3a,%edx + 100eab: e9 fc fa ff ff jmp 1009ac <_translate_sc+0x138> + 100eb0: ba 3b 00 00 00 mov $0x3b,%edx + 100eb5: e9 f2 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100eba: a1 e8 83 10 00 mov 0x1083e8,%eax + 100ebf: 85 c0 test %eax,%eax + 100ec1: 75 09 jne 100ecc <_translate_sc+0x658> + 100ec3: a1 18 84 10 00 mov 0x108418,%eax + 100ec8: 85 c0 test %eax,%eax + 100eca: 74 0a je 100ed6 <_translate_sc+0x662> + 100ecc: ba 22 00 00 00 mov $0x22,%edx + 100ed1: e9 d6 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100ed6: ba 27 00 00 00 mov $0x27,%edx + 100edb: e9 cc fa ff ff jmp 1009ac <_translate_sc+0x138> + 100ee0: ba 7e 00 00 00 mov $0x7e,%edx + 100ee5: e9 c2 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100eea: a1 e8 83 10 00 mov 0x1083e8,%eax + 100eef: 85 c0 test %eax,%eax + 100ef1: 75 0a jne 100efd <_translate_sc+0x689> + 100ef3: 8b 0d 18 84 10 00 mov 0x108418,%ecx + 100ef9: 85 c9 test %ecx,%ecx + 100efb: 74 0a je 100f07 <_translate_sc+0x693> + 100efd: ba 7c 00 00 00 mov $0x7c,%edx + 100f02: e9 a5 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100f07: ba 5c 00 00 00 mov $0x5c,%edx + 100f0c: e9 9b fa ff ff jmp 1009ac <_translate_sc+0x138> + 100f11: a1 e8 83 10 00 mov 0x1083e8,%eax + 100f16: 85 c0 test %eax,%eax + 100f18: 75 0a jne 100f24 <_translate_sc+0x6b0> + 100f1a: 8b 0d 18 84 10 00 mov 0x108418,%ecx + 100f20: 85 c9 test %ecx,%ecx + 100f22: 74 0a je 100f2e <_translate_sc+0x6ba> + 100f24: ba 5a 00 00 00 mov $0x5a,%edx + 100f29: e9 7e fa ff ff jmp 1009ac <_translate_sc+0x138> + 100f2e: ba 7a 00 00 00 mov $0x7a,%edx + 100f33: e9 74 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100f38: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100f3e: 85 d2 test %edx,%edx + 100f40: 75 09 jne 100f4b <_translate_sc+0x6d7> + 100f42: a1 18 84 10 00 mov 0x108418,%eax + 100f47: 85 c0 test %eax,%eax + 100f49: 74 0a je 100f55 <_translate_sc+0x6e1> + 100f4b: ba 58 00 00 00 mov $0x58,%edx + 100f50: e9 57 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100f55: ba 78 00 00 00 mov $0x78,%edx + 100f5a: e9 4d fa ff ff jmp 1009ac <_translate_sc+0x138> + 100f5f: a1 e8 83 10 00 mov 0x1083e8,%eax + 100f64: 85 c0 test %eax,%eax + 100f66: 75 09 jne 100f71 <_translate_sc+0x6fd> + 100f68: a1 18 84 10 00 mov 0x108418,%eax + 100f6d: 85 c0 test %eax,%eax + 100f6f: 74 0a je 100f7b <_translate_sc+0x707> + 100f71: ba 43 00 00 00 mov $0x43,%edx + 100f76: e9 31 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100f7b: ba 63 00 00 00 mov $0x63,%edx + 100f80: e9 27 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100f85: a1 e8 83 10 00 mov 0x1083e8,%eax + 100f8a: 85 c0 test %eax,%eax + 100f8c: 75 09 jne 100f97 <_translate_sc+0x723> + 100f8e: a1 18 84 10 00 mov 0x108418,%eax + 100f93: 85 c0 test %eax,%eax + 100f95: 74 0a je 100fa1 <_translate_sc+0x72d> + 100f97: ba 56 00 00 00 mov $0x56,%edx + 100f9c: e9 0b fa ff ff jmp 1009ac <_translate_sc+0x138> + 100fa1: ba 76 00 00 00 mov $0x76,%edx + 100fa6: e9 01 fa ff ff jmp 1009ac <_translate_sc+0x138> + 100fab: a1 e8 83 10 00 mov 0x1083e8,%eax + 100fb0: 85 c0 test %eax,%eax + 100fb2: 75 0a jne 100fbe <_translate_sc+0x74a> + 100fb4: 8b 0d 18 84 10 00 mov 0x108418,%ecx + 100fba: 85 c9 test %ecx,%ecx + 100fbc: 74 0a je 100fc8 <_translate_sc+0x754> + 100fbe: ba 42 00 00 00 mov $0x42,%edx + 100fc3: e9 e4 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 100fc8: ba 62 00 00 00 mov $0x62,%edx + 100fcd: e9 da f9 ff ff jmp 1009ac <_translate_sc+0x138> + 100fd2: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 100fd8: 85 d2 test %edx,%edx + 100fda: 75 09 jne 100fe5 <_translate_sc+0x771> + 100fdc: a1 18 84 10 00 mov 0x108418,%eax + 100fe1: 85 c0 test %eax,%eax + 100fe3: 74 0a je 100fef <_translate_sc+0x77b> + 100fe5: ba 4e 00 00 00 mov $0x4e,%edx + 100fea: e9 bd f9 ff ff jmp 1009ac <_translate_sc+0x138> + 100fef: ba 6e 00 00 00 mov $0x6e,%edx + 100ff4: e9 b3 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 100ff9: a1 e8 83 10 00 mov 0x1083e8,%eax + 100ffe: 85 c0 test %eax,%eax + 101000: 75 09 jne 10100b <_translate_sc+0x797> + 101002: a1 18 84 10 00 mov 0x108418,%eax + 101007: 85 c0 test %eax,%eax + 101009: 74 0a je 101015 <_translate_sc+0x7a1> + 10100b: ba 4d 00 00 00 mov $0x4d,%edx + 101010: e9 97 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 101015: ba 6d 00 00 00 mov $0x6d,%edx + 10101a: e9 8d f9 ff ff jmp 1009ac <_translate_sc+0x138> + 10101f: a1 e8 83 10 00 mov 0x1083e8,%eax + 101024: 85 c0 test %eax,%eax + 101026: 75 09 jne 101031 <_translate_sc+0x7bd> + 101028: a1 18 84 10 00 mov 0x108418,%eax + 10102d: 85 c0 test %eax,%eax + 10102f: 74 0a je 10103b <_translate_sc+0x7c7> + 101031: ba 3c 00 00 00 mov $0x3c,%edx + 101036: e9 71 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 10103b: ba 2c 00 00 00 mov $0x2c,%edx + 101040: e9 67 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 101045: 8b 15 e8 83 10 00 mov 0x1083e8,%edx + 10104b: 85 d2 test %edx,%edx + 10104d: 75 09 jne 101058 <_translate_sc+0x7e4> + 10104f: a1 18 84 10 00 mov 0x108418,%eax + 101054: 85 c0 test %eax,%eax + 101056: 74 0a je 101062 <_translate_sc+0x7ee> + 101058: ba 3e 00 00 00 mov $0x3e,%edx + 10105d: e9 4a f9 ff ff jmp 1009ac <_translate_sc+0x138> + 101062: ba 2e 00 00 00 mov $0x2e,%edx + 101067: e9 40 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 10106c: a1 e8 83 10 00 mov 0x1083e8,%eax + 101071: 85 c0 test %eax,%eax + 101073: 75 09 jne 10107e <_translate_sc+0x80a> + 101075: a1 18 84 10 00 mov 0x108418,%eax + 10107a: 85 c0 test %eax,%eax + 10107c: 74 0a je 101088 <_translate_sc+0x814> + 10107e: ba 3f 00 00 00 mov $0x3f,%edx + 101083: e9 24 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 101088: ba 2f 00 00 00 mov $0x2f,%edx + 10108d: e9 1a f9 ff ff jmp 1009ac <_translate_sc+0x138> + 101092: ba 2a 00 00 00 mov $0x2a,%edx + 101097: e9 10 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 10109c: ba 20 00 00 00 mov $0x20,%edx + 1010a1: e9 06 f9 ff ff jmp 1009ac <_translate_sc+0x138> + 1010a6: a1 54 84 10 00 mov 0x108454,%eax + 1010ab: 31 d2 xor %edx,%edx + 1010ad: 85 c0 test %eax,%eax + 1010af: 0f 84 f7 f8 ff ff je 1009ac <_translate_sc+0x138> + 1010b5: a1 00 80 10 00 mov 0x108000,%eax + 1010ba: 85 c0 test %eax,%eax + 1010bc: 0f 85 ea f8 ff ff jne 1009ac <_translate_sc+0x138> + 1010c2: ba 37 00 00 00 mov $0x37,%edx + 1010c7: e9 e0 f8 ff ff jmp 1009ac <_translate_sc+0x138> + 1010cc: a1 54 84 10 00 mov 0x108454,%eax + 1010d1: 31 d2 xor %edx,%edx + 1010d3: 85 c0 test %eax,%eax + 1010d5: 0f 84 d1 f8 ff ff je 1009ac <_translate_sc+0x138> + 1010db: 8b 0d 00 80 10 00 mov 0x108000,%ecx + 1010e1: 85 c9 test %ecx,%ecx + 1010e3: 0f 85 c3 f8 ff ff jne 1009ac <_translate_sc+0x138> + 1010e9: ba 38 00 00 00 mov $0x38,%edx + 1010ee: e9 b9 f8 ff ff jmp 1009ac <_translate_sc+0x138> + 1010f3: a1 54 84 10 00 mov 0x108454,%eax + 1010f8: 31 d2 xor %edx,%edx + 1010fa: 85 c0 test %eax,%eax + 1010fc: 0f 84 aa f8 ff ff je 1009ac <_translate_sc+0x138> + 101102: a1 00 80 10 00 mov 0x108000,%eax + 101107: 85 c0 test %eax,%eax + 101109: 0f 85 9d f8 ff ff jne 1009ac <_translate_sc+0x138> + 10110f: ba 39 00 00 00 mov $0x39,%edx + 101114: e9 93 f8 ff ff jmp 1009ac <_translate_sc+0x138> + 101119: ba 2d 00 00 00 mov $0x2d,%edx + 10111e: e9 89 f8 ff ff jmp 1009ac <_translate_sc+0x138> + 101123: a1 54 84 10 00 mov 0x108454,%eax + 101128: 31 d2 xor %edx,%edx + 10112a: 85 c0 test %eax,%eax + 10112c: 0f 84 7a f8 ff ff je 1009ac <_translate_sc+0x138> + 101132: 8b 0d 00 80 10 00 mov 0x108000,%ecx + 101138: 85 c9 test %ecx,%ecx + 10113a: 0f 85 6c f8 ff ff jne 1009ac <_translate_sc+0x138> + 101140: ba 34 00 00 00 mov $0x34,%edx + 101145: e9 62 f8 ff ff jmp 1009ac <_translate_sc+0x138> + 10114a: a1 54 84 10 00 mov 0x108454,%eax + 10114f: 31 d2 xor %edx,%edx + 101151: 85 c0 test %eax,%eax + 101153: 0f 84 53 f8 ff ff je 1009ac <_translate_sc+0x138> + 101159: a1 00 80 10 00 mov 0x108000,%eax + 10115e: 85 c0 test %eax,%eax + 101160: 0f 85 46 f8 ff ff jne 1009ac <_translate_sc+0x138> + 101166: ba 35 00 00 00 mov $0x35,%edx + 10116b: e9 3c f8 ff ff jmp 1009ac <_translate_sc+0x138> + 101170: a1 54 84 10 00 mov 0x108454,%eax + 101175: 31 d2 xor %edx,%edx + 101177: 85 c0 test %eax,%eax + 101179: 0f 84 2d f8 ff ff je 1009ac <_translate_sc+0x138> + 10117f: 8b 0d 00 80 10 00 mov 0x108000,%ecx + 101185: 85 c9 test %ecx,%ecx + 101187: 0f 85 1f f8 ff ff jne 1009ac <_translate_sc+0x138> + 10118d: ba 36 00 00 00 mov $0x36,%edx + 101192: e9 15 f8 ff ff jmp 1009ac <_translate_sc+0x138> + 101197: ba 2b 00 00 00 mov $0x2b,%edx + 10119c: e9 0b f8 ff ff jmp 1009ac <_translate_sc+0x138> + 1011a1: a1 54 84 10 00 mov 0x108454,%eax + 1011a6: 31 d2 xor %edx,%edx + 1011a8: 85 c0 test %eax,%eax + 1011aa: 0f 84 fc f7 ff ff je 1009ac <_translate_sc+0x138> + 1011b0: a1 00 80 10 00 mov 0x108000,%eax + 1011b5: 85 c0 test %eax,%eax + 1011b7: 0f 85 ef f7 ff ff jne 1009ac <_translate_sc+0x138> + 1011bd: ba 31 00 00 00 mov $0x31,%edx + 1011c2: e9 e5 f7 ff ff jmp 1009ac <_translate_sc+0x138> + 1011c7: a1 54 84 10 00 mov 0x108454,%eax + 1011cc: 31 d2 xor %edx,%edx + 1011ce: 85 c0 test %eax,%eax + 1011d0: 0f 84 d6 f7 ff ff je 1009ac <_translate_sc+0x138> + 1011d6: 8b 0d 00 80 10 00 mov 0x108000,%ecx + 1011dc: 85 c9 test %ecx,%ecx + 1011de: 0f 85 c8 f7 ff ff jne 1009ac <_translate_sc+0x138> + 1011e4: ba 32 00 00 00 mov $0x32,%edx + 1011e9: e9 be f7 ff ff jmp 1009ac <_translate_sc+0x138> + 1011ee: a1 54 84 10 00 mov 0x108454,%eax + 1011f3: 31 d2 xor %edx,%edx + 1011f5: 85 c0 test %eax,%eax + 1011f7: 0f 84 af f7 ff ff je 1009ac <_translate_sc+0x138> + 1011fd: a1 00 80 10 00 mov 0x108000,%eax + 101202: 85 c0 test %eax,%eax + 101204: 0f 85 a2 f7 ff ff jne 1009ac <_translate_sc+0x138> + 10120a: ba 33 00 00 00 mov $0x33,%edx + 10120f: e9 98 f7 ff ff jmp 1009ac <_translate_sc+0x138> + 101214: a1 54 84 10 00 mov 0x108454,%eax + 101219: 31 d2 xor %edx,%edx + 10121b: 85 c0 test %eax,%eax + 10121d: 0f 84 89 f7 ff ff je 1009ac <_translate_sc+0x138> + 101223: 8b 0d 00 80 10 00 mov 0x108000,%ecx + 101229: 85 c9 test %ecx,%ecx + 10122b: 0f 85 7b f7 ff ff jne 1009ac <_translate_sc+0x138> + 101231: ba 30 00 00 00 mov $0x30,%edx + 101236: e9 71 f7 ff ff jmp 1009ac <_translate_sc+0x138> + 10123b: a1 54 84 10 00 mov 0x108454,%eax + 101240: 31 d2 xor %edx,%edx + 101242: 85 c0 test %eax,%eax + 101244: 0f 84 62 f7 ff ff je 1009ac <_translate_sc+0x138> + 10124a: 8b 0d 00 80 10 00 mov 0x108000,%ecx + 101250: 85 c9 test %ecx,%ecx + 101252: 0f 85 54 f7 ff ff jne 1009ac <_translate_sc+0x138> + 101258: ba 2e 00 00 00 mov $0x2e,%edx + 10125d: e9 4a f7 ff ff jmp 1009ac <_translate_sc+0x138> + 101262: 89 f6 mov %esi,%esi + 101264: 31 c0 xor %eax,%eax + 101266: 31 d2 xor %edx,%edx + 101268: 85 c0 test %eax,%eax + 10126a: 0f 85 34 f6 ff ff jne 1008a4 <_translate_sc+0x30> + 101270: e9 37 f7 ff ff jmp 1009ac <_translate_sc+0x138> + 101275: 8d 76 00 lea 0x0(%esi),%esi + 101278: 8b 15 40 85 10 00 mov 0x108540,%edx + 10127e: 4a dec %edx + 10127f: 0f 89 01 f6 ff ff jns 100886 <_translate_sc+0x12> + 101285: 31 c0 xor %eax,%eax + 101287: c7 05 40 85 10 00 00 movl $0x0,0x108540 + 10128e: 00 00 00 + 101291: e9 60 f6 ff ff jmp 1008f6 <_translate_sc+0x82> + 101296: 89 f6 mov %esi,%esi + +00101298 : + +/** + * handle_meta_key() + * + * I'll pretty this up later + */ +void handle_meta_key(unsigned k) +{ + 101298: 55 push %ebp + 101299: 89 e5 mov %esp,%ebp + 10129b: 83 ec 08 sub $0x8,%esp + int i; + k = k; /* to shut gcc up */ + + /** + * Check for the infamous three finger salute + */ + if((keys[KEY_RCTRL] || keys[KEY_LCTRL]) && + 10129e: 8b 15 b4 83 10 00 mov 0x1083b4,%edx + 1012a4: 85 d2 test %edx,%edx + 1012a6: 74 69 je 101311 + 1012a8: 8b 15 20 84 10 00 mov 0x108420,%edx + 1012ae: 85 d2 test %edx,%edx + 1012b0: 74 0a je 1012bc + 1012b2: a1 8c 84 10 00 mov 0x10848c,%eax + 1012b7: 85 c0 test %eax,%eax + 1012b9: 75 51 jne 10130c + 1012bb: 90 nop + (keys[KEY_RALT] || keys[KEY_LALT]) && + keys[KEY_DEL]) + { + /** + * FIXME + * + * This should call _send_signal() + */ + reboot(); + } + + /** + * Check for Alt + F1-F12 for virtual terminals + */ + for(i = 0; i < 10; i++) + 1012bc: 31 c0 xor %eax,%eax + 1012be: b9 40 83 10 00 mov $0x108340,%ecx + 1012c3: 90 nop + { + if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[i + KEY_F1]) + 1012c4: 85 d2 test %edx,%edx + 1012c6: 74 0a je 1012d2 + 1012c8: 83 bc 81 ec 00 00 00 cmpl $0x0,0xec(%ecx,%eax,4) + 1012cf: 00 + 1012d0: 75 35 jne 101307 + 1012d2: 40 inc %eax + 1012d3: 83 f8 09 cmp $0x9,%eax + 1012d6: 7e ec jle 1012c4 + { + select_vc(i); + return; + } + } + + if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[KEY_F11]) + 1012d8: 85 d2 test %edx,%edx + 1012da: 74 13 je 1012ef + 1012dc: 8b 15 9c 84 10 00 mov 0x10849c,%edx + 1012e2: 85 d2 test %edx,%edx + 1012e4: 75 18 jne 1012fe + { + select_vc(10); + return; + } + + if((keys[KEY_LALT] || keys[KEY_RALT]) && keys[KEY_F12]) + 1012e6: a1 a0 84 10 00 mov 0x1084a0,%eax + 1012eb: 85 c0 test %eax,%eax + 1012ed: 75 02 jne 1012f1 + { + select_vc(11); + return; + } +} + 1012ef: c9 leave + 1012f0: c3 ret + 1012f1: c7 45 08 0b 00 00 00 movl $0xb,0x8(%ebp) + 1012f8: c9 leave + 1012f9: e9 06 35 00 00 jmp 104804 + 1012fe: c7 45 08 0a 00 00 00 movl $0xa,0x8(%ebp) + 101305: eb f1 jmp 1012f8 + 101307: 89 45 08 mov %eax,0x8(%ebp) + 10130a: eb ec jmp 1012f8 + 10130c: e8 d3 f4 ff ff call 1007e4 + 101311: 8b 15 20 84 10 00 mov 0x108420,%edx + 101317: eb a3 jmp 1012bc + 101319: 8d 76 00 lea 0x0(%esi),%esi + +0010131c : + +/** + * keyboard_irq() + * + * Called when a keyboard interrupt is generated. + */ +void keyboard_irq(void) +{ + 10131c: 55 push %ebp + 10131d: 89 e5 mov %esp,%ebp + 10131f: 53 push %ebx + 101320: 83 ec 10 sub $0x10,%esp + register char a; + unsigned c; + unsigned short kbdstat; + + rawkey = inportb(0x60); + 101323: 6a 60 push $0x60 + 101325: e8 ea 3c 00 00 call 105014 + 10132a: a3 20 83 10 00 mov %eax,0x108320 + outportb(0x61, (a=inportb(0x61)|0x82)); + 10132f: c7 04 24 61 00 00 00 movl $0x61,(%esp,1) + 101336: e8 d9 3c 00 00 call 105014 + 10133b: 83 c8 82 or $0xffffff82,%eax + 10133e: 59 pop %ecx + 10133f: 5b pop %ebx + 101340: 0f be d8 movsbl %al,%ebx + 101343: 53 push %ebx + 101344: 6a 61 push $0x61 + 101346: e8 69 3d 00 00 call 1050b4 + outportb(0x61, a & 0x7F); + 10134b: 58 pop %eax + 10134c: 5a pop %edx + 10134d: 83 e3 7f and $0x7f,%ebx + 101350: 53 push %ebx + 101351: 6a 61 push $0x61 + 101353: e8 5c 3d 00 00 call 1050b4 + + /** + * If it's less than 0x80 then it's definatelly + * a make code or a repeat code + */ + if(rawkey < 0x80) + 101358: 8b 0d 20 83 10 00 mov 0x108320,%ecx + 10135e: 83 c4 10 add $0x10,%esp + 101361: 83 f9 7f cmp $0x7f,%ecx + 101364: 7f 6a jg 1013d0 + { + /** + * We don't want to gunk up the numlock key + * because we will define it's state in the + * break code a bit later + */ + if((rawkey != KEYP_NUMLCK) && (rawkey != KEY_SCRLCK) && (rawkey != KEY_CAPS)) + 101366: 8d 41 bb lea 0xffffffbb(%ecx),%eax + 101369: 83 f8 01 cmp $0x1,%eax + 10136c: 76 10 jbe 10137e + 10136e: 83 f9 3a cmp $0x3a,%ecx + 101371: 74 0b je 10137e + keys[rawkey] = 1; + 101373: c7 04 8d 40 83 10 00 movl $0x1,0x108340(,%ecx,4) + 10137a: 01 00 00 00 + + keyDown(rawkey); + 10137e: 83 ec 0c sub $0xc,%esp + 101381: ff 35 20 83 10 00 pushl 0x108320 + 101387: e8 c4 ee ff ff call 100250 + 10138c: 58 pop %eax + } + else /* rawkey >= 0x80 */ + { + if(rawkey == 0xE0) + { + /** + * It's either a make code, break code, or repeat code + */ + rawkey = inportb(0x60); + outportb(0x61, (a=inportb(0x61)|0x82)); + outportb(0x61, a & 0x7F); + + if(rawkey < 0x80) + { + /** + * Ok, it's a make code or repeat code for the numeric + * keypad (gray keys) + */ + + keys[rawkey] = 1; + + keyDown(rawkey); + } + else /* rawkey >= 0x80 */ + { + /** + * It's either a make code for the numeric keypad or + * a break code for the numeric keypad. + */ + if(rawkey == 0x2A) + { + /** + * Ok, we have a make code for the numeric keypad + * and NUMLOCK is on. The second byte is what we + * want since what we have so far is this: + * + * 0xE0 0x2A + */ + rawkey = inportb(0x60); + outportb(0x61, (a=inportb(0x61)|0x82)); + outportb(0x61, a & 0x7F); + + rawkey = inportb(0x60); + outportb(0x61, (a=inportb(0x61)|0x82)); + outportb(0x61, a & 0x7F); + + keys[rawkey] = 1; + + keyDown(rawkey); + } + else + { + /** + * It's a break code from the numeric keypad. + */ + keys[rawkey] = 0; + + keyUp(rawkey); + } + } + } + else /* rawkey != 0xE0 */ + { + /** + * It's a break code + * + * Make sure we toggle the numlock, scroll lock, and caps lock key. + */ + if(((rawkey - 0x80) == KEYP_NUMLCK) || + ((rawkey - 0x80) == KEY_SCRLCK) || + ((rawkey - 0x80) == KEY_CAPS)) + { + keys[rawkey - 0x80] = !keys[rawkey - 0x80]; + + kbdstat = 0; + if(keys[KEY_SCRLCK]) + kbdstat |= 1; + if(keys[KEYP_NUMLCK]) + kbdstat |= 2; + if(keys[KEY_CAPS]) + kbdstat |= 4; + + _write_kb(0x60, 0xED); + _write_kb(0x60, kbdstat); + outportb(0x20, 0x20); + + keyUp(rawkey); + return; + } + + keys[rawkey - 0x80] = 0; + + keyUp(rawkey); + } + } + + c = _translate_sc(rawkey); + 10138d: ff 35 20 83 10 00 pushl 0x108320 + 101393: e8 dc f4 ff ff call 100874 <_translate_sc> + + if(c != 0) + 101398: 83 c4 10 add $0x10,%esp + 10139b: 85 c0 test %eax,%eax + 10139d: 74 21 je 1013c0 + printf("%c", c); + 10139f: 83 ec 08 sub $0x8,%esp + 1013a2: 50 push %eax + 1013a3: 68 e5 51 10 00 push $0x1051e5 + 1013a8: e8 27 3d 00 00 call 1050d4 + 1013ad: 59 pop %ecx + 1013ae: 5b pop %ebx + else + { + /** + * We need to check for meta-key-crap here + */ + handle_meta_key(rawkey); + } + + //enable(); + outportb(0x20, 0x20); + 1013af: 6a 20 push $0x20 + 1013b1: 6a 20 push $0x20 + 1013b3: e8 fc 3c 00 00 call 1050b4 +} + 1013b8: 8b 5d fc mov 0xfffffffc(%ebp),%ebx + 1013bb: c9 leave + 1013bc: c3 ret + 1013bd: 8d 76 00 lea 0x0(%esi),%esi + 1013c0: 83 ec 0c sub $0xc,%esp + 1013c3: ff 35 20 83 10 00 pushl 0x108320 + 1013c9: e8 ca fe ff ff call 101298 + 1013ce: eb dd jmp 1013ad + 1013d0: 81 f9 e0 00 00 00 cmp $0xe0,%ecx + 1013d6: 0f 84 a5 00 00 00 je 101481 + 1013dc: 8d 81 3b ff ff ff lea 0xffffff3b(%ecx),%eax + 1013e2: 83 f8 01 cmp $0x1,%eax + 1013e5: 76 21 jbe 101408 + 1013e7: 81 f9 ba 00 00 00 cmp $0xba,%ecx + 1013ed: 74 19 je 101408 + 1013ef: 83 ec 0c sub $0xc,%esp + 1013f2: c7 04 8d 40 81 10 00 movl $0x0,0x108140(,%ecx,4) + 1013f9: 00 00 00 00 + 1013fd: 51 push %ecx + 1013fe: e8 55 ee ff ff call 100258 + 101403: eb 87 jmp 10138c + 101405: 8d 76 00 lea 0x0(%esi),%esi + 101408: ba 40 83 10 00 mov $0x108340,%edx + 10140d: 31 c0 xor %eax,%eax + 10140f: 83 bc 8a 00 fe ff ff cmpl $0x0,0xfffffe00(%edx,%ecx,4) + 101416: 00 + 101417: 0f 94 c0 sete %al + 10141a: 89 84 8a 00 fe ff ff mov %eax,0xfffffe00(%edx,%ecx,4) + 101421: a1 58 84 10 00 mov 0x108458,%eax + 101426: 31 db xor %ebx,%ebx + 101428: 85 c0 test %eax,%eax + 10142a: 74 05 je 101431 + 10142c: bb 01 00 00 00 mov $0x1,%ebx + 101431: a1 54 84 10 00 mov 0x108454,%eax + 101436: 85 c0 test %eax,%eax + 101438: 74 03 je 10143d + 10143a: 83 cb 02 or $0x2,%ebx + 10143d: a1 28 84 10 00 mov 0x108428,%eax + 101442: 85 c0 test %eax,%eax + 101444: 74 03 je 101449 + 101446: 83 cb 04 or $0x4,%ebx + 101449: 83 ec 08 sub $0x8,%esp + 10144c: 68 ed 00 00 00 push $0xed + 101451: 6a 60 push $0x60 + 101453: e8 d4 f3 ff ff call 10082c <_write_kb> + 101458: 59 pop %ecx + 101459: 58 pop %eax + 10145a: 0f b7 c3 movzwl %bx,%eax + 10145d: 50 push %eax + 10145e: 6a 60 push $0x60 + 101460: e8 c7 f3 ff ff call 10082c <_write_kb> + 101465: 58 pop %eax + 101466: 5a pop %edx + 101467: 6a 20 push $0x20 + 101469: 6a 20 push $0x20 + 10146b: e8 44 3c 00 00 call 1050b4 + 101470: 58 pop %eax + 101471: ff 35 20 83 10 00 pushl 0x108320 + 101477: e8 dc ed ff ff call 100258 + 10147c: e9 37 ff ff ff jmp 1013b8 + 101481: 83 ec 0c sub $0xc,%esp + 101484: 6a 60 push $0x60 + 101486: e8 89 3b 00 00 call 105014 + 10148b: a3 20 83 10 00 mov %eax,0x108320 + 101490: c7 04 24 61 00 00 00 movl $0x61,(%esp,1) + 101497: e8 78 3b 00 00 call 105014 + 10149c: 83 c8 82 or $0xffffff82,%eax + 10149f: 59 pop %ecx + 1014a0: 5b pop %ebx + 1014a1: 0f be d8 movsbl %al,%ebx + 1014a4: 53 push %ebx + 1014a5: 6a 61 push $0x61 + 1014a7: e8 08 3c 00 00 call 1050b4 + 1014ac: 58 pop %eax + 1014ad: 5a pop %edx + 1014ae: 83 e3 7f and $0x7f,%ebx + 1014b1: 53 push %ebx + 1014b2: 6a 61 push $0x61 + 1014b4: e8 fb 3b 00 00 call 1050b4 + 1014b9: a1 20 83 10 00 mov 0x108320,%eax + 1014be: 83 c4 10 add $0x10,%esp + 1014c1: 83 f8 7f cmp $0x7f,%eax + 1014c4: 0f 8e a2 00 00 00 jle 10156c + 1014ca: 83 f8 2a cmp $0x2a,%eax + 1014cd: 74 14 je 1014e3 + 1014cf: 83 ec 0c sub $0xc,%esp + 1014d2: 50 push %eax + 1014d3: c7 04 85 40 83 10 00 movl $0x0,0x108340(,%eax,4) + 1014da: 00 00 00 00 + 1014de: e9 1b ff ff ff jmp 1013fe + 1014e3: 83 ec 0c sub $0xc,%esp + 1014e6: 6a 60 push $0x60 + 1014e8: e8 27 3b 00 00 call 105014 + 1014ed: a3 20 83 10 00 mov %eax,0x108320 + 1014f2: c7 04 24 61 00 00 00 movl $0x61,(%esp,1) + 1014f9: e8 16 3b 00 00 call 105014 + 1014fe: 83 c8 82 or $0xffffff82,%eax + 101501: 59 pop %ecx + 101502: 5b pop %ebx + 101503: 0f be d8 movsbl %al,%ebx + 101506: 53 push %ebx + 101507: 6a 61 push $0x61 + 101509: e8 a6 3b 00 00 call 1050b4 + 10150e: 58 pop %eax + 10150f: 5a pop %edx + 101510: 83 e3 7f and $0x7f,%ebx + 101513: 53 push %ebx + 101514: 6a 61 push $0x61 + 101516: e8 99 3b 00 00 call 1050b4 + 10151b: c7 04 24 60 00 00 00 movl $0x60,(%esp,1) + 101522: e8 ed 3a 00 00 call 105014 + 101527: a3 20 83 10 00 mov %eax,0x108320 + 10152c: c7 04 24 61 00 00 00 movl $0x61,(%esp,1) + 101533: e8 dc 3a 00 00 call 105014 + 101538: 83 c8 82 or $0xffffff82,%eax + 10153b: 5a pop %edx + 10153c: 59 pop %ecx + 10153d: 0f be d8 movsbl %al,%ebx + 101540: 53 push %ebx + 101541: 6a 61 push $0x61 + 101543: e8 6c 3b 00 00 call 1050b4 + 101548: 59 pop %ecx + 101549: 58 pop %eax + 10154a: 83 e3 7f and $0x7f,%ebx + 10154d: 53 push %ebx + 10154e: 6a 61 push $0x61 + 101550: e8 5f 3b 00 00 call 1050b4 + 101555: a1 20 83 10 00 mov 0x108320,%eax + 10155a: 5a pop %edx + 10155b: c7 04 85 40 83 10 00 movl $0x1,0x108340(,%eax,4) + 101562: 01 00 00 00 + 101566: 50 push %eax + 101567: e9 1b fe ff ff jmp 101387 + 10156c: c7 04 85 40 83 10 00 movl $0x1,0x108340(,%eax,4) + 101573: 01 00 00 00 + 101577: 83 ec 0c sub $0xc,%esp + 10157a: eb ea jmp 101566 + +0010157c : + +/** + * init_keyboard() + * + */ +void init_keyboard(void) +{ + 10157c: 55 push %ebp + 10157d: 89 e5 mov %esp,%ebp + static unsigned char buffers[KBD_BUF_SIZE * MAX_VC]; + + int i; + + //klog("init", "keyboard %2u buf, %2ub each", K_KLOG_PENDING, &_vc[0]); + for(i = 0; i < MAX_VC; i++) + 10157f: b9 20 80 10 00 mov $0x108020,%ecx + 101584: 83 ec 08 sub $0x8,%esp + 101587: 31 d2 xor %edx,%edx + 101589: b8 0b 00 00 00 mov $0xb,%eax + { + _vc[i].keystrokes.data = buffers + KBD_BUF_SIZE * i; + 10158e: 89 8a e0 a2 19 00 mov %ecx,0x19a2e0(%edx) + _vc[i].keystrokes.size = KBD_BUF_SIZE; + 101594: c7 82 e4 a2 19 00 40 movl $0x40,0x19a2e4(%edx) + 10159b: 00 00 00 + 10159e: 83 c1 40 add $0x40,%ecx + 1015a1: 83 c2 34 add $0x34,%edx + 1015a4: 48 dec %eax + 1015a5: 79 e7 jns 10158e + } + + for(i = 0; i < 128; i++) + 1015a7: 31 c0 xor %eax,%eax + 1015a9: 8d 76 00 lea 0x0(%esi),%esi + keys[i] = 0; + 1015ac: c7 04 85 40 83 10 00 movl $0x0,0x108340(,%eax,4) + 1015b3: 00 00 00 00 + 1015b7: 40 inc %eax + 1015b8: 83 f8 7f cmp $0x7f,%eax + 1015bb: 7e ef jle 1015ac + + makebreak = 0; + //klog(NULL, K_KLOG_SUCCESS, &_vc[0], NULL); + //kprintf("init_kbd: %u buffers, %u bytes each\n", + // MAX_VC, KBD_BUF_SIZE); + + //kprintf("[ Entering Runlevel 0 ].......................................................Ok"); + _vc[0].attrib = 8; + printf("[ "); + 1015bd: 83 ec 0c sub $0xc,%esp + 1015c0: 68 b6 51 10 00 push $0x1051b6 + 1015c5: c7 05 a0 85 10 00 00 movl $0x0,0x1085a0 + 1015cc: 00 00 00 + 1015cf: c7 05 f8 a2 19 00 08 movl $0x8,0x19a2f8 + 1015d6: 00 00 00 + 1015d9: e8 f6 3a 00 00 call 1050d4 + _vc[0].attrib = 15; + printf("init: keyboard %2u buf, %2ub each ", MAX_VC, KBD_BUF_SIZE); + 1015de: 83 c4 0c add $0xc,%esp + 1015e1: 6a 40 push $0x40 + 1015e3: 6a 0c push $0xc + 1015e5: 68 60 58 10 00 push $0x105860 + 1015ea: c7 05 f8 a2 19 00 0f movl $0xf,0x19a2f8 + 1015f1: 00 00 00 + 1015f4: e8 db 3a 00 00 call 1050d4 + _vc[0].attrib = 8; + printf("]..........................................."); + 1015f9: c7 04 24 a0 58 10 00 movl $0x1058a0,(%esp,1) + 101600: c7 05 f8 a2 19 00 08 movl $0x8,0x19a2f8 + 101607: 00 00 00 + 10160a: e8 c5 3a 00 00 call 1050d4 + _vc[0].attrib = 2; + printf("Ok"); + 10160f: c7 04 24 d9 54 10 00 movl $0x1054d9,(%esp,1) + 101616: c7 05 f8 a2 19 00 02 movl $0x2,0x19a2f8 + 10161d: 00 00 00 + 101620: e8 af 3a 00 00 call 1050d4 + _vc[0].attrib = 7; + 101625: c7 05 f8 a2 19 00 07 movl $0x7,0x19a2f8 + 10162c: 00 00 00 +} + 10162f: c9 leave + 101630: c3 ret + ... + +00101640 : + 101640: a1 00 70 10 00 mov 0x107000,%eax + 101645: 3d 2a da 44 35 cmp $0x3544da2a,%eax + 10164a: 74 0b je 101657 + 10164c: 66 c7 05 00 80 0b 00 movw $0x9f44,0xb8000 + 101653: 44 9f + 101655: eb fe jmp 101655 + +00101657 : + 101657: 0f 01 15 24 70 10 00 lgdtl 0x107024 + 10165e: 66 b8 10 00 mov $0x10,%ax + 101662: 8e d8 mov %eax,%ds + 101664: 8e c0 mov %eax,%es + 101666: 8e d0 mov %eax,%ss + 101668: 8e e0 mov %eax,%fs + 10166a: 8e e8 mov %eax,%gs + 10166c: ea 73 16 10 00 18 00 ljmp $0x18,$0x101673 + +00101673 : + 101673: bf 00 80 10 00 mov $0x108000,%edi + 101678: b9 00 b0 19 00 mov $0x19b000,%ecx + 10167d: 29 f9 sub %edi,%ecx + 10167f: 31 c0 xor %eax,%eax + 101681: f3 aa repz stos %al,%es:(%edi) + 101683: bc a4 95 10 00 mov $0x1095a4,%esp + 101688: b9 00 01 00 00 mov $0x100,%ecx + 10168d: bf 2a 70 10 00 mov $0x10702a,%edi + 101692: be 6b 17 10 00 mov $0x10176b,%esi + +00101697 : + 101697: 89 f0 mov %esi,%eax + 101699: 66 89 07 mov %ax,(%edi) + 10169c: c1 e8 10 shr $0x10,%eax + 10169f: 66 89 47 06 mov %ax,0x6(%edi) + 1016a3: 81 c7 08 00 00 00 add $0x8,%edi + 1016a9: 81 c6 26 00 00 00 add $0x26,%esi + 1016af: e2 e6 loop 101697 + 1016b1: 0f 01 1d 2a 78 10 00 lidtl 0x10782a + 1016b8: 68 02 00 00 00 push $0x2 + 1016bd: 9d popf + 1016be: e8 61 2c 00 00 call 104324
+ 1016c3: eb fe jmp 1016c3 + 1016c5: 90 nop + 1016c6: 90 nop + 1016c7: 90 nop + +001016c8 : + 1016c8: 02 b0 ad 1b 03 00 add 0x31bad(%eax),%dh + 1016ce: 01 00 add %eax,(%eax) + 1016d0: fb sti + 1016d1: 4f dec %edi + 1016d2: 51 push %ecx + 1016d3: e4 c8 in $0xc8,%al + 1016d5: 16 push %ss + 1016d6: 10 00 adc %al,(%eax) + 1016d8: 00 00 add %al,(%eax) + 1016da: 10 00 adc %al,(%eax) + 1016dc: 00 80 10 00 00 b0 add %al,0xb0000010(%eax) + 1016e2: 19 00 sbb %eax,(%eax) + 1016e4: 40 inc %eax + 1016e5: 16 push %ss + 1016e6: 10 00 adc %al,(%eax) + +001016e8 : + 1016e8: 58 pop %eax + 1016e9: 61 popa + 1016ea: 1f pop %ds + 1016eb: 07 pop %es + 1016ec: 0f a1 pop %fs + 1016ee: 0f a9 pop %gs + 1016f0: 81 c4 08 00 00 00 add $0x8,%esp + 1016f6: cf iret + +001016f7 <_getvect>: + 1016f7: 55 push %ebp + 1016f8: 89 e5 mov %esp,%ebp + 1016fa: 56 push %esi + 1016fb: 53 push %ebx + 1016fc: 8b 75 08 mov 0x8(%ebp),%esi + 1016ff: 31 db xor %ebx,%ebx + 101701: 8a 5d 0c mov 0xc(%ebp),%bl + 101704: c1 e3 03 shl $0x3,%ebx + 101707: 8a 83 2f 70 10 00 mov 0x10702f(%ebx),%al + 10170d: 89 06 mov %eax,(%esi) + 10170f: b8 91 17 10 00 mov $0x101791,%eax + 101714: 2d 6b 17 10 00 sub $0x10176b,%eax + 101719: f6 65 0c mulb 0xc(%ebp) + 10171c: 89 c3 mov %eax,%ebx + 10171e: 81 c3 6b 17 10 00 add $0x10176b,%ebx + 101724: 8b 83 1b 00 00 00 mov 0x1b(%ebx),%eax + 10172a: 89 46 04 mov %eax,0x4(%esi) + 10172d: 5b pop %ebx + 10172e: 5e pop %esi + 10172f: 5d pop %ebp + 101730: c3 ret + +00101731 <_setvect>: + 101731: 55 push %ebp + 101732: 89 e5 mov %esp,%ebp + 101734: 56 push %esi + 101735: 53 push %ebx + 101736: 8b 75 08 mov 0x8(%ebp),%esi + 101739: 8b 06 mov (%esi),%eax + 10173b: 31 db xor %ebx,%ebx + 10173d: 8a 5d 0c mov 0xc(%ebp),%bl + 101740: c1 e3 03 shl $0x3,%ebx + 101743: 88 83 2f 70 10 00 mov %al,0x10702f(%ebx) + 101749: b8 91 17 10 00 mov $0x101791,%eax + 10174e: 2d 6b 17 10 00 sub $0x10176b,%eax + 101753: f6 65 0c mulb 0xc(%ebp) + 101756: 89 c3 mov %eax,%ebx + 101758: 81 c3 6b 17 10 00 add $0x10176b,%ebx + 10175e: 8b 46 04 mov 0x4(%esi),%eax + 101761: 89 83 1b 00 00 00 mov %eax,0x1b(%ebx) + 101767: 5b pop %ebx + 101768: 5e pop %esi + 101769: 5d pop %ebp + 10176a: c3 ret + +0010176b : + 10176b: 6a 00 push $0x0 + 10176d: 6a 00 push $0x0 + 10176f: 0f a8 push %gs + 101771: 0f a0 push %fs + 101773: 06 push %es + 101774: 1e push %ds + 101775: 60 pusha + 101776: 66 b8 10 00 mov $0x10,%ax + 10177a: 8e d8 mov %eax,%ds + 10177c: 8e c0 mov %eax,%es + 10177e: 8e e0 mov %eax,%fs + 101780: 8e e8 mov %eax,%gs + 101782: 89 e0 mov %esp,%eax + 101784: 50 push %eax + +00101785 : + 101785: b8 04 3e 10 00 mov $0x103e04,%eax + 10178a: ff d0 call *%eax + 10178c: e9 57 ff ff ff jmp 1016e8 + +00101791 : + 101791: 6a 00 push $0x0 + 101793: 6a 01 push $0x1 + 101795: 0f a8 push %gs + 101797: 0f a0 push %fs + 101799: 06 push %es + 10179a: 1e push %ds + 10179b: 60 pusha + 10179c: 66 b8 10 00 mov $0x10,%ax + 1017a0: 8e d8 mov %eax,%ds + 1017a2: 8e c0 mov %eax,%es + 1017a4: 8e e0 mov %eax,%fs + 1017a6: 8e e8 mov %eax,%gs + 1017a8: 89 e0 mov %esp,%eax + 1017aa: 50 push %eax + +001017ab : + 1017ab: b8 04 3e 10 00 mov $0x103e04,%eax + 1017b0: ff d0 call *%eax + 1017b2: e9 31 ff ff ff jmp 1016e8 + +001017b7 : + 1017b7: 6a 00 push $0x0 + 1017b9: 6a 02 push $0x2 + 1017bb: 0f a8 push %gs + 1017bd: 0f a0 push %fs + 1017bf: 06 push %es + 1017c0: 1e push %ds + 1017c1: 60 pusha + 1017c2: 66 b8 10 00 mov $0x10,%ax + 1017c6: 8e d8 mov %eax,%ds + 1017c8: 8e c0 mov %eax,%es + 1017ca: 8e e0 mov %eax,%fs + 1017cc: 8e e8 mov %eax,%gs + 1017ce: 89 e0 mov %esp,%eax + 1017d0: 50 push %eax + +001017d1 : + 1017d1: b8 04 3e 10 00 mov $0x103e04,%eax + 1017d6: ff d0 call *%eax + 1017d8: e9 0b ff ff ff jmp 1016e8 + +001017dd : + 1017dd: 6a 00 push $0x0 + 1017df: 6a 03 push $0x3 + 1017e1: 0f a8 push %gs + 1017e3: 0f a0 push %fs + 1017e5: 06 push %es + 1017e6: 1e push %ds + 1017e7: 60 pusha + 1017e8: 66 b8 10 00 mov $0x10,%ax + 1017ec: 8e d8 mov %eax,%ds + 1017ee: 8e c0 mov %eax,%es + 1017f0: 8e e0 mov %eax,%fs + 1017f2: 8e e8 mov %eax,%gs + 1017f4: 89 e0 mov %esp,%eax + 1017f6: 50 push %eax + +001017f7 : + 1017f7: b8 04 3e 10 00 mov $0x103e04,%eax + 1017fc: ff d0 call *%eax + 1017fe: e9 e5 fe ff ff jmp 1016e8 + +00101803 : + 101803: 6a 00 push $0x0 + 101805: 6a 04 push $0x4 + 101807: 0f a8 push %gs + 101809: 0f a0 push %fs + 10180b: 06 push %es + 10180c: 1e push %ds + 10180d: 60 pusha + 10180e: 66 b8 10 00 mov $0x10,%ax + 101812: 8e d8 mov %eax,%ds + 101814: 8e c0 mov %eax,%es + 101816: 8e e0 mov %eax,%fs + 101818: 8e e8 mov %eax,%gs + 10181a: 89 e0 mov %esp,%eax + 10181c: 50 push %eax + +0010181d : + 10181d: b8 04 3e 10 00 mov $0x103e04,%eax + 101822: ff d0 call *%eax + 101824: e9 bf fe ff ff jmp 1016e8 + +00101829 : + 101829: 6a 00 push $0x0 + 10182b: 6a 05 push $0x5 + 10182d: 0f a8 push %gs + 10182f: 0f a0 push %fs + 101831: 06 push %es + 101832: 1e push %ds + 101833: 60 pusha + 101834: 66 b8 10 00 mov $0x10,%ax + 101838: 8e d8 mov %eax,%ds + 10183a: 8e c0 mov %eax,%es + 10183c: 8e e0 mov %eax,%fs + 10183e: 8e e8 mov %eax,%gs + 101840: 89 e0 mov %esp,%eax + 101842: 50 push %eax + +00101843 : + 101843: b8 04 3e 10 00 mov $0x103e04,%eax + 101848: ff d0 call *%eax + 10184a: e9 99 fe ff ff jmp 1016e8 + +0010184f : + 10184f: 6a 00 push $0x0 + 101851: 6a 06 push $0x6 + 101853: 0f a8 push %gs + 101855: 0f a0 push %fs + 101857: 06 push %es + 101858: 1e push %ds + 101859: 60 pusha + 10185a: 66 b8 10 00 mov $0x10,%ax + 10185e: 8e d8 mov %eax,%ds + 101860: 8e c0 mov %eax,%es + 101862: 8e e0 mov %eax,%fs + 101864: 8e e8 mov %eax,%gs + 101866: 89 e0 mov %esp,%eax + 101868: 50 push %eax + +00101869 : + 101869: b8 04 3e 10 00 mov $0x103e04,%eax + 10186e: ff d0 call *%eax + 101870: e9 73 fe ff ff jmp 1016e8 + +00101875 : + 101875: 6a 00 push $0x0 + 101877: 6a 07 push $0x7 + 101879: 0f a8 push %gs + 10187b: 0f a0 push %fs + 10187d: 06 push %es + 10187e: 1e push %ds + 10187f: 60 pusha + 101880: 66 b8 10 00 mov $0x10,%ax + 101884: 8e d8 mov %eax,%ds + 101886: 8e c0 mov %eax,%es + 101888: 8e e0 mov %eax,%fs + 10188a: 8e e8 mov %eax,%gs + 10188c: 89 e0 mov %esp,%eax + 10188e: 50 push %eax + +0010188f : + 10188f: b8 04 3e 10 00 mov $0x103e04,%eax + 101894: ff d0 call *%eax + 101896: e9 4d fe ff ff jmp 1016e8 + +0010189b : + 10189b: 90 nop + 10189c: 90 nop + 10189d: 6a 08 push $0x8 + 10189f: 0f a8 push %gs + 1018a1: 0f a0 push %fs + 1018a3: 06 push %es + 1018a4: 1e push %ds + 1018a5: 60 pusha + 1018a6: 66 b8 10 00 mov $0x10,%ax + 1018aa: 8e d8 mov %eax,%ds + 1018ac: 8e c0 mov %eax,%es + 1018ae: 8e e0 mov %eax,%fs + 1018b0: 8e e8 mov %eax,%gs + 1018b2: 89 e0 mov %esp,%eax + 1018b4: 50 push %eax + +001018b5 : + 1018b5: b8 04 3e 10 00 mov $0x103e04,%eax + 1018ba: ff d0 call *%eax + 1018bc: e9 27 fe ff ff jmp 1016e8 + +001018c1 : + 1018c1: 6a 00 push $0x0 + 1018c3: 6a 09 push $0x9 + 1018c5: 0f a8 push %gs + 1018c7: 0f a0 push %fs + 1018c9: 06 push %es + 1018ca: 1e push %ds + 1018cb: 60 pusha + 1018cc: 66 b8 10 00 mov $0x10,%ax + 1018d0: 8e d8 mov %eax,%ds + 1018d2: 8e c0 mov %eax,%es + 1018d4: 8e e0 mov %eax,%fs + 1018d6: 8e e8 mov %eax,%gs + 1018d8: 89 e0 mov %esp,%eax + 1018da: 50 push %eax + +001018db : + 1018db: b8 04 3e 10 00 mov $0x103e04,%eax + 1018e0: ff d0 call *%eax + 1018e2: e9 01 fe ff ff jmp 1016e8 + +001018e7 : + 1018e7: 90 nop + 1018e8: 90 nop + 1018e9: 6a 0a push $0xa + 1018eb: 0f a8 push %gs + 1018ed: 0f a0 push %fs + 1018ef: 06 push %es + 1018f0: 1e push %ds + 1018f1: 60 pusha + 1018f2: 66 b8 10 00 mov $0x10,%ax + 1018f6: 8e d8 mov %eax,%ds + 1018f8: 8e c0 mov %eax,%es + 1018fa: 8e e0 mov %eax,%fs + 1018fc: 8e e8 mov %eax,%gs + 1018fe: 89 e0 mov %esp,%eax + 101900: 50 push %eax + +00101901 : + 101901: b8 04 3e 10 00 mov $0x103e04,%eax + 101906: ff d0 call *%eax + 101908: e9 db fd ff ff jmp 1016e8 + +0010190d : + 10190d: 90 nop + 10190e: 90 nop + 10190f: 6a 0b push $0xb + 101911: 0f a8 push %gs + 101913: 0f a0 push %fs + 101915: 06 push %es + 101916: 1e push %ds + 101917: 60 pusha + 101918: 66 b8 10 00 mov $0x10,%ax + 10191c: 8e d8 mov %eax,%ds + 10191e: 8e c0 mov %eax,%es + 101920: 8e e0 mov %eax,%fs + 101922: 8e e8 mov %eax,%gs + 101924: 89 e0 mov %esp,%eax + 101926: 50 push %eax + +00101927 : + 101927: b8 04 3e 10 00 mov $0x103e04,%eax + 10192c: ff d0 call *%eax + 10192e: e9 b5 fd ff ff jmp 1016e8 + +00101933 : + 101933: 90 nop + 101934: 90 nop + 101935: 6a 0c push $0xc + 101937: 0f a8 push %gs + 101939: 0f a0 push %fs + 10193b: 06 push %es + 10193c: 1e push %ds + 10193d: 60 pusha + 10193e: 66 b8 10 00 mov $0x10,%ax + 101942: 8e d8 mov %eax,%ds + 101944: 8e c0 mov %eax,%es + 101946: 8e e0 mov %eax,%fs + 101948: 8e e8 mov %eax,%gs + 10194a: 89 e0 mov %esp,%eax + 10194c: 50 push %eax + +0010194d : + 10194d: b8 04 3e 10 00 mov $0x103e04,%eax + 101952: ff d0 call *%eax + 101954: e9 8f fd ff ff jmp 1016e8 + +00101959 : + 101959: 90 nop + 10195a: 90 nop + 10195b: 6a 0d push $0xd + 10195d: 0f a8 push %gs + 10195f: 0f a0 push %fs + 101961: 06 push %es + 101962: 1e push %ds + 101963: 60 pusha + 101964: 66 b8 10 00 mov $0x10,%ax + 101968: 8e d8 mov %eax,%ds + 10196a: 8e c0 mov %eax,%es + 10196c: 8e e0 mov %eax,%fs + 10196e: 8e e8 mov %eax,%gs + 101970: 89 e0 mov %esp,%eax + 101972: 50 push %eax + +00101973 : + 101973: b8 04 3e 10 00 mov $0x103e04,%eax + 101978: ff d0 call *%eax + 10197a: e9 69 fd ff ff jmp 1016e8 + +0010197f : + 10197f: 90 nop + 101980: 90 nop + 101981: 6a 0e push $0xe + 101983: 0f a8 push %gs + 101985: 0f a0 push %fs + 101987: 06 push %es + 101988: 1e push %ds + 101989: 60 pusha + 10198a: 66 b8 10 00 mov $0x10,%ax + 10198e: 8e d8 mov %eax,%ds + 101990: 8e c0 mov %eax,%es + 101992: 8e e0 mov %eax,%fs + 101994: 8e e8 mov %eax,%gs + 101996: 89 e0 mov %esp,%eax + 101998: 50 push %eax + +00101999 : + 101999: b8 04 3e 10 00 mov $0x103e04,%eax + 10199e: ff d0 call *%eax + 1019a0: e9 43 fd ff ff jmp 1016e8 + +001019a5 : + 1019a5: 6a 00 push $0x0 + 1019a7: 6a 0f push $0xf + 1019a9: 0f a8 push %gs + 1019ab: 0f a0 push %fs + 1019ad: 06 push %es + 1019ae: 1e push %ds + 1019af: 60 pusha + 1019b0: 66 b8 10 00 mov $0x10,%ax + 1019b4: 8e d8 mov %eax,%ds + 1019b6: 8e c0 mov %eax,%es + 1019b8: 8e e0 mov %eax,%fs + 1019ba: 8e e8 mov %eax,%gs + 1019bc: 89 e0 mov %esp,%eax + 1019be: 50 push %eax + +001019bf : + 1019bf: b8 04 3e 10 00 mov $0x103e04,%eax + 1019c4: ff d0 call *%eax + 1019c6: e9 1d fd ff ff jmp 1016e8 + +001019cb : + 1019cb: 6a 00 push $0x0 + 1019cd: 6a 10 push $0x10 + 1019cf: 0f a8 push %gs + 1019d1: 0f a0 push %fs + 1019d3: 06 push %es + 1019d4: 1e push %ds + 1019d5: 60 pusha + 1019d6: 66 b8 10 00 mov $0x10,%ax + 1019da: 8e d8 mov %eax,%ds + 1019dc: 8e c0 mov %eax,%es + 1019de: 8e e0 mov %eax,%fs + 1019e0: 8e e8 mov %eax,%gs + 1019e2: 89 e0 mov %esp,%eax + 1019e4: 50 push %eax + +001019e5 : + 1019e5: b8 04 3e 10 00 mov $0x103e04,%eax + 1019ea: ff d0 call *%eax + 1019ec: e9 f7 fc ff ff jmp 1016e8 + +001019f1 : + 1019f1: 6a 00 push $0x0 + 1019f3: 6a 11 push $0x11 + 1019f5: 0f a8 push %gs + 1019f7: 0f a0 push %fs + 1019f9: 06 push %es + 1019fa: 1e push %ds + 1019fb: 60 pusha + 1019fc: 66 b8 10 00 mov $0x10,%ax + 101a00: 8e d8 mov %eax,%ds + 101a02: 8e c0 mov %eax,%es + 101a04: 8e e0 mov %eax,%fs + 101a06: 8e e8 mov %eax,%gs + 101a08: 89 e0 mov %esp,%eax + 101a0a: 50 push %eax + +00101a0b : + 101a0b: b8 04 3e 10 00 mov $0x103e04,%eax + 101a10: ff d0 call *%eax + 101a12: e9 d1 fc ff ff jmp 1016e8 + +00101a17 : + 101a17: 6a 00 push $0x0 + 101a19: 6a 12 push $0x12 + 101a1b: 0f a8 push %gs + 101a1d: 0f a0 push %fs + 101a1f: 06 push %es + 101a20: 1e push %ds + 101a21: 60 pusha + 101a22: 66 b8 10 00 mov $0x10,%ax + 101a26: 8e d8 mov %eax,%ds + 101a28: 8e c0 mov %eax,%es + 101a2a: 8e e0 mov %eax,%fs + 101a2c: 8e e8 mov %eax,%gs + 101a2e: 89 e0 mov %esp,%eax + 101a30: 50 push %eax + +00101a31 : + 101a31: b8 04 3e 10 00 mov $0x103e04,%eax + 101a36: ff d0 call *%eax + 101a38: e9 ab fc ff ff jmp 1016e8 + +00101a3d : + 101a3d: 6a 00 push $0x0 + 101a3f: 6a 13 push $0x13 + 101a41: 0f a8 push %gs + 101a43: 0f a0 push %fs + 101a45: 06 push %es + 101a46: 1e push %ds + 101a47: 60 pusha + 101a48: 66 b8 10 00 mov $0x10,%ax + 101a4c: 8e d8 mov %eax,%ds + 101a4e: 8e c0 mov %eax,%es + 101a50: 8e e0 mov %eax,%fs + 101a52: 8e e8 mov %eax,%gs + 101a54: 89 e0 mov %esp,%eax + 101a56: 50 push %eax + +00101a57 : + 101a57: b8 04 3e 10 00 mov $0x103e04,%eax + 101a5c: ff d0 call *%eax + 101a5e: e9 85 fc ff ff jmp 1016e8 + +00101a63 : + 101a63: 6a 00 push $0x0 + 101a65: 6a 14 push $0x14 + 101a67: 0f a8 push %gs + 101a69: 0f a0 push %fs + 101a6b: 06 push %es + 101a6c: 1e push %ds + 101a6d: 60 pusha + 101a6e: 66 b8 10 00 mov $0x10,%ax + 101a72: 8e d8 mov %eax,%ds + 101a74: 8e c0 mov %eax,%es + 101a76: 8e e0 mov %eax,%fs + 101a78: 8e e8 mov %eax,%gs + 101a7a: 89 e0 mov %esp,%eax + 101a7c: 50 push %eax + +00101a7d : + 101a7d: b8 04 3e 10 00 mov $0x103e04,%eax + 101a82: ff d0 call *%eax + 101a84: e9 5f fc ff ff jmp 1016e8 + +00101a89 : + 101a89: 6a 00 push $0x0 + 101a8b: 6a 15 push $0x15 + 101a8d: 0f a8 push %gs + 101a8f: 0f a0 push %fs + 101a91: 06 push %es + 101a92: 1e push %ds + 101a93: 60 pusha + 101a94: 66 b8 10 00 mov $0x10,%ax + 101a98: 8e d8 mov %eax,%ds + 101a9a: 8e c0 mov %eax,%es + 101a9c: 8e e0 mov %eax,%fs + 101a9e: 8e e8 mov %eax,%gs + 101aa0: 89 e0 mov %esp,%eax + 101aa2: 50 push %eax + +00101aa3 : + 101aa3: b8 04 3e 10 00 mov $0x103e04,%eax + 101aa8: ff d0 call *%eax + 101aaa: e9 39 fc ff ff jmp 1016e8 + +00101aaf : + 101aaf: 6a 00 push $0x0 + 101ab1: 6a 16 push $0x16 + 101ab3: 0f a8 push %gs + 101ab5: 0f a0 push %fs + 101ab7: 06 push %es + 101ab8: 1e push %ds + 101ab9: 60 pusha + 101aba: 66 b8 10 00 mov $0x10,%ax + 101abe: 8e d8 mov %eax,%ds + 101ac0: 8e c0 mov %eax,%es + 101ac2: 8e e0 mov %eax,%fs + 101ac4: 8e e8 mov %eax,%gs + 101ac6: 89 e0 mov %esp,%eax + 101ac8: 50 push %eax + +00101ac9 : + 101ac9: b8 04 3e 10 00 mov $0x103e04,%eax + 101ace: ff d0 call *%eax + 101ad0: e9 13 fc ff ff jmp 1016e8 + +00101ad5 : + 101ad5: 6a 00 push $0x0 + 101ad7: 6a 17 push $0x17 + 101ad9: 0f a8 push %gs + 101adb: 0f a0 push %fs + 101add: 06 push %es + 101ade: 1e push %ds + 101adf: 60 pusha + 101ae0: 66 b8 10 00 mov $0x10,%ax + 101ae4: 8e d8 mov %eax,%ds + 101ae6: 8e c0 mov %eax,%es + 101ae8: 8e e0 mov %eax,%fs + 101aea: 8e e8 mov %eax,%gs + 101aec: 89 e0 mov %esp,%eax + 101aee: 50 push %eax + +00101aef : + 101aef: b8 04 3e 10 00 mov $0x103e04,%eax + 101af4: ff d0 call *%eax + 101af6: e9 ed fb ff ff jmp 1016e8 + +00101afb : + 101afb: 6a 00 push $0x0 + 101afd: 6a 18 push $0x18 + 101aff: 0f a8 push %gs + 101b01: 0f a0 push %fs + 101b03: 06 push %es + 101b04: 1e push %ds + 101b05: 60 pusha + 101b06: 66 b8 10 00 mov $0x10,%ax + 101b0a: 8e d8 mov %eax,%ds + 101b0c: 8e c0 mov %eax,%es + 101b0e: 8e e0 mov %eax,%fs + 101b10: 8e e8 mov %eax,%gs + 101b12: 89 e0 mov %esp,%eax + 101b14: 50 push %eax + +00101b15 : + 101b15: b8 04 3e 10 00 mov $0x103e04,%eax + 101b1a: ff d0 call *%eax + 101b1c: e9 c7 fb ff ff jmp 1016e8 + +00101b21 : + 101b21: 6a 00 push $0x0 + 101b23: 6a 19 push $0x19 + 101b25: 0f a8 push %gs + 101b27: 0f a0 push %fs + 101b29: 06 push %es + 101b2a: 1e push %ds + 101b2b: 60 pusha + 101b2c: 66 b8 10 00 mov $0x10,%ax + 101b30: 8e d8 mov %eax,%ds + 101b32: 8e c0 mov %eax,%es + 101b34: 8e e0 mov %eax,%fs + 101b36: 8e e8 mov %eax,%gs + 101b38: 89 e0 mov %esp,%eax + 101b3a: 50 push %eax + +00101b3b : + 101b3b: b8 04 3e 10 00 mov $0x103e04,%eax + 101b40: ff d0 call *%eax + 101b42: e9 a1 fb ff ff jmp 1016e8 + +00101b47 : + 101b47: 6a 00 push $0x0 + 101b49: 6a 1a push $0x1a + 101b4b: 0f a8 push %gs + 101b4d: 0f a0 push %fs + 101b4f: 06 push %es + 101b50: 1e push %ds + 101b51: 60 pusha + 101b52: 66 b8 10 00 mov $0x10,%ax + 101b56: 8e d8 mov %eax,%ds + 101b58: 8e c0 mov %eax,%es + 101b5a: 8e e0 mov %eax,%fs + 101b5c: 8e e8 mov %eax,%gs + 101b5e: 89 e0 mov %esp,%eax + 101b60: 50 push %eax + +00101b61 : + 101b61: b8 04 3e 10 00 mov $0x103e04,%eax + 101b66: ff d0 call *%eax + 101b68: e9 7b fb ff ff jmp 1016e8 + +00101b6d : + 101b6d: 6a 00 push $0x0 + 101b6f: 6a 1b push $0x1b + 101b71: 0f a8 push %gs + 101b73: 0f a0 push %fs + 101b75: 06 push %es + 101b76: 1e push %ds + 101b77: 60 pusha + 101b78: 66 b8 10 00 mov $0x10,%ax + 101b7c: 8e d8 mov %eax,%ds + 101b7e: 8e c0 mov %eax,%es + 101b80: 8e e0 mov %eax,%fs + 101b82: 8e e8 mov %eax,%gs + 101b84: 89 e0 mov %esp,%eax + 101b86: 50 push %eax + +00101b87 : + 101b87: b8 04 3e 10 00 mov $0x103e04,%eax + 101b8c: ff d0 call *%eax + 101b8e: e9 55 fb ff ff jmp 1016e8 + +00101b93 : + 101b93: 6a 00 push $0x0 + 101b95: 6a 1c push $0x1c + 101b97: 0f a8 push %gs + 101b99: 0f a0 push %fs + 101b9b: 06 push %es + 101b9c: 1e push %ds + 101b9d: 60 pusha + 101b9e: 66 b8 10 00 mov $0x10,%ax + 101ba2: 8e d8 mov %eax,%ds + 101ba4: 8e c0 mov %eax,%es + 101ba6: 8e e0 mov %eax,%fs + 101ba8: 8e e8 mov %eax,%gs + 101baa: 89 e0 mov %esp,%eax + 101bac: 50 push %eax + +00101bad : + 101bad: b8 04 3e 10 00 mov $0x103e04,%eax + 101bb2: ff d0 call *%eax + 101bb4: e9 2f fb ff ff jmp 1016e8 + +00101bb9 : + 101bb9: 6a 00 push $0x0 + 101bbb: 6a 1d push $0x1d + 101bbd: 0f a8 push %gs + 101bbf: 0f a0 push %fs + 101bc1: 06 push %es + 101bc2: 1e push %ds + 101bc3: 60 pusha + 101bc4: 66 b8 10 00 mov $0x10,%ax + 101bc8: 8e d8 mov %eax,%ds + 101bca: 8e c0 mov %eax,%es + 101bcc: 8e e0 mov %eax,%fs + 101bce: 8e e8 mov %eax,%gs + 101bd0: 89 e0 mov %esp,%eax + 101bd2: 50 push %eax + +00101bd3 : + 101bd3: b8 04 3e 10 00 mov $0x103e04,%eax + 101bd8: ff d0 call *%eax + 101bda: e9 09 fb ff ff jmp 1016e8 + +00101bdf : + 101bdf: 6a 00 push $0x0 + 101be1: 6a 1e push $0x1e + 101be3: 0f a8 push %gs + 101be5: 0f a0 push %fs + 101be7: 06 push %es + 101be8: 1e push %ds + 101be9: 60 pusha + 101bea: 66 b8 10 00 mov $0x10,%ax + 101bee: 8e d8 mov %eax,%ds + 101bf0: 8e c0 mov %eax,%es + 101bf2: 8e e0 mov %eax,%fs + 101bf4: 8e e8 mov %eax,%gs + 101bf6: 89 e0 mov %esp,%eax + 101bf8: 50 push %eax + +00101bf9 : + 101bf9: b8 04 3e 10 00 mov $0x103e04,%eax + 101bfe: ff d0 call *%eax + 101c00: e9 e3 fa ff ff jmp 1016e8 + +00101c05 : + 101c05: 6a 00 push $0x0 + 101c07: 6a 1f push $0x1f + 101c09: 0f a8 push %gs + 101c0b: 0f a0 push %fs + 101c0d: 06 push %es + 101c0e: 1e push %ds + 101c0f: 60 pusha + 101c10: 66 b8 10 00 mov $0x10,%ax + 101c14: 8e d8 mov %eax,%ds + 101c16: 8e c0 mov %eax,%es + 101c18: 8e e0 mov %eax,%fs + 101c1a: 8e e8 mov %eax,%gs + 101c1c: 89 e0 mov %esp,%eax + 101c1e: 50 push %eax + +00101c1f : + 101c1f: b8 04 3e 10 00 mov $0x103e04,%eax + 101c24: ff d0 call *%eax + 101c26: e9 bd fa ff ff jmp 1016e8 + +00101c2b : + 101c2b: 6a 00 push $0x0 + 101c2d: 6a 20 push $0x20 + 101c2f: 0f a8 push %gs + 101c31: 0f a0 push %fs + 101c33: 06 push %es + 101c34: 1e push %ds + 101c35: 60 pusha + 101c36: 66 b8 10 00 mov $0x10,%ax + 101c3a: 8e d8 mov %eax,%ds + 101c3c: 8e c0 mov %eax,%es + 101c3e: 8e e0 mov %eax,%fs + 101c40: 8e e8 mov %eax,%gs + 101c42: 89 e0 mov %esp,%eax + 101c44: 50 push %eax + +00101c45 : + 101c45: b8 04 3e 10 00 mov $0x103e04,%eax + 101c4a: ff d0 call *%eax + 101c4c: e9 97 fa ff ff jmp 1016e8 + +00101c51 : + 101c51: 6a 00 push $0x0 + 101c53: 6a 21 push $0x21 + 101c55: 0f a8 push %gs + 101c57: 0f a0 push %fs + 101c59: 06 push %es + 101c5a: 1e push %ds + 101c5b: 60 pusha + 101c5c: 66 b8 10 00 mov $0x10,%ax + 101c60: 8e d8 mov %eax,%ds + 101c62: 8e c0 mov %eax,%es + 101c64: 8e e0 mov %eax,%fs + 101c66: 8e e8 mov %eax,%gs + 101c68: 89 e0 mov %esp,%eax + 101c6a: 50 push %eax + +00101c6b : + 101c6b: b8 04 3e 10 00 mov $0x103e04,%eax + 101c70: ff d0 call *%eax + 101c72: e9 71 fa ff ff jmp 1016e8 + +00101c77 : + 101c77: 6a 00 push $0x0 + 101c79: 6a 22 push $0x22 + 101c7b: 0f a8 push %gs + 101c7d: 0f a0 push %fs + 101c7f: 06 push %es + 101c80: 1e push %ds + 101c81: 60 pusha + 101c82: 66 b8 10 00 mov $0x10,%ax + 101c86: 8e d8 mov %eax,%ds + 101c88: 8e c0 mov %eax,%es + 101c8a: 8e e0 mov %eax,%fs + 101c8c: 8e e8 mov %eax,%gs + 101c8e: 89 e0 mov %esp,%eax + 101c90: 50 push %eax + +00101c91 : + 101c91: b8 04 3e 10 00 mov $0x103e04,%eax + 101c96: ff d0 call *%eax + 101c98: e9 4b fa ff ff jmp 1016e8 + +00101c9d : + 101c9d: 6a 00 push $0x0 + 101c9f: 6a 23 push $0x23 + 101ca1: 0f a8 push %gs + 101ca3: 0f a0 push %fs + 101ca5: 06 push %es + 101ca6: 1e push %ds + 101ca7: 60 pusha + 101ca8: 66 b8 10 00 mov $0x10,%ax + 101cac: 8e d8 mov %eax,%ds + 101cae: 8e c0 mov %eax,%es + 101cb0: 8e e0 mov %eax,%fs + 101cb2: 8e e8 mov %eax,%gs + 101cb4: 89 e0 mov %esp,%eax + 101cb6: 50 push %eax + +00101cb7 : + 101cb7: b8 04 3e 10 00 mov $0x103e04,%eax + 101cbc: ff d0 call *%eax + 101cbe: e9 25 fa ff ff jmp 1016e8 + +00101cc3 : + 101cc3: 6a 00 push $0x0 + 101cc5: 6a 24 push $0x24 + 101cc7: 0f a8 push %gs + 101cc9: 0f a0 push %fs + 101ccb: 06 push %es + 101ccc: 1e push %ds + 101ccd: 60 pusha + 101cce: 66 b8 10 00 mov $0x10,%ax + 101cd2: 8e d8 mov %eax,%ds + 101cd4: 8e c0 mov %eax,%es + 101cd6: 8e e0 mov %eax,%fs + 101cd8: 8e e8 mov %eax,%gs + 101cda: 89 e0 mov %esp,%eax + 101cdc: 50 push %eax + +00101cdd : + 101cdd: b8 04 3e 10 00 mov $0x103e04,%eax + 101ce2: ff d0 call *%eax + 101ce4: e9 ff f9 ff ff jmp 1016e8 + +00101ce9 : + 101ce9: 6a 00 push $0x0 + 101ceb: 6a 25 push $0x25 + 101ced: 0f a8 push %gs + 101cef: 0f a0 push %fs + 101cf1: 06 push %es + 101cf2: 1e push %ds + 101cf3: 60 pusha + 101cf4: 66 b8 10 00 mov $0x10,%ax + 101cf8: 8e d8 mov %eax,%ds + 101cfa: 8e c0 mov %eax,%es + 101cfc: 8e e0 mov %eax,%fs + 101cfe: 8e e8 mov %eax,%gs + 101d00: 89 e0 mov %esp,%eax + 101d02: 50 push %eax + +00101d03 : + 101d03: b8 04 3e 10 00 mov $0x103e04,%eax + 101d08: ff d0 call *%eax + 101d0a: e9 d9 f9 ff ff jmp 1016e8 + +00101d0f : + 101d0f: 6a 00 push $0x0 + 101d11: 6a 26 push $0x26 + 101d13: 0f a8 push %gs + 101d15: 0f a0 push %fs + 101d17: 06 push %es + 101d18: 1e push %ds + 101d19: 60 pusha + 101d1a: 66 b8 10 00 mov $0x10,%ax + 101d1e: 8e d8 mov %eax,%ds + 101d20: 8e c0 mov %eax,%es + 101d22: 8e e0 mov %eax,%fs + 101d24: 8e e8 mov %eax,%gs + 101d26: 89 e0 mov %esp,%eax + 101d28: 50 push %eax + +00101d29 : + 101d29: b8 04 3e 10 00 mov $0x103e04,%eax + 101d2e: ff d0 call *%eax + 101d30: e9 b3 f9 ff ff jmp 1016e8 + +00101d35 : + 101d35: 6a 00 push $0x0 + 101d37: 6a 27 push $0x27 + 101d39: 0f a8 push %gs + 101d3b: 0f a0 push %fs + 101d3d: 06 push %es + 101d3e: 1e push %ds + 101d3f: 60 pusha + 101d40: 66 b8 10 00 mov $0x10,%ax + 101d44: 8e d8 mov %eax,%ds + 101d46: 8e c0 mov %eax,%es + 101d48: 8e e0 mov %eax,%fs + 101d4a: 8e e8 mov %eax,%gs + 101d4c: 89 e0 mov %esp,%eax + 101d4e: 50 push %eax + +00101d4f : + 101d4f: b8 04 3e 10 00 mov $0x103e04,%eax + 101d54: ff d0 call *%eax + 101d56: e9 8d f9 ff ff jmp 1016e8 + +00101d5b : + 101d5b: 6a 00 push $0x0 + 101d5d: 6a 28 push $0x28 + 101d5f: 0f a8 push %gs + 101d61: 0f a0 push %fs + 101d63: 06 push %es + 101d64: 1e push %ds + 101d65: 60 pusha + 101d66: 66 b8 10 00 mov $0x10,%ax + 101d6a: 8e d8 mov %eax,%ds + 101d6c: 8e c0 mov %eax,%es + 101d6e: 8e e0 mov %eax,%fs + 101d70: 8e e8 mov %eax,%gs + 101d72: 89 e0 mov %esp,%eax + 101d74: 50 push %eax + +00101d75 : + 101d75: b8 04 3e 10 00 mov $0x103e04,%eax + 101d7a: ff d0 call *%eax + 101d7c: e9 67 f9 ff ff jmp 1016e8 + +00101d81 : + 101d81: 6a 00 push $0x0 + 101d83: 6a 29 push $0x29 + 101d85: 0f a8 push %gs + 101d87: 0f a0 push %fs + 101d89: 06 push %es + 101d8a: 1e push %ds + 101d8b: 60 pusha + 101d8c: 66 b8 10 00 mov $0x10,%ax + 101d90: 8e d8 mov %eax,%ds + 101d92: 8e c0 mov %eax,%es + 101d94: 8e e0 mov %eax,%fs + 101d96: 8e e8 mov %eax,%gs + 101d98: 89 e0 mov %esp,%eax + 101d9a: 50 push %eax + +00101d9b : + 101d9b: b8 04 3e 10 00 mov $0x103e04,%eax + 101da0: ff d0 call *%eax + 101da2: e9 41 f9 ff ff jmp 1016e8 + +00101da7 : + 101da7: 6a 00 push $0x0 + 101da9: 6a 2a push $0x2a + 101dab: 0f a8 push %gs + 101dad: 0f a0 push %fs + 101daf: 06 push %es + 101db0: 1e push %ds + 101db1: 60 pusha + 101db2: 66 b8 10 00 mov $0x10,%ax + 101db6: 8e d8 mov %eax,%ds + 101db8: 8e c0 mov %eax,%es + 101dba: 8e e0 mov %eax,%fs + 101dbc: 8e e8 mov %eax,%gs + 101dbe: 89 e0 mov %esp,%eax + 101dc0: 50 push %eax + +00101dc1 : + 101dc1: b8 04 3e 10 00 mov $0x103e04,%eax + 101dc6: ff d0 call *%eax + 101dc8: e9 1b f9 ff ff jmp 1016e8 + +00101dcd : + 101dcd: 6a 00 push $0x0 + 101dcf: 6a 2b push $0x2b + 101dd1: 0f a8 push %gs + 101dd3: 0f a0 push %fs + 101dd5: 06 push %es + 101dd6: 1e push %ds + 101dd7: 60 pusha + 101dd8: 66 b8 10 00 mov $0x10,%ax + 101ddc: 8e d8 mov %eax,%ds + 101dde: 8e c0 mov %eax,%es + 101de0: 8e e0 mov %eax,%fs + 101de2: 8e e8 mov %eax,%gs + 101de4: 89 e0 mov %esp,%eax + 101de6: 50 push %eax + +00101de7 : + 101de7: b8 04 3e 10 00 mov $0x103e04,%eax + 101dec: ff d0 call *%eax + 101dee: e9 f5 f8 ff ff jmp 1016e8 + +00101df3 : + 101df3: 6a 00 push $0x0 + 101df5: 6a 2c push $0x2c + 101df7: 0f a8 push %gs + 101df9: 0f a0 push %fs + 101dfb: 06 push %es + 101dfc: 1e push %ds + 101dfd: 60 pusha + 101dfe: 66 b8 10 00 mov $0x10,%ax + 101e02: 8e d8 mov %eax,%ds + 101e04: 8e c0 mov %eax,%es + 101e06: 8e e0 mov %eax,%fs + 101e08: 8e e8 mov %eax,%gs + 101e0a: 89 e0 mov %esp,%eax + 101e0c: 50 push %eax + +00101e0d : + 101e0d: b8 04 3e 10 00 mov $0x103e04,%eax + 101e12: ff d0 call *%eax + 101e14: e9 cf f8 ff ff jmp 1016e8 + +00101e19 : + 101e19: 6a 00 push $0x0 + 101e1b: 6a 2d push $0x2d + 101e1d: 0f a8 push %gs + 101e1f: 0f a0 push %fs + 101e21: 06 push %es + 101e22: 1e push %ds + 101e23: 60 pusha + 101e24: 66 b8 10 00 mov $0x10,%ax + 101e28: 8e d8 mov %eax,%ds + 101e2a: 8e c0 mov %eax,%es + 101e2c: 8e e0 mov %eax,%fs + 101e2e: 8e e8 mov %eax,%gs + 101e30: 89 e0 mov %esp,%eax + 101e32: 50 push %eax + +00101e33 : + 101e33: b8 04 3e 10 00 mov $0x103e04,%eax + 101e38: ff d0 call *%eax + 101e3a: e9 a9 f8 ff ff jmp 1016e8 + +00101e3f : + 101e3f: 6a 00 push $0x0 + 101e41: 6a 2e push $0x2e + 101e43: 0f a8 push %gs + 101e45: 0f a0 push %fs + 101e47: 06 push %es + 101e48: 1e push %ds + 101e49: 60 pusha + 101e4a: 66 b8 10 00 mov $0x10,%ax + 101e4e: 8e d8 mov %eax,%ds + 101e50: 8e c0 mov %eax,%es + 101e52: 8e e0 mov %eax,%fs + 101e54: 8e e8 mov %eax,%gs + 101e56: 89 e0 mov %esp,%eax + 101e58: 50 push %eax + +00101e59 : + 101e59: b8 04 3e 10 00 mov $0x103e04,%eax + 101e5e: ff d0 call *%eax + 101e60: e9 83 f8 ff ff jmp 1016e8 + +00101e65 : + 101e65: 6a 00 push $0x0 + 101e67: 6a 2f push $0x2f + 101e69: 0f a8 push %gs + 101e6b: 0f a0 push %fs + 101e6d: 06 push %es + 101e6e: 1e push %ds + 101e6f: 60 pusha + 101e70: 66 b8 10 00 mov $0x10,%ax + 101e74: 8e d8 mov %eax,%ds + 101e76: 8e c0 mov %eax,%es + 101e78: 8e e0 mov %eax,%fs + 101e7a: 8e e8 mov %eax,%gs + 101e7c: 89 e0 mov %esp,%eax + 101e7e: 50 push %eax + +00101e7f : + 101e7f: b8 04 3e 10 00 mov $0x103e04,%eax + 101e84: ff d0 call *%eax + 101e86: e9 5d f8 ff ff jmp 1016e8 + +00101e8b : + 101e8b: 6a 00 push $0x0 + 101e8d: 6a 30 push $0x30 + 101e8f: 0f a8 push %gs + 101e91: 0f a0 push %fs + 101e93: 06 push %es + 101e94: 1e push %ds + 101e95: 60 pusha + 101e96: 66 b8 10 00 mov $0x10,%ax + 101e9a: 8e d8 mov %eax,%ds + 101e9c: 8e c0 mov %eax,%es + 101e9e: 8e e0 mov %eax,%fs + 101ea0: 8e e8 mov %eax,%gs + 101ea2: 89 e0 mov %esp,%eax + 101ea4: 50 push %eax + +00101ea5 : + 101ea5: b8 04 3e 10 00 mov $0x103e04,%eax + 101eaa: ff d0 call *%eax + 101eac: e9 37 f8 ff ff jmp 1016e8 + +00101eb1 : + 101eb1: 6a 00 push $0x0 + 101eb3: 6a 31 push $0x31 + 101eb5: 0f a8 push %gs + 101eb7: 0f a0 push %fs + 101eb9: 06 push %es + 101eba: 1e push %ds + 101ebb: 60 pusha + 101ebc: 66 b8 10 00 mov $0x10,%ax + 101ec0: 8e d8 mov %eax,%ds + 101ec2: 8e c0 mov %eax,%es + 101ec4: 8e e0 mov %eax,%fs + 101ec6: 8e e8 mov %eax,%gs + 101ec8: 89 e0 mov %esp,%eax + 101eca: 50 push %eax + +00101ecb : + 101ecb: b8 04 3e 10 00 mov $0x103e04,%eax + 101ed0: ff d0 call *%eax + 101ed2: e9 11 f8 ff ff jmp 1016e8 + +00101ed7 : + 101ed7: 6a 00 push $0x0 + 101ed9: 6a 32 push $0x32 + 101edb: 0f a8 push %gs + 101edd: 0f a0 push %fs + 101edf: 06 push %es + 101ee0: 1e push %ds + 101ee1: 60 pusha + 101ee2: 66 b8 10 00 mov $0x10,%ax + 101ee6: 8e d8 mov %eax,%ds + 101ee8: 8e c0 mov %eax,%es + 101eea: 8e e0 mov %eax,%fs + 101eec: 8e e8 mov %eax,%gs + 101eee: 89 e0 mov %esp,%eax + 101ef0: 50 push %eax + +00101ef1 : + 101ef1: b8 04 3e 10 00 mov $0x103e04,%eax + 101ef6: ff d0 call *%eax + 101ef8: e9 eb f7 ff ff jmp 1016e8 + +00101efd : + 101efd: 6a 00 push $0x0 + 101eff: 6a 33 push $0x33 + 101f01: 0f a8 push %gs + 101f03: 0f a0 push %fs + 101f05: 06 push %es + 101f06: 1e push %ds + 101f07: 60 pusha + 101f08: 66 b8 10 00 mov $0x10,%ax + 101f0c: 8e d8 mov %eax,%ds + 101f0e: 8e c0 mov %eax,%es + 101f10: 8e e0 mov %eax,%fs + 101f12: 8e e8 mov %eax,%gs + 101f14: 89 e0 mov %esp,%eax + 101f16: 50 push %eax + +00101f17 : + 101f17: b8 04 3e 10 00 mov $0x103e04,%eax + 101f1c: ff d0 call *%eax + 101f1e: e9 c5 f7 ff ff jmp 1016e8 + +00101f23 : + 101f23: 6a 00 push $0x0 + 101f25: 6a 34 push $0x34 + 101f27: 0f a8 push %gs + 101f29: 0f a0 push %fs + 101f2b: 06 push %es + 101f2c: 1e push %ds + 101f2d: 60 pusha + 101f2e: 66 b8 10 00 mov $0x10,%ax + 101f32: 8e d8 mov %eax,%ds + 101f34: 8e c0 mov %eax,%es + 101f36: 8e e0 mov %eax,%fs + 101f38: 8e e8 mov %eax,%gs + 101f3a: 89 e0 mov %esp,%eax + 101f3c: 50 push %eax + +00101f3d : + 101f3d: b8 04 3e 10 00 mov $0x103e04,%eax + 101f42: ff d0 call *%eax + 101f44: e9 9f f7 ff ff jmp 1016e8 + +00101f49 : + 101f49: 6a 00 push $0x0 + 101f4b: 6a 35 push $0x35 + 101f4d: 0f a8 push %gs + 101f4f: 0f a0 push %fs + 101f51: 06 push %es + 101f52: 1e push %ds + 101f53: 60 pusha + 101f54: 66 b8 10 00 mov $0x10,%ax + 101f58: 8e d8 mov %eax,%ds + 101f5a: 8e c0 mov %eax,%es + 101f5c: 8e e0 mov %eax,%fs + 101f5e: 8e e8 mov %eax,%gs + 101f60: 89 e0 mov %esp,%eax + 101f62: 50 push %eax + +00101f63 : + 101f63: b8 04 3e 10 00 mov $0x103e04,%eax + 101f68: ff d0 call *%eax + 101f6a: e9 79 f7 ff ff jmp 1016e8 + +00101f6f : + 101f6f: 6a 00 push $0x0 + 101f71: 6a 36 push $0x36 + 101f73: 0f a8 push %gs + 101f75: 0f a0 push %fs + 101f77: 06 push %es + 101f78: 1e push %ds + 101f79: 60 pusha + 101f7a: 66 b8 10 00 mov $0x10,%ax + 101f7e: 8e d8 mov %eax,%ds + 101f80: 8e c0 mov %eax,%es + 101f82: 8e e0 mov %eax,%fs + 101f84: 8e e8 mov %eax,%gs + 101f86: 89 e0 mov %esp,%eax + 101f88: 50 push %eax + +00101f89 : + 101f89: b8 04 3e 10 00 mov $0x103e04,%eax + 101f8e: ff d0 call *%eax + 101f90: e9 53 f7 ff ff jmp 1016e8 + +00101f95 : + 101f95: 6a 00 push $0x0 + 101f97: 6a 37 push $0x37 + 101f99: 0f a8 push %gs + 101f9b: 0f a0 push %fs + 101f9d: 06 push %es + 101f9e: 1e push %ds + 101f9f: 60 pusha + 101fa0: 66 b8 10 00 mov $0x10,%ax + 101fa4: 8e d8 mov %eax,%ds + 101fa6: 8e c0 mov %eax,%es + 101fa8: 8e e0 mov %eax,%fs + 101faa: 8e e8 mov %eax,%gs + 101fac: 89 e0 mov %esp,%eax + 101fae: 50 push %eax + +00101faf : + 101faf: b8 04 3e 10 00 mov $0x103e04,%eax + 101fb4: ff d0 call *%eax + 101fb6: e9 2d f7 ff ff jmp 1016e8 + +00101fbb : + 101fbb: 6a 00 push $0x0 + 101fbd: 6a 38 push $0x38 + 101fbf: 0f a8 push %gs + 101fc1: 0f a0 push %fs + 101fc3: 06 push %es + 101fc4: 1e push %ds + 101fc5: 60 pusha + 101fc6: 66 b8 10 00 mov $0x10,%ax + 101fca: 8e d8 mov %eax,%ds + 101fcc: 8e c0 mov %eax,%es + 101fce: 8e e0 mov %eax,%fs + 101fd0: 8e e8 mov %eax,%gs + 101fd2: 89 e0 mov %esp,%eax + 101fd4: 50 push %eax + +00101fd5 : + 101fd5: b8 04 3e 10 00 mov $0x103e04,%eax + 101fda: ff d0 call *%eax + 101fdc: e9 07 f7 ff ff jmp 1016e8 + +00101fe1 : + 101fe1: 6a 00 push $0x0 + 101fe3: 6a 39 push $0x39 + 101fe5: 0f a8 push %gs + 101fe7: 0f a0 push %fs + 101fe9: 06 push %es + 101fea: 1e push %ds + 101feb: 60 pusha + 101fec: 66 b8 10 00 mov $0x10,%ax + 101ff0: 8e d8 mov %eax,%ds + 101ff2: 8e c0 mov %eax,%es + 101ff4: 8e e0 mov %eax,%fs + 101ff6: 8e e8 mov %eax,%gs + 101ff8: 89 e0 mov %esp,%eax + 101ffa: 50 push %eax + +00101ffb : + 101ffb: b8 04 3e 10 00 mov $0x103e04,%eax + 102000: ff d0 call *%eax + 102002: e9 e1 f6 ff ff jmp 1016e8 + +00102007 : + 102007: 6a 00 push $0x0 + 102009: 6a 3a push $0x3a + 10200b: 0f a8 push %gs + 10200d: 0f a0 push %fs + 10200f: 06 push %es + 102010: 1e push %ds + 102011: 60 pusha + 102012: 66 b8 10 00 mov $0x10,%ax + 102016: 8e d8 mov %eax,%ds + 102018: 8e c0 mov %eax,%es + 10201a: 8e e0 mov %eax,%fs + 10201c: 8e e8 mov %eax,%gs + 10201e: 89 e0 mov %esp,%eax + 102020: 50 push %eax + +00102021 : + 102021: b8 04 3e 10 00 mov $0x103e04,%eax + 102026: ff d0 call *%eax + 102028: e9 bb f6 ff ff jmp 1016e8 + +0010202d : + 10202d: 6a 00 push $0x0 + 10202f: 6a 3b push $0x3b + 102031: 0f a8 push %gs + 102033: 0f a0 push %fs + 102035: 06 push %es + 102036: 1e push %ds + 102037: 60 pusha + 102038: 66 b8 10 00 mov $0x10,%ax + 10203c: 8e d8 mov %eax,%ds + 10203e: 8e c0 mov %eax,%es + 102040: 8e e0 mov %eax,%fs + 102042: 8e e8 mov %eax,%gs + 102044: 89 e0 mov %esp,%eax + 102046: 50 push %eax + +00102047 : + 102047: b8 04 3e 10 00 mov $0x103e04,%eax + 10204c: ff d0 call *%eax + 10204e: e9 95 f6 ff ff jmp 1016e8 + +00102053 : + 102053: 6a 00 push $0x0 + 102055: 6a 3c push $0x3c + 102057: 0f a8 push %gs + 102059: 0f a0 push %fs + 10205b: 06 push %es + 10205c: 1e push %ds + 10205d: 60 pusha + 10205e: 66 b8 10 00 mov $0x10,%ax + 102062: 8e d8 mov %eax,%ds + 102064: 8e c0 mov %eax,%es + 102066: 8e e0 mov %eax,%fs + 102068: 8e e8 mov %eax,%gs + 10206a: 89 e0 mov %esp,%eax + 10206c: 50 push %eax + +0010206d : + 10206d: b8 04 3e 10 00 mov $0x103e04,%eax + 102072: ff d0 call *%eax + 102074: e9 6f f6 ff ff jmp 1016e8 + +00102079 : + 102079: 6a 00 push $0x0 + 10207b: 6a 3d push $0x3d + 10207d: 0f a8 push %gs + 10207f: 0f a0 push %fs + 102081: 06 push %es + 102082: 1e push %ds + 102083: 60 pusha + 102084: 66 b8 10 00 mov $0x10,%ax + 102088: 8e d8 mov %eax,%ds + 10208a: 8e c0 mov %eax,%es + 10208c: 8e e0 mov %eax,%fs + 10208e: 8e e8 mov %eax,%gs + 102090: 89 e0 mov %esp,%eax + 102092: 50 push %eax + +00102093 : + 102093: b8 04 3e 10 00 mov $0x103e04,%eax + 102098: ff d0 call *%eax + 10209a: e9 49 f6 ff ff jmp 1016e8 + +0010209f : + 10209f: 6a 00 push $0x0 + 1020a1: 6a 3e push $0x3e + 1020a3: 0f a8 push %gs + 1020a5: 0f a0 push %fs + 1020a7: 06 push %es + 1020a8: 1e push %ds + 1020a9: 60 pusha + 1020aa: 66 b8 10 00 mov $0x10,%ax + 1020ae: 8e d8 mov %eax,%ds + 1020b0: 8e c0 mov %eax,%es + 1020b2: 8e e0 mov %eax,%fs + 1020b4: 8e e8 mov %eax,%gs + 1020b6: 89 e0 mov %esp,%eax + 1020b8: 50 push %eax + +001020b9 : + 1020b9: b8 04 3e 10 00 mov $0x103e04,%eax + 1020be: ff d0 call *%eax + 1020c0: e9 23 f6 ff ff jmp 1016e8 + +001020c5 : + 1020c5: 6a 00 push $0x0 + 1020c7: 6a 3f push $0x3f + 1020c9: 0f a8 push %gs + 1020cb: 0f a0 push %fs + 1020cd: 06 push %es + 1020ce: 1e push %ds + 1020cf: 60 pusha + 1020d0: 66 b8 10 00 mov $0x10,%ax + 1020d4: 8e d8 mov %eax,%ds + 1020d6: 8e c0 mov %eax,%es + 1020d8: 8e e0 mov %eax,%fs + 1020da: 8e e8 mov %eax,%gs + 1020dc: 89 e0 mov %esp,%eax + 1020de: 50 push %eax + +001020df : + 1020df: b8 04 3e 10 00 mov $0x103e04,%eax + 1020e4: ff d0 call *%eax + 1020e6: e9 fd f5 ff ff jmp 1016e8 + +001020eb : + 1020eb: 6a 00 push $0x0 + 1020ed: 6a 40 push $0x40 + 1020ef: 0f a8 push %gs + 1020f1: 0f a0 push %fs + 1020f3: 06 push %es + 1020f4: 1e push %ds + 1020f5: 60 pusha + 1020f6: 66 b8 10 00 mov $0x10,%ax + 1020fa: 8e d8 mov %eax,%ds + 1020fc: 8e c0 mov %eax,%es + 1020fe: 8e e0 mov %eax,%fs + 102100: 8e e8 mov %eax,%gs + 102102: 89 e0 mov %esp,%eax + 102104: 50 push %eax + +00102105 : + 102105: b8 04 3e 10 00 mov $0x103e04,%eax + 10210a: ff d0 call *%eax + 10210c: e9 d7 f5 ff ff jmp 1016e8 + +00102111 : + 102111: 6a 00 push $0x0 + 102113: 6a 41 push $0x41 + 102115: 0f a8 push %gs + 102117: 0f a0 push %fs + 102119: 06 push %es + 10211a: 1e push %ds + 10211b: 60 pusha + 10211c: 66 b8 10 00 mov $0x10,%ax + 102120: 8e d8 mov %eax,%ds + 102122: 8e c0 mov %eax,%es + 102124: 8e e0 mov %eax,%fs + 102126: 8e e8 mov %eax,%gs + 102128: 89 e0 mov %esp,%eax + 10212a: 50 push %eax + +0010212b : + 10212b: b8 04 3e 10 00 mov $0x103e04,%eax + 102130: ff d0 call *%eax + 102132: e9 b1 f5 ff ff jmp 1016e8 + +00102137 : + 102137: 6a 00 push $0x0 + 102139: 6a 42 push $0x42 + 10213b: 0f a8 push %gs + 10213d: 0f a0 push %fs + 10213f: 06 push %es + 102140: 1e push %ds + 102141: 60 pusha + 102142: 66 b8 10 00 mov $0x10,%ax + 102146: 8e d8 mov %eax,%ds + 102148: 8e c0 mov %eax,%es + 10214a: 8e e0 mov %eax,%fs + 10214c: 8e e8 mov %eax,%gs + 10214e: 89 e0 mov %esp,%eax + 102150: 50 push %eax + +00102151 : + 102151: b8 04 3e 10 00 mov $0x103e04,%eax + 102156: ff d0 call *%eax + 102158: e9 8b f5 ff ff jmp 1016e8 + +0010215d : + 10215d: 6a 00 push $0x0 + 10215f: 6a 43 push $0x43 + 102161: 0f a8 push %gs + 102163: 0f a0 push %fs + 102165: 06 push %es + 102166: 1e push %ds + 102167: 60 pusha + 102168: 66 b8 10 00 mov $0x10,%ax + 10216c: 8e d8 mov %eax,%ds + 10216e: 8e c0 mov %eax,%es + 102170: 8e e0 mov %eax,%fs + 102172: 8e e8 mov %eax,%gs + 102174: 89 e0 mov %esp,%eax + 102176: 50 push %eax + +00102177 : + 102177: b8 04 3e 10 00 mov $0x103e04,%eax + 10217c: ff d0 call *%eax + 10217e: e9 65 f5 ff ff jmp 1016e8 + +00102183 : + 102183: 6a 00 push $0x0 + 102185: 6a 44 push $0x44 + 102187: 0f a8 push %gs + 102189: 0f a0 push %fs + 10218b: 06 push %es + 10218c: 1e push %ds + 10218d: 60 pusha + 10218e: 66 b8 10 00 mov $0x10,%ax + 102192: 8e d8 mov %eax,%ds + 102194: 8e c0 mov %eax,%es + 102196: 8e e0 mov %eax,%fs + 102198: 8e e8 mov %eax,%gs + 10219a: 89 e0 mov %esp,%eax + 10219c: 50 push %eax + +0010219d : + 10219d: b8 04 3e 10 00 mov $0x103e04,%eax + 1021a2: ff d0 call *%eax + 1021a4: e9 3f f5 ff ff jmp 1016e8 + +001021a9 : + 1021a9: 6a 00 push $0x0 + 1021ab: 6a 45 push $0x45 + 1021ad: 0f a8 push %gs + 1021af: 0f a0 push %fs + 1021b1: 06 push %es + 1021b2: 1e push %ds + 1021b3: 60 pusha + 1021b4: 66 b8 10 00 mov $0x10,%ax + 1021b8: 8e d8 mov %eax,%ds + 1021ba: 8e c0 mov %eax,%es + 1021bc: 8e e0 mov %eax,%fs + 1021be: 8e e8 mov %eax,%gs + 1021c0: 89 e0 mov %esp,%eax + 1021c2: 50 push %eax + +001021c3 : + 1021c3: b8 04 3e 10 00 mov $0x103e04,%eax + 1021c8: ff d0 call *%eax + 1021ca: e9 19 f5 ff ff jmp 1016e8 + +001021cf : + 1021cf: 6a 00 push $0x0 + 1021d1: 6a 46 push $0x46 + 1021d3: 0f a8 push %gs + 1021d5: 0f a0 push %fs + 1021d7: 06 push %es + 1021d8: 1e push %ds + 1021d9: 60 pusha + 1021da: 66 b8 10 00 mov $0x10,%ax + 1021de: 8e d8 mov %eax,%ds + 1021e0: 8e c0 mov %eax,%es + 1021e2: 8e e0 mov %eax,%fs + 1021e4: 8e e8 mov %eax,%gs + 1021e6: 89 e0 mov %esp,%eax + 1021e8: 50 push %eax + +001021e9 : + 1021e9: b8 04 3e 10 00 mov $0x103e04,%eax + 1021ee: ff d0 call *%eax + 1021f0: e9 f3 f4 ff ff jmp 1016e8 + +001021f5 : + 1021f5: 6a 00 push $0x0 + 1021f7: 6a 47 push $0x47 + 1021f9: 0f a8 push %gs + 1021fb: 0f a0 push %fs + 1021fd: 06 push %es + 1021fe: 1e push %ds + 1021ff: 60 pusha + 102200: 66 b8 10 00 mov $0x10,%ax + 102204: 8e d8 mov %eax,%ds + 102206: 8e c0 mov %eax,%es + 102208: 8e e0 mov %eax,%fs + 10220a: 8e e8 mov %eax,%gs + 10220c: 89 e0 mov %esp,%eax + 10220e: 50 push %eax + +0010220f : + 10220f: b8 04 3e 10 00 mov $0x103e04,%eax + 102214: ff d0 call *%eax + 102216: e9 cd f4 ff ff jmp 1016e8 + +0010221b : + 10221b: 6a 00 push $0x0 + 10221d: 6a 48 push $0x48 + 10221f: 0f a8 push %gs + 102221: 0f a0 push %fs + 102223: 06 push %es + 102224: 1e push %ds + 102225: 60 pusha + 102226: 66 b8 10 00 mov $0x10,%ax + 10222a: 8e d8 mov %eax,%ds + 10222c: 8e c0 mov %eax,%es + 10222e: 8e e0 mov %eax,%fs + 102230: 8e e8 mov %eax,%gs + 102232: 89 e0 mov %esp,%eax + 102234: 50 push %eax + +00102235 : + 102235: b8 04 3e 10 00 mov $0x103e04,%eax + 10223a: ff d0 call *%eax + 10223c: e9 a7 f4 ff ff jmp 1016e8 + +00102241 : + 102241: 6a 00 push $0x0 + 102243: 6a 49 push $0x49 + 102245: 0f a8 push %gs + 102247: 0f a0 push %fs + 102249: 06 push %es + 10224a: 1e push %ds + 10224b: 60 pusha + 10224c: 66 b8 10 00 mov $0x10,%ax + 102250: 8e d8 mov %eax,%ds + 102252: 8e c0 mov %eax,%es + 102254: 8e e0 mov %eax,%fs + 102256: 8e e8 mov %eax,%gs + 102258: 89 e0 mov %esp,%eax + 10225a: 50 push %eax + +0010225b : + 10225b: b8 04 3e 10 00 mov $0x103e04,%eax + 102260: ff d0 call *%eax + 102262: e9 81 f4 ff ff jmp 1016e8 + +00102267 : + 102267: 6a 00 push $0x0 + 102269: 6a 4a push $0x4a + 10226b: 0f a8 push %gs + 10226d: 0f a0 push %fs + 10226f: 06 push %es + 102270: 1e push %ds + 102271: 60 pusha + 102272: 66 b8 10 00 mov $0x10,%ax + 102276: 8e d8 mov %eax,%ds + 102278: 8e c0 mov %eax,%es + 10227a: 8e e0 mov %eax,%fs + 10227c: 8e e8 mov %eax,%gs + 10227e: 89 e0 mov %esp,%eax + 102280: 50 push %eax + +00102281 : + 102281: b8 04 3e 10 00 mov $0x103e04,%eax + 102286: ff d0 call *%eax + 102288: e9 5b f4 ff ff jmp 1016e8 + +0010228d : + 10228d: 6a 00 push $0x0 + 10228f: 6a 4b push $0x4b + 102291: 0f a8 push %gs + 102293: 0f a0 push %fs + 102295: 06 push %es + 102296: 1e push %ds + 102297: 60 pusha + 102298: 66 b8 10 00 mov $0x10,%ax + 10229c: 8e d8 mov %eax,%ds + 10229e: 8e c0 mov %eax,%es + 1022a0: 8e e0 mov %eax,%fs + 1022a2: 8e e8 mov %eax,%gs + 1022a4: 89 e0 mov %esp,%eax + 1022a6: 50 push %eax + +001022a7 : + 1022a7: b8 04 3e 10 00 mov $0x103e04,%eax + 1022ac: ff d0 call *%eax + 1022ae: e9 35 f4 ff ff jmp 1016e8 + +001022b3 : + 1022b3: 6a 00 push $0x0 + 1022b5: 6a 4c push $0x4c + 1022b7: 0f a8 push %gs + 1022b9: 0f a0 push %fs + 1022bb: 06 push %es + 1022bc: 1e push %ds + 1022bd: 60 pusha + 1022be: 66 b8 10 00 mov $0x10,%ax + 1022c2: 8e d8 mov %eax,%ds + 1022c4: 8e c0 mov %eax,%es + 1022c6: 8e e0 mov %eax,%fs + 1022c8: 8e e8 mov %eax,%gs + 1022ca: 89 e0 mov %esp,%eax + 1022cc: 50 push %eax + +001022cd : + 1022cd: b8 04 3e 10 00 mov $0x103e04,%eax + 1022d2: ff d0 call *%eax + 1022d4: e9 0f f4 ff ff jmp 1016e8 + +001022d9 : + 1022d9: 6a 00 push $0x0 + 1022db: 6a 4d push $0x4d + 1022dd: 0f a8 push %gs + 1022df: 0f a0 push %fs + 1022e1: 06 push %es + 1022e2: 1e push %ds + 1022e3: 60 pusha + 1022e4: 66 b8 10 00 mov $0x10,%ax + 1022e8: 8e d8 mov %eax,%ds + 1022ea: 8e c0 mov %eax,%es + 1022ec: 8e e0 mov %eax,%fs + 1022ee: 8e e8 mov %eax,%gs + 1022f0: 89 e0 mov %esp,%eax + 1022f2: 50 push %eax + +001022f3 : + 1022f3: b8 04 3e 10 00 mov $0x103e04,%eax + 1022f8: ff d0 call *%eax + 1022fa: e9 e9 f3 ff ff jmp 1016e8 + +001022ff : + 1022ff: 6a 00 push $0x0 + 102301: 6a 4e push $0x4e + 102303: 0f a8 push %gs + 102305: 0f a0 push %fs + 102307: 06 push %es + 102308: 1e push %ds + 102309: 60 pusha + 10230a: 66 b8 10 00 mov $0x10,%ax + 10230e: 8e d8 mov %eax,%ds + 102310: 8e c0 mov %eax,%es + 102312: 8e e0 mov %eax,%fs + 102314: 8e e8 mov %eax,%gs + 102316: 89 e0 mov %esp,%eax + 102318: 50 push %eax + +00102319 : + 102319: b8 04 3e 10 00 mov $0x103e04,%eax + 10231e: ff d0 call *%eax + 102320: e9 c3 f3 ff ff jmp 1016e8 + +00102325 : + 102325: 6a 00 push $0x0 + 102327: 6a 4f push $0x4f + 102329: 0f a8 push %gs + 10232b: 0f a0 push %fs + 10232d: 06 push %es + 10232e: 1e push %ds + 10232f: 60 pusha + 102330: 66 b8 10 00 mov $0x10,%ax + 102334: 8e d8 mov %eax,%ds + 102336: 8e c0 mov %eax,%es + 102338: 8e e0 mov %eax,%fs + 10233a: 8e e8 mov %eax,%gs + 10233c: 89 e0 mov %esp,%eax + 10233e: 50 push %eax + +0010233f : + 10233f: b8 04 3e 10 00 mov $0x103e04,%eax + 102344: ff d0 call *%eax + 102346: e9 9d f3 ff ff jmp 1016e8 + +0010234b : + 10234b: 6a 00 push $0x0 + 10234d: 6a 50 push $0x50 + 10234f: 0f a8 push %gs + 102351: 0f a0 push %fs + 102353: 06 push %es + 102354: 1e push %ds + 102355: 60 pusha + 102356: 66 b8 10 00 mov $0x10,%ax + 10235a: 8e d8 mov %eax,%ds + 10235c: 8e c0 mov %eax,%es + 10235e: 8e e0 mov %eax,%fs + 102360: 8e e8 mov %eax,%gs + 102362: 89 e0 mov %esp,%eax + 102364: 50 push %eax + +00102365 : + 102365: b8 04 3e 10 00 mov $0x103e04,%eax + 10236a: ff d0 call *%eax + 10236c: e9 77 f3 ff ff jmp 1016e8 + +00102371 : + 102371: 6a 00 push $0x0 + 102373: 6a 51 push $0x51 + 102375: 0f a8 push %gs + 102377: 0f a0 push %fs + 102379: 06 push %es + 10237a: 1e push %ds + 10237b: 60 pusha + 10237c: 66 b8 10 00 mov $0x10,%ax + 102380: 8e d8 mov %eax,%ds + 102382: 8e c0 mov %eax,%es + 102384: 8e e0 mov %eax,%fs + 102386: 8e e8 mov %eax,%gs + 102388: 89 e0 mov %esp,%eax + 10238a: 50 push %eax + +0010238b : + 10238b: b8 04 3e 10 00 mov $0x103e04,%eax + 102390: ff d0 call *%eax + 102392: e9 51 f3 ff ff jmp 1016e8 + +00102397 : + 102397: 6a 00 push $0x0 + 102399: 6a 52 push $0x52 + 10239b: 0f a8 push %gs + 10239d: 0f a0 push %fs + 10239f: 06 push %es + 1023a0: 1e push %ds + 1023a1: 60 pusha + 1023a2: 66 b8 10 00 mov $0x10,%ax + 1023a6: 8e d8 mov %eax,%ds + 1023a8: 8e c0 mov %eax,%es + 1023aa: 8e e0 mov %eax,%fs + 1023ac: 8e e8 mov %eax,%gs + 1023ae: 89 e0 mov %esp,%eax + 1023b0: 50 push %eax + +001023b1 : + 1023b1: b8 04 3e 10 00 mov $0x103e04,%eax + 1023b6: ff d0 call *%eax + 1023b8: e9 2b f3 ff ff jmp 1016e8 + +001023bd : + 1023bd: 6a 00 push $0x0 + 1023bf: 6a 53 push $0x53 + 1023c1: 0f a8 push %gs + 1023c3: 0f a0 push %fs + 1023c5: 06 push %es + 1023c6: 1e push %ds + 1023c7: 60 pusha + 1023c8: 66 b8 10 00 mov $0x10,%ax + 1023cc: 8e d8 mov %eax,%ds + 1023ce: 8e c0 mov %eax,%es + 1023d0: 8e e0 mov %eax,%fs + 1023d2: 8e e8 mov %eax,%gs + 1023d4: 89 e0 mov %esp,%eax + 1023d6: 50 push %eax + +001023d7 : + 1023d7: b8 04 3e 10 00 mov $0x103e04,%eax + 1023dc: ff d0 call *%eax + 1023de: e9 05 f3 ff ff jmp 1016e8 + +001023e3 : + 1023e3: 6a 00 push $0x0 + 1023e5: 6a 54 push $0x54 + 1023e7: 0f a8 push %gs + 1023e9: 0f a0 push %fs + 1023eb: 06 push %es + 1023ec: 1e push %ds + 1023ed: 60 pusha + 1023ee: 66 b8 10 00 mov $0x10,%ax + 1023f2: 8e d8 mov %eax,%ds + 1023f4: 8e c0 mov %eax,%es + 1023f6: 8e e0 mov %eax,%fs + 1023f8: 8e e8 mov %eax,%gs + 1023fa: 89 e0 mov %esp,%eax + 1023fc: 50 push %eax + +001023fd : + 1023fd: b8 04 3e 10 00 mov $0x103e04,%eax + 102402: ff d0 call *%eax + 102404: e9 df f2 ff ff jmp 1016e8 + +00102409 : + 102409: 6a 00 push $0x0 + 10240b: 6a 55 push $0x55 + 10240d: 0f a8 push %gs + 10240f: 0f a0 push %fs + 102411: 06 push %es + 102412: 1e push %ds + 102413: 60 pusha + 102414: 66 b8 10 00 mov $0x10,%ax + 102418: 8e d8 mov %eax,%ds + 10241a: 8e c0 mov %eax,%es + 10241c: 8e e0 mov %eax,%fs + 10241e: 8e e8 mov %eax,%gs + 102420: 89 e0 mov %esp,%eax + 102422: 50 push %eax + +00102423 : + 102423: b8 04 3e 10 00 mov $0x103e04,%eax + 102428: ff d0 call *%eax + 10242a: e9 b9 f2 ff ff jmp 1016e8 + +0010242f : + 10242f: 6a 00 push $0x0 + 102431: 6a 56 push $0x56 + 102433: 0f a8 push %gs + 102435: 0f a0 push %fs + 102437: 06 push %es + 102438: 1e push %ds + 102439: 60 pusha + 10243a: 66 b8 10 00 mov $0x10,%ax + 10243e: 8e d8 mov %eax,%ds + 102440: 8e c0 mov %eax,%es + 102442: 8e e0 mov %eax,%fs + 102444: 8e e8 mov %eax,%gs + 102446: 89 e0 mov %esp,%eax + 102448: 50 push %eax + +00102449 : + 102449: b8 04 3e 10 00 mov $0x103e04,%eax + 10244e: ff d0 call *%eax + 102450: e9 93 f2 ff ff jmp 1016e8 + +00102455 : + 102455: 6a 00 push $0x0 + 102457: 6a 57 push $0x57 + 102459: 0f a8 push %gs + 10245b: 0f a0 push %fs + 10245d: 06 push %es + 10245e: 1e push %ds + 10245f: 60 pusha + 102460: 66 b8 10 00 mov $0x10,%ax + 102464: 8e d8 mov %eax,%ds + 102466: 8e c0 mov %eax,%es + 102468: 8e e0 mov %eax,%fs + 10246a: 8e e8 mov %eax,%gs + 10246c: 89 e0 mov %esp,%eax + 10246e: 50 push %eax + +0010246f : + 10246f: b8 04 3e 10 00 mov $0x103e04,%eax + 102474: ff d0 call *%eax + 102476: e9 6d f2 ff ff jmp 1016e8 + +0010247b : + 10247b: 6a 00 push $0x0 + 10247d: 6a 58 push $0x58 + 10247f: 0f a8 push %gs + 102481: 0f a0 push %fs + 102483: 06 push %es + 102484: 1e push %ds + 102485: 60 pusha + 102486: 66 b8 10 00 mov $0x10,%ax + 10248a: 8e d8 mov %eax,%ds + 10248c: 8e c0 mov %eax,%es + 10248e: 8e e0 mov %eax,%fs + 102490: 8e e8 mov %eax,%gs + 102492: 89 e0 mov %esp,%eax + 102494: 50 push %eax + +00102495 : + 102495: b8 04 3e 10 00 mov $0x103e04,%eax + 10249a: ff d0 call *%eax + 10249c: e9 47 f2 ff ff jmp 1016e8 + +001024a1 : + 1024a1: 6a 00 push $0x0 + 1024a3: 6a 59 push $0x59 + 1024a5: 0f a8 push %gs + 1024a7: 0f a0 push %fs + 1024a9: 06 push %es + 1024aa: 1e push %ds + 1024ab: 60 pusha + 1024ac: 66 b8 10 00 mov $0x10,%ax + 1024b0: 8e d8 mov %eax,%ds + 1024b2: 8e c0 mov %eax,%es + 1024b4: 8e e0 mov %eax,%fs + 1024b6: 8e e8 mov %eax,%gs + 1024b8: 89 e0 mov %esp,%eax + 1024ba: 50 push %eax + +001024bb : + 1024bb: b8 04 3e 10 00 mov $0x103e04,%eax + 1024c0: ff d0 call *%eax + 1024c2: e9 21 f2 ff ff jmp 1016e8 + +001024c7 : + 1024c7: 6a 00 push $0x0 + 1024c9: 6a 5a push $0x5a + 1024cb: 0f a8 push %gs + 1024cd: 0f a0 push %fs + 1024cf: 06 push %es + 1024d0: 1e push %ds + 1024d1: 60 pusha + 1024d2: 66 b8 10 00 mov $0x10,%ax + 1024d6: 8e d8 mov %eax,%ds + 1024d8: 8e c0 mov %eax,%es + 1024da: 8e e0 mov %eax,%fs + 1024dc: 8e e8 mov %eax,%gs + 1024de: 89 e0 mov %esp,%eax + 1024e0: 50 push %eax + +001024e1 : + 1024e1: b8 04 3e 10 00 mov $0x103e04,%eax + 1024e6: ff d0 call *%eax + 1024e8: e9 fb f1 ff ff jmp 1016e8 + +001024ed : + 1024ed: 6a 00 push $0x0 + 1024ef: 6a 5b push $0x5b + 1024f1: 0f a8 push %gs + 1024f3: 0f a0 push %fs + 1024f5: 06 push %es + 1024f6: 1e push %ds + 1024f7: 60 pusha + 1024f8: 66 b8 10 00 mov $0x10,%ax + 1024fc: 8e d8 mov %eax,%ds + 1024fe: 8e c0 mov %eax,%es + 102500: 8e e0 mov %eax,%fs + 102502: 8e e8 mov %eax,%gs + 102504: 89 e0 mov %esp,%eax + 102506: 50 push %eax + +00102507 : + 102507: b8 04 3e 10 00 mov $0x103e04,%eax + 10250c: ff d0 call *%eax + 10250e: e9 d5 f1 ff ff jmp 1016e8 + +00102513 : + 102513: 6a 00 push $0x0 + 102515: 6a 5c push $0x5c + 102517: 0f a8 push %gs + 102519: 0f a0 push %fs + 10251b: 06 push %es + 10251c: 1e push %ds + 10251d: 60 pusha + 10251e: 66 b8 10 00 mov $0x10,%ax + 102522: 8e d8 mov %eax,%ds + 102524: 8e c0 mov %eax,%es + 102526: 8e e0 mov %eax,%fs + 102528: 8e e8 mov %eax,%gs + 10252a: 89 e0 mov %esp,%eax + 10252c: 50 push %eax + +0010252d : + 10252d: b8 04 3e 10 00 mov $0x103e04,%eax + 102532: ff d0 call *%eax + 102534: e9 af f1 ff ff jmp 1016e8 + +00102539 : + 102539: 6a 00 push $0x0 + 10253b: 6a 5d push $0x5d + 10253d: 0f a8 push %gs + 10253f: 0f a0 push %fs + 102541: 06 push %es + 102542: 1e push %ds + 102543: 60 pusha + 102544: 66 b8 10 00 mov $0x10,%ax + 102548: 8e d8 mov %eax,%ds + 10254a: 8e c0 mov %eax,%es + 10254c: 8e e0 mov %eax,%fs + 10254e: 8e e8 mov %eax,%gs + 102550: 89 e0 mov %esp,%eax + 102552: 50 push %eax + +00102553 : + 102553: b8 04 3e 10 00 mov $0x103e04,%eax + 102558: ff d0 call *%eax + 10255a: e9 89 f1 ff ff jmp 1016e8 + +0010255f : + 10255f: 6a 00 push $0x0 + 102561: 6a 5e push $0x5e + 102563: 0f a8 push %gs + 102565: 0f a0 push %fs + 102567: 06 push %es + 102568: 1e push %ds + 102569: 60 pusha + 10256a: 66 b8 10 00 mov $0x10,%ax + 10256e: 8e d8 mov %eax,%ds + 102570: 8e c0 mov %eax,%es + 102572: 8e e0 mov %eax,%fs + 102574: 8e e8 mov %eax,%gs + 102576: 89 e0 mov %esp,%eax + 102578: 50 push %eax + +00102579 : + 102579: b8 04 3e 10 00 mov $0x103e04,%eax + 10257e: ff d0 call *%eax + 102580: e9 63 f1 ff ff jmp 1016e8 + +00102585 : + 102585: 6a 00 push $0x0 + 102587: 6a 5f push $0x5f + 102589: 0f a8 push %gs + 10258b: 0f a0 push %fs + 10258d: 06 push %es + 10258e: 1e push %ds + 10258f: 60 pusha + 102590: 66 b8 10 00 mov $0x10,%ax + 102594: 8e d8 mov %eax,%ds + 102596: 8e c0 mov %eax,%es + 102598: 8e e0 mov %eax,%fs + 10259a: 8e e8 mov %eax,%gs + 10259c: 89 e0 mov %esp,%eax + 10259e: 50 push %eax + +0010259f : + 10259f: b8 04 3e 10 00 mov $0x103e04,%eax + 1025a4: ff d0 call *%eax + 1025a6: e9 3d f1 ff ff jmp 1016e8 + +001025ab : + 1025ab: 6a 00 push $0x0 + 1025ad: 6a 60 push $0x60 + 1025af: 0f a8 push %gs + 1025b1: 0f a0 push %fs + 1025b3: 06 push %es + 1025b4: 1e push %ds + 1025b5: 60 pusha + 1025b6: 66 b8 10 00 mov $0x10,%ax + 1025ba: 8e d8 mov %eax,%ds + 1025bc: 8e c0 mov %eax,%es + 1025be: 8e e0 mov %eax,%fs + 1025c0: 8e e8 mov %eax,%gs + 1025c2: 89 e0 mov %esp,%eax + 1025c4: 50 push %eax + +001025c5 : + 1025c5: b8 04 3e 10 00 mov $0x103e04,%eax + 1025ca: ff d0 call *%eax + 1025cc: e9 17 f1 ff ff jmp 1016e8 + +001025d1 : + 1025d1: 6a 00 push $0x0 + 1025d3: 6a 61 push $0x61 + 1025d5: 0f a8 push %gs + 1025d7: 0f a0 push %fs + 1025d9: 06 push %es + 1025da: 1e push %ds + 1025db: 60 pusha + 1025dc: 66 b8 10 00 mov $0x10,%ax + 1025e0: 8e d8 mov %eax,%ds + 1025e2: 8e c0 mov %eax,%es + 1025e4: 8e e0 mov %eax,%fs + 1025e6: 8e e8 mov %eax,%gs + 1025e8: 89 e0 mov %esp,%eax + 1025ea: 50 push %eax + +001025eb : + 1025eb: b8 04 3e 10 00 mov $0x103e04,%eax + 1025f0: ff d0 call *%eax + 1025f2: e9 f1 f0 ff ff jmp 1016e8 + +001025f7 : + 1025f7: 6a 00 push $0x0 + 1025f9: 6a 62 push $0x62 + 1025fb: 0f a8 push %gs + 1025fd: 0f a0 push %fs + 1025ff: 06 push %es + 102600: 1e push %ds + 102601: 60 pusha + 102602: 66 b8 10 00 mov $0x10,%ax + 102606: 8e d8 mov %eax,%ds + 102608: 8e c0 mov %eax,%es + 10260a: 8e e0 mov %eax,%fs + 10260c: 8e e8 mov %eax,%gs + 10260e: 89 e0 mov %esp,%eax + 102610: 50 push %eax + +00102611 : + 102611: b8 04 3e 10 00 mov $0x103e04,%eax + 102616: ff d0 call *%eax + 102618: e9 cb f0 ff ff jmp 1016e8 + +0010261d : + 10261d: 6a 00 push $0x0 + 10261f: 6a 63 push $0x63 + 102621: 0f a8 push %gs + 102623: 0f a0 push %fs + 102625: 06 push %es + 102626: 1e push %ds + 102627: 60 pusha + 102628: 66 b8 10 00 mov $0x10,%ax + 10262c: 8e d8 mov %eax,%ds + 10262e: 8e c0 mov %eax,%es + 102630: 8e e0 mov %eax,%fs + 102632: 8e e8 mov %eax,%gs + 102634: 89 e0 mov %esp,%eax + 102636: 50 push %eax + +00102637 : + 102637: b8 04 3e 10 00 mov $0x103e04,%eax + 10263c: ff d0 call *%eax + 10263e: e9 a5 f0 ff ff jmp 1016e8 + +00102643 : + 102643: 6a 00 push $0x0 + 102645: 6a 64 push $0x64 + 102647: 0f a8 push %gs + 102649: 0f a0 push %fs + 10264b: 06 push %es + 10264c: 1e push %ds + 10264d: 60 pusha + 10264e: 66 b8 10 00 mov $0x10,%ax + 102652: 8e d8 mov %eax,%ds + 102654: 8e c0 mov %eax,%es + 102656: 8e e0 mov %eax,%fs + 102658: 8e e8 mov %eax,%gs + 10265a: 89 e0 mov %esp,%eax + 10265c: 50 push %eax + +0010265d : + 10265d: b8 04 3e 10 00 mov $0x103e04,%eax + 102662: ff d0 call *%eax + 102664: e9 7f f0 ff ff jmp 1016e8 + +00102669 : + 102669: 6a 00 push $0x0 + 10266b: 6a 65 push $0x65 + 10266d: 0f a8 push %gs + 10266f: 0f a0 push %fs + 102671: 06 push %es + 102672: 1e push %ds + 102673: 60 pusha + 102674: 66 b8 10 00 mov $0x10,%ax + 102678: 8e d8 mov %eax,%ds + 10267a: 8e c0 mov %eax,%es + 10267c: 8e e0 mov %eax,%fs + 10267e: 8e e8 mov %eax,%gs + 102680: 89 e0 mov %esp,%eax + 102682: 50 push %eax + +00102683 : + 102683: b8 04 3e 10 00 mov $0x103e04,%eax + 102688: ff d0 call *%eax + 10268a: e9 59 f0 ff ff jmp 1016e8 + +0010268f : + 10268f: 6a 00 push $0x0 + 102691: 6a 66 push $0x66 + 102693: 0f a8 push %gs + 102695: 0f a0 push %fs + 102697: 06 push %es + 102698: 1e push %ds + 102699: 60 pusha + 10269a: 66 b8 10 00 mov $0x10,%ax + 10269e: 8e d8 mov %eax,%ds + 1026a0: 8e c0 mov %eax,%es + 1026a2: 8e e0 mov %eax,%fs + 1026a4: 8e e8 mov %eax,%gs + 1026a6: 89 e0 mov %esp,%eax + 1026a8: 50 push %eax + +001026a9 : + 1026a9: b8 04 3e 10 00 mov $0x103e04,%eax + 1026ae: ff d0 call *%eax + 1026b0: e9 33 f0 ff ff jmp 1016e8 + +001026b5 : + 1026b5: 6a 00 push $0x0 + 1026b7: 6a 67 push $0x67 + 1026b9: 0f a8 push %gs + 1026bb: 0f a0 push %fs + 1026bd: 06 push %es + 1026be: 1e push %ds + 1026bf: 60 pusha + 1026c0: 66 b8 10 00 mov $0x10,%ax + 1026c4: 8e d8 mov %eax,%ds + 1026c6: 8e c0 mov %eax,%es + 1026c8: 8e e0 mov %eax,%fs + 1026ca: 8e e8 mov %eax,%gs + 1026cc: 89 e0 mov %esp,%eax + 1026ce: 50 push %eax + +001026cf : + 1026cf: b8 04 3e 10 00 mov $0x103e04,%eax + 1026d4: ff d0 call *%eax + 1026d6: e9 0d f0 ff ff jmp 1016e8 + +001026db : + 1026db: 6a 00 push $0x0 + 1026dd: 6a 68 push $0x68 + 1026df: 0f a8 push %gs + 1026e1: 0f a0 push %fs + 1026e3: 06 push %es + 1026e4: 1e push %ds + 1026e5: 60 pusha + 1026e6: 66 b8 10 00 mov $0x10,%ax + 1026ea: 8e d8 mov %eax,%ds + 1026ec: 8e c0 mov %eax,%es + 1026ee: 8e e0 mov %eax,%fs + 1026f0: 8e e8 mov %eax,%gs + 1026f2: 89 e0 mov %esp,%eax + 1026f4: 50 push %eax + +001026f5 : + 1026f5: b8 04 3e 10 00 mov $0x103e04,%eax + 1026fa: ff d0 call *%eax + 1026fc: e9 e7 ef ff ff jmp 1016e8 + +00102701 : + 102701: 6a 00 push $0x0 + 102703: 6a 69 push $0x69 + 102705: 0f a8 push %gs + 102707: 0f a0 push %fs + 102709: 06 push %es + 10270a: 1e push %ds + 10270b: 60 pusha + 10270c: 66 b8 10 00 mov $0x10,%ax + 102710: 8e d8 mov %eax,%ds + 102712: 8e c0 mov %eax,%es + 102714: 8e e0 mov %eax,%fs + 102716: 8e e8 mov %eax,%gs + 102718: 89 e0 mov %esp,%eax + 10271a: 50 push %eax + +0010271b : + 10271b: b8 04 3e 10 00 mov $0x103e04,%eax + 102720: ff d0 call *%eax + 102722: e9 c1 ef ff ff jmp 1016e8 + +00102727 : + 102727: 6a 00 push $0x0 + 102729: 6a 6a push $0x6a + 10272b: 0f a8 push %gs + 10272d: 0f a0 push %fs + 10272f: 06 push %es + 102730: 1e push %ds + 102731: 60 pusha + 102732: 66 b8 10 00 mov $0x10,%ax + 102736: 8e d8 mov %eax,%ds + 102738: 8e c0 mov %eax,%es + 10273a: 8e e0 mov %eax,%fs + 10273c: 8e e8 mov %eax,%gs + 10273e: 89 e0 mov %esp,%eax + 102740: 50 push %eax + +00102741 : + 102741: b8 04 3e 10 00 mov $0x103e04,%eax + 102746: ff d0 call *%eax + 102748: e9 9b ef ff ff jmp 1016e8 + +0010274d : + 10274d: 6a 00 push $0x0 + 10274f: 6a 6b push $0x6b + 102751: 0f a8 push %gs + 102753: 0f a0 push %fs + 102755: 06 push %es + 102756: 1e push %ds + 102757: 60 pusha + 102758: 66 b8 10 00 mov $0x10,%ax + 10275c: 8e d8 mov %eax,%ds + 10275e: 8e c0 mov %eax,%es + 102760: 8e e0 mov %eax,%fs + 102762: 8e e8 mov %eax,%gs + 102764: 89 e0 mov %esp,%eax + 102766: 50 push %eax + +00102767 : + 102767: b8 04 3e 10 00 mov $0x103e04,%eax + 10276c: ff d0 call *%eax + 10276e: e9 75 ef ff ff jmp 1016e8 + +00102773 : + 102773: 6a 00 push $0x0 + 102775: 6a 6c push $0x6c + 102777: 0f a8 push %gs + 102779: 0f a0 push %fs + 10277b: 06 push %es + 10277c: 1e push %ds + 10277d: 60 pusha + 10277e: 66 b8 10 00 mov $0x10,%ax + 102782: 8e d8 mov %eax,%ds + 102784: 8e c0 mov %eax,%es + 102786: 8e e0 mov %eax,%fs + 102788: 8e e8 mov %eax,%gs + 10278a: 89 e0 mov %esp,%eax + 10278c: 50 push %eax + +0010278d : + 10278d: b8 04 3e 10 00 mov $0x103e04,%eax + 102792: ff d0 call *%eax + 102794: e9 4f ef ff ff jmp 1016e8 + +00102799 : + 102799: 6a 00 push $0x0 + 10279b: 6a 6d push $0x6d + 10279d: 0f a8 push %gs + 10279f: 0f a0 push %fs + 1027a1: 06 push %es + 1027a2: 1e push %ds + 1027a3: 60 pusha + 1027a4: 66 b8 10 00 mov $0x10,%ax + 1027a8: 8e d8 mov %eax,%ds + 1027aa: 8e c0 mov %eax,%es + 1027ac: 8e e0 mov %eax,%fs + 1027ae: 8e e8 mov %eax,%gs + 1027b0: 89 e0 mov %esp,%eax + 1027b2: 50 push %eax + +001027b3 : + 1027b3: b8 04 3e 10 00 mov $0x103e04,%eax + 1027b8: ff d0 call *%eax + 1027ba: e9 29 ef ff ff jmp 1016e8 + +001027bf : + 1027bf: 6a 00 push $0x0 + 1027c1: 6a 6e push $0x6e + 1027c3: 0f a8 push %gs + 1027c5: 0f a0 push %fs + 1027c7: 06 push %es + 1027c8: 1e push %ds + 1027c9: 60 pusha + 1027ca: 66 b8 10 00 mov $0x10,%ax + 1027ce: 8e d8 mov %eax,%ds + 1027d0: 8e c0 mov %eax,%es + 1027d2: 8e e0 mov %eax,%fs + 1027d4: 8e e8 mov %eax,%gs + 1027d6: 89 e0 mov %esp,%eax + 1027d8: 50 push %eax + +001027d9 : + 1027d9: b8 04 3e 10 00 mov $0x103e04,%eax + 1027de: ff d0 call *%eax + 1027e0: e9 03 ef ff ff jmp 1016e8 + +001027e5 : + 1027e5: 6a 00 push $0x0 + 1027e7: 6a 6f push $0x6f + 1027e9: 0f a8 push %gs + 1027eb: 0f a0 push %fs + 1027ed: 06 push %es + 1027ee: 1e push %ds + 1027ef: 60 pusha + 1027f0: 66 b8 10 00 mov $0x10,%ax + 1027f4: 8e d8 mov %eax,%ds + 1027f6: 8e c0 mov %eax,%es + 1027f8: 8e e0 mov %eax,%fs + 1027fa: 8e e8 mov %eax,%gs + 1027fc: 89 e0 mov %esp,%eax + 1027fe: 50 push %eax + +001027ff : + 1027ff: b8 04 3e 10 00 mov $0x103e04,%eax + 102804: ff d0 call *%eax + 102806: e9 dd ee ff ff jmp 1016e8 + +0010280b : + 10280b: 6a 00 push $0x0 + 10280d: 6a 70 push $0x70 + 10280f: 0f a8 push %gs + 102811: 0f a0 push %fs + 102813: 06 push %es + 102814: 1e push %ds + 102815: 60 pusha + 102816: 66 b8 10 00 mov $0x10,%ax + 10281a: 8e d8 mov %eax,%ds + 10281c: 8e c0 mov %eax,%es + 10281e: 8e e0 mov %eax,%fs + 102820: 8e e8 mov %eax,%gs + 102822: 89 e0 mov %esp,%eax + 102824: 50 push %eax + +00102825 : + 102825: b8 04 3e 10 00 mov $0x103e04,%eax + 10282a: ff d0 call *%eax + 10282c: e9 b7 ee ff ff jmp 1016e8 + +00102831 : + 102831: 6a 00 push $0x0 + 102833: 6a 71 push $0x71 + 102835: 0f a8 push %gs + 102837: 0f a0 push %fs + 102839: 06 push %es + 10283a: 1e push %ds + 10283b: 60 pusha + 10283c: 66 b8 10 00 mov $0x10,%ax + 102840: 8e d8 mov %eax,%ds + 102842: 8e c0 mov %eax,%es + 102844: 8e e0 mov %eax,%fs + 102846: 8e e8 mov %eax,%gs + 102848: 89 e0 mov %esp,%eax + 10284a: 50 push %eax + +0010284b : + 10284b: b8 04 3e 10 00 mov $0x103e04,%eax + 102850: ff d0 call *%eax + 102852: e9 91 ee ff ff jmp 1016e8 + +00102857 : + 102857: 6a 00 push $0x0 + 102859: 6a 72 push $0x72 + 10285b: 0f a8 push %gs + 10285d: 0f a0 push %fs + 10285f: 06 push %es + 102860: 1e push %ds + 102861: 60 pusha + 102862: 66 b8 10 00 mov $0x10,%ax + 102866: 8e d8 mov %eax,%ds + 102868: 8e c0 mov %eax,%es + 10286a: 8e e0 mov %eax,%fs + 10286c: 8e e8 mov %eax,%gs + 10286e: 89 e0 mov %esp,%eax + 102870: 50 push %eax + +00102871 : + 102871: b8 04 3e 10 00 mov $0x103e04,%eax + 102876: ff d0 call *%eax + 102878: e9 6b ee ff ff jmp 1016e8 + +0010287d : + 10287d: 6a 00 push $0x0 + 10287f: 6a 73 push $0x73 + 102881: 0f a8 push %gs + 102883: 0f a0 push %fs + 102885: 06 push %es + 102886: 1e push %ds + 102887: 60 pusha + 102888: 66 b8 10 00 mov $0x10,%ax + 10288c: 8e d8 mov %eax,%ds + 10288e: 8e c0 mov %eax,%es + 102890: 8e e0 mov %eax,%fs + 102892: 8e e8 mov %eax,%gs + 102894: 89 e0 mov %esp,%eax + 102896: 50 push %eax + +00102897 : + 102897: b8 04 3e 10 00 mov $0x103e04,%eax + 10289c: ff d0 call *%eax + 10289e: e9 45 ee ff ff jmp 1016e8 + +001028a3 : + 1028a3: 6a 00 push $0x0 + 1028a5: 6a 74 push $0x74 + 1028a7: 0f a8 push %gs + 1028a9: 0f a0 push %fs + 1028ab: 06 push %es + 1028ac: 1e push %ds + 1028ad: 60 pusha + 1028ae: 66 b8 10 00 mov $0x10,%ax + 1028b2: 8e d8 mov %eax,%ds + 1028b4: 8e c0 mov %eax,%es + 1028b6: 8e e0 mov %eax,%fs + 1028b8: 8e e8 mov %eax,%gs + 1028ba: 89 e0 mov %esp,%eax + 1028bc: 50 push %eax + +001028bd : + 1028bd: b8 04 3e 10 00 mov $0x103e04,%eax + 1028c2: ff d0 call *%eax + 1028c4: e9 1f ee ff ff jmp 1016e8 + +001028c9 : + 1028c9: 6a 00 push $0x0 + 1028cb: 6a 75 push $0x75 + 1028cd: 0f a8 push %gs + 1028cf: 0f a0 push %fs + 1028d1: 06 push %es + 1028d2: 1e push %ds + 1028d3: 60 pusha + 1028d4: 66 b8 10 00 mov $0x10,%ax + 1028d8: 8e d8 mov %eax,%ds + 1028da: 8e c0 mov %eax,%es + 1028dc: 8e e0 mov %eax,%fs + 1028de: 8e e8 mov %eax,%gs + 1028e0: 89 e0 mov %esp,%eax + 1028e2: 50 push %eax + +001028e3 : + 1028e3: b8 04 3e 10 00 mov $0x103e04,%eax + 1028e8: ff d0 call *%eax + 1028ea: e9 f9 ed ff ff jmp 1016e8 + +001028ef : + 1028ef: 6a 00 push $0x0 + 1028f1: 6a 76 push $0x76 + 1028f3: 0f a8 push %gs + 1028f5: 0f a0 push %fs + 1028f7: 06 push %es + 1028f8: 1e push %ds + 1028f9: 60 pusha + 1028fa: 66 b8 10 00 mov $0x10,%ax + 1028fe: 8e d8 mov %eax,%ds + 102900: 8e c0 mov %eax,%es + 102902: 8e e0 mov %eax,%fs + 102904: 8e e8 mov %eax,%gs + 102906: 89 e0 mov %esp,%eax + 102908: 50 push %eax + +00102909 : + 102909: b8 04 3e 10 00 mov $0x103e04,%eax + 10290e: ff d0 call *%eax + 102910: e9 d3 ed ff ff jmp 1016e8 + +00102915 : + 102915: 6a 00 push $0x0 + 102917: 6a 77 push $0x77 + 102919: 0f a8 push %gs + 10291b: 0f a0 push %fs + 10291d: 06 push %es + 10291e: 1e push %ds + 10291f: 60 pusha + 102920: 66 b8 10 00 mov $0x10,%ax + 102924: 8e d8 mov %eax,%ds + 102926: 8e c0 mov %eax,%es + 102928: 8e e0 mov %eax,%fs + 10292a: 8e e8 mov %eax,%gs + 10292c: 89 e0 mov %esp,%eax + 10292e: 50 push %eax + +0010292f : + 10292f: b8 04 3e 10 00 mov $0x103e04,%eax + 102934: ff d0 call *%eax + 102936: e9 ad ed ff ff jmp 1016e8 + +0010293b : + 10293b: 6a 00 push $0x0 + 10293d: 6a 78 push $0x78 + 10293f: 0f a8 push %gs + 102941: 0f a0 push %fs + 102943: 06 push %es + 102944: 1e push %ds + 102945: 60 pusha + 102946: 66 b8 10 00 mov $0x10,%ax + 10294a: 8e d8 mov %eax,%ds + 10294c: 8e c0 mov %eax,%es + 10294e: 8e e0 mov %eax,%fs + 102950: 8e e8 mov %eax,%gs + 102952: 89 e0 mov %esp,%eax + 102954: 50 push %eax + +00102955 : + 102955: b8 04 3e 10 00 mov $0x103e04,%eax + 10295a: ff d0 call *%eax + 10295c: e9 87 ed ff ff jmp 1016e8 + +00102961 : + 102961: 6a 00 push $0x0 + 102963: 6a 79 push $0x79 + 102965: 0f a8 push %gs + 102967: 0f a0 push %fs + 102969: 06 push %es + 10296a: 1e push %ds + 10296b: 60 pusha + 10296c: 66 b8 10 00 mov $0x10,%ax + 102970: 8e d8 mov %eax,%ds + 102972: 8e c0 mov %eax,%es + 102974: 8e e0 mov %eax,%fs + 102976: 8e e8 mov %eax,%gs + 102978: 89 e0 mov %esp,%eax + 10297a: 50 push %eax + +0010297b : + 10297b: b8 04 3e 10 00 mov $0x103e04,%eax + 102980: ff d0 call *%eax + 102982: e9 61 ed ff ff jmp 1016e8 + +00102987 : + 102987: 6a 00 push $0x0 + 102989: 6a 7a push $0x7a + 10298b: 0f a8 push %gs + 10298d: 0f a0 push %fs + 10298f: 06 push %es + 102990: 1e push %ds + 102991: 60 pusha + 102992: 66 b8 10 00 mov $0x10,%ax + 102996: 8e d8 mov %eax,%ds + 102998: 8e c0 mov %eax,%es + 10299a: 8e e0 mov %eax,%fs + 10299c: 8e e8 mov %eax,%gs + 10299e: 89 e0 mov %esp,%eax + 1029a0: 50 push %eax + +001029a1 : + 1029a1: b8 04 3e 10 00 mov $0x103e04,%eax + 1029a6: ff d0 call *%eax + 1029a8: e9 3b ed ff ff jmp 1016e8 + +001029ad : + 1029ad: 6a 00 push $0x0 + 1029af: 6a 7b push $0x7b + 1029b1: 0f a8 push %gs + 1029b3: 0f a0 push %fs + 1029b5: 06 push %es + 1029b6: 1e push %ds + 1029b7: 60 pusha + 1029b8: 66 b8 10 00 mov $0x10,%ax + 1029bc: 8e d8 mov %eax,%ds + 1029be: 8e c0 mov %eax,%es + 1029c0: 8e e0 mov %eax,%fs + 1029c2: 8e e8 mov %eax,%gs + 1029c4: 89 e0 mov %esp,%eax + 1029c6: 50 push %eax + +001029c7 : + 1029c7: b8 04 3e 10 00 mov $0x103e04,%eax + 1029cc: ff d0 call *%eax + 1029ce: e9 15 ed ff ff jmp 1016e8 + +001029d3 : + 1029d3: 6a 00 push $0x0 + 1029d5: 6a 7c push $0x7c + 1029d7: 0f a8 push %gs + 1029d9: 0f a0 push %fs + 1029db: 06 push %es + 1029dc: 1e push %ds + 1029dd: 60 pusha + 1029de: 66 b8 10 00 mov $0x10,%ax + 1029e2: 8e d8 mov %eax,%ds + 1029e4: 8e c0 mov %eax,%es + 1029e6: 8e e0 mov %eax,%fs + 1029e8: 8e e8 mov %eax,%gs + 1029ea: 89 e0 mov %esp,%eax + 1029ec: 50 push %eax + +001029ed : + 1029ed: b8 04 3e 10 00 mov $0x103e04,%eax + 1029f2: ff d0 call *%eax + 1029f4: e9 ef ec ff ff jmp 1016e8 + +001029f9 : + 1029f9: 6a 00 push $0x0 + 1029fb: 6a 7d push $0x7d + 1029fd: 0f a8 push %gs + 1029ff: 0f a0 push %fs + 102a01: 06 push %es + 102a02: 1e push %ds + 102a03: 60 pusha + 102a04: 66 b8 10 00 mov $0x10,%ax + 102a08: 8e d8 mov %eax,%ds + 102a0a: 8e c0 mov %eax,%es + 102a0c: 8e e0 mov %eax,%fs + 102a0e: 8e e8 mov %eax,%gs + 102a10: 89 e0 mov %esp,%eax + 102a12: 50 push %eax + +00102a13 : + 102a13: b8 04 3e 10 00 mov $0x103e04,%eax + 102a18: ff d0 call *%eax + 102a1a: e9 c9 ec ff ff jmp 1016e8 + +00102a1f : + 102a1f: 6a 00 push $0x0 + 102a21: 6a 7e push $0x7e + 102a23: 0f a8 push %gs + 102a25: 0f a0 push %fs + 102a27: 06 push %es + 102a28: 1e push %ds + 102a29: 60 pusha + 102a2a: 66 b8 10 00 mov $0x10,%ax + 102a2e: 8e d8 mov %eax,%ds + 102a30: 8e c0 mov %eax,%es + 102a32: 8e e0 mov %eax,%fs + 102a34: 8e e8 mov %eax,%gs + 102a36: 89 e0 mov %esp,%eax + 102a38: 50 push %eax + +00102a39 : + 102a39: b8 04 3e 10 00 mov $0x103e04,%eax + 102a3e: ff d0 call *%eax + 102a40: e9 a3 ec ff ff jmp 1016e8 + +00102a45 : + 102a45: 6a 00 push $0x0 + 102a47: 6a 7f push $0x7f + 102a49: 0f a8 push %gs + 102a4b: 0f a0 push %fs + 102a4d: 06 push %es + 102a4e: 1e push %ds + 102a4f: 60 pusha + 102a50: 66 b8 10 00 mov $0x10,%ax + 102a54: 8e d8 mov %eax,%ds + 102a56: 8e c0 mov %eax,%es + 102a58: 8e e0 mov %eax,%fs + 102a5a: 8e e8 mov %eax,%gs + 102a5c: 89 e0 mov %esp,%eax + 102a5e: 50 push %eax + +00102a5f : + 102a5f: b8 04 3e 10 00 mov $0x103e04,%eax + 102a64: ff d0 call *%eax + 102a66: e9 7d ec ff ff jmp 1016e8 + +00102a6b : + 102a6b: 6a 00 push $0x0 + 102a6d: 6a 80 push $0xffffff80 + 102a6f: 0f a8 push %gs + 102a71: 0f a0 push %fs + 102a73: 06 push %es + 102a74: 1e push %ds + 102a75: 60 pusha + 102a76: 66 b8 10 00 mov $0x10,%ax + 102a7a: 8e d8 mov %eax,%ds + 102a7c: 8e c0 mov %eax,%es + 102a7e: 8e e0 mov %eax,%fs + 102a80: 8e e8 mov %eax,%gs + 102a82: 89 e0 mov %esp,%eax + 102a84: 50 push %eax + +00102a85 : + 102a85: b8 04 3e 10 00 mov $0x103e04,%eax + 102a8a: ff d0 call *%eax + 102a8c: e9 57 ec ff ff jmp 1016e8 + +00102a91 : + 102a91: 6a 00 push $0x0 + 102a93: 6a 81 push $0xffffff81 + 102a95: 0f a8 push %gs + 102a97: 0f a0 push %fs + 102a99: 06 push %es + 102a9a: 1e push %ds + 102a9b: 60 pusha + 102a9c: 66 b8 10 00 mov $0x10,%ax + 102aa0: 8e d8 mov %eax,%ds + 102aa2: 8e c0 mov %eax,%es + 102aa4: 8e e0 mov %eax,%fs + 102aa6: 8e e8 mov %eax,%gs + 102aa8: 89 e0 mov %esp,%eax + 102aaa: 50 push %eax + +00102aab : + 102aab: b8 04 3e 10 00 mov $0x103e04,%eax + 102ab0: ff d0 call *%eax + 102ab2: e9 31 ec ff ff jmp 1016e8 + +00102ab7 : + 102ab7: 6a 00 push $0x0 + 102ab9: 6a 82 push $0xffffff82 + 102abb: 0f a8 push %gs + 102abd: 0f a0 push %fs + 102abf: 06 push %es + 102ac0: 1e push %ds + 102ac1: 60 pusha + 102ac2: 66 b8 10 00 mov $0x10,%ax + 102ac6: 8e d8 mov %eax,%ds + 102ac8: 8e c0 mov %eax,%es + 102aca: 8e e0 mov %eax,%fs + 102acc: 8e e8 mov %eax,%gs + 102ace: 89 e0 mov %esp,%eax + 102ad0: 50 push %eax + +00102ad1 : + 102ad1: b8 04 3e 10 00 mov $0x103e04,%eax + 102ad6: ff d0 call *%eax + 102ad8: e9 0b ec ff ff jmp 1016e8 + +00102add : + 102add: 6a 00 push $0x0 + 102adf: 6a 83 push $0xffffff83 + 102ae1: 0f a8 push %gs + 102ae3: 0f a0 push %fs + 102ae5: 06 push %es + 102ae6: 1e push %ds + 102ae7: 60 pusha + 102ae8: 66 b8 10 00 mov $0x10,%ax + 102aec: 8e d8 mov %eax,%ds + 102aee: 8e c0 mov %eax,%es + 102af0: 8e e0 mov %eax,%fs + 102af2: 8e e8 mov %eax,%gs + 102af4: 89 e0 mov %esp,%eax + 102af6: 50 push %eax + +00102af7 : + 102af7: b8 04 3e 10 00 mov $0x103e04,%eax + 102afc: ff d0 call *%eax + 102afe: e9 e5 eb ff ff jmp 1016e8 + +00102b03 : + 102b03: 6a 00 push $0x0 + 102b05: 6a 84 push $0xffffff84 + 102b07: 0f a8 push %gs + 102b09: 0f a0 push %fs + 102b0b: 06 push %es + 102b0c: 1e push %ds + 102b0d: 60 pusha + 102b0e: 66 b8 10 00 mov $0x10,%ax + 102b12: 8e d8 mov %eax,%ds + 102b14: 8e c0 mov %eax,%es + 102b16: 8e e0 mov %eax,%fs + 102b18: 8e e8 mov %eax,%gs + 102b1a: 89 e0 mov %esp,%eax + 102b1c: 50 push %eax + +00102b1d : + 102b1d: b8 04 3e 10 00 mov $0x103e04,%eax + 102b22: ff d0 call *%eax + 102b24: e9 bf eb ff ff jmp 1016e8 + +00102b29 : + 102b29: 6a 00 push $0x0 + 102b2b: 6a 85 push $0xffffff85 + 102b2d: 0f a8 push %gs + 102b2f: 0f a0 push %fs + 102b31: 06 push %es + 102b32: 1e push %ds + 102b33: 60 pusha + 102b34: 66 b8 10 00 mov $0x10,%ax + 102b38: 8e d8 mov %eax,%ds + 102b3a: 8e c0 mov %eax,%es + 102b3c: 8e e0 mov %eax,%fs + 102b3e: 8e e8 mov %eax,%gs + 102b40: 89 e0 mov %esp,%eax + 102b42: 50 push %eax + +00102b43 : + 102b43: b8 04 3e 10 00 mov $0x103e04,%eax + 102b48: ff d0 call *%eax + 102b4a: e9 99 eb ff ff jmp 1016e8 + +00102b4f : + 102b4f: 6a 00 push $0x0 + 102b51: 6a 86 push $0xffffff86 + 102b53: 0f a8 push %gs + 102b55: 0f a0 push %fs + 102b57: 06 push %es + 102b58: 1e push %ds + 102b59: 60 pusha + 102b5a: 66 b8 10 00 mov $0x10,%ax + 102b5e: 8e d8 mov %eax,%ds + 102b60: 8e c0 mov %eax,%es + 102b62: 8e e0 mov %eax,%fs + 102b64: 8e e8 mov %eax,%gs + 102b66: 89 e0 mov %esp,%eax + 102b68: 50 push %eax + +00102b69 : + 102b69: b8 04 3e 10 00 mov $0x103e04,%eax + 102b6e: ff d0 call *%eax + 102b70: e9 73 eb ff ff jmp 1016e8 + +00102b75 : + 102b75: 6a 00 push $0x0 + 102b77: 6a 87 push $0xffffff87 + 102b79: 0f a8 push %gs + 102b7b: 0f a0 push %fs + 102b7d: 06 push %es + 102b7e: 1e push %ds + 102b7f: 60 pusha + 102b80: 66 b8 10 00 mov $0x10,%ax + 102b84: 8e d8 mov %eax,%ds + 102b86: 8e c0 mov %eax,%es + 102b88: 8e e0 mov %eax,%fs + 102b8a: 8e e8 mov %eax,%gs + 102b8c: 89 e0 mov %esp,%eax + 102b8e: 50 push %eax + +00102b8f : + 102b8f: b8 04 3e 10 00 mov $0x103e04,%eax + 102b94: ff d0 call *%eax + 102b96: e9 4d eb ff ff jmp 1016e8 + +00102b9b : + 102b9b: 6a 00 push $0x0 + 102b9d: 6a 88 push $0xffffff88 + 102b9f: 0f a8 push %gs + 102ba1: 0f a0 push %fs + 102ba3: 06 push %es + 102ba4: 1e push %ds + 102ba5: 60 pusha + 102ba6: 66 b8 10 00 mov $0x10,%ax + 102baa: 8e d8 mov %eax,%ds + 102bac: 8e c0 mov %eax,%es + 102bae: 8e e0 mov %eax,%fs + 102bb0: 8e e8 mov %eax,%gs + 102bb2: 89 e0 mov %esp,%eax + 102bb4: 50 push %eax + +00102bb5 : + 102bb5: b8 04 3e 10 00 mov $0x103e04,%eax + 102bba: ff d0 call *%eax + 102bbc: e9 27 eb ff ff jmp 1016e8 + +00102bc1 : + 102bc1: 6a 00 push $0x0 + 102bc3: 6a 89 push $0xffffff89 + 102bc5: 0f a8 push %gs + 102bc7: 0f a0 push %fs + 102bc9: 06 push %es + 102bca: 1e push %ds + 102bcb: 60 pusha + 102bcc: 66 b8 10 00 mov $0x10,%ax + 102bd0: 8e d8 mov %eax,%ds + 102bd2: 8e c0 mov %eax,%es + 102bd4: 8e e0 mov %eax,%fs + 102bd6: 8e e8 mov %eax,%gs + 102bd8: 89 e0 mov %esp,%eax + 102bda: 50 push %eax + +00102bdb : + 102bdb: b8 04 3e 10 00 mov $0x103e04,%eax + 102be0: ff d0 call *%eax + 102be2: e9 01 eb ff ff jmp 1016e8 + +00102be7 : + 102be7: 6a 00 push $0x0 + 102be9: 6a 8a push $0xffffff8a + 102beb: 0f a8 push %gs + 102bed: 0f a0 push %fs + 102bef: 06 push %es + 102bf0: 1e push %ds + 102bf1: 60 pusha + 102bf2: 66 b8 10 00 mov $0x10,%ax + 102bf6: 8e d8 mov %eax,%ds + 102bf8: 8e c0 mov %eax,%es + 102bfa: 8e e0 mov %eax,%fs + 102bfc: 8e e8 mov %eax,%gs + 102bfe: 89 e0 mov %esp,%eax + 102c00: 50 push %eax + +00102c01 : + 102c01: b8 04 3e 10 00 mov $0x103e04,%eax + 102c06: ff d0 call *%eax + 102c08: e9 db ea ff ff jmp 1016e8 + +00102c0d : + 102c0d: 6a 00 push $0x0 + 102c0f: 6a 8b push $0xffffff8b + 102c11: 0f a8 push %gs + 102c13: 0f a0 push %fs + 102c15: 06 push %es + 102c16: 1e push %ds + 102c17: 60 pusha + 102c18: 66 b8 10 00 mov $0x10,%ax + 102c1c: 8e d8 mov %eax,%ds + 102c1e: 8e c0 mov %eax,%es + 102c20: 8e e0 mov %eax,%fs + 102c22: 8e e8 mov %eax,%gs + 102c24: 89 e0 mov %esp,%eax + 102c26: 50 push %eax + +00102c27 : + 102c27: b8 04 3e 10 00 mov $0x103e04,%eax + 102c2c: ff d0 call *%eax + 102c2e: e9 b5 ea ff ff jmp 1016e8 + +00102c33 : + 102c33: 6a 00 push $0x0 + 102c35: 6a 8c push $0xffffff8c + 102c37: 0f a8 push %gs + 102c39: 0f a0 push %fs + 102c3b: 06 push %es + 102c3c: 1e push %ds + 102c3d: 60 pusha + 102c3e: 66 b8 10 00 mov $0x10,%ax + 102c42: 8e d8 mov %eax,%ds + 102c44: 8e c0 mov %eax,%es + 102c46: 8e e0 mov %eax,%fs + 102c48: 8e e8 mov %eax,%gs + 102c4a: 89 e0 mov %esp,%eax + 102c4c: 50 push %eax + +00102c4d : + 102c4d: b8 04 3e 10 00 mov $0x103e04,%eax + 102c52: ff d0 call *%eax + 102c54: e9 8f ea ff ff jmp 1016e8 + +00102c59 : + 102c59: 6a 00 push $0x0 + 102c5b: 6a 8d push $0xffffff8d + 102c5d: 0f a8 push %gs + 102c5f: 0f a0 push %fs + 102c61: 06 push %es + 102c62: 1e push %ds + 102c63: 60 pusha + 102c64: 66 b8 10 00 mov $0x10,%ax + 102c68: 8e d8 mov %eax,%ds + 102c6a: 8e c0 mov %eax,%es + 102c6c: 8e e0 mov %eax,%fs + 102c6e: 8e e8 mov %eax,%gs + 102c70: 89 e0 mov %esp,%eax + 102c72: 50 push %eax + +00102c73 : + 102c73: b8 04 3e 10 00 mov $0x103e04,%eax + 102c78: ff d0 call *%eax + 102c7a: e9 69 ea ff ff jmp 1016e8 + +00102c7f : + 102c7f: 6a 00 push $0x0 + 102c81: 6a 8e push $0xffffff8e + 102c83: 0f a8 push %gs + 102c85: 0f a0 push %fs + 102c87: 06 push %es + 102c88: 1e push %ds + 102c89: 60 pusha + 102c8a: 66 b8 10 00 mov $0x10,%ax + 102c8e: 8e d8 mov %eax,%ds + 102c90: 8e c0 mov %eax,%es + 102c92: 8e e0 mov %eax,%fs + 102c94: 8e e8 mov %eax,%gs + 102c96: 89 e0 mov %esp,%eax + 102c98: 50 push %eax + +00102c99 : + 102c99: b8 04 3e 10 00 mov $0x103e04,%eax + 102c9e: ff d0 call *%eax + 102ca0: e9 43 ea ff ff jmp 1016e8 + +00102ca5 : + 102ca5: 6a 00 push $0x0 + 102ca7: 6a 8f push $0xffffff8f + 102ca9: 0f a8 push %gs + 102cab: 0f a0 push %fs + 102cad: 06 push %es + 102cae: 1e push %ds + 102caf: 60 pusha + 102cb0: 66 b8 10 00 mov $0x10,%ax + 102cb4: 8e d8 mov %eax,%ds + 102cb6: 8e c0 mov %eax,%es + 102cb8: 8e e0 mov %eax,%fs + 102cba: 8e e8 mov %eax,%gs + 102cbc: 89 e0 mov %esp,%eax + 102cbe: 50 push %eax + +00102cbf : + 102cbf: b8 04 3e 10 00 mov $0x103e04,%eax + 102cc4: ff d0 call *%eax + 102cc6: e9 1d ea ff ff jmp 1016e8 + +00102ccb : + 102ccb: 6a 00 push $0x0 + 102ccd: 6a 90 push $0xffffff90 + 102ccf: 0f a8 push %gs + 102cd1: 0f a0 push %fs + 102cd3: 06 push %es + 102cd4: 1e push %ds + 102cd5: 60 pusha + 102cd6: 66 b8 10 00 mov $0x10,%ax + 102cda: 8e d8 mov %eax,%ds + 102cdc: 8e c0 mov %eax,%es + 102cde: 8e e0 mov %eax,%fs + 102ce0: 8e e8 mov %eax,%gs + 102ce2: 89 e0 mov %esp,%eax + 102ce4: 50 push %eax + +00102ce5 : + 102ce5: b8 04 3e 10 00 mov $0x103e04,%eax + 102cea: ff d0 call *%eax + 102cec: e9 f7 e9 ff ff jmp 1016e8 + +00102cf1 : + 102cf1: 6a 00 push $0x0 + 102cf3: 6a 91 push $0xffffff91 + 102cf5: 0f a8 push %gs + 102cf7: 0f a0 push %fs + 102cf9: 06 push %es + 102cfa: 1e push %ds + 102cfb: 60 pusha + 102cfc: 66 b8 10 00 mov $0x10,%ax + 102d00: 8e d8 mov %eax,%ds + 102d02: 8e c0 mov %eax,%es + 102d04: 8e e0 mov %eax,%fs + 102d06: 8e e8 mov %eax,%gs + 102d08: 89 e0 mov %esp,%eax + 102d0a: 50 push %eax + +00102d0b : + 102d0b: b8 04 3e 10 00 mov $0x103e04,%eax + 102d10: ff d0 call *%eax + 102d12: e9 d1 e9 ff ff jmp 1016e8 + +00102d17 : + 102d17: 6a 00 push $0x0 + 102d19: 6a 92 push $0xffffff92 + 102d1b: 0f a8 push %gs + 102d1d: 0f a0 push %fs + 102d1f: 06 push %es + 102d20: 1e push %ds + 102d21: 60 pusha + 102d22: 66 b8 10 00 mov $0x10,%ax + 102d26: 8e d8 mov %eax,%ds + 102d28: 8e c0 mov %eax,%es + 102d2a: 8e e0 mov %eax,%fs + 102d2c: 8e e8 mov %eax,%gs + 102d2e: 89 e0 mov %esp,%eax + 102d30: 50 push %eax + +00102d31 : + 102d31: b8 04 3e 10 00 mov $0x103e04,%eax + 102d36: ff d0 call *%eax + 102d38: e9 ab e9 ff ff jmp 1016e8 + +00102d3d : + 102d3d: 6a 00 push $0x0 + 102d3f: 6a 93 push $0xffffff93 + 102d41: 0f a8 push %gs + 102d43: 0f a0 push %fs + 102d45: 06 push %es + 102d46: 1e push %ds + 102d47: 60 pusha + 102d48: 66 b8 10 00 mov $0x10,%ax + 102d4c: 8e d8 mov %eax,%ds + 102d4e: 8e c0 mov %eax,%es + 102d50: 8e e0 mov %eax,%fs + 102d52: 8e e8 mov %eax,%gs + 102d54: 89 e0 mov %esp,%eax + 102d56: 50 push %eax + +00102d57 : + 102d57: b8 04 3e 10 00 mov $0x103e04,%eax + 102d5c: ff d0 call *%eax + 102d5e: e9 85 e9 ff ff jmp 1016e8 + +00102d63 : + 102d63: 6a 00 push $0x0 + 102d65: 6a 94 push $0xffffff94 + 102d67: 0f a8 push %gs + 102d69: 0f a0 push %fs + 102d6b: 06 push %es + 102d6c: 1e push %ds + 102d6d: 60 pusha + 102d6e: 66 b8 10 00 mov $0x10,%ax + 102d72: 8e d8 mov %eax,%ds + 102d74: 8e c0 mov %eax,%es + 102d76: 8e e0 mov %eax,%fs + 102d78: 8e e8 mov %eax,%gs + 102d7a: 89 e0 mov %esp,%eax + 102d7c: 50 push %eax + +00102d7d : + 102d7d: b8 04 3e 10 00 mov $0x103e04,%eax + 102d82: ff d0 call *%eax + 102d84: e9 5f e9 ff ff jmp 1016e8 + +00102d89 : + 102d89: 6a 00 push $0x0 + 102d8b: 6a 95 push $0xffffff95 + 102d8d: 0f a8 push %gs + 102d8f: 0f a0 push %fs + 102d91: 06 push %es + 102d92: 1e push %ds + 102d93: 60 pusha + 102d94: 66 b8 10 00 mov $0x10,%ax + 102d98: 8e d8 mov %eax,%ds + 102d9a: 8e c0 mov %eax,%es + 102d9c: 8e e0 mov %eax,%fs + 102d9e: 8e e8 mov %eax,%gs + 102da0: 89 e0 mov %esp,%eax + 102da2: 50 push %eax + +00102da3 : + 102da3: b8 04 3e 10 00 mov $0x103e04,%eax + 102da8: ff d0 call *%eax + 102daa: e9 39 e9 ff ff jmp 1016e8 + +00102daf : + 102daf: 6a 00 push $0x0 + 102db1: 6a 96 push $0xffffff96 + 102db3: 0f a8 push %gs + 102db5: 0f a0 push %fs + 102db7: 06 push %es + 102db8: 1e push %ds + 102db9: 60 pusha + 102dba: 66 b8 10 00 mov $0x10,%ax + 102dbe: 8e d8 mov %eax,%ds + 102dc0: 8e c0 mov %eax,%es + 102dc2: 8e e0 mov %eax,%fs + 102dc4: 8e e8 mov %eax,%gs + 102dc6: 89 e0 mov %esp,%eax + 102dc8: 50 push %eax + +00102dc9 : + 102dc9: b8 04 3e 10 00 mov $0x103e04,%eax + 102dce: ff d0 call *%eax + 102dd0: e9 13 e9 ff ff jmp 1016e8 + +00102dd5 : + 102dd5: 6a 00 push $0x0 + 102dd7: 6a 97 push $0xffffff97 + 102dd9: 0f a8 push %gs + 102ddb: 0f a0 push %fs + 102ddd: 06 push %es + 102dde: 1e push %ds + 102ddf: 60 pusha + 102de0: 66 b8 10 00 mov $0x10,%ax + 102de4: 8e d8 mov %eax,%ds + 102de6: 8e c0 mov %eax,%es + 102de8: 8e e0 mov %eax,%fs + 102dea: 8e e8 mov %eax,%gs + 102dec: 89 e0 mov %esp,%eax + 102dee: 50 push %eax + +00102def : + 102def: b8 04 3e 10 00 mov $0x103e04,%eax + 102df4: ff d0 call *%eax + 102df6: e9 ed e8 ff ff jmp 1016e8 + +00102dfb : + 102dfb: 6a 00 push $0x0 + 102dfd: 6a 98 push $0xffffff98 + 102dff: 0f a8 push %gs + 102e01: 0f a0 push %fs + 102e03: 06 push %es + 102e04: 1e push %ds + 102e05: 60 pusha + 102e06: 66 b8 10 00 mov $0x10,%ax + 102e0a: 8e d8 mov %eax,%ds + 102e0c: 8e c0 mov %eax,%es + 102e0e: 8e e0 mov %eax,%fs + 102e10: 8e e8 mov %eax,%gs + 102e12: 89 e0 mov %esp,%eax + 102e14: 50 push %eax + +00102e15 : + 102e15: b8 04 3e 10 00 mov $0x103e04,%eax + 102e1a: ff d0 call *%eax + 102e1c: e9 c7 e8 ff ff jmp 1016e8 + +00102e21 : + 102e21: 6a 00 push $0x0 + 102e23: 6a 99 push $0xffffff99 + 102e25: 0f a8 push %gs + 102e27: 0f a0 push %fs + 102e29: 06 push %es + 102e2a: 1e push %ds + 102e2b: 60 pusha + 102e2c: 66 b8 10 00 mov $0x10,%ax + 102e30: 8e d8 mov %eax,%ds + 102e32: 8e c0 mov %eax,%es + 102e34: 8e e0 mov %eax,%fs + 102e36: 8e e8 mov %eax,%gs + 102e38: 89 e0 mov %esp,%eax + 102e3a: 50 push %eax + +00102e3b : + 102e3b: b8 04 3e 10 00 mov $0x103e04,%eax + 102e40: ff d0 call *%eax + 102e42: e9 a1 e8 ff ff jmp 1016e8 + +00102e47 : + 102e47: 6a 00 push $0x0 + 102e49: 6a 9a push $0xffffff9a + 102e4b: 0f a8 push %gs + 102e4d: 0f a0 push %fs + 102e4f: 06 push %es + 102e50: 1e push %ds + 102e51: 60 pusha + 102e52: 66 b8 10 00 mov $0x10,%ax + 102e56: 8e d8 mov %eax,%ds + 102e58: 8e c0 mov %eax,%es + 102e5a: 8e e0 mov %eax,%fs + 102e5c: 8e e8 mov %eax,%gs + 102e5e: 89 e0 mov %esp,%eax + 102e60: 50 push %eax + +00102e61 : + 102e61: b8 04 3e 10 00 mov $0x103e04,%eax + 102e66: ff d0 call *%eax + 102e68: e9 7b e8 ff ff jmp 1016e8 + +00102e6d : + 102e6d: 6a 00 push $0x0 + 102e6f: 6a 9b push $0xffffff9b + 102e71: 0f a8 push %gs + 102e73: 0f a0 push %fs + 102e75: 06 push %es + 102e76: 1e push %ds + 102e77: 60 pusha + 102e78: 66 b8 10 00 mov $0x10,%ax + 102e7c: 8e d8 mov %eax,%ds + 102e7e: 8e c0 mov %eax,%es + 102e80: 8e e0 mov %eax,%fs + 102e82: 8e e8 mov %eax,%gs + 102e84: 89 e0 mov %esp,%eax + 102e86: 50 push %eax + +00102e87 : + 102e87: b8 04 3e 10 00 mov $0x103e04,%eax + 102e8c: ff d0 call *%eax + 102e8e: e9 55 e8 ff ff jmp 1016e8 + +00102e93 : + 102e93: 6a 00 push $0x0 + 102e95: 6a 9c push $0xffffff9c + 102e97: 0f a8 push %gs + 102e99: 0f a0 push %fs + 102e9b: 06 push %es + 102e9c: 1e push %ds + 102e9d: 60 pusha + 102e9e: 66 b8 10 00 mov $0x10,%ax + 102ea2: 8e d8 mov %eax,%ds + 102ea4: 8e c0 mov %eax,%es + 102ea6: 8e e0 mov %eax,%fs + 102ea8: 8e e8 mov %eax,%gs + 102eaa: 89 e0 mov %esp,%eax + 102eac: 50 push %eax + +00102ead : + 102ead: b8 04 3e 10 00 mov $0x103e04,%eax + 102eb2: ff d0 call *%eax + 102eb4: e9 2f e8 ff ff jmp 1016e8 + +00102eb9 : + 102eb9: 6a 00 push $0x0 + 102ebb: 6a 9d push $0xffffff9d + 102ebd: 0f a8 push %gs + 102ebf: 0f a0 push %fs + 102ec1: 06 push %es + 102ec2: 1e push %ds + 102ec3: 60 pusha + 102ec4: 66 b8 10 00 mov $0x10,%ax + 102ec8: 8e d8 mov %eax,%ds + 102eca: 8e c0 mov %eax,%es + 102ecc: 8e e0 mov %eax,%fs + 102ece: 8e e8 mov %eax,%gs + 102ed0: 89 e0 mov %esp,%eax + 102ed2: 50 push %eax + +00102ed3 : + 102ed3: b8 04 3e 10 00 mov $0x103e04,%eax + 102ed8: ff d0 call *%eax + 102eda: e9 09 e8 ff ff jmp 1016e8 + +00102edf : + 102edf: 6a 00 push $0x0 + 102ee1: 6a 9e push $0xffffff9e + 102ee3: 0f a8 push %gs + 102ee5: 0f a0 push %fs + 102ee7: 06 push %es + 102ee8: 1e push %ds + 102ee9: 60 pusha + 102eea: 66 b8 10 00 mov $0x10,%ax + 102eee: 8e d8 mov %eax,%ds + 102ef0: 8e c0 mov %eax,%es + 102ef2: 8e e0 mov %eax,%fs + 102ef4: 8e e8 mov %eax,%gs + 102ef6: 89 e0 mov %esp,%eax + 102ef8: 50 push %eax + +00102ef9 : + 102ef9: b8 04 3e 10 00 mov $0x103e04,%eax + 102efe: ff d0 call *%eax + 102f00: e9 e3 e7 ff ff jmp 1016e8 + +00102f05 : + 102f05: 6a 00 push $0x0 + 102f07: 6a 9f push $0xffffff9f + 102f09: 0f a8 push %gs + 102f0b: 0f a0 push %fs + 102f0d: 06 push %es + 102f0e: 1e push %ds + 102f0f: 60 pusha + 102f10: 66 b8 10 00 mov $0x10,%ax + 102f14: 8e d8 mov %eax,%ds + 102f16: 8e c0 mov %eax,%es + 102f18: 8e e0 mov %eax,%fs + 102f1a: 8e e8 mov %eax,%gs + 102f1c: 89 e0 mov %esp,%eax + 102f1e: 50 push %eax + +00102f1f : + 102f1f: b8 04 3e 10 00 mov $0x103e04,%eax + 102f24: ff d0 call *%eax + 102f26: e9 bd e7 ff ff jmp 1016e8 + +00102f2b : + 102f2b: 6a 00 push $0x0 + 102f2d: 6a a0 push $0xffffffa0 + 102f2f: 0f a8 push %gs + 102f31: 0f a0 push %fs + 102f33: 06 push %es + 102f34: 1e push %ds + 102f35: 60 pusha + 102f36: 66 b8 10 00 mov $0x10,%ax + 102f3a: 8e d8 mov %eax,%ds + 102f3c: 8e c0 mov %eax,%es + 102f3e: 8e e0 mov %eax,%fs + 102f40: 8e e8 mov %eax,%gs + 102f42: 89 e0 mov %esp,%eax + 102f44: 50 push %eax + +00102f45 : + 102f45: b8 04 3e 10 00 mov $0x103e04,%eax + 102f4a: ff d0 call *%eax + 102f4c: e9 97 e7 ff ff jmp 1016e8 + +00102f51 : + 102f51: 6a 00 push $0x0 + 102f53: 6a a1 push $0xffffffa1 + 102f55: 0f a8 push %gs + 102f57: 0f a0 push %fs + 102f59: 06 push %es + 102f5a: 1e push %ds + 102f5b: 60 pusha + 102f5c: 66 b8 10 00 mov $0x10,%ax + 102f60: 8e d8 mov %eax,%ds + 102f62: 8e c0 mov %eax,%es + 102f64: 8e e0 mov %eax,%fs + 102f66: 8e e8 mov %eax,%gs + 102f68: 89 e0 mov %esp,%eax + 102f6a: 50 push %eax + +00102f6b : + 102f6b: b8 04 3e 10 00 mov $0x103e04,%eax + 102f70: ff d0 call *%eax + 102f72: e9 71 e7 ff ff jmp 1016e8 + +00102f77 : + 102f77: 6a 00 push $0x0 + 102f79: 6a a2 push $0xffffffa2 + 102f7b: 0f a8 push %gs + 102f7d: 0f a0 push %fs + 102f7f: 06 push %es + 102f80: 1e push %ds + 102f81: 60 pusha + 102f82: 66 b8 10 00 mov $0x10,%ax + 102f86: 8e d8 mov %eax,%ds + 102f88: 8e c0 mov %eax,%es + 102f8a: 8e e0 mov %eax,%fs + 102f8c: 8e e8 mov %eax,%gs + 102f8e: 89 e0 mov %esp,%eax + 102f90: 50 push %eax + +00102f91 : + 102f91: b8 04 3e 10 00 mov $0x103e04,%eax + 102f96: ff d0 call *%eax + 102f98: e9 4b e7 ff ff jmp 1016e8 + +00102f9d : + 102f9d: 6a 00 push $0x0 + 102f9f: 6a a3 push $0xffffffa3 + 102fa1: 0f a8 push %gs + 102fa3: 0f a0 push %fs + 102fa5: 06 push %es + 102fa6: 1e push %ds + 102fa7: 60 pusha + 102fa8: 66 b8 10 00 mov $0x10,%ax + 102fac: 8e d8 mov %eax,%ds + 102fae: 8e c0 mov %eax,%es + 102fb0: 8e e0 mov %eax,%fs + 102fb2: 8e e8 mov %eax,%gs + 102fb4: 89 e0 mov %esp,%eax + 102fb6: 50 push %eax + +00102fb7 : + 102fb7: b8 04 3e 10 00 mov $0x103e04,%eax + 102fbc: ff d0 call *%eax + 102fbe: e9 25 e7 ff ff jmp 1016e8 + +00102fc3 : + 102fc3: 6a 00 push $0x0 + 102fc5: 6a a4 push $0xffffffa4 + 102fc7: 0f a8 push %gs + 102fc9: 0f a0 push %fs + 102fcb: 06 push %es + 102fcc: 1e push %ds + 102fcd: 60 pusha + 102fce: 66 b8 10 00 mov $0x10,%ax + 102fd2: 8e d8 mov %eax,%ds + 102fd4: 8e c0 mov %eax,%es + 102fd6: 8e e0 mov %eax,%fs + 102fd8: 8e e8 mov %eax,%gs + 102fda: 89 e0 mov %esp,%eax + 102fdc: 50 push %eax + +00102fdd : + 102fdd: b8 04 3e 10 00 mov $0x103e04,%eax + 102fe2: ff d0 call *%eax + 102fe4: e9 ff e6 ff ff jmp 1016e8 + +00102fe9 : + 102fe9: 6a 00 push $0x0 + 102feb: 6a a5 push $0xffffffa5 + 102fed: 0f a8 push %gs + 102fef: 0f a0 push %fs + 102ff1: 06 push %es + 102ff2: 1e push %ds + 102ff3: 60 pusha + 102ff4: 66 b8 10 00 mov $0x10,%ax + 102ff8: 8e d8 mov %eax,%ds + 102ffa: 8e c0 mov %eax,%es + 102ffc: 8e e0 mov %eax,%fs + 102ffe: 8e e8 mov %eax,%gs + 103000: 89 e0 mov %esp,%eax + 103002: 50 push %eax + +00103003 : + 103003: b8 04 3e 10 00 mov $0x103e04,%eax + 103008: ff d0 call *%eax + 10300a: e9 d9 e6 ff ff jmp 1016e8 + +0010300f : + 10300f: 6a 00 push $0x0 + 103011: 6a a6 push $0xffffffa6 + 103013: 0f a8 push %gs + 103015: 0f a0 push %fs + 103017: 06 push %es + 103018: 1e push %ds + 103019: 60 pusha + 10301a: 66 b8 10 00 mov $0x10,%ax + 10301e: 8e d8 mov %eax,%ds + 103020: 8e c0 mov %eax,%es + 103022: 8e e0 mov %eax,%fs + 103024: 8e e8 mov %eax,%gs + 103026: 89 e0 mov %esp,%eax + 103028: 50 push %eax + +00103029 : + 103029: b8 04 3e 10 00 mov $0x103e04,%eax + 10302e: ff d0 call *%eax + 103030: e9 b3 e6 ff ff jmp 1016e8 + +00103035 : + 103035: 6a 00 push $0x0 + 103037: 6a a7 push $0xffffffa7 + 103039: 0f a8 push %gs + 10303b: 0f a0 push %fs + 10303d: 06 push %es + 10303e: 1e push %ds + 10303f: 60 pusha + 103040: 66 b8 10 00 mov $0x10,%ax + 103044: 8e d8 mov %eax,%ds + 103046: 8e c0 mov %eax,%es + 103048: 8e e0 mov %eax,%fs + 10304a: 8e e8 mov %eax,%gs + 10304c: 89 e0 mov %esp,%eax + 10304e: 50 push %eax + +0010304f : + 10304f: b8 04 3e 10 00 mov $0x103e04,%eax + 103054: ff d0 call *%eax + 103056: e9 8d e6 ff ff jmp 1016e8 + +0010305b : + 10305b: 6a 00 push $0x0 + 10305d: 6a a8 push $0xffffffa8 + 10305f: 0f a8 push %gs + 103061: 0f a0 push %fs + 103063: 06 push %es + 103064: 1e push %ds + 103065: 60 pusha + 103066: 66 b8 10 00 mov $0x10,%ax + 10306a: 8e d8 mov %eax,%ds + 10306c: 8e c0 mov %eax,%es + 10306e: 8e e0 mov %eax,%fs + 103070: 8e e8 mov %eax,%gs + 103072: 89 e0 mov %esp,%eax + 103074: 50 push %eax + +00103075 : + 103075: b8 04 3e 10 00 mov $0x103e04,%eax + 10307a: ff d0 call *%eax + 10307c: e9 67 e6 ff ff jmp 1016e8 + +00103081 : + 103081: 6a 00 push $0x0 + 103083: 6a a9 push $0xffffffa9 + 103085: 0f a8 push %gs + 103087: 0f a0 push %fs + 103089: 06 push %es + 10308a: 1e push %ds + 10308b: 60 pusha + 10308c: 66 b8 10 00 mov $0x10,%ax + 103090: 8e d8 mov %eax,%ds + 103092: 8e c0 mov %eax,%es + 103094: 8e e0 mov %eax,%fs + 103096: 8e e8 mov %eax,%gs + 103098: 89 e0 mov %esp,%eax + 10309a: 50 push %eax + +0010309b : + 10309b: b8 04 3e 10 00 mov $0x103e04,%eax + 1030a0: ff d0 call *%eax + 1030a2: e9 41 e6 ff ff jmp 1016e8 + +001030a7 : + 1030a7: 6a 00 push $0x0 + 1030a9: 6a aa push $0xffffffaa + 1030ab: 0f a8 push %gs + 1030ad: 0f a0 push %fs + 1030af: 06 push %es + 1030b0: 1e push %ds + 1030b1: 60 pusha + 1030b2: 66 b8 10 00 mov $0x10,%ax + 1030b6: 8e d8 mov %eax,%ds + 1030b8: 8e c0 mov %eax,%es + 1030ba: 8e e0 mov %eax,%fs + 1030bc: 8e e8 mov %eax,%gs + 1030be: 89 e0 mov %esp,%eax + 1030c0: 50 push %eax + +001030c1 : + 1030c1: b8 04 3e 10 00 mov $0x103e04,%eax + 1030c6: ff d0 call *%eax + 1030c8: e9 1b e6 ff ff jmp 1016e8 + +001030cd : + 1030cd: 6a 00 push $0x0 + 1030cf: 6a ab push $0xffffffab + 1030d1: 0f a8 push %gs + 1030d3: 0f a0 push %fs + 1030d5: 06 push %es + 1030d6: 1e push %ds + 1030d7: 60 pusha + 1030d8: 66 b8 10 00 mov $0x10,%ax + 1030dc: 8e d8 mov %eax,%ds + 1030de: 8e c0 mov %eax,%es + 1030e0: 8e e0 mov %eax,%fs + 1030e2: 8e e8 mov %eax,%gs + 1030e4: 89 e0 mov %esp,%eax + 1030e6: 50 push %eax + +001030e7 : + 1030e7: b8 04 3e 10 00 mov $0x103e04,%eax + 1030ec: ff d0 call *%eax + 1030ee: e9 f5 e5 ff ff jmp 1016e8 + +001030f3 : + 1030f3: 6a 00 push $0x0 + 1030f5: 6a ac push $0xffffffac + 1030f7: 0f a8 push %gs + 1030f9: 0f a0 push %fs + 1030fb: 06 push %es + 1030fc: 1e push %ds + 1030fd: 60 pusha + 1030fe: 66 b8 10 00 mov $0x10,%ax + 103102: 8e d8 mov %eax,%ds + 103104: 8e c0 mov %eax,%es + 103106: 8e e0 mov %eax,%fs + 103108: 8e e8 mov %eax,%gs + 10310a: 89 e0 mov %esp,%eax + 10310c: 50 push %eax + +0010310d : + 10310d: b8 04 3e 10 00 mov $0x103e04,%eax + 103112: ff d0 call *%eax + 103114: e9 cf e5 ff ff jmp 1016e8 + +00103119 : + 103119: 6a 00 push $0x0 + 10311b: 6a ad push $0xffffffad + 10311d: 0f a8 push %gs + 10311f: 0f a0 push %fs + 103121: 06 push %es + 103122: 1e push %ds + 103123: 60 pusha + 103124: 66 b8 10 00 mov $0x10,%ax + 103128: 8e d8 mov %eax,%ds + 10312a: 8e c0 mov %eax,%es + 10312c: 8e e0 mov %eax,%fs + 10312e: 8e e8 mov %eax,%gs + 103130: 89 e0 mov %esp,%eax + 103132: 50 push %eax + +00103133 : + 103133: b8 04 3e 10 00 mov $0x103e04,%eax + 103138: ff d0 call *%eax + 10313a: e9 a9 e5 ff ff jmp 1016e8 + +0010313f : + 10313f: 6a 00 push $0x0 + 103141: 6a ae push $0xffffffae + 103143: 0f a8 push %gs + 103145: 0f a0 push %fs + 103147: 06 push %es + 103148: 1e push %ds + 103149: 60 pusha + 10314a: 66 b8 10 00 mov $0x10,%ax + 10314e: 8e d8 mov %eax,%ds + 103150: 8e c0 mov %eax,%es + 103152: 8e e0 mov %eax,%fs + 103154: 8e e8 mov %eax,%gs + 103156: 89 e0 mov %esp,%eax + 103158: 50 push %eax + +00103159 : + 103159: b8 04 3e 10 00 mov $0x103e04,%eax + 10315e: ff d0 call *%eax + 103160: e9 83 e5 ff ff jmp 1016e8 + +00103165 : + 103165: 6a 00 push $0x0 + 103167: 6a af push $0xffffffaf + 103169: 0f a8 push %gs + 10316b: 0f a0 push %fs + 10316d: 06 push %es + 10316e: 1e push %ds + 10316f: 60 pusha + 103170: 66 b8 10 00 mov $0x10,%ax + 103174: 8e d8 mov %eax,%ds + 103176: 8e c0 mov %eax,%es + 103178: 8e e0 mov %eax,%fs + 10317a: 8e e8 mov %eax,%gs + 10317c: 89 e0 mov %esp,%eax + 10317e: 50 push %eax + +0010317f : + 10317f: b8 04 3e 10 00 mov $0x103e04,%eax + 103184: ff d0 call *%eax + 103186: e9 5d e5 ff ff jmp 1016e8 + +0010318b : + 10318b: 6a 00 push $0x0 + 10318d: 6a b0 push $0xffffffb0 + 10318f: 0f a8 push %gs + 103191: 0f a0 push %fs + 103193: 06 push %es + 103194: 1e push %ds + 103195: 60 pusha + 103196: 66 b8 10 00 mov $0x10,%ax + 10319a: 8e d8 mov %eax,%ds + 10319c: 8e c0 mov %eax,%es + 10319e: 8e e0 mov %eax,%fs + 1031a0: 8e e8 mov %eax,%gs + 1031a2: 89 e0 mov %esp,%eax + 1031a4: 50 push %eax + +001031a5 : + 1031a5: b8 04 3e 10 00 mov $0x103e04,%eax + 1031aa: ff d0 call *%eax + 1031ac: e9 37 e5 ff ff jmp 1016e8 + +001031b1 : + 1031b1: 6a 00 push $0x0 + 1031b3: 6a b1 push $0xffffffb1 + 1031b5: 0f a8 push %gs + 1031b7: 0f a0 push %fs + 1031b9: 06 push %es + 1031ba: 1e push %ds + 1031bb: 60 pusha + 1031bc: 66 b8 10 00 mov $0x10,%ax + 1031c0: 8e d8 mov %eax,%ds + 1031c2: 8e c0 mov %eax,%es + 1031c4: 8e e0 mov %eax,%fs + 1031c6: 8e e8 mov %eax,%gs + 1031c8: 89 e0 mov %esp,%eax + 1031ca: 50 push %eax + +001031cb : + 1031cb: b8 04 3e 10 00 mov $0x103e04,%eax + 1031d0: ff d0 call *%eax + 1031d2: e9 11 e5 ff ff jmp 1016e8 + +001031d7 : + 1031d7: 6a 00 push $0x0 + 1031d9: 6a b2 push $0xffffffb2 + 1031db: 0f a8 push %gs + 1031dd: 0f a0 push %fs + 1031df: 06 push %es + 1031e0: 1e push %ds + 1031e1: 60 pusha + 1031e2: 66 b8 10 00 mov $0x10,%ax + 1031e6: 8e d8 mov %eax,%ds + 1031e8: 8e c0 mov %eax,%es + 1031ea: 8e e0 mov %eax,%fs + 1031ec: 8e e8 mov %eax,%gs + 1031ee: 89 e0 mov %esp,%eax + 1031f0: 50 push %eax + +001031f1 : + 1031f1: b8 04 3e 10 00 mov $0x103e04,%eax + 1031f6: ff d0 call *%eax + 1031f8: e9 eb e4 ff ff jmp 1016e8 + +001031fd : + 1031fd: 6a 00 push $0x0 + 1031ff: 6a b3 push $0xffffffb3 + 103201: 0f a8 push %gs + 103203: 0f a0 push %fs + 103205: 06 push %es + 103206: 1e push %ds + 103207: 60 pusha + 103208: 66 b8 10 00 mov $0x10,%ax + 10320c: 8e d8 mov %eax,%ds + 10320e: 8e c0 mov %eax,%es + 103210: 8e e0 mov %eax,%fs + 103212: 8e e8 mov %eax,%gs + 103214: 89 e0 mov %esp,%eax + 103216: 50 push %eax + +00103217 : + 103217: b8 04 3e 10 00 mov $0x103e04,%eax + 10321c: ff d0 call *%eax + 10321e: e9 c5 e4 ff ff jmp 1016e8 + +00103223 : + 103223: 6a 00 push $0x0 + 103225: 6a b4 push $0xffffffb4 + 103227: 0f a8 push %gs + 103229: 0f a0 push %fs + 10322b: 06 push %es + 10322c: 1e push %ds + 10322d: 60 pusha + 10322e: 66 b8 10 00 mov $0x10,%ax + 103232: 8e d8 mov %eax,%ds + 103234: 8e c0 mov %eax,%es + 103236: 8e e0 mov %eax,%fs + 103238: 8e e8 mov %eax,%gs + 10323a: 89 e0 mov %esp,%eax + 10323c: 50 push %eax + +0010323d : + 10323d: b8 04 3e 10 00 mov $0x103e04,%eax + 103242: ff d0 call *%eax + 103244: e9 9f e4 ff ff jmp 1016e8 + +00103249 : + 103249: 6a 00 push $0x0 + 10324b: 6a b5 push $0xffffffb5 + 10324d: 0f a8 push %gs + 10324f: 0f a0 push %fs + 103251: 06 push %es + 103252: 1e push %ds + 103253: 60 pusha + 103254: 66 b8 10 00 mov $0x10,%ax + 103258: 8e d8 mov %eax,%ds + 10325a: 8e c0 mov %eax,%es + 10325c: 8e e0 mov %eax,%fs + 10325e: 8e e8 mov %eax,%gs + 103260: 89 e0 mov %esp,%eax + 103262: 50 push %eax + +00103263 : + 103263: b8 04 3e 10 00 mov $0x103e04,%eax + 103268: ff d0 call *%eax + 10326a: e9 79 e4 ff ff jmp 1016e8 + +0010326f : + 10326f: 6a 00 push $0x0 + 103271: 6a b6 push $0xffffffb6 + 103273: 0f a8 push %gs + 103275: 0f a0 push %fs + 103277: 06 push %es + 103278: 1e push %ds + 103279: 60 pusha + 10327a: 66 b8 10 00 mov $0x10,%ax + 10327e: 8e d8 mov %eax,%ds + 103280: 8e c0 mov %eax,%es + 103282: 8e e0 mov %eax,%fs + 103284: 8e e8 mov %eax,%gs + 103286: 89 e0 mov %esp,%eax + 103288: 50 push %eax + +00103289 : + 103289: b8 04 3e 10 00 mov $0x103e04,%eax + 10328e: ff d0 call *%eax + 103290: e9 53 e4 ff ff jmp 1016e8 + +00103295 : + 103295: 6a 00 push $0x0 + 103297: 6a b7 push $0xffffffb7 + 103299: 0f a8 push %gs + 10329b: 0f a0 push %fs + 10329d: 06 push %es + 10329e: 1e push %ds + 10329f: 60 pusha + 1032a0: 66 b8 10 00 mov $0x10,%ax + 1032a4: 8e d8 mov %eax,%ds + 1032a6: 8e c0 mov %eax,%es + 1032a8: 8e e0 mov %eax,%fs + 1032aa: 8e e8 mov %eax,%gs + 1032ac: 89 e0 mov %esp,%eax + 1032ae: 50 push %eax + +001032af : + 1032af: b8 04 3e 10 00 mov $0x103e04,%eax + 1032b4: ff d0 call *%eax + 1032b6: e9 2d e4 ff ff jmp 1016e8 + +001032bb : + 1032bb: 6a 00 push $0x0 + 1032bd: 6a b8 push $0xffffffb8 + 1032bf: 0f a8 push %gs + 1032c1: 0f a0 push %fs + 1032c3: 06 push %es + 1032c4: 1e push %ds + 1032c5: 60 pusha + 1032c6: 66 b8 10 00 mov $0x10,%ax + 1032ca: 8e d8 mov %eax,%ds + 1032cc: 8e c0 mov %eax,%es + 1032ce: 8e e0 mov %eax,%fs + 1032d0: 8e e8 mov %eax,%gs + 1032d2: 89 e0 mov %esp,%eax + 1032d4: 50 push %eax + +001032d5 : + 1032d5: b8 04 3e 10 00 mov $0x103e04,%eax + 1032da: ff d0 call *%eax + 1032dc: e9 07 e4 ff ff jmp 1016e8 + +001032e1 : + 1032e1: 6a 00 push $0x0 + 1032e3: 6a b9 push $0xffffffb9 + 1032e5: 0f a8 push %gs + 1032e7: 0f a0 push %fs + 1032e9: 06 push %es + 1032ea: 1e push %ds + 1032eb: 60 pusha + 1032ec: 66 b8 10 00 mov $0x10,%ax + 1032f0: 8e d8 mov %eax,%ds + 1032f2: 8e c0 mov %eax,%es + 1032f4: 8e e0 mov %eax,%fs + 1032f6: 8e e8 mov %eax,%gs + 1032f8: 89 e0 mov %esp,%eax + 1032fa: 50 push %eax + +001032fb : + 1032fb: b8 04 3e 10 00 mov $0x103e04,%eax + 103300: ff d0 call *%eax + 103302: e9 e1 e3 ff ff jmp 1016e8 + +00103307 : + 103307: 6a 00 push $0x0 + 103309: 6a ba push $0xffffffba + 10330b: 0f a8 push %gs + 10330d: 0f a0 push %fs + 10330f: 06 push %es + 103310: 1e push %ds + 103311: 60 pusha + 103312: 66 b8 10 00 mov $0x10,%ax + 103316: 8e d8 mov %eax,%ds + 103318: 8e c0 mov %eax,%es + 10331a: 8e e0 mov %eax,%fs + 10331c: 8e e8 mov %eax,%gs + 10331e: 89 e0 mov %esp,%eax + 103320: 50 push %eax + +00103321 : + 103321: b8 04 3e 10 00 mov $0x103e04,%eax + 103326: ff d0 call *%eax + 103328: e9 bb e3 ff ff jmp 1016e8 + +0010332d : + 10332d: 6a 00 push $0x0 + 10332f: 6a bb push $0xffffffbb + 103331: 0f a8 push %gs + 103333: 0f a0 push %fs + 103335: 06 push %es + 103336: 1e push %ds + 103337: 60 pusha + 103338: 66 b8 10 00 mov $0x10,%ax + 10333c: 8e d8 mov %eax,%ds + 10333e: 8e c0 mov %eax,%es + 103340: 8e e0 mov %eax,%fs + 103342: 8e e8 mov %eax,%gs + 103344: 89 e0 mov %esp,%eax + 103346: 50 push %eax + +00103347 : + 103347: b8 04 3e 10 00 mov $0x103e04,%eax + 10334c: ff d0 call *%eax + 10334e: e9 95 e3 ff ff jmp 1016e8 + +00103353 : + 103353: 6a 00 push $0x0 + 103355: 6a bc push $0xffffffbc + 103357: 0f a8 push %gs + 103359: 0f a0 push %fs + 10335b: 06 push %es + 10335c: 1e push %ds + 10335d: 60 pusha + 10335e: 66 b8 10 00 mov $0x10,%ax + 103362: 8e d8 mov %eax,%ds + 103364: 8e c0 mov %eax,%es + 103366: 8e e0 mov %eax,%fs + 103368: 8e e8 mov %eax,%gs + 10336a: 89 e0 mov %esp,%eax + 10336c: 50 push %eax + +0010336d : + 10336d: b8 04 3e 10 00 mov $0x103e04,%eax + 103372: ff d0 call *%eax + 103374: e9 6f e3 ff ff jmp 1016e8 + +00103379 : + 103379: 6a 00 push $0x0 + 10337b: 6a bd push $0xffffffbd + 10337d: 0f a8 push %gs + 10337f: 0f a0 push %fs + 103381: 06 push %es + 103382: 1e push %ds + 103383: 60 pusha + 103384: 66 b8 10 00 mov $0x10,%ax + 103388: 8e d8 mov %eax,%ds + 10338a: 8e c0 mov %eax,%es + 10338c: 8e e0 mov %eax,%fs + 10338e: 8e e8 mov %eax,%gs + 103390: 89 e0 mov %esp,%eax + 103392: 50 push %eax + +00103393 : + 103393: b8 04 3e 10 00 mov $0x103e04,%eax + 103398: ff d0 call *%eax + 10339a: e9 49 e3 ff ff jmp 1016e8 + +0010339f : + 10339f: 6a 00 push $0x0 + 1033a1: 6a be push $0xffffffbe + 1033a3: 0f a8 push %gs + 1033a5: 0f a0 push %fs + 1033a7: 06 push %es + 1033a8: 1e push %ds + 1033a9: 60 pusha + 1033aa: 66 b8 10 00 mov $0x10,%ax + 1033ae: 8e d8 mov %eax,%ds + 1033b0: 8e c0 mov %eax,%es + 1033b2: 8e e0 mov %eax,%fs + 1033b4: 8e e8 mov %eax,%gs + 1033b6: 89 e0 mov %esp,%eax + 1033b8: 50 push %eax + +001033b9 : + 1033b9: b8 04 3e 10 00 mov $0x103e04,%eax + 1033be: ff d0 call *%eax + 1033c0: e9 23 e3 ff ff jmp 1016e8 + +001033c5 : + 1033c5: 6a 00 push $0x0 + 1033c7: 6a bf push $0xffffffbf + 1033c9: 0f a8 push %gs + 1033cb: 0f a0 push %fs + 1033cd: 06 push %es + 1033ce: 1e push %ds + 1033cf: 60 pusha + 1033d0: 66 b8 10 00 mov $0x10,%ax + 1033d4: 8e d8 mov %eax,%ds + 1033d6: 8e c0 mov %eax,%es + 1033d8: 8e e0 mov %eax,%fs + 1033da: 8e e8 mov %eax,%gs + 1033dc: 89 e0 mov %esp,%eax + 1033de: 50 push %eax + +001033df : + 1033df: b8 04 3e 10 00 mov $0x103e04,%eax + 1033e4: ff d0 call *%eax + 1033e6: e9 fd e2 ff ff jmp 1016e8 + +001033eb : + 1033eb: 6a 00 push $0x0 + 1033ed: 6a c0 push $0xffffffc0 + 1033ef: 0f a8 push %gs + 1033f1: 0f a0 push %fs + 1033f3: 06 push %es + 1033f4: 1e push %ds + 1033f5: 60 pusha + 1033f6: 66 b8 10 00 mov $0x10,%ax + 1033fa: 8e d8 mov %eax,%ds + 1033fc: 8e c0 mov %eax,%es + 1033fe: 8e e0 mov %eax,%fs + 103400: 8e e8 mov %eax,%gs + 103402: 89 e0 mov %esp,%eax + 103404: 50 push %eax + +00103405 : + 103405: b8 04 3e 10 00 mov $0x103e04,%eax + 10340a: ff d0 call *%eax + 10340c: e9 d7 e2 ff ff jmp 1016e8 + +00103411 : + 103411: 6a 00 push $0x0 + 103413: 6a c1 push $0xffffffc1 + 103415: 0f a8 push %gs + 103417: 0f a0 push %fs + 103419: 06 push %es + 10341a: 1e push %ds + 10341b: 60 pusha + 10341c: 66 b8 10 00 mov $0x10,%ax + 103420: 8e d8 mov %eax,%ds + 103422: 8e c0 mov %eax,%es + 103424: 8e e0 mov %eax,%fs + 103426: 8e e8 mov %eax,%gs + 103428: 89 e0 mov %esp,%eax + 10342a: 50 push %eax + +0010342b : + 10342b: b8 04 3e 10 00 mov $0x103e04,%eax + 103430: ff d0 call *%eax + 103432: e9 b1 e2 ff ff jmp 1016e8 + +00103437 : + 103437: 6a 00 push $0x0 + 103439: 6a c2 push $0xffffffc2 + 10343b: 0f a8 push %gs + 10343d: 0f a0 push %fs + 10343f: 06 push %es + 103440: 1e push %ds + 103441: 60 pusha + 103442: 66 b8 10 00 mov $0x10,%ax + 103446: 8e d8 mov %eax,%ds + 103448: 8e c0 mov %eax,%es + 10344a: 8e e0 mov %eax,%fs + 10344c: 8e e8 mov %eax,%gs + 10344e: 89 e0 mov %esp,%eax + 103450: 50 push %eax + +00103451 : + 103451: b8 04 3e 10 00 mov $0x103e04,%eax + 103456: ff d0 call *%eax + 103458: e9 8b e2 ff ff jmp 1016e8 + +0010345d : + 10345d: 6a 00 push $0x0 + 10345f: 6a c3 push $0xffffffc3 + 103461: 0f a8 push %gs + 103463: 0f a0 push %fs + 103465: 06 push %es + 103466: 1e push %ds + 103467: 60 pusha + 103468: 66 b8 10 00 mov $0x10,%ax + 10346c: 8e d8 mov %eax,%ds + 10346e: 8e c0 mov %eax,%es + 103470: 8e e0 mov %eax,%fs + 103472: 8e e8 mov %eax,%gs + 103474: 89 e0 mov %esp,%eax + 103476: 50 push %eax + +00103477 : + 103477: b8 04 3e 10 00 mov $0x103e04,%eax + 10347c: ff d0 call *%eax + 10347e: e9 65 e2 ff ff jmp 1016e8 + +00103483 : + 103483: 6a 00 push $0x0 + 103485: 6a c4 push $0xffffffc4 + 103487: 0f a8 push %gs + 103489: 0f a0 push %fs + 10348b: 06 push %es + 10348c: 1e push %ds + 10348d: 60 pusha + 10348e: 66 b8 10 00 mov $0x10,%ax + 103492: 8e d8 mov %eax,%ds + 103494: 8e c0 mov %eax,%es + 103496: 8e e0 mov %eax,%fs + 103498: 8e e8 mov %eax,%gs + 10349a: 89 e0 mov %esp,%eax + 10349c: 50 push %eax + +0010349d : + 10349d: b8 04 3e 10 00 mov $0x103e04,%eax + 1034a2: ff d0 call *%eax + 1034a4: e9 3f e2 ff ff jmp 1016e8 + +001034a9 : + 1034a9: 6a 00 push $0x0 + 1034ab: 6a c5 push $0xffffffc5 + 1034ad: 0f a8 push %gs + 1034af: 0f a0 push %fs + 1034b1: 06 push %es + 1034b2: 1e push %ds + 1034b3: 60 pusha + 1034b4: 66 b8 10 00 mov $0x10,%ax + 1034b8: 8e d8 mov %eax,%ds + 1034ba: 8e c0 mov %eax,%es + 1034bc: 8e e0 mov %eax,%fs + 1034be: 8e e8 mov %eax,%gs + 1034c0: 89 e0 mov %esp,%eax + 1034c2: 50 push %eax + +001034c3 : + 1034c3: b8 04 3e 10 00 mov $0x103e04,%eax + 1034c8: ff d0 call *%eax + 1034ca: e9 19 e2 ff ff jmp 1016e8 + +001034cf : + 1034cf: 6a 00 push $0x0 + 1034d1: 6a c6 push $0xffffffc6 + 1034d3: 0f a8 push %gs + 1034d5: 0f a0 push %fs + 1034d7: 06 push %es + 1034d8: 1e push %ds + 1034d9: 60 pusha + 1034da: 66 b8 10 00 mov $0x10,%ax + 1034de: 8e d8 mov %eax,%ds + 1034e0: 8e c0 mov %eax,%es + 1034e2: 8e e0 mov %eax,%fs + 1034e4: 8e e8 mov %eax,%gs + 1034e6: 89 e0 mov %esp,%eax + 1034e8: 50 push %eax + +001034e9 : + 1034e9: b8 04 3e 10 00 mov $0x103e04,%eax + 1034ee: ff d0 call *%eax + 1034f0: e9 f3 e1 ff ff jmp 1016e8 + +001034f5 : + 1034f5: 6a 00 push $0x0 + 1034f7: 6a c7 push $0xffffffc7 + 1034f9: 0f a8 push %gs + 1034fb: 0f a0 push %fs + 1034fd: 06 push %es + 1034fe: 1e push %ds + 1034ff: 60 pusha + 103500: 66 b8 10 00 mov $0x10,%ax + 103504: 8e d8 mov %eax,%ds + 103506: 8e c0 mov %eax,%es + 103508: 8e e0 mov %eax,%fs + 10350a: 8e e8 mov %eax,%gs + 10350c: 89 e0 mov %esp,%eax + 10350e: 50 push %eax + +0010350f : + 10350f: b8 04 3e 10 00 mov $0x103e04,%eax + 103514: ff d0 call *%eax + 103516: e9 cd e1 ff ff jmp 1016e8 + +0010351b : + 10351b: 6a 00 push $0x0 + 10351d: 6a c8 push $0xffffffc8 + 10351f: 0f a8 push %gs + 103521: 0f a0 push %fs + 103523: 06 push %es + 103524: 1e push %ds + 103525: 60 pusha + 103526: 66 b8 10 00 mov $0x10,%ax + 10352a: 8e d8 mov %eax,%ds + 10352c: 8e c0 mov %eax,%es + 10352e: 8e e0 mov %eax,%fs + 103530: 8e e8 mov %eax,%gs + 103532: 89 e0 mov %esp,%eax + 103534: 50 push %eax + +00103535 : + 103535: b8 04 3e 10 00 mov $0x103e04,%eax + 10353a: ff d0 call *%eax + 10353c: e9 a7 e1 ff ff jmp 1016e8 + +00103541 : + 103541: 6a 00 push $0x0 + 103543: 6a c9 push $0xffffffc9 + 103545: 0f a8 push %gs + 103547: 0f a0 push %fs + 103549: 06 push %es + 10354a: 1e push %ds + 10354b: 60 pusha + 10354c: 66 b8 10 00 mov $0x10,%ax + 103550: 8e d8 mov %eax,%ds + 103552: 8e c0 mov %eax,%es + 103554: 8e e0 mov %eax,%fs + 103556: 8e e8 mov %eax,%gs + 103558: 89 e0 mov %esp,%eax + 10355a: 50 push %eax + +0010355b : + 10355b: b8 04 3e 10 00 mov $0x103e04,%eax + 103560: ff d0 call *%eax + 103562: e9 81 e1 ff ff jmp 1016e8 + +00103567 : + 103567: 6a 00 push $0x0 + 103569: 6a ca push $0xffffffca + 10356b: 0f a8 push %gs + 10356d: 0f a0 push %fs + 10356f: 06 push %es + 103570: 1e push %ds + 103571: 60 pusha + 103572: 66 b8 10 00 mov $0x10,%ax + 103576: 8e d8 mov %eax,%ds + 103578: 8e c0 mov %eax,%es + 10357a: 8e e0 mov %eax,%fs + 10357c: 8e e8 mov %eax,%gs + 10357e: 89 e0 mov %esp,%eax + 103580: 50 push %eax + +00103581 : + 103581: b8 04 3e 10 00 mov $0x103e04,%eax + 103586: ff d0 call *%eax + 103588: e9 5b e1 ff ff jmp 1016e8 + +0010358d : + 10358d: 6a 00 push $0x0 + 10358f: 6a cb push $0xffffffcb + 103591: 0f a8 push %gs + 103593: 0f a0 push %fs + 103595: 06 push %es + 103596: 1e push %ds + 103597: 60 pusha + 103598: 66 b8 10 00 mov $0x10,%ax + 10359c: 8e d8 mov %eax,%ds + 10359e: 8e c0 mov %eax,%es + 1035a0: 8e e0 mov %eax,%fs + 1035a2: 8e e8 mov %eax,%gs + 1035a4: 89 e0 mov %esp,%eax + 1035a6: 50 push %eax + +001035a7 : + 1035a7: b8 04 3e 10 00 mov $0x103e04,%eax + 1035ac: ff d0 call *%eax + 1035ae: e9 35 e1 ff ff jmp 1016e8 + +001035b3 : + 1035b3: 6a 00 push $0x0 + 1035b5: 6a cc push $0xffffffcc + 1035b7: 0f a8 push %gs + 1035b9: 0f a0 push %fs + 1035bb: 06 push %es + 1035bc: 1e push %ds + 1035bd: 60 pusha + 1035be: 66 b8 10 00 mov $0x10,%ax + 1035c2: 8e d8 mov %eax,%ds + 1035c4: 8e c0 mov %eax,%es + 1035c6: 8e e0 mov %eax,%fs + 1035c8: 8e e8 mov %eax,%gs + 1035ca: 89 e0 mov %esp,%eax + 1035cc: 50 push %eax + +001035cd : + 1035cd: b8 04 3e 10 00 mov $0x103e04,%eax + 1035d2: ff d0 call *%eax + 1035d4: e9 0f e1 ff ff jmp 1016e8 + +001035d9 : + 1035d9: 6a 00 push $0x0 + 1035db: 6a cd push $0xffffffcd + 1035dd: 0f a8 push %gs + 1035df: 0f a0 push %fs + 1035e1: 06 push %es + 1035e2: 1e push %ds + 1035e3: 60 pusha + 1035e4: 66 b8 10 00 mov $0x10,%ax + 1035e8: 8e d8 mov %eax,%ds + 1035ea: 8e c0 mov %eax,%es + 1035ec: 8e e0 mov %eax,%fs + 1035ee: 8e e8 mov %eax,%gs + 1035f0: 89 e0 mov %esp,%eax + 1035f2: 50 push %eax + +001035f3 : + 1035f3: b8 04 3e 10 00 mov $0x103e04,%eax + 1035f8: ff d0 call *%eax + 1035fa: e9 e9 e0 ff ff jmp 1016e8 + +001035ff : + 1035ff: 6a 00 push $0x0 + 103601: 6a ce push $0xffffffce + 103603: 0f a8 push %gs + 103605: 0f a0 push %fs + 103607: 06 push %es + 103608: 1e push %ds + 103609: 60 pusha + 10360a: 66 b8 10 00 mov $0x10,%ax + 10360e: 8e d8 mov %eax,%ds + 103610: 8e c0 mov %eax,%es + 103612: 8e e0 mov %eax,%fs + 103614: 8e e8 mov %eax,%gs + 103616: 89 e0 mov %esp,%eax + 103618: 50 push %eax + +00103619 : + 103619: b8 04 3e 10 00 mov $0x103e04,%eax + 10361e: ff d0 call *%eax + 103620: e9 c3 e0 ff ff jmp 1016e8 + +00103625 : + 103625: 6a 00 push $0x0 + 103627: 6a cf push $0xffffffcf + 103629: 0f a8 push %gs + 10362b: 0f a0 push %fs + 10362d: 06 push %es + 10362e: 1e push %ds + 10362f: 60 pusha + 103630: 66 b8 10 00 mov $0x10,%ax + 103634: 8e d8 mov %eax,%ds + 103636: 8e c0 mov %eax,%es + 103638: 8e e0 mov %eax,%fs + 10363a: 8e e8 mov %eax,%gs + 10363c: 89 e0 mov %esp,%eax + 10363e: 50 push %eax + +0010363f : + 10363f: b8 04 3e 10 00 mov $0x103e04,%eax + 103644: ff d0 call *%eax + 103646: e9 9d e0 ff ff jmp 1016e8 + +0010364b : + 10364b: 6a 00 push $0x0 + 10364d: 6a d0 push $0xffffffd0 + 10364f: 0f a8 push %gs + 103651: 0f a0 push %fs + 103653: 06 push %es + 103654: 1e push %ds + 103655: 60 pusha + 103656: 66 b8 10 00 mov $0x10,%ax + 10365a: 8e d8 mov %eax,%ds + 10365c: 8e c0 mov %eax,%es + 10365e: 8e e0 mov %eax,%fs + 103660: 8e e8 mov %eax,%gs + 103662: 89 e0 mov %esp,%eax + 103664: 50 push %eax + +00103665 : + 103665: b8 04 3e 10 00 mov $0x103e04,%eax + 10366a: ff d0 call *%eax + 10366c: e9 77 e0 ff ff jmp 1016e8 + +00103671 : + 103671: 6a 00 push $0x0 + 103673: 6a d1 push $0xffffffd1 + 103675: 0f a8 push %gs + 103677: 0f a0 push %fs + 103679: 06 push %es + 10367a: 1e push %ds + 10367b: 60 pusha + 10367c: 66 b8 10 00 mov $0x10,%ax + 103680: 8e d8 mov %eax,%ds + 103682: 8e c0 mov %eax,%es + 103684: 8e e0 mov %eax,%fs + 103686: 8e e8 mov %eax,%gs + 103688: 89 e0 mov %esp,%eax + 10368a: 50 push %eax + +0010368b : + 10368b: b8 04 3e 10 00 mov $0x103e04,%eax + 103690: ff d0 call *%eax + 103692: e9 51 e0 ff ff jmp 1016e8 + +00103697 : + 103697: 6a 00 push $0x0 + 103699: 6a d2 push $0xffffffd2 + 10369b: 0f a8 push %gs + 10369d: 0f a0 push %fs + 10369f: 06 push %es + 1036a0: 1e push %ds + 1036a1: 60 pusha + 1036a2: 66 b8 10 00 mov $0x10,%ax + 1036a6: 8e d8 mov %eax,%ds + 1036a8: 8e c0 mov %eax,%es + 1036aa: 8e e0 mov %eax,%fs + 1036ac: 8e e8 mov %eax,%gs + 1036ae: 89 e0 mov %esp,%eax + 1036b0: 50 push %eax + +001036b1 : + 1036b1: b8 04 3e 10 00 mov $0x103e04,%eax + 1036b6: ff d0 call *%eax + 1036b8: e9 2b e0 ff ff jmp 1016e8 + +001036bd : + 1036bd: 6a 00 push $0x0 + 1036bf: 6a d3 push $0xffffffd3 + 1036c1: 0f a8 push %gs + 1036c3: 0f a0 push %fs + 1036c5: 06 push %es + 1036c6: 1e push %ds + 1036c7: 60 pusha + 1036c8: 66 b8 10 00 mov $0x10,%ax + 1036cc: 8e d8 mov %eax,%ds + 1036ce: 8e c0 mov %eax,%es + 1036d0: 8e e0 mov %eax,%fs + 1036d2: 8e e8 mov %eax,%gs + 1036d4: 89 e0 mov %esp,%eax + 1036d6: 50 push %eax + +001036d7 : + 1036d7: b8 04 3e 10 00 mov $0x103e04,%eax + 1036dc: ff d0 call *%eax + 1036de: e9 05 e0 ff ff jmp 1016e8 + +001036e3 : + 1036e3: 6a 00 push $0x0 + 1036e5: 6a d4 push $0xffffffd4 + 1036e7: 0f a8 push %gs + 1036e9: 0f a0 push %fs + 1036eb: 06 push %es + 1036ec: 1e push %ds + 1036ed: 60 pusha + 1036ee: 66 b8 10 00 mov $0x10,%ax + 1036f2: 8e d8 mov %eax,%ds + 1036f4: 8e c0 mov %eax,%es + 1036f6: 8e e0 mov %eax,%fs + 1036f8: 8e e8 mov %eax,%gs + 1036fa: 89 e0 mov %esp,%eax + 1036fc: 50 push %eax + +001036fd : + 1036fd: b8 04 3e 10 00 mov $0x103e04,%eax + 103702: ff d0 call *%eax + 103704: e9 df df ff ff jmp 1016e8 + +00103709 : + 103709: 6a 00 push $0x0 + 10370b: 6a d5 push $0xffffffd5 + 10370d: 0f a8 push %gs + 10370f: 0f a0 push %fs + 103711: 06 push %es + 103712: 1e push %ds + 103713: 60 pusha + 103714: 66 b8 10 00 mov $0x10,%ax + 103718: 8e d8 mov %eax,%ds + 10371a: 8e c0 mov %eax,%es + 10371c: 8e e0 mov %eax,%fs + 10371e: 8e e8 mov %eax,%gs + 103720: 89 e0 mov %esp,%eax + 103722: 50 push %eax + +00103723 : + 103723: b8 04 3e 10 00 mov $0x103e04,%eax + 103728: ff d0 call *%eax + 10372a: e9 b9 df ff ff jmp 1016e8 + +0010372f : + 10372f: 6a 00 push $0x0 + 103731: 6a d6 push $0xffffffd6 + 103733: 0f a8 push %gs + 103735: 0f a0 push %fs + 103737: 06 push %es + 103738: 1e push %ds + 103739: 60 pusha + 10373a: 66 b8 10 00 mov $0x10,%ax + 10373e: 8e d8 mov %eax,%ds + 103740: 8e c0 mov %eax,%es + 103742: 8e e0 mov %eax,%fs + 103744: 8e e8 mov %eax,%gs + 103746: 89 e0 mov %esp,%eax + 103748: 50 push %eax + +00103749 : + 103749: b8 04 3e 10 00 mov $0x103e04,%eax + 10374e: ff d0 call *%eax + 103750: e9 93 df ff ff jmp 1016e8 + +00103755 : + 103755: 6a 00 push $0x0 + 103757: 6a d7 push $0xffffffd7 + 103759: 0f a8 push %gs + 10375b: 0f a0 push %fs + 10375d: 06 push %es + 10375e: 1e push %ds + 10375f: 60 pusha + 103760: 66 b8 10 00 mov $0x10,%ax + 103764: 8e d8 mov %eax,%ds + 103766: 8e c0 mov %eax,%es + 103768: 8e e0 mov %eax,%fs + 10376a: 8e e8 mov %eax,%gs + 10376c: 89 e0 mov %esp,%eax + 10376e: 50 push %eax + +0010376f : + 10376f: b8 04 3e 10 00 mov $0x103e04,%eax + 103774: ff d0 call *%eax + 103776: e9 6d df ff ff jmp 1016e8 + +0010377b : + 10377b: 6a 00 push $0x0 + 10377d: 6a d8 push $0xffffffd8 + 10377f: 0f a8 push %gs + 103781: 0f a0 push %fs + 103783: 06 push %es + 103784: 1e push %ds + 103785: 60 pusha + 103786: 66 b8 10 00 mov $0x10,%ax + 10378a: 8e d8 mov %eax,%ds + 10378c: 8e c0 mov %eax,%es + 10378e: 8e e0 mov %eax,%fs + 103790: 8e e8 mov %eax,%gs + 103792: 89 e0 mov %esp,%eax + 103794: 50 push %eax + +00103795 : + 103795: b8 04 3e 10 00 mov $0x103e04,%eax + 10379a: ff d0 call *%eax + 10379c: e9 47 df ff ff jmp 1016e8 + +001037a1 : + 1037a1: 6a 00 push $0x0 + 1037a3: 6a d9 push $0xffffffd9 + 1037a5: 0f a8 push %gs + 1037a7: 0f a0 push %fs + 1037a9: 06 push %es + 1037aa: 1e push %ds + 1037ab: 60 pusha + 1037ac: 66 b8 10 00 mov $0x10,%ax + 1037b0: 8e d8 mov %eax,%ds + 1037b2: 8e c0 mov %eax,%es + 1037b4: 8e e0 mov %eax,%fs + 1037b6: 8e e8 mov %eax,%gs + 1037b8: 89 e0 mov %esp,%eax + 1037ba: 50 push %eax + +001037bb : + 1037bb: b8 04 3e 10 00 mov $0x103e04,%eax + 1037c0: ff d0 call *%eax + 1037c2: e9 21 df ff ff jmp 1016e8 + +001037c7 : + 1037c7: 6a 00 push $0x0 + 1037c9: 6a da push $0xffffffda + 1037cb: 0f a8 push %gs + 1037cd: 0f a0 push %fs + 1037cf: 06 push %es + 1037d0: 1e push %ds + 1037d1: 60 pusha + 1037d2: 66 b8 10 00 mov $0x10,%ax + 1037d6: 8e d8 mov %eax,%ds + 1037d8: 8e c0 mov %eax,%es + 1037da: 8e e0 mov %eax,%fs + 1037dc: 8e e8 mov %eax,%gs + 1037de: 89 e0 mov %esp,%eax + 1037e0: 50 push %eax + +001037e1 : + 1037e1: b8 04 3e 10 00 mov $0x103e04,%eax + 1037e6: ff d0 call *%eax + 1037e8: e9 fb de ff ff jmp 1016e8 + +001037ed : + 1037ed: 6a 00 push $0x0 + 1037ef: 6a db push $0xffffffdb + 1037f1: 0f a8 push %gs + 1037f3: 0f a0 push %fs + 1037f5: 06 push %es + 1037f6: 1e push %ds + 1037f7: 60 pusha + 1037f8: 66 b8 10 00 mov $0x10,%ax + 1037fc: 8e d8 mov %eax,%ds + 1037fe: 8e c0 mov %eax,%es + 103800: 8e e0 mov %eax,%fs + 103802: 8e e8 mov %eax,%gs + 103804: 89 e0 mov %esp,%eax + 103806: 50 push %eax + +00103807 : + 103807: b8 04 3e 10 00 mov $0x103e04,%eax + 10380c: ff d0 call *%eax + 10380e: e9 d5 de ff ff jmp 1016e8 + +00103813 : + 103813: 6a 00 push $0x0 + 103815: 6a dc push $0xffffffdc + 103817: 0f a8 push %gs + 103819: 0f a0 push %fs + 10381b: 06 push %es + 10381c: 1e push %ds + 10381d: 60 pusha + 10381e: 66 b8 10 00 mov $0x10,%ax + 103822: 8e d8 mov %eax,%ds + 103824: 8e c0 mov %eax,%es + 103826: 8e e0 mov %eax,%fs + 103828: 8e e8 mov %eax,%gs + 10382a: 89 e0 mov %esp,%eax + 10382c: 50 push %eax + +0010382d : + 10382d: b8 04 3e 10 00 mov $0x103e04,%eax + 103832: ff d0 call *%eax + 103834: e9 af de ff ff jmp 1016e8 + +00103839 : + 103839: 6a 00 push $0x0 + 10383b: 6a dd push $0xffffffdd + 10383d: 0f a8 push %gs + 10383f: 0f a0 push %fs + 103841: 06 push %es + 103842: 1e push %ds + 103843: 60 pusha + 103844: 66 b8 10 00 mov $0x10,%ax + 103848: 8e d8 mov %eax,%ds + 10384a: 8e c0 mov %eax,%es + 10384c: 8e e0 mov %eax,%fs + 10384e: 8e e8 mov %eax,%gs + 103850: 89 e0 mov %esp,%eax + 103852: 50 push %eax + +00103853 : + 103853: b8 04 3e 10 00 mov $0x103e04,%eax + 103858: ff d0 call *%eax + 10385a: e9 89 de ff ff jmp 1016e8 + +0010385f : + 10385f: 6a 00 push $0x0 + 103861: 6a de push $0xffffffde + 103863: 0f a8 push %gs + 103865: 0f a0 push %fs + 103867: 06 push %es + 103868: 1e push %ds + 103869: 60 pusha + 10386a: 66 b8 10 00 mov $0x10,%ax + 10386e: 8e d8 mov %eax,%ds + 103870: 8e c0 mov %eax,%es + 103872: 8e e0 mov %eax,%fs + 103874: 8e e8 mov %eax,%gs + 103876: 89 e0 mov %esp,%eax + 103878: 50 push %eax + +00103879 : + 103879: b8 04 3e 10 00 mov $0x103e04,%eax + 10387e: ff d0 call *%eax + 103880: e9 63 de ff ff jmp 1016e8 + +00103885 : + 103885: 6a 00 push $0x0 + 103887: 6a df push $0xffffffdf + 103889: 0f a8 push %gs + 10388b: 0f a0 push %fs + 10388d: 06 push %es + 10388e: 1e push %ds + 10388f: 60 pusha + 103890: 66 b8 10 00 mov $0x10,%ax + 103894: 8e d8 mov %eax,%ds + 103896: 8e c0 mov %eax,%es + 103898: 8e e0 mov %eax,%fs + 10389a: 8e e8 mov %eax,%gs + 10389c: 89 e0 mov %esp,%eax + 10389e: 50 push %eax + +0010389f : + 10389f: b8 04 3e 10 00 mov $0x103e04,%eax + 1038a4: ff d0 call *%eax + 1038a6: e9 3d de ff ff jmp 1016e8 + +001038ab : + 1038ab: 6a 00 push $0x0 + 1038ad: 6a e0 push $0xffffffe0 + 1038af: 0f a8 push %gs + 1038b1: 0f a0 push %fs + 1038b3: 06 push %es + 1038b4: 1e push %ds + 1038b5: 60 pusha + 1038b6: 66 b8 10 00 mov $0x10,%ax + 1038ba: 8e d8 mov %eax,%ds + 1038bc: 8e c0 mov %eax,%es + 1038be: 8e e0 mov %eax,%fs + 1038c0: 8e e8 mov %eax,%gs + 1038c2: 89 e0 mov %esp,%eax + 1038c4: 50 push %eax + +001038c5 : + 1038c5: b8 04 3e 10 00 mov $0x103e04,%eax + 1038ca: ff d0 call *%eax + 1038cc: e9 17 de ff ff jmp 1016e8 + +001038d1 : + 1038d1: 6a 00 push $0x0 + 1038d3: 6a e1 push $0xffffffe1 + 1038d5: 0f a8 push %gs + 1038d7: 0f a0 push %fs + 1038d9: 06 push %es + 1038da: 1e push %ds + 1038db: 60 pusha + 1038dc: 66 b8 10 00 mov $0x10,%ax + 1038e0: 8e d8 mov %eax,%ds + 1038e2: 8e c0 mov %eax,%es + 1038e4: 8e e0 mov %eax,%fs + 1038e6: 8e e8 mov %eax,%gs + 1038e8: 89 e0 mov %esp,%eax + 1038ea: 50 push %eax + +001038eb : + 1038eb: b8 04 3e 10 00 mov $0x103e04,%eax + 1038f0: ff d0 call *%eax + 1038f2: e9 f1 dd ff ff jmp 1016e8 + +001038f7 : + 1038f7: 6a 00 push $0x0 + 1038f9: 6a e2 push $0xffffffe2 + 1038fb: 0f a8 push %gs + 1038fd: 0f a0 push %fs + 1038ff: 06 push %es + 103900: 1e push %ds + 103901: 60 pusha + 103902: 66 b8 10 00 mov $0x10,%ax + 103906: 8e d8 mov %eax,%ds + 103908: 8e c0 mov %eax,%es + 10390a: 8e e0 mov %eax,%fs + 10390c: 8e e8 mov %eax,%gs + 10390e: 89 e0 mov %esp,%eax + 103910: 50 push %eax + +00103911 : + 103911: b8 04 3e 10 00 mov $0x103e04,%eax + 103916: ff d0 call *%eax + 103918: e9 cb dd ff ff jmp 1016e8 + +0010391d : + 10391d: 6a 00 push $0x0 + 10391f: 6a e3 push $0xffffffe3 + 103921: 0f a8 push %gs + 103923: 0f a0 push %fs + 103925: 06 push %es + 103926: 1e push %ds + 103927: 60 pusha + 103928: 66 b8 10 00 mov $0x10,%ax + 10392c: 8e d8 mov %eax,%ds + 10392e: 8e c0 mov %eax,%es + 103930: 8e e0 mov %eax,%fs + 103932: 8e e8 mov %eax,%gs + 103934: 89 e0 mov %esp,%eax + 103936: 50 push %eax + +00103937 : + 103937: b8 04 3e 10 00 mov $0x103e04,%eax + 10393c: ff d0 call *%eax + 10393e: e9 a5 dd ff ff jmp 1016e8 + +00103943 : + 103943: 6a 00 push $0x0 + 103945: 6a e4 push $0xffffffe4 + 103947: 0f a8 push %gs + 103949: 0f a0 push %fs + 10394b: 06 push %es + 10394c: 1e push %ds + 10394d: 60 pusha + 10394e: 66 b8 10 00 mov $0x10,%ax + 103952: 8e d8 mov %eax,%ds + 103954: 8e c0 mov %eax,%es + 103956: 8e e0 mov %eax,%fs + 103958: 8e e8 mov %eax,%gs + 10395a: 89 e0 mov %esp,%eax + 10395c: 50 push %eax + +0010395d : + 10395d: b8 04 3e 10 00 mov $0x103e04,%eax + 103962: ff d0 call *%eax + 103964: e9 7f dd ff ff jmp 1016e8 + +00103969 : + 103969: 6a 00 push $0x0 + 10396b: 6a e5 push $0xffffffe5 + 10396d: 0f a8 push %gs + 10396f: 0f a0 push %fs + 103971: 06 push %es + 103972: 1e push %ds + 103973: 60 pusha + 103974: 66 b8 10 00 mov $0x10,%ax + 103978: 8e d8 mov %eax,%ds + 10397a: 8e c0 mov %eax,%es + 10397c: 8e e0 mov %eax,%fs + 10397e: 8e e8 mov %eax,%gs + 103980: 89 e0 mov %esp,%eax + 103982: 50 push %eax + +00103983 : + 103983: b8 04 3e 10 00 mov $0x103e04,%eax + 103988: ff d0 call *%eax + 10398a: e9 59 dd ff ff jmp 1016e8 + +0010398f : + 10398f: 6a 00 push $0x0 + 103991: 6a e6 push $0xffffffe6 + 103993: 0f a8 push %gs + 103995: 0f a0 push %fs + 103997: 06 push %es + 103998: 1e push %ds + 103999: 60 pusha + 10399a: 66 b8 10 00 mov $0x10,%ax + 10399e: 8e d8 mov %eax,%ds + 1039a0: 8e c0 mov %eax,%es + 1039a2: 8e e0 mov %eax,%fs + 1039a4: 8e e8 mov %eax,%gs + 1039a6: 89 e0 mov %esp,%eax + 1039a8: 50 push %eax + +001039a9 : + 1039a9: b8 04 3e 10 00 mov $0x103e04,%eax + 1039ae: ff d0 call *%eax + 1039b0: e9 33 dd ff ff jmp 1016e8 + +001039b5 : + 1039b5: 6a 00 push $0x0 + 1039b7: 6a e7 push $0xffffffe7 + 1039b9: 0f a8 push %gs + 1039bb: 0f a0 push %fs + 1039bd: 06 push %es + 1039be: 1e push %ds + 1039bf: 60 pusha + 1039c0: 66 b8 10 00 mov $0x10,%ax + 1039c4: 8e d8 mov %eax,%ds + 1039c6: 8e c0 mov %eax,%es + 1039c8: 8e e0 mov %eax,%fs + 1039ca: 8e e8 mov %eax,%gs + 1039cc: 89 e0 mov %esp,%eax + 1039ce: 50 push %eax + +001039cf : + 1039cf: b8 04 3e 10 00 mov $0x103e04,%eax + 1039d4: ff d0 call *%eax + 1039d6: e9 0d dd ff ff jmp 1016e8 + +001039db : + 1039db: 6a 00 push $0x0 + 1039dd: 6a e8 push $0xffffffe8 + 1039df: 0f a8 push %gs + 1039e1: 0f a0 push %fs + 1039e3: 06 push %es + 1039e4: 1e push %ds + 1039e5: 60 pusha + 1039e6: 66 b8 10 00 mov $0x10,%ax + 1039ea: 8e d8 mov %eax,%ds + 1039ec: 8e c0 mov %eax,%es + 1039ee: 8e e0 mov %eax,%fs + 1039f0: 8e e8 mov %eax,%gs + 1039f2: 89 e0 mov %esp,%eax + 1039f4: 50 push %eax + +001039f5 : + 1039f5: b8 04 3e 10 00 mov $0x103e04,%eax + 1039fa: ff d0 call *%eax + 1039fc: e9 e7 dc ff ff jmp 1016e8 + +00103a01 : + 103a01: 6a 00 push $0x0 + 103a03: 6a e9 push $0xffffffe9 + 103a05: 0f a8 push %gs + 103a07: 0f a0 push %fs + 103a09: 06 push %es + 103a0a: 1e push %ds + 103a0b: 60 pusha + 103a0c: 66 b8 10 00 mov $0x10,%ax + 103a10: 8e d8 mov %eax,%ds + 103a12: 8e c0 mov %eax,%es + 103a14: 8e e0 mov %eax,%fs + 103a16: 8e e8 mov %eax,%gs + 103a18: 89 e0 mov %esp,%eax + 103a1a: 50 push %eax + +00103a1b : + 103a1b: b8 04 3e 10 00 mov $0x103e04,%eax + 103a20: ff d0 call *%eax + 103a22: e9 c1 dc ff ff jmp 1016e8 + +00103a27 : + 103a27: 6a 00 push $0x0 + 103a29: 6a ea push $0xffffffea + 103a2b: 0f a8 push %gs + 103a2d: 0f a0 push %fs + 103a2f: 06 push %es + 103a30: 1e push %ds + 103a31: 60 pusha + 103a32: 66 b8 10 00 mov $0x10,%ax + 103a36: 8e d8 mov %eax,%ds + 103a38: 8e c0 mov %eax,%es + 103a3a: 8e e0 mov %eax,%fs + 103a3c: 8e e8 mov %eax,%gs + 103a3e: 89 e0 mov %esp,%eax + 103a40: 50 push %eax + +00103a41 : + 103a41: b8 04 3e 10 00 mov $0x103e04,%eax + 103a46: ff d0 call *%eax + 103a48: e9 9b dc ff ff jmp 1016e8 + +00103a4d : + 103a4d: 6a 00 push $0x0 + 103a4f: 6a eb push $0xffffffeb + 103a51: 0f a8 push %gs + 103a53: 0f a0 push %fs + 103a55: 06 push %es + 103a56: 1e push %ds + 103a57: 60 pusha + 103a58: 66 b8 10 00 mov $0x10,%ax + 103a5c: 8e d8 mov %eax,%ds + 103a5e: 8e c0 mov %eax,%es + 103a60: 8e e0 mov %eax,%fs + 103a62: 8e e8 mov %eax,%gs + 103a64: 89 e0 mov %esp,%eax + 103a66: 50 push %eax + +00103a67 : + 103a67: b8 04 3e 10 00 mov $0x103e04,%eax + 103a6c: ff d0 call *%eax + 103a6e: e9 75 dc ff ff jmp 1016e8 + +00103a73 : + 103a73: 6a 00 push $0x0 + 103a75: 6a ec push $0xffffffec + 103a77: 0f a8 push %gs + 103a79: 0f a0 push %fs + 103a7b: 06 push %es + 103a7c: 1e push %ds + 103a7d: 60 pusha + 103a7e: 66 b8 10 00 mov $0x10,%ax + 103a82: 8e d8 mov %eax,%ds + 103a84: 8e c0 mov %eax,%es + 103a86: 8e e0 mov %eax,%fs + 103a88: 8e e8 mov %eax,%gs + 103a8a: 89 e0 mov %esp,%eax + 103a8c: 50 push %eax + +00103a8d : + 103a8d: b8 04 3e 10 00 mov $0x103e04,%eax + 103a92: ff d0 call *%eax + 103a94: e9 4f dc ff ff jmp 1016e8 + +00103a99 : + 103a99: 6a 00 push $0x0 + 103a9b: 6a ed push $0xffffffed + 103a9d: 0f a8 push %gs + 103a9f: 0f a0 push %fs + 103aa1: 06 push %es + 103aa2: 1e push %ds + 103aa3: 60 pusha + 103aa4: 66 b8 10 00 mov $0x10,%ax + 103aa8: 8e d8 mov %eax,%ds + 103aaa: 8e c0 mov %eax,%es + 103aac: 8e e0 mov %eax,%fs + 103aae: 8e e8 mov %eax,%gs + 103ab0: 89 e0 mov %esp,%eax + 103ab2: 50 push %eax + +00103ab3 : + 103ab3: b8 04 3e 10 00 mov $0x103e04,%eax + 103ab8: ff d0 call *%eax + 103aba: e9 29 dc ff ff jmp 1016e8 + +00103abf : + 103abf: 6a 00 push $0x0 + 103ac1: 6a ee push $0xffffffee + 103ac3: 0f a8 push %gs + 103ac5: 0f a0 push %fs + 103ac7: 06 push %es + 103ac8: 1e push %ds + 103ac9: 60 pusha + 103aca: 66 b8 10 00 mov $0x10,%ax + 103ace: 8e d8 mov %eax,%ds + 103ad0: 8e c0 mov %eax,%es + 103ad2: 8e e0 mov %eax,%fs + 103ad4: 8e e8 mov %eax,%gs + 103ad6: 89 e0 mov %esp,%eax + 103ad8: 50 push %eax + +00103ad9 : + 103ad9: b8 04 3e 10 00 mov $0x103e04,%eax + 103ade: ff d0 call *%eax + 103ae0: e9 03 dc ff ff jmp 1016e8 + +00103ae5 : + 103ae5: 6a 00 push $0x0 + 103ae7: 6a ef push $0xffffffef + 103ae9: 0f a8 push %gs + 103aeb: 0f a0 push %fs + 103aed: 06 push %es + 103aee: 1e push %ds + 103aef: 60 pusha + 103af0: 66 b8 10 00 mov $0x10,%ax + 103af4: 8e d8 mov %eax,%ds + 103af6: 8e c0 mov %eax,%es + 103af8: 8e e0 mov %eax,%fs + 103afa: 8e e8 mov %eax,%gs + 103afc: 89 e0 mov %esp,%eax + 103afe: 50 push %eax + +00103aff : + 103aff: b8 04 3e 10 00 mov $0x103e04,%eax + 103b04: ff d0 call *%eax + 103b06: e9 dd db ff ff jmp 1016e8 + +00103b0b : + 103b0b: 6a 00 push $0x0 + 103b0d: 6a f0 push $0xfffffff0 + 103b0f: 0f a8 push %gs + 103b11: 0f a0 push %fs + 103b13: 06 push %es + 103b14: 1e push %ds + 103b15: 60 pusha + 103b16: 66 b8 10 00 mov $0x10,%ax + 103b1a: 8e d8 mov %eax,%ds + 103b1c: 8e c0 mov %eax,%es + 103b1e: 8e e0 mov %eax,%fs + 103b20: 8e e8 mov %eax,%gs + 103b22: 89 e0 mov %esp,%eax + 103b24: 50 push %eax + +00103b25 : + 103b25: b8 04 3e 10 00 mov $0x103e04,%eax + 103b2a: ff d0 call *%eax + 103b2c: e9 b7 db ff ff jmp 1016e8 + +00103b31 : + 103b31: 6a 00 push $0x0 + 103b33: 6a f1 push $0xfffffff1 + 103b35: 0f a8 push %gs + 103b37: 0f a0 push %fs + 103b39: 06 push %es + 103b3a: 1e push %ds + 103b3b: 60 pusha + 103b3c: 66 b8 10 00 mov $0x10,%ax + 103b40: 8e d8 mov %eax,%ds + 103b42: 8e c0 mov %eax,%es + 103b44: 8e e0 mov %eax,%fs + 103b46: 8e e8 mov %eax,%gs + 103b48: 89 e0 mov %esp,%eax + 103b4a: 50 push %eax + +00103b4b : + 103b4b: b8 04 3e 10 00 mov $0x103e04,%eax + 103b50: ff d0 call *%eax + 103b52: e9 91 db ff ff jmp 1016e8 + +00103b57 : + 103b57: 6a 00 push $0x0 + 103b59: 6a f2 push $0xfffffff2 + 103b5b: 0f a8 push %gs + 103b5d: 0f a0 push %fs + 103b5f: 06 push %es + 103b60: 1e push %ds + 103b61: 60 pusha + 103b62: 66 b8 10 00 mov $0x10,%ax + 103b66: 8e d8 mov %eax,%ds + 103b68: 8e c0 mov %eax,%es + 103b6a: 8e e0 mov %eax,%fs + 103b6c: 8e e8 mov %eax,%gs + 103b6e: 89 e0 mov %esp,%eax + 103b70: 50 push %eax + +00103b71 : + 103b71: b8 04 3e 10 00 mov $0x103e04,%eax + 103b76: ff d0 call *%eax + 103b78: e9 6b db ff ff jmp 1016e8 + +00103b7d : + 103b7d: 6a 00 push $0x0 + 103b7f: 6a f3 push $0xfffffff3 + 103b81: 0f a8 push %gs + 103b83: 0f a0 push %fs + 103b85: 06 push %es + 103b86: 1e push %ds + 103b87: 60 pusha + 103b88: 66 b8 10 00 mov $0x10,%ax + 103b8c: 8e d8 mov %eax,%ds + 103b8e: 8e c0 mov %eax,%es + 103b90: 8e e0 mov %eax,%fs + 103b92: 8e e8 mov %eax,%gs + 103b94: 89 e0 mov %esp,%eax + 103b96: 50 push %eax + +00103b97 : + 103b97: b8 04 3e 10 00 mov $0x103e04,%eax + 103b9c: ff d0 call *%eax + 103b9e: e9 45 db ff ff jmp 1016e8 + +00103ba3 : + 103ba3: 6a 00 push $0x0 + 103ba5: 6a f4 push $0xfffffff4 + 103ba7: 0f a8 push %gs + 103ba9: 0f a0 push %fs + 103bab: 06 push %es + 103bac: 1e push %ds + 103bad: 60 pusha + 103bae: 66 b8 10 00 mov $0x10,%ax + 103bb2: 8e d8 mov %eax,%ds + 103bb4: 8e c0 mov %eax,%es + 103bb6: 8e e0 mov %eax,%fs + 103bb8: 8e e8 mov %eax,%gs + 103bba: 89 e0 mov %esp,%eax + 103bbc: 50 push %eax + +00103bbd : + 103bbd: b8 04 3e 10 00 mov $0x103e04,%eax + 103bc2: ff d0 call *%eax + 103bc4: e9 1f db ff ff jmp 1016e8 + +00103bc9 : + 103bc9: 6a 00 push $0x0 + 103bcb: 6a f5 push $0xfffffff5 + 103bcd: 0f a8 push %gs + 103bcf: 0f a0 push %fs + 103bd1: 06 push %es + 103bd2: 1e push %ds + 103bd3: 60 pusha + 103bd4: 66 b8 10 00 mov $0x10,%ax + 103bd8: 8e d8 mov %eax,%ds + 103bda: 8e c0 mov %eax,%es + 103bdc: 8e e0 mov %eax,%fs + 103bde: 8e e8 mov %eax,%gs + 103be0: 89 e0 mov %esp,%eax + 103be2: 50 push %eax + +00103be3 : + 103be3: b8 04 3e 10 00 mov $0x103e04,%eax + 103be8: ff d0 call *%eax + 103bea: e9 f9 da ff ff jmp 1016e8 + +00103bef : + 103bef: 6a 00 push $0x0 + 103bf1: 6a f6 push $0xfffffff6 + 103bf3: 0f a8 push %gs + 103bf5: 0f a0 push %fs + 103bf7: 06 push %es + 103bf8: 1e push %ds + 103bf9: 60 pusha + 103bfa: 66 b8 10 00 mov $0x10,%ax + 103bfe: 8e d8 mov %eax,%ds + 103c00: 8e c0 mov %eax,%es + 103c02: 8e e0 mov %eax,%fs + 103c04: 8e e8 mov %eax,%gs + 103c06: 89 e0 mov %esp,%eax + 103c08: 50 push %eax + +00103c09 : + 103c09: b8 04 3e 10 00 mov $0x103e04,%eax + 103c0e: ff d0 call *%eax + 103c10: e9 d3 da ff ff jmp 1016e8 + +00103c15 : + 103c15: 6a 00 push $0x0 + 103c17: 6a f7 push $0xfffffff7 + 103c19: 0f a8 push %gs + 103c1b: 0f a0 push %fs + 103c1d: 06 push %es + 103c1e: 1e push %ds + 103c1f: 60 pusha + 103c20: 66 b8 10 00 mov $0x10,%ax + 103c24: 8e d8 mov %eax,%ds + 103c26: 8e c0 mov %eax,%es + 103c28: 8e e0 mov %eax,%fs + 103c2a: 8e e8 mov %eax,%gs + 103c2c: 89 e0 mov %esp,%eax + 103c2e: 50 push %eax + +00103c2f : + 103c2f: b8 04 3e 10 00 mov $0x103e04,%eax + 103c34: ff d0 call *%eax + 103c36: e9 ad da ff ff jmp 1016e8 + +00103c3b : + 103c3b: 6a 00 push $0x0 + 103c3d: 6a f8 push $0xfffffff8 + 103c3f: 0f a8 push %gs + 103c41: 0f a0 push %fs + 103c43: 06 push %es + 103c44: 1e push %ds + 103c45: 60 pusha + 103c46: 66 b8 10 00 mov $0x10,%ax + 103c4a: 8e d8 mov %eax,%ds + 103c4c: 8e c0 mov %eax,%es + 103c4e: 8e e0 mov %eax,%fs + 103c50: 8e e8 mov %eax,%gs + 103c52: 89 e0 mov %esp,%eax + 103c54: 50 push %eax + +00103c55 : + 103c55: b8 04 3e 10 00 mov $0x103e04,%eax + 103c5a: ff d0 call *%eax + 103c5c: e9 87 da ff ff jmp 1016e8 + +00103c61 : + 103c61: 6a 00 push $0x0 + 103c63: 6a f9 push $0xfffffff9 + 103c65: 0f a8 push %gs + 103c67: 0f a0 push %fs + 103c69: 06 push %es + 103c6a: 1e push %ds + 103c6b: 60 pusha + 103c6c: 66 b8 10 00 mov $0x10,%ax + 103c70: 8e d8 mov %eax,%ds + 103c72: 8e c0 mov %eax,%es + 103c74: 8e e0 mov %eax,%fs + 103c76: 8e e8 mov %eax,%gs + 103c78: 89 e0 mov %esp,%eax + 103c7a: 50 push %eax + +00103c7b : + 103c7b: b8 04 3e 10 00 mov $0x103e04,%eax + 103c80: ff d0 call *%eax + 103c82: e9 61 da ff ff jmp 1016e8 + +00103c87 : + 103c87: 6a 00 push $0x0 + 103c89: 6a fa push $0xfffffffa + 103c8b: 0f a8 push %gs + 103c8d: 0f a0 push %fs + 103c8f: 06 push %es + 103c90: 1e push %ds + 103c91: 60 pusha + 103c92: 66 b8 10 00 mov $0x10,%ax + 103c96: 8e d8 mov %eax,%ds + 103c98: 8e c0 mov %eax,%es + 103c9a: 8e e0 mov %eax,%fs + 103c9c: 8e e8 mov %eax,%gs + 103c9e: 89 e0 mov %esp,%eax + 103ca0: 50 push %eax + +00103ca1 : + 103ca1: b8 04 3e 10 00 mov $0x103e04,%eax + 103ca6: ff d0 call *%eax + 103ca8: e9 3b da ff ff jmp 1016e8 + +00103cad : + 103cad: 6a 00 push $0x0 + 103caf: 6a fb push $0xfffffffb + 103cb1: 0f a8 push %gs + 103cb3: 0f a0 push %fs + 103cb5: 06 push %es + 103cb6: 1e push %ds + 103cb7: 60 pusha + 103cb8: 66 b8 10 00 mov $0x10,%ax + 103cbc: 8e d8 mov %eax,%ds + 103cbe: 8e c0 mov %eax,%es + 103cc0: 8e e0 mov %eax,%fs + 103cc2: 8e e8 mov %eax,%gs + 103cc4: 89 e0 mov %esp,%eax + 103cc6: 50 push %eax + +00103cc7 : + 103cc7: b8 04 3e 10 00 mov $0x103e04,%eax + 103ccc: ff d0 call *%eax + 103cce: e9 15 da ff ff jmp 1016e8 + +00103cd3 : + 103cd3: 6a 00 push $0x0 + 103cd5: 6a fc push $0xfffffffc + 103cd7: 0f a8 push %gs + 103cd9: 0f a0 push %fs + 103cdb: 06 push %es + 103cdc: 1e push %ds + 103cdd: 60 pusha + 103cde: 66 b8 10 00 mov $0x10,%ax + 103ce2: 8e d8 mov %eax,%ds + 103ce4: 8e c0 mov %eax,%es + 103ce6: 8e e0 mov %eax,%fs + 103ce8: 8e e8 mov %eax,%gs + 103cea: 89 e0 mov %esp,%eax + 103cec: 50 push %eax + +00103ced : + 103ced: b8 04 3e 10 00 mov $0x103e04,%eax + 103cf2: ff d0 call *%eax + 103cf4: e9 ef d9 ff ff jmp 1016e8 + +00103cf9 : + 103cf9: 6a 00 push $0x0 + 103cfb: 6a fd push $0xfffffffd + 103cfd: 0f a8 push %gs + 103cff: 0f a0 push %fs + 103d01: 06 push %es + 103d02: 1e push %ds + 103d03: 60 pusha + 103d04: 66 b8 10 00 mov $0x10,%ax + 103d08: 8e d8 mov %eax,%ds + 103d0a: 8e c0 mov %eax,%es + 103d0c: 8e e0 mov %eax,%fs + 103d0e: 8e e8 mov %eax,%gs + 103d10: 89 e0 mov %esp,%eax + 103d12: 50 push %eax + +00103d13 : + 103d13: b8 04 3e 10 00 mov $0x103e04,%eax + 103d18: ff d0 call *%eax + 103d1a: e9 c9 d9 ff ff jmp 1016e8 + +00103d1f : + 103d1f: 6a 00 push $0x0 + 103d21: 6a fe push $0xfffffffe + 103d23: 0f a8 push %gs + 103d25: 0f a0 push %fs + 103d27: 06 push %es + 103d28: 1e push %ds + 103d29: 60 pusha + 103d2a: 66 b8 10 00 mov $0x10,%ax + 103d2e: 8e d8 mov %eax,%ds + 103d30: 8e c0 mov %eax,%es + 103d32: 8e e0 mov %eax,%fs + 103d34: 8e e8 mov %eax,%gs + 103d36: 89 e0 mov %esp,%eax + 103d38: 50 push %eax + +00103d39 : + 103d39: b8 04 3e 10 00 mov $0x103e04,%eax + 103d3e: ff d0 call *%eax + 103d40: e9 a3 d9 ff ff jmp 1016e8 + +00103d45 : + 103d45: 6a 00 push $0x0 + 103d47: 6a ff push $0xffffffff + 103d49: 0f a8 push %gs + 103d4b: 0f a0 push %fs + 103d4d: 06 push %es + 103d4e: 1e push %ds + 103d4f: 60 pusha + 103d50: 66 b8 10 00 mov $0x10,%ax + 103d54: 8e d8 mov %eax,%ds + 103d56: 8e c0 mov %eax,%es + 103d58: 8e e0 mov %eax,%fs + 103d5a: 8e e8 mov %eax,%gs + 103d5c: 89 e0 mov %esp,%eax + 103d5e: 50 push %eax + +00103d5f : + 103d5f: b8 04 3e 10 00 mov $0x103e04,%eax + 103d64: ff d0 call *%eax + 103d66: e9 7d d9 ff ff jmp 1016e8 + ... + +00103d6c : +/** + * printf/kprintf helper + */ +static int kprintf_help(unsigned c, void **ptr) +{ + 103d6c: 55 push %ebp + 103d6d: 89 e5 mov %esp,%ebp + 103d6f: 83 ec 14 sub $0x14,%esp + /** + * Leave this for now + */ + ptr = ptr; + + putch(c); + 103d72: ff 75 08 pushl 0x8(%ebp) + 103d75: e8 86 0d 00 00 call 104b00 + return 0; +} + 103d7a: 31 c0 xor %eax,%eax + 103d7c: c9 leave + 103d7d: c3 ret + 103d7e: 89 f6 mov %esi,%esi + +00103d80 : + +/** + * Format output and print it to stdout (vtty0) + * Just like on any other operating system + */ +/*void printf(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + (void)do_printf(fmt, args, kprintf_help, NULL); + va_end(args); +}*/ + +void kprintf(const char *fmt, ...) +{ + 103d80: 55 push %ebp + 103d81: 89 e5 mov %esp,%ebp + 103d83: 83 ec 08 sub $0x8,%esp + va_list args; + + va_start(args, fmt); + (void)do_printf(fmt, args, kprintf_help, NULL); + 103d86: 6a 00 push $0x0 + 103d88: 68 6c 3d 10 00 push $0x103d6c + 103d8d: 8d 45 0c lea 0xc(%ebp),%eax + 103d90: 50 push %eax + 103d91: ff 75 08 pushl 0x8(%ebp) + 103d94: e8 37 0f 00 00 call 104cd0 + va_end(args); +} + 103d99: c9 leave + 103d9a: c3 ret + 103d9b: 90 nop + +00103d9c : + +/** + * Format output and print it to stdout (vtty0) + * Just like on any other operating system + */ +void printk(const char *fmt, ...) +{ + 103d9c: 55 push %ebp + 103d9d: 89 e5 mov %esp,%ebp + 103d9f: 83 ec 08 sub $0x8,%esp + va_list args; + + /** + * TODO + * + * Select vtty0 + */ + va_start(args, fmt); + (void)do_printf(fmt, args, kprintf_help, NULL); + 103da2: 6a 00 push $0x0 + 103da4: 68 6c 3d 10 00 push $0x103d6c + 103da9: 8d 45 0c lea 0xc(%ebp),%eax + 103dac: 50 push %eax + 103dad: ff 75 08 pushl 0x8(%ebp) + 103db0: e8 1b 0f 00 00 call 104cd0 + va_end(args); +} + 103db5: c9 leave + 103db6: c3 ret + 103db7: 90 nop + +00103db8 : + +/** + * Oh yeah, the fun function ;) + */ +void panic(const char *fmt, ...) +{ + 103db8: 55 push %ebp + 103db9: 89 e5 mov %esp,%ebp + 103dbb: 53 push %ebx + 103dbc: 50 push %eax + va_list args; + + disable(); /* interrupts off */ + 103dbd: e8 06 0f 00 00 call 104cc8 + va_start(args, fmt); + _vc[0].attrib = 15; + printf("\n\npanic: "); + 103dc2: 83 ec 0c sub $0xc,%esp + 103dc5: 68 cd 58 10 00 push $0x1058cd + 103dca: c7 05 f8 a2 19 00 0f movl $0xf,0x19a2f8 + 103dd1: 00 00 00 + 103dd4: e8 fb 12 00 00 call 1050d4 + (void)do_printf(fmt, args, kprintf_help, NULL); + 103dd9: 6a 00 push $0x0 + 103ddb: 68 6c 3d 10 00 push $0x103d6c + 103de0: 8d 5d 0c lea 0xc(%ebp),%ebx + 103de3: 53 push %ebx + 103de4: ff 75 08 pushl 0x8(%ebp) + 103de7: e8 e4 0e 00 00 call 104cd0 + + printf("\n\nSystem halted."); + 103dec: 83 c4 14 add $0x14,%esp + 103def: 68 d7 58 10 00 push $0x1058d7 + 103df4: e8 db 12 00 00 call 1050d4 + __asm__ __volatile__ ("hlt"); + 103df9: f4 hlt + + while(1) + 103dfa: 83 c4 10 add $0x10,%esp + 103dfd: 8d 76 00 lea 0x0(%esi),%esi + 103e00: eb fe jmp 103e00 + 103e02: 89 f6 mov %esi,%esi + +00103e04 : + /* freeze */; +} + +/** + * Called when a kernel fault is detected. This does not + * (normally) get called when something goes awry in + * user-space, therefore it is designed for kernel-space + */ +void fault(regs_t *regs) +{ + 103e04: 55 push %ebp + 103e05: 89 e5 mov %esp,%ebp + 103e07: 53 push %ebx + 103e08: 52 push %edx + 103e09: 8b 5d 08 mov 0x8(%ebp),%ebx + struct exception + { + char *message; + int signal; + int processor; + }; + + static const struct exception ex[] = + { + {"Divide error", SIGFPE, 86}, + {"Debug exception", SIGTRAP, 86}, + {"Nonmaskable interrupt (NMI)", SIGBUS, 86}, + {"Breakpoint (INT3)", SIGEMT, 86}, + {"Overflow (INTO)", SIGFPE, 186}, + {"Bounds check", SIGFPE, 186}, + {"Invalid opcode", SIGILL, 186}, + {"Coprocessor not available", SIGFPE, 186}, + {"Double fault", SIGBUS, 286}, + {"Coprocessor segment overrun", SIGSEGV, 286}, + {"Invalid TSS", SIGSEGV, 286}, + {"Segment not present", SIGSEGV, 286}, + {"Stack exception", SIGSEGV, 286}, + {"General Protection Fault", SIGSEGV, 286}, + {"Page fault", SIGSEGV, 386}, + {NULL, SIGILL, 0}, + {"Coprocessor error", SIGFPE, 386}, + {"Alignment check",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"??",0,0}, + {"IRQ0",0,0}, + {"IRQ1",0,0}, + {"IRQ2",0,0}, + {"IRQ3",0,0}, + {"IRQ4",0,0}, + {"IRQ5",0,0}, + {"IRQ6",0,0}, + {"IRQ7",0,0}, + {"IRQ8",0,0}, + {"IRQ9",0,0}, + {"IRQ10",0,0}, + {"IRQ11",0,0}, + {"IRQ12",0,0}, + {"IRQ13",0,0}, + {"IRQ14",0,0}, + {"IRQ15",0,0}, + {"syscall",0,0} + }; + + + switch(regs->which_int) + 103e0c: 83 7b 30 20 cmpl $0x20,0x30(%ebx) + 103e10: 74 6e je 103e80 + { + /** + * this handler installed at compile-time + * Keyboard handler is installed at run-time (see below) + */ + case 0x20: /* timer IRQ 0 */ + //blink(); + /** + * reset hardware interrupt at 8259 chip + */ + outportb(0x20, 0x20); + break; + default: + _vc[0].attrib = 15; + printf("\n\npanic: Exception 0x%08X", regs->which_int); + 103e12: 83 ec 08 sub $0x8,%esp + 103e15: c7 05 f8 a2 19 00 0f movl $0xf,0x19a2f8 + 103e1c: 00 00 00 + 103e1f: ff 73 30 pushl 0x30(%ebx) + 103e22: 68 79 5a 10 00 push $0x105a79 + 103e27: e8 a8 12 00 00 call 1050d4 + if(regs->which_int <= sizeof(ex) / sizeof(ex[0].message)) + 103e2c: 8b 43 30 mov 0x30(%ebx),%eax + 103e2f: 83 c4 10 add $0x10,%esp + 103e32: 3d 93 00 00 00 cmp $0x93,%eax + 103e37: 76 2b jbe 103e64 + printf(" (%s)", ex[regs->which_int].message); + printf("\n"); + 103e39: 83 ec 0c sub $0xc,%esp + 103e3c: 68 f8 5a 10 00 push $0x105af8 + 103e41: e8 8e 12 00 00 call 1050d4 + dump_regs(regs); + 103e46: 89 1c 24 mov %ebx,(%esp,1) + 103e49: e8 7e c3 ff ff call 1001cc + printf("\n\nSystem halted."); + 103e4e: c7 04 24 d7 58 10 00 movl $0x1058d7,(%esp,1) + 103e55: e8 7a 12 00 00 call 1050d4 + __asm__ __volatile__ ("hlt"); + 103e5a: f4 hlt + break; + 103e5b: 83 c4 10 add $0x10,%esp + } +} + 103e5e: 8b 5d fc mov 0xfffffffc(%ebp),%ebx + 103e61: c9 leave + 103e62: c3 ret + 103e63: 90 nop + 103e64: 83 ec 08 sub $0x8,%esp + 103e67: 8d 04 40 lea (%eax,%eax,2),%eax + 103e6a: ff 34 85 00 5b 10 00 pushl 0x105b00(,%eax,4) + 103e71: 68 93 5a 10 00 push $0x105a93 + 103e76: e8 59 12 00 00 call 1050d4 + 103e7b: 83 c4 10 add $0x10,%esp + 103e7e: eb b9 jmp 103e39 + 103e80: 83 ec 08 sub $0x8,%esp + 103e83: 6a 20 push $0x20 + 103e85: 6a 20 push $0x20 + 103e87: e8 28 12 00 00 call 1050b4 + 103e8c: eb cd jmp 103e5b + 103e8e: 89 f6 mov %esi,%esi + +00103e90 : + +/** + * ?? + */ +static void init_8259s(void) +{ + 103e90: 55 push %ebp + 103e91: 89 e5 mov %esp,%ebp + 103e93: 83 ec 10 sub $0x10,%esp + static const unsigned irq0_int = 0x20, irq8_int = 0x28; + + /** + * Initialization Control Word #1 (ICW1) + */ + outportb(0x20, 0x11); + 103e96: 6a 11 push $0x11 + 103e98: 6a 20 push $0x20 + 103e9a: e8 15 12 00 00 call 1050b4 + outportb(0xA0, 0x11); + 103e9f: 59 pop %ecx + 103ea0: 58 pop %eax + 103ea1: 6a 11 push $0x11 + 103ea3: 68 a0 00 00 00 push $0xa0 + 103ea8: e8 07 12 00 00 call 1050b4 + + /** + * ICW2: + * route IRQs 0-7 to INTs 20h-27h + */ + outportb(0x21, irq0_int); + 103ead: 58 pop %eax + 103eae: 5a pop %edx + 103eaf: 6a 20 push $0x20 + 103eb1: 6a 21 push $0x21 + 103eb3: e8 fc 11 00 00 call 1050b4 + + /** + * route IRQs 8-15 to INTs 28h-2Fh + */ + outportb(0xA1, irq8_int); + 103eb8: 59 pop %ecx + 103eb9: 58 pop %eax + 103eba: 6a 28 push $0x28 + 103ebc: 68 a1 00 00 00 push $0xa1 + 103ec1: e8 ee 11 00 00 call 1050b4 + + /** + * ICW3 + */ + outportb(0x21, 0x04); + 103ec6: 58 pop %eax + 103ec7: 5a pop %edx + 103ec8: 6a 04 push $0x4 + 103eca: 6a 21 push $0x21 + 103ecc: e8 e3 11 00 00 call 1050b4 + outportb(0xA1, 0x02); + 103ed1: 59 pop %ecx + 103ed2: 58 pop %eax + 103ed3: 6a 02 push $0x2 + 103ed5: 68 a1 00 00 00 push $0xa1 + 103eda: e8 d5 11 00 00 call 1050b4 + + /** + * ICW4 + */ + outportb(0x21, 0x01); + 103edf: 58 pop %eax + 103ee0: 5a pop %edx + 103ee1: 6a 01 push $0x1 + 103ee3: 6a 21 push $0x21 + 103ee5: e8 ca 11 00 00 call 1050b4 + outportb(0xA1, 0x01); + 103eea: 59 pop %ecx + 103eeb: 58 pop %eax + 103eec: 6a 01 push $0x1 + 103eee: 68 a1 00 00 00 push $0xa1 + 103ef3: e8 bc 11 00 00 call 1050b4 + + /** + * enable IRQ0 (timer) and IRQ1 (keyboard) + */ + outportb(0x21, ~0x03); + 103ef8: 58 pop %eax + 103ef9: 5a pop %edx + 103efa: 6a fc push $0xfffffffc + 103efc: 6a 21 push $0x21 + 103efe: e8 b1 11 00 00 call 1050b4 + outportb(0xA1, ~0x00); + 103f03: 59 pop %ecx + 103f04: 58 pop %eax + 103f05: 6a ff push $0xffffffff + 103f07: 68 a1 00 00 00 push $0xa1 + 103f0c: e8 a3 11 00 00 call 1050b4 +} + 103f11: c9 leave + 103f12: c3 ret + 103f13: 90 nop + +00103f14 : + +/** + * MinGW32 + */ +#ifdef __WIN32__ +#if __GNUC__<3 +#error Do not use MinGW GCC 2.x with NASM +#endif + int __main(void) { return 0; } + void _alloca(void) { } +#endif + +/** + * malloc, realloc, free, etc + */ +static char *g_heap_bot, *g_kbrk, *g_heap_top; +static void dump_heap(void) +{ + 103f14: 55 push %ebp + 103f15: 89 e5 mov %esp,%ebp + 103f17: 57 push %edi + 103f18: 56 push %esi + 103f19: 53 push %ebx + 103f1a: 83 ec 18 sub $0x18,%esp + unsigned blks_used = 0, blks_free = 0; + size_t bytes_used = 0, bytes_free = 0; + malloc_t *m; + int total; + + kprintf("===============================================\n"); + 103f1d: 68 60 5d 10 00 push $0x105d60 + 103f22: c7 45 f0 00 00 00 00 movl $0x0,0xfffffff0(%ebp) + 103f29: c7 45 ec 00 00 00 00 movl $0x0,0xffffffec(%ebp) + 103f30: e8 4b fe ff ff call 103d80 + for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next) + 103f35: 8b 1d e0 36 18 00 mov 0x1836e0,%ebx + 103f3b: 31 ff xor %edi,%edi + 103f3d: 31 f6 xor %esi,%esi + 103f3f: 83 c4 10 add $0x10,%esp + 103f42: 85 db test %ebx,%ebx + 103f44: 74 39 je 103f7f + 103f46: 89 f6 mov %esi,%esi + { + printk("block %5p: %6u bytes %s\n", m, + 103f48: f6 43 09 80 testb $0x80,0x9(%ebx) + 103f4c: 0f 84 be 00 00 00 je 104010 + 103f52: b8 99 5a 10 00 mov $0x105a99,%eax + 103f57: 50 push %eax + 103f58: ff 33 pushl (%ebx) + 103f5a: 53 push %ebx + 103f5b: 68 9e 5a 10 00 push $0x105a9e + 103f60: e8 37 fe ff ff call 103d9c + m->size, m->used ? "used" : "free"); + if(m->used) + 103f65: 83 c4 10 add $0x10,%esp + 103f68: f6 43 09 80 testb $0x80,0x9(%ebx) + 103f6c: 0f 84 92 00 00 00 je 104004 + { + blks_used++; + bytes_used += m->size; + 103f72: 8b 03 mov (%ebx),%eax + 103f74: 47 inc %edi + 103f75: 01 45 f0 add %eax,0xfffffff0(%ebp) + 103f78: 8b 5b 04 mov 0x4(%ebx),%ebx + 103f7b: 85 db test %ebx,%ebx + 103f7d: 75 c9 jne 103f48 + } + else + { + blks_free++; + bytes_free += m->size; + } + } + kprintf("blocks: %6u used, %6u free, %6u total\n", blks_used, + 103f7f: 8d 1c 3e lea (%esi,%edi,1),%ebx + 103f82: 53 push %ebx + 103f83: 56 push %esi + 103f84: 57 push %edi + 103f85: 68 a0 5d 10 00 push $0x105da0 + 103f8a: e8 f1 fd ff ff call 103d80 + blks_free, blks_used + blks_free); + kprintf(" bytes: %6u used, %6u free, %6u total\n", bytes_used, + 103f8f: 8b 75 f0 mov 0xfffffff0(%ebp),%esi + 103f92: 03 75 ec add 0xffffffec(%ebp),%esi + 103f95: 56 push %esi + 103f96: ff 75 ec pushl 0xffffffec(%ebp) + 103f99: ff 75 f0 pushl 0xfffffff0(%ebp) + 103f9c: 68 e0 5d 10 00 push $0x105de0 + 103fa1: e8 da fd ff ff call 103d80 + bytes_free, bytes_used + bytes_free); + kprintf("g_heap_bot=0x%p, g_kbrk=0x%p, g_heap_top=0x%p\n", + 103fa6: 83 c4 20 add $0x20,%esp + 103fa9: ff 35 e8 36 18 00 pushl 0x1836e8 + 103faf: ff 35 e4 36 18 00 pushl 0x1836e4 + 103fb5: ff 35 e0 36 18 00 pushl 0x1836e0 + 103fbb: 68 20 5e 10 00 push $0x105e20 + 103fc0: e8 bb fd ff ff call 103d80 + g_heap_bot, g_kbrk, g_heap_top); + total = (bytes_used + bytes_free) + + 103fc5: 8d 1c 5b lea (%ebx,%ebx,2),%ebx + (blks_used + blks_free) * sizeof(malloc_t); + if(total != g_kbrk - g_heap_bot) + 103fc8: a1 e4 36 18 00 mov 0x1836e4,%eax + 103fcd: 8d 1c 9e lea (%esi,%ebx,4),%ebx + 103fd0: 2b 05 e0 36 18 00 sub 0x1836e0,%eax + 103fd6: 83 c4 10 add $0x10,%esp + 103fd9: 39 c3 cmp %eax,%ebx + 103fdb: 74 10 je 103fed + kprintf("*** some heap memory is not accounted for\n"); + 103fdd: 83 ec 0c sub $0xc,%esp + 103fe0: 68 60 5e 10 00 push $0x105e60 + 103fe5: e8 96 fd ff ff call 103d80 + 103fea: 83 c4 10 add $0x10,%esp + kprintf("===============================================\n"); + 103fed: 83 ec 0c sub $0xc,%esp + 103ff0: 68 60 5d 10 00 push $0x105d60 + 103ff5: e8 86 fd ff ff call 103d80 +} + 103ffa: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 103ffd: 5b pop %ebx + 103ffe: 5e pop %esi + 103fff: 5f pop %edi + 104000: c9 leave + 104001: c3 ret + 104002: 89 f6 mov %esi,%esi + 104004: 8b 03 mov (%ebx),%eax + 104006: 46 inc %esi + 104007: 01 45 ec add %eax,0xffffffec(%ebp) + 10400a: e9 69 ff ff ff jmp 103f78 + 10400f: 90 nop + 104010: b8 b7 5a 10 00 mov $0x105ab7,%eax + 104015: e9 3d ff ff ff jmp 103f57 + 10401a: 89 f6 mov %esi,%esi + +0010401c : + +void dumpheapk(void) +{ + 10401c: 55 push %ebp + 10401d: 89 e5 mov %esp,%ebp + dump_heap(); + 10401f: c9 leave + 104020: e9 ef fe ff ff jmp 103f14 + 104025: 8d 76 00 lea 0x0(%esi),%esi + +00104028 : +} + +/** + * POSIX sbrk() looks like this + * void *sbrk(int incr); + * + * Mine is a bit different so I can signal the calling function + * if more memory than desired was allocated (e.g. in a system with paging) + * If your kbrk()/sbrk() always allocates the amount of memory you ask for, + * this code can be easily changed. + * + * int brk( void *sbrk( void *kbrk( + * function void *adr); int delta); int *delta); + * ---------------------- ------------ ------------ ------------- + * POSIX? yes yes NO + * return value if error -1 -1 NULL + * get break value . sbrk(0) int x=0; kbrk(&x); + * set break value to X brk(X) sbrk(X - sbrk(0)) int x=X, y=0; kbrk(&x) - kbrk(&y); + * enlarge heap by N bytes . sbrk(+N) int x=N; kbrk(&x); + * shrink heap by N bytes . sbrk(-N) int x=-N; kbrk(&x); + * can you tell if you're + * given more memory + * than you wanted? no no yes + */ +static void *kbrk(int *delta) +{ + static char heap[HEAP_SIZE]; + char *new_brk, *old_brk; + + /** + * heap doesn't exist yet + */ + if(g_heap_bot == NULL) + 104028: 8b 0d e0 36 18 00 mov 0x1836e0,%ecx + 10402e: 55 push %ebp + 10402f: 85 c9 test %ecx,%ecx + 104031: 89 e5 mov %esp,%ebp + 104033: 53 push %ebx + 104034: 75 1f jne 104055 + { + g_heap_bot = g_kbrk = heap; + 104036: b9 c0 95 10 00 mov $0x1095c0,%ecx + 10403b: c7 05 e4 36 18 00 c0 movl $0x1095c0,0x1836e4 + 104042: 95 10 00 + 104045: 89 0d e0 36 18 00 mov %ecx,0x1836e0 + g_heap_top = g_heap_bot + HEAP_SIZE; + 10404b: c7 05 e8 36 18 00 e0 movl $0x1836e0,0x1836e8 + 104052: 36 18 00 + } + new_brk = g_kbrk + (*delta); + 104055: 8b 1d e4 36 18 00 mov 0x1836e4,%ebx + 10405b: 8b 45 08 mov 0x8(%ebp),%eax + 10405e: 89 da mov %ebx,%edx + 104060: 03 10 add (%eax),%edx + + /** + * too low: return NULL + */ + if(new_brk < g_heap_bot) + 104062: 31 c0 xor %eax,%eax + 104064: 39 ca cmp %ecx,%edx + 104066: 72 10 jb 104078 + return NULL; + + /** + * too high: return NULL + */ + if(new_brk >= g_heap_top) + 104068: 3b 15 e8 36 18 00 cmp 0x1836e8,%edx + 10406e: 73 08 jae 104078 + return NULL; + + /** + * success: adjust brk value... + */ + old_brk = g_kbrk; + g_kbrk = new_brk; + 104070: 89 15 e4 36 18 00 mov %edx,0x1836e4 + + /** + * ...return actual delta... (for this sbrk(), they are the same) + * (*delta) = (*delta); + * ...return old brk value + */ + return old_brk; + 104076: 89 d8 mov %ebx,%eax +} + 104078: 8b 1c 24 mov (%esp,1),%ebx + 10407b: c9 leave + 10407c: c3 ret + 10407d: 8d 76 00 lea 0x0(%esi),%esi + +00104080 : + +/** + * malloc() and free() use g_heap_bot, but not g_kbrk nor g_heap_top + */ +void *kmalloc(size_t size) +{ + 104080: 55 push %ebp + 104081: 89 e5 mov %esp,%ebp + 104083: 57 push %edi + 104084: 56 push %esi + 104085: 53 push %ebx + 104086: 83 ec 0c sub $0xc,%esp + 104089: 8b 7d 08 mov 0x8(%ebp),%edi + unsigned total_size; + malloc_t *m, *n; + int delta; + + if(size == 0) + 10408c: 31 c0 xor %eax,%eax + 10408e: 85 ff test %edi,%edi + 104090: 0f 84 af 00 00 00 je 104145 + return NULL; + total_size = size + sizeof(malloc_t); + + /** + * search heap for free block (FIRST FIT) + */ + m = (malloc_t *)g_heap_bot; + 104096: 8b 1d e0 36 18 00 mov 0x1836e0,%ebx + + /** + * g_heap_bot == 0 == NULL if heap does not yet exist + */ + if(m != NULL) + 10409c: 85 db test %ebx,%ebx + 10409e: 8d 77 0c lea 0xc(%edi),%esi + 1040a1: 74 35 je 1040d8 + { + if(m->magic != MALLOC_MAGIC) + 1040a3: 0f b7 43 08 movzwl 0x8(%ebx),%eax + 1040a7: 25 ff 7f 00 00 and $0x7fff,%eax + 1040ac: 3d 92 6d 00 00 cmp $0x6d92,%eax + 1040b1: 0f 85 e5 00 00 00 jne 10419c + { + /*printf("*** kernel heap is corrupt in kmalloc()\n");*/ + panic("kernel heap is corrupt in malloc()"); + return NULL; + } + for(; m->next != NULL; m = m->next) + 1040b7: 8b 43 04 mov 0x4(%ebx),%eax + 1040ba: 85 c0 test %eax,%eax + 1040bc: 74 1a je 1040d8 + 1040be: 89 f6 mov %esi,%esi + { + if(m->used) + 1040c0: 8a 53 09 mov 0x9(%ebx),%dl + 1040c3: f6 c2 80 test $0x80,%dl + 1040c6: 0f 84 8c 00 00 00 je 104158 + 1040cc: 89 c3 mov %eax,%ebx + 1040ce: 8b 40 04 mov 0x4(%eax),%eax + 1040d1: 85 c0 test %eax,%eax + 1040d3: 75 eb jne 1040c0 + 1040d5: 8d 76 00 lea 0x0(%esi),%esi + continue; + + /** + * size == m->size is a perfect fit + */ + if(size == m->size) + m->used = 1; + else + { + /** + * otherwise, we need an extra sizeof(malloc_t) bytes for the header + * of a second, free block + */ + if(total_size > m->size) + continue; + + /** + * create a new, smaller free block after this one + */ + n = (malloc_t *)((char *)m + total_size); + n->size = m->size - total_size; + n->next = m->next; + n->magic = MALLOC_MAGIC; + n->used = 0; + + /** + * reduce the size of this block and mark it used + */ + m->size = size; + m->next = n; + m->used = 1; + } + return (char *)m + sizeof(malloc_t); + } + } + + /** + * use kbrk() to enlarge (or create!) heap + */ + delta = total_size; + n = kbrk(&delta); + 1040d8: 83 ec 0c sub $0xc,%esp + 1040db: 8d 45 f0 lea 0xfffffff0(%ebp),%eax + 1040de: 50 push %eax + 1040df: 89 75 f0 mov %esi,0xfffffff0(%ebp) + 1040e2: e8 41 ff ff ff call 104028 + 1040e7: 89 c2 mov %eax,%edx + + /** + * uh-oh + */ + if(n == NULL) + 1040e9: 83 c4 10 add $0x10,%esp + 1040ec: 31 c0 xor %eax,%eax + 1040ee: 85 d2 test %edx,%edx + 1040f0: 74 53 je 104145 + return NULL; + + if(m != NULL) + 1040f2: 85 db test %ebx,%ebx + 1040f4: 74 03 je 1040f9 + m->next = n; + 1040f6: 89 53 04 mov %edx,0x4(%ebx) + + n->size = size; + n->magic = MALLOC_MAGIC; + 1040f9: 66 8b 42 08 mov 0x8(%edx),%ax + 1040fd: 25 00 80 ff ff and $0xffff8000,%eax + 104102: 0d 92 6d 00 00 or $0x6d92,%eax + 104107: 66 89 42 08 mov %ax,0x8(%edx) + n->used = 1; + 10410b: 80 4a 09 80 orb $0x80,0x9(%edx) + + /** + * did kbrk() return the exact amount of memory we wanted? + * cast to make "gcc -Wall -W ..." shut the hell up + */ + if((int)total_size == delta) + 10410f: 8b 45 f0 mov 0xfffffff0(%ebp),%eax + 104112: 39 c6 cmp %eax,%esi + 104114: 89 3a mov %edi,(%edx) + 104116: 74 35 je 10414d + n->next = NULL; + else + { + + /** + * it returned more than we wanted (it will never return less): + * create a new, free block + */ + m = (malloc_t *)((char *)n + total_size); + m->size = delta - total_size - sizeof(malloc_t); + 104118: 29 f0 sub %esi,%eax + 10411a: 8d 1c 16 lea (%esi,%edx,1),%ebx + 10411d: 83 e8 0c sub $0xc,%eax + 104120: 89 03 mov %eax,(%ebx) + m->next = NULL; + m->magic = MALLOC_MAGIC; + 104122: 66 8b 43 08 mov 0x8(%ebx),%ax + 104126: 25 00 80 ff ff and $0xffff8000,%eax + 10412b: 0d 92 6d 00 00 or $0x6d92,%eax + 104130: 66 89 43 08 mov %ax,0x8(%ebx) + 104134: c7 43 04 00 00 00 00 movl $0x0,0x4(%ebx) + m->used = 0; + 10413b: 80 63 09 7f andb $0x7f,0x9(%ebx) + + n->next = m; + 10413f: 89 5a 04 mov %ebx,0x4(%edx) + } + return (char *)n + sizeof(malloc_t); + 104142: 8d 42 0c lea 0xc(%edx),%eax +} + 104145: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 104148: 5b pop %ebx + 104149: 5e pop %esi + 10414a: 5f pop %edi + 10414b: c9 leave + 10414c: c3 ret + 10414d: c7 42 04 00 00 00 00 movl $0x0,0x4(%edx) + 104154: eb ec jmp 104142 + 104156: 89 f6 mov %esi,%esi + 104158: 8b 0b mov (%ebx),%ecx + 10415a: 39 cf cmp %ecx,%edi + 10415c: 74 36 je 104194 + 10415e: 39 ce cmp %ecx,%esi + 104160: 0f 87 66 ff ff ff ja 1040cc + 104166: 8d 14 1e lea (%esi,%ebx,1),%edx + 104169: 89 42 04 mov %eax,0x4(%edx) + 10416c: 66 8b 42 08 mov 0x8(%edx),%ax + 104170: 25 00 80 ff ff and $0xffff8000,%eax + 104175: 0d 92 6d 00 00 or $0x6d92,%eax + 10417a: 66 89 42 08 mov %ax,0x8(%edx) + 10417e: 29 f1 sub %esi,%ecx + 104180: 80 62 09 7f andb $0x7f,0x9(%edx) + 104184: 89 0a mov %ecx,(%edx) + 104186: 89 53 04 mov %edx,0x4(%ebx) + 104189: 89 3b mov %edi,(%ebx) + 10418b: 80 4b 09 80 orb $0x80,0x9(%ebx) + 10418f: 8d 43 0c lea 0xc(%ebx),%eax + 104192: eb b1 jmp 104145 + 104194: 83 ca 80 or $0xffffff80,%edx + 104197: 88 53 09 mov %dl,0x9(%ebx) + 10419a: eb f3 jmp 10418f + 10419c: 83 ec 0c sub $0xc,%esp + 10419f: 68 a0 5e 10 00 push $0x105ea0 + 1041a4: e8 0f fc ff ff call 103db8 + 1041a9: 31 c0 xor %eax,%eax + 1041ab: eb 98 jmp 104145 + 1041ad: 8d 76 00 lea 0x0(%esi),%esi + +001041b0 : + +void kfree(void *blk) +{ + 1041b0: 55 push %ebp + 1041b1: 89 e5 mov %esp,%ebp + 1041b3: 56 push %esi + 1041b4: 53 push %ebx + 1041b5: 8b 5d 08 mov 0x8(%ebp),%ebx + malloc_t *m, *n; + + /** + * get address of header + */ + m = (malloc_t *)((char *)blk - sizeof(malloc_t)); + 1041b8: 8d 4b f4 lea 0xfffffff4(%ebx),%ecx + if(m->magic != MALLOC_MAGIC) + 1041bb: 0f b7 41 08 movzwl 0x8(%ecx),%eax + 1041bf: 25 ff 7f 00 00 and $0x7fff,%eax + 1041c4: 3d 92 6d 00 00 cmp $0x6d92,%eax + 1041c9: 74 15 je 1041e0 + { + /*printf("*** attempt to kfree() block at 0x%p with bad magic value\n", blk);*/ + panic("attempt to free() block at 0x%p with bad magic value", blk); + 1041cb: 83 ec 08 sub $0x8,%esp + 1041ce: 53 push %ebx + 1041cf: 68 e0 5e 10 00 push $0x105ee0 + 1041d4: e8 df fb ff ff call 103db8 + return; + } + + /** + * find this block in the heap + */ + n = (malloc_t *)g_heap_bot; + if(n->magic != MALLOC_MAGIC) + { + /*printf("*** kernel heap is corrupt in kfree()\n");*/ + panic("kernel heap is corrupt in free()"); + return; + } + for(; n != NULL; n = n->next) + { + if(n == m) + break; + } + + /** + * not found? bad pointer or no heap or something else? + */ + if(n == NULL) + { + /*printf("*** attempt to kfree() block at 0x%p that is not in the heap\n", blk);*/ + panic("attempt to free() block at 0x%p that is not in the heap", blk); + return; + } + + /** + * free the block + */ + m->used = 0; + + /** + * coalesce adjacent free blocks + * Hard to spell, hard to do + */ + for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next) + { + while(!m->used && m->next != NULL && !m->next->used) + { + /** + * resize this block + */ + m->size += sizeof(malloc_t) + m->next->size; + + /** + * merge with next block + */ + m->next = m->next->next; + } + } +} + 1041d9: 8d 65 f8 lea 0xfffffff8(%ebp),%esp + 1041dc: 5b pop %ebx + 1041dd: 5e pop %esi + 1041de: c9 leave + 1041df: c3 ret + 1041e0: 8b 15 e0 36 18 00 mov 0x1836e0,%edx + 1041e6: 0f b7 42 08 movzwl 0x8(%edx),%eax + 1041ea: 25 ff 7f 00 00 and $0x7fff,%eax + 1041ef: 3d 92 6d 00 00 cmp $0x6d92,%eax + 1041f4: 74 12 je 104208 + 1041f6: c7 45 08 20 5f 10 00 movl $0x105f20,0x8(%ebp) + 1041fd: 8d 65 f8 lea 0xfffffff8(%ebp),%esp + 104200: 5b pop %ebx + 104201: 5e pop %esi + 104202: c9 leave + 104203: e9 b0 fb ff ff jmp 103db8 + 104208: 85 d2 test %edx,%edx + 10420a: 74 0b je 104217 + 10420c: 39 ca cmp %ecx,%edx + 10420e: 74 12 je 104222 + 104210: 8b 52 04 mov 0x4(%edx),%edx + 104213: 85 d2 test %edx,%edx + 104215: 75 f5 jne 10420c + 104217: 83 ec 08 sub $0x8,%esp + 10421a: 53 push %ebx + 10421b: 68 60 5f 10 00 push $0x105f60 + 104220: eb b2 jmp 1041d4 + 104222: 85 d2 test %edx,%edx + 104224: 74 f1 je 104217 + 104226: 80 61 09 7f andb $0x7f,0x9(%ecx) + 10422a: 8b 0d e0 36 18 00 mov 0x1836e0,%ecx + 104230: 85 c9 test %ecx,%ecx + 104232: 74 a5 je 1041d9 + 104234: f6 41 09 80 testb $0x80,0x9(%ecx) + 104238: 75 46 jne 104280 + 10423a: 8b 51 04 mov 0x4(%ecx),%edx + 10423d: 85 d2 test %edx,%edx + 10423f: 89 d3 mov %edx,%ebx + 104241: 74 31 je 104274 + 104243: f6 42 09 80 testb $0x80,0x9(%edx) + 104247: 75 2b jne 104274 + 104249: 31 f6 xor %esi,%esi + 10424b: 90 nop + 10424c: 8b 03 mov (%ebx),%eax + 10424e: 03 01 add (%ecx),%eax + 104250: 83 c0 0c add $0xc,%eax + 104253: 89 01 mov %eax,(%ecx) + 104255: 85 f6 test %esi,%esi + 104257: 8b 43 04 mov 0x4(%ebx),%eax + 10425a: 89 41 04 mov %eax,0x4(%ecx) + 10425d: 89 c2 mov %eax,%edx + 10425f: 75 13 jne 104274 + 104261: 31 d2 xor %edx,%edx + 104263: 85 c0 test %eax,%eax + 104265: 74 0d je 104274 + 104267: f6 40 09 80 testb $0x80,0x9(%eax) + 10426b: 89 c3 mov %eax,%ebx + 10426d: 74 dd je 10424c + 10426f: 89 c2 mov %eax,%edx + 104271: 8d 76 00 lea 0x0(%esi),%esi + 104274: 85 d2 test %edx,%edx + 104276: 89 d1 mov %edx,%ecx + 104278: 75 ba jne 104234 + 10427a: e9 5a ff ff ff jmp 1041d9 + 10427f: 90 nop + 104280: 8b 51 04 mov 0x4(%ecx),%edx + 104283: eb ef jmp 104274 + 104285: 8d 76 00 lea 0x0(%esi),%esi + +00104288 : + +void testheap(void) +{ + 104288: 55 push %ebp + 104289: 89 e5 mov %esp,%ebp + 10428b: 83 ec 14 sub $0x14,%esp + //int i; + //char *t; + //kprintf("before char *t = kmalloc((size_t *)25):\n"); + //dump_heap(); + //t = kmalloc(25); + //strcpy(t, "123456789012345678901234"); + //kprintf("after char *t = kmalloc((size_t *)25):\n"); + //dump_heap(); + //kfree(t); + //kprintf("after kfree(t):\n"); + //dump_heap(); + //kprintf("before char *t = kmalloc((size_t *)25):\n"); + + kprintf("Unable to run testheap -- kmalloc() is broken.\n"); + 10428e: 68 a0 5f 10 00 push $0x105fa0 + 104293: e8 e8 fa ff ff call 103d80 +} + 104298: c9 leave + 104299: c3 ret + 10429a: 89 f6 mov %esi,%esi + +0010429c : + +void *krealloc(void *blk, size_t size) +{ + 10429c: 55 push %ebp + 10429d: 89 e5 mov %esp,%ebp + 10429f: 57 push %edi + 1042a0: 56 push %esi + 1042a1: 53 push %ebx + 1042a2: 83 ec 0c sub $0xc,%esp + 1042a5: 8b 5d 0c mov 0xc(%ebp),%ebx + void *new_blk; + malloc_t *m; + + /** + * size == 0: free block + */ + if(size == 0) + 1042a8: 85 db test %ebx,%ebx + 1042aa: 8b 75 08 mov 0x8(%ebp),%esi + 1042ad: 75 1d jne 1042cc + { + if(blk != NULL) + 1042af: 85 f6 test %esi,%esi + 1042b1: 74 0c je 1042bf + kfree(blk); + 1042b3: 83 ec 0c sub $0xc,%esp + 1042b6: 56 push %esi + 1042b7: e8 f4 fe ff ff call 1041b0 + 1042bc: 83 c4 10 add $0x10,%esp + new_blk = NULL; + 1042bf: 31 ff xor %edi,%edi + } + else + { + /** + * allocate new block + */ + new_blk = kmalloc(size); + + /** + * if allocation OK, and if old block exists, copy old block to new + */ + if(new_blk != NULL && blk != NULL) + { + m = (malloc_t *)((char *)blk - sizeof(malloc_t)); + if(m->magic != MALLOC_MAGIC) + { + /*printf("*** attempt to krealloc() block at 0x%p with bad magic value\n", blk);*/ + panic("attempt to realloc() block at 0x%p with bad magic value", blk); + return NULL; + } + + /** + * copy minimum of old and new block sizes + */ + if(size > m->size) + size = m->size; + memcpy(new_blk, blk, size); + + /** + * free the old block + */ + kfree(blk); + } + } + return new_blk; + 1042c1: 89 f8 mov %edi,%eax +} + 1042c3: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 1042c6: 5b pop %ebx + 1042c7: 5e pop %esi + 1042c8: 5f pop %edi + 1042c9: c9 leave + 1042ca: c3 ret + 1042cb: 90 nop + 1042cc: 83 ec 0c sub $0xc,%esp + 1042cf: 53 push %ebx + 1042d0: e8 ab fd ff ff call 104080 + 1042d5: 83 c4 10 add $0x10,%esp + 1042d8: 85 c0 test %eax,%eax + 1042da: 89 c7 mov %eax,%edi + 1042dc: 74 e3 je 1042c1 + 1042de: 85 f6 test %esi,%esi + 1042e0: 74 df je 1042c1 + 1042e2: 0f b7 46 fc movzwl 0xfffffffc(%esi),%eax + 1042e6: 25 ff 7f 00 00 and $0x7fff,%eax + 1042eb: 3d 92 6d 00 00 cmp $0x6d92,%eax + 1042f0: 75 1f jne 104311 + 1042f2: 8b 46 f4 mov 0xfffffff4(%esi),%eax + 1042f5: 39 c3 cmp %eax,%ebx + 1042f7: 76 02 jbe 1042fb + 1042f9: 89 c3 mov %eax,%ebx + 1042fb: 50 push %eax + 1042fc: 53 push %ebx + 1042fd: 56 push %esi + 1042fe: 57 push %edi + 1042ff: e8 58 0d 00 00 call 10505c + 104304: 89 34 24 mov %esi,(%esp,1) + 104307: e8 a4 fe ff ff call 1041b0 + 10430c: 83 c4 10 add $0x10,%esp + 10430f: eb b0 jmp 1042c1 + 104311: 83 ec 08 sub $0x8,%esp + 104314: 56 push %esi + 104315: 68 e0 5f 10 00 push $0x105fe0 + 10431a: e8 99 fa ff ff call 103db8 + 10431f: 31 c0 xor %eax,%eax + 104321: eb a0 jmp 1042c3 + 104323: 90 nop + +00104324
: + +void keyboardISR(void); + +int main(void) +{ + 104324: 55 push %ebp + 104325: 89 e5 mov %esp,%ebp + 104327: 83 ec 08 sub $0x8,%esp + 10432a: 83 e4 f0 and $0xfffffff0,%esp + /** + * keyboard interrupt init + */ + vector_t v; + unsigned i; + + init_video(); + 10432d: e8 e6 07 00 00 call 104b18 + init_keyboard(); + 104332: e8 45 d2 ff ff call 10157c + init_8259s(); + 104337: e8 54 fb ff ff call 103e90 + + /** + * XXX: + * i know this is a very ugly way of doing this, + * however it is the only way it can be done for now. + * in the future, i will implement a kprintf function + * whose sole purpose will be writing boot messages. + * + * Also, the color codes need to be mapped to constants + * in order to make using them a hell of a lot easier. + */ + + klog("init", "Installing keyboard interrupt handler", K_KLOG_PENDING, &_vc[0]); + 10433c: 68 e0 a2 19 00 push $0x19a2e0 + 104341: 6a 01 push $0x1 + 104343: 68 20 60 10 00 push $0x106020 + 104348: 68 bc 5a 10 00 push $0x105abc + 10434d: e8 ae bc ff ff call 100000 + /* we don't save the old vector */ + v.eip = (unsigned)keyboard_irq; + v.access_byte = 0x8E; /* present, ring 0, '386 interrupt gate */ + setvect(&v, 0x21); + 104352: 58 pop %eax + 104353: 5a pop %edx + 104354: 8d 45 f8 lea 0xfffffff8(%ebp),%eax + 104357: 6a 21 push $0x21 + 104359: 50 push %eax + 10435a: c7 45 fc 1c 13 10 00 movl $0x10131c,0xfffffffc(%ebp) + 104361: c7 45 f8 8e 00 00 00 movl $0x8e,0xfffffff8(%ebp) + 104368: e8 c4 d3 ff ff call 101731 <_setvect> + klog(NULL, NULL, K_KLOG_SUCCESS, &_vc[0]); + 10436d: 68 e0 a2 19 00 push $0x19a2e0 + 104372: 6a 00 push $0x0 + 104374: 6a 00 push $0x0 + 104376: 6a 00 push $0x0 + 104378: e8 83 bc ff ff call 100000 + + /*init_tasks();*/ + + klog("init", "Enabling hardware interrupts", K_KLOG_PENDING, &_vc[0]); + 10437d: 83 c4 20 add $0x20,%esp + 104380: 68 e0 a2 19 00 push $0x19a2e0 + 104385: 6a 01 push $0x1 + 104387: 68 c1 5a 10 00 push $0x105ac1 + 10438c: 68 bc 5a 10 00 push $0x105abc + 104391: e8 6a bc ff ff call 100000 + enable(); + 104396: e8 71 0c 00 00 call 10500c + /*for(i = 0; i < 0xFFFFFFF; i++);*/ + klog(NULL, NULL, K_KLOG_SUCCESS, &_vc[0]); + 10439b: 68 e0 a2 19 00 push $0x19a2e0 + 1043a0: 6a 00 push $0x0 + 1043a2: 6a 00 push $0x0 + 1043a4: 6a 00 push $0x0 + 1043a6: e8 55 bc ff ff call 100000 + + /** + * Initialize memory management + */ + /*_mm_init();*/ + + /** + * finished init, time for some gooey ;) + */ + printf(" _ _ _ _ ____ _____ ___ "); + 1043ab: 83 c4 14 add $0x14,%esp + 1043ae: 68 60 60 10 00 push $0x106060 + 1043b3: e8 1c 0d 00 00 call 1050d4 + printf(" ( )_( )( \\/ )( _ \\( _ )/ __) "); + 1043b8: c7 04 24 c0 60 10 00 movl $0x1060c0,(%esp,1) + 1043bf: e8 10 0d 00 00 call 1050d4 + printf(" ) _ ( \\ / ) _ < )(_)( \\__ \\ "); + 1043c4: c7 04 24 20 61 10 00 movl $0x106120,(%esp,1) + 1043cb: e8 04 0d 00 00 call 1050d4 + printf(" (_) (_) (__) (____/(_____)(___/ \n"); + 1043d0: c7 04 24 80 61 10 00 movl $0x106180,(%esp,1) + 1043d7: e8 f8 0c 00 00 call 1050d4 + + printf(" Hybrid Operating System (HybOS) \n"); + 1043dc: c7 04 24 e0 61 10 00 movl $0x1061e0,(%esp,1) + 1043e3: e8 ec 0c 00 00 call 1050d4 + + /** + * XXX: debug only + */ + printf("ALT + F1 - F8 for virtual terminals\n"); + 1043e8: c7 04 24 40 62 10 00 movl $0x106240,(%esp,1) + 1043ef: e8 e0 0c 00 00 call 1050d4 + printf("Three finger salute to restart\n"); + 1043f4: c7 04 24 80 62 10 00 movl $0x106280,(%esp,1) + 1043fb: e8 d4 0c 00 00 call 1050d4 + printf("More work needs to be done\n"); + 104400: c7 04 24 de 5a 10 00 movl $0x105ade,(%esp,1) + 104407: e8 c8 0c 00 00 call 1050d4 + printf("$ "); + 10440c: c7 04 24 d6 54 10 00 movl $0x1054d6,(%esp,1) + 104413: e8 bc 0c 00 00 call 1050d4 + + /** + * fork (kfork()) control over to a shell + */ + /*init_shell();*/ + + /** + * idle task/thread + */ + while(1) + 104418: 83 c4 10 add $0x10,%esp + 10441b: 90 nop + { + schedule(); + 10441c: e8 47 01 00 00 call 104568 + 104421: eb f9 jmp 10441c + ... + +00104424 <_mm_init>: +void _mm_page_copy_dword(uint32_t dest, uint32_t src); +void _mm_virtual_init(void); + +void _mm_init(void) +{ + 104424: 55 push %ebp + 104425: 89 e5 mov %esp,%ebp + 104427: 83 ec 08 sub $0x8,%esp + klog("init", "Initializing memory management", K_KLOG_PENDING, &_vc[0]); + 10442a: 68 e0 a2 19 00 push $0x19a2e0 + 10442f: 6a 01 push $0x1 + 104431: 68 a0 62 10 00 push $0x1062a0 + 104436: 68 bc 5a 10 00 push $0x105abc + 10443b: e8 c0 bb ff ff call 100000 + _mm_physical_init(); + 104440: e8 17 00 00 00 call 10445c <_mm_physical_init> + _mm_virtual_init(); + 104445: e8 ce 00 00 00 call 104518 <_mm_virtual_init> + klog((void *)0, (void *)0, K_KLOG_SUCCESS, &_vc[0]); + 10444a: 68 e0 a2 19 00 push $0x19a2e0 + 10444f: 6a 00 push $0x0 + 104451: 6a 00 push $0x0 + 104453: 6a 00 push $0x0 + 104455: e8 a6 bb ff ff call 100000 +} + 10445a: c9 leave + 10445b: c3 ret + +0010445c <_mm_physical_init>: + +void _mm_physical_init(void) +{ + 10445c: 55 push %ebp + 10445d: 89 e5 mov %esp,%ebp + unsigned i; + unsigned size = 16 * 1024 * 1024; + + size /= PAGESIZE; + size++; + size /= 32; + + buffer = (unsigned *)0x40000; + 10445f: ba 00 00 04 00 mov $0x40000,%edx + 104464: c7 05 84 72 19 00 00 movl $0x40000,0x197284 + 10446b: 00 04 00 + bufferIterator = (unsigned *)0x40000; + 10446e: c7 05 80 72 19 00 00 movl $0x40000,0x197280 + 104475: 00 04 00 + + for(i = 0; i < 72; i++) + 104478: 31 c0 xor %eax,%eax + 10447a: 89 f6 mov %esi,%esi + buffer[i] = 0xFFFFFFFF; + 10447c: c7 04 82 ff ff ff ff movl $0xffffffff,(%edx,%eax,4) + 104483: 40 inc %eax + 104484: 83 f8 47 cmp $0x47,%eax + 104487: 76 f3 jbe 10447c <_mm_physical_init+0x20> + 104489: b8 48 00 00 00 mov $0x48,%eax + 10448e: 89 f6 mov %esi,%esi + + for(i = 72; i < size; i++) + buffer[i] = 0x00000000; + 104490: c7 04 82 00 00 00 00 movl $0x0,(%edx,%eax,4) + 104497: 40 inc %eax + 104498: 3d 80 00 00 00 cmp $0x80,%eax + 10449d: 72 f1 jb 104490 <_mm_physical_init+0x34> +} + 10449f: c9 leave + 1044a0: c3 ret + 1044a1: 8d 76 00 lea 0x0(%esi),%esi + +001044a4 <_mm_physical_alloc>: + +unsigned _mm_physical_alloc(void) +{ + 1044a4: 55 push %ebp + 1044a5: 89 e5 mov %esp,%ebp + 1044a7: 56 push %esi + 1044a8: 53 push %ebx + unsigned mask = 0x00000001; + unsigned bit = 0; + + /** + * Search for a free space + */ + while(*bufferIterator == 0xFFFFFFFF) + 1044a9: 8b 15 80 72 19 00 mov 0x197280,%edx + 1044af: 31 f6 xor %esi,%esi + 1044b1: 83 3a ff cmpl $0xffffffff,(%edx) + 1044b4: b9 01 00 00 00 mov $0x1,%ecx + 1044b9: 74 1f je 1044da <_mm_physical_alloc+0x36> + bufferIterator++; + + /** + * Search for a bit that indicates a free page + */ + while(*bufferIterator & mask) + 1044bb: 8b 02 mov (%edx),%eax + 1044bd: a8 01 test $0x1,%al + 1044bf: 74 0a je 1044cb <_mm_physical_alloc+0x27> + 1044c1: 8d 76 00 lea 0x0(%esi),%esi + { + mask <<= 1; + 1044c4: d1 e1 shl %ecx + bit++; + 1044c6: 46 inc %esi + 1044c7: 85 c1 test %eax,%ecx + 1044c9: 75 f9 jne 1044c4 <_mm_physical_alloc+0x20> + } + + *bufferIterator |= mask; + 1044cb: 09 0a or %ecx,(%edx) + + return 32 * (bufferIterator - buffer) + bit; +} + 1044cd: 5b pop %ebx + 1044ce: 2b 15 84 72 19 00 sub 0x197284,%edx + 1044d4: 8d 04 d6 lea (%esi,%edx,8),%eax + 1044d7: 5e pop %esi + 1044d8: c9 leave + 1044d9: c3 ret + 1044da: 8d 42 04 lea 0x4(%edx),%eax + 1044dd: 8d 76 00 lea 0x0(%esi),%esi + 1044e0: 89 c2 mov %eax,%edx + 1044e2: 8d 40 04 lea 0x4(%eax),%eax + 1044e5: 83 78 fc ff cmpl $0xffffffff,0xfffffffc(%eax) + 1044e9: 74 f5 je 1044e0 <_mm_physical_alloc+0x3c> + 1044eb: 89 15 80 72 19 00 mov %edx,0x197280 + 1044f1: eb c8 jmp 1044bb <_mm_physical_alloc+0x17> + 1044f3: 90 nop + +001044f4 <_mm_physical_free>: + +void _mm_physical_free(unsigned page) +{ + 1044f4: 55 push %ebp + 1044f5: 89 e5 mov %esp,%ebp + 1044f7: 8b 4d 08 mov 0x8(%ebp),%ecx + 1044fa: 53 push %ebx + buffer[page >> 5] &= ~(1 << (page & 0x1F)); /* confused yet?!? */ + 1044fb: b8 fe ff ff ff mov $0xfffffffe,%eax + 104500: 89 cb mov %ecx,%ebx + 104502: 83 e1 1f and $0x1f,%ecx + 104505: c1 eb 05 shr $0x5,%ebx + 104508: 8b 15 84 72 19 00 mov 0x197284,%edx + 10450e: d3 c0 rol %cl,%eax + 104510: 21 04 9a and %eax,(%edx,%ebx,4) +} + 104513: 8b 1c 24 mov (%esp,1),%ebx + 104516: c9 leave + 104517: c3 ret + +00104518 <_mm_virtual_init>: + +void _mm_virtual_init(void) +{ + 104518: 55 push %ebp + 104519: 89 e5 mov %esp,%ebp + 10451b: c9 leave + 10451c: c3 ret + 10451d: 8d 76 00 lea 0x0(%esi),%esi + +00104520 <_mm_page_copy_byte>: +} + +void _mm_page_copy_byte(uint32_t dest, uint32_t src) +{ + 104520: 55 push %ebp + 104521: 89 e5 mov %esp,%ebp + 104523: 57 push %edi + 104524: 56 push %esi + 104525: 8b 7d 08 mov 0x8(%ebp),%edi + 104528: 8b 75 0c mov 0xc(%ebp),%esi + __asm__ __volatile__ + 10452b: b9 00 00 10 00 mov $0x100000,%ecx + 104530: fc cld + 104531: f3 a4 repz movsb %ds:(%esi),%es:(%edi) + ( + "cld;" + "rep; movsb;" + : + : "c" (1024*1024), "D" (dest), "S" (src) + : "memory" + ); +} + 104533: 5e pop %esi + 104534: 5f pop %edi + 104535: c9 leave + 104536: c3 ret + 104537: 90 nop + +00104538 <_mm_page_copy_word>: + +void _mm_page_copy_word(uint32_t dest, uint32_t src) +{ + 104538: 55 push %ebp + 104539: 89 e5 mov %esp,%ebp + 10453b: 57 push %edi + 10453c: 56 push %esi + 10453d: 8b 7d 08 mov 0x8(%ebp),%edi + 104540: 8b 75 0c mov 0xc(%ebp),%esi + __asm__ __volatile__ + 104543: b9 00 00 08 00 mov $0x80000,%ecx + 104548: fc cld + 104549: f3 66 a5 repz movsw %ds:(%esi),%es:(%edi) + ( + "cld;" + "rep; movsw;" + : + : "c" (512*1024), "D" (dest), "S" (src) + : "memory" + ); +} + 10454c: 5e pop %esi + 10454d: 5f pop %edi + 10454e: c9 leave + 10454f: c3 ret + +00104550 <_mm_page_copy_dword>: + +void _mm_page_copy_dword(uint32_t dest, uint32_t src) +{ + 104550: 55 push %ebp + 104551: 89 e5 mov %esp,%ebp + 104553: 57 push %edi + 104554: 56 push %esi + 104555: 8b 7d 08 mov 0x8(%ebp),%edi + 104558: 8b 75 0c mov 0xc(%ebp),%esi + __asm__ __volatile__ + 10455b: b9 00 00 04 00 mov $0x40000,%ecx + 104560: fc cld + 104561: f3 a5 repz movsl %ds:(%esi),%es:(%edi) + ( + "cld;" + "rep; movsl;" + : + : "c" (256*1024), "D" (dest), "S" (src) + : "memory" + ); +} + 104563: 5e pop %esi + 104564: 5f pop %edi + 104565: c9 leave + 104566: c3 ret + ... + +00104568 : + * schedule() + * + */ +void schedule(void) +{ + 104568: 55 push %ebp + 104569: 89 e5 mov %esp,%ebp + 10456b: 83 ec 08 sub $0x8,%esp + static unsigned current; + + /** + * If setjmp() returns non-zero it means that we came here through + * hyperspace from our call to longjmp() below, so just return + */ +/** UBU + if(setjmp(_curr_task->state) != 0) + return; +**/ + + /** + * Try to find the next runnable task + */ + do + 10456e: 8b 15 00 37 18 00 mov 0x183700,%edx + { + current++; + 104574: 42 inc %edx + if(current >= MAX_TASK) + 104575: 83 fa 0f cmp $0xf,%edx + 104578: 89 d0 mov %edx,%eax + 10457a: 76 04 jbe 104580 + current = 0; + 10457c: 31 c0 xor %eax,%eax + 10457e: 31 d2 xor %edx,%edx + _curr_task = _tasks + current; + 104580: 8d 04 40 lea (%eax,%eax,2),%eax + 104583: c1 e0 04 shl $0x4,%eax + 104586: 05 20 37 18 00 add $0x183720,%eax + } while(_curr_task->status != TS_RUNNABLE); + 10458b: 83 78 2c 01 cmpl $0x1,0x2c(%eax) + 10458f: 75 e3 jne 104574 + + /** + * Jump to the new task + */ + longjmp(_curr_task->state, 1); + 104591: 83 ec 08 sub $0x8,%esp + 104594: a3 a0 a2 19 00 mov %eax,0x19a2a0 + 104599: 6a 01 push $0x1 + 10459b: 83 c0 04 add $0x4,%eax + 10459e: 50 push %eax + 10459f: 89 15 00 37 18 00 mov %edx,0x183700 + 1045a5: e8 76 0a 00 00 call 105020 + 1045aa: 89 f6 mov %esi,%esi + +001045ac : +} +/***************************************************************************** +*****************************************************************************/ +#define NUM_TASKS 0 + +/** + * init_tasks() + * + */ +void init_tasks(void) +{ + 1045ac: 55 push %ebp + 1045ad: 89 e5 mov %esp,%ebp + 1045af: 83 ec 08 sub $0x8,%esp + static unsigned char stacks[NUM_TASKS][USER_STACK_SIZE]; + /*static unsigned entry[NUM_TASKS] = + { + 0, (unsigned)task1, + (unsigned)task2, (unsigned)task3, + (unsigned)task4 + };*/ + static unsigned entry[NUM_TASKS]; + + unsigned adr, i; + + klog("init", "task handler", K_KLOG_PENDING, &_vc[0]); + 1045b2: 68 e0 a2 19 00 push $0x19a2e0 + 1045b7: 6a 01 push $0x1 + 1045b9: 68 c4 62 10 00 push $0x1062c4 + 1045be: 68 bc 5a 10 00 push $0x105abc + 1045c3: e8 38 ba ff ff call 100000 + + /** + * For user taskes, initialize the saved state + */ + for(i = 1; i < NUM_TASKS; i++) + 1045c8: 83 c4 10 add $0x10,%esp + { + (void)setjmp(_tasks[i].state); + + /** + * especially the stack pointer + */ + adr = (unsigned)(stacks[i] + USER_STACK_SIZE); + _tasks[i].state[0].JMPBUF_SP = adr; + + /** + * and program counter + */ + _tasks[i].state[0].JMPBUF_IP = entry[i]; + + /** + * enable interrupts (by setting EFLAGS value) + */ + _tasks[i].state[0].JMPBUF_FLAGS = 0x200; + + /** + * allocate a virtual console to this task + */ + _tasks[i].vc = _vc + i; + + /** + * and mark it as runnable + */ + _tasks[i].status = TS_RUNNABLE; + } + + /** + * mark task 0 runnable (idle task) + */ + _tasks[0].status = TS_RUNNABLE; + 1045cb: c7 05 4c 37 18 00 01 movl $0x1,0x18374c + 1045d2: 00 00 00 + + /** + * set _curr_task so schedule() will save state + * of task 0 + */ + _curr_task = _tasks + 0; + + klog(NULL, NULL, K_KLOG_SUCCESS, &_vc[0]); + 1045d5: 68 e0 a2 19 00 push $0x19a2e0 + 1045da: 6a 00 push $0x0 + 1045dc: 6a 00 push $0x0 + 1045de: 6a 00 push $0x0 + 1045e0: c7 05 a0 a2 19 00 20 movl $0x183720,0x19a2a0 + 1045e7: 37 18 00 + 1045ea: e8 11 ba ff ff call 100000 +} + 1045ef: c9 leave + 1045f0: c3 ret + 1045f1: 00 00 add %al,(%eax) + ... + +001045f4 : + * write() + * + */ +static int write(const unsigned char *str, unsigned len) +{ + 1045f4: 55 push %ebp + 1045f5: 89 e5 mov %esp,%ebp + 1045f7: 57 push %edi + 1045f8: 56 push %esi + 1045f9: 53 push %ebx + 1045fa: 83 ec 0c sub $0xc,%esp + 1045fd: 8b 7d 0c mov 0xc(%ebp),%edi + unsigned i; + + for(i = 0; i < len; i++) + 104600: 31 f6 xor %esi,%esi + 104602: 39 fe cmp %edi,%esi + 104604: 8b 5d 08 mov 0x8(%ebp),%ebx + 104607: 72 0b jb 104614 + { + putch_help(_curr_task->vc, *str); + str++; + } + return i; +} + 104609: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 10460c: 5b pop %ebx + 10460d: 89 f0 mov %esi,%eax + 10460f: 5e pop %esi + 104610: 5f pop %edi + 104611: c9 leave + 104612: c3 ret + 104613: 90 nop + 104614: 83 ec 08 sub $0x8,%esp + 104617: 0f b6 03 movzbl (%ebx),%eax + 10461a: 50 push %eax + 10461b: a1 a0 a2 19 00 mov 0x19a2a0,%eax + 104620: ff 30 pushl (%eax) + 104622: 46 inc %esi + 104623: e8 68 02 00 00 call 104890 + 104628: 43 inc %ebx + 104629: 83 c4 10 add $0x10,%esp + 10462c: 39 fe cmp %edi,%esi + 10462e: 72 e4 jb 104614 + 104630: eb d7 jmp 104609 + 104632: 89 f6 mov %esi,%esi + +00104634 : + +/** + * yield() + * + */ +static void yield(void) +{ + 104634: 55 push %ebp + 104635: 89 e5 mov %esp,%ebp + schedule(); + 104637: c9 leave + 104638: e9 2b ff ff ff jmp 104568 + 10463d: 8d 76 00 lea 0x0(%esi),%esi + +00104640 : +} + +#define WAIT 0xFFFFFL + +/** + * wait() + */ +static void wait(void) +{ + 104640: 55 push %ebp + 104641: 89 e5 mov %esp,%ebp + unsigned long wait; + + for(wait = WAIT; wait != 0; wait--) + 104643: b8 ff ff 0f 00 mov $0xfffff,%eax + 104648: 48 dec %eax + 104649: 75 fd jne 104648 + /* nothing */; +} + 10464b: c9 leave + 10464c: c3 ret + 10464d: 8d 76 00 lea 0x0(%esi),%esi + +00104650 : + +/** + * task1() + * + */ +void task1(void) +{ + 104650: 55 push %ebp + 104651: 89 e5 mov %esp,%ebp + 104653: 83 ec 08 sub $0x8,%esp + 104656: 89 f6 mov %esi,%esi + //static const unsigned char msg_a[] = "root@hybos $ "; +/**/ + + //write(msg_a, sizeof(msg_a)); + wait(); + 104658: e8 e3 ff ff ff call 104640 + while(1) + { + /* so we can process other events */ + yield(); + 10465d: e8 d2 ff ff ff call 104634 + wait(); + 104662: eb f4 jmp 104658 + +00104664 : + } +} + +/** + * task2() + * + */ +void task2(void) +{ + 104664: 55 push %ebp + 104665: 89 e5 mov %esp,%ebp + 104667: 83 ec 08 sub $0x8,%esp + 10466a: 89 f6 mov %esi,%esi + //static const unsigned char msg_a[] = "root@hybos $ "; +/**/ + + //write(msg_a, sizeof(msg_a)); + wait(); + 10466c: e8 cf ff ff ff call 104640 + while(1) + { + yield(); + 104671: e8 be ff ff ff call 104634 + wait(); + 104676: eb f4 jmp 10466c + +00104678 : + } +} + +/** + * task3() + * + */ +void task3(void) +{ + 104678: 55 push %ebp + 104679: 89 e5 mov %esp,%ebp + 10467b: 83 ec 08 sub $0x8,%esp + 10467e: 89 f6 mov %esi,%esi + //static const unsigned char msg_a[] = "root@hybos $ "; +/**/ + + //write(msg_a, sizeof(msg_a)); + wait(); + 104680: e8 bb ff ff ff call 104640 + while(1) + { + yield(); + 104685: e8 aa ff ff ff call 104634 + wait(); + 10468a: eb f4 jmp 104680 + +0010468c : + } +} + +/** + * task4() + * + */ +void task4(void) +{ + 10468c: 55 push %ebp + 10468d: 89 e5 mov %esp,%ebp + 10468f: 83 ec 08 sub $0x8,%esp + 104692: 89 f6 mov %esi,%esi + //static const unsigned char msg_a[] = "root@hybos $ "; +/**/ + + //write(msg_a, sizeof(msg_a)); + wait(); + 104694: e8 a7 ff ff ff call 104640 + while(1) + { + yield(); + 104699: e8 96 ff ff ff call 104634 + wait(); + 10469e: eb f4 jmp 104694 + +001046a0 : + * blink() + * + */ +void blink(void) +{ + 1046a0: 55 push %ebp + (*(unsigned char *)_vga_fb_adr)++; + 1046a1: a1 28 3a 18 00 mov 0x183a28,%eax + 1046a6: 89 e5 mov %esp,%ebp + 1046a8: fe 00 incb (%eax) +} + 1046aa: c9 leave + 1046ab: c3 ret + +001046ac : + +/** + * get_current_vc() + * + */ +unsigned get_current_vc() +{ + 1046ac: 55 push %ebp + 1046ad: 89 e5 mov %esp,%ebp + return curr_vtty; + 1046af: a1 c0 a2 19 00 mov 0x19a2c0,%eax +} + 1046b4: c9 leave + 1046b5: c3 ret + 1046b6: 89 f6 mov %esi,%esi + +001046b8 : + +/** + * scroll() + * + */ +static void scroll(console_t *con) +{ + 1046b8: 55 push %ebp + 1046b9: 89 e5 mov %esp,%ebp + 1046bb: 57 push %edi + 1046bc: 56 push %esi + 1046bd: 53 push %ebx + 1046be: 83 ec 0c sub $0xc,%esp + unsigned short *fb_adr; + unsigned blank, temp; + + blank = 0x20 | ((unsigned)con->attrib << 8); + 1046c1: 8b 45 08 mov 0x8(%ebp),%eax + 1046c4: 8b 70 18 mov 0x18(%eax),%esi + 1046c7: c1 e6 08 shl $0x8,%esi + fb_adr = con->fb_adr; + 1046ca: 8b 78 30 mov 0x30(%eax),%edi + + /** + * scroll up + */ + if(con->csr_y >= _vc_height) + 1046cd: 8b 15 34 3a 18 00 mov 0x183a34,%edx + 1046d3: 8b 40 20 mov 0x20(%eax),%eax + 1046d6: 83 ce 20 or $0x20,%esi + 1046d9: 39 d0 cmp %edx,%eax + 1046db: 73 0b jae 1046e8 + { + temp = con->csr_y - _vc_height + 1; + memcpy(fb_adr, fb_adr + temp * _vc_width, + (_vc_height - temp) * _vc_width * 2); + + /** + * blank bottom line of screen + */ + memsetw(fb_adr + (_vc_height - temp) * _vc_width, + blank, _vc_width); + con->csr_y = _vc_height - 1; + } + + //for(i = 0; i < 0x1000000; i++) ; +} + 1046dd: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 1046e0: 5b pop %ebx + 1046e1: 5e pop %esi + 1046e2: 5f pop %edi + 1046e3: c9 leave + 1046e4: c3 ret + 1046e5: 8d 76 00 lea 0x0(%esi),%esi + 1046e8: 29 d0 sub %edx,%eax + 1046ea: 8d 58 01 lea 0x1(%eax),%ebx + 1046ed: 29 da sub %ebx,%edx + 1046ef: 50 push %eax + 1046f0: a1 30 3a 18 00 mov 0x183a30,%eax + 1046f5: 0f af d0 imul %eax,%edx + 1046f8: d1 e2 shl %edx + 1046fa: 0f af c3 imul %ebx,%eax + 1046fd: 52 push %edx + 1046fe: 8d 04 47 lea (%edi,%eax,2),%eax + 104701: 50 push %eax + 104702: 57 push %edi + 104703: e8 54 09 00 00 call 10505c + 104708: a1 34 3a 18 00 mov 0x183a34,%eax + 10470d: 83 c4 0c add $0xc,%esp + 104710: 29 d8 sub %ebx,%eax + 104712: ff 35 30 3a 18 00 pushl 0x183a30 + 104718: 0f af 05 30 3a 18 00 imul 0x183a30,%eax + 10471f: 56 push %esi + 104720: 8d 04 47 lea (%edi,%eax,2),%eax + 104723: 50 push %eax + 104724: e8 5f 09 00 00 call 105088 + 104729: a1 34 3a 18 00 mov 0x183a34,%eax + 10472e: 48 dec %eax + 10472f: 8b 55 08 mov 0x8(%ebp),%edx + 104732: 89 42 20 mov %eax,0x20(%edx) + 104735: 83 c4 10 add $0x10,%esp + 104738: eb a3 jmp 1046dd + 10473a: 89 f6 mov %esi,%esi + +0010473c : + +/** + * set_attrib() + * + */ +static void set_attrib(console_t *con, unsigned att) +{ + 10473c: 55 push %ebp + 10473d: 89 e5 mov %esp,%ebp + 10473f: 8b 4d 0c mov 0xc(%ebp),%ecx + 104742: 53 push %ebx + static const unsigned ansi_to_vga[] = + { + 0, 4, 2, 6, 1, 5, 3, 7 + }; + + unsigned new_att; + + new_att = con->attrib; + if(att == 0) + 104743: 85 c9 test %ecx,%ecx + 104745: 8b 5d 08 mov 0x8(%ebp),%ebx + 104748: 8b 53 18 mov 0x18(%ebx),%edx + 10474b: 75 0b jne 104758 + new_att &= ~0x08; /* bold off */ + 10474d: 83 e2 f7 and $0xfffffff7,%edx + else if(att == 1) + new_att |= 0x08; /* bold on */ + else if(att >= 30 && att <= 37) + { + att = ansi_to_vga[att - 30]; + new_att = (new_att & ~0x07) | att;/* fg color */ + } + else if(att >= 40 && att <= 47) + { + att = ansi_to_vga[att - 40] << 4; + new_att = (new_att & ~0x70) | att;/* bg color */ + } + con->attrib = new_att; + 104750: 89 53 18 mov %edx,0x18(%ebx) +} + 104753: 8b 1c 24 mov (%esp,1),%ebx + 104756: c9 leave + 104757: c3 ret + 104758: 83 f9 01 cmp $0x1,%ecx + 10475b: 74 33 je 104790 + 10475d: 8d 41 e2 lea 0xffffffe2(%ecx),%eax + 104760: 83 f8 07 cmp $0x7,%eax + 104763: 77 0f ja 104774 + 104765: 83 e2 f8 and $0xfffffff8,%edx + 104768: 0b 14 8d 68 62 10 00 or 0x106268(,%ecx,4),%edx + 10476f: eb df jmp 104750 + 104771: 8d 76 00 lea 0x0(%esi),%esi + 104774: 8d 41 d8 lea 0xffffffd8(%ecx),%eax + 104777: 83 f8 07 cmp $0x7,%eax + 10477a: 77 d4 ja 104750 + 10477c: 8b 04 8d 40 62 10 00 mov 0x106240(,%ecx,4),%eax + 104783: c1 e0 04 shl $0x4,%eax + 104786: 83 e2 8f and $0xffffff8f,%edx + 104789: 09 c2 or %eax,%edx + 10478b: eb c3 jmp 104750 + 10478d: 8d 76 00 lea 0x0(%esi),%esi + 104790: 83 ca 08 or $0x8,%edx + 104793: eb bb jmp 104750 + 104795: 8d 76 00 lea 0x0(%esi),%esi + +00104798 : + +/** + * move_csr() + * + */ +static void move_csr(void) +{ + 104798: 55 push %ebp + 104799: 89 e5 mov %esp,%ebp + 10479b: 53 push %ebx + 10479c: 83 ec 0c sub $0xc,%esp + unsigned temp; + + temp = (_curr_vc->csr_y * _vc_width + _curr_vc->csr_x) + + 10479f: a1 24 3a 18 00 mov 0x183a24,%eax + 1047a4: 8b 1d 30 3a 18 00 mov 0x183a30,%ebx + 1047aa: 0f af 58 20 imul 0x20(%eax),%ebx + 1047ae: 03 58 1c add 0x1c(%eax),%ebx + 1047b1: 8b 40 30 mov 0x30(%eax),%eax + 1047b4: 2b 05 28 3a 18 00 sub 0x183a28,%eax + (_curr_vc->fb_adr - _vga_fb_adr); + outportb(_crtc_io_adr + 0, 14); + 1047ba: 6a 0e push $0xe + 1047bc: d1 f8 sar %eax + 1047be: ff 35 2c 3a 18 00 pushl 0x183a2c + 1047c4: 01 c3 add %eax,%ebx + 1047c6: e8 e9 08 00 00 call 1050b4 + outportb(_crtc_io_adr + 1, temp >> 8); + 1047cb: 59 pop %ecx + 1047cc: 58 pop %eax + 1047cd: 89 d8 mov %ebx,%eax + 1047cf: c1 e8 08 shr $0x8,%eax + 1047d2: 50 push %eax + 1047d3: a1 2c 3a 18 00 mov 0x183a2c,%eax + 1047d8: 40 inc %eax + 1047d9: 50 push %eax + 1047da: e8 d5 08 00 00 call 1050b4 + outportb(_crtc_io_adr + 0, 15); + 1047df: 58 pop %eax + 1047e0: 5a pop %edx + 1047e1: 6a 0f push $0xf + 1047e3: ff 35 2c 3a 18 00 pushl 0x183a2c + 1047e9: e8 c6 08 00 00 call 1050b4 + outportb(_crtc_io_adr + 1, temp); + 1047ee: 5a pop %edx + 1047ef: 59 pop %ecx + 1047f0: a1 2c 3a 18 00 mov 0x183a2c,%eax + 1047f5: 53 push %ebx + 1047f6: 40 inc %eax + 1047f7: 50 push %eax + 1047f8: e8 b7 08 00 00 call 1050b4 +} + 1047fd: 8b 5d fc mov 0xfffffffc(%ebp),%ebx + 104800: c9 leave + 104801: c3 ret + 104802: 89 f6 mov %esi,%esi + +00104804 : + + +/** + * select_vc() + * + */ +void select_vc(unsigned which_vc) +{ + 104804: 55 push %ebp + 104805: 89 e5 mov %esp,%ebp + 104807: 56 push %esi + 104808: 53 push %ebx + 104809: 8b 75 08 mov 0x8(%ebp),%esi + unsigned i; + + if(which_vc >= _num_vcs) + 10480c: 3b 35 20 3a 18 00 cmp 0x183a20,%esi + 104812: 72 08 jb 10481c + return; + _curr_vc = _vc + which_vc; + i = _curr_vc->fb_adr - _vga_fb_adr; + outportb(_crtc_io_adr + 0, 12); + outportb(_crtc_io_adr + 1, i >> 8); + outportb(_crtc_io_adr + 0, 13); + outportb(_crtc_io_adr + 1, i); + + curr_vtty = which_vc; + + move_csr(); +} + 104814: 8d 65 f8 lea 0xfffffff8(%ebp),%esp + 104817: 5b pop %ebx + 104818: 5e pop %esi + 104819: c9 leave + 10481a: c3 ret + 10481b: 90 nop + 10481c: 8d 04 76 lea (%esi,%esi,2),%eax + 10481f: 8d 04 86 lea (%esi,%eax,4),%eax + 104822: 8d 04 85 e0 a2 19 00 lea 0x19a2e0(,%eax,4),%eax + 104829: 8b 58 30 mov 0x30(%eax),%ebx + 10482c: 83 ec 08 sub $0x8,%esp + 10482f: a3 24 3a 18 00 mov %eax,0x183a24 + 104834: 2b 1d 28 3a 18 00 sub 0x183a28,%ebx + 10483a: 6a 0c push $0xc + 10483c: d1 fb sar %ebx + 10483e: ff 35 2c 3a 18 00 pushl 0x183a2c + 104844: e8 6b 08 00 00 call 1050b4 + 104849: 58 pop %eax + 10484a: 89 d8 mov %ebx,%eax + 10484c: 5a pop %edx + 10484d: c1 e8 08 shr $0x8,%eax + 104850: 50 push %eax + 104851: a1 2c 3a 18 00 mov 0x183a2c,%eax + 104856: 40 inc %eax + 104857: 50 push %eax + 104858: e8 57 08 00 00 call 1050b4 + 10485d: 59 pop %ecx + 10485e: 58 pop %eax + 10485f: 6a 0d push $0xd + 104861: ff 35 2c 3a 18 00 pushl 0x183a2c + 104867: e8 48 08 00 00 call 1050b4 + 10486c: 58 pop %eax + 10486d: 5a pop %edx + 10486e: 53 push %ebx + 10486f: a1 2c 3a 18 00 mov 0x183a2c,%eax + 104874: 40 inc %eax + 104875: 50 push %eax + 104876: e8 39 08 00 00 call 1050b4 + 10487b: 89 35 c0 a2 19 00 mov %esi,0x19a2c0 + 104881: 83 c4 10 add $0x10,%esp + 104884: 8d 65 f8 lea 0xfffffff8(%ebp),%esp + 104887: 5b pop %ebx + 104888: 5e pop %esi + 104889: c9 leave + 10488a: e9 09 ff ff ff jmp 104798 + 10488f: 90 nop + +00104890 : + +/** + * putch_help() + * + */ +void putch_help(console_t *con, unsigned c) +{ + 104890: 55 push %ebp + 104891: 89 e5 mov %esp,%ebp + 104893: 57 push %edi + 104894: 56 push %esi + 104895: 53 push %ebx + 104896: 83 ec 0c sub $0xc,%esp + 104899: 8b 5d 08 mov 0x8(%ebp),%ebx + unsigned short *fb_adr; + unsigned att; + + att = (unsigned)con->attrib << 8; + 10489c: 8b 73 18 mov 0x18(%ebx),%esi + fb_adr = con->fb_adr; + + /** + * state machine to handle escape sequences + * + * ESC + */ + if(con->esc == 1) + 10489f: 8b 43 14 mov 0x14(%ebx),%eax + 1048a2: c1 e6 08 shl $0x8,%esi + 1048a5: 83 f8 01 cmp $0x1,%eax + 1048a8: 8b 4d 0c mov 0xc(%ebp),%ecx + 1048ab: 8b 7b 30 mov 0x30(%ebx),%edi + 1048ae: 0f 84 30 02 00 00 je 104ae4 + { + if(c == '[') + { + con->esc++; + con->esc1 = 0; + return; + } + /* else fall-through: zero esc and print c */ + } + + /** + * ESC[ + */ + else if(con->esc == 2) + 1048b4: 83 f8 02 cmp $0x2,%eax + 1048b7: 0f 84 a3 01 00 00 je 104a60 + { + if(isdigit(c)) + { + con->esc1 = con->esc1 * 10 + c - '0'; + return; + } + else if(c == ';') + { + con->esc++; + con->esc2 = 0; + return; + } + + /** + * ESC[2J (clear screen) + */ + else if(c == 'J') + { + if(con->esc1 == 2) + { + memsetw(fb_adr, ' ' | att, + _vc_height * _vc_width); + con->csr_x = con->csr_y = 0; + } + } + + /** + * ESC[num1m (set attribute num1) + */ + else if(c == 'm') + set_attrib(con, con->esc1); + con->esc = 0; /* anything else with one numeric arg */ + return; + } + + /** + * ESC[num1 + */ + else if(con->esc == 3) + 1048bd: 83 f8 03 cmp $0x3,%eax + 1048c0: 0f 84 22 01 00 00 je 1049e8 + { + if(isdigit(c)) + { + con->esc2 = con->esc2 * 10 + c - '0'; + return; + } + else if(c == ';') + { + con->esc++; /* ESC[num1;num2; */ + con->esc3 = 0; + return; + } + + /** + * ESC[num1;num2H (move cursor to num1,num2) + */ + else if(c == 'H') + { + if(con->esc2 < _vc_width) + con->csr_x = con->esc2; + if(con->esc1 < _vc_height) + con->csr_y = con->esc1; + } + + /** + * ESC[num1;num2m (set attributes num1,num2) + */ + else if(c == 'm') + { + set_attrib(con, con->esc1); + set_attrib(con, con->esc2); + } + con->esc = 0; + return; + } + /** + * ESC[num1;num2;num3 + */ + else if(con->esc == 4) + 1048c6: 83 f8 04 cmp $0x4,%eax + 1048c9: 0f 84 c9 00 00 00 je 104998 + { + if(isdigit(c)) + { + con->esc3 = con->esc3 * 10 + c - '0'; + return; + } + /** + * ESC[num1;num2;num3m (set attributes num1,num2,num3) + */ + else if(c == 'm') + { + set_attrib(con, con->esc1); + set_attrib(con, con->esc2); + set_attrib(con, con->esc3); + } + con->esc = 0; + return; + } + con->esc = 0; + + /** + * escape character + */ + if(c == 0x1B) + 1048cf: 83 f9 1b cmp $0x1b,%ecx + 1048d2: c7 43 14 00 00 00 00 movl $0x0,0x14(%ebx) + 1048d9: 0f 84 ad 00 00 00 je 10498c + { + con->esc = 1; + return; + } + /** + * backspace + */ + if(c == 0x08) + 1048df: 83 f9 08 cmp $0x8,%ecx + 1048e2: 0f 84 9a 00 00 00 je 104982 + { + if(con->csr_x != 0) + con->csr_x--; + } + /** + * tab + */ + else if(c == 0x09) + 1048e8: 83 f9 09 cmp $0x9,%ecx + 1048eb: 0f 84 83 00 00 00 je 104974 + con->csr_x = (con->csr_x + 8) & ~(8 - 1); + /** + * carriage return + */ + else if(c == '\r') /* 0x0D */ + 1048f1: 83 f9 0d cmp $0xd,%ecx + 1048f4: 74 75 je 10496b + con->csr_x = 0; + /** + * line feed + */ +/* else if(c == '\n') *//* 0x0A */ +/* con->csr_y++;*/ + /** + * CR/LF + */ + else if(c == '\n') /* ### - 0x0A again */ + 1048f6: 83 f9 0a cmp $0xa,%ecx + 1048f9: 74 62 je 10495d + { + con->csr_x = 0; + con->csr_y++; + } + /** + * printable ASCII + */ + else if(c >= ' ') + 1048fb: 83 f9 1f cmp $0x1f,%ecx + 1048fe: 76 58 jbe 104958 + { + unsigned short *where; + + where = fb_adr + (con->csr_y * _vc_width + con->csr_x); + 104900: a1 30 3a 18 00 mov 0x183a30,%eax + 104905: 8b 53 1c mov 0x1c(%ebx),%edx + 104908: 0f af 43 20 imul 0x20(%ebx),%eax + 10490c: 01 d0 add %edx,%eax + *where = (c | att); + 10490e: 09 f1 or %esi,%ecx + con->csr_x++; + 104910: 42 inc %edx + 104911: 66 89 0c 47 mov %cx,(%edi,%eax,2) + 104915: 89 d0 mov %edx,%eax + 104917: 89 53 1c mov %edx,0x1c(%ebx) + 10491a: 89 f6 mov %esi,%esi + } + if(con->csr_x >= _vc_width) + 10491c: 3b 05 30 3a 18 00 cmp 0x183a30,%eax + 104922: 72 0a jb 10492e + { + con->csr_x = 0; + 104924: c7 43 1c 00 00 00 00 movl $0x0,0x1c(%ebx) + con->csr_y++; + 10492b: ff 43 20 incl 0x20(%ebx) + } + scroll(con); + 10492e: 83 ec 0c sub $0xc,%esp + 104931: 53 push %ebx + 104932: e8 81 fd ff ff call 1046b8 + + /** + * move cursor only if the VC we're writing is the current VC + */ + if(_curr_vc == con) + 104937: 83 c4 10 add $0x10,%esp + 10493a: 39 1d 24 3a 18 00 cmp %ebx,0x183a24 + 104940: 74 0a je 10494c + 104942: 89 f6 mov %esi,%esi + move_csr(); +} + 104944: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 104947: 5b pop %ebx + 104948: 5e pop %esi + 104949: 5f pop %edi + 10494a: c9 leave + 10494b: c3 ret + 10494c: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 10494f: 5b pop %ebx + 104950: 5e pop %esi + 104951: 5f pop %edi + 104952: c9 leave + 104953: e9 40 fe ff ff jmp 104798 + 104958: 8b 43 1c mov 0x1c(%ebx),%eax + 10495b: eb bf jmp 10491c + 10495d: c7 43 1c 00 00 00 00 movl $0x0,0x1c(%ebx) + 104964: ff 43 20 incl 0x20(%ebx) + 104967: 31 c0 xor %eax,%eax + 104969: eb b1 jmp 10491c + 10496b: c7 43 1c 00 00 00 00 movl $0x0,0x1c(%ebx) + 104972: eb f3 jmp 104967 + 104974: 8b 43 1c mov 0x1c(%ebx),%eax + 104977: 83 c0 08 add $0x8,%eax + 10497a: 83 e0 f8 and $0xfffffff8,%eax + 10497d: 89 43 1c mov %eax,0x1c(%ebx) + 104980: eb 9a jmp 10491c + 104982: 8b 43 1c mov 0x1c(%ebx),%eax + 104985: 85 c0 test %eax,%eax + 104987: 74 93 je 10491c + 104989: 48 dec %eax + 10498a: eb f1 jmp 10497d + 10498c: c7 43 14 01 00 00 00 movl $0x1,0x14(%ebx) + 104993: eb af jmp 104944 + 104995: 8d 76 00 lea 0x0(%esi),%esi + 104998: f6 81 41 78 10 00 04 testb $0x4,0x107841(%ecx) + 10499f: 74 0f je 1049b0 + 1049a1: 8b 43 2c mov 0x2c(%ebx),%eax + 1049a4: 8d 04 80 lea (%eax,%eax,4),%eax + 1049a7: 8d 44 41 d0 lea 0xffffffd0(%ecx,%eax,2),%eax + 1049ab: 89 43 2c mov %eax,0x2c(%ebx) + 1049ae: eb 94 jmp 104944 + 1049b0: 83 f9 6d cmp $0x6d,%ecx + 1049b3: 74 0c je 1049c1 + 1049b5: 8d 76 00 lea 0x0(%esi),%esi + 1049b8: c7 43 14 00 00 00 00 movl $0x0,0x14(%ebx) + 1049bf: eb 83 jmp 104944 + 1049c1: 83 ec 08 sub $0x8,%esp + 1049c4: ff 73 24 pushl 0x24(%ebx) + 1049c7: 53 push %ebx + 1049c8: e8 6f fd ff ff call 10473c + 1049cd: 5f pop %edi + 1049ce: 58 pop %eax + 1049cf: ff 73 28 pushl 0x28(%ebx) + 1049d2: 53 push %ebx + 1049d3: e8 64 fd ff ff call 10473c + 1049d8: 59 pop %ecx + 1049d9: 5e pop %esi + 1049da: ff 73 2c pushl 0x2c(%ebx) + 1049dd: 53 push %ebx + 1049de: e8 59 fd ff ff call 10473c + 1049e3: 83 c4 10 add $0x10,%esp + 1049e6: eb d0 jmp 1049b8 + 1049e8: f6 81 41 78 10 00 04 testb $0x4,0x107841(%ecx) + 1049ef: 74 12 je 104a03 + 1049f1: 8b 43 28 mov 0x28(%ebx),%eax + 1049f4: 8d 04 80 lea (%eax,%eax,4),%eax + 1049f7: 8d 44 41 d0 lea 0xffffffd0(%ecx,%eax,2),%eax + 1049fb: 89 43 28 mov %eax,0x28(%ebx) + 1049fe: e9 41 ff ff ff jmp 104944 + 104a03: 83 f9 3b cmp $0x3b,%ecx + 104a06: 74 42 je 104a4a + 104a08: 83 f9 48 cmp $0x48,%ecx + 104a0b: 74 18 je 104a25 + 104a0d: 83 f9 6d cmp $0x6d,%ecx + 104a10: 75 a6 jne 1049b8 + 104a12: 83 ec 08 sub $0x8,%esp + 104a15: ff 73 24 pushl 0x24(%ebx) + 104a18: 53 push %ebx + 104a19: e8 1e fd ff ff call 10473c + 104a1e: 58 pop %eax + 104a1f: 5a pop %edx + 104a20: ff 73 28 pushl 0x28(%ebx) + 104a23: eb b8 jmp 1049dd + 104a25: 8b 43 28 mov 0x28(%ebx),%eax + 104a28: 3b 05 30 3a 18 00 cmp 0x183a30,%eax + 104a2e: 73 03 jae 104a33 + 104a30: 89 43 1c mov %eax,0x1c(%ebx) + 104a33: 8b 43 24 mov 0x24(%ebx),%eax + 104a36: 3b 05 34 3a 18 00 cmp 0x183a34,%eax + 104a3c: 0f 83 76 ff ff ff jae 1049b8 + 104a42: 89 43 20 mov %eax,0x20(%ebx) + 104a45: e9 6e ff ff ff jmp 1049b8 + 104a4a: c7 43 14 04 00 00 00 movl $0x4,0x14(%ebx) + 104a51: c7 43 2c 00 00 00 00 movl $0x0,0x2c(%ebx) + 104a58: e9 e7 fe ff ff jmp 104944 + 104a5d: 8d 76 00 lea 0x0(%esi),%esi + 104a60: f6 81 41 78 10 00 04 testb $0x4,0x107841(%ecx) + 104a67: 74 13 je 104a7c + 104a69: 8b 43 24 mov 0x24(%ebx),%eax + 104a6c: 8d 04 80 lea (%eax,%eax,4),%eax + 104a6f: 8d 44 41 d0 lea 0xffffffd0(%ecx,%eax,2),%eax + 104a73: 89 43 24 mov %eax,0x24(%ebx) + 104a76: e9 c9 fe ff ff jmp 104944 + 104a7b: 90 nop + 104a7c: 83 f9 3b cmp $0x3b,%ecx + 104a7f: 74 4e je 104acf + 104a81: 83 f9 4a cmp $0x4a,%ecx + 104a84: 74 14 je 104a9a + 104a86: 83 f9 6d cmp $0x6d,%ecx + 104a89: 0f 85 29 ff ff ff jne 1049b8 + 104a8f: 83 ec 08 sub $0x8,%esp + 104a92: ff 73 24 pushl 0x24(%ebx) + 104a95: e9 43 ff ff ff jmp 1049dd + 104a9a: 83 7b 24 02 cmpl $0x2,0x24(%ebx) + 104a9e: 0f 85 14 ff ff ff jne 1049b8 + 104aa4: 51 push %ecx + 104aa5: a1 30 3a 18 00 mov 0x183a30,%eax + 104aaa: 0f af 05 34 3a 18 00 imul 0x183a34,%eax + 104ab1: 50 push %eax + 104ab2: 83 ce 20 or $0x20,%esi + 104ab5: 56 push %esi + 104ab6: 57 push %edi + 104ab7: e8 cc 05 00 00 call 105088 + 104abc: c7 43 20 00 00 00 00 movl $0x0,0x20(%ebx) + 104ac3: c7 43 1c 00 00 00 00 movl $0x0,0x1c(%ebx) + 104aca: e9 14 ff ff ff jmp 1049e3 + 104acf: c7 43 14 03 00 00 00 movl $0x3,0x14(%ebx) + 104ad6: c7 43 28 00 00 00 00 movl $0x0,0x28(%ebx) + 104add: e9 62 fe ff ff jmp 104944 + 104ae2: 89 f6 mov %esi,%esi + 104ae4: 83 f9 5b cmp $0x5b,%ecx + 104ae7: 0f 85 e2 fd ff ff jne 1048cf + 104aed: c7 43 14 02 00 00 00 movl $0x2,0x14(%ebx) + 104af4: c7 43 24 00 00 00 00 movl $0x0,0x24(%ebx) + 104afb: e9 44 fe ff ff jmp 104944 + +00104b00 : + +/** + * putch() + * + */ +void putch(unsigned c) +{ + 104b00: 55 push %ebp + 104b01: 89 e5 mov %esp,%ebp + 104b03: 83 ec 10 sub $0x10,%esp +/* all kernel messages to VC #0 */ +// putch_help(_vc + 0, c); +/* all kernel messages to current VC */ + putch_help(_curr_vc, c); + 104b06: ff 75 08 pushl 0x8(%ebp) + 104b09: ff 35 24 3a 18 00 pushl 0x183a24 + 104b0f: e8 7c fd ff ff call 104890 +} + 104b14: c9 leave + 104b15: c3 ret + 104b16: 89 f6 mov %esi,%esi + +00104b18 : + +/** + * init_video() + * + */ +void init_video(void) +{ + 104b18: 55 push %ebp + 104b19: 89 e5 mov %esp,%ebp + 104b1b: 56 push %esi + 104b1c: 53 push %ebx + unsigned i; + + /** + * check for monochrome or color VGA emulation + */ + if((inportb(VGA_MISC_READ) & 0x01) != 0) + 104b1d: 83 ec 0c sub $0xc,%esp + 104b20: 68 cc 03 00 00 push $0x3cc + 104b25: e8 ea 04 00 00 call 105014 + 104b2a: 83 c4 10 add $0x10,%esp + 104b2d: a8 01 test $0x1,%al + 104b2f: 0f 84 78 01 00 00 je 104cad + { + _vga_fb_adr = (unsigned short *)0xB8000L; + 104b35: c7 05 28 3a 18 00 00 movl $0xb8000,0x183a28 + 104b3c: 80 0b 00 + _crtc_io_adr = 0x3D4; + 104b3f: c7 05 2c 3a 18 00 d4 movl $0x3d4,0x183a2c + 104b46: 03 00 00 + } + else + { + _vga_fb_adr = (unsigned short *)0xB0000L; + _crtc_io_adr = 0x3B4; + } + + /** + * read current screen size from BIOS data segment (addresses 400-4FF) + */ + _vc_width = *(unsigned short *)0x44A; + _vc_height = *(unsigned char *)0x484 + 1; + 104b49: 0f b6 05 84 04 00 00 movzbl 0x484,%eax + 104b50: 40 inc %eax + 104b51: 0f b7 15 4a 04 00 00 movzwl 0x44a,%edx + 104b58: 89 15 30 3a 18 00 mov %edx,0x183a30 + + /** + * figure out how many VCs we can have with 32K of display memory. + * Use INTEGER division to round down. + */ + _num_vcs = 32768L / (_vc_width * _vc_height * 2); + 104b5e: 0f af d0 imul %eax,%edx + 104b61: d1 e2 shl %edx + 104b63: 89 d1 mov %edx,%ecx + 104b65: a3 34 3a 18 00 mov %eax,0x183a34 + 104b6a: 31 d2 xor %edx,%edx + 104b6c: b8 00 80 00 00 mov $0x8000,%eax + 104b71: f7 f1 div %ecx + if(_num_vcs > MAX_VC) + 104b73: 83 f8 0c cmp $0xc,%eax + 104b76: a3 20 3a 18 00 mov %eax,0x183a20 + 104b7b: 76 0a jbe 104b87 + _num_vcs = MAX_VC; + 104b7d: c7 05 20 3a 18 00 0c movl $0xc,0x183a20 + 104b84: 00 00 00 + + /** + * init VCs, with a different foreground color for each + */ + for(i = 0; i < _num_vcs; i++) + 104b87: 31 f6 xor %esi,%esi + 104b89: 3b 35 20 3a 18 00 cmp 0x183a20,%esi + 104b8f: 73 53 jae 104be4 + 104b91: bb e0 a2 19 00 mov $0x19a2e0,%ebx + 104b96: 89 f6 mov %esi,%esi + { + _curr_vc = _vc + i; + //_curr_vc->attrib = i + 1; + + /* terminal foreground color */ + _curr_vc->attrib = 7; + _curr_vc->fb_adr = _vga_fb_adr + + 104b98: a1 34 3a 18 00 mov 0x183a34,%eax + 104b9d: 0f af 05 30 3a 18 00 imul 0x183a30,%eax + 104ba4: 8b 15 28 3a 18 00 mov 0x183a28,%edx + 104baa: 0f af c6 imul %esi,%eax + _vc_width * _vc_height * i; + + /** + * ESC[2J clears the screen + */ + //kprintf("\x1B[2J this is VC#%u (of 0-%u)\n", + // i, _num_vcs - 1); + printf("\x1B[2J"); + 104bad: 83 ec 0c sub $0xc,%esp + 104bb0: 8d 04 42 lea (%edx,%eax,2),%eax + 104bb3: c7 43 18 07 00 00 00 movl $0x7,0x18(%ebx) + 104bba: 89 43 30 mov %eax,0x30(%ebx) + 104bbd: 68 00 63 10 00 push $0x106300 + 104bc2: 89 1d 24 3a 18 00 mov %ebx,0x183a24 + 104bc8: e8 07 05 00 00 call 1050d4 + + if(i != 0) + 104bcd: 83 c4 10 add $0x10,%esp + 104bd0: 85 f6 test %esi,%esi + 104bd2: 0f 85 c0 00 00 00 jne 104c98 + 104bd8: 46 inc %esi + 104bd9: 83 c3 34 add $0x34,%ebx + 104bdc: 3b 35 20 3a 18 00 cmp 0x183a20,%esi + 104be2: 72 b4 jb 104b98 + printf("$ "); + } + select_vc(0); + 104be4: 83 ec 0c sub $0xc,%esp + 104be7: 6a 00 push $0x0 + 104be9: e8 16 fc ff ff call 104804 + curr_vtty = 0; + + _curr_vc->attrib = 8; + 104bee: a1 24 3a 18 00 mov 0x183a24,%eax + 104bf3: c7 05 c0 a2 19 00 00 movl $0x0,0x19a2c0 + 104bfa: 00 00 00 + 104bfd: c7 40 18 08 00 00 00 movl $0x8,0x18(%eax) + printf("[ "); + 104c04: c7 04 24 b6 51 10 00 movl $0x1051b6,(%esp,1) + 104c0b: e8 c4 04 00 00 call 1050d4 + _curr_vc->attrib = 15; + 104c10: a1 24 3a 18 00 mov 0x183a24,%eax + 104c15: c7 40 18 0f 00 00 00 movl $0xf,0x18(%eax) + printf("init: video %5s emulation, %2ux%2u, framebuffer at 0x%1X ", + 104c1c: 5b pop %ebx + 104c1d: ff 35 28 3a 18 00 pushl 0x183a28 + 104c23: ff 35 34 3a 18 00 pushl 0x183a34 + 104c29: 81 3d 2c 3a 18 00 d4 cmpl $0x3d4,0x183a2c + 104c30: 03 00 00 + 104c33: ff 35 30 3a 18 00 pushl 0x183a30 + 104c39: 74 54 je 104c8f + 104c3b: b8 05 63 10 00 mov $0x106305,%eax + 104c40: 50 push %eax + 104c41: 68 40 63 10 00 push $0x106340 + 104c46: e8 89 04 00 00 call 1050d4 + (_crtc_io_adr == 0x3D4) ? "color" : "mono", + _vc_width, _vc_height, _vga_fb_adr); + _curr_vc->attrib = 8; + printf("]................"); + 104c4b: 83 c4 14 add $0x14,%esp + 104c4e: a1 24 3a 18 00 mov 0x183a24,%eax + 104c53: c7 40 18 08 00 00 00 movl $0x8,0x18(%eax) + 104c5a: 68 0a 63 10 00 push $0x10630a + 104c5f: e8 70 04 00 00 call 1050d4 + _curr_vc->attrib = 2; + 104c64: a1 24 3a 18 00 mov 0x183a24,%eax + 104c69: c7 40 18 02 00 00 00 movl $0x2,0x18(%eax) + printf("Ok"); + 104c70: c7 04 24 d9 54 10 00 movl $0x1054d9,(%esp,1) + 104c77: e8 58 04 00 00 call 1050d4 + _curr_vc->attrib = 7; + 104c7c: a1 24 3a 18 00 mov 0x183a24,%eax + 104c81: c7 40 18 07 00 00 00 movl $0x7,0x18(%eax) +} + 104c88: 8d 65 f8 lea 0xfffffff8(%ebp),%esp + 104c8b: 5b pop %ebx + 104c8c: 5e pop %esi + 104c8d: c9 leave + 104c8e: c3 ret + 104c8f: b8 1c 63 10 00 mov $0x10631c,%eax + 104c94: eb aa jmp 104c40 + 104c96: 89 f6 mov %esi,%esi + 104c98: 83 ec 0c sub $0xc,%esp + 104c9b: 68 d6 54 10 00 push $0x1054d6 + 104ca0: e8 2f 04 00 00 call 1050d4 + 104ca5: 83 c4 10 add $0x10,%esp + 104ca8: e9 2b ff ff ff jmp 104bd8 + 104cad: c7 05 28 3a 18 00 00 movl $0xb0000,0x183a28 + 104cb4: 00 0b 00 + 104cb7: c7 05 2c 3a 18 00 b4 movl $0x3b4,0x183a2c + 104cbe: 03 00 00 + 104cc1: e9 83 fe ff ff jmp 104b49 + ... + +00104cc8 : +/***************************************************************************** +*****************************************************************************/ +unsigned disable(void) +{ + 104cc8: 55 push %ebp + 104cc9: 89 e5 mov %esp,%ebp + unsigned ret_val; + + __asm__ __volatile__("pushfl\n" + 104ccb: 9c pushf + 104ccc: 58 pop %eax + 104ccd: fa cli + "popl %0\n" + "cli" + : "=a"(ret_val) + :); + return ret_val; +} + 104cce: c9 leave + 104ccf: c3 ret + +00104cd0 : +2^32-1 in base 8 has 11 digits (add 5 for trailing NUL and for slop) */ +#define PR_BUFLEN 16 + +int do_printf(const char *fmt, va_list args, fnptr_t fn, void *ptr) +{ + 104cd0: 55 push %ebp + 104cd1: 89 e5 mov %esp,%ebp + 104cd3: 57 push %edi + 104cd4: 56 push %esi + 104cd5: 53 push %ebx + 104cd6: 83 ec 2c sub $0x2c,%esp + 104cd9: 8b 75 08 mov 0x8(%ebp),%esi + unsigned state, flags, radix, actual_wd, count, given_wd; + unsigned char *where, buf[PR_BUFLEN]; + long num; + + state = flags = count = given_wd = 0; + 104cdc: c7 45 cc 00 00 00 00 movl $0x0,0xffffffcc(%ebp) + 104ce3: c7 45 d0 00 00 00 00 movl $0x0,0xffffffd0(%ebp) + 104cea: c7 45 d4 00 00 00 00 movl $0x0,0xffffffd4(%ebp) +/* begin scanning format specifier list */ + for(; *fmt; fmt++) + 104cf1: 8a 0e mov (%esi),%cl + 104cf3: 31 db xor %ebx,%ebx + 104cf5: 84 c9 test %cl,%cl + 104cf7: 74 38 je 104d31 + 104cf9: 8d 76 00 lea 0x0(%esi),%esi + { + switch(state) + 104cfc: 83 fb 04 cmp $0x4,%ebx + 104cff: 0f 87 d7 01 00 00 ja 104edc + 104d05: ff 24 9d 7c 63 10 00 jmp *0x10637c(,%ebx,4) + { +/* STATE 0: AWAITING % */ + case 0: + if(*fmt != '%') /* not %... */ + 104d0c: 80 f9 25 cmp $0x25,%cl + 104d0f: 74 2b je 104d3c + { + fn(*fmt, &ptr); /* ...just echo it */ + 104d11: 83 ec 08 sub $0x8,%esp + 104d14: 8d 45 14 lea 0x14(%ebp),%eax + 104d17: 50 push %eax + 104d18: 0f be c1 movsbl %cl,%eax + 104d1b: 50 push %eax + 104d1c: ff 55 10 call *0x10(%ebp) + count++; + 104d1f: ff 45 d0 incl 0xffffffd0(%ebp) + break; + } +/* found %, get next char and advance state to check if next char is a flag */ + state++; + fmt++; + /* FALL THROUGH */ +/* STATE 1: AWAITING FLAGS (%-0) */ + case 1: + if(*fmt == '%') /* %% */ + { + fn(*fmt, &ptr); + count++; + state = flags = given_wd = 0; + break; + 104d22: 83 c4 10 add $0x10,%esp + 104d25: 8d 76 00 lea 0x0(%esi),%esi + 104d28: 46 inc %esi + 104d29: 8a 06 mov (%esi),%al + 104d2b: 84 c0 test %al,%al + 104d2d: 88 c1 mov %al,%cl + 104d2f: 75 cb jne 104cfc + } + if(*fmt == '-') + { + if(flags & PR_LJ)/* %-- is illegal */ + state = flags = given_wd = 0; + else + flags |= PR_LJ; + break; + } +/* not a flag char: advance state to check if it's field width */ + state++; +/* check now for '%0...' */ + if(*fmt == '0') + { + flags |= PR_LZ; + fmt++; + } + /* FALL THROUGH */ +/* STATE 2: AWAITING (NUMERIC) FIELD WIDTH */ + case 2: + if(*fmt >= '0' && *fmt <= '9') + { + given_wd = 10 * given_wd + + (*fmt - '0'); + break; + } +/* not field width: advance state to check if it's a modifier */ + state++; + /* FALL THROUGH */ +/* STATE 3: AWAITING MODIFIER CHARS (FNlh) */ + case 3: + if(*fmt == 'F') + { + flags |= PR_FP; + break; + } + if(*fmt == 'N') + break; + if(*fmt == 'l') + { + flags |= PR_32; + break; + } + if(*fmt == 'h') + { + flags |= PR_16; + break; + } +/* not modifier: advance state to check if it's a conversion char */ + state++; + /* FALL THROUGH */ +/* STATE 4: AWAITING CONVERSION CHARS (Xxpndiuocs) */ + case 4: + where = buf + PR_BUFLEN - 1; + *where = '\0'; + switch(*fmt) + { + case 'X': + flags |= PR_CA; + /* FALL THROUGH */ +/* xxx - far pointers (%Fp, %Fn) not yet supported */ + case 'x': + case 'p': + case 'n': + radix = 16; + goto DO_NUM; + case 'd': + case 'i': + flags |= PR_SG; + /* FALL THROUGH */ + case 'u': + radix = 10; + goto DO_NUM; + case 'o': + radix = 8; +/* load the value to be printed. l=long=32 bits: */ +DO_NUM: if(flags & PR_32) + num = va_arg(args, unsigned long); +/* h=short=16 bits (signed or unsigned) */ + else if(flags & PR_16) + { + if(flags & PR_SG) + num = va_arg(args, short); + else + num = va_arg(args, unsigned short); + } +/* no h nor l: sizeof(int) bits (signed or unsigned) */ + else + { + if(flags & PR_SG) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + } +/* take care of sign */ + if(flags & PR_SG) + { + if(num < 0) + { + flags |= PR_WS; + num = -num; + } + } +/* convert binary to octal/decimal/hex ASCII +OK, I found my mistake. The math here is _always_ unsigned */ + do + { + unsigned long temp; + + temp = (unsigned long)num % radix; + where--; + if(temp < 10) + *where = temp + '0'; + else if(flags & PR_CA) + *where = temp - 10 + 'A'; + else + *where = temp - 10 + 'a'; + num = (unsigned long)num / radix; + } + while(num != 0); + goto EMIT; + case 'c': +/* disallow pad-left-with-zeroes for %c */ + flags &= ~PR_LZ; + where--; + *where = (unsigned char)va_arg(args, + unsigned char); + actual_wd = 1; + goto EMIT2; + case 's': +/* disallow pad-left-with-zeroes for %s */ + flags &= ~PR_LZ; + where = va_arg(args, unsigned char *); +EMIT: + actual_wd = strlen(where); + if(flags & PR_WS) + actual_wd++; +/* if we pad left with ZEROES, do the sign now */ + if((flags & (PR_WS | PR_LZ)) == + (PR_WS | PR_LZ)) + { + fn('-', &ptr); + count++; + } +/* pad on left with spaces or zeroes (for right justify) */ +EMIT2: if((flags & PR_LJ) == 0) + { + while(given_wd > actual_wd) + { + fn(flags & PR_LZ ? '0' : + ' ', &ptr); + count++; + given_wd--; + } + } +/* if we pad left with SPACES, do the sign now */ + if((flags & (PR_WS | PR_LZ)) == PR_WS) + { + fn('-', &ptr); + count++; + } +/* emit string/char/converted number */ + while(*where != '\0') + { + fn(*where++, &ptr); + count++; + } +/* pad on right with spaces (for left justify) */ + if(given_wd < actual_wd) + given_wd = 0; + else given_wd -= actual_wd; + for(; given_wd; given_wd--) + { + fn(' ', &ptr); + count++; + } + break; + default: + break; + } + default: + state = flags = given_wd = 0; + break; + } + } + return count; +} + 104d31: 8b 45 d0 mov 0xffffffd0(%ebp),%eax + 104d34: 8d 65 f4 lea 0xfffffff4(%ebp),%esp + 104d37: 5b pop %ebx + 104d38: 5e pop %esi + 104d39: 5f pop %edi + 104d3a: c9 leave + 104d3b: c3 ret + 104d3c: 46 inc %esi + 104d3d: 43 inc %ebx + 104d3e: 8a 0e mov (%esi),%cl + 104d40: 80 f9 25 cmp $0x25,%cl + 104d43: 0f 84 9d 02 00 00 je 104fe6 + 104d49: 80 f9 2d cmp $0x2d,%cl + 104d4c: 0f 84 81 02 00 00 je 104fd3 + 104d52: 43 inc %ebx + 104d53: 80 f9 30 cmp $0x30,%cl + 104d56: 0f 84 6b 02 00 00 je 104fc7 + 104d5c: 8d 41 d0 lea 0xffffffd0(%ecx),%eax + 104d5f: 3c 09 cmp $0x9,%al + 104d61: 77 12 ja 104d75 + 104d63: 8b 45 cc mov 0xffffffcc(%ebp),%eax + 104d66: 8d 14 80 lea (%eax,%eax,4),%edx + 104d69: 0f be c1 movsbl %cl,%eax + 104d6c: 8d 54 50 d0 lea 0xffffffd0(%eax,%edx,2),%edx + 104d70: 89 55 cc mov %edx,0xffffffcc(%ebp) + 104d73: eb b3 jmp 104d28 + 104d75: 43 inc %ebx + 104d76: 80 f9 46 cmp $0x46,%cl + 104d79: 0f 84 3c 02 00 00 je 104fbb + 104d7f: 80 f9 4e cmp $0x4e,%cl + 104d82: 74 a4 je 104d28 + 104d84: 80 f9 6c cmp $0x6c,%cl + 104d87: 0f 84 25 02 00 00 je 104fb2 + 104d8d: 80 f9 68 cmp $0x68,%cl + 104d90: 0f 84 13 02 00 00 je 104fa9 + 104d96: 89 f6 mov %esi,%esi + 104d98: 0f be c1 movsbl %cl,%eax + 104d9b: 83 e8 58 sub $0x58,%eax + 104d9e: 83 f8 20 cmp $0x20,%eax + 104da1: 8d 7d e7 lea 0xffffffe7(%ebp),%edi + 104da4: c6 45 e7 00 movb $0x0,0xffffffe7(%ebp) + 104da8: 0f 87 2e 01 00 00 ja 104edc + 104dae: ff 24 85 90 63 10 00 jmp *0x106390(,%eax,4) + 104db5: 83 4d d4 02 orl $0x2,0xffffffd4(%ebp) + 104db9: bb 10 00 00 00 mov $0x10,%ebx + 104dbe: f6 45 d4 08 testb $0x8,0xffffffd4(%ebp) + 104dc2: 0f 85 8c 01 00 00 jne 104f54 + 104dc8: f6 45 d4 10 testb $0x10,0xffffffd4(%ebp) + 104dcc: 0f 84 6d 01 00 00 je 104f3f + 104dd2: f6 45 d4 04 testb $0x4,0xffffffd4(%ebp) + 104dd6: 0f 84 53 01 00 00 je 104f2f + 104ddc: 83 45 0c 04 addl $0x4,0xc(%ebp) + 104de0: 8b 45 0c mov 0xc(%ebp),%eax + 104de3: 0f bf 48 fc movswl 0xfffffffc(%eax),%ecx + 104de7: f6 45 d4 04 testb $0x4,0xffffffd4(%ebp) + 104deb: 74 08 je 104df5 + 104ded: 85 c9 test %ecx,%ecx + 104def: 0f 88 2f 01 00 00 js 104f24 + 104df5: 8b 45 d4 mov 0xffffffd4(%ebp),%eax + 104df8: 83 e0 02 and $0x2,%eax + 104dfb: 89 45 c8 mov %eax,0xffffffc8(%ebp) + 104dfe: 89 f6 mov %esi,%esi + 104e00: 31 d2 xor %edx,%edx + 104e02: 89 c8 mov %ecx,%eax + 104e04: f7 f3 div %ebx + 104e06: 4f dec %edi + 104e07: 83 fa 09 cmp $0x9,%edx + 104e0a: 8d 42 30 lea 0x30(%edx),%eax + 104e0d: 76 11 jbe 104e20 + 104e0f: 8b 45 c8 mov 0xffffffc8(%ebp),%eax + 104e12: 85 c0 test %eax,%eax + 104e14: 0f 84 02 01 00 00 je 104f1c + 104e1a: 8d 42 37 lea 0x37(%edx),%eax + 104e1d: 8d 76 00 lea 0x0(%esi),%esi + 104e20: 31 d2 xor %edx,%edx + 104e22: 88 07 mov %al,(%edi) + 104e24: 89 c8 mov %ecx,%eax + 104e26: f7 f3 div %ebx + 104e28: 85 c0 test %eax,%eax + 104e2a: 89 c1 mov %eax,%ecx + 104e2c: 75 d2 jne 104e00 + 104e2e: 83 ec 0c sub $0xc,%esp + 104e31: 57 push %edi + 104e32: e8 21 03 00 00 call 105158 + 104e37: 83 c4 10 add $0x10,%esp + 104e3a: f6 45 d4 20 testb $0x20,0xffffffd4(%ebp) + 104e3e: 89 c3 mov %eax,%ebx + 104e40: 74 01 je 104e43 + 104e42: 43 inc %ebx + 104e43: 8b 45 d4 mov 0xffffffd4(%ebp),%eax + 104e46: 83 e0 60 and $0x60,%eax + 104e49: 83 f8 60 cmp $0x60,%eax + 104e4c: 0f 84 b3 00 00 00 je 104f05 + 104e52: f6 45 d4 01 testb $0x1,0xffffffd4(%ebp) + 104e56: 75 31 jne 104e89 + 104e58: 39 5d cc cmp %ebx,0xffffffcc(%ebp) + 104e5b: 76 2c jbe 104e89 + 104e5d: 8d 76 00 lea 0x0(%esi),%esi + 104e60: 83 ec 08 sub $0x8,%esp + 104e63: 8d 45 14 lea 0x14(%ebp),%eax + 104e66: f6 45 d4 40 testb $0x40,0xffffffd4(%ebp) + 104e6a: 50 push %eax + 104e6b: b8 30 00 00 00 mov $0x30,%eax + 104e70: 75 05 jne 104e77 + 104e72: b8 20 00 00 00 mov $0x20,%eax + 104e77: 50 push %eax + 104e78: ff 55 10 call *0x10(%ebp) + 104e7b: ff 4d cc decl 0xffffffcc(%ebp) + 104e7e: ff 45 d0 incl 0xffffffd0(%ebp) + 104e81: 83 c4 10 add $0x10,%esp + 104e84: 39 5d cc cmp %ebx,0xffffffcc(%ebp) + 104e87: 77 d7 ja 104e60 + 104e89: 83 65 d4 60 andl $0x60,0xffffffd4(%ebp) + 104e8d: 83 7d d4 20 cmpl $0x20,0xffffffd4(%ebp) + 104e91: 74 5e je 104ef1 + 104e93: 8a 07 mov (%edi),%al + 104e95: 84 c0 test %al,%al + 104e97: 74 1e je 104eb7 + 104e99: 8d 76 00 lea 0x0(%esi),%esi + 104e9c: 83 ec 08 sub $0x8,%esp + 104e9f: 8d 55 14 lea 0x14(%ebp),%edx + 104ea2: 52 push %edx + 104ea3: 0f b6 c0 movzbl %al,%eax + 104ea6: 50 push %eax + 104ea7: ff 55 10 call *0x10(%ebp) + 104eaa: 47 inc %edi + 104eab: ff 45 d0 incl 0xffffffd0(%ebp) + 104eae: 8a 07 mov (%edi),%al + 104eb0: 83 c4 10 add $0x10,%esp + 104eb3: 84 c0 test %al,%al + 104eb5: 75 e5 jne 104e9c + 104eb7: 39 5d cc cmp %ebx,0xffffffcc(%ebp) + 104eba: 72 20 jb 104edc + 104ebc: 29 5d cc sub %ebx,0xffffffcc(%ebp) + 104ebf: 74 1b je 104edc + 104ec1: 8d 76 00 lea 0x0(%esi),%esi + 104ec4: 83 ec 08 sub $0x8,%esp + 104ec7: 8d 45 14 lea 0x14(%ebp),%eax + 104eca: 50 push %eax + 104ecb: 6a 20 push $0x20 + 104ecd: ff 55 10 call *0x10(%ebp) + 104ed0: ff 45 d0 incl 0xffffffd0(%ebp) + 104ed3: 83 c4 10 add $0x10,%esp + 104ed6: ff 4d cc decl 0xffffffcc(%ebp) + 104ed9: 75 e9 jne 104ec4 + 104edb: 90 nop + 104edc: c7 45 cc 00 00 00 00 movl $0x0,0xffffffcc(%ebp) + 104ee3: c7 45 d4 00 00 00 00 movl $0x0,0xffffffd4(%ebp) + 104eea: 31 db xor %ebx,%ebx + 104eec: e9 37 fe ff ff jmp 104d28 + 104ef1: 83 ec 08 sub $0x8,%esp + 104ef4: 8d 55 14 lea 0x14(%ebp),%edx + 104ef7: 52 push %edx + 104ef8: 6a 2d push $0x2d + 104efa: ff 55 10 call *0x10(%ebp) + 104efd: ff 45 d0 incl 0xffffffd0(%ebp) + 104f00: 83 c4 10 add $0x10,%esp + 104f03: eb 8e jmp 104e93 + 104f05: 83 ec 08 sub $0x8,%esp + 104f08: 8d 55 14 lea 0x14(%ebp),%edx + 104f0b: 52 push %edx + 104f0c: 6a 2d push $0x2d + 104f0e: ff 55 10 call *0x10(%ebp) + 104f11: ff 45 d0 incl 0xffffffd0(%ebp) + 104f14: 83 c4 10 add $0x10,%esp + 104f17: e9 36 ff ff ff jmp 104e52 + 104f1c: 8d 42 57 lea 0x57(%edx),%eax + 104f1f: e9 fc fe ff ff jmp 104e20 + 104f24: 83 4d d4 20 orl $0x20,0xffffffd4(%ebp) + 104f28: f7 d9 neg %ecx + 104f2a: e9 c6 fe ff ff jmp 104df5 + 104f2f: 83 45 0c 04 addl $0x4,0xc(%ebp) + 104f33: 8b 55 0c mov 0xc(%ebp),%edx + 104f36: 0f b7 4a fc movzwl 0xfffffffc(%edx),%ecx + 104f3a: e9 a8 fe ff ff jmp 104de7 + 104f3f: f6 45 d4 04 testb $0x4,0xffffffd4(%ebp) + 104f43: 74 0f je 104f54 + 104f45: 83 45 0c 04 addl $0x4,0xc(%ebp) + 104f49: 8b 45 0c mov 0xc(%ebp),%eax + 104f4c: 8b 48 fc mov 0xfffffffc(%eax),%ecx + 104f4f: e9 93 fe ff ff jmp 104de7 + 104f54: 83 45 0c 04 addl $0x4,0xc(%ebp) + 104f58: 8b 55 0c mov 0xc(%ebp),%edx + 104f5b: 8b 4a fc mov 0xfffffffc(%edx),%ecx + 104f5e: e9 84 fe ff ff jmp 104de7 + 104f63: 83 45 0c 04 addl $0x4,0xc(%ebp) + 104f67: 83 65 d4 bf andl $0xffffffbf,0xffffffd4(%ebp) + 104f6b: 8b 55 0c mov 0xc(%ebp),%edx + 104f6e: 4f dec %edi + 104f6f: 8a 42 fc mov 0xfffffffc(%edx),%al + 104f72: bb 01 00 00 00 mov $0x1,%ebx + 104f77: 88 07 mov %al,(%edi) + 104f79: e9 d4 fe ff ff jmp 104e52 + 104f7e: 83 4d d4 04 orl $0x4,0xffffffd4(%ebp) + 104f82: bb 0a 00 00 00 mov $0xa,%ebx + 104f87: e9 32 fe ff ff jmp 104dbe + 104f8c: bb 08 00 00 00 mov $0x8,%ebx + 104f91: e9 28 fe ff ff jmp 104dbe + 104f96: 83 45 0c 04 addl $0x4,0xc(%ebp) + 104f9a: 8b 45 0c mov 0xc(%ebp),%eax + 104f9d: 83 65 d4 bf andl $0xffffffbf,0xffffffd4(%ebp) + 104fa1: 8b 78 fc mov 0xfffffffc(%eax),%edi + 104fa4: e9 85 fe ff ff jmp 104e2e + 104fa9: 83 4d d4 10 orl $0x10,0xffffffd4(%ebp) + 104fad: e9 76 fd ff ff jmp 104d28 + 104fb2: 83 4d d4 08 orl $0x8,0xffffffd4(%ebp) + 104fb6: e9 6d fd ff ff jmp 104d28 + 104fbb: 81 4d d4 80 00 00 00 orl $0x80,0xffffffd4(%ebp) + 104fc2: e9 61 fd ff ff jmp 104d28 + 104fc7: 83 4d d4 40 orl $0x40,0xffffffd4(%ebp) + 104fcb: 46 inc %esi + 104fcc: 8a 0e mov (%esi),%cl + 104fce: e9 89 fd ff ff jmp 104d5c + 104fd3: f6 45 d4 01 testb $0x1,0xffffffd4(%ebp) + 104fd7: 0f 85 ff fe ff ff jne 104edc + 104fdd: 83 4d d4 01 orl $0x1,0xffffffd4(%ebp) + 104fe1: e9 42 fd ff ff jmp 104d28 + 104fe6: 83 ec 08 sub $0x8,%esp + 104fe9: 8d 55 14 lea 0x14(%ebp),%edx + 104fec: 52 push %edx + 104fed: 6a 25 push $0x25 + 104fef: ff 55 10 call *0x10(%ebp) + 104ff2: 31 db xor %ebx,%ebx + 104ff4: ff 45 d0 incl 0xffffffd0(%ebp) + 104ff7: c7 45 cc 00 00 00 00 movl $0x0,0xffffffcc(%ebp) + 104ffe: c7 45 d4 00 00 00 00 movl $0x0,0xffffffd4(%ebp) + 105005: e9 18 fd ff ff jmp 104d22 + ... + +0010500c : +/***************************************************************************** +*****************************************************************************/ +void enable(void) +{ + 10500c: 55 push %ebp + 10500d: 89 e5 mov %esp,%ebp + __asm__ __volatile__("sti" + 10500f: fb sti + : + : + ); +} + 105010: c9 leave + 105011: c3 ret + ... + +00105014 : +/***************************************************************************** +*****************************************************************************/ +unsigned inportb(unsigned short port) +{ + 105014: 55 push %ebp + 105015: 89 e5 mov %esp,%ebp + 105017: 8b 55 08 mov 0x8(%ebp),%edx + unsigned char ret_val; + + __asm__ __volatile__("inb %1,%0" + 10501a: ec in (%dx),%al + : "=a"(ret_val) + : "d"(port)); + return ret_val; + 10501b: 0f b6 c0 movzbl %al,%eax +} + 10501e: c9 leave + 10501f: c3 ret + +00105020 : +4. Save/restore the floating-point state when entering/leaving + the kernel (protected OS only) +*****************************************************************************/ +void longjmp(jmp_buf buf, int ret_val) +{ + 105020: 55 push %ebp + 105021: 89 e5 mov %esp,%ebp + 105023: 8b 45 0c mov 0xc(%ebp),%eax + unsigned *esp; + +/* make sure return value is not 0 */ + if(ret_val == 0) + 105026: 85 c0 test %eax,%eax + 105028: 75 05 jne 10502f + ret_val++; + 10502a: b8 01 00 00 00 mov $0x1,%eax +/* EAX is used for return values, so store it in jmp_buf.EAX */ + buf->eax = ret_val; + 10502f: 8b 4d 08 mov 0x8(%ebp),%ecx + 105032: 89 41 1c mov %eax,0x1c(%ecx) +/* get ESP for new stack */ + esp = (unsigned *)buf->esp; +/* push EFLAGS on the new stack */ + esp--; + 105035: 8b 41 0c mov 0xc(%ecx),%eax + 105038: 83 e8 04 sub $0x4,%eax + *esp = buf->eflags; + 10503b: 8b 51 24 mov 0x24(%ecx),%edx + 10503e: 89 10 mov %edx,(%eax) +/* push current CS on the new stack */ + esp--; + 105040: 83 e8 04 sub $0x4,%eax + __asm__ __volatile__( + 105043: 8c 08 movl %cs,(%eax) + "mov %%cs,%0\n" + : "=m"(*esp)); +/* push EIP on the new stack */ + esp--; + 105045: 83 e8 04 sub $0x4,%eax + *esp = buf->eip; + 105048: 8b 51 20 mov 0x20(%ecx),%edx + 10504b: 89 10 mov %edx,(%eax) +/* new ESP is 12 bytes lower; update jmp_buf.ESP */ + buf->esp = (unsigned)esp; + 10504d: 89 41 0c mov %eax,0xc(%ecx) +/* now, briefly, make the jmp_buf struct our stack */ + __asm__ __volatile__( + 105050: 8b 65 08 mov 0x8(%ebp),%esp + 105053: 61 popa + 105054: 8b 64 24 ec mov 0xffffffec(%esp,1),%esp + 105058: cf iret + "movl %0,%%esp\n" +/* ESP now points to 8 general-purpose registers stored in jmp_buf +Pop them */ + "popa\n" +/* load new stack pointer from jmp_buf */ + "movl -20(%%esp),%%esp\n" +/* ESP now points to new stack, with the IRET frame (EIP, CS, EFLAGS) +we created just above. Pop these registers: */ + "iret\n" + : + : "m"(buf)); +} + 105059: c9 leave + 10505a: c3 ret + ... + +0010505c : +void *memcpy(void *s, const void *t, unsigned n) +{ + 10505c: 55 push %ebp + 10505d: 89 e5 mov %esp,%ebp + void *ret = s; + + while(n--) + 10505f: 8b 55 10 mov 0x10(%ebp),%edx + 105062: 56 push %esi + 105063: 4a dec %edx + 105064: 53 push %ebx + 105065: 83 fa ff cmp $0xffffffff,%edx + 105068: 8b 5d 08 mov 0x8(%ebp),%ebx + 10506b: 8b 4d 0c mov 0xc(%ebp),%ecx + 10506e: 89 de mov %ebx,%esi + 105070: 74 0e je 105080 + 105072: 89 f6 mov %esi,%esi + { + *(char *)s = *(char *)t; + 105074: 8a 01 mov (%ecx),%al + s = (char *)s + 1; + t = (char *)t + 1; + 105076: 4a dec %edx + 105077: 88 03 mov %al,(%ebx) + 105079: 41 inc %ecx + 10507a: 43 inc %ebx + 10507b: 83 fa ff cmp $0xffffffff,%edx + 10507e: 75 f4 jne 105074 + } + + return ret; +} + 105080: 5b pop %ebx + 105081: 89 f0 mov %esi,%eax + 105083: 5e pop %esi + 105084: c9 leave + 105085: c3 ret + ... + +00105088 : + +void *memsetw(void *s, short i, unsigned n) +{ + 105088: 55 push %ebp + 105089: 89 e5 mov %esp,%ebp + void *start = s; + + while(n--) + 10508b: 8b 55 10 mov 0x10(%ebp),%edx + 10508e: 4a dec %edx + 10508f: 8b 4d 08 mov 0x8(%ebp),%ecx + 105092: 83 fa ff cmp $0xffffffff,%edx + 105095: 53 push %ebx + 105096: 8b 45 0c mov 0xc(%ebp),%eax + 105099: 89 cb mov %ecx,%ebx + 10509b: 74 0f je 1050ac + 10509d: 8d 76 00 lea 0x0(%esi),%esi + { + *(short *)s = (short)i; + s = (short *)s + 1; + 1050a0: 4a dec %edx + 1050a1: 66 89 01 mov %ax,(%ecx) + 1050a4: 83 c1 02 add $0x2,%ecx + 1050a7: 83 fa ff cmp $0xffffffff,%edx + 1050aa: 75 f4 jne 1050a0 + } + + return(start); +} + 1050ac: 89 d8 mov %ebx,%eax + 1050ae: 5b pop %ebx + 1050af: c9 leave + 1050b0: c3 ret + 1050b1: 00 00 add %al,(%eax) + ... + +001050b4 : +/***************************************************************************** +*****************************************************************************/ +void outportb(unsigned port, unsigned val) +{ + 1050b4: 55 push %ebp + 1050b5: 89 e5 mov %esp,%ebp + 1050b7: 8b 55 08 mov 0x8(%ebp),%edx + 1050ba: 8b 45 0c mov 0xc(%ebp),%eax + __asm__ __volatile__("outb %b0,%w1" + 1050bd: ee out %al,(%dx) + : + : "a"(val), "d"(port)); +} + 1050be: c9 leave + 1050bf: c3 ret + +001050c0 : +int do_printf(const char *fmt, va_list args, fnptr_t fn, void *ptr); +void putch(unsigned c); + +int printf_help(unsigned c, void **ptr) +{ + 1050c0: 55 push %ebp + 1050c1: 89 e5 mov %esp,%ebp + 1050c3: 83 ec 14 sub $0x14,%esp + /** + * Leave this for now + */ + ptr = ptr; + + putch(c); + 1050c6: ff 75 08 pushl 0x8(%ebp) + 1050c9: e8 32 fa ff ff call 104b00 + return 0; +} + 1050ce: 31 c0 xor %eax,%eax + 1050d0: c9 leave + 1050d1: c3 ret + 1050d2: 89 f6 mov %esi,%esi + +001050d4 : + +void printf(const char *fmt, ...) +{ + 1050d4: 55 push %ebp + 1050d5: 89 e5 mov %esp,%ebp + 1050d7: 83 ec 08 sub $0x8,%esp + va_list args; + + va_start(args, fmt); + (void)do_printf(fmt, args, printf_help, NULL); + 1050da: 6a 00 push $0x0 + 1050dc: 68 c0 50 10 00 push $0x1050c0 + 1050e1: 8d 45 0c lea 0xc(%ebp),%eax + 1050e4: 50 push %eax + 1050e5: ff 75 08 pushl 0x8(%ebp) + 1050e8: e8 e3 fb ff ff call 104cd0 + va_end(args); +} + 1050ed: c9 leave + 1050ee: c3 ret + ... + +001050f0 : +int strcmp(const char * src, const char * dst) +{ + 1050f0: 55 push %ebp + 1050f1: 89 e5 mov %esp,%ebp + 1050f3: 56 push %esi + 1050f4: 53 push %ebx + 1050f5: 8b 5d 0c mov 0xc(%ebp),%ebx + 1050f8: 8b 75 08 mov 0x8(%ebp),%esi + int ret = 0 ; + + while(!(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) + 1050fb: 8a 0b mov (%ebx),%cl + 1050fd: 0f b6 c1 movzbl %cl,%eax + 105100: 0f b6 16 movzbl (%esi),%edx + 105103: 29 c2 sub %eax,%edx + 105105: 89 d0 mov %edx,%eax + 105107: 75 1b jne 105124 + 105109: 84 c9 test %cl,%cl + 10510b: 74 17 je 105124 + 10510d: 8d 76 00 lea 0x0(%esi),%esi + ++src, ++dst; + 105110: 43 inc %ebx + 105111: 46 inc %esi + 105112: 8a 0b mov (%ebx),%cl + 105114: 0f b6 c1 movzbl %cl,%eax + 105117: 0f b6 16 movzbl (%esi),%edx + 10511a: 29 c2 sub %eax,%edx + 10511c: 89 d0 mov %edx,%eax + 10511e: 75 04 jne 105124 + 105120: 84 c9 test %cl,%cl + 105122: 75 ec jne 105110 + + if(ret < 0) + 105124: 85 c0 test %eax,%eax + 105126: 78 0d js 105135 + ret = -1 ; + else if(ret > 0) + 105128: 85 c0 test %eax,%eax + 10512a: 7e 05 jle 105131 + ret = 1 ; + 10512c: b8 01 00 00 00 mov $0x1,%eax + + return(ret); +} + 105131: 5b pop %ebx + 105132: 5e pop %esi + 105133: c9 leave + 105134: c3 ret + 105135: b8 ff ff ff ff mov $0xffffffff,%eax + 10513a: eb f5 jmp 105131 + +0010513c : + +char *strcpy(char *s, const char *t) +{ + 10513c: 55 push %ebp + 10513d: 89 e5 mov %esp,%ebp + 10513f: 8b 4d 08 mov 0x8(%ebp),%ecx + 105142: 8b 55 0c mov 0xc(%ebp),%edx + 105145: 8d 76 00 lea 0x0(%esi),%esi + while((*(s++) = *(t++))); + 105148: 8a 02 mov (%edx),%al + 10514a: 88 01 mov %al,(%ecx) + 10514c: 42 inc %edx + 10514d: 41 inc %ecx + 10514e: 84 c0 test %al,%al + 105150: 75 f6 jne 105148 + + return s; +} + 105152: 89 c8 mov %ecx,%eax + 105154: c9 leave + 105155: c3 ret + ... + +00105158 : +#include /* size_t */ +/***************************************************************************** +*****************************************************************************/ +size_t strlen(const char *str) +{ + 105158: 55 push %ebp + 105159: 89 e5 mov %esp,%ebp + 10515b: 8b 55 08 mov 0x8(%ebp),%edx + size_t ret_val; + + for(ret_val = 0; *str != '\0'; str++) + 10515e: 31 c0 xor %eax,%eax + 105160: 80 3a 00 cmpb $0x0,(%edx) + 105163: 74 0a je 10516f + 105165: 8d 76 00 lea 0x0(%esi),%esi + 105168: 42 inc %edx + ret_val++; + 105169: 40 inc %eax + 10516a: 80 3a 00 cmpb $0x0,(%edx) + 10516d: 75 f9 jne 105168 + return ret_val; +} + 10516f: c9 leave + 105170: c3 ret + 105171: 00 00 add %al,(%eax) + ... + +00105174 : +#include /* size_t */ + +char *strncpy(char * dest, const char * source, size_t count) +{ + 105174: 55 push %ebp + 105175: 89 e5 mov %esp,%ebp + 105177: 8b 55 10 mov 0x10(%ebp),%edx + 10517a: 56 push %esi + char *start = dest; + + while(count && (*dest++ = *source++)) /* copy string */ + 10517b: 85 d2 test %edx,%edx + 10517d: 53 push %ebx + 10517e: 8b 75 08 mov 0x8(%ebp),%esi + 105181: 8b 5d 0c mov 0xc(%ebp),%ebx + 105184: 74 2a je 1051b0 + 105186: 8a 03 mov (%ebx),%al + 105188: 43 inc %ebx + 105189: 84 c0 test %al,%al + 10518b: 88 06 mov %al,(%esi) + 10518d: 8d 4e 01 lea 0x1(%esi),%ecx + 105190: 74 0f je 1051a1 + 105192: 89 f6 mov %esi,%esi + count--; + 105194: 4a dec %edx + 105195: 74 19 je 1051b0 + 105197: 8a 03 mov (%ebx),%al + 105199: 88 01 mov %al,(%ecx) + 10519b: 43 inc %ebx + 10519c: 41 inc %ecx + 10519d: 84 c0 test %al,%al + 10519f: 75 f3 jne 105194 + + if(count) /* pad out with zeroes */ + 1051a1: 85 d2 test %edx,%edx + 1051a3: 74 0b je 1051b0 + while(--count) + 1051a5: 4a dec %edx + 1051a6: 74 08 je 1051b0 + *dest++ = '\0'; + 1051a8: c6 01 00 movb $0x0,(%ecx) + 1051ab: 41 inc %ecx + 1051ac: 4a dec %edx + 1051ad: 75 f9 jne 1051a8 + 1051af: 90 nop + + return(start); +} + 1051b0: 5b pop %ebx + 1051b1: 89 f0 mov %esi,%eax + 1051b3: 5e pop %esi + 1051b4: c9 leave + 1051b5: c3 ret + 1051b6: 5b pop %ebx + 1051b7: 20 00 and %al,(%eax) + 1051b9: 25 73 3a 20 25 and $0x25203a73,%eax + 1051be: 73 00 jae 1051c0 + 1051c0: 20 5d 00 and %bl,0x0(%ebp) + 1051c3: 57 push %edi + 1051c4: 61 popa + 1051c5: 69 74 00 08 08 08 08 imul $0x46080808,0x8(%eax,%eax,1),%esi + 1051cc: 46 + 1051cd: 61 popa + 1051ce: 69 6c 0a 00 08 08 08 imul $0x8080808,0x0(%edx,%ecx,1),%ebp + 1051d5: 08 + 1051d6: 2e 2e 00 4f 6b add %cl,%cs:0x6b(%edi) + 1051db: 0a 00 or (%eax),%al + 1051dd: 25 30 32 58 20 and $0x20583230,%eax + 1051e2: 00 09 add %cl,(%ecx) + 1051e4: 00 25 63 00 75 53 add %ah,0x53750063 + 1051ea: 50 push %eax + 1051eb: 3d 25 30 38 58 cmp $0x58383025,%eax + 1051f0: 20 75 53 and %dh,0x53(%ebp) + 1051f3: 53 push %ebx + 1051f4: 3d 25 30 38 58 cmp $0x58383025,%eax + 1051f9: 0a 00 or (%eax),%al + 1051fb: 00 00 add %al,(%eax) + 1051fd: 00 00 add %al,(%eax) + 1051ff: 00 45 44 add %al,0x44(%ebp) + 105202: 49 dec %ecx + 105203: 3d 25 30 38 58 cmp $0x58383025,%eax + 105208: 20 45 53 and %al,0x53(%ebp) + 10520b: 49 dec %ecx + 10520c: 3d 25 30 38 58 cmp $0x58383025,%eax + 105211: 20 45 42 and %al,0x42(%ebp) + 105214: 50 push %eax + 105215: 3d 25 30 38 58 cmp $0x58383025,%eax + 10521a: 20 45 53 and %al,0x53(%ebp) + 10521d: 50 push %eax + 10521e: 3d 25 30 38 58 cmp $0x58383025,%eax + 105223: 0a 00 or (%eax),%al + ... + 10523d: 00 00 add %al,(%eax) + 10523f: 00 45 42 add %al,0x42(%ebp) + 105242: 58 pop %eax + 105243: 3d 25 30 38 58 cmp $0x58383025,%eax + 105248: 20 45 44 and %al,0x44(%ebp) + 10524b: 58 pop %eax + 10524c: 3d 25 30 38 58 cmp $0x58383025,%eax + 105251: 20 45 43 and %al,0x43(%ebp) + 105254: 58 pop %eax + 105255: 3d 25 30 38 58 cmp $0x58383025,%eax + 10525a: 20 45 41 and %al,0x41(%ebp) + 10525d: 58 pop %eax + 10525e: 3d 25 30 38 58 cmp $0x58383025,%eax + 105263: 0a 00 or (%eax),%al + ... + 10527d: 00 00 add %al,(%eax) + 10527f: 00 20 add %ah,(%eax) + 105281: 44 inc %esp + 105282: 53 push %ebx + 105283: 3d 25 30 38 58 cmp $0x58383025,%eax + 105288: 20 20 and %ah,(%eax) + 10528a: 45 inc %ebp + 10528b: 53 push %ebx + 10528c: 3d 25 30 38 58 cmp $0x58383025,%eax + 105291: 20 20 and %ah,(%eax) + 105293: 46 inc %esi + 105294: 53 push %ebx + 105295: 3d 25 30 38 58 cmp $0x58383025,%eax + 10529a: 20 20 and %ah,(%eax) + 10529c: 47 inc %edi + 10529d: 53 push %ebx + 10529e: 3d 25 30 38 58 cmp $0x58383025,%eax + 1052a3: 0a 00 or (%eax),%al + ... + 1052bd: 00 00 add %al,(%eax) + 1052bf: 00 69 6e add %ch,0x6e(%ecx) + 1052c2: 74 3d je 105301 + 1052c4: 25 30 38 58 20 and $0x20583830,%eax + 1052c9: 65 gs + 1052ca: 72 72 jb 10533e + 1052cc: 3d 25 30 38 58 cmp $0x58383025,%eax + 1052d1: 20 45 49 and %al,0x49(%ebp) + 1052d4: 50 push %eax + 1052d5: 3d 25 30 38 58 cmp $0x58383025,%eax + 1052da: 20 20 and %ah,(%eax) + 1052dc: 43 inc %ebx + 1052dd: 53 push %ebx + 1052de: 3d 25 30 38 58 cmp $0x58383025,%eax + 1052e3: 0a 00 or (%eax),%al + ... + 1052fd: 00 00 add %al,(%eax) + 1052ff: 00 64 75 6d add %ah,0x6d(%ebp,%esi,2) + 105303: 70 68 jo 10536d + 105305: 65 gs + 105306: 61 popa + 105307: 70 00 jo 105309 + 105309: 00 2d 68 00 00 00 add %ch,0x68 + ... + 10531f: 00 50 72 add %dl,0x72(%eax) + 105322: 69 6e 74 20 6c 69 73 imul $0x73696c20,0x74(%esi),%ebp + 105329: 74 69 je 105394 + 10532b: 6e outsb %ds:(%esi),(%dx) + 10532c: 67 20 6f 66 addr16 and %ch,102(%bx) + 105330: 20 68 65 and %ch,0x65(%eax) + 105333: 61 popa + 105334: 70 20 jo 105356 + 105336: 75 73 jne 1053ab + 105338: 61 popa + 105339: 67 65 20 61 6e addr16 and %ah,%gs:110(%bx,%di) + 10533e: 64 20 73 74 and %dh,%fs:0x74(%ebx) + 105342: 61 popa + 105343: 74 75 je 1053ba + 105345: 73 2e jae 105375 + 105347: 00 00 add %al,(%eax) + 105349: 65 63 68 6f arpl %bp,%gs:0x6f(%eax) + ... + 10535d: 00 00 add %al,(%eax) + 10535f: 00 45 63 add %al,0x63(%ebp) + 105362: 68 6f 20 61 20 push $0x2061206f + 105367: 6c insb (%dx),%es:(%edi) + 105368: 69 6e 65 20 6f 66 20 imul $0x20666f20,0x65(%esi),%ebp + 10536f: 74 65 je 1053d6 + 105371: 78 74 js 1053e7 + 105373: 20 74 6f 20 and %dh,0x20(%edi,%ebp,2) + 105377: 74 68 je 1053e1 + 105379: 65 20 74 65 72 and %dh,%gs:0x72(%ebp,2) + 10537e: 6d insl (%dx),%es:(%edi) + 10537f: 69 6e 61 6c 2e 00 00 imul $0x2e6c,0x61(%esi),%ebp + 105386: 68 65 6c 70 00 push $0x706c65 + ... + 10539f: 00 44 69 73 add %al,0x73(%ecx,%ebp,2) + 1053a3: 70 6c jo 105411 + 1053a5: 61 popa + 1053a6: 79 73 jns 10541b + 1053a8: 20 67 65 and %ah,0x65(%edi) + 1053ab: 6e outsb %ds:(%esi),(%dx) + 1053ac: 65 gs + 1053ad: 72 61 jb 105410 + 1053af: 6c insb (%dx),%es:(%edi) + 1053b0: 20 68 65 and %ch,0x65(%eax) + 1053b3: 6c insb (%dx),%es:(%edi) + 1053b4: 70 20 jo 1053d6 + 1053b6: 6d insl (%dx),%es:(%edi) + 1053b7: 65 6e outsb %gs:(%esi),(%dx) + 1053b9: 75 20 jne 1053db + 1053bb: 6f outsl %ds:(%esi),(%dx) + 1053bc: 72 20 jb 1053de + 1053be: 68 65 6c 70 20 push $0x20706c65 + 1053c3: 6f outsl %ds:(%esi),(%dx) + 1053c4: 6e outsb %ds:(%esi),(%dx) + 1053c5: 20 73 70 and %dh,0x70(%ebx) + 1053c8: 65 63 69 66 arpl %bp,%gs:0x66(%ecx) + 1053cc: 69 63 20 63 6f 6d 6d imul $0x6d6d6f63,0x20(%ebx),%esp + 1053d3: 61 popa + 1053d4: 6e outsb %ds:(%esi),(%dx) + 1053d5: 64 2e 00 00 add %al,%cs:%fs:(%eax) + 1053d9: 73 68 jae 105443 + 1053db: 75 74 jne 105451 + 1053dd: 64 6f outsl %fs:(%esi),(%dx) + 1053df: 77 6e ja 10544f + 1053e1: 00 00 add %al,(%eax) + 1053e3: 2d 72 00 00 4e sub $0x4e000072,%eax + 1053e8: 4f dec %edi + 1053e9: 57 push %edi + 1053ea: 00 00 add %al,(%eax) + 1053ec: 48 dec %eax + 1053ed: 61 popa + 1053ee: 6c insb (%dx),%es:(%edi) + 1053ef: 74 20 je 105411 + 1053f1: 6f outsl %ds:(%esi),(%dx) + 1053f2: 72 20 jb 105414 + 1053f4: 72 65 jb 10545b + 1053f6: 73 74 jae 10546c + 1053f8: 61 popa + 1053f9: 72 74 jb 10546f + 1053fb: 20 74 68 65 and %dh,0x65(%eax,%ebp,2) + 1053ff: 20 73 79 and %dh,0x79(%ebx) + 105402: 73 74 jae 105478 + 105404: 65 gs + 105405: 6d insl (%dx),%es:(%edi) + 105406: 2e 00 00 add %al,%cs:(%eax) + 105409: 63 6c 73 00 arpl %bp,0x0(%ebx,%esi,2) + ... + 10541d: 00 00 add %al,(%eax) + 10541f: 00 43 6c add %al,0x6c(%ebx) + 105422: 65 gs + 105423: 61 popa + 105424: 72 73 jb 105499 + 105426: 20 74 68 65 and %dh,0x65(%eax,%ebp,2) + 10542a: 20 74 65 72 and %dh,0x72(%ebp,2) + 10542e: 6d insl (%dx),%es:(%edi) + 10542f: 69 6e 61 6c 20 6f 66 imul $0x666f206c,0x61(%esi),%ebp + 105436: 20 61 6c and %ah,0x6c(%ecx) + 105439: 6c insb (%dx),%es:(%edi) + 10543a: 20 6f 75 and %ch,0x75(%edi) + 10543d: 74 70 je 1054af + 10543f: 75 74 jne 1054b5 + 105441: 2e 00 00 add %al,%cs:(%eax) + 105444: 70 77 jo 1054bd + 105446: 64 00 00 add %al,%fs:(%eax) + ... + 10545d: 00 00 add %al,(%eax) + 10545f: 00 50 72 add %dl,0x72(%eax) + 105462: 69 6e 74 73 20 74 68 imul $0x68742073,0x74(%esi),%ebp + 105469: 65 20 63 75 and %ah,%gs:0x75(%ebx) + 10546d: 72 72 jb 1054e1 + 10546f: 65 6e outsb %gs:(%esi),(%dx) + 105471: 74 20 je 105493 + 105473: 77 6f ja 1054e4 + 105475: 72 6b jb 1054e2 + 105477: 69 6e 67 20 64 69 72 imul $0x72696420,0x67(%esi),%ebp + 10547e: 65 63 74 6f 72 arpl %si,%gs:0x72(%edi,%ebp,2) + 105483: 79 2e jns 1054b3 + 105485: 00 00 add %al,(%eax) + 105487: 68 65 6c 70 00 push $0x706c65 + 10548c: 65 gs + 10548d: 73 68 jae 1054f7 + 10548f: 3a 20 cmp (%eax),%ah + 105491: 27 daa + 105492: 25 73 27 20 6e and $0x6e202773,%eax + 105497: 6f outsl %ds:(%esi),(%dx) + 105498: 74 20 je 1054ba + 10549a: 66 6f outsw %ds:(%esi),(%dx) + 10549c: 75 6e jne 10550c + 10549e: 64 2e 0a 00 or %cs:%fs:(%eax),%al + 1054a2: 55 push %ebp + 1054a3: 73 61 jae 105506 + 1054a5: 67 65 3a 20 addr16 cmp %gs:(%bx,%si),%ah + 1054a9: 25 73 20 25 73 and $0x73252073,%eax + 1054ae: 0a 00 or (%eax),%al + 1054b0: 48 dec %eax + 1054b1: 79 62 jns 105515 + 1054b3: 4f dec %edi + 1054b4: 53 push %ebx + 1054b5: 20 45 53 and %al,0x53(%ebp) + 1054b8: 68 65 6c 6c 20 push $0x206c6c65 + 1054bd: 43 inc %ebx + 1054be: 6f outsl %ds:(%esi),(%dx) + 1054bf: 6d insl (%dx),%es:(%edi) + 1054c0: 6d insl (%dx),%es:(%edi) + 1054c1: 61 popa + 1054c2: 6e outsb %ds:(%esi),(%dx) + 1054c3: 64 fs + 1054c4: 73 3a jae 105500 + 1054c6: 0a 00 or (%eax),%al + 1054c8: 25 31 30 73 20 and $0x20733031,%eax + 1054cd: 25 2d 73 0a 00 and $0xa732d,%eax + 1054d2: 08 20 or %ah,(%eax) + 1054d4: 08 00 or %al,(%eax) + 1054d6: 24 20 and $0x20,%al + 1054d8: 00 4f 6b add %cl,0x6b(%edi) + 1054db: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1054df: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1054e3: 00 94 09 10 00 c2 09 add %dl,0x9c20010(%ecx,%ecx,1) + 1054ea: 10 00 adc %al,(%eax) + 1054ec: e3 09 jecxz 1054f7 + 1054ee: 10 00 adc %al,(%eax) + 1054f0: 03 0a add (%edx),%ecx + 1054f2: 10 00 adc %al,(%eax) + 1054f4: 24 0a and $0xa,%al + 1054f6: 10 00 adc %al,(%eax) + 1054f8: 4a dec %edx + 1054f9: 0a 10 or (%eax),%dl + 1054fb: 00 71 0a add %dh,0xa(%ecx) + 1054fe: 10 00 adc %al,(%eax) + 105500: 97 xchg %eax,%edi + 105501: 0a 10 or (%eax),%dl + 105503: 00 be 0a 10 00 e4 add %bh,0xe400100a(%esi) + 105509: 0a 10 or (%eax),%dl + 10550b: 00 0b add %cl,(%ebx) + 10550d: 0b 10 or (%eax),%edx + 10550f: 00 31 add %dh,(%ecx) + 105511: 0b 10 or (%eax),%edx + 105513: 00 57 0b add %dl,0xb(%edi) + 105516: 10 00 adc %al,(%eax) + 105518: 64 12 10 adc %fs:(%eax),%dl + 10551b: 00 61 0b add %ah,0xb(%ecx) + 10551e: 10 00 adc %al,(%eax) + 105520: 88 0b mov %cl,(%ebx) + 105522: 10 00 adc %al,(%eax) + 105524: ae scas %es:(%edi),%al + 105525: 0b 10 or (%eax),%edx + 105527: 00 d4 add %dl,%ah + 105529: 0b 10 or (%eax),%edx + 10552b: 00 fb add %bh,%bl + 10552d: 0b 10 or (%eax),%edx + 10552f: 00 22 add %ah,(%edx) + 105531: 0c 10 or $0x10,%al + 105533: 00 48 0c add %cl,0xc(%eax) + 105536: 10 00 adc %al,(%eax) + 105538: 6e outsb %ds:(%esi),(%dx) + 105539: 0c 10 or $0x10,%al + 10553b: 00 95 0c 10 00 bc add %dl,0xbc00100c(%ebp) + 105541: 0c 10 or $0x10,%al + 105543: 00 e2 add %ah,%dl + 105545: 0c 10 or $0x10,%al + 105547: 00 08 add %cl,(%eax) + 105549: 0d 10 00 2f 0d or $0xd2f0010,%eax + 10554e: 10 00 adc %al,(%eax) + 105550: 64 12 10 adc %fs:(%eax),%dl + 105553: 00 39 add %bh,(%ecx) + 105555: 0d 10 00 60 0d or $0xd600010,%eax + 10555a: 10 00 adc %al,(%eax) + 10555c: 86 0d 10 00 ac 0d xchg %cl,0xdac0010 + 105562: 10 00 adc %al,(%eax) + 105564: d3 0d 10 00 fa 0d rorl %cl,0xdfa0010 + 10556a: 10 00 adc %al,(%eax) + 10556c: 20 0e and %cl,(%esi) + 10556e: 10 00 adc %al,(%eax) + 105570: 46 inc %esi + 105571: 0e push %cs + 105572: 10 00 adc %al,(%eax) + 105574: 6d insl (%dx),%es:(%edi) + 105575: 0e push %cs + 105576: 10 00 adc %al,(%eax) + 105578: 94 xchg %eax,%esp + 105579: 0e push %cs + 10557a: 10 00 adc %al,(%eax) + 10557c: ba 0e 10 00 e0 mov $0xe000100e,%edx + 105581: 0e push %cs + 105582: 10 00 adc %al,(%eax) + 105584: 64 12 10 adc %fs:(%eax),%dl + 105587: 00 ea add %ch,%dl + 105589: 0e push %cs + 10558a: 10 00 adc %al,(%eax) + 10558c: 11 0f adc %ecx,(%edi) + 10558e: 10 00 adc %al,(%eax) + 105590: 38 0f cmp %cl,(%edi) + 105592: 10 00 adc %al,(%eax) + 105594: 5f pop %edi + 105595: 0f 10 00 movups (%eax),%xmm0 + 105598: 85 0f test %ecx,(%edi) + 10559a: 10 00 adc %al,(%eax) + 10559c: ab stos %eax,%es:(%edi) + 10559d: 0f 10 00 movups (%eax),%xmm0 + 1055a0: d2 0f rorb %cl,(%edi) + 1055a2: 10 00 adc %al,(%eax) + 1055a4: f9 stc + 1055a5: 0f 10 00 movups (%eax),%xmm0 + 1055a8: 1f pop %ds + 1055a9: 10 10 adc %dl,(%eax) + 1055ab: 00 45 10 add %al,0x10(%ebp) + 1055ae: 10 00 adc %al,(%eax) + 1055b0: 6c insb (%dx),%es:(%edi) + 1055b1: 10 10 adc %dl,(%eax) + 1055b3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055b7: 00 92 10 10 00 64 add %dl,0x64001010(%edx) + 1055bd: 12 10 adc (%eax),%dl + 1055bf: 00 9c 10 10 00 64 12 add %bl,0x12640010(%eax,%edx,1) + 1055c6: 10 00 adc %al,(%eax) + 1055c8: 64 12 10 adc %fs:(%eax),%dl + 1055cb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055cf: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055d3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055d7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055db: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055df: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055e3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055e7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055eb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055ef: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055f3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1055f7: 00 a6 10 10 00 cc add %ah,0xcc001010(%esi) + 1055fd: 10 10 adc %dl,(%eax) + 1055ff: 00 f3 add %dh,%bl + 105601: 10 10 adc %dl,(%eax) + 105603: 00 19 add %bl,(%ecx) + 105605: 11 10 adc %edx,(%eax) + 105607: 00 23 add %ah,(%ebx) + 105609: 11 10 adc %edx,(%eax) + 10560b: 00 4a 11 add %cl,0x11(%edx) + 10560e: 10 00 adc %al,(%eax) + 105610: 70 11 jo 105623 + 105612: 10 00 adc %al,(%eax) + 105614: 97 xchg %eax,%edi + 105615: 11 10 adc %edx,(%eax) + 105617: 00 a1 11 10 00 c7 add %ah,0xc7001011(%ecx) + 10561d: 11 10 adc %edx,(%eax) + 10561f: 00 ee add %ch,%dh + 105621: 11 10 adc %edx,(%eax) + 105623: 00 14 12 add %dl,(%edx,%edx,1) + 105626: 10 00 adc %al,(%eax) + 105628: 3b 12 cmp (%edx),%edx + 10562a: 10 00 adc %al,(%eax) + 10562c: 64 12 10 adc %fs:(%eax),%dl + 10562f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105633: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105637: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10563b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10563f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105643: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105647: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10564b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10564f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105653: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105657: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10565b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10565f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105663: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105667: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10566b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10566f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105673: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105677: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10567b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10567f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105683: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105687: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10568b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10568f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105693: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105697: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10569b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10569f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056a3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056a7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056ab: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056af: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056b3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056b7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056bb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056bf: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056c3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056c7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056cb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056cf: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056d3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056d7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056db: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056df: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056e3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056e7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056eb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056ef: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056f3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056f7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056fb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1056ff: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105703: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105707: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10570b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10570f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105713: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105717: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10571b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10571f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105723: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105727: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10572b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10572f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105733: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105737: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10573b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10573f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105743: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105747: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10574b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10574f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105753: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105757: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10575b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10575f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105763: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105767: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10576b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10576f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105773: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105777: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10577b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10577f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105783: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105787: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10578b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10578f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105793: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105797: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10579b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10579f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057a3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057a7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057ab: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057af: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057b3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057b7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057bb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057bf: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057c3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057c7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057cb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057cf: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057d3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057d7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057db: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057df: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057e3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057e7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057eb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057ef: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057f3: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057f7: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057fb: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 1057ff: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105803: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105807: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10580b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10580f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105813: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105817: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10581b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10581f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105823: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105827: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10582b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10582f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105833: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105837: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10583b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10583f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105843: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105847: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10584b: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10584f: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105853: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 105857: 00 64 12 10 add %ah,0x10(%edx,%edx,1) + 10585b: 00 98 08 10 00 69 add %bl,0x69001008(%eax) + 105861: 6e outsb %ds:(%esi),(%dx) + 105862: 69 74 3a 20 6b 65 79 imul $0x6279656b,0x20(%edx,%edi,1),%esi + 105869: 62 + 10586a: 6f outsl %ds:(%esi),(%dx) + 10586b: 61 popa + 10586c: 72 64 jb 1058d2 + 10586e: 20 25 32 75 20 62 and %ah,0x62207532 + 105874: 75 66 jne 1058dc + 105876: 2c 20 sub $0x20,%al + 105878: 25 32 75 62 20 and $0x20627532,%eax + 10587d: 65 gs + 10587e: 61 popa + 10587f: 63 68 20 arpl %bp,0x20(%eax) + ... + 10589e: 00 00 add %al,(%eax) + 1058a0: 5d pop %ebp + 1058a1: 2e cs + 1058a2: 2e cs + 1058a3: 2e cs + 1058a4: 2e cs + 1058a5: 2e cs + 1058a6: 2e cs + 1058a7: 2e cs + 1058a8: 2e cs + 1058a9: 2e cs + 1058aa: 2e cs + 1058ab: 2e cs + 1058ac: 2e cs + 1058ad: 2e cs + 1058ae: 2e cs + 1058af: 2e cs + 1058b0: 2e cs + 1058b1: 2e cs + 1058b2: 2e cs + 1058b3: 2e cs + 1058b4: 2e cs + 1058b5: 2e cs + 1058b6: 2e cs + 1058b7: 2e cs + 1058b8: 2e 2e 2e 2e 2e 2e 2e add %dl,%cs:(%edx) + 1058bf: 2e 2e 2e 2e 2e 2e 2e + 1058c6: 2e 2e 2e 2e 2e 2e 00 + 1058cd: 0a + 1058ce: 0a 70 61 or 0x61(%eax),%dh + 1058d1: 6e outsb %ds:(%esi),(%dx) + 1058d2: 69 63 3a 20 00 0a 0a imul $0xa0a0020,0x3a(%ebx),%esp + 1058d9: 53 push %ebx + 1058da: 79 73 jns 10594f + 1058dc: 74 65 je 105943 + 1058de: 6d insl (%dx),%es:(%edi) + 1058df: 20 68 61 and %ch,0x61(%eax) + 1058e2: 6c insb (%dx),%es:(%edi) + 1058e3: 74 65 je 10594a + 1058e5: 64 2e 00 44 69 76 add %al,%cs:%fs:0x76(%ecx,%ebp,2) + 1058eb: 69 64 65 20 65 72 72 imul $0x6f727265,0x20(%ebp,2),%esp + 1058f2: 6f + 1058f3: 72 00 jb 1058f5 + 1058f5: 44 inc %esp + 1058f6: 65 62 75 67 bound %esi,%gs:0x67(%ebp) + 1058fa: 20 65 78 and %ah,0x78(%ebp) + 1058fd: 63 65 70 arpl %sp,0x70(%ebp) + 105900: 74 69 je 10596b + 105902: 6f outsl %ds:(%esi),(%dx) + 105903: 6e outsb %ds:(%esi),(%dx) + 105904: 00 4e 6f add %cl,0x6f(%esi) + 105907: 6e outsb %ds:(%esi),(%dx) + 105908: 6d insl (%dx),%es:(%edi) + 105909: 61 popa + 10590a: 73 6b jae 105977 + 10590c: 61 popa + 10590d: 62 6c 65 20 bound %ebp,0x20(%ebp,2) + 105911: 69 6e 74 65 72 72 75 imul $0x75727265,0x74(%esi),%ebp + 105918: 70 74 jo 10598e + 10591a: 20 28 and %ch,(%eax) + 10591c: 4e dec %esi + 10591d: 4d dec %ebp + 10591e: 49 dec %ecx + 10591f: 29 00 sub %eax,(%eax) + 105921: 42 inc %edx + 105922: 72 65 jb 105989 + 105924: 61 popa + 105925: 6b 70 6f 69 imul $0x69,0x6f(%eax),%esi + 105929: 6e outsb %ds:(%esi),(%dx) + 10592a: 74 20 je 10594c + 10592c: 28 49 4e sub %cl,0x4e(%ecx) + 10592f: 54 push %esp + 105930: 33 29 xor (%ecx),%ebp + 105932: 00 4f 76 add %cl,0x76(%edi) + 105935: 65 gs + 105936: 72 66 jb 10599e + 105938: 6c insb (%dx),%es:(%edi) + 105939: 6f outsl %ds:(%esi),(%dx) + 10593a: 77 20 ja 10595c + 10593c: 28 49 4e sub %cl,0x4e(%ecx) + 10593f: 54 push %esp + 105940: 4f dec %edi + 105941: 29 00 sub %eax,(%eax) + 105943: 42 inc %edx + 105944: 6f outsl %ds:(%esi),(%dx) + 105945: 75 6e jne 1059b5 + 105947: 64 fs + 105948: 73 20 jae 10596a + 10594a: 63 68 65 arpl %bp,0x65(%eax) + 10594d: 63 6b 00 arpl %bp,0x0(%ebx) + 105950: 49 dec %ecx + 105951: 6e outsb %ds:(%esi),(%dx) + 105952: 76 61 jbe 1059b5 + 105954: 6c insb (%dx),%es:(%edi) + 105955: 69 64 20 6f 70 63 6f imul $0x646f6370,0x6f(%eax,1),%esp + 10595c: 64 + 10595d: 65 00 43 6f add %al,%gs:0x6f(%ebx) + 105961: 70 72 jo 1059d5 + 105963: 6f outsl %ds:(%esi),(%dx) + 105964: 63 65 73 arpl %sp,0x73(%ebp) + 105967: 73 6f jae 1059d8 + 105969: 72 20 jb 10598b + 10596b: 6e outsb %ds:(%esi),(%dx) + 10596c: 6f outsl %ds:(%esi),(%dx) + 10596d: 74 20 je 10598f + 10596f: 61 popa + 105970: 76 61 jbe 1059d3 + 105972: 69 6c 61 62 6c 65 00 imul $0x4400656c,0x62(%ecx,2),%ebp + 105979: 44 + 10597a: 6f outsl %ds:(%esi),(%dx) + 10597b: 75 62 jne 1059df + 10597d: 6c insb (%dx),%es:(%edi) + 10597e: 65 20 66 61 and %ah,%gs:0x61(%esi) + 105982: 75 6c jne 1059f0 + 105984: 74 00 je 105986 + 105986: 43 inc %ebx + 105987: 6f outsl %ds:(%esi),(%dx) + 105988: 70 72 jo 1059fc + 10598a: 6f outsl %ds:(%esi),(%dx) + 10598b: 63 65 73 arpl %sp,0x73(%ebp) + 10598e: 73 6f jae 1059ff + 105990: 72 20 jb 1059b2 + 105992: 73 65 jae 1059f9 + 105994: 67 6d addr16 insl (%dx),%es:(%di) + 105996: 65 6e outsb %gs:(%esi),(%dx) + 105998: 74 20 je 1059ba + 10599a: 6f outsl %ds:(%esi),(%dx) + 10599b: 76 65 jbe 105a02 + 10599d: 72 72 jb 105a11 + 10599f: 75 6e jne 105a0f + 1059a1: 00 49 6e add %cl,0x6e(%ecx) + 1059a4: 76 61 jbe 105a07 + 1059a6: 6c insb (%dx),%es:(%edi) + 1059a7: 69 64 20 54 53 53 00 imul $0x53005353,0x54(%eax,1),%esp + 1059ae: 53 + 1059af: 65 gs + 1059b0: 67 6d addr16 insl (%dx),%es:(%di) + 1059b2: 65 6e outsb %gs:(%esi),(%dx) + 1059b4: 74 20 je 1059d6 + 1059b6: 6e outsb %ds:(%esi),(%dx) + 1059b7: 6f outsl %ds:(%esi),(%dx) + 1059b8: 74 20 je 1059da + 1059ba: 70 72 jo 105a2e + 1059bc: 65 gs + 1059bd: 73 65 jae 105a24 + 1059bf: 6e outsb %ds:(%esi),(%dx) + 1059c0: 74 00 je 1059c2 + 1059c2: 53 push %ebx + 1059c3: 74 61 je 105a26 + 1059c5: 63 6b 20 arpl %bp,0x20(%ebx) + 1059c8: 65 gs + 1059c9: 78 63 js 105a2e + 1059cb: 65 gs + 1059cc: 70 74 jo 105a42 + 1059ce: 69 6f 6e 00 47 65 6e imul $0x6e654700,0x6e(%edi),%ebp + 1059d5: 65 gs + 1059d6: 72 61 jb 105a39 + 1059d8: 6c insb (%dx),%es:(%edi) + 1059d9: 20 50 72 and %dl,0x72(%eax) + 1059dc: 6f outsl %ds:(%esi),(%dx) + 1059dd: 74 65 je 105a44 + 1059df: 63 74 69 6f arpl %si,0x6f(%ecx,%ebp,2) + 1059e3: 6e outsb %ds:(%esi),(%dx) + 1059e4: 20 46 61 and %al,0x61(%esi) + 1059e7: 75 6c jne 105a55 + 1059e9: 74 00 je 1059eb + 1059eb: 50 push %eax + 1059ec: 61 popa + 1059ed: 67 65 20 66 61 addr16 and %ah,%gs:97(%bp) + 1059f2: 75 6c jne 105a60 + 1059f4: 74 00 je 1059f6 + 1059f6: 43 inc %ebx + 1059f7: 6f outsl %ds:(%esi),(%dx) + 1059f8: 70 72 jo 105a6c + 1059fa: 6f outsl %ds:(%esi),(%dx) + 1059fb: 63 65 73 arpl %sp,0x73(%ebp) + 1059fe: 73 6f jae 105a6f + 105a00: 72 20 jb 105a22 + 105a02: 65 gs + 105a03: 72 72 jb 105a77 + 105a05: 6f outsl %ds:(%esi),(%dx) + 105a06: 72 00 jb 105a08 + 105a08: 41 inc %ecx + 105a09: 6c insb (%dx),%es:(%edi) + 105a0a: 69 67 6e 6d 65 6e 74 imul $0x746e656d,0x6e(%edi),%esp + 105a11: 20 63 68 and %ah,0x68(%ebx) + 105a14: 65 63 6b 00 arpl %bp,%gs:0x0(%ebx) + 105a18: 3f aas + 105a19: 3f aas + 105a1a: 00 49 52 add %cl,0x52(%ecx) + 105a1d: 51 push %ecx + 105a1e: 30 00 xor %al,(%eax) + 105a20: 49 dec %ecx + 105a21: 52 push %edx + 105a22: 51 push %ecx + 105a23: 31 00 xor %eax,(%eax) + 105a25: 49 dec %ecx + 105a26: 52 push %edx + 105a27: 51 push %ecx + 105a28: 32 00 xor (%eax),%al + 105a2a: 49 dec %ecx + 105a2b: 52 push %edx + 105a2c: 51 push %ecx + 105a2d: 33 00 xor (%eax),%eax + 105a2f: 49 dec %ecx + 105a30: 52 push %edx + 105a31: 51 push %ecx + 105a32: 34 00 xor $0x0,%al + 105a34: 49 dec %ecx + 105a35: 52 push %edx + 105a36: 51 push %ecx + 105a37: 35 00 49 52 51 xor $0x51524900,%eax + 105a3c: 36 00 49 52 add %cl,%ss:0x52(%ecx) + 105a40: 51 push %ecx + 105a41: 37 aaa + 105a42: 00 49 52 add %cl,0x52(%ecx) + 105a45: 51 push %ecx + 105a46: 38 00 cmp %al,(%eax) + 105a48: 49 dec %ecx + 105a49: 52 push %edx + 105a4a: 51 push %ecx + 105a4b: 39 00 cmp %eax,(%eax) + 105a4d: 49 dec %ecx + 105a4e: 52 push %edx + 105a4f: 51 push %ecx + 105a50: 31 30 xor %esi,(%eax) + 105a52: 00 49 52 add %cl,0x52(%ecx) + 105a55: 51 push %ecx + 105a56: 31 31 xor %esi,(%ecx) + 105a58: 00 49 52 add %cl,0x52(%ecx) + 105a5b: 51 push %ecx + 105a5c: 31 32 xor %esi,(%edx) + 105a5e: 00 49 52 add %cl,0x52(%ecx) + 105a61: 51 push %ecx + 105a62: 31 33 xor %esi,(%ebx) + 105a64: 00 49 52 add %cl,0x52(%ecx) + 105a67: 51 push %ecx + 105a68: 31 34 00 xor %esi,(%eax,%eax,1) + 105a6b: 49 dec %ecx + 105a6c: 52 push %edx + 105a6d: 51 push %ecx + 105a6e: 31 35 00 73 79 73 xor %esi,0x73797300 + 105a74: 63 61 6c arpl %sp,0x6c(%ecx) + 105a77: 6c insb (%dx),%es:(%edi) + 105a78: 00 0a add %cl,(%edx) + 105a7a: 0a 70 61 or 0x61(%eax),%dh + 105a7d: 6e outsb %ds:(%esi),(%dx) + 105a7e: 69 63 3a 20 45 78 63 imul $0x63784520,0x3a(%ebx),%esp + 105a85: 65 gs + 105a86: 70 74 jo 105afc + 105a88: 69 6f 6e 20 30 78 25 imul $0x25783020,0x6e(%edi),%ebp + 105a8f: 30 38 xor %bh,(%eax) + 105a91: 58 pop %eax + 105a92: 00 20 add %ah,(%eax) + 105a94: 28 25 73 29 00 75 sub %ah,0x75002973 + 105a9a: 73 65 jae 105b01 + 105a9c: 64 00 62 6c add %ah,%fs:0x6c(%edx) + 105aa0: 6f outsl %ds:(%esi),(%dx) + 105aa1: 63 6b 20 arpl %bp,0x20(%ebx) + 105aa4: 25 35 70 3a 20 and $0x203a7035,%eax + 105aa9: 25 36 75 20 62 and $0x62207536,%eax + 105aae: 79 74 jns 105b24 + 105ab0: 65 gs + 105ab1: 73 20 jae 105ad3 + 105ab3: 25 73 0a 00 66 and $0x66000a73,%eax + 105ab8: 72 65 jb 105b1f + 105aba: 65 00 69 6e add %ch,%gs:0x6e(%ecx) + 105abe: 69 74 00 45 6e 61 62 imul $0x6c62616e,0x45(%eax,%eax,1),%esi + 105ac5: 6c + 105ac6: 69 6e 67 20 68 61 72 imul $0x72616820,0x67(%esi),%ebp + 105acd: 64 fs + 105ace: 77 61 ja 105b31 + 105ad0: 72 65 jb 105b37 + 105ad2: 20 69 6e and %ch,0x6e(%ecx) + 105ad5: 74 65 je 105b3c + 105ad7: 72 72 jb 105b4b + 105ad9: 75 70 jne 105b4b + 105adb: 74 73 je 105b50 + 105add: 00 4d 6f add %cl,0x6f(%ebp) + 105ae0: 72 65 jb 105b47 + 105ae2: 20 77 6f and %dh,0x6f(%edi) + 105ae5: 72 6b jb 105b52 + 105ae7: 20 6e 65 and %ch,0x65(%esi) + 105aea: 65 gs + 105aeb: 64 fs + 105aec: 73 20 jae 105b0e + 105aee: 74 6f je 105b5f + 105af0: 20 62 65 and %ah,0x65(%edx) + 105af3: 20 64 6f 6e and %ah,0x6e(%edi,%ebp,2) + 105af7: 65 0a 00 or %gs:(%eax),%al + 105afa: 00 00 add %al,(%eax) + 105afc: 00 00 add %al,(%eax) + ... + +00105b00 : + 105b00: e8 58 10 00 08 00 00 00 56 00 00 00 f5 58 10 00 .X......V....X.. + 105b10: 05 00 00 00 56 00 00 00 05 59 10 00 07 00 00 00 ....V....Y...... + 105b20: 56 00 00 00 21 59 10 00 07 00 00 00 56 00 00 00 V...!Y......V... + 105b30: 33 59 10 00 08 00 00 00 ba 00 00 00 43 59 10 00 3Y..........CY.. + 105b40: 08 00 00 00 ba 00 00 00 50 59 10 00 04 00 00 00 ........PY...... + 105b50: ba 00 00 00 5f 59 10 00 08 00 00 00 ba 00 00 00 ...._Y.......... + 105b60: 79 59 10 00 07 00 00 00 1e 01 00 00 86 59 10 00 yY...........Y.. + 105b70: 0b 00 00 00 1e 01 00 00 a2 59 10 00 0b 00 00 00 .........Y...... + 105b80: 1e 01 00 00 ae 59 10 00 0b 00 00 00 1e 01 00 00 .....Y.......... + 105b90: c2 59 10 00 0b 00 00 00 1e 01 00 00 d2 59 10 00 .Y...........Y.. + 105ba0: 0b 00 00 00 1e 01 00 00 eb 59 10 00 0b 00 00 00 .........Y...... + 105bb0: 82 01 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ................ + 105bc0: f6 59 10 00 08 00 00 00 82 01 00 00 08 5a 10 00 .Y...........Z.. + ... + 105bd8: 18 5a 10 00 00 00 00 00 00 00 00 00 18 5a 10 00 .Z...........Z.. + ... + 105bf0: 18 5a 10 00 00 00 00 00 00 00 00 00 18 5a 10 00 .Z...........Z.. + ... + 105c08: 18 5a 10 00 00 00 00 00 00 00 00 00 18 5a 10 00 .Z...........Z.. + ... + 105c20: 18 5a 10 00 00 00 00 00 00 00 00 00 18 5a 10 00 .Z...........Z.. + ... + 105c38: 18 5a 10 00 00 00 00 00 00 00 00 00 18 5a 10 00 .Z...........Z.. + ... + 105c50: 18 5a 10 00 00 00 00 00 00 00 00 00 18 5a 10 00 .Z...........Z.. + ... + 105c68: 18 5a 10 00 00 00 00 00 00 00 00 00 18 5a 10 00 .Z...........Z.. + ... + 105c80: 1b 5a 10 00 00 00 00 00 00 00 00 00 20 5a 10 00 .Z.......... Z.. + ... + 105c98: 25 5a 10 00 00 00 00 00 00 00 00 00 2a 5a 10 00 %Z..........*Z.. + ... + 105cb0: 2f 5a 10 00 00 00 00 00 00 00 00 00 34 5a 10 00 /Z..........4Z.. + ... + 105cc8: 39 5a 10 00 00 00 00 00 00 00 00 00 3e 5a 10 00 9Z..........>Z.. + ... + 105ce0: 43 5a 10 00 00 00 00 00 00 00 00 00 48 5a 10 00 CZ..........HZ.. + ... + 105cf8: 4d 5a 10 00 00 00 00 00 00 00 00 00 53 5a 10 00 MZ..........SZ.. + ... + 105d10: 59 5a 10 00 00 00 00 00 00 00 00 00 5f 5a 10 00 YZ.........._Z.. + ... + 105d28: 65 5a 10 00 00 00 00 00 00 00 00 00 6b 5a 10 00 eZ..........kZ.. + ... + 105d40: 71 5a 10 00 00 00 00 00 00 00 00 00 qZ.......... + +00105d4c : + 105d4c: 20 00 00 00 ... + +00105d50 : + 105d50: 28 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (............... + 105d60: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d ================ + 105d70: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d ================ + 105d80: 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 0a ===============. + ... + 105da0: 62 6c 6f 63 6b 73 3a 20 25 36 75 20 75 73 65 64 blocks: %6u used + 105db0: 2c 20 25 36 75 20 66 72 65 65 2c 20 25 36 75 20 , %6u free, %6u + 105dc0: 74 6f 74 61 6c 0a 00 00 00 00 00 00 00 00 00 00 total........... + ... + 105de0: 20 62 79 74 65 73 3a 20 25 36 75 20 75 73 65 64 bytes: %6u used + 105df0: 2c 20 25 36 75 20 66 72 65 65 2c 20 25 36 75 20 , %6u free, %6u + 105e00: 74 6f 74 61 6c 0a 00 00 00 00 00 00 00 00 00 00 total........... + ... + 105e20: 67 5f 68 65 61 70 5f 62 6f 74 3d 30 78 25 70 2c g_heap_bot=0x%p, + 105e30: 20 67 5f 6b 62 72 6b 3d 30 78 25 70 2c 20 67 5f g_kbrk=0x%p, g_ + 105e40: 68 65 61 70 5f 74 6f 70 3d 30 78 25 70 0a 00 00 heap_top=0x%p... + ... + 105e60: 2a 2a 2a 20 73 6f 6d 65 20 68 65 61 70 20 6d 65 *** some heap me + 105e70: 6d 6f 72 79 20 69 73 20 6e 6f 74 20 61 63 63 6f mory is not acco + 105e80: 75 6e 74 65 64 20 66 6f 72 0a 00 00 00 00 00 00 unted for....... + ... + 105ea0: 6b 65 72 6e 65 6c 20 68 65 61 70 20 69 73 20 63 kernel heap is c + 105eb0: 6f 72 72 75 70 74 20 69 6e 20 6d 61 6c 6c 6f 63 orrupt in malloc + 105ec0: 28 29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ().............. + ... + 105ee0: 61 74 74 65 6d 70 74 20 74 6f 20 66 72 65 65 28 attempt to free( + 105ef0: 29 20 62 6c 6f 63 6b 20 61 74 20 30 78 25 70 20 ) block at 0x%p + 105f00: 77 69 74 68 20 62 61 64 20 6d 61 67 69 63 20 76 with bad magic v + 105f10: 61 6c 75 65 00 00 00 00 00 00 00 00 00 00 00 00 alue............ + 105f20: 6b 65 72 6e 65 6c 20 68 65 61 70 20 69 73 20 63 kernel heap is c + 105f30: 6f 72 72 75 70 74 20 69 6e 20 66 72 65 65 28 29 orrupt in free() + ... + 105f60: 61 74 74 65 6d 70 74 20 74 6f 20 66 72 65 65 28 attempt to free( + 105f70: 29 20 62 6c 6f 63 6b 20 61 74 20 30 78 25 70 20 ) block at 0x%p + 105f80: 74 68 61 74 20 69 73 20 6e 6f 74 20 69 6e 20 74 that is not in t + 105f90: 68 65 20 68 65 61 70 00 00 00 00 00 00 00 00 00 he heap......... + 105fa0: 55 6e 61 62 6c 65 20 74 6f 20 72 75 6e 20 74 65 Unable to run te + 105fb0: 73 74 68 65 61 70 20 2d 2d 20 6b 6d 61 6c 6c 6f stheap -- kmallo + 105fc0: 63 28 29 20 69 73 20 62 72 6f 6b 65 6e 2e 0a 00 c() is broken... + ... + 105fe0: 61 74 74 65 6d 70 74 20 74 6f 20 72 65 61 6c 6c attempt to reall + 105ff0: 6f 63 28 29 20 62 6c 6f 63 6b 20 61 74 20 30 78 oc() block at 0x + 106000: 25 70 20 77 69 74 68 20 62 61 64 20 6d 61 67 69 %p with bad magi + 106010: 63 20 76 61 6c 75 65 00 00 00 00 00 00 00 00 00 c value......... + 106020: 49 6e 73 74 61 6c 6c 69 6e 67 20 6b 65 79 62 6f Installing keybo + 106030: 61 72 64 20 69 6e 74 65 72 72 75 70 74 20 68 61 ard interrupt ha + 106040: 6e 64 6c 65 72 00 00 00 00 00 00 00 00 00 00 00 ndler........... + ... + 106060: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 106070: 20 20 20 20 20 20 20 20 20 5f 20 20 20 5f 20 20 _ _ + 106080: 5f 20 20 5f 20 20 5f 5f 5f 5f 20 20 5f 5f 5f 5f _ _ ____ ____ + 106090: 5f 20 20 5f 5f 5f 20 20 20 20 20 20 20 20 20 20 _ ___ + 1060a0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + ... + 1060c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 1060d0: 20 20 20 20 20 20 20 20 28 20 29 5f 28 20 29 28 ( )_( )( + 1060e0: 20 5c 2f 20 29 28 20 20 5f 20 5c 28 20 20 5f 20 \/ )( _ \( _ + 1060f0: 20 29 2f 20 5f 5f 29 20 20 20 20 20 20 20 20 20 )/ __) + 106100: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + ... + 106120: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 106130: 20 20 20 20 20 20 20 20 20 29 20 5f 20 28 20 20 ) _ ( + 106140: 5c 20 20 2f 20 20 29 20 5f 20 3c 20 29 28 5f 29 \ / ) _ < )(_) + 106150: 28 20 5c 5f 5f 20 5c 20 20 20 20 20 20 20 20 20 ( \__ \ + 106160: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + ... + 106180: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 106190: 20 20 20 20 20 20 20 20 28 5f 29 20 28 5f 29 20 (_) (_) + 1061a0: 28 5f 5f 29 20 28 5f 5f 5f 5f 2f 28 5f 5f 5f 5f (__) (____/(____ + 1061b0: 5f 29 28 5f 5f 5f 2f 20 20 20 20 20 20 20 20 20 _)(___/ + 1061c0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 1061d0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 1061e0: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 1061f0: 20 20 20 20 20 20 20 20 48 79 62 72 69 64 20 4f Hybrid O + 106200: 70 65 72 61 74 69 6e 67 20 53 79 73 74 65 6d 20 perating System + 106210: 28 48 79 62 4f 53 29 20 20 20 20 20 20 20 20 20 (HybOS) + 106220: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 106230: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 106240: 41 4c 54 20 2b 20 46 31 20 2d 20 46 38 20 66 6f ALT + F1 - F8 fo + 106250: 72 20 76 69 72 74 75 61 6c 20 74 65 72 6d 69 6e r virtual termin + 106260: 61 6c 73 0a 00 00 00 00 00 00 00 00 00 00 00 00 als............. + ... + 106280: 54 68 72 65 65 20 66 69 6e 67 65 72 20 73 61 6c Three finger sal + 106290: 75 74 65 20 74 6f 20 72 65 73 74 61 72 74 0a 00 ute to restart.. + 1062a0: 49 6e 69 74 69 61 6c 69 7a 69 6e 67 20 6d 65 6d Initializing mem + 1062b0: 6f 72 79 20 6d 61 6e 61 67 65 6d 65 6e 74 00 00 ory management.. + 1062c0: 00 00 00 00 74 61 73 6b 20 68 61 6e 64 6c 65 72 ....task handler + ... + +001062e0 : + 1062e0: 00 00 00 00 04 00 00 00 02 00 00 00 06 00 00 00 ................ + 1062f0: 01 00 00 00 05 00 00 00 03 00 00 00 07 00 00 00 ................ + 106300: 1b 5b 32 4a 00 6d 6f 6e 6f 00 5d 2e 2e 2e 2e 2e .[2J.mono.]..... + 106310: 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 2e 00 63 6f 6c 6f ............colo + 106320: 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r............... + ... + 106340: 69 6e 69 74 3a 20 76 69 64 65 6f 20 25 35 73 20 init: video %5s + 106350: 65 6d 75 6c 61 74 69 6f 6e 2c 20 25 32 75 78 25 emulation, %2ux% + 106360: 32 75 2c 20 66 72 61 6d 65 62 75 66 66 65 72 20 2u, framebuffer + 106370: 61 74 20 30 78 25 31 58 20 00 00 00 0c 4d 10 00 at 0x%1X ....M.. + 106380: 40 4d 10 00 5c 4d 10 00 76 4d 10 00 98 4d 10 00 @M..\M..vM...M.. + 106390: b5 4d 10 00 dc 4e 10 00 dc 4e 10 00 dc 4e 10 00 .M...N...N...N.. + 1063a0: dc 4e 10 00 dc 4e 10 00 dc 4e 10 00 dc 4e 10 00 .N...N...N...N.. + 1063b0: dc 4e 10 00 dc 4e 10 00 dc 4e 10 00 63 4f 10 00 .N...N...N..cO.. + 1063c0: 7e 4f 10 00 dc 4e 10 00 dc 4e 10 00 dc 4e 10 00 ~O...N...N...N.. + 1063d0: dc 4e 10 00 7e 4f 10 00 dc 4e 10 00 dc 4e 10 00 .N..~O...N...N.. + 1063e0: dc 4e 10 00 dc 4e 10 00 b9 4d 10 00 8c 4f 10 00 .N...N...M...O.. + 1063f0: b9 4d 10 00 dc 4e 10 00 dc 4e 10 00 96 4f 10 00 .M...N...N...O.. + 106400: dc 4e 10 00 82 4f 10 00 dc 4e 10 00 dc 4e 10 00 .N...O...N...N.. + 106410: b9 4d 10 00 00 00 00 00 00 00 00 00 00 00 00 00 .M.............. + ... diff --git a/Dump/hybos/src/objects/kernel.sym b/Dump/hybos/src/objects/kernel.sym new file mode 100644 index 0000000..9626ccf --- /dev/null +++ b/Dump/hybos/src/objects/kernel.sym @@ -0,0 +1,656 @@ +00000001 a MULTIBOOT_PAGE_ALIGN +00000002 a MULTIBOOT_MEMORY_INFO +00000010 a LINEAR_DATA_SEL +00000018 a LINEAR_CODE_SEL +00010000 a MULTIBOOT_AOUT_KLUDGE +00010003 a MULTIBOOT_HEADER_FLAGS +00100000 A LS_Phys +00100000 A LS_Virt +00100000 T LS_Code /usr/home/reddawg/source/hybos/src/kernel/bootlog.c:10 +00100000 T _code /usr/home/reddawg/source/hybos/src/kernel/bootlog.c:10 +00100000 T code /usr/home/reddawg/source/hybos/src/kernel/bootlog.c:10 +00100000 T klog /usr/home/reddawg/source/hybos/src/kernel/bootlog.c:10 +0010011c T dump /usr/home/reddawg/source/hybos/src/kernel/debug.c:17 +001001cc T dump_regs /usr/home/reddawg/source/hybos/src/kernel/debug.c:44 +00100250 T keyDown /usr/home/reddawg/source/hybos/src/esh/esh.c:44 +00100258 T keyUp /usr/home/reddawg/source/hybos/src/esh/esh.c:58 +00100260 T initCommands /usr/home/reddawg/source/hybos/src/esh/esh.c:63 +00100434 T mapCommand /usr/home/reddawg/source/hybos/src/esh/esh.c:118 +001004b4 T isParam /usr/home/reddawg/source/hybos/src/esh/esh.c:162 +00100508 T mapParams /usr/home/reddawg/source/hybos/src/esh/esh.c:185 +0010064c T processCommand /usr/home/reddawg/source/hybos/src/esh/esh.c:264 +001007e4 t reboot /usr/home/reddawg/source/hybos/src/kernel/keyboard.c:58 +0010082c t _write_kb /usr/home/reddawg/source/hybos/src/kernel/keyboard.c:99 +00100874 T _translate_sc /usr/home/reddawg/source/hybos/src/kernel/keyboard.c:149 +00101298 T handle_meta_key /usr/home/reddawg/source/hybos/src/kernel/keyboard.c:364 +0010131c T keyboard_irq /usr/home/reddawg/source/hybos/src/kernel/keyboard.c:414 +0010157c T init_keyboard /usr/home/reddawg/source/hybos/src/kernel/keyboard.c:555 +00101640 T entry +00101657 t ds_ok +00101673 t sbat +00101697 t do_idt +001016c8 t mboot +001016e8 t all_ints +001016f7 T _getvect +001016f7 T getvect +00101731 T _setvect +00101731 T setvect +0010176b t isr0 +00101785 t isr0.1 +00101791 t isr1 +001017ab t isr1.1 +001017b7 t isr2 +001017d1 t isr2.1 +001017dd t isr3 +001017f7 t isr3.1 +00101803 t isr4 +0010181d t isr4.1 +00101829 t isr5 +00101843 t isr5.1 +0010184f t isr6 +00101869 t isr6.1 +00101875 t isr7 +0010188f t isr7.1 +0010189b t isr8 +001018b5 t isr8.1 +001018c1 t isr9 +001018db t isr9.1 +001018e7 t isr0Ah +00101901 t isr0Ah.1 +0010190d t isr0Bh +00101927 t isr0Bh.1 +00101933 t isr0Ch +0010194d t isr0Ch.1 +00101959 t isr0Dh +00101973 t isr0Dh.1 +0010197f t isr0Eh +00101999 t isr0Eh.1 +001019a5 t isr0Fh +001019bf t isr0Fh.1 +001019cb t isr10h +001019e5 t isr10h.1 +001019f1 t isr11h +00101a0b t isr11h.1 +00101a17 t isr12h +00101a31 t isr12h.1 +00101a3d t isr13h +00101a57 t isr13h.1 +00101a63 t isr14h +00101a7d t isr14h.1 +00101a89 t isr15h +00101aa3 t isr15h.1 +00101aaf t isr16h +00101ac9 t isr16h.1 +00101ad5 t isr17h +00101aef t isr17h.1 +00101afb t isr18h +00101b15 t isr18h.1 +00101b21 t isr19h +00101b3b t isr19h.1 +00101b47 t isr1Ah +00101b61 t isr1Ah.1 +00101b6d t isr1Bh +00101b87 t isr1Bh.1 +00101b93 t isr1Ch +00101bad t isr1Ch.1 +00101bb9 t isr1Dh +00101bd3 t isr1Dh.1 +00101bdf t isr1Eh +00101bf9 t isr1Eh.1 +00101c05 t isr1Fh +00101c1f t isr1Fh.1 +00101c2b t isr20h +00101c45 t isr20h.1 +00101c51 t isr21h +00101c6b t isr21h.1 +00101c77 t isr22h +00101c91 t isr22h.1 +00101c9d t isr23h +00101cb7 t isr23h.1 +00101cc3 t isr24h +00101cdd t isr24h.1 +00101ce9 t isr25h +00101d03 t isr25h.1 +00101d0f t isr26h +00101d29 t isr26h.1 +00101d35 t isr27h +00101d4f t isr27h.1 +00101d5b t isr28h +00101d75 t isr28h.1 +00101d81 t isr29h +00101d9b t isr29h.1 +00101da7 t isr2Ah +00101dc1 t isr2Ah.1 +00101dcd t isr2Bh +00101de7 t isr2Bh.1 +00101df3 t isr2Ch +00101e0d t isr2Ch.1 +00101e19 t isr2Dh +00101e33 t isr2Dh.1 +00101e3f t isr2Eh +00101e59 t isr2Eh.1 +00101e65 t isr2Fh +00101e7f t isr2Fh.1 +00101e8b t isr30h +00101ea5 t isr30h.1 +00101eb1 t isr49 +00101ecb t isr49.1 +00101ed7 t isr50 +00101ef1 t isr50.1 +00101efd t isr51 +00101f17 t isr51.1 +00101f23 t isr52 +00101f3d t isr52.1 +00101f49 t isr53 +00101f63 t isr53.1 +00101f6f t isr54 +00101f89 t isr54.1 +00101f95 t isr55 +00101faf t isr55.1 +00101fbb t isr56 +00101fd5 t isr56.1 +00101fe1 t isr57 +00101ffb t isr57.1 +00102007 t isr58 +00102021 t isr58.1 +0010202d t isr59 +00102047 t isr59.1 +00102053 t isr60 +0010206d t isr60.1 +00102079 t isr61 +00102093 t isr61.1 +0010209f t isr62 +001020b9 t isr62.1 +001020c5 t isr63 +001020df t isr63.1 +001020eb t isr64 +00102105 t isr64.1 +00102111 t isr65 +0010212b t isr65.1 +00102137 t isr66 +00102151 t isr66.1 +0010215d t isr67 +00102177 t isr67.1 +00102183 t isr68 +0010219d t isr68.1 +001021a9 t isr69 +001021c3 t isr69.1 +001021cf t isr70 +001021e9 t isr70.1 +001021f5 t isr71 +0010220f t isr71.1 +0010221b t isr72 +00102235 t isr72.1 +00102241 t isr73 +0010225b t isr73.1 +00102267 t isr74 +00102281 t isr74.1 +0010228d t isr75 +001022a7 t isr75.1 +001022b3 t isr76 +001022cd t isr76.1 +001022d9 t isr77 +001022f3 t isr77.1 +001022ff t isr78 +00102319 t isr78.1 +00102325 t isr79 +0010233f t isr79.1 +0010234b t isr80 +00102365 t isr80.1 +00102371 t isr81 +0010238b t isr81.1 +00102397 t isr82 +001023b1 t isr82.1 +001023bd t isr83 +001023d7 t isr83.1 +001023e3 t isr84 +001023fd t isr84.1 +00102409 t isr85 +00102423 t isr85.1 +0010242f t isr86 +00102449 t isr86.1 +00102455 t isr87 +0010246f t isr87.1 +0010247b t isr88 +00102495 t isr88.1 +001024a1 t isr89 +001024bb t isr89.1 +001024c7 t isr90 +001024e1 t isr90.1 +001024ed t isr91 +00102507 t isr91.1 +00102513 t isr92 +0010252d t isr92.1 +00102539 t isr93 +00102553 t isr93.1 +0010255f t isr94 +00102579 t isr94.1 +00102585 t isr95 +0010259f t isr95.1 +001025ab t isr96 +001025c5 t isr96.1 +001025d1 t isr97 +001025eb t isr97.1 +001025f7 t isr98 +00102611 t isr98.1 +0010261d t isr99 +00102637 t isr99.1 +00102643 t isr100 +0010265d t isr100.1 +00102669 t isr101 +00102683 t isr101.1 +0010268f t isr102 +001026a9 t isr102.1 +001026b5 t isr103 +001026cf t isr103.1 +001026db t isr104 +001026f5 t isr104.1 +00102701 t isr105 +0010271b t isr105.1 +00102727 t isr106 +00102741 t isr106.1 +0010274d t isr107 +00102767 t isr107.1 +00102773 t isr108 +0010278d t isr108.1 +00102799 t isr109 +001027b3 t isr109.1 +001027bf t isr110 +001027d9 t isr110.1 +001027e5 t isr111 +001027ff t isr111.1 +0010280b t isr112 +00102825 t isr112.1 +00102831 t isr113 +0010284b t isr113.1 +00102857 t isr114 +00102871 t isr114.1 +0010287d t isr115 +00102897 t isr115.1 +001028a3 t isr116 +001028bd t isr116.1 +001028c9 t isr117 +001028e3 t isr117.1 +001028ef t isr118 +00102909 t isr118.1 +00102915 t isr119 +0010292f t isr119.1 +0010293b t isr120 +00102955 t isr120.1 +00102961 t isr121 +0010297b t isr121.1 +00102987 t isr122 +001029a1 t isr122.1 +001029ad t isr123 +001029c7 t isr123.1 +001029d3 t isr124 +001029ed t isr124.1 +001029f9 t isr125 +00102a13 t isr125.1 +00102a1f t isr126 +00102a39 t isr126.1 +00102a45 t isr127 +00102a5f t isr127.1 +00102a6b t isr128 +00102a85 t isr128.1 +00102a91 t isr129 +00102aab t isr129.1 +00102ab7 t isr130 +00102ad1 t isr130.1 +00102add t isr131 +00102af7 t isr131.1 +00102b03 t isr132 +00102b1d t isr132.1 +00102b29 t isr133 +00102b43 t isr133.1 +00102b4f t isr134 +00102b69 t isr134.1 +00102b75 t isr135 +00102b8f t isr135.1 +00102b9b t isr136 +00102bb5 t isr136.1 +00102bc1 t isr137 +00102bdb t isr137.1 +00102be7 t isr138 +00102c01 t isr138.1 +00102c0d t isr139 +00102c27 t isr139.1 +00102c33 t isr140 +00102c4d t isr140.1 +00102c59 t isr141 +00102c73 t isr141.1 +00102c7f t isr142 +00102c99 t isr142.1 +00102ca5 t isr143 +00102cbf t isr143.1 +00102ccb t isr144 +00102ce5 t isr144.1 +00102cf1 t isr145 +00102d0b t isr145.1 +00102d17 t isr146 +00102d31 t isr146.1 +00102d3d t isr147 +00102d57 t isr147.1 +00102d63 t isr148 +00102d7d t isr148.1 +00102d89 t isr149 +00102da3 t isr149.1 +00102daf t isr150 +00102dc9 t isr150.1 +00102dd5 t isr151 +00102def t isr151.1 +00102dfb t isr152 +00102e15 t isr152.1 +00102e21 t isr153 +00102e3b t isr153.1 +00102e47 t isr154 +00102e61 t isr154.1 +00102e6d t isr155 +00102e87 t isr155.1 +00102e93 t isr156 +00102ead t isr156.1 +00102eb9 t isr157 +00102ed3 t isr157.1 +00102edf t isr158 +00102ef9 t isr158.1 +00102f05 t isr159 +00102f1f t isr159.1 +00102f2b t isr160 +00102f45 t isr160.1 +00102f51 t isr161 +00102f6b t isr161.1 +00102f77 t isr162 +00102f91 t isr162.1 +00102f9d t isr163 +00102fb7 t isr163.1 +00102fc3 t isr164 +00102fdd t isr164.1 +00102fe9 t isr165 +00103003 t isr165.1 +0010300f t isr166 +00103029 t isr166.1 +00103035 t isr167 +0010304f t isr167.1 +0010305b t isr168 +00103075 t isr168.1 +00103081 t isr169 +0010309b t isr169.1 +001030a7 t isr170 +001030c1 t isr170.1 +001030cd t isr171 +001030e7 t isr171.1 +001030f3 t isr172 +0010310d t isr172.1 +00103119 t isr173 +00103133 t isr173.1 +0010313f t isr174 +00103159 t isr174.1 +00103165 t isr175 +0010317f t isr175.1 +0010318b t isr176 +001031a5 t isr176.1 +001031b1 t isr177 +001031cb t isr177.1 +001031d7 t isr178 +001031f1 t isr178.1 +001031fd t isr179 +00103217 t isr179.1 +00103223 t isr180 +0010323d t isr180.1 +00103249 t isr181 +00103263 t isr181.1 +0010326f t isr182 +00103289 t isr182.1 +00103295 t isr183 +001032af t isr183.1 +001032bb t isr184 +001032d5 t isr184.1 +001032e1 t isr185 +001032fb t isr185.1 +00103307 t isr186 +00103321 t isr186.1 +0010332d t isr187 +00103347 t isr187.1 +00103353 t isr188 +0010336d t isr188.1 +00103379 t isr189 +00103393 t isr189.1 +0010339f t isr190 +001033b9 t isr190.1 +001033c5 t isr191 +001033df t isr191.1 +001033eb t isr192 +00103405 t isr192.1 +00103411 t isr193 +0010342b t isr193.1 +00103437 t isr194 +00103451 t isr194.1 +0010345d t isr195 +00103477 t isr195.1 +00103483 t isr196 +0010349d t isr196.1 +001034a9 t isr197 +001034c3 t isr197.1 +001034cf t isr198 +001034e9 t isr198.1 +001034f5 t isr199 +0010350f t isr199.1 +0010351b t isr200 +00103535 t isr200.1 +00103541 t isr201 +0010355b t isr201.1 +00103567 t isr202 +00103581 t isr202.1 +0010358d t isr203 +001035a7 t isr203.1 +001035b3 t isr204 +001035cd t isr204.1 +001035d9 t isr205 +001035f3 t isr205.1 +001035ff t isr206 +00103619 t isr206.1 +00103625 t isr207 +0010363f t isr207.1 +0010364b t isr208 +00103665 t isr208.1 +00103671 t isr209 +0010368b t isr209.1 +00103697 t isr210 +001036b1 t isr210.1 +001036bd t isr211 +001036d7 t isr211.1 +001036e3 t isr212 +001036fd t isr212.1 +00103709 t isr213 +00103723 t isr213.1 +0010372f t isr214 +00103749 t isr214.1 +00103755 t isr215 +0010376f t isr215.1 +0010377b t isr216 +00103795 t isr216.1 +001037a1 t isr217 +001037bb t isr217.1 +001037c7 t isr218 +001037e1 t isr218.1 +001037ed t isr219 +00103807 t isr219.1 +00103813 t isr220 +0010382d t isr220.1 +00103839 t isr221 +00103853 t isr221.1 +0010385f t isr222 +00103879 t isr222.1 +00103885 t isr223 +0010389f t isr223.1 +001038ab t isr224 +001038c5 t isr224.1 +001038d1 t isr225 +001038eb t isr225.1 +001038f7 t isr226 +00103911 t isr226.1 +0010391d t isr227 +00103937 t isr227.1 +00103943 t isr228 +0010395d t isr228.1 +00103969 t isr229 +00103983 t isr229.1 +0010398f t isr230 +001039a9 t isr230.1 +001039b5 t isr231 +001039cf t isr231.1 +001039db t isr232 +001039f5 t isr232.1 +00103a01 t isr233 +00103a1b t isr233.1 +00103a27 t isr234 +00103a41 t isr234.1 +00103a4d t isr235 +00103a67 t isr235.1 +00103a73 t isr236 +00103a8d t isr236.1 +00103a99 t isr237 +00103ab3 t isr237.1 +00103abf t isr238 +00103ad9 t isr238.1 +00103ae5 t isr239 +00103aff t isr239.1 +00103b0b t isr240 +00103b25 t isr240.1 +00103b31 t isr241 +00103b4b t isr241.1 +00103b57 t isr242 +00103b71 t isr242.1 +00103b7d t isr243 +00103b97 t isr243.1 +00103ba3 t isr244 +00103bbd t isr244.1 +00103bc9 t isr245 +00103be3 t isr245.1 +00103bef t isr246 +00103c09 t isr246.1 +00103c15 t isr247 +00103c2f t isr247.1 +00103c3b t isr248 +00103c55 t isr248.1 +00103c61 t isr249 +00103c7b t isr249.1 +00103c87 t isr250 +00103ca1 t isr250.1 +00103cad t isr251 +00103cc7 t isr251.1 +00103cd3 t isr252 +00103ced t isr252.1 +00103cf9 t isr253 +00103d13 t isr253.1 +00103d1f t isr254 +00103d39 t isr254.1 +00103d45 t isr255 +00103d5f t isr255.1 +00103d6c t kprintf_help /usr/home/reddawg/source/hybos/src/kernel/main.c:80 +00103d80 T kprintf /usr/home/reddawg/source/hybos/src/kernel/main.c:104 +00103d9c T printk /usr/home/reddawg/source/hybos/src/kernel/main.c:117 +00103db8 T panic /usr/home/reddawg/source/hybos/src/kernel/main.c:134 +00103e04 T fault /usr/home/reddawg/source/hybos/src/kernel/main.c:156 +00103e90 t init_8259s /usr/home/reddawg/source/hybos/src/kernel/main.c:248 +00103f14 t dump_heap /usr/home/reddawg/source/hybos/src/kernel/main.c:303 +0010401c T dumpheapk /usr/home/reddawg/source/hybos/src/kernel/main.c:339 +00104028 t kbrk /usr/home/reddawg/source/hybos/src/kernel/main.c:373 +00104080 T kmalloc /usr/home/reddawg/source/hybos/src/kernel/main.c:410 +001041b0 T kfree /usr/home/reddawg/source/hybos/src/kernel/main.c:518 +00104288 T testheap /usr/home/reddawg/source/hybos/src/kernel/main.c:585 +0010429c T krealloc /usr/home/reddawg/source/hybos/src/kernel/main.c:603 +00104324 T main /usr/home/reddawg/source/hybos/src/kernel/main.c:655 +00104424 T _mm_init /usr/home/reddawg/source/hybos/src/mm/memory.c:23 +0010445c T _mm_physical_init /usr/home/reddawg/source/hybos/src/mm/memory.c:31 +001044a4 T _mm_physical_alloc /usr/home/reddawg/source/hybos/src/mm/memory.c:50 +001044f4 T _mm_physical_free /usr/home/reddawg/source/hybos/src/mm/memory.c:75 +00104518 T _mm_virtual_init /usr/home/reddawg/source/hybos/src/mm/memory.c:80 +00104520 T _mm_page_copy_byte /usr/home/reddawg/source/hybos/src/mm/memory.c:84 +00104538 T _mm_page_copy_word /usr/home/reddawg/source/hybos/src/mm/memory.c:96 +00104550 T _mm_page_copy_dword /usr/home/reddawg/source/hybos/src/mm/memory.c:108 +00104568 T schedule /usr/home/reddawg/source/hybos/src/kernel/sched.c:91 +001045ac T init_tasks /usr/home/reddawg/source/hybos/src/kernel/sched.c:128 +001045f4 t write /usr/home/reddawg/source/hybos/src/kernel/tasks.c:31 +00104634 t yield /usr/home/reddawg/source/hybos/src/kernel/tasks.c:47 +00104640 t wait /usr/home/reddawg/source/hybos/src/kernel/tasks.c:57 +00104650 T task1 /usr/home/reddawg/source/hybos/src/kernel/tasks.c:69 +00104664 T task2 /usr/home/reddawg/source/hybos/src/kernel/tasks.c:88 +00104678 T task3 /usr/home/reddawg/source/hybos/src/kernel/tasks.c:106 +0010468c T task4 /usr/home/reddawg/source/hybos/src/kernel/tasks.c:124 +001046a0 T blink /usr/home/reddawg/source/hybos/src/kernel/video.c:51 +001046ac T get_current_vc /usr/home/reddawg/source/hybos/src/kernel/video.c:60 +001046b8 t scroll /usr/home/reddawg/source/hybos/src/kernel/video.c:69 +0010473c t set_attrib /usr/home/reddawg/source/hybos/src/kernel/video.c:101 +00104798 t move_csr /usr/home/reddawg/source/hybos/src/kernel/video.c:132 +00104804 T select_vc /usr/home/reddawg/source/hybos/src/kernel/video.c:149 +00104890 T putch_help /usr/home/reddawg/source/hybos/src/kernel/video.c:171 +00104b00 T putch /usr/home/reddawg/source/hybos/src/kernel/video.c:365 +00104b18 T init_video /usr/home/reddawg/source/hybos/src/kernel/video.c:377 +00104cc8 T disable /usr/home/reddawg/source/hybos/lib/x86/disable.c:4 +00104cd0 T do_printf /usr/home/reddawg/source/hybos/lib/stdio/doprintf.c:62 +0010500c T enable /usr/home/reddawg/source/hybos/lib/x86/enable.c:4 +00105014 T inportb /usr/home/reddawg/source/hybos/lib/x86/inportb.c:4 +00105020 T longjmp /usr/home/reddawg/source/hybos/lib/setjmp/longjmp.c:42 +0010505c T memcpy /usr/home/reddawg/source/hybos/lib/mem/memcpy.c:2 +00105088 T memsetw /usr/home/reddawg/source/hybos/lib/mem/memsetw.c:3 +001050b4 T outportb /usr/home/reddawg/source/hybos/lib/x86/outportb.c:4 +001050c0 T printf_help /usr/home/reddawg/source/hybos/lib/stdio/printf.c:14 +001050d4 T printf /usr/home/reddawg/source/hybos/lib/stdio/printf.c:25 +001050f0 T strcmp /usr/home/reddawg/source/hybos/lib/string/strcmp.c:2 +0010513c T strcpy /usr/home/reddawg/source/hybos/lib/string/strcpy.c:3 +00105158 T strlen /usr/home/reddawg/source/hybos/lib/string/strlen.c:5 +00105174 T strncpy /usr/home/reddawg/source/hybos/lib/string/strncpy.c:4 +00105b00 t ex.0 +00105d4c t irq0_int.1 +00105d50 t irq8_int.2 +001062e0 t ansi_to_vga.0 +00107000 D LS_Data +00107000 D _data +00107000 D data +00107000 d ds_magic +00107004 d gdt +00107024 d gdt_end +00107024 d gdt_ptr +0010702a d idt +0010782a d idt_end +0010782a d idt_ptr +00107840 D _ctype +00108000 B LS_Bss +00108000 B _bss +00108000 B bss +00108000 b altk.0 +00108020 b buffers.1 +00108320 b rawkey +00108340 b keys +00108540 b numkeysbuffer +00108560 b szInBuf +001085a0 b makebreak +001095a4 b stack +001095c0 b heap.3 +001836e0 b g_heap_bot +001836e4 b g_kbrk +001836e8 b g_heap_top +00183700 b current.0 +00183704 b entry.2 +00183704 b stacks.1 +00183720 b _tasks +00183a20 b _num_vcs +00183a24 b _curr_vc +00183a28 b _vga_fb_adr +00183a2c b _crtc_io_adr +00183a30 b _vc_width +00183a34 b _vc_height +00183a40 B eshCommands +00194280 B ts +00197280 B bufferIterator +00197284 B buffer +001972a0 B td +0019a2a0 B _curr_task +0019a2c0 B curr_vtty +0019a2e0 B _vc +0019b000 A _end +0019b000 A end +1badb002 a MULTIBOOT_HEADER_MAGIC +3544da2a a DS_MAGIC +e4514ffb a MULTIBOOT_CHECKSUM diff --git a/Dump/linecount.c b/Dump/linecount.c new file mode 100644 index 0000000..ebb844c --- /dev/null +++ b/Dump/linecount.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + int fd = 0x0; + int curcnt = 0x0; + int maxcnt = 0x0; + char c; + + if (argc < 2) { + printf("Error: No file specified\n"); + exit(0x0); + } + + fd = open(argv[1],O_RDONLY); + + if (fd == 0x0) { + printf("Error: Not a valid file: [%s]\n",argv[1]); + exit(0x0); + } + + curcnt = 0; + maxcnt = 0; + printf("File opened...\n"); + + while (read(fd,&c,1) != 0x0) { + if (c == 0x0C) { + printf("linefeed found!\n\tcurcnt = %i\n\tmaxcnt = %i\n", curcnt, maxcnt); + if (curcnt > maxcnt) + maxcnt = curcnt; + curcnt = 0; + } + else if (c == 0x0D) { + read(fd,&c,1); + if (c = 0x0A) + curcnt++; + printf("DDD"); + } + } + close(fd); + printf("Max line count is: %i\n", maxcnt); + return(0x0); + } diff --git a/Dump/linecount2.c b/Dump/linecount2.c new file mode 100644 index 0000000..8b17e94 --- /dev/null +++ b/Dump/linecount2.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + int fd = 0x0; + int curcnt = 0x1; + int maxcnt = 0x0; + char c; + + if (argc < 2) { + printf("Error: No file specified\n"); + exit(0x0); + } + + fd = open(argv[1],O_RDONLY); + + if (fd == 0x0) { + printf("Error: Not a valid file: [%s]\n",argv[1]); + exit(0x0); + } + + printf("File opened...\n"); + + while (read(fd,&c,1) != 0x0) { + if (c == 0x0C) { + if (curcnt > maxcnt) + maxcnt = curcnt; + curcnt = 1; + } + else if (c == 0x0A) + curcnt++; + } + close(fd); + printf("Max line count is: %i\n", maxcnt); + return(0x0); + } diff --git a/Dump/linecount3.c b/Dump/linecount3.c new file mode 100644 index 0000000..8b17e94 --- /dev/null +++ b/Dump/linecount3.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + int fd = 0x0; + int curcnt = 0x1; + int maxcnt = 0x0; + char c; + + if (argc < 2) { + printf("Error: No file specified\n"); + exit(0x0); + } + + fd = open(argv[1],O_RDONLY); + + if (fd == 0x0) { + printf("Error: Not a valid file: [%s]\n",argv[1]); + exit(0x0); + } + + printf("File opened...\n"); + + while (read(fd,&c,1) != 0x0) { + if (c == 0x0C) { + if (curcnt > maxcnt) + maxcnt = curcnt; + curcnt = 1; + } + else if (c == 0x0A) + curcnt++; + } + close(fd); + printf("Max line count is: %i\n", maxcnt); + return(0x0); + } diff --git a/Dump/ubix.elf b/Dump/ubix.elf new file mode 100644 index 0000000..0570158 --- /dev/null +++ b/Dump/ubix.elf Binary files differ diff --git a/Dump/ubix.flp b/Dump/ubix.flp new file mode 100644 index 0000000..750e409 --- /dev/null +++ b/Dump/ubix.flp Binary files differ diff --git a/Dump/ubix.img b/Dump/ubix.img new file mode 100644 index 0000000..3ca7f58 --- /dev/null +++ b/Dump/ubix.img Binary files differ diff --git a/Dump/ubthread.c b/Dump/ubthread.c new file mode 100644 index 0000000..d0ab762 --- /dev/null +++ b/Dump/ubthread.c @@ -0,0 +1,137 @@ +/***************************************************************************************** + Copyright (c) 2002 The UbixOS Project + All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of +conditions, the following disclaimer and the list of authors. Redistributions in binary +form must reproduce the above copyright notice, this list of conditions, the following +disclaimer and the list of authors in the documentation and/or other materials provided +with the distribution. Neither the name of the UbixOS Project nor the names of its +contributors may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + $Log: ubthread.c,v $ + Revision 1.7 2004/04/13 16:16:44 reddawg + Changed our copyright, it is all now under a BSD-Style license + + + + $Id: ubthread.c,v 1.7 2004/04/13 16:16:44 reddawg Exp $ + +*****************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct ubthread_cond_list *conds = 0x0; +struct ubthread_mutex_list *mutex = 0x0; + +kTask_t *ubthread_self() { + return(_current); + } + +int ubthread_cond_init(ubthread_cond_t *cond,const uInt32 attr) { + ubthread_cond_t ubcond = kmalloc(sizeof(struct ubthread_cond),sysID); + ubcond->id = (int)cond; + ubcond->locked = UNLOCKED; + *cond = ubcond; + return(0x0); + } + +int ubthread_mutex_init(ubthread_mutex_t *mutex,const uInt32 attr) { + ubthread_mutex_t ubmutex = kmalloc(sizeof(struct ubthread_mutex),sysID); + ubmutex->id = (int)mutex; + ubmutex->locked = UNLOCKED; + *mutex = ubmutex; + return(0x0); + } + +int ubthread_cond_destroy(ubthread_cond_t *cond) { + kfree(*cond); + *cond = 0x0; + return(0x0); + } + +int ubthread_mutex_destroy(ubthread_mutex_t *mutex) { + kfree(*mutex); + *mutex = 0x0; + return(0x0); + } + +int ubthread_create(kTask_t **thread,const uInt32 *attr,void *start_routine, void *arg) { + *thread = (void *)execThread((void *)start_routine,(uInt32)(kmalloc(0x4000,sysID)+0x4000),arg,"TCP/IP Thread"); + return(0x0); + } + +int ubthread_mutex_lock(ubthread_mutex_t *mutex) { + ubthread_mutex_t ubmutex = *mutex; + if (ubmutex->locked == LOCKED) { + kprintf("Mutex Already Lock By %x Trying To Be Relocked By %x\n",ubmutex->pid,_current->id); + } + while (ubmutex->locked == LOCKED); + ubmutex->locked = LOCKED; + ubmutex->pid = _current->id; + return(0x0); + } + +int ubthread_mutex_unlock(ubthread_mutex_t *mutex) { + ubthread_mutex_t ubmutex = *mutex; + if (ubmutex->pid == _current->id) { + ubmutex->locked = UNLOCKED; + return(0x0); + } + else { + kprintf("Trying To Unlock Mutex From No Locking Thread\n"); + ubmutex->locked = UNLOCKED; + return(-1); + } + } + +int ubthread_cond_timedwait(ubthread_cond_t *cond, ubthread_mutex_t *mutex, const struct timespec *abstime) { + ubthread_cond_t ubcond = *cond; + ubthread_mutex_t ubmutex = *mutex; + uInt32 enterTime = systemVitals->sysUptime+20; + while (enterTime > systemVitals->sysUptime) { + if (ubcond->locked == UNLOCKED) break; + schedYield(); + } + ubmutex->locked = UNLOCKED; + return(0x0); + } + +int ubthread_cond_wait(ubthread_cond_t *cond, ubthread_mutex_t *mutex) { + ubthread_cond_t ubcond = *cond; + ubthread_mutex_t ubmutex = *mutex; + while (ubcond->locked == 0x0); + ubmutex->locked = UNLOCKED; + return(0x0); + } + +int ubthread_cond_signal(ubthread_cond_t *cond) { + ubthread_cond_t ubcond = *cond; + ubcond->locked = UNLOCKED; + return(0x0); + } + +/*** + END + ***/ diff --git a/Dump/ufs/ffs/ffs_alloc.c b/Dump/ufs/ffs/ffs_alloc.c new file mode 100644 index 0000000..042d4e6 --- /dev/null +++ b/Dump/ufs/ffs/ffs_alloc.c @@ -0,0 +1,3237 @@ +/*- + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_alloc.c 8.18 (Berkeley) 5/26/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_alloc.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include "opt_quota.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef ufs2_daddr_t allocfcn_t(struct inode *ip, u_int cg, ufs2_daddr_t bpref, + int size, int rsize); + +static ufs2_daddr_t ffs_alloccg(struct inode *, u_int, ufs2_daddr_t, int, int); +static ufs2_daddr_t + ffs_alloccgblk(struct inode *, struct buf *, ufs2_daddr_t, int); +static void ffs_blkfree_cg(struct ufsmount *, struct fs *, + struct vnode *, ufs2_daddr_t, long, ino_t, + struct workhead *); +static void ffs_blkfree_trim_completed(struct bio *); +static void ffs_blkfree_trim_task(void *ctx, int pending __unused); +#ifdef INVARIANTS +static int ffs_checkblk(struct inode *, ufs2_daddr_t, long); +#endif +static ufs2_daddr_t ffs_clusteralloc(struct inode *, u_int, ufs2_daddr_t, int); +static ino_t ffs_dirpref(struct inode *); +static ufs2_daddr_t ffs_fragextend(struct inode *, u_int, ufs2_daddr_t, + int, int); +static ufs2_daddr_t ffs_hashalloc + (struct inode *, u_int, ufs2_daddr_t, int, int, allocfcn_t *); +static ufs2_daddr_t ffs_nodealloccg(struct inode *, u_int, ufs2_daddr_t, int, + int); +static ufs1_daddr_t ffs_mapsearch(struct fs *, struct cg *, ufs2_daddr_t, int); +static int ffs_reallocblks_ufs1(struct vop_reallocblks_args *); +static int ffs_reallocblks_ufs2(struct vop_reallocblks_args *); + +/* + * Allocate a block in the filesystem. + * + * The size of the requested block is given, which must be some + * multiple of fs_fsize and <= fs_bsize. + * A preference may be optionally specified. If a preference is given + * the following hierarchy is used to allocate a block: + * 1) allocate the requested block. + * 2) allocate a rotationally optimal block in the same cylinder. + * 3) allocate a block in the same cylinder group. + * 4) quadradically rehash into other cylinder groups, until an + * available block is located. + * If no block preference is given the following hierarchy is used + * to allocate a block: + * 1) allocate a block in the cylinder group that contains the + * inode for the file. + * 2) quadradically rehash into other cylinder groups, until an + * available block is located. + */ +int +ffs_alloc(ip, lbn, bpref, size, flags, cred, bnp) + struct inode *ip; + ufs2_daddr_t lbn, bpref; + int size, flags; + struct ucred *cred; + ufs2_daddr_t *bnp; +{ + struct fs *fs; + struct ufsmount *ump; + ufs2_daddr_t bno; + u_int cg, reclaimed; + static struct timeval lastfail; + static int curfail; + int64_t delta; +#ifdef QUOTA + int error; +#endif + + *bnp = 0; + ump = ITOUMP(ip); + fs = ump->um_fs; + mtx_assert(UFS_MTX(ump), MA_OWNED); +#ifdef INVARIANTS + if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) { + printf("dev = %s, bsize = %ld, size = %d, fs = %s\n", + devtoname(ump->um_dev), (long)fs->fs_bsize, size, + fs->fs_fsmnt); + panic("ffs_alloc: bad size"); + } + if (cred == NOCRED) + panic("ffs_alloc: missing credential"); +#endif /* INVARIANTS */ + reclaimed = 0; +retry: +#ifdef QUOTA + UFS_UNLOCK(ump); + error = chkdq(ip, btodb(size), cred, 0); + if (error) + return (error); + UFS_LOCK(ump); +#endif + if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) + goto nospace; + if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0) && + freespace(fs, fs->fs_minfree) - numfrags(fs, size) < 0) + goto nospace; + if (bpref >= fs->fs_size) + bpref = 0; + if (bpref == 0) + cg = ino_to_cg(fs, ip->i_number); + else + cg = dtog(fs, bpref); + bno = ffs_hashalloc(ip, cg, bpref, size, size, ffs_alloccg); + if (bno > 0) { + delta = btodb(size); + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); + if (flags & IO_EXT) + ip->i_flag |= IN_CHANGE; + else + ip->i_flag |= IN_CHANGE | IN_UPDATE; + *bnp = bno; + return (0); + } +nospace: +#ifdef QUOTA + UFS_UNLOCK(ump); + /* + * Restore user's disk quota because allocation failed. + */ + (void) chkdq(ip, -btodb(size), cred, FORCE); + UFS_LOCK(ump); +#endif + if (reclaimed == 0 && (flags & IO_BUFLOCKED) == 0) { + reclaimed = 1; + softdep_request_cleanup(fs, ITOV(ip), cred, FLUSH_BLOCKS_WAIT); + goto retry; + } + UFS_UNLOCK(ump); + if (reclaimed > 0 && ppsratecheck(&lastfail, &curfail, 1)) { + ffs_fserr(fs, ip->i_number, "filesystem full"); + uprintf("\n%s: write failed, filesystem is full\n", + fs->fs_fsmnt); + } + return (ENOSPC); +} + +/* + * Reallocate a fragment to a bigger size + * + * The number and size of the old block is given, and a preference + * and new size is also specified. The allocator attempts to extend + * the original block. Failing that, the regular block allocator is + * invoked to get an appropriate block. + */ +int +ffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, flags, cred, bpp) + struct inode *ip; + ufs2_daddr_t lbprev; + ufs2_daddr_t bprev; + ufs2_daddr_t bpref; + int osize, nsize, flags; + struct ucred *cred; + struct buf **bpp; +{ + struct vnode *vp; + struct fs *fs; + struct buf *bp; + struct ufsmount *ump; + u_int cg, request, reclaimed; + int error, gbflags; + ufs2_daddr_t bno; + static struct timeval lastfail; + static int curfail; + int64_t delta; + + vp = ITOV(ip); + ump = ITOUMP(ip); + fs = ump->um_fs; + bp = NULL; + gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; + + mtx_assert(UFS_MTX(ump), MA_OWNED); +#ifdef INVARIANTS + if (vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED) + panic("ffs_realloccg: allocation on suspended filesystem"); + if ((u_int)osize > fs->fs_bsize || fragoff(fs, osize) != 0 || + (u_int)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) { + printf( + "dev = %s, bsize = %ld, osize = %d, nsize = %d, fs = %s\n", + devtoname(ump->um_dev), (long)fs->fs_bsize, osize, + nsize, fs->fs_fsmnt); + panic("ffs_realloccg: bad size"); + } + if (cred == NOCRED) + panic("ffs_realloccg: missing credential"); +#endif /* INVARIANTS */ + reclaimed = 0; +retry: + if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0) && + freespace(fs, fs->fs_minfree) - numfrags(fs, nsize - osize) < 0) { + goto nospace; + } + if (bprev == 0) { + printf("dev = %s, bsize = %ld, bprev = %jd, fs = %s\n", + devtoname(ump->um_dev), (long)fs->fs_bsize, (intmax_t)bprev, + fs->fs_fsmnt); + panic("ffs_realloccg: bad bprev"); + } + UFS_UNLOCK(ump); + /* + * Allocate the extra space in the buffer. + */ + error = bread_gb(vp, lbprev, osize, NOCRED, gbflags, &bp); + if (error) { + brelse(bp); + return (error); + } + + if (bp->b_blkno == bp->b_lblkno) { + if (lbprev >= NDADDR) + panic("ffs_realloccg: lbprev out of range"); + bp->b_blkno = fsbtodb(fs, bprev); + } + +#ifdef QUOTA + error = chkdq(ip, btodb(nsize - osize), cred, 0); + if (error) { + brelse(bp); + return (error); + } +#endif + /* + * Check for extension in the existing location. + */ + *bpp = NULL; + cg = dtog(fs, bprev); + UFS_LOCK(ump); + bno = ffs_fragextend(ip, cg, bprev, osize, nsize); + if (bno) { + if (bp->b_blkno != fsbtodb(fs, bno)) + panic("ffs_realloccg: bad blockno"); + delta = btodb(nsize - osize); + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); + if (flags & IO_EXT) + ip->i_flag |= IN_CHANGE; + else + ip->i_flag |= IN_CHANGE | IN_UPDATE; + allocbuf(bp, nsize); + bp->b_flags |= B_DONE; + vfs_bio_bzero_buf(bp, osize, nsize - osize); + if ((bp->b_flags & (B_MALLOC | B_VMIO)) == B_VMIO) + vfs_bio_set_valid(bp, osize, nsize - osize); + *bpp = bp; + return (0); + } + /* + * Allocate a new disk location. + */ + if (bpref >= fs->fs_size) + bpref = 0; + switch ((int)fs->fs_optim) { + case FS_OPTSPACE: + /* + * Allocate an exact sized fragment. Although this makes + * best use of space, we will waste time relocating it if + * the file continues to grow. If the fragmentation is + * less than half of the minimum free reserve, we choose + * to begin optimizing for time. + */ + request = nsize; + if (fs->fs_minfree <= 5 || + fs->fs_cstotal.cs_nffree > + (off_t)fs->fs_dsize * fs->fs_minfree / (2 * 100)) + break; + log(LOG_NOTICE, "%s: optimization changed from SPACE to TIME\n", + fs->fs_fsmnt); + fs->fs_optim = FS_OPTTIME; + break; + case FS_OPTTIME: + /* + * At this point we have discovered a file that is trying to + * grow a small fragment to a larger fragment. To save time, + * we allocate a full sized block, then free the unused portion. + * If the file continues to grow, the `ffs_fragextend' call + * above will be able to grow it in place without further + * copying. If aberrant programs cause disk fragmentation to + * grow within 2% of the free reserve, we choose to begin + * optimizing for space. + */ + request = fs->fs_bsize; + if (fs->fs_cstotal.cs_nffree < + (off_t)fs->fs_dsize * (fs->fs_minfree - 2) / 100) + break; + log(LOG_NOTICE, "%s: optimization changed from TIME to SPACE\n", + fs->fs_fsmnt); + fs->fs_optim = FS_OPTSPACE; + break; + default: + printf("dev = %s, optim = %ld, fs = %s\n", + devtoname(ump->um_dev), (long)fs->fs_optim, fs->fs_fsmnt); + panic("ffs_realloccg: bad optim"); + /* NOTREACHED */ + } + bno = ffs_hashalloc(ip, cg, bpref, request, nsize, ffs_alloccg); + if (bno > 0) { + bp->b_blkno = fsbtodb(fs, bno); + if (!DOINGSOFTDEP(vp)) + ffs_blkfree(ump, fs, ump->um_devvp, bprev, (long)osize, + ip->i_number, vp->v_type, NULL); + delta = btodb(nsize - osize); + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + delta); + if (flags & IO_EXT) + ip->i_flag |= IN_CHANGE; + else + ip->i_flag |= IN_CHANGE | IN_UPDATE; + allocbuf(bp, nsize); + bp->b_flags |= B_DONE; + vfs_bio_bzero_buf(bp, osize, nsize - osize); + if ((bp->b_flags & (B_MALLOC | B_VMIO)) == B_VMIO) + vfs_bio_set_valid(bp, osize, nsize - osize); + *bpp = bp; + return (0); + } +#ifdef QUOTA + UFS_UNLOCK(ump); + /* + * Restore user's disk quota because allocation failed. + */ + (void) chkdq(ip, -btodb(nsize - osize), cred, FORCE); + UFS_LOCK(ump); +#endif +nospace: + /* + * no space available + */ + if (reclaimed == 0 && (flags & IO_BUFLOCKED) == 0) { + reclaimed = 1; + UFS_UNLOCK(ump); + if (bp) { + brelse(bp); + bp = NULL; + } + UFS_LOCK(ump); + softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT); + goto retry; + } + UFS_UNLOCK(ump); + if (bp) + brelse(bp); + if (reclaimed > 0 && ppsratecheck(&lastfail, &curfail, 1)) { + ffs_fserr(fs, ip->i_number, "filesystem full"); + uprintf("\n%s: write failed, filesystem is full\n", + fs->fs_fsmnt); + } + return (ENOSPC); +} + +/* + * Reallocate a sequence of blocks into a contiguous sequence of blocks. + * + * The vnode and an array of buffer pointers for a range of sequential + * logical blocks to be made contiguous is given. The allocator attempts + * to find a range of sequential blocks starting as close as possible + * from the end of the allocation for the logical block immediately + * preceding the current range. If successful, the physical block numbers + * in the buffer pointers and in the inode are changed to reflect the new + * allocation. If unsuccessful, the allocation is left unchanged. The + * success in doing the reallocation is returned. Note that the error + * return is not reflected back to the user. Rather the previous block + * allocation will be used. + */ + +SYSCTL_NODE(_vfs, OID_AUTO, ffs, CTLFLAG_RW, 0, "FFS filesystem"); + +static int doasyncfree = 1; +SYSCTL_INT(_vfs_ffs, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, +"do not force synchronous writes when blocks are reallocated"); + +static int doreallocblks = 1; +SYSCTL_INT(_vfs_ffs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, +"enable block reallocation"); + +static int maxclustersearch = 10; +SYSCTL_INT(_vfs_ffs, OID_AUTO, maxclustersearch, CTLFLAG_RW, &maxclustersearch, +0, "max number of cylinder group to search for contigous blocks"); + +#ifdef DEBUG +static volatile int prtrealloc = 0; +#endif + +int +ffs_reallocblks(ap) + struct vop_reallocblks_args /* { + struct vnode *a_vp; + struct cluster_save *a_buflist; + } */ *ap; +{ + struct ufsmount *ump; + + /* + * If the underlying device can do deletes, then skip reallocating + * the blocks of this file into contiguous sequences. Devices that + * benefit from BIO_DELETE also benefit from not moving the data. + * These devices are flash and therefore work less well with this + * optimization. Also skip if reallocblks has been disabled globally. + */ + ump = ap->a_vp->v_mount->mnt_data; + if (ump->um_candelete || doreallocblks == 0) + return (ENOSPC); + + /* + * We can't wait in softdep prealloc as it may fsync and recurse + * here. Instead we simply fail to reallocate blocks if this + * rare condition arises. + */ + if (DOINGSOFTDEP(ap->a_vp)) + if (softdep_prealloc(ap->a_vp, MNT_NOWAIT) != 0) + return (ENOSPC); + if (ump->um_fstype == UFS1) + return (ffs_reallocblks_ufs1(ap)); + return (ffs_reallocblks_ufs2(ap)); +} + +static int +ffs_reallocblks_ufs1(ap) + struct vop_reallocblks_args /* { + struct vnode *a_vp; + struct cluster_save *a_buflist; + } */ *ap; +{ + struct fs *fs; + struct inode *ip; + struct vnode *vp; + struct buf *sbp, *ebp; + ufs1_daddr_t *bap, *sbap, *ebap; + struct cluster_save *buflist; + struct ufsmount *ump; + ufs_lbn_t start_lbn, end_lbn; + ufs1_daddr_t soff, newblk, blkno; + ufs2_daddr_t pref; + struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; + int i, cg, len, start_lvl, end_lvl, ssize; + + vp = ap->a_vp; + ip = VTOI(vp); + ump = ITOUMP(ip); + fs = ump->um_fs; + /* + * If we are not tracking block clusters or if we have less than 4% + * free blocks left, then do not attempt to cluster. Running with + * less than 5% free block reserve is not recommended and those that + * choose to do so do not expect to have good file layout. + */ + if (fs->fs_contigsumsize <= 0 || freespace(fs, 4) < 0) + return (ENOSPC); + buflist = ap->a_buflist; + len = buflist->bs_nchildren; + start_lbn = buflist->bs_children[0]->b_lblkno; + end_lbn = start_lbn + len - 1; +#ifdef INVARIANTS + for (i = 0; i < len; i++) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 1"); + for (i = 1; i < len; i++) + if (buflist->bs_children[i]->b_lblkno != start_lbn + i) + panic("ffs_reallocblks: non-logical cluster"); + blkno = buflist->bs_children[0]->b_blkno; + ssize = fsbtodb(fs, fs->fs_frag); + for (i = 1; i < len - 1; i++) + if (buflist->bs_children[i]->b_blkno != blkno + (i * ssize)) + panic("ffs_reallocblks: non-physical cluster %d", i); +#endif + /* + * If the cluster crosses the boundary for the first indirect + * block, leave space for the indirect block. Indirect blocks + * are initially laid out in a position after the last direct + * block. Block reallocation would usually destroy locality by + * moving the indirect block out of the way to make room for + * data blocks if we didn't compensate here. We should also do + * this for other indirect block boundaries, but it is only + * important for the first one. + */ + if (start_lbn < NDADDR && end_lbn >= NDADDR) + return (ENOSPC); + /* + * If the latest allocation is in a new cylinder group, assume that + * the filesystem has decided to move and do not force it back to + * the previous cylinder group. + */ + if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != + dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) + return (ENOSPC); + if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) || + ufs_getlbns(vp, end_lbn, end_ap, &end_lvl)) + return (ENOSPC); + /* + * Get the starting offset and block map for the first block. + */ + if (start_lvl == 0) { + sbap = &ip->i_din1->di_db[0]; + soff = start_lbn; + } else { + idp = &start_ap[start_lvl - 1]; + if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &sbp)) { + brelse(sbp); + return (ENOSPC); + } + sbap = (ufs1_daddr_t *)sbp->b_data; + soff = idp->in_off; + } + /* + * If the block range spans two block maps, get the second map. + */ + ebap = NULL; + if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { + ssize = len; + } else { +#ifdef INVARIANTS + if (start_lvl > 0 && + start_ap[start_lvl - 1].in_lbn == idp->in_lbn) + panic("ffs_reallocblk: start == end"); +#endif + ssize = len - (idp->in_off + 1); + if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) + goto fail; + ebap = (ufs1_daddr_t *)ebp->b_data; + } + /* + * Find the preferred location for the cluster. If we have not + * previously failed at this endeavor, then follow our standard + * preference calculation. If we have failed at it, then pick up + * where we last ended our search. + */ + UFS_LOCK(ump); + if (ip->i_nextclustercg == -1) + pref = ffs_blkpref_ufs1(ip, start_lbn, soff, sbap); + else + pref = cgdata(fs, ip->i_nextclustercg); + /* + * Search the block map looking for an allocation of the desired size. + * To avoid wasting too much time, we limit the number of cylinder + * groups that we will search. + */ + cg = dtog(fs, pref); + for (i = min(maxclustersearch, fs->fs_ncg); i > 0; i--) { + if ((newblk = ffs_clusteralloc(ip, cg, pref, len)) != 0) + break; + cg += 1; + if (cg >= fs->fs_ncg) + cg = 0; + } + /* + * If we have failed in our search, record where we gave up for + * next time. Otherwise, fall back to our usual search citerion. + */ + if (newblk == 0) { + ip->i_nextclustercg = cg; + UFS_UNLOCK(ump); + goto fail; + } + ip->i_nextclustercg = -1; + /* + * We have found a new contiguous block. + * + * First we have to replace the old block pointers with the new + * block pointers in the inode and indirect blocks associated + * with the file. + */ +#ifdef DEBUG + if (prtrealloc) + printf("realloc: ino %ju, lbns %jd-%jd\n\told:", + (uintmax_t)ip->i_number, + (intmax_t)start_lbn, (intmax_t)end_lbn); +#endif + blkno = newblk; + for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { + if (i == ssize) { + bap = ebap; + soff = -i; + } +#ifdef INVARIANTS + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 2"); + if (dbtofsb(fs, buflist->bs_children[i]->b_blkno) != *bap) + panic("ffs_reallocblks: alloc mismatch"); +#endif +#ifdef DEBUG + if (prtrealloc) + printf(" %d,", *bap); +#endif + if (DOINGSOFTDEP(vp)) { + if (sbap == &ip->i_din1->di_db[0] && i < ssize) + softdep_setup_allocdirect(ip, start_lbn + i, + blkno, *bap, fs->fs_bsize, fs->fs_bsize, + buflist->bs_children[i]); + else + softdep_setup_allocindir_page(ip, start_lbn + i, + i < ssize ? sbp : ebp, soff + i, blkno, + *bap, buflist->bs_children[i]); + } + *bap++ = blkno; + } + /* + * Next we must write out the modified inode and indirect blocks. + * For strict correctness, the writes should be synchronous since + * the old block values may have been written to disk. In practise + * they are almost never written, but if we are concerned about + * strict correctness, the `doasyncfree' flag should be set to zero. + * + * The test on `doasyncfree' should be changed to test a flag + * that shows whether the associated buffers and inodes have + * been written. The flag should be set when the cluster is + * started and cleared whenever the buffer or inode is flushed. + * We can then check below to see if it is set, and do the + * synchronous write only when it has been cleared. + */ + if (sbap != &ip->i_din1->di_db[0]) { + if (doasyncfree) + bdwrite(sbp); + else + bwrite(sbp); + } else { + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (!doasyncfree) + ffs_update(vp, 1); + } + if (ssize < len) { + if (doasyncfree) + bdwrite(ebp); + else + bwrite(ebp); + } + /* + * Last, free the old blocks and assign the new blocks to the buffers. + */ +#ifdef DEBUG + if (prtrealloc) + printf("\n\tnew:"); +#endif + for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { + if (!DOINGSOFTDEP(vp)) + ffs_blkfree(ump, fs, ump->um_devvp, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), + fs->fs_bsize, ip->i_number, vp->v_type, NULL); + buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); +#ifdef INVARIANTS + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 3"); +#endif +#ifdef DEBUG + if (prtrealloc) + printf(" %d,", blkno); +#endif + } +#ifdef DEBUG + if (prtrealloc) { + prtrealloc--; + printf("\n"); + } +#endif + return (0); + +fail: + if (ssize < len) + brelse(ebp); + if (sbap != &ip->i_din1->di_db[0]) + brelse(sbp); + return (ENOSPC); +} + +static int +ffs_reallocblks_ufs2(ap) + struct vop_reallocblks_args /* { + struct vnode *a_vp; + struct cluster_save *a_buflist; + } */ *ap; +{ + struct fs *fs; + struct inode *ip; + struct vnode *vp; + struct buf *sbp, *ebp; + ufs2_daddr_t *bap, *sbap, *ebap; + struct cluster_save *buflist; + struct ufsmount *ump; + ufs_lbn_t start_lbn, end_lbn; + ufs2_daddr_t soff, newblk, blkno, pref; + struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; + int i, cg, len, start_lvl, end_lvl, ssize; + + vp = ap->a_vp; + ip = VTOI(vp); + ump = ITOUMP(ip); + fs = ump->um_fs; + /* + * If we are not tracking block clusters or if we have less than 4% + * free blocks left, then do not attempt to cluster. Running with + * less than 5% free block reserve is not recommended and those that + * choose to do so do not expect to have good file layout. + */ + if (fs->fs_contigsumsize <= 0 || freespace(fs, 4) < 0) + return (ENOSPC); + buflist = ap->a_buflist; + len = buflist->bs_nchildren; + start_lbn = buflist->bs_children[0]->b_lblkno; + end_lbn = start_lbn + len - 1; +#ifdef INVARIANTS + for (i = 0; i < len; i++) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 1"); + for (i = 1; i < len; i++) + if (buflist->bs_children[i]->b_lblkno != start_lbn + i) + panic("ffs_reallocblks: non-logical cluster"); + blkno = buflist->bs_children[0]->b_blkno; + ssize = fsbtodb(fs, fs->fs_frag); + for (i = 1; i < len - 1; i++) + if (buflist->bs_children[i]->b_blkno != blkno + (i * ssize)) + panic("ffs_reallocblks: non-physical cluster %d", i); +#endif + /* + * If the cluster crosses the boundary for the first indirect + * block, do not move anything in it. Indirect blocks are + * usually initially laid out in a position between the data + * blocks. Block reallocation would usually destroy locality by + * moving the indirect block out of the way to make room for + * data blocks if we didn't compensate here. We should also do + * this for other indirect block boundaries, but it is only + * important for the first one. + */ + if (start_lbn < NDADDR && end_lbn >= NDADDR) + return (ENOSPC); + /* + * If the latest allocation is in a new cylinder group, assume that + * the filesystem has decided to move and do not force it back to + * the previous cylinder group. + */ + if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != + dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) + return (ENOSPC); + if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) || + ufs_getlbns(vp, end_lbn, end_ap, &end_lvl)) + return (ENOSPC); + /* + * Get the starting offset and block map for the first block. + */ + if (start_lvl == 0) { + sbap = &ip->i_din2->di_db[0]; + soff = start_lbn; + } else { + idp = &start_ap[start_lvl - 1]; + if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &sbp)) { + brelse(sbp); + return (ENOSPC); + } + sbap = (ufs2_daddr_t *)sbp->b_data; + soff = idp->in_off; + } + /* + * If the block range spans two block maps, get the second map. + */ + ebap = NULL; + if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { + ssize = len; + } else { +#ifdef INVARIANTS + if (start_lvl > 0 && + start_ap[start_lvl - 1].in_lbn == idp->in_lbn) + panic("ffs_reallocblk: start == end"); +#endif + ssize = len - (idp->in_off + 1); + if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) + goto fail; + ebap = (ufs2_daddr_t *)ebp->b_data; + } + /* + * Find the preferred location for the cluster. If we have not + * previously failed at this endeavor, then follow our standard + * preference calculation. If we have failed at it, then pick up + * where we last ended our search. + */ + UFS_LOCK(ump); + if (ip->i_nextclustercg == -1) + pref = ffs_blkpref_ufs2(ip, start_lbn, soff, sbap); + else + pref = cgdata(fs, ip->i_nextclustercg); + /* + * Search the block map looking for an allocation of the desired size. + * To avoid wasting too much time, we limit the number of cylinder + * groups that we will search. + */ + cg = dtog(fs, pref); + for (i = min(maxclustersearch, fs->fs_ncg); i > 0; i--) { + if ((newblk = ffs_clusteralloc(ip, cg, pref, len)) != 0) + break; + cg += 1; + if (cg >= fs->fs_ncg) + cg = 0; + } + /* + * If we have failed in our search, record where we gave up for + * next time. Otherwise, fall back to our usual search citerion. + */ + if (newblk == 0) { + ip->i_nextclustercg = cg; + UFS_UNLOCK(ump); + goto fail; + } + ip->i_nextclustercg = -1; + /* + * We have found a new contiguous block. + * + * First we have to replace the old block pointers with the new + * block pointers in the inode and indirect blocks associated + * with the file. + */ +#ifdef DEBUG + if (prtrealloc) + printf("realloc: ino %ju, lbns %jd-%jd\n\told:", (uintmax_t)ip->i_number, + (intmax_t)start_lbn, (intmax_t)end_lbn); +#endif + blkno = newblk; + for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { + if (i == ssize) { + bap = ebap; + soff = -i; + } +#ifdef INVARIANTS + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 2"); + if (dbtofsb(fs, buflist->bs_children[i]->b_blkno) != *bap) + panic("ffs_reallocblks: alloc mismatch"); +#endif +#ifdef DEBUG + if (prtrealloc) + printf(" %jd,", (intmax_t)*bap); +#endif + if (DOINGSOFTDEP(vp)) { + if (sbap == &ip->i_din2->di_db[0] && i < ssize) + softdep_setup_allocdirect(ip, start_lbn + i, + blkno, *bap, fs->fs_bsize, fs->fs_bsize, + buflist->bs_children[i]); + else + softdep_setup_allocindir_page(ip, start_lbn + i, + i < ssize ? sbp : ebp, soff + i, blkno, + *bap, buflist->bs_children[i]); + } + *bap++ = blkno; + } + /* + * Next we must write out the modified inode and indirect blocks. + * For strict correctness, the writes should be synchronous since + * the old block values may have been written to disk. In practise + * they are almost never written, but if we are concerned about + * strict correctness, the `doasyncfree' flag should be set to zero. + * + * The test on `doasyncfree' should be changed to test a flag + * that shows whether the associated buffers and inodes have + * been written. The flag should be set when the cluster is + * started and cleared whenever the buffer or inode is flushed. + * We can then check below to see if it is set, and do the + * synchronous write only when it has been cleared. + */ + if (sbap != &ip->i_din2->di_db[0]) { + if (doasyncfree) + bdwrite(sbp); + else + bwrite(sbp); + } else { + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (!doasyncfree) + ffs_update(vp, 1); + } + if (ssize < len) { + if (doasyncfree) + bdwrite(ebp); + else + bwrite(ebp); + } + /* + * Last, free the old blocks and assign the new blocks to the buffers. + */ +#ifdef DEBUG + if (prtrealloc) + printf("\n\tnew:"); +#endif + for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { + if (!DOINGSOFTDEP(vp)) + ffs_blkfree(ump, fs, ump->um_devvp, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), + fs->fs_bsize, ip->i_number, vp->v_type, NULL); + buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); +#ifdef INVARIANTS + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 3"); +#endif +#ifdef DEBUG + if (prtrealloc) + printf(" %jd,", (intmax_t)blkno); +#endif + } +#ifdef DEBUG + if (prtrealloc) { + prtrealloc--; + printf("\n"); + } +#endif + return (0); + +fail: + if (ssize < len) + brelse(ebp); + if (sbap != &ip->i_din2->di_db[0]) + brelse(sbp); + return (ENOSPC); +} + +/* + * Allocate an inode in the filesystem. + * + * If allocating a directory, use ffs_dirpref to select the inode. + * If allocating in a directory, the following hierarchy is followed: + * 1) allocate the preferred inode. + * 2) allocate an inode in the same cylinder group. + * 3) quadradically rehash into other cylinder groups, until an + * available inode is located. + * If no inode preference is given the following hierarchy is used + * to allocate an inode: + * 1) allocate an inode in cylinder group 0. + * 2) quadradically rehash into other cylinder groups, until an + * available inode is located. + */ +int +ffs_valloc(pvp, mode, cred, vpp) + struct vnode *pvp; + int mode; + struct ucred *cred; + struct vnode **vpp; +{ + struct inode *pip; + struct fs *fs; + struct inode *ip; + struct timespec ts; + struct ufsmount *ump; + ino_t ino, ipref; + u_int cg; + int error, error1, reclaimed; + static struct timeval lastfail; + static int curfail; + + *vpp = NULL; + pip = VTOI(pvp); + ump = ITOUMP(pip); + fs = ump->um_fs; + + UFS_LOCK(ump); + reclaimed = 0; +retry: + if (fs->fs_cstotal.cs_nifree == 0) + goto noinodes; + + if ((mode & IFMT) == IFDIR) + ipref = ffs_dirpref(pip); + else + ipref = pip->i_number; + if (ipref >= fs->fs_ncg * fs->fs_ipg) + ipref = 0; + cg = ino_to_cg(fs, ipref); + /* + * Track number of dirs created one after another + * in a same cg without intervening by files. + */ + if ((mode & IFMT) == IFDIR) { + if (fs->fs_contigdirs[cg] < 255) + fs->fs_contigdirs[cg]++; + } else { + if (fs->fs_contigdirs[cg] > 0) + fs->fs_contigdirs[cg]--; + } + ino = (ino_t)ffs_hashalloc(pip, cg, ipref, mode, 0, + (allocfcn_t *)ffs_nodealloccg); + if (ino == 0) + goto noinodes; + error = ffs_vget(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); + if (error) { + error1 = ffs_vgetf(pvp->v_mount, ino, LK_EXCLUSIVE, vpp, + FFSV_FORCEINSMQ); + ffs_vfree(pvp, ino, mode); + if (error1 == 0) { + ip = VTOI(*vpp); + if (ip->i_mode) + goto dup_alloc; + ip->i_flag |= IN_MODIFIED; + vput(*vpp); + } + return (error); + } + ip = VTOI(*vpp); + if (ip->i_mode) { +dup_alloc: + printf("mode = 0%o, inum = %ju, fs = %s\n", + ip->i_mode, (uintmax_t)ip->i_number, fs->fs_fsmnt); + panic("ffs_valloc: dup alloc"); + } + if (DIP(ip, i_blocks) && (fs->fs_flags & FS_UNCLEAN) == 0) { /* XXX */ + printf("free inode %s/%lu had %ld blocks\n", + fs->fs_fsmnt, (u_long)ino, (long)DIP(ip, i_blocks)); + DIP_SET(ip, i_blocks, 0); + } + ip->i_flags = 0; + DIP_SET(ip, i_flags, 0); + /* + * Set up a new generation number for this inode. + */ + while (ip->i_gen == 0 || ++ip->i_gen == 0) + ip->i_gen = arc4random(); + DIP_SET(ip, i_gen, ip->i_gen); + if (fs->fs_magic == FS_UFS2_MAGIC) { + vfs_timestamp(&ts); + ip->i_din2->di_birthtime = ts.tv_sec; + ip->i_din2->di_birthnsec = ts.tv_nsec; + } + ufs_prepare_reclaim(*vpp); + ip->i_flag = 0; + (*vpp)->v_vflag = 0; + (*vpp)->v_type = VNON; + if (fs->fs_magic == FS_UFS2_MAGIC) { + (*vpp)->v_op = &ffs_vnodeops2; + ip->i_flag |= IN_UFS2; + } else { + (*vpp)->v_op = &ffs_vnodeops1; + } + return (0); +noinodes: + if (reclaimed == 0) { + reclaimed = 1; + softdep_request_cleanup(fs, pvp, cred, FLUSH_INODES_WAIT); + goto retry; + } + UFS_UNLOCK(ump); + if (ppsratecheck(&lastfail, &curfail, 1)) { + ffs_fserr(fs, pip->i_number, "out of inodes"); + uprintf("\n%s: create/symlink failed, no inodes free\n", + fs->fs_fsmnt); + } + return (ENOSPC); +} + +/* + * Find a cylinder group to place a directory. + * + * The policy implemented by this algorithm is to allocate a + * directory inode in the same cylinder group as its parent + * directory, but also to reserve space for its files inodes + * and data. Restrict the number of directories which may be + * allocated one after another in the same cylinder group + * without intervening allocation of files. + * + * If we allocate a first level directory then force allocation + * in another cylinder group. + */ +static ino_t +ffs_dirpref(pip) + struct inode *pip; +{ + struct fs *fs; + int cg, prefcg, dirsize, cgsize; + u_int avgifree, avgbfree, avgndir, curdirsize; + u_int minifree, minbfree, maxndir; + u_int mincg, minndir; + u_int maxcontigdirs; + + mtx_assert(UFS_MTX(ITOUMP(pip)), MA_OWNED); + fs = ITOFS(pip); + + avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; + avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; + avgndir = fs->fs_cstotal.cs_ndir / fs->fs_ncg; + + /* + * Force allocation in another cg if creating a first level dir. + */ + ASSERT_VOP_LOCKED(ITOV(pip), "ffs_dirpref"); + if (ITOV(pip)->v_vflag & VV_ROOT) { + prefcg = arc4random() % fs->fs_ncg; + mincg = prefcg; + minndir = fs->fs_ipg; + for (cg = prefcg; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_ndir < minndir && + fs->fs_cs(fs, cg).cs_nifree >= avgifree && + fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + mincg = cg; + minndir = fs->fs_cs(fs, cg).cs_ndir; + } + for (cg = 0; cg < prefcg; cg++) + if (fs->fs_cs(fs, cg).cs_ndir < minndir && + fs->fs_cs(fs, cg).cs_nifree >= avgifree && + fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + mincg = cg; + minndir = fs->fs_cs(fs, cg).cs_ndir; + } + return ((ino_t)(fs->fs_ipg * mincg)); + } + + /* + * Count various limits which used for + * optimal allocation of a directory inode. + */ + maxndir = min(avgndir + fs->fs_ipg / 16, fs->fs_ipg); + minifree = avgifree - avgifree / 4; + if (minifree < 1) + minifree = 1; + minbfree = avgbfree - avgbfree / 4; + if (minbfree < 1) + minbfree = 1; + cgsize = fs->fs_fsize * fs->fs_fpg; + dirsize = fs->fs_avgfilesize * fs->fs_avgfpdir; + curdirsize = avgndir ? (cgsize - avgbfree * fs->fs_bsize) / avgndir : 0; + if (dirsize < curdirsize) + dirsize = curdirsize; + if (dirsize <= 0) + maxcontigdirs = 0; /* dirsize overflowed */ + else + maxcontigdirs = min((avgbfree * fs->fs_bsize) / dirsize, 255); + if (fs->fs_avgfpdir > 0) + maxcontigdirs = min(maxcontigdirs, + fs->fs_ipg / fs->fs_avgfpdir); + if (maxcontigdirs == 0) + maxcontigdirs = 1; + + /* + * Limit number of dirs in one cg and reserve space for + * regular files, but only if we have no deficit in + * inodes or space. + * + * We are trying to find a suitable cylinder group nearby + * our preferred cylinder group to place a new directory. + * We scan from our preferred cylinder group forward looking + * for a cylinder group that meets our criterion. If we get + * to the final cylinder group and do not find anything, + * we start scanning forwards from the beginning of the + * filesystem. While it might seem sensible to start scanning + * backwards or even to alternate looking forward and backward, + * this approach fails badly when the filesystem is nearly full. + * Specifically, we first search all the areas that have no space + * and finally try the one preceding that. We repeat this on + * every request and in the case of the final block end up + * searching the entire filesystem. By jumping to the front + * of the filesystem, our future forward searches always look + * in new cylinder groups so finds every possible block after + * one pass over the filesystem. + */ + prefcg = ino_to_cg(fs, pip->i_number); + for (cg = prefcg; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_ndir < maxndir && + fs->fs_cs(fs, cg).cs_nifree >= minifree && + fs->fs_cs(fs, cg).cs_nbfree >= minbfree) { + if (fs->fs_contigdirs[cg] < maxcontigdirs) + return ((ino_t)(fs->fs_ipg * cg)); + } + for (cg = 0; cg < prefcg; cg++) + if (fs->fs_cs(fs, cg).cs_ndir < maxndir && + fs->fs_cs(fs, cg).cs_nifree >= minifree && + fs->fs_cs(fs, cg).cs_nbfree >= minbfree) { + if (fs->fs_contigdirs[cg] < maxcontigdirs) + return ((ino_t)(fs->fs_ipg * cg)); + } + /* + * This is a backstop when we have deficit in space. + */ + for (cg = prefcg; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_nifree >= avgifree) + return ((ino_t)(fs->fs_ipg * cg)); + for (cg = 0; cg < prefcg; cg++) + if (fs->fs_cs(fs, cg).cs_nifree >= avgifree) + break; + return ((ino_t)(fs->fs_ipg * cg)); +} + +/* + * Select the desired position for the next block in a file. The file is + * logically divided into sections. The first section is composed of the + * direct blocks and the next fs_maxbpg blocks. Each additional section + * contains fs_maxbpg blocks. + * + * If no blocks have been allocated in the first section, the policy is to + * request a block in the same cylinder group as the inode that describes + * the file. The first indirect is allocated immediately following the last + * direct block and the data blocks for the first indirect immediately + * follow it. + * + * If no blocks have been allocated in any other section, the indirect + * block(s) are allocated in the same cylinder group as its inode in an + * area reserved immediately following the inode blocks. The policy for + * the data blocks is to place them in a cylinder group with a greater than + * average number of free blocks. An appropriate cylinder group is found + * by using a rotor that sweeps the cylinder groups. When a new group of + * blocks is needed, the sweep begins in the cylinder group following the + * cylinder group from which the previous allocation was made. The sweep + * continues until a cylinder group with greater than the average number + * of free blocks is found. If the allocation is for the first block in an + * indirect block or the previous block is a hole, then the information on + * the previous allocation is unavailable; here a best guess is made based + * on the logical block number being allocated. + * + * If a section is already partially allocated, the policy is to + * allocate blocks contiguously within the section if possible. + */ +ufs2_daddr_t +ffs_blkpref_ufs1(ip, lbn, indx, bap) + struct inode *ip; + ufs_lbn_t lbn; + int indx; + ufs1_daddr_t *bap; +{ + struct fs *fs; + u_int cg, inocg; + u_int avgbfree, startcg; + ufs2_daddr_t pref; + + KASSERT(indx <= 0 || bap != NULL, ("need non-NULL bap")); + mtx_assert(UFS_MTX(ITOUMP(ip)), MA_OWNED); + fs = ITOFS(ip); + /* + * Allocation of indirect blocks is indicated by passing negative + * values in indx: -1 for single indirect, -2 for double indirect, + * -3 for triple indirect. As noted below, we attempt to allocate + * the first indirect inline with the file data. For all later + * indirect blocks, the data is often allocated in other cylinder + * groups. However to speed random file access and to speed up + * fsck, the filesystem reserves the first fs_metaspace blocks + * (typically half of fs_minfree) of the data area of each cylinder + * group to hold these later indirect blocks. + */ + inocg = ino_to_cg(fs, ip->i_number); + if (indx < 0) { + /* + * Our preference for indirect blocks is the zone at the + * beginning of the inode's cylinder group data area that + * we try to reserve for indirect blocks. + */ + pref = cgmeta(fs, inocg); + /* + * If we are allocating the first indirect block, try to + * place it immediately following the last direct block. + */ + if (indx == -1 && lbn < NDADDR + NINDIR(fs) && + ip->i_din1->di_db[NDADDR - 1] != 0) + pref = ip->i_din1->di_db[NDADDR - 1] + fs->fs_frag; + return (pref); + } + /* + * If we are allocating the first data block in the first indirect + * block and the indirect has been allocated in the data block area, + * try to place it immediately following the indirect block. + */ + if (lbn == NDADDR) { + pref = ip->i_din1->di_ib[0]; + if (pref != 0 && pref >= cgdata(fs, inocg) && + pref < cgbase(fs, inocg + 1)) + return (pref + fs->fs_frag); + } + /* + * If we are at the beginning of a file, or we have already allocated + * the maximum number of blocks per cylinder group, or we do not + * have a block allocated immediately preceding us, then we need + * to decide where to start allocating new blocks. + */ + if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { + /* + * If we are allocating a directory data block, we want + * to place it in the metadata area. + */ + if ((ip->i_mode & IFMT) == IFDIR) + return (cgmeta(fs, inocg)); + /* + * Until we fill all the direct and all the first indirect's + * blocks, we try to allocate in the data area of the inode's + * cylinder group. + */ + if (lbn < NDADDR + NINDIR(fs)) + return (cgdata(fs, inocg)); + /* + * Find a cylinder with greater than average number of + * unused data blocks. + */ + if (indx == 0 || bap[indx - 1] == 0) + startcg = inocg + lbn / fs->fs_maxbpg; + else + startcg = dtog(fs, bap[indx - 1]) + 1; + startcg %= fs->fs_ncg; + avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; + for (cg = startcg; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + fs->fs_cgrotor = cg; + return (cgdata(fs, cg)); + } + for (cg = 0; cg <= startcg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + fs->fs_cgrotor = cg; + return (cgdata(fs, cg)); + } + return (0); + } + /* + * Otherwise, we just always try to lay things out contiguously. + */ + return (bap[indx - 1] + fs->fs_frag); +} + +/* + * Same as above, but for UFS2 + */ +ufs2_daddr_t +ffs_blkpref_ufs2(ip, lbn, indx, bap) + struct inode *ip; + ufs_lbn_t lbn; + int indx; + ufs2_daddr_t *bap; +{ + struct fs *fs; + u_int cg, inocg; + u_int avgbfree, startcg; + ufs2_daddr_t pref; + + KASSERT(indx <= 0 || bap != NULL, ("need non-NULL bap")); + mtx_assert(UFS_MTX(ITOUMP(ip)), MA_OWNED); + fs = ITOFS(ip); + /* + * Allocation of indirect blocks is indicated by passing negative + * values in indx: -1 for single indirect, -2 for double indirect, + * -3 for triple indirect. As noted below, we attempt to allocate + * the first indirect inline with the file data. For all later + * indirect blocks, the data is often allocated in other cylinder + * groups. However to speed random file access and to speed up + * fsck, the filesystem reserves the first fs_metaspace blocks + * (typically half of fs_minfree) of the data area of each cylinder + * group to hold these later indirect blocks. + */ + inocg = ino_to_cg(fs, ip->i_number); + if (indx < 0) { + /* + * Our preference for indirect blocks is the zone at the + * beginning of the inode's cylinder group data area that + * we try to reserve for indirect blocks. + */ + pref = cgmeta(fs, inocg); + /* + * If we are allocating the first indirect block, try to + * place it immediately following the last direct block. + */ + if (indx == -1 && lbn < NDADDR + NINDIR(fs) && + ip->i_din2->di_db[NDADDR - 1] != 0) + pref = ip->i_din2->di_db[NDADDR - 1] + fs->fs_frag; + return (pref); + } + /* + * If we are allocating the first data block in the first indirect + * block and the indirect has been allocated in the data block area, + * try to place it immediately following the indirect block. + */ + if (lbn == NDADDR) { + pref = ip->i_din2->di_ib[0]; + if (pref != 0 && pref >= cgdata(fs, inocg) && + pref < cgbase(fs, inocg + 1)) + return (pref + fs->fs_frag); + } + /* + * If we are at the beginning of a file, or we have already allocated + * the maximum number of blocks per cylinder group, or we do not + * have a block allocated immediately preceding us, then we need + * to decide where to start allocating new blocks. + */ + if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { + /* + * If we are allocating a directory data block, we want + * to place it in the metadata area. + */ + if ((ip->i_mode & IFMT) == IFDIR) + return (cgmeta(fs, inocg)); + /* + * Until we fill all the direct and all the first indirect's + * blocks, we try to allocate in the data area of the inode's + * cylinder group. + */ + if (lbn < NDADDR + NINDIR(fs)) + return (cgdata(fs, inocg)); + /* + * Find a cylinder with greater than average number of + * unused data blocks. + */ + if (indx == 0 || bap[indx - 1] == 0) + startcg = inocg + lbn / fs->fs_maxbpg; + else + startcg = dtog(fs, bap[indx - 1]) + 1; + startcg %= fs->fs_ncg; + avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; + for (cg = startcg; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + fs->fs_cgrotor = cg; + return (cgdata(fs, cg)); + } + for (cg = 0; cg <= startcg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + fs->fs_cgrotor = cg; + return (cgdata(fs, cg)); + } + return (0); + } + /* + * Otherwise, we just always try to lay things out contiguously. + */ + return (bap[indx - 1] + fs->fs_frag); +} + +/* + * Implement the cylinder overflow algorithm. + * + * The policy implemented by this algorithm is: + * 1) allocate the block in its requested cylinder group. + * 2) quadradically rehash on the cylinder group number. + * 3) brute force search for a free block. + * + * Must be called with the UFS lock held. Will release the lock on success + * and return with it held on failure. + */ +/*VARARGS5*/ +static ufs2_daddr_t +ffs_hashalloc(ip, cg, pref, size, rsize, allocator) + struct inode *ip; + u_int cg; + ufs2_daddr_t pref; + int size; /* Search size for data blocks, mode for inodes */ + int rsize; /* Real allocated size. */ + allocfcn_t *allocator; +{ + struct fs *fs; + ufs2_daddr_t result; + u_int i, icg = cg; + + mtx_assert(UFS_MTX(ITOUMP(ip)), MA_OWNED); +#ifdef INVARIANTS + if (ITOV(ip)->v_mount->mnt_kern_flag & MNTK_SUSPENDED) + panic("ffs_hashalloc: allocation on suspended filesystem"); +#endif + fs = ITOFS(ip); + /* + * 1: preferred cylinder group + */ + result = (*allocator)(ip, cg, pref, size, rsize); + if (result) + return (result); + /* + * 2: quadratic rehash + */ + for (i = 1; i < fs->fs_ncg; i *= 2) { + cg += i; + if (cg >= fs->fs_ncg) + cg -= fs->fs_ncg; + result = (*allocator)(ip, cg, 0, size, rsize); + if (result) + return (result); + } + /* + * 3: brute force search + * Note that we start at i == 2, since 0 was checked initially, + * and 1 is always checked in the quadratic rehash. + */ + cg = (icg + 2) % fs->fs_ncg; + for (i = 2; i < fs->fs_ncg; i++) { + result = (*allocator)(ip, cg, 0, size, rsize); + if (result) + return (result); + cg++; + if (cg == fs->fs_ncg) + cg = 0; + } + return (0); +} + +/* + * Determine whether a fragment can be extended. + * + * Check to see if the necessary fragments are available, and + * if they are, allocate them. + */ +static ufs2_daddr_t +ffs_fragextend(ip, cg, bprev, osize, nsize) + struct inode *ip; + u_int cg; + ufs2_daddr_t bprev; + int osize, nsize; +{ + struct fs *fs; + struct cg *cgp; + struct buf *bp; + struct ufsmount *ump; + int nffree; + long bno; + int frags, bbase; + int i, error; + u_int8_t *blksfree; + + ump = ITOUMP(ip); + fs = ump->um_fs; + if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize)) + return (0); + frags = numfrags(fs, nsize); + bbase = fragnum(fs, bprev); + if (bbase > fragnum(fs, (bprev + frags - 1))) { + /* cannot extend across a block boundary */ + return (0); + } + UFS_UNLOCK(ump); + error = bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) + goto fail; + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) + goto fail; + bp->b_xflags |= BX_BKGRDWRITE; + cgp->cg_old_time = cgp->cg_time = time_second; + bno = dtogd(fs, bprev); + blksfree = cg_blksfree(cgp); + for (i = numfrags(fs, osize); i < frags; i++) + if (isclr(blksfree, bno + i)) + goto fail; + /* + * the current fragment can be extended + * deduct the count on fragment being extended into + * increase the count on the remaining fragment (if any) + * allocate the extended piece + */ + for (i = frags; i < fs->fs_frag - bbase; i++) + if (isclr(blksfree, bno + i)) + break; + cgp->cg_frsum[i - numfrags(fs, osize)]--; + if (i != frags) + cgp->cg_frsum[i - frags]++; + for (i = numfrags(fs, osize), nffree = 0; i < frags; i++) { + clrbit(blksfree, bno + i); + cgp->cg_cs.cs_nffree--; + nffree++; + } + UFS_LOCK(ump); + fs->fs_cstotal.cs_nffree -= nffree; + fs->fs_cs(fs, cg).cs_nffree -= nffree; + fs->fs_fmod = 1; + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + if (DOINGSOFTDEP(ITOV(ip))) + softdep_setup_blkmapdep(bp, UFSTOVFS(ump), bprev, + frags, numfrags(fs, osize)); + bdwrite(bp); + return (bprev); + +fail: + brelse(bp); + UFS_LOCK(ump); + return (0); + +} + +/* + * Determine whether a block can be allocated. + * + * Check to see if a block of the appropriate size is available, + * and if it is, allocate it. + */ +static ufs2_daddr_t +ffs_alloccg(ip, cg, bpref, size, rsize) + struct inode *ip; + u_int cg; + ufs2_daddr_t bpref; + int size; + int rsize; +{ + struct fs *fs; + struct cg *cgp; + struct buf *bp; + struct ufsmount *ump; + ufs1_daddr_t bno; + ufs2_daddr_t blkno; + int i, allocsiz, error, frags; + u_int8_t *blksfree; + + ump = ITOUMP(ip); + fs = ump->um_fs; + if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) + return (0); + UFS_UNLOCK(ump); + error = bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) + goto fail; + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp) || + (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) + goto fail; + bp->b_xflags |= BX_BKGRDWRITE; + cgp->cg_old_time = cgp->cg_time = time_second; + if (size == fs->fs_bsize) { + UFS_LOCK(ump); + blkno = ffs_alloccgblk(ip, bp, bpref, rsize); + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + bdwrite(bp); + return (blkno); + } + /* + * check to see if any fragments are already available + * allocsiz is the size which will be allocated, hacking + * it down to a smaller size if necessary + */ + blksfree = cg_blksfree(cgp); + frags = numfrags(fs, size); + for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) + if (cgp->cg_frsum[allocsiz] != 0) + break; + if (allocsiz == fs->fs_frag) { + /* + * no fragments were available, so a block will be + * allocated, and hacked up + */ + if (cgp->cg_cs.cs_nbfree == 0) + goto fail; + UFS_LOCK(ump); + blkno = ffs_alloccgblk(ip, bp, bpref, rsize); + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + bdwrite(bp); + return (blkno); + } + KASSERT(size == rsize, + ("ffs_alloccg: size(%d) != rsize(%d)", size, rsize)); + bno = ffs_mapsearch(fs, cgp, bpref, allocsiz); + if (bno < 0) + goto fail; + for (i = 0; i < frags; i++) + clrbit(blksfree, bno + i); + cgp->cg_cs.cs_nffree -= frags; + cgp->cg_frsum[allocsiz]--; + if (frags != allocsiz) + cgp->cg_frsum[allocsiz - frags]++; + UFS_LOCK(ump); + fs->fs_cstotal.cs_nffree -= frags; + fs->fs_cs(fs, cg).cs_nffree -= frags; + fs->fs_fmod = 1; + blkno = cgbase(fs, cg) + bno; + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + if (DOINGSOFTDEP(ITOV(ip))) + softdep_setup_blkmapdep(bp, UFSTOVFS(ump), blkno, frags, 0); + bdwrite(bp); + return (blkno); + +fail: + brelse(bp); + UFS_LOCK(ump); + return (0); +} + +/* + * Allocate a block in a cylinder group. + * + * This algorithm implements the following policy: + * 1) allocate the requested block. + * 2) allocate a rotationally optimal block in the same cylinder. + * 3) allocate the next available block on the block rotor for the + * specified cylinder group. + * Note that this routine only allocates fs_bsize blocks; these + * blocks may be fragmented by the routine that allocates them. + */ +static ufs2_daddr_t +ffs_alloccgblk(ip, bp, bpref, size) + struct inode *ip; + struct buf *bp; + ufs2_daddr_t bpref; + int size; +{ + struct fs *fs; + struct cg *cgp; + struct ufsmount *ump; + ufs1_daddr_t bno; + ufs2_daddr_t blkno; + u_int8_t *blksfree; + int i, cgbpref; + + ump = ITOUMP(ip); + fs = ump->um_fs; + mtx_assert(UFS_MTX(ump), MA_OWNED); + cgp = (struct cg *)bp->b_data; + blksfree = cg_blksfree(cgp); + if (bpref == 0) { + bpref = cgbase(fs, cgp->cg_cgx) + cgp->cg_rotor + fs->fs_frag; + } else if ((cgbpref = dtog(fs, bpref)) != cgp->cg_cgx) { + /* map bpref to correct zone in this cg */ + if (bpref < cgdata(fs, cgbpref)) + bpref = cgmeta(fs, cgp->cg_cgx); + else + bpref = cgdata(fs, cgp->cg_cgx); + } + /* + * if the requested block is available, use it + */ + bno = dtogd(fs, blknum(fs, bpref)); + if (ffs_isblock(fs, blksfree, fragstoblks(fs, bno))) + goto gotit; + /* + * Take the next available block in this cylinder group. + */ + bno = ffs_mapsearch(fs, cgp, bpref, (int)fs->fs_frag); + if (bno < 0) + return (0); + /* Update cg_rotor only if allocated from the data zone */ + if (bno >= dtogd(fs, cgdata(fs, cgp->cg_cgx))) + cgp->cg_rotor = bno; +gotit: + blkno = fragstoblks(fs, bno); + ffs_clrblock(fs, blksfree, (long)blkno); + ffs_clusteracct(fs, cgp, blkno, -1); + cgp->cg_cs.cs_nbfree--; + fs->fs_cstotal.cs_nbfree--; + fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; + fs->fs_fmod = 1; + blkno = cgbase(fs, cgp->cg_cgx) + bno; + /* + * If the caller didn't want the whole block free the frags here. + */ + size = numfrags(fs, size); + if (size != fs->fs_frag) { + bno = dtogd(fs, blkno); + for (i = size; i < fs->fs_frag; i++) + setbit(blksfree, bno + i); + i = fs->fs_frag - size; + cgp->cg_cs.cs_nffree += i; + fs->fs_cstotal.cs_nffree += i; + fs->fs_cs(fs, cgp->cg_cgx).cs_nffree += i; + fs->fs_fmod = 1; + cgp->cg_frsum[i]++; + } + /* XXX Fixme. */ + UFS_UNLOCK(ump); + if (DOINGSOFTDEP(ITOV(ip))) + softdep_setup_blkmapdep(bp, UFSTOVFS(ump), blkno, + size, 0); + UFS_LOCK(ump); + return (blkno); +} + +/* + * Determine whether a cluster can be allocated. + * + * We do not currently check for optimal rotational layout if there + * are multiple choices in the same cylinder group. Instead we just + * take the first one that we find following bpref. + */ +static ufs2_daddr_t +ffs_clusteralloc(ip, cg, bpref, len) + struct inode *ip; + u_int cg; + ufs2_daddr_t bpref; + int len; +{ + struct fs *fs; + struct cg *cgp; + struct buf *bp; + struct ufsmount *ump; + int i, run, bit, map, got; + ufs2_daddr_t bno; + u_char *mapp; + int32_t *lp; + u_int8_t *blksfree; + + ump = ITOUMP(ip); + fs = ump->um_fs; + if (fs->fs_maxcluster[cg] < len) + return (0); + UFS_UNLOCK(ump); + if (bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, + NOCRED, &bp)) + goto fail_lock; + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) + goto fail_lock; + bp->b_xflags |= BX_BKGRDWRITE; + /* + * Check to see if a cluster of the needed size (or bigger) is + * available in this cylinder group. + */ + lp = &cg_clustersum(cgp)[len]; + for (i = len; i <= fs->fs_contigsumsize; i++) + if (*lp++ > 0) + break; + if (i > fs->fs_contigsumsize) { + /* + * This is the first time looking for a cluster in this + * cylinder group. Update the cluster summary information + * to reflect the true maximum sized cluster so that + * future cluster allocation requests can avoid reading + * the cylinder group map only to find no clusters. + */ + lp = &cg_clustersum(cgp)[len - 1]; + for (i = len - 1; i > 0; i--) + if (*lp-- > 0) + break; + UFS_LOCK(ump); + fs->fs_maxcluster[cg] = i; + goto fail; + } + /* + * Search the cluster map to find a big enough cluster. + * We take the first one that we find, even if it is larger + * than we need as we prefer to get one close to the previous + * block allocation. We do not search before the current + * preference point as we do not want to allocate a block + * that is allocated before the previous one (as we will + * then have to wait for another pass of the elevator + * algorithm before it will be read). We prefer to fail and + * be recalled to try an allocation in the next cylinder group. + */ + if (dtog(fs, bpref) != cg) + bpref = cgdata(fs, cg); + else + bpref = blknum(fs, bpref); + bpref = fragstoblks(fs, dtogd(fs, bpref)); + mapp = &cg_clustersfree(cgp)[bpref / NBBY]; + map = *mapp++; + bit = 1 << (bpref % NBBY); + for (run = 0, got = bpref; got < cgp->cg_nclusterblks; got++) { + if ((map & bit) == 0) { + run = 0; + } else { + run++; + if (run == len) + break; + } + if ((got & (NBBY - 1)) != (NBBY - 1)) { + bit <<= 1; + } else { + map = *mapp++; + bit = 1; + } + } + if (got >= cgp->cg_nclusterblks) + goto fail_lock; + /* + * Allocate the cluster that we have found. + */ + blksfree = cg_blksfree(cgp); + for (i = 1; i <= len; i++) + if (!ffs_isblock(fs, blksfree, got - run + i)) + panic("ffs_clusteralloc: map mismatch"); + bno = cgbase(fs, cg) + blkstofrags(fs, got - run + 1); + if (dtog(fs, bno) != cg) + panic("ffs_clusteralloc: allocated out of group"); + len = blkstofrags(fs, len); + UFS_LOCK(ump); + for (i = 0; i < len; i += fs->fs_frag) + if (ffs_alloccgblk(ip, bp, bno + i, fs->fs_bsize) != bno + i) + panic("ffs_clusteralloc: lost block"); + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + bdwrite(bp); + return (bno); + +fail_lock: + UFS_LOCK(ump); +fail: + brelse(bp); + return (0); +} + +static inline struct buf * +getinobuf(struct inode *ip, u_int cg, u_int32_t cginoblk, int gbflags) +{ + struct fs *fs; + + fs = ITOFS(ip); + return (getblk(ITODEVVP(ip), fsbtodb(fs, ino_to_fsba(fs, + cg * fs->fs_ipg + cginoblk)), (int)fs->fs_bsize, 0, 0, + gbflags)); +} + +/* + * Synchronous inode initialization is needed only when barrier writes do not + * work as advertised, and will impose a heavy cost on file creation in a newly + * created filesystem. + */ +static int doasyncinodeinit = 1; +SYSCTL_INT(_vfs_ffs, OID_AUTO, doasyncinodeinit, CTLFLAG_RWTUN, + &doasyncinodeinit, 0, + "Perform inode block initialization using asynchronous writes"); + +/* + * Determine whether an inode can be allocated. + * + * Check to see if an inode is available, and if it is, + * allocate it using the following policy: + * 1) allocate the requested inode. + * 2) allocate the next available inode after the requested + * inode in the specified cylinder group. + */ +static ufs2_daddr_t +ffs_nodealloccg(ip, cg, ipref, mode, unused) + struct inode *ip; + u_int cg; + ufs2_daddr_t ipref; + int mode; + int unused; +{ + struct fs *fs; + struct cg *cgp; + struct buf *bp, *ibp; + struct ufsmount *ump; + u_int8_t *inosused, *loc; + struct ufs2_dinode *dp2; + int error, start, len, i; + u_int32_t old_initediblk; + + ump = ITOUMP(ip); + fs = ump->um_fs; +check_nifree: + if (fs->fs_cs(fs, cg).cs_nifree == 0) + return (0); + UFS_UNLOCK(ump); + error = bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) { + brelse(bp); + UFS_LOCK(ump); + return (0); + } + cgp = (struct cg *)bp->b_data; +restart: + if (!cg_chkmagic(cgp) || cgp->cg_cs.cs_nifree == 0) { + brelse(bp); + UFS_LOCK(ump); + return (0); + } + bp->b_xflags |= BX_BKGRDWRITE; + inosused = cg_inosused(cgp); + if (ipref) { + ipref %= fs->fs_ipg; + if (isclr(inosused, ipref)) + goto gotit; + } + start = cgp->cg_irotor / NBBY; + len = howmany(fs->fs_ipg - cgp->cg_irotor, NBBY); + loc = memcchr(&inosused[start], 0xff, len); + if (loc == NULL) { + len = start + 1; + start = 0; + loc = memcchr(&inosused[start], 0xff, len); + if (loc == NULL) { + printf("cg = %d, irotor = %ld, fs = %s\n", + cg, (long)cgp->cg_irotor, fs->fs_fsmnt); + panic("ffs_nodealloccg: map corrupted"); + /* NOTREACHED */ + } + } + ipref = (loc - inosused) * NBBY + ffs(~*loc) - 1; +gotit: + /* + * Check to see if we need to initialize more inodes. + */ + if (fs->fs_magic == FS_UFS2_MAGIC && + ipref + INOPB(fs) > cgp->cg_initediblk && + cgp->cg_initediblk < cgp->cg_niblk) { + old_initediblk = cgp->cg_initediblk; + + /* + * Free the cylinder group lock before writing the + * initialized inode block. Entering the + * babarrierwrite() with the cylinder group lock + * causes lock order violation between the lock and + * snaplk. + * + * Another thread can decide to initialize the same + * inode block, but whichever thread first gets the + * cylinder group lock after writing the newly + * allocated inode block will update it and the other + * will realize that it has lost and leave the + * cylinder group unchanged. + */ + ibp = getinobuf(ip, cg, old_initediblk, GB_LOCK_NOWAIT); + brelse(bp); + if (ibp == NULL) { + /* + * The inode block buffer is already owned by + * another thread, which must initialize it. + * Wait on the buffer to allow another thread + * to finish the updates, with dropped cg + * buffer lock, then retry. + */ + ibp = getinobuf(ip, cg, old_initediblk, 0); + brelse(ibp); + UFS_LOCK(ump); + goto check_nifree; + } + bzero(ibp->b_data, (int)fs->fs_bsize); + dp2 = (struct ufs2_dinode *)(ibp->b_data); + for (i = 0; i < INOPB(fs); i++) { + while (dp2->di_gen == 0) + dp2->di_gen = arc4random(); + dp2++; + } + + /* + * Rather than adding a soft updates dependency to ensure + * that the new inode block is written before it is claimed + * by the cylinder group map, we just do a barrier write + * here. The barrier write will ensure that the inode block + * gets written before the updated cylinder group map can be + * written. The barrier write should only slow down bulk + * loading of newly created filesystems. + */ + if (doasyncinodeinit) + babarrierwrite(ibp); + else + bwrite(ibp); + + /* + * After the inode block is written, try to update the + * cg initediblk pointer. If another thread beat us + * to it, then leave it unchanged as the other thread + * has already set it correctly. + */ + error = bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, NOCRED, &bp); + UFS_LOCK(ump); + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + if (error != 0) { + brelse(bp); + return (error); + } + cgp = (struct cg *)bp->b_data; + if (cgp->cg_initediblk == old_initediblk) + cgp->cg_initediblk += INOPB(fs); + goto restart; + } + cgp->cg_old_time = cgp->cg_time = time_second; + cgp->cg_irotor = ipref; + UFS_LOCK(ump); + ACTIVECLEAR(fs, cg); + setbit(inosused, ipref); + cgp->cg_cs.cs_nifree--; + fs->fs_cstotal.cs_nifree--; + fs->fs_cs(fs, cg).cs_nifree--; + fs->fs_fmod = 1; + if ((mode & IFMT) == IFDIR) { + cgp->cg_cs.cs_ndir++; + fs->fs_cstotal.cs_ndir++; + fs->fs_cs(fs, cg).cs_ndir++; + } + UFS_UNLOCK(ump); + if (DOINGSOFTDEP(ITOV(ip))) + softdep_setup_inomapdep(bp, ip, cg * fs->fs_ipg + ipref, mode); + bdwrite(bp); + return ((ino_t)(cg * fs->fs_ipg + ipref)); +} + +/* + * Free a block or fragment. + * + * The specified block or fragment is placed back in the + * free map. If a fragment is deallocated, a possible + * block reassembly is checked. + */ +static void +ffs_blkfree_cg(ump, fs, devvp, bno, size, inum, dephd) + struct ufsmount *ump; + struct fs *fs; + struct vnode *devvp; + ufs2_daddr_t bno; + long size; + ino_t inum; + struct workhead *dephd; +{ + struct mount *mp; + struct cg *cgp; + struct buf *bp; + ufs1_daddr_t fragno, cgbno; + ufs2_daddr_t cgblkno; + int i, blk, frags, bbase; + u_int cg; + u_int8_t *blksfree; + struct cdev *dev; + + cg = dtog(fs, bno); + if (devvp->v_type == VREG) { + /* devvp is a snapshot */ + MPASS(devvp->v_mount->mnt_data == ump); + dev = ump->um_devvp->v_rdev; + cgblkno = fragstoblks(fs, cgtod(fs, cg)); + } else if (devvp->v_type == VCHR) { + /* devvp is a normal disk device */ + dev = devvp->v_rdev; + cgblkno = fsbtodb(fs, cgtod(fs, cg)); + ASSERT_VOP_LOCKED(devvp, "ffs_blkfree_cg"); + } else + return; +#ifdef INVARIANTS + if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 || + fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) { + printf("dev=%s, bno = %jd, bsize = %ld, size = %ld, fs = %s\n", + devtoname(dev), (intmax_t)bno, (long)fs->fs_bsize, + size, fs->fs_fsmnt); + panic("ffs_blkfree_cg: bad size"); + } +#endif + if ((u_int)bno >= fs->fs_size) { + printf("bad block %jd, ino %lu\n", (intmax_t)bno, + (u_long)inum); + ffs_fserr(fs, inum, "bad block"); + return; + } + if (bread(devvp, cgblkno, (int)fs->fs_cgsize, NOCRED, &bp)) { + brelse(bp); + return; + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) { + brelse(bp); + return; + } + bp->b_xflags |= BX_BKGRDWRITE; + cgp->cg_old_time = cgp->cg_time = time_second; + cgbno = dtogd(fs, bno); + blksfree = cg_blksfree(cgp); + UFS_LOCK(ump); + if (size == fs->fs_bsize) { + fragno = fragstoblks(fs, cgbno); + if (!ffs_isfreeblock(fs, blksfree, fragno)) { + if (devvp->v_type == VREG) { + UFS_UNLOCK(ump); + /* devvp is a snapshot */ + brelse(bp); + return; + } + printf("dev = %s, block = %jd, fs = %s\n", + devtoname(dev), (intmax_t)bno, fs->fs_fsmnt); + panic("ffs_blkfree_cg: freeing free block"); + } + ffs_setblock(fs, blksfree, fragno); + ffs_clusteracct(fs, cgp, fragno, 1); + cgp->cg_cs.cs_nbfree++; + fs->fs_cstotal.cs_nbfree++; + fs->fs_cs(fs, cg).cs_nbfree++; + } else { + bbase = cgbno - fragnum(fs, cgbno); + /* + * decrement the counts associated with the old frags + */ + blk = blkmap(fs, blksfree, bbase); + ffs_fragacct(fs, blk, cgp->cg_frsum, -1); + /* + * deallocate the fragment + */ + frags = numfrags(fs, size); + for (i = 0; i < frags; i++) { + if (isset(blksfree, cgbno + i)) { + printf("dev = %s, block = %jd, fs = %s\n", + devtoname(dev), (intmax_t)(bno + i), + fs->fs_fsmnt); + panic("ffs_blkfree_cg: freeing free frag"); + } + setbit(blksfree, cgbno + i); + } + cgp->cg_cs.cs_nffree += i; + fs->fs_cstotal.cs_nffree += i; + fs->fs_cs(fs, cg).cs_nffree += i; + /* + * add back in counts associated with the new frags + */ + blk = blkmap(fs, blksfree, bbase); + ffs_fragacct(fs, blk, cgp->cg_frsum, 1); + /* + * if a complete block has been reassembled, account for it + */ + fragno = fragstoblks(fs, bbase); + if (ffs_isblock(fs, blksfree, fragno)) { + cgp->cg_cs.cs_nffree -= fs->fs_frag; + fs->fs_cstotal.cs_nffree -= fs->fs_frag; + fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; + ffs_clusteracct(fs, cgp, fragno, 1); + cgp->cg_cs.cs_nbfree++; + fs->fs_cstotal.cs_nbfree++; + fs->fs_cs(fs, cg).cs_nbfree++; + } + } + fs->fs_fmod = 1; + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + mp = UFSTOVFS(ump); + if (MOUNTEDSOFTDEP(mp) && devvp->v_type == VCHR) + softdep_setup_blkfree(UFSTOVFS(ump), bp, bno, + numfrags(fs, size), dephd); + bdwrite(bp); +} + +struct ffs_blkfree_trim_params { + struct task task; + struct ufsmount *ump; + struct vnode *devvp; + ufs2_daddr_t bno; + long size; + ino_t inum; + struct workhead *pdephd; + struct workhead dephd; +}; + +static void +ffs_blkfree_trim_task(ctx, pending) + void *ctx; + int pending; +{ + struct ffs_blkfree_trim_params *tp; + + tp = ctx; + ffs_blkfree_cg(tp->ump, tp->ump->um_fs, tp->devvp, tp->bno, tp->size, + tp->inum, tp->pdephd); + vn_finished_secondary_write(UFSTOVFS(tp->ump)); + atomic_add_int(&tp->ump->um_trim_inflight, -1); + free(tp, M_TEMP); +} + +static void +ffs_blkfree_trim_completed(bip) + struct bio *bip; +{ + struct ffs_blkfree_trim_params *tp; + + tp = bip->bio_caller2; + g_destroy_bio(bip); + TASK_INIT(&tp->task, 0, ffs_blkfree_trim_task, tp); + taskqueue_enqueue(tp->ump->um_trim_tq, &tp->task); +} + +void +ffs_blkfree(ump, fs, devvp, bno, size, inum, vtype, dephd) + struct ufsmount *ump; + struct fs *fs; + struct vnode *devvp; + ufs2_daddr_t bno; + long size; + ino_t inum; + enum vtype vtype; + struct workhead *dephd; +{ + struct mount *mp; + struct bio *bip; + struct ffs_blkfree_trim_params *tp; + + /* + * Check to see if a snapshot wants to claim the block. + * Check that devvp is a normal disk device, not a snapshot, + * it has a snapshot(s) associated with it, and one of the + * snapshots wants to claim the block. + */ + if (devvp->v_type == VCHR && + (devvp->v_vflag & VV_COPYONWRITE) && + ffs_snapblkfree(fs, devvp, bno, size, inum, vtype, dephd)) { + return; + } + /* + * Nothing to delay if TRIM is disabled, or the operation is + * performed on the snapshot. + */ + if (!ump->um_candelete || devvp->v_type == VREG) { + ffs_blkfree_cg(ump, fs, devvp, bno, size, inum, dephd); + return; + } + + /* + * Postpone the set of the free bit in the cg bitmap until the + * BIO_DELETE is completed. Otherwise, due to disk queue + * reordering, TRIM might be issued after we reuse the block + * and write some new data into it. + */ + atomic_add_int(&ump->um_trim_inflight, 1); + tp = malloc(sizeof(struct ffs_blkfree_trim_params), M_TEMP, M_WAITOK); + tp->ump = ump; + tp->devvp = devvp; + tp->bno = bno; + tp->size = size; + tp->inum = inum; + if (dephd != NULL) { + LIST_INIT(&tp->dephd); + LIST_SWAP(dephd, &tp->dephd, worklist, wk_list); + tp->pdephd = &tp->dephd; + } else + tp->pdephd = NULL; + + bip = g_alloc_bio(); + bip->bio_cmd = BIO_DELETE; + bip->bio_offset = dbtob(fsbtodb(fs, bno)); + bip->bio_done = ffs_blkfree_trim_completed; + bip->bio_length = size; + bip->bio_caller2 = tp; + + mp = UFSTOVFS(ump); + vn_start_secondary_write(NULL, &mp, 0); + g_io_request(bip, (struct g_consumer *)devvp->v_bufobj.bo_private); +} + +#ifdef INVARIANTS +/* + * Verify allocation of a block or fragment. Returns true if block or + * fragment is allocated, false if it is free. + */ +static int +ffs_checkblk(ip, bno, size) + struct inode *ip; + ufs2_daddr_t bno; + long size; +{ + struct fs *fs; + struct cg *cgp; + struct buf *bp; + ufs1_daddr_t cgbno; + int i, error, frags, free; + u_int8_t *blksfree; + + fs = ITOFS(ip); + if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) { + printf("bsize = %ld, size = %ld, fs = %s\n", + (long)fs->fs_bsize, size, fs->fs_fsmnt); + panic("ffs_checkblk: bad size"); + } + if ((u_int)bno >= fs->fs_size) + panic("ffs_checkblk: bad block %jd", (intmax_t)bno); + error = bread(ITODEVVP(ip), fsbtodb(fs, cgtod(fs, dtog(fs, bno))), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) + panic("ffs_checkblk: cg bread failed"); + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) + panic("ffs_checkblk: cg magic mismatch"); + bp->b_xflags |= BX_BKGRDWRITE; + blksfree = cg_blksfree(cgp); + cgbno = dtogd(fs, bno); + if (size == fs->fs_bsize) { + free = ffs_isblock(fs, blksfree, fragstoblks(fs, cgbno)); + } else { + frags = numfrags(fs, size); + for (free = 0, i = 0; i < frags; i++) + if (isset(blksfree, cgbno + i)) + free++; + if (free != 0 && free != frags) + panic("ffs_checkblk: partially free fragment"); + } + brelse(bp); + return (!free); +} +#endif /* INVARIANTS */ + +/* + * Free an inode. + */ +int +ffs_vfree(pvp, ino, mode) + struct vnode *pvp; + ino_t ino; + int mode; +{ + struct ufsmount *ump; + struct inode *ip; + + if (DOINGSOFTDEP(pvp)) { + softdep_freefile(pvp, ino, mode); + return (0); + } + ip = VTOI(pvp); + ump = VFSTOUFS(pvp->v_mount); + return (ffs_freefile(ump, ump->um_fs, ump->um_devvp, ino, mode, NULL)); +} + +/* + * Do the actual free operation. + * The specified inode is placed back in the free map. + */ +int +ffs_freefile(ump, fs, devvp, ino, mode, wkhd) + struct ufsmount *ump; + struct fs *fs; + struct vnode *devvp; + ino_t ino; + int mode; + struct workhead *wkhd; +{ + struct cg *cgp; + struct buf *bp; + ufs2_daddr_t cgbno; + int error; + u_int cg; + u_int8_t *inosused; + struct cdev *dev; + + cg = ino_to_cg(fs, ino); + if (devvp->v_type == VREG) { + /* devvp is a snapshot */ + MPASS(devvp->v_mount->mnt_data == ump); + dev = ump->um_devvp->v_rdev; + cgbno = fragstoblks(fs, cgtod(fs, cg)); + } else if (devvp->v_type == VCHR) { + /* devvp is a normal disk device */ + dev = devvp->v_rdev; + cgbno = fsbtodb(fs, cgtod(fs, cg)); + } else { + bp = NULL; + return (0); + } + if (ino >= fs->fs_ipg * fs->fs_ncg) + panic("ffs_freefile: range: dev = %s, ino = %ju, fs = %s", + devtoname(dev), (uintmax_t)ino, fs->fs_fsmnt); + if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) { + brelse(bp); + return (error); + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) { + brelse(bp); + return (0); + } + bp->b_xflags |= BX_BKGRDWRITE; + cgp->cg_old_time = cgp->cg_time = time_second; + inosused = cg_inosused(cgp); + ino %= fs->fs_ipg; + if (isclr(inosused, ino)) { + printf("dev = %s, ino = %ju, fs = %s\n", devtoname(dev), + (uintmax_t)(ino + cg * fs->fs_ipg), fs->fs_fsmnt); + if (fs->fs_ronly == 0) + panic("ffs_freefile: freeing free inode"); + } + clrbit(inosused, ino); + if (ino < cgp->cg_irotor) + cgp->cg_irotor = ino; + cgp->cg_cs.cs_nifree++; + UFS_LOCK(ump); + fs->fs_cstotal.cs_nifree++; + fs->fs_cs(fs, cg).cs_nifree++; + if ((mode & IFMT) == IFDIR) { + cgp->cg_cs.cs_ndir--; + fs->fs_cstotal.cs_ndir--; + fs->fs_cs(fs, cg).cs_ndir--; + } + fs->fs_fmod = 1; + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + if (MOUNTEDSOFTDEP(UFSTOVFS(ump)) && devvp->v_type == VCHR) + softdep_setup_inofree(UFSTOVFS(ump), bp, + ino + cg * fs->fs_ipg, wkhd); + bdwrite(bp); + return (0); +} + +/* + * Check to see if a file is free. + */ +int +ffs_checkfreefile(fs, devvp, ino) + struct fs *fs; + struct vnode *devvp; + ino_t ino; +{ + struct cg *cgp; + struct buf *bp; + ufs2_daddr_t cgbno; + int ret; + u_int cg; + u_int8_t *inosused; + + cg = ino_to_cg(fs, ino); + if (devvp->v_type == VREG) { + /* devvp is a snapshot */ + cgbno = fragstoblks(fs, cgtod(fs, cg)); + } else if (devvp->v_type == VCHR) { + /* devvp is a normal disk device */ + cgbno = fsbtodb(fs, cgtod(fs, cg)); + } else { + return (1); + } + if (ino >= fs->fs_ipg * fs->fs_ncg) + return (1); + if (bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp)) { + brelse(bp); + return (1); + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) { + brelse(bp); + return (1); + } + inosused = cg_inosused(cgp); + ino %= fs->fs_ipg; + ret = isclr(inosused, ino); + brelse(bp); + return (ret); +} + +/* + * Find a block of the specified size in the specified cylinder group. + * + * It is a panic if a request is made to find a block if none are + * available. + */ +static ufs1_daddr_t +ffs_mapsearch(fs, cgp, bpref, allocsiz) + struct fs *fs; + struct cg *cgp; + ufs2_daddr_t bpref; + int allocsiz; +{ + ufs1_daddr_t bno; + int start, len, loc, i; + int blk, field, subfield, pos; + u_int8_t *blksfree; + + /* + * find the fragment by searching through the free block + * map for an appropriate bit pattern + */ + if (bpref) + start = dtogd(fs, bpref) / NBBY; + else + start = cgp->cg_frotor / NBBY; + blksfree = cg_blksfree(cgp); + len = howmany(fs->fs_fpg, NBBY) - start; + loc = scanc((u_int)len, (u_char *)&blksfree[start], + fragtbl[fs->fs_frag], + (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); + if (loc == 0) { + len = start + 1; + start = 0; + loc = scanc((u_int)len, (u_char *)&blksfree[0], + fragtbl[fs->fs_frag], + (u_char)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); + if (loc == 0) { + printf("start = %d, len = %d, fs = %s\n", + start, len, fs->fs_fsmnt); + panic("ffs_alloccg: map corrupted"); + /* NOTREACHED */ + } + } + bno = (start + len - loc) * NBBY; + cgp->cg_frotor = bno; + /* + * found the byte in the map + * sift through the bits to find the selected frag + */ + for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { + blk = blkmap(fs, blksfree, bno); + blk <<= 1; + field = around[allocsiz]; + subfield = inside[allocsiz]; + for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { + if ((blk & field) == subfield) + return (bno + pos); + field <<= 1; + subfield <<= 1; + } + } + printf("bno = %lu, fs = %s\n", (u_long)bno, fs->fs_fsmnt); + panic("ffs_alloccg: block not in map"); + return (-1); +} + +/* + * Fserr prints the name of a filesystem with an error diagnostic. + * + * The form of the error message is: + * fs: error message + */ +void +ffs_fserr(fs, inum, cp) + struct fs *fs; + ino_t inum; + char *cp; +{ + struct thread *td = curthread; /* XXX */ + struct proc *p = td->td_proc; + + log(LOG_ERR, "pid %d (%s), uid %d inumber %ju on %s: %s\n", + p->p_pid, p->p_comm, td->td_ucred->cr_uid, (uintmax_t)inum, + fs->fs_fsmnt, cp); +} + +/* + * This function provides the capability for the fsck program to + * update an active filesystem. Fourteen operations are provided: + * + * adjrefcnt(inode, amt) - adjusts the reference count on the + * specified inode by the specified amount. Under normal + * operation the count should always go down. Decrementing + * the count to zero will cause the inode to be freed. + * adjblkcnt(inode, amt) - adjust the number of blocks used by the + * inode by the specified amount. + * adjndir, adjbfree, adjifree, adjffree, adjnumclusters(amt) - + * adjust the superblock summary. + * freedirs(inode, count) - directory inodes [inode..inode + count - 1] + * are marked as free. Inodes should never have to be marked + * as in use. + * freefiles(inode, count) - file inodes [inode..inode + count - 1] + * are marked as free. Inodes should never have to be marked + * as in use. + * freeblks(blockno, size) - blocks [blockno..blockno + size - 1] + * are marked as free. Blocks should never have to be marked + * as in use. + * setflags(flags, set/clear) - the fs_flags field has the specified + * flags set (second parameter +1) or cleared (second parameter -1). + * setcwd(dirinode) - set the current directory to dirinode in the + * filesystem associated with the snapshot. + * setdotdot(oldvalue, newvalue) - Verify that the inode number for ".." + * in the current directory is oldvalue then change it to newvalue. + * unlink(nameptr, oldvalue) - Verify that the inode number associated + * with nameptr in the current directory is oldvalue then unlink it. + * + * The following functions may only be used on a quiescent filesystem + * by the soft updates journal. They are not safe to be run on an active + * filesystem. + * + * setinode(inode, dip) - the specified disk inode is replaced with the + * contents pointed to by dip. + * setbufoutput(fd, flags) - output associated with the specified file + * descriptor (which must reference the character device supporting + * the filesystem) switches from using physio to running through the + * buffer cache when flags is set to 1. The descriptor reverts to + * physio for output when flags is set to zero. + */ + +static int sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS); + +SYSCTL_PROC(_vfs_ffs, FFS_ADJ_REFCNT, adjrefcnt, CTLFLAG_WR|CTLTYPE_STRUCT, + 0, 0, sysctl_ffs_fsck, "S,fsck", "Adjust Inode Reference Count"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_BLKCNT, adjblkcnt, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust Inode Used Blocks Count"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NDIR, adjndir, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of directories"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NBFREE, adjnbfree, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of free blocks"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NIFREE, adjnifree, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of free inodes"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NFFREE, adjnffree, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of free frags"); + +static SYSCTL_NODE(_vfs_ffs, FFS_ADJ_NUMCLUSTERS, adjnumclusters, CTLFLAG_WR, + sysctl_ffs_fsck, "Adjust number of free clusters"); + +static SYSCTL_NODE(_vfs_ffs, FFS_DIR_FREE, freedirs, CTLFLAG_WR, + sysctl_ffs_fsck, "Free Range of Directory Inodes"); + +static SYSCTL_NODE(_vfs_ffs, FFS_FILE_FREE, freefiles, CTLFLAG_WR, + sysctl_ffs_fsck, "Free Range of File Inodes"); + +static SYSCTL_NODE(_vfs_ffs, FFS_BLK_FREE, freeblks, CTLFLAG_WR, + sysctl_ffs_fsck, "Free Range of Blocks"); + +static SYSCTL_NODE(_vfs_ffs, FFS_SET_FLAGS, setflags, CTLFLAG_WR, + sysctl_ffs_fsck, "Change Filesystem Flags"); + +static SYSCTL_NODE(_vfs_ffs, FFS_SET_CWD, setcwd, CTLFLAG_WR, + sysctl_ffs_fsck, "Set Current Working Directory"); + +static SYSCTL_NODE(_vfs_ffs, FFS_SET_DOTDOT, setdotdot, CTLFLAG_WR, + sysctl_ffs_fsck, "Change Value of .. Entry"); + +static SYSCTL_NODE(_vfs_ffs, FFS_UNLINK, unlink, CTLFLAG_WR, + sysctl_ffs_fsck, "Unlink a Duplicate Name"); + +static SYSCTL_NODE(_vfs_ffs, FFS_SET_INODE, setinode, CTLFLAG_WR, + sysctl_ffs_fsck, "Update an On-Disk Inode"); + +static SYSCTL_NODE(_vfs_ffs, FFS_SET_BUFOUTPUT, setbufoutput, CTLFLAG_WR, + sysctl_ffs_fsck, "Set Buffered Writing for Descriptor"); + +#define DEBUG 1 +#ifdef DEBUG +static int fsckcmds = 0; +SYSCTL_INT(_debug, OID_AUTO, fsckcmds, CTLFLAG_RW, &fsckcmds, 0, ""); +#endif /* DEBUG */ + +static int buffered_write(struct file *, struct uio *, struct ucred *, + int, struct thread *); + +static int +sysctl_ffs_fsck(SYSCTL_HANDLER_ARGS) +{ + struct thread *td = curthread; + struct fsck_cmd cmd; + struct ufsmount *ump; + struct vnode *vp, *dvp, *fdvp; + struct inode *ip, *dp; + struct mount *mp; + struct fs *fs; + ufs2_daddr_t blkno; + long blkcnt, blksize; + struct file *fp, *vfp; + cap_rights_t rights; + int filetype, error; + static struct fileops *origops, bufferedops; + + if (req->newlen > sizeof cmd) + return (EBADRPC); + if ((error = SYSCTL_IN(req, &cmd, sizeof cmd)) != 0) + return (error); + if (cmd.version != FFS_CMD_VERSION) + return (ERPCMISMATCH); + if ((error = getvnode(td, cmd.handle, + cap_rights_init(&rights, CAP_FSCK), &fp)) != 0) + return (error); + vp = fp->f_data; + if (vp->v_type != VREG && vp->v_type != VDIR) { + fdrop(fp, td); + return (EINVAL); + } + vn_start_write(vp, &mp, V_WAIT); + if (mp == NULL || + strncmp(mp->mnt_stat.f_fstypename, "ufs", MFSNAMELEN)) { + vn_finished_write(mp); + fdrop(fp, td); + return (EINVAL); + } + ump = VFSTOUFS(mp); + if ((mp->mnt_flag & MNT_RDONLY) && + ump->um_fsckpid != td->td_proc->p_pid) { + vn_finished_write(mp); + fdrop(fp, td); + return (EROFS); + } + fs = ump->um_fs; + filetype = IFREG; + + switch (oidp->oid_number) { + + case FFS_SET_FLAGS: +#ifdef DEBUG + if (fsckcmds) + printf("%s: %s flags\n", mp->mnt_stat.f_mntonname, + cmd.size > 0 ? "set" : "clear"); +#endif /* DEBUG */ + if (cmd.size > 0) + fs->fs_flags |= (long)cmd.value; + else + fs->fs_flags &= ~(long)cmd.value; + break; + + case FFS_ADJ_REFCNT: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust inode %jd link count by %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value, + (intmax_t)cmd.size); + } +#endif /* DEBUG */ + if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) + break; + ip = VTOI(vp); + ip->i_nlink += cmd.size; + DIP_SET(ip, i_nlink, ip->i_nlink); + ip->i_effnlink += cmd.size; + ip->i_flag |= IN_CHANGE | IN_MODIFIED; + error = ffs_update(vp, 1); + if (DOINGSOFTDEP(vp)) + softdep_change_linkcnt(ip); + vput(vp); + break; + + case FFS_ADJ_BLKCNT: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust inode %jd block count by %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value, + (intmax_t)cmd.size); + } +#endif /* DEBUG */ + if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) + break; + ip = VTOI(vp); + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + cmd.size); + ip->i_flag |= IN_CHANGE | IN_MODIFIED; + error = ffs_update(vp, 1); + vput(vp); + break; + + case FFS_DIR_FREE: + filetype = IFDIR; + /* fall through */ + + case FFS_FILE_FREE: +#ifdef DEBUG + if (fsckcmds) { + if (cmd.size == 1) + printf("%s: free %s inode %ju\n", + mp->mnt_stat.f_mntonname, + filetype == IFDIR ? "directory" : "file", + (uintmax_t)cmd.value); + else + printf("%s: free %s inodes %ju-%ju\n", + mp->mnt_stat.f_mntonname, + filetype == IFDIR ? "directory" : "file", + (uintmax_t)cmd.value, + (uintmax_t)(cmd.value + cmd.size - 1)); + } +#endif /* DEBUG */ + while (cmd.size > 0) { + if ((error = ffs_freefile(ump, fs, ump->um_devvp, + cmd.value, filetype, NULL))) + break; + cmd.size -= 1; + cmd.value += 1; + } + break; + + case FFS_BLK_FREE: +#ifdef DEBUG + if (fsckcmds) { + if (cmd.size == 1) + printf("%s: free block %jd\n", + mp->mnt_stat.f_mntonname, + (intmax_t)cmd.value); + else + printf("%s: free blocks %jd-%jd\n", + mp->mnt_stat.f_mntonname, + (intmax_t)cmd.value, + (intmax_t)cmd.value + cmd.size - 1); + } +#endif /* DEBUG */ + blkno = cmd.value; + blkcnt = cmd.size; + blksize = fs->fs_frag - (blkno % fs->fs_frag); + while (blkcnt > 0) { + if (blksize > blkcnt) + blksize = blkcnt; + ffs_blkfree(ump, fs, ump->um_devvp, blkno, + blksize * fs->fs_fsize, ROOTINO, VDIR, NULL); + blkno += blksize; + blkcnt -= blksize; + blksize = fs->fs_frag; + } + break; + + /* + * Adjust superblock summaries. fsck(8) is expected to + * submit deltas when necessary. + */ + case FFS_ADJ_NDIR: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of directories by %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_ndir += cmd.value; + break; + + case FFS_ADJ_NBFREE: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of free blocks by %+jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_nbfree += cmd.value; + break; + + case FFS_ADJ_NIFREE: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of free inodes by %+jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_nifree += cmd.value; + break; + + case FFS_ADJ_NFFREE: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of free frags by %+jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_nffree += cmd.value; + break; + + case FFS_ADJ_NUMCLUSTERS: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: adjust number of free clusters by %+jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + fs->fs_cstotal.cs_numclusters += cmd.value; + break; + + case FFS_SET_CWD: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: set current directory to inode %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_SHARED, &vp))) + break; + AUDIT_ARG_VNODE1(vp); + if ((error = change_dir(vp, td)) != 0) { + vput(vp); + break; + } + VOP_UNLOCK(vp, 0); + pwd_chdir(td, vp); + break; + + case FFS_SET_DOTDOT: +#ifdef DEBUG + if (fsckcmds) { + printf("%s: change .. in cwd from %jd to %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value, + (intmax_t)cmd.size); + } +#endif /* DEBUG */ + /* + * First we have to get and lock the parent directory + * to which ".." points. + */ + error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &fdvp); + if (error) + break; + /* + * Now we get and lock the child directory containing "..". + */ + FILEDESC_SLOCK(td->td_proc->p_fd); + dvp = td->td_proc->p_fd->fd_cdir; + FILEDESC_SUNLOCK(td->td_proc->p_fd); + if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0) { + vput(fdvp); + break; + } + dp = VTOI(dvp); + dp->i_offset = 12; /* XXX mastertemplate.dot_reclen */ + error = ufs_dirrewrite(dp, VTOI(fdvp), (ino_t)cmd.size, + DT_DIR, 0); + cache_purge(fdvp); + cache_purge(dvp); + vput(dvp); + vput(fdvp); + break; + + case FFS_UNLINK: +#ifdef DEBUG + if (fsckcmds) { + char buf[32]; + + if (copyinstr((char *)(intptr_t)cmd.value, buf,32,NULL)) + strncpy(buf, "Name_too_long", 32); + printf("%s: unlink %s (inode %jd)\n", + mp->mnt_stat.f_mntonname, buf, (intmax_t)cmd.size); + } +#endif /* DEBUG */ + /* + * kern_unlinkat will do its own start/finish writes and + * they do not nest, so drop ours here. Setting mp == NULL + * indicates that vn_finished_write is not needed down below. + */ + vn_finished_write(mp); + mp = NULL; + error = kern_unlinkat(td, AT_FDCWD, (char *)(intptr_t)cmd.value, + UIO_USERSPACE, (ino_t)cmd.size); + break; + + case FFS_SET_INODE: + if (ump->um_fsckpid != td->td_proc->p_pid) { + error = EPERM; + break; + } +#ifdef DEBUG + if (fsckcmds) { + printf("%s: update inode %jd\n", + mp->mnt_stat.f_mntonname, (intmax_t)cmd.value); + } +#endif /* DEBUG */ + if ((error = ffs_vget(mp, (ino_t)cmd.value, LK_EXCLUSIVE, &vp))) + break; + AUDIT_ARG_VNODE1(vp); + ip = VTOI(vp); + if (I_IS_UFS1(ip)) + error = copyin((void *)(intptr_t)cmd.size, ip->i_din1, + sizeof(struct ufs1_dinode)); + else + error = copyin((void *)(intptr_t)cmd.size, ip->i_din2, + sizeof(struct ufs2_dinode)); + if (error) { + vput(vp); + break; + } + ip->i_flag |= IN_CHANGE | IN_MODIFIED; + error = ffs_update(vp, 1); + vput(vp); + break; + + case FFS_SET_BUFOUTPUT: + if (ump->um_fsckpid != td->td_proc->p_pid) { + error = EPERM; + break; + } + if (ITOUMP(VTOI(vp)) != ump) { + error = EINVAL; + break; + } +#ifdef DEBUG + if (fsckcmds) { + printf("%s: %s buffered output for descriptor %jd\n", + mp->mnt_stat.f_mntonname, + cmd.size == 1 ? "enable" : "disable", + (intmax_t)cmd.value); + } +#endif /* DEBUG */ + if ((error = getvnode(td, cmd.value, + cap_rights_init(&rights, CAP_FSCK), &vfp)) != 0) + break; + if (vfp->f_vnode->v_type != VCHR) { + fdrop(vfp, td); + error = EINVAL; + break; + } + if (origops == NULL) { + origops = vfp->f_ops; + bcopy((void *)origops, (void *)&bufferedops, + sizeof(bufferedops)); + bufferedops.fo_write = buffered_write; + } + if (cmd.size == 1) + atomic_store_rel_ptr((volatile uintptr_t *)&vfp->f_ops, + (uintptr_t)&bufferedops); + else + atomic_store_rel_ptr((volatile uintptr_t *)&vfp->f_ops, + (uintptr_t)origops); + fdrop(vfp, td); + break; + + default: +#ifdef DEBUG + if (fsckcmds) { + printf("Invalid request %d from fsck\n", + oidp->oid_number); + } +#endif /* DEBUG */ + error = EINVAL; + break; + + } + fdrop(fp, td); + vn_finished_write(mp); + return (error); +} + +/* + * Function to switch a descriptor to use the buffer cache to stage + * its I/O. This is needed so that writes to the filesystem device + * will give snapshots a chance to copy modified blocks for which it + * needs to retain copies. + */ +static int +buffered_write(fp, uio, active_cred, flags, td) + struct file *fp; + struct uio *uio; + struct ucred *active_cred; + int flags; + struct thread *td; +{ + struct vnode *devvp, *vp; + struct inode *ip; + struct buf *bp; + struct fs *fs; + struct filedesc *fdp; + int error; + daddr_t lbn; + + /* + * The devvp is associated with the /dev filesystem. To discover + * the filesystem with which the device is associated, we depend + * on the application setting the current directory to a location + * within the filesystem being written. Yes, this is an ugly hack. + */ + devvp = fp->f_vnode; + if (!vn_isdisk(devvp, NULL)) + return (EINVAL); + fdp = td->td_proc->p_fd; + FILEDESC_SLOCK(fdp); + vp = fdp->fd_cdir; + vref(vp); + FILEDESC_SUNLOCK(fdp); + vn_lock(vp, LK_SHARED | LK_RETRY); + /* + * Check that the current directory vnode indeed belongs to + * UFS before trying to dereference UFS-specific v_data fields. + */ + if (vp->v_op != &ffs_vnodeops1 && vp->v_op != &ffs_vnodeops2) { + vput(vp); + return (EINVAL); + } + ip = VTOI(vp); + if (ITODEVVP(ip) != devvp) { + vput(vp); + return (EINVAL); + } + fs = ITOFS(ip); + vput(vp); + foffset_lock_uio(fp, uio, flags); + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); +#ifdef DEBUG + if (fsckcmds) { + printf("%s: buffered write for block %jd\n", + fs->fs_fsmnt, (intmax_t)btodb(uio->uio_offset)); + } +#endif /* DEBUG */ + /* + * All I/O must be contained within a filesystem block, start on + * a fragment boundary, and be a multiple of fragments in length. + */ + if (uio->uio_resid > fs->fs_bsize - (uio->uio_offset % fs->fs_bsize) || + fragoff(fs, uio->uio_offset) != 0 || + fragoff(fs, uio->uio_resid) != 0) { + error = EINVAL; + goto out; + } + lbn = numfrags(fs, uio->uio_offset); + bp = getblk(devvp, lbn, uio->uio_resid, 0, 0, 0); + bp->b_flags |= B_RELBUF; + if ((error = uiomove((char *)bp->b_data, uio->uio_resid, uio)) != 0) { + brelse(bp); + goto out; + } + error = bwrite(bp); +out: + VOP_UNLOCK(devvp, 0); + foffset_unlock_uio(fp, uio, flags | FOF_NEXTOFF); + return (error); +} diff --git a/Dump/ufs/ffs/ffs_balloc.c b/Dump/ufs/ffs/ffs_balloc.c new file mode 100644 index 0000000..0aa2f40 --- /dev/null +++ b/Dump/ufs/ffs/ffs_balloc.c @@ -0,0 +1,1151 @@ +/*- + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_balloc.c 8.8 (Berkeley) 6/16/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_balloc.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* + * Balloc defines the structure of filesystem storage + * by allocating the physical blocks on a device given + * the inode and the logical block number in a file. + * This is the allocation strategy for UFS1. Below is + * the allocation strategy for UFS2. + */ +int +ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size, + struct ucred *cred, int flags, struct buf **bpp) +{ + struct inode *ip; + struct ufs1_dinode *dp; + ufs_lbn_t lbn, lastlbn; + struct fs *fs; + ufs1_daddr_t nb; + struct buf *bp, *nbp; + struct ufsmount *ump; + struct indir indirs[NIADDR + 2]; + int deallocated, osize, nsize, num, i, error; + ufs2_daddr_t newb; + ufs1_daddr_t *bap, pref; + ufs1_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; + ufs2_daddr_t *lbns_remfree, lbns[NIADDR + 1]; + int unwindidx = -1; + int saved_inbdflush; + static struct timeval lastfail; + static int curfail; + int gbflags, reclaimed; + + ip = VTOI(vp); + dp = ip->i_din1; + fs = ITOFS(ip); + ump = ITOUMP(ip); + lbn = lblkno(fs, startoffset); + size = blkoff(fs, startoffset) + size; + reclaimed = 0; + if (size > fs->fs_bsize) + panic("ffs_balloc_ufs1: blk too big"); + *bpp = NULL; + if (flags & IO_EXT) + return (EOPNOTSUPP); + if (lbn < 0) + return (EFBIG); + gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; + + if (DOINGSOFTDEP(vp)) + softdep_prealloc(vp, MNT_WAIT); + /* + * If the next write will extend the file into a new block, + * and the file is currently composed of a fragment + * this fragment has to be extended to be a full block. + */ + lastlbn = lblkno(fs, ip->i_size); + if (lastlbn < NDADDR && lastlbn < lbn) { + nb = lastlbn; + osize = blksize(fs, ip, nb); + if (osize < fs->fs_bsize && osize > 0) { + UFS_LOCK(ump); + error = ffs_realloccg(ip, nb, dp->di_db[nb], + ffs_blkpref_ufs1(ip, lastlbn, (int)nb, + &dp->di_db[0]), osize, (int)fs->fs_bsize, flags, + cred, &bp); + if (error) + return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, nb, + dbtofsb(fs, bp->b_blkno), dp->di_db[nb], + fs->fs_bsize, osize, bp); + ip->i_size = smalllblktosize(fs, nb + 1); + dp->di_size = ip->i_size; + dp->di_db[nb] = dbtofsb(fs, bp->b_blkno); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (flags & IO_SYNC) + bwrite(bp); + else + bawrite(bp); + } + } + /* + * The first NDADDR blocks are direct blocks + */ + if (lbn < NDADDR) { + if (flags & BA_METAONLY) + panic("ffs_balloc_ufs1: BA_METAONLY for direct block"); + nb = dp->di_db[lbn]; + if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { + error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + bp->b_blkno = fsbtodb(fs, nb); + *bpp = bp; + return (0); + } + if (nb != 0) { + /* + * Consider need to reallocate a fragment. + */ + osize = fragroundup(fs, blkoff(fs, ip->i_size)); + nsize = fragroundup(fs, size); + if (nsize <= osize) { + error = bread(vp, lbn, osize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + bp->b_blkno = fsbtodb(fs, nb); + } else { + UFS_LOCK(ump); + error = ffs_realloccg(ip, lbn, dp->di_db[lbn], + ffs_blkpref_ufs1(ip, lbn, (int)lbn, + &dp->di_db[0]), osize, nsize, flags, + cred, &bp); + if (error) + return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, lbn, + dbtofsb(fs, bp->b_blkno), nb, + nsize, osize, bp); + } + } else { + if (ip->i_size < smalllblktosize(fs, lbn + 1)) + nsize = fragroundup(fs, size); + else + nsize = fs->fs_bsize; + UFS_LOCK(ump); + error = ffs_alloc(ip, lbn, + ffs_blkpref_ufs1(ip, lbn, (int)lbn, &dp->di_db[0]), + nsize, flags, cred, &newb); + if (error) + return (error); + bp = getblk(vp, lbn, nsize, 0, 0, gbflags); + bp->b_blkno = fsbtodb(fs, newb); + if (flags & BA_CLRBUF) + vfs_bio_clrbuf(bp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, lbn, newb, 0, + nsize, 0, bp); + } + dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + *bpp = bp; + return (0); + } + /* + * Determine the number of levels of indirection. + */ + pref = 0; + if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) + return(error); +#ifdef INVARIANTS + if (num < 1) + panic ("ffs_balloc_ufs1: ufs_getlbns returned indirect block"); +#endif + saved_inbdflush = curthread_pflags_set(TDP_INBDFLUSH); + /* + * Fetch the first indirect block allocating if necessary. + */ + --num; + nb = dp->di_ib[indirs[0].in_off]; + allocib = NULL; + allocblk = allociblk; + lbns_remfree = lbns; + if (nb == 0) { + UFS_LOCK(ump); + pref = ffs_blkpref_ufs1(ip, lbn, -indirs[0].in_off - 1, + (ufs1_daddr_t *)0); + if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + flags, cred, &newb)) != 0) { + curthread_pflags_restore(saved_inbdflush); + return (error); + } + pref = newb + fs->fs_frag; + nb = newb; + MPASS(allocblk < allociblk + nitems(allociblk)); + MPASS(lbns_remfree < lbns + nitems(lbns)); + *allocblk++ = nb; + *lbns_remfree++ = indirs[1].in_lbn; + bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, gbflags); + bp->b_blkno = fsbtodb(fs, nb); + vfs_bio_clrbuf(bp); + if (DOINGSOFTDEP(vp)) { + softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, + newb, 0, fs->fs_bsize, 0, bp); + bdwrite(bp); + } else { + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if (DOINGASYNC(vp)) + bdwrite(bp); + else if ((error = bwrite(bp)) != 0) + goto fail; + } + allocib = &dp->di_ib[indirs[0].in_off]; + *allocib = nb; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + /* + * Fetch through the indirect blocks, allocating as necessary. + */ +retry: + for (i = 1;;) { + error = bread(vp, + indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); + if (error) { + brelse(bp); + goto fail; + } + bap = (ufs1_daddr_t *)bp->b_data; + nb = bap[indirs[i].in_off]; + if (i == num) + break; + i += 1; + if (nb != 0) { + bqrelse(bp); + continue; + } + UFS_LOCK(ump); + /* + * If parent indirect has just been allocated, try to cluster + * immediately following it. + */ + if (pref == 0) + pref = ffs_blkpref_ufs1(ip, lbn, i - num - 1, + (ufs1_daddr_t *)0); + if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + flags | IO_BUFLOCKED, cred, &newb)) != 0) { + brelse(bp); + if (DOINGSOFTDEP(vp) && ++reclaimed == 1) { + UFS_LOCK(ump); + softdep_request_cleanup(fs, vp, cred, + FLUSH_BLOCKS_WAIT); + UFS_UNLOCK(ump); + goto retry; + } + if (ppsratecheck(&lastfail, &curfail, 1)) { + ffs_fserr(fs, ip->i_number, "filesystem full"); + uprintf("\n%s: write failed, filesystem " + "is full\n", fs->fs_fsmnt); + } + goto fail; + } + pref = newb + fs->fs_frag; + nb = newb; + MPASS(allocblk < allociblk + nitems(allociblk)); + MPASS(lbns_remfree < lbns + nitems(lbns)); + *allocblk++ = nb; + *lbns_remfree++ = indirs[i].in_lbn; + nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0); + nbp->b_blkno = fsbtodb(fs, nb); + vfs_bio_clrbuf(nbp); + if (DOINGSOFTDEP(vp)) { + softdep_setup_allocindir_meta(nbp, ip, bp, + indirs[i - 1].in_off, nb); + bdwrite(nbp); + } else { + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if ((error = bwrite(nbp)) != 0) { + brelse(bp); + goto fail; + } + } + bap[indirs[i - 1].in_off] = nb; + if (allocib == NULL && unwindidx < 0) + unwindidx = i - 1; + /* + * If required, write synchronously, otherwise use + * delayed write. + */ + if (flags & IO_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + } + /* + * If asked only for the indirect block, then return it. + */ + if (flags & BA_METAONLY) { + curthread_pflags_restore(saved_inbdflush); + *bpp = bp; + return (0); + } + /* + * Get the data block, allocating if necessary. + */ + if (nb == 0) { + UFS_LOCK(ump); + /* + * If allocating metadata at the front of the cylinder + * group and parent indirect block has just been allocated, + * then cluster next to it if it is the first indirect in + * the file. Otherwise it has been allocated in the metadata + * area, so we want to find our own place out in the data area. + */ + if (pref == 0 || (lbn > NDADDR && fs->fs_metaspace != 0)) + pref = ffs_blkpref_ufs1(ip, lbn, indirs[i].in_off, + &bap[0]); + error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + flags | IO_BUFLOCKED, cred, &newb); + if (error) { + brelse(bp); + if (DOINGSOFTDEP(vp) && ++reclaimed == 1) { + UFS_LOCK(ump); + softdep_request_cleanup(fs, vp, cred, + FLUSH_BLOCKS_WAIT); + UFS_UNLOCK(ump); + goto retry; + } + if (ppsratecheck(&lastfail, &curfail, 1)) { + ffs_fserr(fs, ip->i_number, "filesystem full"); + uprintf("\n%s: write failed, filesystem " + "is full\n", fs->fs_fsmnt); + } + goto fail; + } + nb = newb; + MPASS(allocblk < allociblk + nitems(allociblk)); + MPASS(lbns_remfree < lbns + nitems(lbns)); + *allocblk++ = nb; + *lbns_remfree++ = lbn; + nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); + nbp->b_blkno = fsbtodb(fs, nb); + if (flags & BA_CLRBUF) + vfs_bio_clrbuf(nbp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocindir_page(ip, lbn, bp, + indirs[i].in_off, nb, 0, nbp); + bap[indirs[i].in_off] = nb; + /* + * If required, write synchronously, otherwise use + * delayed write. + */ + if (flags & IO_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + curthread_pflags_restore(saved_inbdflush); + *bpp = nbp; + return (0); + } + brelse(bp); + if (flags & BA_CLRBUF) { + int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; + if (seqcount != 0 && + (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0 && + !(vm_page_count_severe() || buf_dirty_count_severe())) { + error = cluster_read(vp, ip->i_size, lbn, + (int)fs->fs_bsize, NOCRED, + MAXBSIZE, seqcount, gbflags, &nbp); + } else { + error = bread_gb(vp, lbn, (int)fs->fs_bsize, NOCRED, + gbflags, &nbp); + } + if (error) { + brelse(nbp); + goto fail; + } + } else { + nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); + nbp->b_blkno = fsbtodb(fs, nb); + } + curthread_pflags_restore(saved_inbdflush); + *bpp = nbp; + return (0); +fail: + curthread_pflags_restore(saved_inbdflush); + /* + * If we have failed to allocate any blocks, simply return the error. + * This is the usual case and avoids the need to fsync the file. + */ + if (allocblk == allociblk && allocib == NULL && unwindidx == -1) + return (error); + /* + * If we have failed part way through block allocation, we + * have to deallocate any indirect blocks that we have allocated. + * We have to fsync the file before we start to get rid of all + * of its dependencies so that we do not leave them dangling. + * We have to sync it at the end so that the soft updates code + * does not find any untracked changes. Although this is really + * slow, running out of disk space is not expected to be a common + * occurrence. The error return from fsync is ignored as we already + * have an error to return to the user. + * + * XXX Still have to journal the free below + */ + (void) ffs_syncvnode(vp, MNT_WAIT, 0); + for (deallocated = 0, blkp = allociblk, lbns_remfree = lbns; + blkp < allocblk; blkp++, lbns_remfree++) { + /* + * We shall not leave the freed blocks on the vnode + * buffer object lists. + */ + bp = getblk(vp, *lbns_remfree, fs->fs_bsize, 0, 0, + GB_NOCREAT | GB_UNMAPPED); + if (bp != NULL) { + KASSERT(bp->b_blkno == fsbtodb(fs, *blkp), + ("mismatch1 l %jd %jd b %ju %ju", + (intmax_t)bp->b_lblkno, (uintmax_t)*lbns_remfree, + (uintmax_t)bp->b_blkno, + (uintmax_t)fsbtodb(fs, *blkp))); + bp->b_flags |= B_INVAL | B_RELBUF | B_NOCACHE; + bp->b_flags &= ~(B_ASYNC | B_CACHE); + brelse(bp); + } + deallocated += fs->fs_bsize; + } + if (allocib != NULL) { + *allocib = 0; + } else if (unwindidx >= 0) { + int r; + + r = bread(vp, indirs[unwindidx].in_lbn, + (int)fs->fs_bsize, NOCRED, &bp); + if (r) { + panic("Could not unwind indirect block, error %d", r); + brelse(bp); + } else { + bap = (ufs1_daddr_t *)bp->b_data; + bap[indirs[unwindidx].in_off] = 0; + if (flags & IO_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + } + } + if (deallocated) { +#ifdef QUOTA + /* + * Restore user's disk quota because allocation failed. + */ + (void) chkdq(ip, -btodb(deallocated), cred, FORCE); +#endif + dp->di_blocks -= btodb(deallocated); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + (void) ffs_syncvnode(vp, MNT_WAIT, 0); + /* + * After the buffers are invalidated and on-disk pointers are + * cleared, free the blocks. + */ + for (blkp = allociblk; blkp < allocblk; blkp++) { +#ifdef INVARIANTS + if (blkp == allociblk) + lbns_remfree = lbns; + bp = getblk(vp, *lbns_remfree, fs->fs_bsize, 0, 0, + GB_NOCREAT | GB_UNMAPPED); + if (bp != NULL) { + panic("zombie1 %jd %ju %ju", + (intmax_t)bp->b_lblkno, (uintmax_t)bp->b_blkno, + (uintmax_t)fsbtodb(fs, *blkp)); + } + lbns_remfree++; +#endif + ffs_blkfree(ump, fs, ump->um_devvp, *blkp, fs->fs_bsize, + ip->i_number, vp->v_type, NULL); + } + return (error); +} + +/* + * Balloc defines the structure of file system storage + * by allocating the physical blocks on a device given + * the inode and the logical block number in a file. + * This is the allocation strategy for UFS2. Above is + * the allocation strategy for UFS1. + */ +int +ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, int size, + struct ucred *cred, int flags, struct buf **bpp) +{ + struct inode *ip; + struct ufs2_dinode *dp; + ufs_lbn_t lbn, lastlbn; + struct fs *fs; + struct buf *bp, *nbp; + struct ufsmount *ump; + struct indir indirs[NIADDR + 2]; + ufs2_daddr_t nb, newb, *bap, pref; + ufs2_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; + ufs2_daddr_t *lbns_remfree, lbns[NIADDR + 1]; + int deallocated, osize, nsize, num, i, error; + int unwindidx = -1; + int saved_inbdflush; + static struct timeval lastfail; + static int curfail; + int gbflags, reclaimed; + + ip = VTOI(vp); + dp = ip->i_din2; + fs = ITOFS(ip); + ump = ITOUMP(ip); + lbn = lblkno(fs, startoffset); + size = blkoff(fs, startoffset) + size; + reclaimed = 0; + if (size > fs->fs_bsize) + panic("ffs_balloc_ufs2: blk too big"); + *bpp = NULL; + if (lbn < 0) + return (EFBIG); + gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; + + if (DOINGSOFTDEP(vp)) + softdep_prealloc(vp, MNT_WAIT); + + /* + * Check for allocating external data. + */ + if (flags & IO_EXT) { + if (lbn >= NXADDR) + return (EFBIG); + /* + * If the next write will extend the data into a new block, + * and the data is currently composed of a fragment + * this fragment has to be extended to be a full block. + */ + lastlbn = lblkno(fs, dp->di_extsize); + if (lastlbn < lbn) { + nb = lastlbn; + osize = sblksize(fs, dp->di_extsize, nb); + if (osize < fs->fs_bsize && osize > 0) { + UFS_LOCK(ump); + error = ffs_realloccg(ip, -1 - nb, + dp->di_extb[nb], + ffs_blkpref_ufs2(ip, lastlbn, (int)nb, + &dp->di_extb[0]), osize, + (int)fs->fs_bsize, flags, cred, &bp); + if (error) + return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocext(ip, nb, + dbtofsb(fs, bp->b_blkno), + dp->di_extb[nb], + fs->fs_bsize, osize, bp); + dp->di_extsize = smalllblktosize(fs, nb + 1); + dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno); + bp->b_xflags |= BX_ALTDATA; + ip->i_flag |= IN_CHANGE; + if (flags & IO_SYNC) + bwrite(bp); + else + bawrite(bp); + } + } + /* + * All blocks are direct blocks + */ + if (flags & BA_METAONLY) + panic("ffs_balloc_ufs2: BA_METAONLY for ext block"); + nb = dp->di_extb[lbn]; + if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) { + error = bread_gb(vp, -1 - lbn, fs->fs_bsize, NOCRED, + gbflags, &bp); + if (error) { + brelse(bp); + return (error); + } + bp->b_blkno = fsbtodb(fs, nb); + bp->b_xflags |= BX_ALTDATA; + *bpp = bp; + return (0); + } + if (nb != 0) { + /* + * Consider need to reallocate a fragment. + */ + osize = fragroundup(fs, blkoff(fs, dp->di_extsize)); + nsize = fragroundup(fs, size); + if (nsize <= osize) { + error = bread_gb(vp, -1 - lbn, osize, NOCRED, + gbflags, &bp); + if (error) { + brelse(bp); + return (error); + } + bp->b_blkno = fsbtodb(fs, nb); + bp->b_xflags |= BX_ALTDATA; + } else { + UFS_LOCK(ump); + error = ffs_realloccg(ip, -1 - lbn, + dp->di_extb[lbn], + ffs_blkpref_ufs2(ip, lbn, (int)lbn, + &dp->di_extb[0]), osize, nsize, flags, + cred, &bp); + if (error) + return (error); + bp->b_xflags |= BX_ALTDATA; + if (DOINGSOFTDEP(vp)) + softdep_setup_allocext(ip, lbn, + dbtofsb(fs, bp->b_blkno), nb, + nsize, osize, bp); + } + } else { + if (dp->di_extsize < smalllblktosize(fs, lbn + 1)) + nsize = fragroundup(fs, size); + else + nsize = fs->fs_bsize; + UFS_LOCK(ump); + error = ffs_alloc(ip, lbn, + ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]), + nsize, flags, cred, &newb); + if (error) + return (error); + bp = getblk(vp, -1 - lbn, nsize, 0, 0, gbflags); + bp->b_blkno = fsbtodb(fs, newb); + bp->b_xflags |= BX_ALTDATA; + if (flags & BA_CLRBUF) + vfs_bio_clrbuf(bp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocext(ip, lbn, newb, 0, + nsize, 0, bp); + } + dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno); + ip->i_flag |= IN_CHANGE; + *bpp = bp; + return (0); + } + /* + * If the next write will extend the file into a new block, + * and the file is currently composed of a fragment + * this fragment has to be extended to be a full block. + */ + lastlbn = lblkno(fs, ip->i_size); + if (lastlbn < NDADDR && lastlbn < lbn) { + nb = lastlbn; + osize = blksize(fs, ip, nb); + if (osize < fs->fs_bsize && osize > 0) { + UFS_LOCK(ump); + error = ffs_realloccg(ip, nb, dp->di_db[nb], + ffs_blkpref_ufs2(ip, lastlbn, (int)nb, + &dp->di_db[0]), osize, (int)fs->fs_bsize, + flags, cred, &bp); + if (error) + return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, nb, + dbtofsb(fs, bp->b_blkno), + dp->di_db[nb], + fs->fs_bsize, osize, bp); + ip->i_size = smalllblktosize(fs, nb + 1); + dp->di_size = ip->i_size; + dp->di_db[nb] = dbtofsb(fs, bp->b_blkno); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (flags & IO_SYNC) + bwrite(bp); + else + bawrite(bp); + } + } + /* + * The first NDADDR blocks are direct blocks + */ + if (lbn < NDADDR) { + if (flags & BA_METAONLY) + panic("ffs_balloc_ufs2: BA_METAONLY for direct block"); + nb = dp->di_db[lbn]; + if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { + error = bread_gb(vp, lbn, fs->fs_bsize, NOCRED, + gbflags, &bp); + if (error) { + brelse(bp); + return (error); + } + bp->b_blkno = fsbtodb(fs, nb); + *bpp = bp; + return (0); + } + if (nb != 0) { + /* + * Consider need to reallocate a fragment. + */ + osize = fragroundup(fs, blkoff(fs, ip->i_size)); + nsize = fragroundup(fs, size); + if (nsize <= osize) { + error = bread_gb(vp, lbn, osize, NOCRED, + gbflags, &bp); + if (error) { + brelse(bp); + return (error); + } + bp->b_blkno = fsbtodb(fs, nb); + } else { + UFS_LOCK(ump); + error = ffs_realloccg(ip, lbn, dp->di_db[lbn], + ffs_blkpref_ufs2(ip, lbn, (int)lbn, + &dp->di_db[0]), osize, nsize, flags, + cred, &bp); + if (error) + return (error); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, lbn, + dbtofsb(fs, bp->b_blkno), nb, + nsize, osize, bp); + } + } else { + if (ip->i_size < smalllblktosize(fs, lbn + 1)) + nsize = fragroundup(fs, size); + else + nsize = fs->fs_bsize; + UFS_LOCK(ump); + error = ffs_alloc(ip, lbn, + ffs_blkpref_ufs2(ip, lbn, (int)lbn, + &dp->di_db[0]), nsize, flags, cred, &newb); + if (error) + return (error); + bp = getblk(vp, lbn, nsize, 0, 0, gbflags); + bp->b_blkno = fsbtodb(fs, newb); + if (flags & BA_CLRBUF) + vfs_bio_clrbuf(bp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocdirect(ip, lbn, newb, 0, + nsize, 0, bp); + } + dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + *bpp = bp; + return (0); + } + /* + * Determine the number of levels of indirection. + */ + pref = 0; + if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) + return(error); +#ifdef INVARIANTS + if (num < 1) + panic ("ffs_balloc_ufs2: ufs_getlbns returned indirect block"); +#endif + saved_inbdflush = curthread_pflags_set(TDP_INBDFLUSH); + /* + * Fetch the first indirect block allocating if necessary. + */ + --num; + nb = dp->di_ib[indirs[0].in_off]; + allocib = NULL; + allocblk = allociblk; + lbns_remfree = lbns; + if (nb == 0) { + UFS_LOCK(ump); + pref = ffs_blkpref_ufs2(ip, lbn, -indirs[0].in_off - 1, + (ufs2_daddr_t *)0); + if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + flags, cred, &newb)) != 0) { + curthread_pflags_restore(saved_inbdflush); + return (error); + } + pref = newb + fs->fs_frag; + nb = newb; + MPASS(allocblk < allociblk + nitems(allociblk)); + MPASS(lbns_remfree < lbns + nitems(lbns)); + *allocblk++ = nb; + *lbns_remfree++ = indirs[1].in_lbn; + bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, + GB_UNMAPPED); + bp->b_blkno = fsbtodb(fs, nb); + vfs_bio_clrbuf(bp); + if (DOINGSOFTDEP(vp)) { + softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, + newb, 0, fs->fs_bsize, 0, bp); + bdwrite(bp); + } else { + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if (DOINGASYNC(vp)) + bdwrite(bp); + else if ((error = bwrite(bp)) != 0) + goto fail; + } + allocib = &dp->di_ib[indirs[0].in_off]; + *allocib = nb; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + /* + * Fetch through the indirect blocks, allocating as necessary. + */ +retry: + for (i = 1;;) { + error = bread(vp, + indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); + if (error) { + brelse(bp); + goto fail; + } + bap = (ufs2_daddr_t *)bp->b_data; + nb = bap[indirs[i].in_off]; + if (i == num) + break; + i += 1; + if (nb != 0) { + bqrelse(bp); + continue; + } + UFS_LOCK(ump); + /* + * If parent indirect has just been allocated, try to cluster + * immediately following it. + */ + if (pref == 0) + pref = ffs_blkpref_ufs2(ip, lbn, i - num - 1, + (ufs2_daddr_t *)0); + if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + flags | IO_BUFLOCKED, cred, &newb)) != 0) { + brelse(bp); + if (DOINGSOFTDEP(vp) && ++reclaimed == 1) { + UFS_LOCK(ump); + softdep_request_cleanup(fs, vp, cred, + FLUSH_BLOCKS_WAIT); + UFS_UNLOCK(ump); + goto retry; + } + if (ppsratecheck(&lastfail, &curfail, 1)) { + ffs_fserr(fs, ip->i_number, "filesystem full"); + uprintf("\n%s: write failed, filesystem " + "is full\n", fs->fs_fsmnt); + } + goto fail; + } + pref = newb + fs->fs_frag; + nb = newb; + MPASS(allocblk < allociblk + nitems(allociblk)); + MPASS(lbns_remfree < lbns + nitems(lbns)); + *allocblk++ = nb; + *lbns_remfree++ = indirs[i].in_lbn; + nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, + GB_UNMAPPED); + nbp->b_blkno = fsbtodb(fs, nb); + vfs_bio_clrbuf(nbp); + if (DOINGSOFTDEP(vp)) { + softdep_setup_allocindir_meta(nbp, ip, bp, + indirs[i - 1].in_off, nb); + bdwrite(nbp); + } else { + /* + * Write synchronously so that indirect blocks + * never point at garbage. + */ + if ((error = bwrite(nbp)) != 0) { + brelse(bp); + goto fail; + } + } + bap[indirs[i - 1].in_off] = nb; + if (allocib == NULL && unwindidx < 0) + unwindidx = i - 1; + /* + * If required, write synchronously, otherwise use + * delayed write. + */ + if (flags & IO_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + } + /* + * If asked only for the indirect block, then return it. + */ + if (flags & BA_METAONLY) { + curthread_pflags_restore(saved_inbdflush); + *bpp = bp; + return (0); + } + /* + * Get the data block, allocating if necessary. + */ + if (nb == 0) { + UFS_LOCK(ump); + /* + * If allocating metadata at the front of the cylinder + * group and parent indirect block has just been allocated, + * then cluster next to it if it is the first indirect in + * the file. Otherwise it has been allocated in the metadata + * area, so we want to find our own place out in the data area. + */ + if (pref == 0 || (lbn > NDADDR && fs->fs_metaspace != 0)) + pref = ffs_blkpref_ufs2(ip, lbn, indirs[i].in_off, + &bap[0]); + error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, + flags | IO_BUFLOCKED, cred, &newb); + if (error) { + brelse(bp); + if (DOINGSOFTDEP(vp) && ++reclaimed == 1) { + UFS_LOCK(ump); + softdep_request_cleanup(fs, vp, cred, + FLUSH_BLOCKS_WAIT); + UFS_UNLOCK(ump); + goto retry; + } + if (ppsratecheck(&lastfail, &curfail, 1)) { + ffs_fserr(fs, ip->i_number, "filesystem full"); + uprintf("\n%s: write failed, filesystem " + "is full\n", fs->fs_fsmnt); + } + goto fail; + } + nb = newb; + MPASS(allocblk < allociblk + nitems(allociblk)); + MPASS(lbns_remfree < lbns + nitems(lbns)); + *allocblk++ = nb; + *lbns_remfree++ = lbn; + nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); + nbp->b_blkno = fsbtodb(fs, nb); + if (flags & BA_CLRBUF) + vfs_bio_clrbuf(nbp); + if (DOINGSOFTDEP(vp)) + softdep_setup_allocindir_page(ip, lbn, bp, + indirs[i].in_off, nb, 0, nbp); + bap[indirs[i].in_off] = nb; + /* + * If required, write synchronously, otherwise use + * delayed write. + */ + if (flags & IO_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + curthread_pflags_restore(saved_inbdflush); + *bpp = nbp; + return (0); + } + brelse(bp); + /* + * If requested clear invalid portions of the buffer. If we + * have to do a read-before-write (typical if BA_CLRBUF is set), + * try to do some read-ahead in the sequential case to reduce + * the number of I/O transactions. + */ + if (flags & BA_CLRBUF) { + int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; + if (seqcount != 0 && + (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0 && + !(vm_page_count_severe() || buf_dirty_count_severe())) { + error = cluster_read(vp, ip->i_size, lbn, + (int)fs->fs_bsize, NOCRED, + MAXBSIZE, seqcount, gbflags, &nbp); + } else { + error = bread_gb(vp, lbn, (int)fs->fs_bsize, + NOCRED, gbflags, &nbp); + } + if (error) { + brelse(nbp); + goto fail; + } + } else { + nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); + nbp->b_blkno = fsbtodb(fs, nb); + } + curthread_pflags_restore(saved_inbdflush); + *bpp = nbp; + return (0); +fail: + curthread_pflags_restore(saved_inbdflush); + /* + * If we have failed to allocate any blocks, simply return the error. + * This is the usual case and avoids the need to fsync the file. + */ + if (allocblk == allociblk && allocib == NULL && unwindidx == -1) + return (error); + /* + * If we have failed part way through block allocation, we + * have to deallocate any indirect blocks that we have allocated. + * We have to fsync the file before we start to get rid of all + * of its dependencies so that we do not leave them dangling. + * We have to sync it at the end so that the soft updates code + * does not find any untracked changes. Although this is really + * slow, running out of disk space is not expected to be a common + * occurrence. The error return from fsync is ignored as we already + * have an error to return to the user. + * + * XXX Still have to journal the free below + */ + (void) ffs_syncvnode(vp, MNT_WAIT, 0); + for (deallocated = 0, blkp = allociblk, lbns_remfree = lbns; + blkp < allocblk; blkp++, lbns_remfree++) { + /* + * We shall not leave the freed blocks on the vnode + * buffer object lists. + */ + bp = getblk(vp, *lbns_remfree, fs->fs_bsize, 0, 0, + GB_NOCREAT | GB_UNMAPPED); + if (bp != NULL) { + KASSERT(bp->b_blkno == fsbtodb(fs, *blkp), + ("mismatch2 l %jd %jd b %ju %ju", + (intmax_t)bp->b_lblkno, (uintmax_t)*lbns_remfree, + (uintmax_t)bp->b_blkno, + (uintmax_t)fsbtodb(fs, *blkp))); + bp->b_flags |= B_INVAL | B_RELBUF | B_NOCACHE; + bp->b_flags &= ~(B_ASYNC | B_CACHE); + brelse(bp); + } + deallocated += fs->fs_bsize; + } + if (allocib != NULL) { + *allocib = 0; + } else if (unwindidx >= 0) { + int r; + + r = bread(vp, indirs[unwindidx].in_lbn, + (int)fs->fs_bsize, NOCRED, &bp); + if (r) { + panic("Could not unwind indirect block, error %d", r); + brelse(bp); + } else { + bap = (ufs2_daddr_t *)bp->b_data; + bap[indirs[unwindidx].in_off] = 0; + if (flags & IO_SYNC) { + bwrite(bp); + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + } + } + if (deallocated) { +#ifdef QUOTA + /* + * Restore user's disk quota because allocation failed. + */ + (void) chkdq(ip, -btodb(deallocated), cred, FORCE); +#endif + dp->di_blocks -= btodb(deallocated); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + (void) ffs_syncvnode(vp, MNT_WAIT, 0); + /* + * After the buffers are invalidated and on-disk pointers are + * cleared, free the blocks. + */ + for (blkp = allociblk; blkp < allocblk; blkp++) { +#ifdef INVARIANTS + if (blkp == allociblk) + lbns_remfree = lbns; + bp = getblk(vp, *lbns_remfree, fs->fs_bsize, 0, 0, + GB_NOCREAT | GB_UNMAPPED); + if (bp != NULL) { + panic("zombie2 %jd %ju %ju", + (intmax_t)bp->b_lblkno, (uintmax_t)bp->b_blkno, + (uintmax_t)fsbtodb(fs, *blkp)); + } + lbns_remfree++; +#endif + ffs_blkfree(ump, fs, ump->um_devvp, *blkp, fs->fs_bsize, + ip->i_number, vp->v_type, NULL); + } + return (error); +} diff --git a/Dump/ufs/ffs/ffs_extern.h b/Dump/ufs/ffs/ffs_extern.h new file mode 100644 index 0000000..f50b403 --- /dev/null +++ b/Dump/ufs/ffs/ffs_extern.h @@ -0,0 +1,200 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_extern.h 8.6 (Berkeley) 3/30/95 + * $FreeBSD: releng/11.2/sys/ufs/ffs/ffs_extern.h 331722 2018-03-29 02:50:57Z eadler $ + */ + +#ifndef _UFS_FFS_EXTERN_H +#define _UFS_FFS_EXTERN_H + +#ifndef _KERNEL +#error "No user-serving parts inside" +#else + +struct buf; +struct cg; +struct fid; +struct fs; +struct inode; +struct malloc_type; +struct mount; +struct thread; +struct sockaddr; +struct statfs; +struct ucred; +struct vnode; +struct vop_fsync_args; +struct vop_reallocblks_args; +struct workhead; + +int ffs_alloc(struct inode *, ufs2_daddr_t, ufs2_daddr_t, int, int, + struct ucred *, ufs2_daddr_t *); +int ffs_balloc_ufs1(struct vnode *a_vp, off_t a_startoffset, int a_size, + struct ucred *a_cred, int a_flags, struct buf **a_bpp); +int ffs_balloc_ufs2(struct vnode *a_vp, off_t a_startoffset, int a_size, + struct ucred *a_cred, int a_flags, struct buf **a_bpp); +int ffs_blkatoff(struct vnode *, off_t, char **, struct buf **); +void ffs_blkfree(struct ufsmount *, struct fs *, struct vnode *, + ufs2_daddr_t, long, ino_t, enum vtype, struct workhead *); +ufs2_daddr_t ffs_blkpref_ufs1(struct inode *, ufs_lbn_t, int, ufs1_daddr_t *); +ufs2_daddr_t ffs_blkpref_ufs2(struct inode *, ufs_lbn_t, int, ufs2_daddr_t *); +int ffs_checkfreefile(struct fs *, struct vnode *, ino_t); +void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t); +void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int); +void ffs_bdflush(struct bufobj *, struct buf *); +int ffs_copyonwrite(struct vnode *, struct buf *); +int ffs_flushfiles(struct mount *, int, struct thread *); +void ffs_fragacct(struct fs *, int, int32_t [], int); +int ffs_freefile(struct ufsmount *, struct fs *, struct vnode *, ino_t, + int, struct workhead *); +void ffs_fserr(struct fs *, ino_t, char *); +int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t); +int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t); +void ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t); +void ffs_oldfscompat_write(struct fs *, struct ufsmount *); +int ffs_own_mount(const struct mount *mp); +int ffs_reallocblks(struct vop_reallocblks_args *); +int ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t, + ufs2_daddr_t, int, int, int, struct ucred *, struct buf **); +int ffs_reload(struct mount *, struct thread *, int); +int ffs_sbupdate(struct ufsmount *, int, int); +void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t); +int ffs_snapblkfree(struct fs *, struct vnode *, ufs2_daddr_t, long, ino_t, + enum vtype, struct workhead *); +void ffs_snapremove(struct vnode *vp); +int ffs_snapshot(struct mount *mp, char *snapfile); +void ffs_snapshot_mount(struct mount *mp); +void ffs_snapshot_unmount(struct mount *mp); +void process_deferred_inactive(struct mount *mp); +void ffs_sync_snap(struct mount *, int); +int ffs_syncvnode(struct vnode *vp, int waitfor, int flags); +int ffs_truncate(struct vnode *, off_t, int, struct ucred *); +int ffs_update(struct vnode *, int); +int ffs_valloc(struct vnode *, int, struct ucred *, struct vnode **); + +int ffs_vfree(struct vnode *, ino_t, int); +vfs_vget_t ffs_vget; +int ffs_vgetf(struct mount *, ino_t, int, struct vnode **, int); +void ffs_susp_initialize(void); +void ffs_susp_uninitialize(void); + +#define FFSV_FORCEINSMQ 0x0001 + +#define FFSR_FORCE 0x0001 +#define FFSR_UNSUSPEND 0x0002 + +extern struct vop_vector ffs_vnodeops1; +extern struct vop_vector ffs_fifoops1; +extern struct vop_vector ffs_vnodeops2; +extern struct vop_vector ffs_fifoops2; + +/* + * Soft update function prototypes. + */ + +int softdep_check_suspend(struct mount *, struct vnode *, + int, int, int, int); +void softdep_get_depcounts(struct mount *, int *, int *); +void softdep_initialize(void); +void softdep_uninitialize(void); +int softdep_mount(struct vnode *, struct mount *, struct fs *, + struct ucred *); +void softdep_unmount(struct mount *); +int softdep_move_dependencies(struct buf *, struct buf *); +int softdep_flushworklist(struct mount *, int *, struct thread *); +int softdep_flushfiles(struct mount *, int, struct thread *); +void softdep_update_inodeblock(struct inode *, struct buf *, int); +void softdep_load_inodeblock(struct inode *); +void softdep_freefile(struct vnode *, ino_t, int); +int softdep_request_cleanup(struct fs *, struct vnode *, + struct ucred *, int); +void softdep_setup_freeblocks(struct inode *, off_t, int); +void softdep_setup_inomapdep(struct buf *, struct inode *, ino_t, int); +void softdep_setup_blkmapdep(struct buf *, struct mount *, ufs2_daddr_t, + int, int); +void softdep_setup_allocdirect(struct inode *, ufs_lbn_t, ufs2_daddr_t, + ufs2_daddr_t, long, long, struct buf *); +void softdep_setup_allocext(struct inode *, ufs_lbn_t, ufs2_daddr_t, + ufs2_daddr_t, long, long, struct buf *); +void softdep_setup_allocindir_meta(struct buf *, struct inode *, + struct buf *, int, ufs2_daddr_t); +void softdep_setup_allocindir_page(struct inode *, ufs_lbn_t, + struct buf *, int, ufs2_daddr_t, ufs2_daddr_t, struct buf *); +void softdep_setup_blkfree(struct mount *, struct buf *, ufs2_daddr_t, int, + struct workhead *); +void softdep_setup_inofree(struct mount *, struct buf *, ino_t, + struct workhead *); +void softdep_setup_sbupdate(struct ufsmount *, struct fs *, struct buf *); +void softdep_fsync_mountdev(struct vnode *); +int softdep_sync_metadata(struct vnode *); +int softdep_sync_buf(struct vnode *, struct buf *, int); +int softdep_fsync(struct vnode *); +int softdep_prealloc(struct vnode *, int); +int softdep_journal_lookup(struct mount *, struct vnode **); +void softdep_journal_freeblocks(struct inode *, struct ucred *, off_t, int); +void softdep_journal_fsync(struct inode *); +void softdep_buf_append(struct buf *, struct workhead *); +void softdep_inode_append(struct inode *, struct ucred *, struct workhead *); +void softdep_freework(struct workhead *); + + +/* + * Things to request flushing in softdep_request_cleanup() + */ +#define FLUSH_INODES 1 +#define FLUSH_INODES_WAIT 2 +#define FLUSH_BLOCKS 3 +#define FLUSH_BLOCKS_WAIT 4 +/* + * Flag to ffs_syncvnode() to request flushing of data only, + * but skip the ffs_update() on the inode itself. Used to avoid + * deadlock when flushing snapshot inodes while holding snaplk. + */ +#define NO_INO_UPDT 0x00000001 +/* + * Request data sync only from ffs_syncvnode(), not touching even more + * metadata than NO_INO_UPDT. + */ +#define DATA_ONLY 0x00000002 + +int ffs_rdonly(struct inode *); + +TAILQ_HEAD(snaphead, inode); + +struct snapdata { + LIST_ENTRY(snapdata) sn_link; + struct snaphead sn_head; + daddr_t sn_listsize; + daddr_t *sn_blklist; + struct lock sn_lock; +}; + +#endif /* _KERNEL */ + +#endif /* !_UFS_FFS_EXTERN_H */ diff --git a/Dump/ufs/ffs/ffs_inode.c b/Dump/ufs/ffs/ffs_inode.c new file mode 100644 index 0000000..1652f51 --- /dev/null +++ b/Dump/ufs/ffs/ffs_inode.c @@ -0,0 +1,765 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_inode.c 8.13 (Berkeley) 4/21/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_inode.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include "opt_quota.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +static int ffs_indirtrunc(struct inode *, ufs2_daddr_t, ufs2_daddr_t, + ufs2_daddr_t, int, ufs2_daddr_t *); + +/* + * Update the access, modified, and inode change times as specified by the + * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode + * to disk if the IN_MODIFIED flag is set (it may be set initially, or by + * the timestamp update). The IN_LAZYMOD flag is set to force a write + * later if not now. The IN_LAZYACCESS is set instead of IN_MODIFIED if the fs + * is currently being suspended (or is suspended) and vnode has been accessed. + * If we write now, then clear IN_MODIFIED, IN_LAZYACCESS and IN_LAZYMOD to + * reflect the presumably successful write, and if waitfor is set, then wait + * for the write to complete. + */ +int +ffs_update(vp, waitfor) + struct vnode *vp; + int waitfor; +{ + struct fs *fs; + struct buf *bp; + struct inode *ip; + int flags, error; + + ASSERT_VOP_ELOCKED(vp, "ffs_update"); + ufs_itimes(vp); + ip = VTOI(vp); + if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0) + return (0); + ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED); + fs = ITOFS(ip); + if (fs->fs_ronly && ITOUMP(ip)->um_fsckpid == 0) + return (0); + /* + * If we are updating a snapshot and another process is currently + * writing the buffer containing the inode for this snapshot then + * a deadlock can occur when it tries to check the snapshot to see + * if that block needs to be copied. Thus when updating a snapshot + * we check to see if the buffer is already locked, and if it is + * we drop the snapshot lock until the buffer has been written + * and is available to us. We have to grab a reference to the + * snapshot vnode to prevent it from being removed while we are + * waiting for the buffer. + */ + flags = 0; + if (IS_SNAPSHOT(ip)) + flags = GB_LOCK_NOWAIT; +loop: + error = breadn_flags(ITODEVVP(ip), + fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), + (int) fs->fs_bsize, 0, 0, 0, NOCRED, flags, &bp); + if (error != 0) { + if (error != EBUSY) + return (error); + KASSERT((IS_SNAPSHOT(ip)), ("EBUSY from non-snapshot")); + /* + * Wait for our inode block to become available. + * + * Hold a reference to the vnode to protect against + * ffs_snapgone(). Since we hold a reference, it can only + * get reclaimed (VI_DOOMED flag) in a forcible downgrade + * or unmount. For an unmount, the entire filesystem will be + * gone, so we cannot attempt to touch anything associated + * with it while the vnode is unlocked; all we can do is + * pause briefly and try again. If when we relock the vnode + * we discover that it has been reclaimed, updating it is no + * longer necessary and we can just return an error. + */ + vref(vp); + VOP_UNLOCK(vp, 0); + pause("ffsupd", 1); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + vrele(vp); + if ((vp->v_iflag & VI_DOOMED) != 0) + return (ENOENT); + goto loop; + } + if (DOINGSOFTDEP(vp)) + softdep_update_inodeblock(ip, bp, waitfor); + else if (ip->i_effnlink != ip->i_nlink) + panic("ffs_update: bad link cnt"); + if (I_IS_UFS1(ip)) { + *((struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1; + /* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */ + random_harvest_queue(&(ip->i_din1), sizeof(ip->i_din1), 1, RANDOM_FS_ATIME); + } else { + *((struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2; + /* XXX: FIX? The entropy here is desirable, but the harvesting may be expensive */ + random_harvest_queue(&(ip->i_din2), sizeof(ip->i_din2), 1, RANDOM_FS_ATIME); + } + if (waitfor && !DOINGASYNC(vp)) + error = bwrite(bp); + else if (vm_page_count_severe() || buf_dirty_count_severe()) { + bawrite(bp); + error = 0; + } else { + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + error = 0; + } + return (error); +} + +#define SINGLE 0 /* index of single indirect block */ +#define DOUBLE 1 /* index of double indirect block */ +#define TRIPLE 2 /* index of triple indirect block */ +/* + * Truncate the inode ip to at most length size, freeing the + * disk blocks. + */ +int +ffs_truncate(vp, length, flags, cred) + struct vnode *vp; + off_t length; + int flags; + struct ucred *cred; +{ + struct inode *ip; + ufs2_daddr_t bn, lbn, lastblock, lastiblock[NIADDR], indir_lbn[NIADDR]; + ufs2_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; + ufs2_daddr_t count, blocksreleased = 0, datablocks, blkno; + struct bufobj *bo; + struct fs *fs; + struct buf *bp; + struct ufsmount *ump; + int softdeptrunc, journaltrunc; + int needextclean, extblocks; + int offset, size, level, nblocks; + int i, error, allerror, indiroff; + off_t osize; + + ip = VTOI(vp); + ump = VFSTOUFS(vp->v_mount); + fs = ump->um_fs; + bo = &vp->v_bufobj; + + ASSERT_VOP_LOCKED(vp, "ffs_truncate"); + + if (length < 0) + return (EINVAL); + if (length > fs->fs_maxfilesize) + return (EFBIG); +#ifdef QUOTA + error = getinoquota(ip); + if (error) + return (error); +#endif + /* + * Historically clients did not have to specify which data + * they were truncating. So, if not specified, we assume + * traditional behavior, e.g., just the normal data. + */ + if ((flags & (IO_EXT | IO_NORMAL)) == 0) + flags |= IO_NORMAL; + if (!DOINGSOFTDEP(vp) && !DOINGASYNC(vp)) + flags |= IO_SYNC; + /* + * If we are truncating the extended-attributes, and cannot + * do it with soft updates, then do it slowly here. If we are + * truncating both the extended attributes and the file contents + * (e.g., the file is being unlinked), then pick it off with + * soft updates below. + */ + allerror = 0; + needextclean = 0; + softdeptrunc = 0; + journaltrunc = DOINGSUJ(vp); + if (journaltrunc == 0 && DOINGSOFTDEP(vp) && length == 0) + softdeptrunc = !softdep_slowdown(vp); + extblocks = 0; + datablocks = DIP(ip, i_blocks); + if (fs->fs_magic == FS_UFS2_MAGIC && ip->i_din2->di_extsize > 0) { + extblocks = btodb(fragroundup(fs, ip->i_din2->di_extsize)); + datablocks -= extblocks; + } + if ((flags & IO_EXT) && extblocks > 0) { + if (length != 0) + panic("ffs_truncate: partial trunc of extdata"); + if (softdeptrunc || journaltrunc) { + if ((flags & IO_NORMAL) == 0) + goto extclean; + needextclean = 1; + } else { + if ((error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0) + return (error); +#ifdef QUOTA + (void) chkdq(ip, -extblocks, NOCRED, 0); +#endif + vinvalbuf(vp, V_ALT, 0, 0); + vn_pages_remove(vp, + OFF_TO_IDX(lblktosize(fs, -extblocks)), 0); + osize = ip->i_din2->di_extsize; + ip->i_din2->di_blocks -= extblocks; + ip->i_din2->di_extsize = 0; + for (i = 0; i < NXADDR; i++) { + oldblks[i] = ip->i_din2->di_extb[i]; + ip->i_din2->di_extb[i] = 0; + } + ip->i_flag |= IN_CHANGE; + if ((error = ffs_update(vp, !DOINGASYNC(vp)))) + return (error); + for (i = 0; i < NXADDR; i++) { + if (oldblks[i] == 0) + continue; + ffs_blkfree(ump, fs, ITODEVVP(ip), oldblks[i], + sblksize(fs, osize, i), ip->i_number, + vp->v_type, NULL); + } + } + } + if ((flags & IO_NORMAL) == 0) + return (0); + if (vp->v_type == VLNK && + (ip->i_size < vp->v_mount->mnt_maxsymlinklen || + datablocks == 0)) { +#ifdef INVARIANTS + if (length != 0) + panic("ffs_truncate: partial truncate of symlink"); +#endif + bzero(SHORTLINK(ip), (u_int)ip->i_size); + ip->i_size = 0; + DIP_SET(ip, i_size, 0); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (needextclean) + goto extclean; + return (ffs_update(vp, !DOINGASYNC(vp))); + } + if (ip->i_size == length) { + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (needextclean) + goto extclean; + return (ffs_update(vp, 0)); + } + if (fs->fs_ronly) + panic("ffs_truncate: read-only filesystem"); + if (IS_SNAPSHOT(ip)) + ffs_snapremove(vp); + vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0; + osize = ip->i_size; + /* + * Lengthen the size of the file. We must ensure that the + * last byte of the file is allocated. Since the smallest + * value of osize is 0, length will be at least 1. + */ + if (osize < length) { + vnode_pager_setsize(vp, length); + flags |= BA_CLRBUF; + error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp); + if (error) { + vnode_pager_setsize(vp, osize); + return (error); + } + ip->i_size = length; + DIP_SET(ip, i_size, length); + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + if (flags & IO_SYNC) + bwrite(bp); + else if (DOINGASYNC(vp)) + bdwrite(bp); + else + bawrite(bp); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + return (ffs_update(vp, !DOINGASYNC(vp))); + } + /* + * Lookup block number for a given offset. Zero length files + * have no blocks, so return a blkno of -1. + */ + lbn = lblkno(fs, length - 1); + if (length == 0) { + blkno = -1; + } else if (lbn < NDADDR) { + blkno = DIP(ip, i_db[lbn]); + } else { + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize, + cred, BA_METAONLY, &bp); + if (error) + return (error); + indiroff = (lbn - NDADDR) % NINDIR(fs); + if (I_IS_UFS1(ip)) + blkno = ((ufs1_daddr_t *)(bp->b_data))[indiroff]; + else + blkno = ((ufs2_daddr_t *)(bp->b_data))[indiroff]; + /* + * If the block number is non-zero, then the indirect block + * must have been previously allocated and need not be written. + * If the block number is zero, then we may have allocated + * the indirect block and hence need to write it out. + */ + if (blkno != 0) + brelse(bp); + else if (DOINGSOFTDEP(vp) || DOINGASYNC(vp)) + bdwrite(bp); + else + bwrite(bp); + } + /* + * If the block number at the new end of the file is zero, + * then we must allocate it to ensure that the last block of + * the file is allocated. Soft updates does not handle this + * case, so here we have to clean up the soft updates data + * structures describing the allocation past the truncation + * point. Finding and deallocating those structures is a lot of + * work. Since partial truncation with a hole at the end occurs + * rarely, we solve the problem by syncing the file so that it + * will have no soft updates data structures left. + */ + if (blkno == 0 && (error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0) + return (error); + if (blkno != 0 && DOINGSOFTDEP(vp)) { + if (softdeptrunc == 0 && journaltrunc == 0) { + /* + * If soft updates cannot handle this truncation, + * clean up soft dependency data structures and + * fall through to the synchronous truncation. + */ + if ((error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0) + return (error); + } else { + flags = IO_NORMAL | (needextclean ? IO_EXT: 0); + if (journaltrunc) + softdep_journal_freeblocks(ip, cred, length, + flags); + else + softdep_setup_freeblocks(ip, length, flags); + ASSERT_VOP_LOCKED(vp, "ffs_truncate1"); + if (journaltrunc == 0) { + ip->i_flag |= IN_CHANGE | IN_UPDATE; + error = ffs_update(vp, 0); + } + return (error); + } + } + /* + * Shorten the size of the file. If the last block of the + * shortened file is unallocated, we must allocate it. + * Additionally, if the file is not being truncated to a + * block boundary, the contents of the partial block + * following the end of the file must be zero'ed in + * case it ever becomes accessible again because of + * subsequent file growth. Directories however are not + * zero'ed as they should grow back initialized to empty. + */ + offset = blkoff(fs, length); + if (blkno != 0 && offset == 0) { + ip->i_size = length; + DIP_SET(ip, i_size, length); + } else { + lbn = lblkno(fs, length); + flags |= BA_CLRBUF; + error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp); + if (error) + return (error); + /* + * When we are doing soft updates and the UFS_BALLOC + * above fills in a direct block hole with a full sized + * block that will be truncated down to a fragment below, + * we must flush out the block dependency with an FSYNC + * so that we do not get a soft updates inconsistency + * when we create the fragment below. + */ + if (DOINGSOFTDEP(vp) && lbn < NDADDR && + fragroundup(fs, blkoff(fs, length)) < fs->fs_bsize && + (error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0) + return (error); + ip->i_size = length; + DIP_SET(ip, i_size, length); + size = blksize(fs, ip, lbn); + if (vp->v_type != VDIR && offset != 0) + bzero((char *)bp->b_data + offset, + (u_int)(size - offset)); + /* Kirk's code has reallocbuf(bp, size, 1) here */ + allocbuf(bp, size); + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + if (flags & IO_SYNC) + bwrite(bp); + else if (DOINGASYNC(vp)) + bdwrite(bp); + else + bawrite(bp); + } + /* + * Calculate index into inode's block list of + * last direct and indirect blocks (if any) + * which we want to keep. Lastblock is -1 when + * the file is truncated to 0. + */ + lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; + lastiblock[SINGLE] = lastblock - NDADDR; + lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); + lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); + nblocks = btodb(fs->fs_bsize); + /* + * Update file and block pointers on disk before we start freeing + * blocks. If we crash before free'ing blocks below, the blocks + * will be returned to the free list. lastiblock values are also + * normalized to -1 for calls to ffs_indirtrunc below. + */ + for (level = TRIPLE; level >= SINGLE; level--) { + oldblks[NDADDR + level] = DIP(ip, i_ib[level]); + if (lastiblock[level] < 0) { + DIP_SET(ip, i_ib[level], 0); + lastiblock[level] = -1; + } + } + for (i = 0; i < NDADDR; i++) { + oldblks[i] = DIP(ip, i_db[i]); + if (i > lastblock) + DIP_SET(ip, i_db[i], 0); + } + ip->i_flag |= IN_CHANGE | IN_UPDATE; + allerror = ffs_update(vp, !DOINGASYNC(vp)); + + /* + * Having written the new inode to disk, save its new configuration + * and put back the old block pointers long enough to process them. + * Note that we save the new block configuration so we can check it + * when we are done. + */ + for (i = 0; i < NDADDR; i++) { + newblks[i] = DIP(ip, i_db[i]); + DIP_SET(ip, i_db[i], oldblks[i]); + } + for (i = 0; i < NIADDR; i++) { + newblks[NDADDR + i] = DIP(ip, i_ib[i]); + DIP_SET(ip, i_ib[i], oldblks[NDADDR + i]); + } + ip->i_size = osize; + DIP_SET(ip, i_size, osize); + + error = vtruncbuf(vp, cred, length, fs->fs_bsize); + if (error && (allerror == 0)) + allerror = error; + + /* + * Indirect blocks first. + */ + indir_lbn[SINGLE] = -NDADDR; + indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; + indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; + for (level = TRIPLE; level >= SINGLE; level--) { + bn = DIP(ip, i_ib[level]); + if (bn != 0) { + error = ffs_indirtrunc(ip, indir_lbn[level], + fsbtodb(fs, bn), lastiblock[level], level, &count); + if (error) + allerror = error; + blocksreleased += count; + if (lastiblock[level] < 0) { + DIP_SET(ip, i_ib[level], 0); + ffs_blkfree(ump, fs, ump->um_devvp, bn, + fs->fs_bsize, ip->i_number, + vp->v_type, NULL); + blocksreleased += nblocks; + } + } + if (lastiblock[level] >= 0) + goto done; + } + + /* + * All whole direct blocks or frags. + */ + for (i = NDADDR - 1; i > lastblock; i--) { + long bsize; + + bn = DIP(ip, i_db[i]); + if (bn == 0) + continue; + DIP_SET(ip, i_db[i], 0); + bsize = blksize(fs, ip, i); + ffs_blkfree(ump, fs, ump->um_devvp, bn, bsize, ip->i_number, + vp->v_type, NULL); + blocksreleased += btodb(bsize); + } + if (lastblock < 0) + goto done; + + /* + * Finally, look for a change in size of the + * last direct block; release any frags. + */ + bn = DIP(ip, i_db[lastblock]); + if (bn != 0) { + long oldspace, newspace; + + /* + * Calculate amount of space we're giving + * back as old block size minus new block size. + */ + oldspace = blksize(fs, ip, lastblock); + ip->i_size = length; + DIP_SET(ip, i_size, length); + newspace = blksize(fs, ip, lastblock); + if (newspace == 0) + panic("ffs_truncate: newspace"); + if (oldspace - newspace > 0) { + /* + * Block number of space to be free'd is + * the old block # plus the number of frags + * required for the storage we're keeping. + */ + bn += numfrags(fs, newspace); + ffs_blkfree(ump, fs, ump->um_devvp, bn, + oldspace - newspace, ip->i_number, vp->v_type, NULL); + blocksreleased += btodb(oldspace - newspace); + } + } +done: +#ifdef INVARIANTS + for (level = SINGLE; level <= TRIPLE; level++) + if (newblks[NDADDR + level] != DIP(ip, i_ib[level])) + panic("ffs_truncate1"); + for (i = 0; i < NDADDR; i++) + if (newblks[i] != DIP(ip, i_db[i])) + panic("ffs_truncate2"); + BO_LOCK(bo); + if (length == 0 && + (fs->fs_magic != FS_UFS2_MAGIC || ip->i_din2->di_extsize == 0) && + (bo->bo_dirty.bv_cnt > 0 || bo->bo_clean.bv_cnt > 0)) + panic("ffs_truncate3"); + BO_UNLOCK(bo); +#endif /* INVARIANTS */ + /* + * Put back the real size. + */ + ip->i_size = length; + DIP_SET(ip, i_size, length); + if (DIP(ip, i_blocks) >= blocksreleased) + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - blocksreleased); + else /* sanity */ + DIP_SET(ip, i_blocks, 0); + ip->i_flag |= IN_CHANGE; +#ifdef QUOTA + (void) chkdq(ip, -blocksreleased, NOCRED, 0); +#endif + return (allerror); + +extclean: + if (journaltrunc) + softdep_journal_freeblocks(ip, cred, length, IO_EXT); + else + softdep_setup_freeblocks(ip, length, IO_EXT); + return (ffs_update(vp, (flags & IO_SYNC) != 0 || !DOINGASYNC(vp))); +} + +/* + * Release blocks associated with the inode ip and stored in the indirect + * block bn. Blocks are free'd in LIFO order up to (but not including) + * lastbn. If level is greater than SINGLE, the block is an indirect block + * and recursive calls to indirtrunc must be used to cleanse other indirect + * blocks. + */ +static int +ffs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) + struct inode *ip; + ufs2_daddr_t lbn, lastbn; + ufs2_daddr_t dbn; + int level; + ufs2_daddr_t *countp; +{ + struct buf *bp; + struct fs *fs; + struct vnode *vp; + caddr_t copy = NULL; + int i, nblocks, error = 0, allerror = 0; + ufs2_daddr_t nb, nlbn, last; + ufs2_daddr_t blkcount, factor, blocksreleased = 0; + ufs1_daddr_t *bap1 = NULL; + ufs2_daddr_t *bap2 = NULL; +#define BAP(ip, i) (I_IS_UFS1(ip) ? bap1[i] : bap2[i]) + + fs = ITOFS(ip); + + /* + * Calculate index in current block of last + * block to be kept. -1 indicates the entire + * block so we need not calculate the index. + */ + factor = lbn_offset(fs, level); + last = lastbn; + if (lastbn > 0) + last /= factor; + nblocks = btodb(fs->fs_bsize); + /* + * Get buffer of block pointers, zero those entries corresponding + * to blocks to be free'd, and update on disk copy first. Since + * double(triple) indirect before single(double) indirect, calls + * to bmap on these blocks will fail. However, we already have + * the on disk address, so we have to set the b_blkno field + * explicitly instead of letting bread do everything for us. + */ + vp = ITOV(ip); + bp = getblk(vp, lbn, (int)fs->fs_bsize, 0, 0, 0); + if ((bp->b_flags & B_CACHE) == 0) { +#ifdef RACCT + if (racct_enable) { + PROC_LOCK(curproc); + racct_add_buf(curproc, bp, 0); + PROC_UNLOCK(curproc); + } +#endif /* RACCT */ + curthread->td_ru.ru_inblock++; /* pay for read */ + bp->b_iocmd = BIO_READ; + bp->b_flags &= ~B_INVAL; + bp->b_ioflags &= ~BIO_ERROR; + if (bp->b_bcount > bp->b_bufsize) + panic("ffs_indirtrunc: bad buffer size"); + bp->b_blkno = dbn; + vfs_busy_pages(bp, 0); + bp->b_iooffset = dbtob(bp->b_blkno); + bstrategy(bp); + error = bufwait(bp); + } + if (error) { + brelse(bp); + *countp = 0; + return (error); + } + + if (I_IS_UFS1(ip)) + bap1 = (ufs1_daddr_t *)bp->b_data; + else + bap2 = (ufs2_daddr_t *)bp->b_data; + if (lastbn != -1) { + copy = malloc(fs->fs_bsize, M_TEMP, M_WAITOK); + bcopy((caddr_t)bp->b_data, copy, (u_int)fs->fs_bsize); + for (i = last + 1; i < NINDIR(fs); i++) + if (I_IS_UFS1(ip)) + bap1[i] = 0; + else + bap2[i] = 0; + if (DOINGASYNC(vp)) { + bdwrite(bp); + } else { + error = bwrite(bp); + if (error) + allerror = error; + } + if (I_IS_UFS1(ip)) + bap1 = (ufs1_daddr_t *)copy; + else + bap2 = (ufs2_daddr_t *)copy; + } + + /* + * Recursively free totally unused blocks. + */ + for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; + i--, nlbn += factor) { + nb = BAP(ip, i); + if (nb == 0) + continue; + if (level > SINGLE) { + if ((error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), + (ufs2_daddr_t)-1, level - 1, &blkcount)) != 0) + allerror = error; + blocksreleased += blkcount; + } + ffs_blkfree(ITOUMP(ip), fs, ITODEVVP(ip), nb, fs->fs_bsize, + ip->i_number, vp->v_type, NULL); + blocksreleased += nblocks; + } + + /* + * Recursively free last partial block. + */ + if (level > SINGLE && lastbn >= 0) { + last = lastbn % factor; + nb = BAP(ip, i); + if (nb != 0) { + error = ffs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), + last, level - 1, &blkcount); + if (error) + allerror = error; + blocksreleased += blkcount; + } + } + if (copy != NULL) { + free(copy, M_TEMP); + } else { + bp->b_flags |= B_INVAL | B_NOCACHE; + brelse(bp); + } + + *countp = blocksreleased; + return (allerror); +} + +int +ffs_rdonly(struct inode *ip) +{ + + return (ITOFS(ip)->fs_ronly != 0); +} + diff --git a/Dump/ufs/ffs/ffs_rawread.c b/Dump/ufs/ffs/ffs_rawread.c new file mode 100644 index 0000000..4cb577a --- /dev/null +++ b/Dump/ufs/ffs/ffs_rawread.c @@ -0,0 +1,474 @@ +/*- + * Copyright (c) 2000-2003 Tor Egge + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_rawread.c 318266 2017-05-14 11:51:30Z kib $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static int ffs_rawread_readahead(struct vnode *vp, + caddr_t udata, + off_t offset, + size_t len, + struct thread *td, + struct buf *bp); +static int ffs_rawread_main(struct vnode *vp, + struct uio *uio); + +static int ffs_rawread_sync(struct vnode *vp); + +int ffs_rawread(struct vnode *vp, struct uio *uio, int *workdone); + +SYSCTL_DECL(_vfs_ffs); + +static int ffsrawbufcnt = 4; +SYSCTL_INT(_vfs_ffs, OID_AUTO, ffsrawbufcnt, CTLFLAG_RD, &ffsrawbufcnt, 0, + "Buffers available for raw reads"); + +static int allowrawread = 1; +SYSCTL_INT(_vfs_ffs, OID_AUTO, allowrawread, CTLFLAG_RW, &allowrawread, 0, + "Flag to enable raw reads"); + +static int rawreadahead = 1; +SYSCTL_INT(_vfs_ffs, OID_AUTO, rawreadahead, CTLFLAG_RW, &rawreadahead, 0, + "Flag to enable readahead for long raw reads"); + +static void +ffs_rawread_setup(void *arg __unused) +{ + + ffsrawbufcnt = (nswbuf > 100 ) ? (nswbuf - (nswbuf >> 4)) : nswbuf - 8; +} +SYSINIT(ffs_raw, SI_SUB_VM_CONF, SI_ORDER_ANY, ffs_rawread_setup, NULL); + +static int +ffs_rawread_sync(struct vnode *vp) +{ + int error; + int upgraded; + struct bufobj *bo; + struct mount *mp; + vm_object_t obj; + + /* Check for dirty mmap, pending writes and dirty buffers */ + bo = &vp->v_bufobj; + BO_LOCK(bo); + VI_LOCK(vp); + if (bo->bo_numoutput > 0 || + bo->bo_dirty.bv_cnt > 0 || + ((obj = vp->v_object) != NULL && + (obj->flags & OBJ_MIGHTBEDIRTY) != 0)) { + VI_UNLOCK(vp); + BO_UNLOCK(bo); + + if (vn_start_write(vp, &mp, V_NOWAIT) != 0) { + if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) + upgraded = 1; + else + upgraded = 0; + VOP_UNLOCK(vp, 0); + (void) vn_start_write(vp, &mp, V_WAIT); + VOP_LOCK(vp, LK_EXCLUSIVE); + } else if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { + upgraded = 1; + /* Upgrade to exclusive lock, this might block */ + VOP_LOCK(vp, LK_UPGRADE); + } else + upgraded = 0; + + + VI_LOCK(vp); + /* Check if vnode was reclaimed while unlocked. */ + if ((vp->v_iflag & VI_DOOMED) != 0) { + VI_UNLOCK(vp); + if (upgraded != 0) + VOP_LOCK(vp, LK_DOWNGRADE); + vn_finished_write(mp); + return (EIO); + } + /* Attempt to msync mmap() regions to clean dirty mmap */ + if ((obj = vp->v_object) != NULL && + (obj->flags & OBJ_MIGHTBEDIRTY) != 0) { + VI_UNLOCK(vp); + VM_OBJECT_WLOCK(obj); + vm_object_page_clean(obj, 0, 0, OBJPC_SYNC); + VM_OBJECT_WUNLOCK(obj); + } else + VI_UNLOCK(vp); + + /* Wait for pending writes to complete */ + BO_LOCK(bo); + error = bufobj_wwait(&vp->v_bufobj, 0, 0); + if (error != 0) { + /* XXX: can't happen with a zero timeout ??? */ + BO_UNLOCK(bo); + if (upgraded != 0) + VOP_LOCK(vp, LK_DOWNGRADE); + vn_finished_write(mp); + return (error); + } + /* Flush dirty buffers */ + if (bo->bo_dirty.bv_cnt > 0) { + BO_UNLOCK(bo); + if ((error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0) { + if (upgraded != 0) + VOP_LOCK(vp, LK_DOWNGRADE); + vn_finished_write(mp); + return (error); + } + BO_LOCK(bo); + if (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0) + panic("ffs_rawread_sync: dirty bufs"); + } + BO_UNLOCK(bo); + if (upgraded != 0) + VOP_LOCK(vp, LK_DOWNGRADE); + vn_finished_write(mp); + } else { + VI_UNLOCK(vp); + BO_UNLOCK(bo); + } + return 0; +} + + +static int +ffs_rawread_readahead(struct vnode *vp, + caddr_t udata, + off_t offset, + size_t len, + struct thread *td, + struct buf *bp) +{ + int error; + u_int iolen; + off_t blockno; + int blockoff; + int bsize; + struct vnode *dp; + int bforwards; + struct inode *ip; + ufs2_daddr_t blkno; + + bsize = vp->v_mount->mnt_stat.f_iosize; + + ip = VTOI(vp); + dp = ITODEVVP(ip); + + iolen = ((vm_offset_t) udata) & PAGE_MASK; + bp->b_bcount = len; + if (bp->b_bcount + iolen > bp->b_kvasize) { + bp->b_bcount = bp->b_kvasize; + if (iolen != 0) + bp->b_bcount -= PAGE_SIZE; + } + bp->b_flags = 0; /* XXX necessary ? */ + bp->b_iocmd = BIO_READ; + bp->b_iodone = bdone; + bp->b_data = udata; + blockno = offset / bsize; + blockoff = (offset % bsize) / DEV_BSIZE; + if ((daddr_t) blockno != blockno) { + return EINVAL; /* blockno overflow */ + } + + bp->b_lblkno = bp->b_blkno = blockno; + + error = ufs_bmaparray(vp, bp->b_lblkno, &blkno, NULL, &bforwards, NULL); + if (error != 0) + return error; + if (blkno == -1) { + + /* Fill holes with NULs to preserve semantics */ + + if (bp->b_bcount + blockoff * DEV_BSIZE > bsize) + bp->b_bcount = bsize - blockoff * DEV_BSIZE; + bp->b_bufsize = bp->b_bcount; + + if (vmapbuf(bp, 1) < 0) + return EFAULT; + + maybe_yield(); + bzero(bp->b_data, bp->b_bufsize); + + /* Mark operation completed (similar to bufdone()) */ + + bp->b_resid = 0; + bp->b_flags |= B_DONE; + return 0; + } + bp->b_blkno = blkno + blockoff; + bp->b_offset = bp->b_iooffset = (blkno + blockoff) * DEV_BSIZE; + + if (bp->b_bcount + blockoff * DEV_BSIZE > bsize * (1 + bforwards)) + bp->b_bcount = bsize * (1 + bforwards) - blockoff * DEV_BSIZE; + bp->b_bufsize = bp->b_bcount; + + if (vmapbuf(bp, 1) < 0) + return EFAULT; + + BO_STRATEGY(&dp->v_bufobj, bp); + return 0; +} + + +static int +ffs_rawread_main(struct vnode *vp, + struct uio *uio) +{ + int error, nerror; + struct buf *bp, *nbp, *tbp; + u_int iolen; + caddr_t udata; + long resid; + off_t offset; + struct thread *td; + + td = uio->uio_td ? uio->uio_td : curthread; + udata = uio->uio_iov->iov_base; + resid = uio->uio_resid; + offset = uio->uio_offset; + + /* + * keep the process from being swapped + */ + PHOLD(td->td_proc); + + error = 0; + nerror = 0; + + bp = NULL; + nbp = NULL; + + while (resid > 0) { + + if (bp == NULL) { /* Setup first read */ + /* XXX: Leave some bufs for swap */ + bp = getpbuf(&ffsrawbufcnt); + pbgetvp(vp, bp); + error = ffs_rawread_readahead(vp, udata, offset, + resid, td, bp); + if (error != 0) + break; + + if (resid > bp->b_bufsize) { /* Setup fist readahead */ + /* XXX: Leave bufs for swap */ + if (rawreadahead != 0) + nbp = trypbuf(&ffsrawbufcnt); + else + nbp = NULL; + if (nbp != NULL) { + pbgetvp(vp, nbp); + + nerror = ffs_rawread_readahead(vp, + udata + + bp->b_bufsize, + offset + + bp->b_bufsize, + resid - + bp->b_bufsize, + td, + nbp); + if (nerror) { + pbrelvp(nbp); + relpbuf(nbp, &ffsrawbufcnt); + nbp = NULL; + } + } + } + } + + bwait(bp, PRIBIO, "rawrd"); + vunmapbuf(bp); + + iolen = bp->b_bcount - bp->b_resid; + if (iolen == 0 && (bp->b_ioflags & BIO_ERROR) == 0) { + nerror = 0; /* Ignore possible beyond EOF error */ + break; /* EOF */ + } + + if ((bp->b_ioflags & BIO_ERROR) != 0) { + error = bp->b_error; + break; + } + resid -= iolen; + udata += iolen; + offset += iolen; + if (iolen < bp->b_bufsize) { + /* Incomplete read. Try to read remaining part */ + error = ffs_rawread_readahead(vp, + udata, + offset, + bp->b_bufsize - iolen, + td, + bp); + if (error != 0) + break; + } else if (nbp != NULL) { /* Complete read with readahead */ + + tbp = bp; + bp = nbp; + nbp = tbp; + + if (resid <= bp->b_bufsize) { /* No more readaheads */ + pbrelvp(nbp); + relpbuf(nbp, &ffsrawbufcnt); + nbp = NULL; + } else { /* Setup next readahead */ + nerror = ffs_rawread_readahead(vp, + udata + + bp->b_bufsize, + offset + + bp->b_bufsize, + resid - + bp->b_bufsize, + td, + nbp); + if (nerror != 0) { + pbrelvp(nbp); + relpbuf(nbp, &ffsrawbufcnt); + nbp = NULL; + } + } + } else if (nerror != 0) {/* Deferred Readahead error */ + break; + } else if (resid > 0) { /* More to read, no readahead */ + error = ffs_rawread_readahead(vp, udata, offset, + resid, td, bp); + if (error != 0) + break; + } + } + + if (bp != NULL) { + pbrelvp(bp); + relpbuf(bp, &ffsrawbufcnt); + } + if (nbp != NULL) { /* Run down readahead buffer */ + bwait(nbp, PRIBIO, "rawrd"); + vunmapbuf(nbp); + pbrelvp(nbp); + relpbuf(nbp, &ffsrawbufcnt); + } + + if (error == 0) + error = nerror; + PRELE(td->td_proc); + uio->uio_iov->iov_base = udata; + uio->uio_resid = resid; + uio->uio_offset = offset; + return error; +} + + +int +ffs_rawread(struct vnode *vp, + struct uio *uio, + int *workdone) +{ + if (allowrawread != 0 && + uio->uio_iovcnt == 1 && + uio->uio_segflg == UIO_USERSPACE && + uio->uio_resid == uio->uio_iov->iov_len && + (((uio->uio_td != NULL) ? uio->uio_td : curthread)->td_pflags & + TDP_DEADLKTREAT) == 0) { + int secsize; /* Media sector size */ + off_t filebytes; /* Bytes left of file */ + int blockbytes; /* Bytes left of file in full blocks */ + int partialbytes; /* Bytes in last partial block */ + int skipbytes; /* Bytes not to read in ffs_rawread */ + struct inode *ip; + int error; + + + /* Only handle sector aligned reads */ + ip = VTOI(vp); + secsize = ITODEVVP(ip)->v_bufobj.bo_bsize; + if ((uio->uio_offset & (secsize - 1)) == 0 && + (uio->uio_resid & (secsize - 1)) == 0) { + + /* Sync dirty pages and buffers if needed */ + error = ffs_rawread_sync(vp); + if (error != 0) + return error; + + /* Check for end of file */ + if (ip->i_size > uio->uio_offset) { + filebytes = ip->i_size - uio->uio_offset; + + /* No special eof handling needed ? */ + if (uio->uio_resid <= filebytes) { + *workdone = 1; + return ffs_rawread_main(vp, uio); + } + + partialbytes = ((unsigned int) ip->i_size) % + ITOFS(ip)->fs_bsize; + blockbytes = (int) filebytes - partialbytes; + if (blockbytes > 0) { + skipbytes = uio->uio_resid - + blockbytes; + uio->uio_resid = blockbytes; + error = ffs_rawread_main(vp, uio); + uio->uio_resid += skipbytes; + if (error != 0) + return error; + /* Read remaining part using buffer */ + } + } + } + } + *workdone = 0; + return 0; +} diff --git a/Dump/ufs/ffs/ffs_snapshot.c b/Dump/ufs/ffs/ffs_snapshot.c new file mode 100644 index 0000000..f30dfca --- /dev/null +++ b/Dump/ufs/ffs/ffs_snapshot.c @@ -0,0 +1,2699 @@ +/*- + * Copyright 2000 Marshall Kirk McKusick. All Rights Reserved. + * + * Further information about snapshots can be obtained from: + * + * Marshall Kirk McKusick http://www.mckusick.com/softdep/ + * 1614 Oxford Street mckusick@mckusick.com + * Berkeley, CA 94709-1608 +1-510-843-9542 + * USA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY MARSHALL KIRK MCKUSICK ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL MARSHALL KIRK MCKUSICK BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_snapshot.c 8.11 (McKusick) 7/23/00 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_snapshot.c 322130 2017-08-07 02:17:15Z mckusick $"); + +#include "opt_quota.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define KERNCRED thread0.td_ucred +#define DEBUG 1 + +#include "opt_ffs.h" + +#ifdef NO_FFS_SNAPSHOT +int +ffs_snapshot(mp, snapfile) + struct mount *mp; + char *snapfile; +{ + return (EINVAL); +} + +int +ffs_snapblkfree(fs, devvp, bno, size, inum, vtype, wkhd) + struct fs *fs; + struct vnode *devvp; + ufs2_daddr_t bno; + long size; + ino_t inum; + enum vtype vtype; + struct workhead *wkhd; +{ + return (EINVAL); +} + +void +ffs_snapremove(vp) + struct vnode *vp; +{ +} + +void +ffs_snapshot_mount(mp) + struct mount *mp; +{ +} + +void +ffs_snapshot_unmount(mp) + struct mount *mp; +{ +} + +void +ffs_snapgone(ip) + struct inode *ip; +{ +} + +int +ffs_copyonwrite(devvp, bp) + struct vnode *devvp; + struct buf *bp; +{ + return (EINVAL); +} + +void +ffs_sync_snap(mp, waitfor) + struct mount *mp; + int waitfor; +{ +} + +#else +FEATURE(ffs_snapshot, "FFS snapshot support"); + +LIST_HEAD(, snapdata) snapfree; +static struct mtx snapfree_lock; +MTX_SYSINIT(ffs_snapfree, &snapfree_lock, "snapdata free list", MTX_DEF); + +static int cgaccount(int, struct vnode *, struct buf *, int); +static int expunge_ufs1(struct vnode *, struct inode *, struct fs *, + int (*)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, struct fs *, + ufs_lbn_t, int), int, int); +static int indiracct_ufs1(struct vnode *, struct vnode *, int, + ufs1_daddr_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, struct fs *, + int (*)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, struct fs *, + ufs_lbn_t, int), int); +static int fullacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int snapacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int mapacct_ufs1(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int expunge_ufs2(struct vnode *, struct inode *, struct fs *, + int (*)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *, + ufs_lbn_t, int), int, int); +static int indiracct_ufs2(struct vnode *, struct vnode *, int, + ufs2_daddr_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, ufs_lbn_t, struct fs *, + int (*)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *, + ufs_lbn_t, int), int); +static int fullacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int snapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int mapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); +static int readblock(struct vnode *vp, struct buf *, ufs2_daddr_t); +static void try_free_snapdata(struct vnode *devvp); +static struct snapdata *ffs_snapdata_acquire(struct vnode *devvp); +static int ffs_bp_snapblk(struct vnode *, struct buf *); + +/* + * To ensure the consistency of snapshots across crashes, we must + * synchronously write out copied blocks before allowing the + * originals to be modified. Because of the rather severe speed + * penalty that this imposes, the code normally only ensures + * persistence for the filesystem metadata contained within a + * snapshot. Setting the following flag allows this crash + * persistence to be enabled for file contents. + */ +int dopersistence = 0; + +#ifdef DEBUG +#include +SYSCTL_INT(_debug, OID_AUTO, dopersistence, CTLFLAG_RW, &dopersistence, 0, ""); +static int snapdebug = 0; +SYSCTL_INT(_debug, OID_AUTO, snapdebug, CTLFLAG_RW, &snapdebug, 0, ""); +int collectsnapstats = 0; +SYSCTL_INT(_debug, OID_AUTO, collectsnapstats, CTLFLAG_RW, &collectsnapstats, + 0, ""); +#endif /* DEBUG */ + +/* + * Create a snapshot file and initialize it for the filesystem. + */ +int +ffs_snapshot(mp, snapfile) + struct mount *mp; + char *snapfile; +{ + ufs2_daddr_t numblks, blkno, *blkp, *snapblklist; + int error, cg, snaploc; + int i, size, len, loc; + ufs2_daddr_t blockno; + uint64_t flag; + struct timespec starttime = {0, 0}, endtime; + char saved_nice = 0; + long redo = 0, snaplistsize = 0; + int32_t *lp; + void *space; + struct fs *copy_fs = NULL, *fs; + struct thread *td = curthread; + struct inode *ip, *xp; + struct buf *bp, *nbp, *ibp; + struct nameidata nd; + struct mount *wrtmp; + struct vattr vat; + struct vnode *vp, *xvp, *mvp, *devvp; + struct uio auio; + struct iovec aiov; + struct snapdata *sn; + struct ufsmount *ump; + + ump = VFSTOUFS(mp); + fs = ump->um_fs; + sn = NULL; + /* + * At the moment, journaled soft updates cannot support + * taking snapshots. + */ + if (MOUNTEDSUJ(mp)) { + vfs_mount_error(mp, "%s: Snapshots are not yet supported when " + "running with journaled soft updates", fs->fs_fsmnt); + return (EOPNOTSUPP); + } + MNT_ILOCK(mp); + flag = mp->mnt_flag; + MNT_IUNLOCK(mp); + /* + * Need to serialize access to snapshot code per filesystem. + */ + /* + * Assign a snapshot slot in the superblock. + */ + UFS_LOCK(ump); + for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) + if (fs->fs_snapinum[snaploc] == 0) + break; + UFS_UNLOCK(ump); + if (snaploc == FSMAXSNAP) + return (ENOSPC); + /* + * Create the snapshot file. + */ +restart: + NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | NOCACHE, UIO_SYSSPACE, + snapfile, td); + if ((error = namei(&nd)) != 0) + return (error); + if (nd.ni_vp != NULL) { + vput(nd.ni_vp); + error = EEXIST; + } + if (nd.ni_dvp->v_mount != mp) + error = EXDEV; + if (error) { + NDFREE(&nd, NDF_ONLY_PNBUF); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + return (error); + } + VATTR_NULL(&vat); + vat.va_type = VREG; + vat.va_mode = S_IRUSR; + vat.va_vaflags |= VA_EXCLUSIVE; + if (VOP_GETWRITEMOUNT(nd.ni_dvp, &wrtmp)) + wrtmp = NULL; + if (wrtmp != mp) + panic("ffs_snapshot: mount mismatch"); + vfs_rel(wrtmp); + if (vn_start_write(NULL, &wrtmp, V_NOWAIT) != 0) { + NDFREE(&nd, NDF_ONLY_PNBUF); + vput(nd.ni_dvp); + if ((error = vn_start_write(NULL, &wrtmp, + V_XSLEEP | PCATCH)) != 0) + return (error); + goto restart; + } + error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vat); + VOP_UNLOCK(nd.ni_dvp, 0); + if (error) { + NDFREE(&nd, NDF_ONLY_PNBUF); + vn_finished_write(wrtmp); + vrele(nd.ni_dvp); + return (error); + } + vp = nd.ni_vp; + vp->v_vflag |= VV_SYSTEM; + ip = VTOI(vp); + devvp = ITODEVVP(ip); + /* + * Allocate and copy the last block contents so as to be able + * to set size to that of the filesystem. + */ + numblks = howmany(fs->fs_size, fs->fs_frag); + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)(numblks - 1)), + fs->fs_bsize, KERNCRED, BA_CLRBUF, &bp); + if (error) + goto out; + ip->i_size = lblktosize(fs, (off_t)numblks); + DIP_SET(ip, i_size, ip->i_size); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + error = readblock(vp, bp, numblks - 1); + bawrite(bp); + if (error != 0) + goto out; + /* + * Preallocate critical data structures so that we can copy + * them in without further allocation after we suspend all + * operations on the filesystem. We would like to just release + * the allocated buffers without writing them since they will + * be filled in below once we are ready to go, but this upsets + * the soft update code, so we go ahead and write the new buffers. + * + * Allocate all indirect blocks and mark all of them as not + * needing to be copied. + */ + for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) { + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)blkno), + fs->fs_bsize, td->td_ucred, BA_METAONLY, &ibp); + if (error) + goto out; + bawrite(ibp); + } + /* + * Allocate copies for the superblock and its summary information. + */ + error = UFS_BALLOC(vp, fs->fs_sblockloc, fs->fs_sbsize, KERNCRED, + 0, &nbp); + if (error) + goto out; + bawrite(nbp); + blkno = fragstoblks(fs, fs->fs_csaddr); + len = howmany(fs->fs_cssize, fs->fs_bsize); + for (loc = 0; loc < len; loc++) { + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)(blkno + loc)), + fs->fs_bsize, KERNCRED, 0, &nbp); + if (error) + goto out; + bawrite(nbp); + } + /* + * Allocate all cylinder group blocks. + */ + for (cg = 0; cg < fs->fs_ncg; cg++) { + error = UFS_BALLOC(vp, lfragtosize(fs, cgtod(fs, cg)), + fs->fs_bsize, KERNCRED, 0, &nbp); + if (error) + goto out; + bawrite(nbp); + if (cg % 10 == 0) + ffs_syncvnode(vp, MNT_WAIT, 0); + } + /* + * Copy all the cylinder group maps. Although the + * filesystem is still active, we hope that only a few + * cylinder groups will change between now and when we + * suspend operations. Thus, we will be able to quickly + * touch up the few cylinder groups that changed during + * the suspension period. + */ + len = howmany(fs->fs_ncg, NBBY); + space = malloc(len, M_DEVBUF, M_WAITOK|M_ZERO); + UFS_LOCK(ump); + fs->fs_active = space; + UFS_UNLOCK(ump); + for (cg = 0; cg < fs->fs_ncg; cg++) { + error = UFS_BALLOC(vp, lfragtosize(fs, cgtod(fs, cg)), + fs->fs_bsize, KERNCRED, 0, &nbp); + if (error) + goto out; + error = cgaccount(cg, vp, nbp, 1); + bawrite(nbp); + if (cg % 10 == 0) + ffs_syncvnode(vp, MNT_WAIT, 0); + if (error) + goto out; + } + /* + * Change inode to snapshot type file. + */ + ip->i_flags |= SF_SNAPSHOT; + DIP_SET(ip, i_flags, ip->i_flags); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + /* + * Ensure that the snapshot is completely on disk. + * Since we have marked it as a snapshot it is safe to + * unlock it as no process will be allowed to write to it. + */ + if ((error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0) + goto out; + VOP_UNLOCK(vp, 0); + /* + * All allocations are done, so we can now snapshot the system. + * + * Recind nice scheduling while running with the filesystem suspended. + */ + if (td->td_proc->p_nice > 0) { + struct proc *p; + + p = td->td_proc; + PROC_LOCK(p); + saved_nice = p->p_nice; + sched_nice(p, 0); + PROC_UNLOCK(p); + } + /* + * Suspend operation on filesystem. + */ + for (;;) { + vn_finished_write(wrtmp); + if ((error = vfs_write_suspend(vp->v_mount, 0)) != 0) { + vn_start_write(NULL, &wrtmp, V_WAIT); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + goto out; + } + if (mp->mnt_kern_flag & MNTK_SUSPENDED) + break; + vn_start_write(NULL, &wrtmp, V_WAIT); + } + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + if (ip->i_effnlink == 0) { + error = ENOENT; /* Snapshot file unlinked */ + goto out1; + } + if (collectsnapstats) + nanotime(&starttime); + + /* The last block might have changed. Copy it again to be sure. */ + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)(numblks - 1)), + fs->fs_bsize, KERNCRED, BA_CLRBUF, &bp); + if (error != 0) + goto out1; + error = readblock(vp, bp, numblks - 1); + bp->b_flags |= B_VALIDSUSPWRT; + bawrite(bp); + if (error != 0) + goto out1; + /* + * First, copy all the cylinder group maps that have changed. + */ + for (cg = 0; cg < fs->fs_ncg; cg++) { + if ((ACTIVECGNUM(fs, cg) & ACTIVECGOFF(cg)) != 0) + continue; + redo++; + error = UFS_BALLOC(vp, lfragtosize(fs, cgtod(fs, cg)), + fs->fs_bsize, KERNCRED, 0, &nbp); + if (error) + goto out1; + error = cgaccount(cg, vp, nbp, 2); + bawrite(nbp); + if (error) + goto out1; + } + /* + * Grab a copy of the superblock and its summary information. + * We delay writing it until the suspension is released below. + */ + copy_fs = malloc((u_long)fs->fs_bsize, M_UFSMNT, M_WAITOK); + bcopy(fs, copy_fs, fs->fs_sbsize); + if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) + copy_fs->fs_clean = 1; + size = fs->fs_bsize < SBLOCKSIZE ? fs->fs_bsize : SBLOCKSIZE; + if (fs->fs_sbsize < size) + bzero(&((char *)copy_fs)[fs->fs_sbsize], + size - fs->fs_sbsize); + size = blkroundup(fs, fs->fs_cssize); + if (fs->fs_contigsumsize > 0) + size += fs->fs_ncg * sizeof(int32_t); + space = malloc((u_long)size, M_UFSMNT, M_WAITOK); + copy_fs->fs_csp = space; + bcopy(fs->fs_csp, copy_fs->fs_csp, fs->fs_cssize); + space = (char *)space + fs->fs_cssize; + loc = howmany(fs->fs_cssize, fs->fs_fsize); + i = fs->fs_frag - loc % fs->fs_frag; + len = (i == fs->fs_frag) ? 0 : i * fs->fs_fsize; + if (len > 0) { + if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + loc), + len, KERNCRED, &bp)) != 0) { + brelse(bp); + free(copy_fs->fs_csp, M_UFSMNT); + free(copy_fs, M_UFSMNT); + copy_fs = NULL; + goto out1; + } + bcopy(bp->b_data, space, (u_int)len); + space = (char *)space + len; + bp->b_flags |= B_INVAL | B_NOCACHE; + brelse(bp); + } + if (fs->fs_contigsumsize > 0) { + copy_fs->fs_maxcluster = lp = space; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + } + /* + * We must check for active files that have been unlinked + * (e.g., with a zero link count). We have to expunge all + * trace of these files from the snapshot so that they are + * not reclaimed prematurely by fsck or unnecessarily dumped. + * We turn off the MNTK_SUSPENDED flag to avoid a panic from + * spec_strategy about writing on a suspended filesystem. + * Note that we skip unlinked snapshot files as they will + * be handled separately below. + * + * We also calculate the needed size for the snapshot list. + */ + snaplistsize = fs->fs_ncg + howmany(fs->fs_cssize, fs->fs_bsize) + + FSMAXSNAP + 1 /* superblock */ + 1 /* last block */ + 1 /* size */; + MNT_ILOCK(mp); + mp->mnt_kern_flag &= ~MNTK_SUSPENDED; + MNT_IUNLOCK(mp); +loop: + MNT_VNODE_FOREACH_ALL(xvp, mp, mvp) { + if ((xvp->v_usecount == 0 && + (xvp->v_iflag & (VI_OWEINACT | VI_DOINGINACT)) == 0) || + xvp->v_type == VNON || + IS_SNAPSHOT(VTOI(xvp))) { + VI_UNLOCK(xvp); + continue; + } + /* + * We can skip parent directory vnode because it must have + * this snapshot file in it. + */ + if (xvp == nd.ni_dvp) { + VI_UNLOCK(xvp); + continue; + } + vholdl(xvp); + if (vn_lock(xvp, LK_EXCLUSIVE | LK_INTERLOCK) != 0) { + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + vdrop(xvp); + goto loop; + } + VI_LOCK(xvp); + if (xvp->v_usecount == 0 && + (xvp->v_iflag & (VI_OWEINACT | VI_DOINGINACT)) == 0) { + VI_UNLOCK(xvp); + VOP_UNLOCK(xvp, 0); + vdrop(xvp); + continue; + } + VI_UNLOCK(xvp); + if (snapdebug) + vn_printf(xvp, "ffs_snapshot: busy vnode "); + if (VOP_GETATTR(xvp, &vat, td->td_ucred) == 0 && + vat.va_nlink > 0) { + VOP_UNLOCK(xvp, 0); + vdrop(xvp); + continue; + } + xp = VTOI(xvp); + if (ffs_checkfreefile(copy_fs, vp, xp->i_number)) { + VOP_UNLOCK(xvp, 0); + vdrop(xvp); + continue; + } + /* + * If there is a fragment, clear it here. + */ + blkno = 0; + loc = howmany(xp->i_size, fs->fs_bsize) - 1; + if (loc < NDADDR) { + len = fragroundup(fs, blkoff(fs, xp->i_size)); + if (len != 0 && len < fs->fs_bsize) { + ffs_blkfree(ump, copy_fs, vp, + DIP(xp, i_db[loc]), len, xp->i_number, + xvp->v_type, NULL); + blkno = DIP(xp, i_db[loc]); + DIP_SET(xp, i_db[loc], 0); + } + } + snaplistsize += 1; + if (I_IS_UFS1(xp)) + error = expunge_ufs1(vp, xp, copy_fs, fullacct_ufs1, + BLK_NOCOPY, 1); + else + error = expunge_ufs2(vp, xp, copy_fs, fullacct_ufs2, + BLK_NOCOPY, 1); + if (blkno) + DIP_SET(xp, i_db[loc], blkno); + if (!error) + error = ffs_freefile(ump, copy_fs, vp, xp->i_number, + xp->i_mode, NULL); + VOP_UNLOCK(xvp, 0); + vdrop(xvp); + if (error) { + free(copy_fs->fs_csp, M_UFSMNT); + free(copy_fs, M_UFSMNT); + copy_fs = NULL; + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + goto out1; + } + } + /* + * Erase the journal file from the snapshot. + */ + if (fs->fs_flags & FS_SUJ) { + error = softdep_journal_lookup(mp, &xvp); + if (error) { + free(copy_fs->fs_csp, M_UFSMNT); + free(copy_fs, M_UFSMNT); + copy_fs = NULL; + goto out1; + } + xp = VTOI(xvp); + if (I_IS_UFS1(xp)) + error = expunge_ufs1(vp, xp, copy_fs, fullacct_ufs1, + BLK_NOCOPY, 0); + else + error = expunge_ufs2(vp, xp, copy_fs, fullacct_ufs2, + BLK_NOCOPY, 0); + vput(xvp); + } + /* + * Acquire a lock on the snapdata structure, creating it if necessary. + */ + sn = ffs_snapdata_acquire(devvp); + /* + * Change vnode to use shared snapshot lock instead of the original + * private lock. + */ + vp->v_vnlock = &sn->sn_lock; + lockmgr(&vp->v_lock, LK_RELEASE, NULL); + xp = TAILQ_FIRST(&sn->sn_head); + /* + * If this is the first snapshot on this filesystem, then we need + * to allocate the space for the list of preallocated snapshot blocks. + * This list will be refined below, but this preliminary one will + * keep us out of deadlock until the full one is ready. + */ + if (xp == NULL) { + snapblklist = malloc(snaplistsize * sizeof(daddr_t), + M_UFSMNT, M_WAITOK); + blkp = &snapblklist[1]; + *blkp++ = lblkno(fs, fs->fs_sblockloc); + blkno = fragstoblks(fs, fs->fs_csaddr); + for (cg = 0; cg < fs->fs_ncg; cg++) { + if (fragstoblks(fs, cgtod(fs, cg) > blkno)) + break; + *blkp++ = fragstoblks(fs, cgtod(fs, cg)); + } + len = howmany(fs->fs_cssize, fs->fs_bsize); + for (loc = 0; loc < len; loc++) + *blkp++ = blkno + loc; + for (; cg < fs->fs_ncg; cg++) + *blkp++ = fragstoblks(fs, cgtod(fs, cg)); + snapblklist[0] = blkp - snapblklist; + VI_LOCK(devvp); + if (sn->sn_blklist != NULL) + panic("ffs_snapshot: non-empty list"); + sn->sn_blklist = snapblklist; + sn->sn_listsize = blkp - snapblklist; + VI_UNLOCK(devvp); + } + /* + * Record snapshot inode. Since this is the newest snapshot, + * it must be placed at the end of the list. + */ + VI_LOCK(devvp); + fs->fs_snapinum[snaploc] = ip->i_number; + if (ip->i_nextsnap.tqe_prev != 0) + panic("ffs_snapshot: %ju already on list", + (uintmax_t)ip->i_number); + TAILQ_INSERT_TAIL(&sn->sn_head, ip, i_nextsnap); + devvp->v_vflag |= VV_COPYONWRITE; + VI_UNLOCK(devvp); + ASSERT_VOP_LOCKED(vp, "ffs_snapshot vp"); +out1: + KASSERT((sn != NULL && copy_fs != NULL && error == 0) || + (sn == NULL && copy_fs == NULL && error != 0), + ("email phk@ and mckusick@")); + /* + * Resume operation on filesystem. + */ + vfs_write_resume(vp->v_mount, VR_START_WRITE | VR_NO_SUSPCLR); + if (collectsnapstats && starttime.tv_sec > 0) { + nanotime(&endtime); + timespecsub(&endtime, &starttime); + printf("%s: suspended %ld.%03ld sec, redo %ld of %d\n", + vp->v_mount->mnt_stat.f_mntonname, (long)endtime.tv_sec, + endtime.tv_nsec / 1000000, redo, fs->fs_ncg); + } + if (copy_fs == NULL) + goto out; + /* + * Copy allocation information from all the snapshots in + * this snapshot and then expunge them from its view. + */ + TAILQ_FOREACH(xp, &sn->sn_head, i_nextsnap) { + if (xp == ip) + break; + if (I_IS_UFS1(xp)) + error = expunge_ufs1(vp, xp, fs, snapacct_ufs1, + BLK_SNAP, 0); + else + error = expunge_ufs2(vp, xp, fs, snapacct_ufs2, + BLK_SNAP, 0); + if (error == 0 && xp->i_effnlink == 0) { + error = ffs_freefile(ump, + copy_fs, + vp, + xp->i_number, + xp->i_mode, NULL); + } + if (error) { + fs->fs_snapinum[snaploc] = 0; + goto done; + } + } + /* + * Allocate space for the full list of preallocated snapshot blocks. + */ + snapblklist = malloc(snaplistsize * sizeof(daddr_t), + M_UFSMNT, M_WAITOK); + ip->i_snapblklist = &snapblklist[1]; + /* + * Expunge the blocks used by the snapshots from the set of + * blocks marked as used in the snapshot bitmaps. Also, collect + * the list of allocated blocks in i_snapblklist. + */ + if (I_IS_UFS1(ip)) + error = expunge_ufs1(vp, ip, copy_fs, mapacct_ufs1, + BLK_SNAP, 0); + else + error = expunge_ufs2(vp, ip, copy_fs, mapacct_ufs2, + BLK_SNAP, 0); + if (error) { + fs->fs_snapinum[snaploc] = 0; + free(snapblklist, M_UFSMNT); + goto done; + } + if (snaplistsize < ip->i_snapblklist - snapblklist) + panic("ffs_snapshot: list too small"); + snaplistsize = ip->i_snapblklist - snapblklist; + snapblklist[0] = snaplistsize; + ip->i_snapblklist = 0; + /* + * Write out the list of allocated blocks to the end of the snapshot. + */ + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (void *)snapblklist; + aiov.iov_len = snaplistsize * sizeof(daddr_t); + auio.uio_resid = aiov.iov_len; + auio.uio_offset = ip->i_size; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_td = td; + if ((error = VOP_WRITE(vp, &auio, IO_UNIT, td->td_ucred)) != 0) { + fs->fs_snapinum[snaploc] = 0; + free(snapblklist, M_UFSMNT); + goto done; + } + /* + * Write the superblock and its summary information + * to the snapshot. + */ + blkno = fragstoblks(fs, fs->fs_csaddr); + len = howmany(fs->fs_cssize, fs->fs_bsize); + space = copy_fs->fs_csp; + for (loc = 0; loc < len; loc++) { + error = bread(vp, blkno + loc, fs->fs_bsize, KERNCRED, &nbp); + if (error) { + brelse(nbp); + fs->fs_snapinum[snaploc] = 0; + free(snapblklist, M_UFSMNT); + goto done; + } + bcopy(space, nbp->b_data, fs->fs_bsize); + space = (char *)space + fs->fs_bsize; + bawrite(nbp); + } + error = bread(vp, lblkno(fs, fs->fs_sblockloc), fs->fs_bsize, + KERNCRED, &nbp); + if (error) { + brelse(nbp); + } else { + loc = blkoff(fs, fs->fs_sblockloc); + bcopy((char *)copy_fs, &nbp->b_data[loc], (u_int)fs->fs_sbsize); + bawrite(nbp); + } + /* + * As this is the newest list, it is the most inclusive, so + * should replace the previous list. + */ + VI_LOCK(devvp); + space = sn->sn_blklist; + sn->sn_blklist = snapblklist; + sn->sn_listsize = snaplistsize; + VI_UNLOCK(devvp); + if (space != NULL) + free(space, M_UFSMNT); + /* + * Preallocate all the direct blocks in the snapshot inode so + * that we never have to write the inode itself to commit an + * update to the contents of the snapshot. Note that once + * created, the size of the snapshot will never change, so + * there will never be a need to write the inode except to + * update the non-integrity-critical time fields and + * allocated-block count. + */ + for (blockno = 0; blockno < NDADDR; blockno++) { + if (DIP(ip, i_db[blockno]) != 0) + continue; + error = UFS_BALLOC(vp, lblktosize(fs, blockno), + fs->fs_bsize, KERNCRED, BA_CLRBUF, &bp); + if (error) + break; + error = readblock(vp, bp, blockno); + bawrite(bp); + if (error != 0) + break; + } +done: + free(copy_fs->fs_csp, M_UFSMNT); + free(copy_fs, M_UFSMNT); + copy_fs = NULL; +out: + NDFREE(&nd, NDF_ONLY_PNBUF); + if (saved_nice > 0) { + struct proc *p; + + p = td->td_proc; + PROC_LOCK(p); + sched_nice(td->td_proc, saved_nice); + PROC_UNLOCK(td->td_proc); + } + UFS_LOCK(ump); + if (fs->fs_active != 0) { + free(fs->fs_active, M_DEVBUF); + fs->fs_active = 0; + } + UFS_UNLOCK(ump); + MNT_ILOCK(mp); + mp->mnt_flag = (mp->mnt_flag & MNT_QUOTA) | (flag & ~MNT_QUOTA); + MNT_IUNLOCK(mp); + if (error) + (void) ffs_truncate(vp, (off_t)0, 0, NOCRED); + (void) ffs_syncvnode(vp, MNT_WAIT, 0); + if (error) + vput(vp); + else + VOP_UNLOCK(vp, 0); + vrele(nd.ni_dvp); + vn_finished_write(wrtmp); + process_deferred_inactive(mp); + return (error); +} + +/* + * Copy a cylinder group map. All the unallocated blocks are marked + * BLK_NOCOPY so that the snapshot knows that it need not copy them + * if they are later written. If passno is one, then this is a first + * pass, so only setting needs to be done. If passno is 2, then this + * is a revision to a previous pass which must be undone as the + * replacement pass is done. + */ +static int +cgaccount(cg, vp, nbp, passno) + int cg; + struct vnode *vp; + struct buf *nbp; + int passno; +{ + struct buf *bp, *ibp; + struct inode *ip; + struct cg *cgp; + struct fs *fs; + ufs2_daddr_t base, numblks; + int error, len, loc, indiroff; + + ip = VTOI(vp); + fs = ITOFS(ip); + error = bread(ITODEVVP(ip), fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, KERNCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) { + brelse(bp); + return (EIO); + } + UFS_LOCK(ITOUMP(ip)); + ACTIVESET(fs, cg); + /* + * Recomputation of summary information might not have been performed + * at mount time. Sync up summary information for current cylinder + * group while data is in memory to ensure that result of background + * fsck is slightly more consistent. + */ + fs->fs_cs(fs, cg) = cgp->cg_cs; + UFS_UNLOCK(ITOUMP(ip)); + bcopy(bp->b_data, nbp->b_data, fs->fs_cgsize); + if (fs->fs_cgsize < fs->fs_bsize) + bzero(&nbp->b_data[fs->fs_cgsize], + fs->fs_bsize - fs->fs_cgsize); + cgp = (struct cg *)nbp->b_data; + bqrelse(bp); + if (passno == 2) + nbp->b_flags |= B_VALIDSUSPWRT; + numblks = howmany(fs->fs_size, fs->fs_frag); + len = howmany(fs->fs_fpg, fs->fs_frag); + base = cgbase(fs, cg) / fs->fs_frag; + if (base + len >= numblks) + len = numblks - base - 1; + loc = 0; + if (base < NDADDR) { + for ( ; loc < NDADDR; loc++) { + if (ffs_isblock(fs, cg_blksfree(cgp), loc)) + DIP_SET(ip, i_db[loc], BLK_NOCOPY); + else if (passno == 2 && DIP(ip, i_db[loc])== BLK_NOCOPY) + DIP_SET(ip, i_db[loc], 0); + else if (passno == 1 && DIP(ip, i_db[loc])== BLK_NOCOPY) + panic("ffs_snapshot: lost direct block"); + } + } + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)(base + loc)), + fs->fs_bsize, KERNCRED, BA_METAONLY, &ibp); + if (error) { + return (error); + } + indiroff = (base + loc - NDADDR) % NINDIR(fs); + for ( ; loc < len; loc++, indiroff++) { + if (indiroff >= NINDIR(fs)) { + if (passno == 2) + ibp->b_flags |= B_VALIDSUSPWRT; + bawrite(ibp); + error = UFS_BALLOC(vp, + lblktosize(fs, (off_t)(base + loc)), + fs->fs_bsize, KERNCRED, BA_METAONLY, &ibp); + if (error) { + return (error); + } + indiroff = 0; + } + if (I_IS_UFS1(ip)) { + if (ffs_isblock(fs, cg_blksfree(cgp), loc)) + ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = + BLK_NOCOPY; + else if (passno == 2 && ((ufs1_daddr_t *)(ibp->b_data)) + [indiroff] == BLK_NOCOPY) + ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = 0; + else if (passno == 1 && ((ufs1_daddr_t *)(ibp->b_data)) + [indiroff] == BLK_NOCOPY) + panic("ffs_snapshot: lost indirect block"); + continue; + } + if (ffs_isblock(fs, cg_blksfree(cgp), loc)) + ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = BLK_NOCOPY; + else if (passno == 2 && + ((ufs2_daddr_t *)(ibp->b_data)) [indiroff] == BLK_NOCOPY) + ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = 0; + else if (passno == 1 && + ((ufs2_daddr_t *)(ibp->b_data)) [indiroff] == BLK_NOCOPY) + panic("ffs_snapshot: lost indirect block"); + } + if (passno == 2) + ibp->b_flags |= B_VALIDSUSPWRT; + bdwrite(ibp); + return (0); +} + +/* + * Before expunging a snapshot inode, note all the + * blocks that it claims with BLK_SNAP so that fsck will + * be able to account for those blocks properly and so + * that this snapshot knows that it need not copy them + * if the other snapshot holding them is freed. This code + * is reproduced once each for UFS1 and UFS2. + */ +static int +expunge_ufs1(snapvp, cancelip, fs, acctfunc, expungetype, clearmode) + struct vnode *snapvp; + struct inode *cancelip; + struct fs *fs; + int (*acctfunc)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); + int expungetype; + int clearmode; +{ + int i, error, indiroff; + ufs_lbn_t lbn, rlbn; + ufs2_daddr_t len, blkno, numblks, blksperindir; + struct ufs1_dinode *dip; + struct thread *td = curthread; + struct buf *bp; + + /* + * Prepare to expunge the inode. If its inode block has not + * yet been copied, then allocate and fill the copy. + */ + lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number)); + blkno = 0; + if (lbn < NDADDR) { + blkno = VTOI(snapvp)->i_din1->di_db[lbn]; + } else { + if (DOINGSOFTDEP(snapvp)) + softdep_prealloc(snapvp, MNT_WAIT); + td->td_pflags |= TDP_COWINPROGRESS; + error = ffs_balloc_ufs1(snapvp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, BA_METAONLY, &bp); + td->td_pflags &= ~TDP_COWINPROGRESS; + if (error) + return (error); + indiroff = (lbn - NDADDR) % NINDIR(fs); + blkno = ((ufs1_daddr_t *)(bp->b_data))[indiroff]; + bqrelse(bp); + } + if (blkno != 0) { + if ((error = bread(snapvp, lbn, fs->fs_bsize, KERNCRED, &bp))) + return (error); + } else { + error = ffs_balloc_ufs1(snapvp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, 0, &bp); + if (error) + return (error); + if ((error = readblock(snapvp, bp, lbn)) != 0) + return (error); + } + /* + * Set a snapshot inode to be a zero length file, regular files + * or unlinked snapshots to be completely unallocated. + */ + dip = (struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, cancelip->i_number); + if (clearmode || cancelip->i_effnlink == 0) + dip->di_mode = 0; + dip->di_size = 0; + dip->di_blocks = 0; + dip->di_flags &= ~SF_SNAPSHOT; + bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs1_daddr_t)); + bdwrite(bp); + /* + * Now go through and expunge all the blocks in the file + * using the function requested. + */ + numblks = howmany(cancelip->i_size, fs->fs_bsize); + if ((error = (*acctfunc)(snapvp, &cancelip->i_din1->di_db[0], + &cancelip->i_din1->di_db[NDADDR], fs, 0, expungetype))) + return (error); + if ((error = (*acctfunc)(snapvp, &cancelip->i_din1->di_ib[0], + &cancelip->i_din1->di_ib[NIADDR], fs, -1, expungetype))) + return (error); + blksperindir = 1; + lbn = -NDADDR; + len = numblks - NDADDR; + rlbn = NDADDR; + for (i = 0; len > 0 && i < NIADDR; i++) { + error = indiracct_ufs1(snapvp, ITOV(cancelip), i, + cancelip->i_din1->di_ib[i], lbn, rlbn, len, + blksperindir, fs, acctfunc, expungetype); + if (error) + return (error); + blksperindir *= NINDIR(fs); + lbn -= blksperindir + 1; + len -= blksperindir; + rlbn += blksperindir; + } + return (0); +} + +/* + * Descend an indirect block chain for vnode cancelvp accounting for all + * its indirect blocks in snapvp. + */ +static int +indiracct_ufs1(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, + blksperindir, fs, acctfunc, expungetype) + struct vnode *snapvp; + struct vnode *cancelvp; + int level; + ufs1_daddr_t blkno; + ufs_lbn_t lbn; + ufs_lbn_t rlbn; + ufs_lbn_t remblks; + ufs_lbn_t blksperindir; + struct fs *fs; + int (*acctfunc)(struct vnode *, ufs1_daddr_t *, ufs1_daddr_t *, + struct fs *, ufs_lbn_t, int); + int expungetype; +{ + int error, num, i; + ufs_lbn_t subblksperindir; + struct indir indirs[NIADDR + 2]; + ufs1_daddr_t last, *bap; + struct buf *bp; + + if (blkno == 0) { + if (expungetype == BLK_NOCOPY) + return (0); + panic("indiracct_ufs1: missing indir"); + } + if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0) + return (error); + if (lbn != indirs[num - 1 - level].in_lbn || num < 2) + panic("indiracct_ufs1: botched params"); + /* + * We have to expand bread here since it will deadlock looking + * up the block number for any blocks that are not in the cache. + */ + bp = getblk(cancelvp, lbn, fs->fs_bsize, 0, 0, 0); + bp->b_blkno = fsbtodb(fs, blkno); + if ((bp->b_flags & (B_DONE | B_DELWRI)) == 0 && + (error = readblock(cancelvp, bp, fragstoblks(fs, blkno)))) { + brelse(bp); + return (error); + } + /* + * Account for the block pointers in this indirect block. + */ + last = howmany(remblks, blksperindir); + if (last > NINDIR(fs)) + last = NINDIR(fs); + bap = malloc(fs->fs_bsize, M_DEVBUF, M_WAITOK); + bcopy(bp->b_data, (caddr_t)bap, fs->fs_bsize); + bqrelse(bp); + error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs, + level == 0 ? rlbn : -1, expungetype); + if (error || level == 0) + goto out; + /* + * Account for the block pointers in each of the indirect blocks + * in the levels below us. + */ + subblksperindir = blksperindir / NINDIR(fs); + for (lbn++, level--, i = 0; i < last; i++) { + error = indiracct_ufs1(snapvp, cancelvp, level, bap[i], lbn, + rlbn, remblks, subblksperindir, fs, acctfunc, expungetype); + if (error) + goto out; + rlbn += blksperindir; + lbn -= blksperindir; + remblks -= blksperindir; + } +out: + free(bap, M_DEVBUF); + return (error); +} + +/* + * Do both snap accounting and map accounting. + */ +static int +fullacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype) + struct vnode *vp; + ufs1_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int exptype; /* BLK_SNAP or BLK_NOCOPY */ +{ + int error; + + if ((error = snapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype))) + return (error); + return (mapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, exptype)); +} + +/* + * Identify a set of blocks allocated in a snapshot inode. + */ +static int +snapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, expungetype) + struct vnode *vp; + ufs1_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int expungetype; /* BLK_SNAP or BLK_NOCOPY */ +{ + struct inode *ip = VTOI(vp); + ufs1_daddr_t blkno, *blkp; + ufs_lbn_t lbn; + struct buf *ibp; + int error; + + for ( ; oldblkp < lastblkp; oldblkp++) { + blkno = *oldblkp; + if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP) + continue; + lbn = fragstoblks(fs, blkno); + if (lbn < NDADDR) { + blkp = &ip->i_din1->di_db[lbn]; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } else { + error = ffs_balloc_ufs1(vp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, BA_METAONLY, &ibp); + if (error) + return (error); + blkp = &((ufs1_daddr_t *)(ibp->b_data)) + [(lbn - NDADDR) % NINDIR(fs)]; + } + /* + * If we are expunging a snapshot vnode and we + * find a block marked BLK_NOCOPY, then it is + * one that has been allocated to this snapshot after + * we took our current snapshot and can be ignored. + */ + if (expungetype == BLK_SNAP && *blkp == BLK_NOCOPY) { + if (lbn >= NDADDR) + brelse(ibp); + } else { + if (*blkp != 0) + panic("snapacct_ufs1: bad block"); + *blkp = expungetype; + if (lbn >= NDADDR) + bdwrite(ibp); + } + } + return (0); +} + +/* + * Account for a set of blocks allocated in a snapshot inode. + */ +static int +mapacct_ufs1(vp, oldblkp, lastblkp, fs, lblkno, expungetype) + struct vnode *vp; + ufs1_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int expungetype; +{ + ufs1_daddr_t blkno; + struct inode *ip; + ino_t inum; + int acctit; + + ip = VTOI(vp); + inum = ip->i_number; + if (lblkno == -1) + acctit = 0; + else + acctit = 1; + for ( ; oldblkp < lastblkp; oldblkp++, lblkno++) { + blkno = *oldblkp; + if (blkno == 0 || blkno == BLK_NOCOPY) + continue; + if (acctit && expungetype == BLK_SNAP && blkno != BLK_SNAP) + *ip->i_snapblklist++ = lblkno; + if (blkno == BLK_SNAP) + blkno = blkstofrags(fs, lblkno); + ffs_blkfree(ITOUMP(ip), fs, vp, blkno, fs->fs_bsize, inum, + vp->v_type, NULL); + } + return (0); +} + +/* + * Before expunging a snapshot inode, note all the + * blocks that it claims with BLK_SNAP so that fsck will + * be able to account for those blocks properly and so + * that this snapshot knows that it need not copy them + * if the other snapshot holding them is freed. This code + * is reproduced once each for UFS1 and UFS2. + */ +static int +expunge_ufs2(snapvp, cancelip, fs, acctfunc, expungetype, clearmode) + struct vnode *snapvp; + struct inode *cancelip; + struct fs *fs; + int (*acctfunc)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); + int expungetype; + int clearmode; +{ + int i, error, indiroff; + ufs_lbn_t lbn, rlbn; + ufs2_daddr_t len, blkno, numblks, blksperindir; + struct ufs2_dinode *dip; + struct thread *td = curthread; + struct buf *bp; + + /* + * Prepare to expunge the inode. If its inode block has not + * yet been copied, then allocate and fill the copy. + */ + lbn = fragstoblks(fs, ino_to_fsba(fs, cancelip->i_number)); + blkno = 0; + if (lbn < NDADDR) { + blkno = VTOI(snapvp)->i_din2->di_db[lbn]; + } else { + if (DOINGSOFTDEP(snapvp)) + softdep_prealloc(snapvp, MNT_WAIT); + td->td_pflags |= TDP_COWINPROGRESS; + error = ffs_balloc_ufs2(snapvp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, BA_METAONLY, &bp); + td->td_pflags &= ~TDP_COWINPROGRESS; + if (error) + return (error); + indiroff = (lbn - NDADDR) % NINDIR(fs); + blkno = ((ufs2_daddr_t *)(bp->b_data))[indiroff]; + bqrelse(bp); + } + if (blkno != 0) { + if ((error = bread(snapvp, lbn, fs->fs_bsize, KERNCRED, &bp))) + return (error); + } else { + error = ffs_balloc_ufs2(snapvp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, 0, &bp); + if (error) + return (error); + if ((error = readblock(snapvp, bp, lbn)) != 0) + return (error); + } + /* + * Set a snapshot inode to be a zero length file, regular files + * to be completely unallocated. + */ + dip = (struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, cancelip->i_number); + if (clearmode || cancelip->i_effnlink == 0) + dip->di_mode = 0; + dip->di_size = 0; + dip->di_blocks = 0; + dip->di_flags &= ~SF_SNAPSHOT; + bzero(&dip->di_db[0], (NDADDR + NIADDR) * sizeof(ufs2_daddr_t)); + bdwrite(bp); + /* + * Now go through and expunge all the blocks in the file + * using the function requested. + */ + numblks = howmany(cancelip->i_size, fs->fs_bsize); + if ((error = (*acctfunc)(snapvp, &cancelip->i_din2->di_db[0], + &cancelip->i_din2->di_db[NDADDR], fs, 0, expungetype))) + return (error); + if ((error = (*acctfunc)(snapvp, &cancelip->i_din2->di_ib[0], + &cancelip->i_din2->di_ib[NIADDR], fs, -1, expungetype))) + return (error); + blksperindir = 1; + lbn = -NDADDR; + len = numblks - NDADDR; + rlbn = NDADDR; + for (i = 0; len > 0 && i < NIADDR; i++) { + error = indiracct_ufs2(snapvp, ITOV(cancelip), i, + cancelip->i_din2->di_ib[i], lbn, rlbn, len, + blksperindir, fs, acctfunc, expungetype); + if (error) + return (error); + blksperindir *= NINDIR(fs); + lbn -= blksperindir + 1; + len -= blksperindir; + rlbn += blksperindir; + } + return (0); +} + +/* + * Descend an indirect block chain for vnode cancelvp accounting for all + * its indirect blocks in snapvp. + */ +static int +indiracct_ufs2(snapvp, cancelvp, level, blkno, lbn, rlbn, remblks, + blksperindir, fs, acctfunc, expungetype) + struct vnode *snapvp; + struct vnode *cancelvp; + int level; + ufs2_daddr_t blkno; + ufs_lbn_t lbn; + ufs_lbn_t rlbn; + ufs_lbn_t remblks; + ufs_lbn_t blksperindir; + struct fs *fs; + int (*acctfunc)(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, + struct fs *, ufs_lbn_t, int); + int expungetype; +{ + int error, num, i; + ufs_lbn_t subblksperindir; + struct indir indirs[NIADDR + 2]; + ufs2_daddr_t last, *bap; + struct buf *bp; + + if (blkno == 0) { + if (expungetype == BLK_NOCOPY) + return (0); + panic("indiracct_ufs2: missing indir"); + } + if ((error = ufs_getlbns(cancelvp, rlbn, indirs, &num)) != 0) + return (error); + if (lbn != indirs[num - 1 - level].in_lbn || num < 2) + panic("indiracct_ufs2: botched params"); + /* + * We have to expand bread here since it will deadlock looking + * up the block number for any blocks that are not in the cache. + */ + bp = getblk(cancelvp, lbn, fs->fs_bsize, 0, 0, 0); + bp->b_blkno = fsbtodb(fs, blkno); + if ((bp->b_flags & B_CACHE) == 0 && + (error = readblock(cancelvp, bp, fragstoblks(fs, blkno)))) { + brelse(bp); + return (error); + } + /* + * Account for the block pointers in this indirect block. + */ + last = howmany(remblks, blksperindir); + if (last > NINDIR(fs)) + last = NINDIR(fs); + bap = malloc(fs->fs_bsize, M_DEVBUF, M_WAITOK); + bcopy(bp->b_data, (caddr_t)bap, fs->fs_bsize); + bqrelse(bp); + error = (*acctfunc)(snapvp, &bap[0], &bap[last], fs, + level == 0 ? rlbn : -1, expungetype); + if (error || level == 0) + goto out; + /* + * Account for the block pointers in each of the indirect blocks + * in the levels below us. + */ + subblksperindir = blksperindir / NINDIR(fs); + for (lbn++, level--, i = 0; i < last; i++) { + error = indiracct_ufs2(snapvp, cancelvp, level, bap[i], lbn, + rlbn, remblks, subblksperindir, fs, acctfunc, expungetype); + if (error) + goto out; + rlbn += blksperindir; + lbn -= blksperindir; + remblks -= blksperindir; + } +out: + free(bap, M_DEVBUF); + return (error); +} + +/* + * Do both snap accounting and map accounting. + */ +static int +fullacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype) + struct vnode *vp; + ufs2_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int exptype; /* BLK_SNAP or BLK_NOCOPY */ +{ + int error; + + if ((error = snapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype))) + return (error); + return (mapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, exptype)); +} + +/* + * Identify a set of blocks allocated in a snapshot inode. + */ +static int +snapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, expungetype) + struct vnode *vp; + ufs2_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int expungetype; /* BLK_SNAP or BLK_NOCOPY */ +{ + struct inode *ip = VTOI(vp); + ufs2_daddr_t blkno, *blkp; + ufs_lbn_t lbn; + struct buf *ibp; + int error; + + for ( ; oldblkp < lastblkp; oldblkp++) { + blkno = *oldblkp; + if (blkno == 0 || blkno == BLK_NOCOPY || blkno == BLK_SNAP) + continue; + lbn = fragstoblks(fs, blkno); + if (lbn < NDADDR) { + blkp = &ip->i_din2->di_db[lbn]; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } else { + error = ffs_balloc_ufs2(vp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, BA_METAONLY, &ibp); + if (error) + return (error); + blkp = &((ufs2_daddr_t *)(ibp->b_data)) + [(lbn - NDADDR) % NINDIR(fs)]; + } + /* + * If we are expunging a snapshot vnode and we + * find a block marked BLK_NOCOPY, then it is + * one that has been allocated to this snapshot after + * we took our current snapshot and can be ignored. + */ + if (expungetype == BLK_SNAP && *blkp == BLK_NOCOPY) { + if (lbn >= NDADDR) + brelse(ibp); + } else { + if (*blkp != 0) + panic("snapacct_ufs2: bad block"); + *blkp = expungetype; + if (lbn >= NDADDR) + bdwrite(ibp); + } + } + return (0); +} + +/* + * Account for a set of blocks allocated in a snapshot inode. + */ +static int +mapacct_ufs2(vp, oldblkp, lastblkp, fs, lblkno, expungetype) + struct vnode *vp; + ufs2_daddr_t *oldblkp, *lastblkp; + struct fs *fs; + ufs_lbn_t lblkno; + int expungetype; +{ + ufs2_daddr_t blkno; + struct inode *ip; + ino_t inum; + int acctit; + + ip = VTOI(vp); + inum = ip->i_number; + if (lblkno == -1) + acctit = 0; + else + acctit = 1; + for ( ; oldblkp < lastblkp; oldblkp++, lblkno++) { + blkno = *oldblkp; + if (blkno == 0 || blkno == BLK_NOCOPY) + continue; + if (acctit && expungetype == BLK_SNAP && blkno != BLK_SNAP) + *ip->i_snapblklist++ = lblkno; + if (blkno == BLK_SNAP) + blkno = blkstofrags(fs, lblkno); + ffs_blkfree(ITOUMP(ip), fs, vp, blkno, fs->fs_bsize, inum, + vp->v_type, NULL); + } + return (0); +} + +/* + * Decrement extra reference on snapshot when last name is removed. + * It will not be freed until the last open reference goes away. + */ +void +ffs_snapgone(ip) + struct inode *ip; +{ + struct inode *xp; + struct fs *fs; + int snaploc; + struct snapdata *sn; + struct ufsmount *ump; + + /* + * Find snapshot in incore list. + */ + xp = NULL; + sn = ITODEVVP(ip)->v_rdev->si_snapdata; + if (sn != NULL) + TAILQ_FOREACH(xp, &sn->sn_head, i_nextsnap) + if (xp == ip) + break; + if (xp != NULL) + vrele(ITOV(ip)); + else if (snapdebug) + printf("ffs_snapgone: lost snapshot vnode %ju\n", + (uintmax_t)ip->i_number); + /* + * Delete snapshot inode from superblock. Keep list dense. + */ + ump = ITOUMP(ip); + fs = ump->um_fs; + UFS_LOCK(ump); + for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) + if (fs->fs_snapinum[snaploc] == ip->i_number) + break; + if (snaploc < FSMAXSNAP) { + for (snaploc++; snaploc < FSMAXSNAP; snaploc++) { + if (fs->fs_snapinum[snaploc] == 0) + break; + fs->fs_snapinum[snaploc - 1] = fs->fs_snapinum[snaploc]; + } + fs->fs_snapinum[snaploc - 1] = 0; + } + UFS_UNLOCK(ump); +} + +/* + * Prepare a snapshot file for being removed. + */ +void +ffs_snapremove(vp) + struct vnode *vp; +{ + struct inode *ip; + struct vnode *devvp; + struct buf *ibp; + struct fs *fs; + ufs2_daddr_t numblks, blkno, dblk; + int error, i, last, loc; + struct snapdata *sn; + + ip = VTOI(vp); + fs = ITOFS(ip); + devvp = ITODEVVP(ip); + /* + * If active, delete from incore list (this snapshot may + * already have been in the process of being deleted, so + * would not have been active). + * + * Clear copy-on-write flag if last snapshot. + */ + VI_LOCK(devvp); + if (ip->i_nextsnap.tqe_prev != 0) { + sn = devvp->v_rdev->si_snapdata; + TAILQ_REMOVE(&sn->sn_head, ip, i_nextsnap); + ip->i_nextsnap.tqe_prev = 0; + VI_UNLOCK(devvp); + lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL); + for (i = 0; i < sn->sn_lock.lk_recurse; i++) + lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL); + KASSERT(vp->v_vnlock == &sn->sn_lock, + ("ffs_snapremove: lost lock mutation")); + vp->v_vnlock = &vp->v_lock; + VI_LOCK(devvp); + while (sn->sn_lock.lk_recurse > 0) + lockmgr(&sn->sn_lock, LK_RELEASE, NULL); + lockmgr(&sn->sn_lock, LK_RELEASE, NULL); + try_free_snapdata(devvp); + } else + VI_UNLOCK(devvp); + /* + * Clear all BLK_NOCOPY fields. Pass any block claims to other + * snapshots that want them (see ffs_snapblkfree below). + */ + for (blkno = 1; blkno < NDADDR; blkno++) { + dblk = DIP(ip, i_db[blkno]); + if (dblk == 0) + continue; + if (dblk == BLK_NOCOPY || dblk == BLK_SNAP) + DIP_SET(ip, i_db[blkno], 0); + else if ((dblk == blkstofrags(fs, blkno) && + ffs_snapblkfree(fs, ITODEVVP(ip), dblk, fs->fs_bsize, + ip->i_number, vp->v_type, NULL))) { + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - + btodb(fs->fs_bsize)); + DIP_SET(ip, i_db[blkno], 0); + } + } + numblks = howmany(ip->i_size, fs->fs_bsize); + for (blkno = NDADDR; blkno < numblks; blkno += NINDIR(fs)) { + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)blkno), + fs->fs_bsize, KERNCRED, BA_METAONLY, &ibp); + if (error) + continue; + if (fs->fs_size - blkno > NINDIR(fs)) + last = NINDIR(fs); + else + last = fs->fs_size - blkno; + for (loc = 0; loc < last; loc++) { + if (I_IS_UFS1(ip)) { + dblk = ((ufs1_daddr_t *)(ibp->b_data))[loc]; + if (dblk == 0) + continue; + if (dblk == BLK_NOCOPY || dblk == BLK_SNAP) + ((ufs1_daddr_t *)(ibp->b_data))[loc]= 0; + else if ((dblk == blkstofrags(fs, blkno) && + ffs_snapblkfree(fs, ITODEVVP(ip), dblk, + fs->fs_bsize, ip->i_number, vp->v_type, + NULL))) { + ip->i_din1->di_blocks -= + btodb(fs->fs_bsize); + ((ufs1_daddr_t *)(ibp->b_data))[loc]= 0; + } + continue; + } + dblk = ((ufs2_daddr_t *)(ibp->b_data))[loc]; + if (dblk == 0) + continue; + if (dblk == BLK_NOCOPY || dblk == BLK_SNAP) + ((ufs2_daddr_t *)(ibp->b_data))[loc] = 0; + else if ((dblk == blkstofrags(fs, blkno) && + ffs_snapblkfree(fs, ITODEVVP(ip), dblk, + fs->fs_bsize, ip->i_number, vp->v_type, NULL))) { + ip->i_din2->di_blocks -= btodb(fs->fs_bsize); + ((ufs2_daddr_t *)(ibp->b_data))[loc] = 0; + } + } + bawrite(ibp); + } + /* + * Clear snapshot flag and drop reference. + */ + ip->i_flags &= ~SF_SNAPSHOT; + DIP_SET(ip, i_flags, ip->i_flags); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + /* + * The dirtied indirects must be written out before + * softdep_setup_freeblocks() is called. Otherwise indir_trunc() + * may find indirect pointers using the magic BLK_* values. + */ + if (DOINGSOFTDEP(vp)) + ffs_syncvnode(vp, MNT_WAIT, 0); +#ifdef QUOTA + /* + * Reenable disk quotas for ex-snapshot file. + */ + if (!getinoquota(ip)) + (void) chkdq(ip, DIP(ip, i_blocks), KERNCRED, FORCE); +#endif +} + +/* + * Notification that a block is being freed. Return zero if the free + * should be allowed to proceed. Return non-zero if the snapshot file + * wants to claim the block. The block will be claimed if it is an + * uncopied part of one of the snapshots. It will be freed if it is + * either a BLK_NOCOPY or has already been copied in all of the snapshots. + * If a fragment is being freed, then all snapshots that care about + * it must make a copy since a snapshot file can only claim full sized + * blocks. Note that if more than one snapshot file maps the block, + * we can pick one at random to claim it. Since none of the snapshots + * can change, we are assurred that they will all see the same unmodified + * image. When deleting a snapshot file (see ffs_snapremove above), we + * must push any of these claimed blocks to one of the other snapshots + * that maps it. These claimed blocks are easily identified as they will + * have a block number equal to their logical block number within the + * snapshot. A copied block can never have this property because they + * must always have been allocated from a BLK_NOCOPY location. + */ +int +ffs_snapblkfree(fs, devvp, bno, size, inum, vtype, wkhd) + struct fs *fs; + struct vnode *devvp; + ufs2_daddr_t bno; + long size; + ino_t inum; + enum vtype vtype; + struct workhead *wkhd; +{ + struct buf *ibp, *cbp, *savedcbp = NULL; + struct thread *td = curthread; + struct inode *ip; + struct vnode *vp = NULL; + ufs_lbn_t lbn; + ufs2_daddr_t blkno; + int indiroff = 0, error = 0, claimedblk = 0; + struct snapdata *sn; + + lbn = fragstoblks(fs, bno); +retry: + VI_LOCK(devvp); + sn = devvp->v_rdev->si_snapdata; + if (sn == NULL) { + VI_UNLOCK(devvp); + return (0); + } + if (lockmgr(&sn->sn_lock, LK_INTERLOCK | LK_EXCLUSIVE | LK_SLEEPFAIL, + VI_MTX(devvp)) != 0) + goto retry; + TAILQ_FOREACH(ip, &sn->sn_head, i_nextsnap) { + vp = ITOV(ip); + if (DOINGSOFTDEP(vp)) + softdep_prealloc(vp, MNT_WAIT); + /* + * Lookup block being written. + */ + if (lbn < NDADDR) { + blkno = DIP(ip, i_db[lbn]); + } else { + td->td_pflags |= TDP_COWINPROGRESS; + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, BA_METAONLY, &ibp); + td->td_pflags &= ~TDP_COWINPROGRESS; + if (error) + break; + indiroff = (lbn - NDADDR) % NINDIR(fs); + if (I_IS_UFS1(ip)) + blkno=((ufs1_daddr_t *)(ibp->b_data))[indiroff]; + else + blkno=((ufs2_daddr_t *)(ibp->b_data))[indiroff]; + } + /* + * Check to see if block needs to be copied. + */ + if (blkno == 0) { + /* + * A block that we map is being freed. If it has not + * been claimed yet, we will claim or copy it (below). + */ + claimedblk = 1; + } else if (blkno == BLK_SNAP) { + /* + * No previous snapshot claimed the block, + * so it will be freed and become a BLK_NOCOPY + * (don't care) for us. + */ + if (claimedblk) + panic("snapblkfree: inconsistent block type"); + if (lbn < NDADDR) { + DIP_SET(ip, i_db[lbn], BLK_NOCOPY); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } else if (I_IS_UFS1(ip)) { + ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = + BLK_NOCOPY; + bdwrite(ibp); + } else { + ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = + BLK_NOCOPY; + bdwrite(ibp); + } + continue; + } else /* BLK_NOCOPY or default */ { + /* + * If the snapshot has already copied the block + * (default), or does not care about the block, + * it is not needed. + */ + if (lbn >= NDADDR) + bqrelse(ibp); + continue; + } + /* + * If this is a full size block, we will just grab it + * and assign it to the snapshot inode. Otherwise we + * will proceed to copy it. See explanation for this + * routine as to why only a single snapshot needs to + * claim this block. + */ + if (size == fs->fs_bsize) { +#ifdef DEBUG + if (snapdebug) + printf("%s %ju lbn %jd from inum %ju\n", + "Grabonremove: snapino", + (uintmax_t)ip->i_number, + (intmax_t)lbn, (uintmax_t)inum); +#endif + /* + * If journaling is tracking this write we must add + * the work to the inode or indirect being written. + */ + if (wkhd != NULL) { + if (lbn < NDADDR) + softdep_inode_append(ip, + curthread->td_ucred, wkhd); + else + softdep_buf_append(ibp, wkhd); + } + if (lbn < NDADDR) { + DIP_SET(ip, i_db[lbn], bno); + } else if (I_IS_UFS1(ip)) { + ((ufs1_daddr_t *)(ibp->b_data))[indiroff] = bno; + bdwrite(ibp); + } else { + ((ufs2_daddr_t *)(ibp->b_data))[indiroff] = bno; + bdwrite(ibp); + } + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) + btodb(size)); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + lockmgr(vp->v_vnlock, LK_RELEASE, NULL); + return (1); + } + if (lbn >= NDADDR) + bqrelse(ibp); + /* + * Allocate the block into which to do the copy. Note that this + * allocation will never require any additional allocations for + * the snapshot inode. + */ + td->td_pflags |= TDP_COWINPROGRESS; + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, 0, &cbp); + td->td_pflags &= ~TDP_COWINPROGRESS; + if (error) + break; +#ifdef DEBUG + if (snapdebug) + printf("%s%ju lbn %jd %s %ju size %ld to blkno %jd\n", + "Copyonremove: snapino ", (uintmax_t)ip->i_number, + (intmax_t)lbn, "for inum", (uintmax_t)inum, size, + (intmax_t)cbp->b_blkno); +#endif + /* + * If we have already read the old block contents, then + * simply copy them to the new block. Note that we need + * to synchronously write snapshots that have not been + * unlinked, and hence will be visible after a crash, + * to ensure their integrity. At a minimum we ensure the + * integrity of the filesystem metadata, but use the + * dopersistence sysctl-setable flag to decide on the + * persistence needed for file content data. + */ + if (savedcbp != NULL) { + bcopy(savedcbp->b_data, cbp->b_data, fs->fs_bsize); + bawrite(cbp); + if ((vtype == VDIR || dopersistence) && + ip->i_effnlink > 0) + (void) ffs_syncvnode(vp, MNT_WAIT, NO_INO_UPDT); + continue; + } + /* + * Otherwise, read the old block contents into the buffer. + */ + if ((error = readblock(vp, cbp, lbn)) != 0) { + bzero(cbp->b_data, fs->fs_bsize); + bawrite(cbp); + if ((vtype == VDIR || dopersistence) && + ip->i_effnlink > 0) + (void) ffs_syncvnode(vp, MNT_WAIT, NO_INO_UPDT); + break; + } + savedcbp = cbp; + } + /* + * Note that we need to synchronously write snapshots that + * have not been unlinked, and hence will be visible after + * a crash, to ensure their integrity. At a minimum we + * ensure the integrity of the filesystem metadata, but + * use the dopersistence sysctl-setable flag to decide on + * the persistence needed for file content data. + */ + if (savedcbp) { + vp = savedcbp->b_vp; + bawrite(savedcbp); + if ((vtype == VDIR || dopersistence) && + VTOI(vp)->i_effnlink > 0) + (void) ffs_syncvnode(vp, MNT_WAIT, NO_INO_UPDT); + } + /* + * If we have been unable to allocate a block in which to do + * the copy, then return non-zero so that the fragment will + * not be freed. Although space will be lost, the snapshot + * will stay consistent. + */ + if (error != 0 && wkhd != NULL) + softdep_freework(wkhd); + lockmgr(&sn->sn_lock, LK_RELEASE, NULL); + return (error); +} + +/* + * Associate snapshot files when mounting. + */ +void +ffs_snapshot_mount(mp) + struct mount *mp; +{ + struct ufsmount *ump = VFSTOUFS(mp); + struct vnode *devvp = ump->um_devvp; + struct fs *fs = ump->um_fs; + struct thread *td = curthread; + struct snapdata *sn; + struct vnode *vp; + struct vnode *lastvp; + struct inode *ip; + struct uio auio; + struct iovec aiov; + void *snapblklist; + char *reason; + daddr_t snaplistsize; + int error, snaploc, loc; + + /* + * XXX The following needs to be set before ffs_truncate or + * VOP_READ can be called. + */ + mp->mnt_stat.f_iosize = fs->fs_bsize; + /* + * Process each snapshot listed in the superblock. + */ + vp = NULL; + lastvp = NULL; + sn = NULL; + for (snaploc = 0; snaploc < FSMAXSNAP; snaploc++) { + if (fs->fs_snapinum[snaploc] == 0) + break; + if ((error = ffs_vget(mp, fs->fs_snapinum[snaploc], + LK_EXCLUSIVE, &vp)) != 0){ + printf("ffs_snapshot_mount: vget failed %d\n", error); + continue; + } + ip = VTOI(vp); + if (!IS_SNAPSHOT(ip) || ip->i_size == + lblktosize(fs, howmany(fs->fs_size, fs->fs_frag))) { + if (!IS_SNAPSHOT(ip)) { + reason = "non-snapshot"; + } else { + reason = "old format snapshot"; + (void)ffs_truncate(vp, (off_t)0, 0, NOCRED); + (void)ffs_syncvnode(vp, MNT_WAIT, 0); + } + printf("ffs_snapshot_mount: %s inode %d\n", + reason, fs->fs_snapinum[snaploc]); + vput(vp); + vp = NULL; + for (loc = snaploc + 1; loc < FSMAXSNAP; loc++) { + if (fs->fs_snapinum[loc] == 0) + break; + fs->fs_snapinum[loc - 1] = fs->fs_snapinum[loc]; + } + fs->fs_snapinum[loc - 1] = 0; + snaploc--; + continue; + } + /* + * Acquire a lock on the snapdata structure, creating it if + * necessary. + */ + sn = ffs_snapdata_acquire(devvp); + /* + * Change vnode to use shared snapshot lock instead of the + * original private lock. + */ + vp->v_vnlock = &sn->sn_lock; + lockmgr(&vp->v_lock, LK_RELEASE, NULL); + /* + * Link it onto the active snapshot list. + */ + VI_LOCK(devvp); + if (ip->i_nextsnap.tqe_prev != 0) + panic("ffs_snapshot_mount: %ju already on list", + (uintmax_t)ip->i_number); + else + TAILQ_INSERT_TAIL(&sn->sn_head, ip, i_nextsnap); + vp->v_vflag |= VV_SYSTEM; + VI_UNLOCK(devvp); + VOP_UNLOCK(vp, 0); + lastvp = vp; + } + vp = lastvp; + /* + * No usable snapshots found. + */ + if (sn == NULL || vp == NULL) + return; + /* + * Allocate the space for the block hints list. We always want to + * use the list from the newest snapshot. + */ + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (void *)&snaplistsize; + aiov.iov_len = sizeof(snaplistsize); + auio.uio_resid = aiov.iov_len; + auio.uio_offset = + lblktosize(fs, howmany(fs->fs_size, fs->fs_frag)); + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_READ; + auio.uio_td = td; + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + if ((error = VOP_READ(vp, &auio, IO_UNIT, td->td_ucred)) != 0) { + printf("ffs_snapshot_mount: read_1 failed %d\n", error); + VOP_UNLOCK(vp, 0); + return; + } + snapblklist = malloc(snaplistsize * sizeof(daddr_t), + M_UFSMNT, M_WAITOK); + auio.uio_iovcnt = 1; + aiov.iov_base = snapblklist; + aiov.iov_len = snaplistsize * sizeof (daddr_t); + auio.uio_resid = aiov.iov_len; + auio.uio_offset -= sizeof(snaplistsize); + if ((error = VOP_READ(vp, &auio, IO_UNIT, td->td_ucred)) != 0) { + printf("ffs_snapshot_mount: read_2 failed %d\n", error); + VOP_UNLOCK(vp, 0); + free(snapblklist, M_UFSMNT); + return; + } + VOP_UNLOCK(vp, 0); + VI_LOCK(devvp); + ASSERT_VOP_LOCKED(devvp, "ffs_snapshot_mount"); + sn->sn_listsize = snaplistsize; + sn->sn_blklist = (daddr_t *)snapblklist; + devvp->v_vflag |= VV_COPYONWRITE; + VI_UNLOCK(devvp); +} + +/* + * Disassociate snapshot files when unmounting. + */ +void +ffs_snapshot_unmount(mp) + struct mount *mp; +{ + struct vnode *devvp = VFSTOUFS(mp)->um_devvp; + struct snapdata *sn; + struct inode *xp; + struct vnode *vp; + + VI_LOCK(devvp); + sn = devvp->v_rdev->si_snapdata; + while (sn != NULL && (xp = TAILQ_FIRST(&sn->sn_head)) != NULL) { + vp = ITOV(xp); + TAILQ_REMOVE(&sn->sn_head, xp, i_nextsnap); + xp->i_nextsnap.tqe_prev = 0; + lockmgr(&sn->sn_lock, LK_INTERLOCK | LK_EXCLUSIVE, + VI_MTX(devvp)); + lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL); + KASSERT(vp->v_vnlock == &sn->sn_lock, + ("ffs_snapshot_unmount: lost lock mutation")); + vp->v_vnlock = &vp->v_lock; + lockmgr(&vp->v_lock, LK_RELEASE, NULL); + lockmgr(&sn->sn_lock, LK_RELEASE, NULL); + if (xp->i_effnlink > 0) + vrele(vp); + VI_LOCK(devvp); + sn = devvp->v_rdev->si_snapdata; + } + try_free_snapdata(devvp); + ASSERT_VOP_LOCKED(devvp, "ffs_snapshot_unmount"); +} + +/* + * Check the buffer block to be belong to device buffer that shall be + * locked after snaplk. devvp shall be locked on entry, and will be + * leaved locked upon exit. + */ +static int +ffs_bp_snapblk(devvp, bp) + struct vnode *devvp; + struct buf *bp; +{ + struct snapdata *sn; + struct fs *fs; + ufs2_daddr_t lbn, *snapblklist; + int lower, upper, mid; + + ASSERT_VI_LOCKED(devvp, "ffs_bp_snapblk"); + KASSERT(devvp->v_type == VCHR, ("Not a device %p", devvp)); + sn = devvp->v_rdev->si_snapdata; + if (sn == NULL || TAILQ_FIRST(&sn->sn_head) == NULL) + return (0); + fs = ITOFS(TAILQ_FIRST(&sn->sn_head)); + lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno)); + snapblklist = sn->sn_blklist; + upper = sn->sn_listsize - 1; + lower = 1; + while (lower <= upper) { + mid = (lower + upper) / 2; + if (snapblklist[mid] == lbn) + break; + if (snapblklist[mid] < lbn) + lower = mid + 1; + else + upper = mid - 1; + } + if (lower <= upper) + return (1); + return (0); +} + +void +ffs_bdflush(bo, bp) + struct bufobj *bo; + struct buf *bp; +{ + struct thread *td; + struct vnode *vp, *devvp; + struct buf *nbp; + int bp_bdskip; + + if (bo->bo_dirty.bv_cnt <= dirtybufthresh) + return; + + td = curthread; + vp = bp->b_vp; + devvp = bo->__bo_vnode; + KASSERT(vp == devvp, ("devvp != vp %p %p", bo, bp)); + + VI_LOCK(devvp); + bp_bdskip = ffs_bp_snapblk(devvp, bp); + if (bp_bdskip) + bdwriteskip++; + VI_UNLOCK(devvp); + if (bo->bo_dirty.bv_cnt > dirtybufthresh + 10 && !bp_bdskip) { + (void) VOP_FSYNC(vp, MNT_NOWAIT, td); + altbufferflushes++; + } else { + BO_LOCK(bo); + /* + * Try to find a buffer to flush. + */ + TAILQ_FOREACH(nbp, &bo->bo_dirty.bv_hd, b_bobufs) { + if ((nbp->b_vflags & BV_BKGRDINPROG) || + BUF_LOCK(nbp, + LK_EXCLUSIVE | LK_NOWAIT, NULL)) + continue; + if (bp == nbp) + panic("bdwrite: found ourselves"); + BO_UNLOCK(bo); + /* + * Don't countdeps with the bo lock + * held. + */ + if (buf_countdeps(nbp, 0)) { + BO_LOCK(bo); + BUF_UNLOCK(nbp); + continue; + } + if (bp_bdskip) { + VI_LOCK(devvp); + if (!ffs_bp_snapblk(vp, nbp)) { + VI_UNLOCK(devvp); + BO_LOCK(bo); + BUF_UNLOCK(nbp); + continue; + } + VI_UNLOCK(devvp); + } + if (nbp->b_flags & B_CLUSTEROK) { + vfs_bio_awrite(nbp); + } else { + bremfree(nbp); + bawrite(nbp); + } + dirtybufferflushes++; + break; + } + if (nbp == NULL) + BO_UNLOCK(bo); + } +} + +/* + * Check for need to copy block that is about to be written, + * copying the block if necessary. + */ +int +ffs_copyonwrite(devvp, bp) + struct vnode *devvp; + struct buf *bp; +{ + struct snapdata *sn; + struct buf *ibp, *cbp, *savedcbp = NULL; + struct thread *td = curthread; + struct fs *fs; + struct inode *ip; + struct vnode *vp = NULL; + ufs2_daddr_t lbn, blkno, *snapblklist; + int lower, upper, mid, indiroff, error = 0; + int launched_async_io, prev_norunningbuf; + long saved_runningbufspace; + + if (devvp != bp->b_vp && IS_SNAPSHOT(VTOI(bp->b_vp))) + return (0); /* Update on a snapshot file */ + if (td->td_pflags & TDP_COWINPROGRESS) + panic("ffs_copyonwrite: recursive call"); + /* + * First check to see if it is in the preallocated list. + * By doing this check we avoid several potential deadlocks. + */ + VI_LOCK(devvp); + sn = devvp->v_rdev->si_snapdata; + if (sn == NULL || + TAILQ_EMPTY(&sn->sn_head)) { + VI_UNLOCK(devvp); + return (0); /* No snapshot */ + } + ip = TAILQ_FIRST(&sn->sn_head); + fs = ITOFS(ip); + lbn = fragstoblks(fs, dbtofsb(fs, bp->b_blkno)); + snapblklist = sn->sn_blklist; + upper = sn->sn_listsize - 1; + lower = 1; + while (lower <= upper) { + mid = (lower + upper) / 2; + if (snapblklist[mid] == lbn) + break; + if (snapblklist[mid] < lbn) + lower = mid + 1; + else + upper = mid - 1; + } + if (lower <= upper) { + VI_UNLOCK(devvp); + return (0); + } + launched_async_io = 0; + prev_norunningbuf = td->td_pflags & TDP_NORUNNINGBUF; + /* + * Since I/O on bp isn't yet in progress and it may be blocked + * for a long time waiting on snaplk, back it out of + * runningbufspace, possibly waking other threads waiting for space. + */ + saved_runningbufspace = bp->b_runningbufspace; + if (saved_runningbufspace != 0) + runningbufwakeup(bp); + /* + * Not in the precomputed list, so check the snapshots. + */ + while (lockmgr(&sn->sn_lock, LK_INTERLOCK | LK_EXCLUSIVE | LK_SLEEPFAIL, + VI_MTX(devvp)) != 0) { + VI_LOCK(devvp); + sn = devvp->v_rdev->si_snapdata; + if (sn == NULL || + TAILQ_EMPTY(&sn->sn_head)) { + VI_UNLOCK(devvp); + if (saved_runningbufspace != 0) { + bp->b_runningbufspace = saved_runningbufspace; + atomic_add_long(&runningbufspace, + bp->b_runningbufspace); + } + return (0); /* Snapshot gone */ + } + } + TAILQ_FOREACH(ip, &sn->sn_head, i_nextsnap) { + vp = ITOV(ip); + if (DOINGSOFTDEP(vp)) + softdep_prealloc(vp, MNT_WAIT); + /* + * We ensure that everything of our own that needs to be + * copied will be done at the time that ffs_snapshot is + * called. Thus we can skip the check here which can + * deadlock in doing the lookup in UFS_BALLOC. + */ + if (bp->b_vp == vp) + continue; + /* + * Check to see if block needs to be copied. We do not have + * to hold the snapshot lock while doing this lookup as it + * will never require any additional allocations for the + * snapshot inode. + */ + if (lbn < NDADDR) { + blkno = DIP(ip, i_db[lbn]); + } else { + td->td_pflags |= TDP_COWINPROGRESS | TDP_NORUNNINGBUF; + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, BA_METAONLY, &ibp); + td->td_pflags &= ~TDP_COWINPROGRESS; + if (error) + break; + indiroff = (lbn - NDADDR) % NINDIR(fs); + if (I_IS_UFS1(ip)) + blkno=((ufs1_daddr_t *)(ibp->b_data))[indiroff]; + else + blkno=((ufs2_daddr_t *)(ibp->b_data))[indiroff]; + bqrelse(ibp); + } +#ifdef INVARIANTS + if (blkno == BLK_SNAP && bp->b_lblkno >= 0) + panic("ffs_copyonwrite: bad copy block"); +#endif + if (blkno != 0) + continue; + /* + * Allocate the block into which to do the copy. Since + * multiple processes may all try to copy the same block, + * we have to recheck our need to do a copy if we sleep + * waiting for the lock. + * + * Because all snapshots on a filesystem share a single + * lock, we ensure that we will never be in competition + * with another process to allocate a block. + */ + td->td_pflags |= TDP_COWINPROGRESS | TDP_NORUNNINGBUF; + error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), + fs->fs_bsize, KERNCRED, 0, &cbp); + td->td_pflags &= ~TDP_COWINPROGRESS; + if (error) + break; +#ifdef DEBUG + if (snapdebug) { + printf("Copyonwrite: snapino %ju lbn %jd for ", + (uintmax_t)ip->i_number, (intmax_t)lbn); + if (bp->b_vp == devvp) + printf("fs metadata"); + else + printf("inum %ju", + (uintmax_t)VTOI(bp->b_vp)->i_number); + printf(" lblkno %jd to blkno %jd\n", + (intmax_t)bp->b_lblkno, (intmax_t)cbp->b_blkno); + } +#endif + /* + * If we have already read the old block contents, then + * simply copy them to the new block. Note that we need + * to synchronously write snapshots that have not been + * unlinked, and hence will be visible after a crash, + * to ensure their integrity. At a minimum we ensure the + * integrity of the filesystem metadata, but use the + * dopersistence sysctl-setable flag to decide on the + * persistence needed for file content data. + */ + if (savedcbp != NULL) { + bcopy(savedcbp->b_data, cbp->b_data, fs->fs_bsize); + bawrite(cbp); + if ((devvp == bp->b_vp || bp->b_vp->v_type == VDIR || + dopersistence) && ip->i_effnlink > 0) + (void) ffs_syncvnode(vp, MNT_WAIT, NO_INO_UPDT); + else + launched_async_io = 1; + continue; + } + /* + * Otherwise, read the old block contents into the buffer. + */ + if ((error = readblock(vp, cbp, lbn)) != 0) { + bzero(cbp->b_data, fs->fs_bsize); + bawrite(cbp); + if ((devvp == bp->b_vp || bp->b_vp->v_type == VDIR || + dopersistence) && ip->i_effnlink > 0) + (void) ffs_syncvnode(vp, MNT_WAIT, NO_INO_UPDT); + else + launched_async_io = 1; + break; + } + savedcbp = cbp; + } + /* + * Note that we need to synchronously write snapshots that + * have not been unlinked, and hence will be visible after + * a crash, to ensure their integrity. At a minimum we + * ensure the integrity of the filesystem metadata, but + * use the dopersistence sysctl-setable flag to decide on + * the persistence needed for file content data. + */ + if (savedcbp) { + vp = savedcbp->b_vp; + bawrite(savedcbp); + if ((devvp == bp->b_vp || bp->b_vp->v_type == VDIR || + dopersistence) && VTOI(vp)->i_effnlink > 0) + (void) ffs_syncvnode(vp, MNT_WAIT, NO_INO_UPDT); + else + launched_async_io = 1; + } + lockmgr(vp->v_vnlock, LK_RELEASE, NULL); + td->td_pflags = (td->td_pflags & ~TDP_NORUNNINGBUF) | + prev_norunningbuf; + if (launched_async_io && (td->td_pflags & TDP_NORUNNINGBUF) == 0) + waitrunningbufspace(); + /* + * I/O on bp will now be started, so count it in runningbufspace. + */ + if (saved_runningbufspace != 0) { + bp->b_runningbufspace = saved_runningbufspace; + atomic_add_long(&runningbufspace, bp->b_runningbufspace); + } + return (error); +} + +/* + * sync snapshots to force freework records waiting on snapshots to claim + * blocks to free. + */ +void +ffs_sync_snap(mp, waitfor) + struct mount *mp; + int waitfor; +{ + struct snapdata *sn; + struct vnode *devvp; + struct vnode *vp; + struct inode *ip; + + devvp = VFSTOUFS(mp)->um_devvp; + if ((devvp->v_vflag & VV_COPYONWRITE) == 0) + return; + for (;;) { + VI_LOCK(devvp); + sn = devvp->v_rdev->si_snapdata; + if (sn == NULL) { + VI_UNLOCK(devvp); + return; + } + if (lockmgr(&sn->sn_lock, + LK_INTERLOCK | LK_EXCLUSIVE | LK_SLEEPFAIL, + VI_MTX(devvp)) == 0) + break; + } + TAILQ_FOREACH(ip, &sn->sn_head, i_nextsnap) { + vp = ITOV(ip); + ffs_syncvnode(vp, waitfor, NO_INO_UPDT); + } + lockmgr(&sn->sn_lock, LK_RELEASE, NULL); +} + +/* + * Read the specified block into the given buffer. + * Much of this boiler-plate comes from bwrite(). + */ +static int +readblock(vp, bp, lbn) + struct vnode *vp; + struct buf *bp; + ufs2_daddr_t lbn; +{ + struct inode *ip = VTOI(vp); + struct bio *bip; + struct fs *fs; + + ip = VTOI(vp); + fs = ITOFS(ip); + + bip = g_alloc_bio(); + bip->bio_cmd = BIO_READ; + bip->bio_offset = dbtob(fsbtodb(fs, blkstofrags(fs, lbn))); + bip->bio_data = bp->b_data; + bip->bio_length = bp->b_bcount; + bip->bio_done = NULL; + + g_io_request(bip, ITODEVVP(ip)->v_bufobj.bo_private); + bp->b_error = biowait(bip, "snaprdb"); + g_destroy_bio(bip); + return (bp->b_error); +} + +#endif + +/* + * Process file deletes that were deferred by ufs_inactive() due to + * the file system being suspended. Transfer IN_LAZYACCESS into + * IN_MODIFIED for vnodes that were accessed during suspension. + */ +void +process_deferred_inactive(struct mount *mp) +{ + struct vnode *vp, *mvp; + struct inode *ip; + struct thread *td; + int error; + + td = curthread; + (void) vn_start_secondary_write(NULL, &mp, V_WAIT); + loop: + MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { + /* + * IN_LAZYACCESS is checked here without holding any + * vnode lock, but this flag is set only while holding + * vnode interlock. + */ + if (vp->v_type == VNON || + ((VTOI(vp)->i_flag & IN_LAZYACCESS) == 0 && + ((vp->v_iflag & VI_OWEINACT) == 0 || vp->v_usecount > 0))) { + VI_UNLOCK(vp); + continue; + } + vholdl(vp); + error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK); + if (error != 0) { + vdrop(vp); + if (error == ENOENT) + continue; /* vnode recycled */ + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + goto loop; + } + ip = VTOI(vp); + if ((ip->i_flag & IN_LAZYACCESS) != 0) { + ip->i_flag &= ~IN_LAZYACCESS; + ip->i_flag |= IN_MODIFIED; + } + VI_LOCK(vp); + if ((vp->v_iflag & VI_OWEINACT) == 0 || vp->v_usecount > 0) { + VI_UNLOCK(vp); + VOP_UNLOCK(vp, 0); + vdrop(vp); + continue; + } + vinactive(vp, td); + VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, + ("process_deferred_inactive: got VI_OWEINACT")); + VI_UNLOCK(vp); + VOP_UNLOCK(vp, 0); + vdrop(vp); + } + vn_finished_secondary_write(mp); +} + +#ifndef NO_FFS_SNAPSHOT + +static struct snapdata * +ffs_snapdata_alloc(void) +{ + struct snapdata *sn; + + /* + * Fetch a snapdata from the free list if there is one available. + */ + mtx_lock(&snapfree_lock); + sn = LIST_FIRST(&snapfree); + if (sn != NULL) + LIST_REMOVE(sn, sn_link); + mtx_unlock(&snapfree_lock); + if (sn != NULL) + return (sn); + /* + * If there were no free snapdatas allocate one. + */ + sn = malloc(sizeof *sn, M_UFSMNT, M_WAITOK | M_ZERO); + TAILQ_INIT(&sn->sn_head); + lockinit(&sn->sn_lock, PVFS, "snaplk", VLKTIMEOUT, + LK_CANRECURSE | LK_NOSHARE); + return (sn); +} + +/* + * The snapdata is never freed because we can not be certain that + * there are no threads sleeping on the snap lock. Persisting + * them permanently avoids costly synchronization in ffs_lock(). + */ +static void +ffs_snapdata_free(struct snapdata *sn) +{ + mtx_lock(&snapfree_lock); + LIST_INSERT_HEAD(&snapfree, sn, sn_link); + mtx_unlock(&snapfree_lock); +} + +/* Try to free snapdata associated with devvp */ +static void +try_free_snapdata(struct vnode *devvp) +{ + struct snapdata *sn; + ufs2_daddr_t *snapblklist; + + ASSERT_VI_LOCKED(devvp, "try_free_snapdata"); + sn = devvp->v_rdev->si_snapdata; + + if (sn == NULL || TAILQ_FIRST(&sn->sn_head) != NULL || + (devvp->v_vflag & VV_COPYONWRITE) == 0) { + VI_UNLOCK(devvp); + return; + } + + devvp->v_rdev->si_snapdata = NULL; + devvp->v_vflag &= ~VV_COPYONWRITE; + lockmgr(&sn->sn_lock, LK_DRAIN|LK_INTERLOCK, VI_MTX(devvp)); + snapblklist = sn->sn_blklist; + sn->sn_blklist = NULL; + sn->sn_listsize = 0; + lockmgr(&sn->sn_lock, LK_RELEASE, NULL); + if (snapblklist != NULL) + free(snapblklist, M_UFSMNT); + ffs_snapdata_free(sn); +} + +static struct snapdata * +ffs_snapdata_acquire(struct vnode *devvp) +{ + struct snapdata *nsn, *sn; + int error; + + /* + * Allocate a free snapdata. This is done before acquiring the + * devvp lock to avoid allocation while the devvp interlock is + * held. + */ + nsn = ffs_snapdata_alloc(); + + for (;;) { + VI_LOCK(devvp); + sn = devvp->v_rdev->si_snapdata; + if (sn == NULL) { + /* + * This is the first snapshot on this + * filesystem and we use our pre-allocated + * snapdata. Publish sn with the sn_lock + * owned by us, to avoid the race. + */ + error = lockmgr(&nsn->sn_lock, LK_EXCLUSIVE | + LK_NOWAIT, NULL); + if (error != 0) + panic("leaked sn, lockmgr error %d", error); + sn = devvp->v_rdev->si_snapdata = nsn; + VI_UNLOCK(devvp); + nsn = NULL; + break; + } + + /* + * There is a snapshots which already exists on this + * filesystem, grab a reference to the common lock. + */ + error = lockmgr(&sn->sn_lock, LK_INTERLOCK | + LK_EXCLUSIVE | LK_SLEEPFAIL, VI_MTX(devvp)); + if (error == 0) + break; + } + + /* + * Free any unused snapdata. + */ + if (nsn != NULL) + ffs_snapdata_free(nsn); + + return (sn); +} + +#endif diff --git a/Dump/ufs/ffs/ffs_softdep.c b/Dump/ufs/ffs/ffs_softdep.c new file mode 100644 index 0000000..c154435 --- /dev/null +++ b/Dump/ufs/ffs/ffs_softdep.c @@ -0,0 +1,14469 @@ +/*- + * Copyright 1998, 2000 Marshall Kirk McKusick. + * Copyright 2009, 2010 Jeffrey W. Roberson + * All rights reserved. + * + * The soft updates code is derived from the appendix of a University + * of Michigan technical report (Gregory R. Ganger and Yale N. Patt, + * "Soft Updates: A Solution to the Metadata Update Problem in File + * Systems", CSE-TR-254-95, August 1995). + * + * Further information about soft updates can be obtained from: + * + * Marshall Kirk McKusick http://www.mckusick.com/softdep/ + * 1614 Oxford Street mckusick@mckusick.com + * Berkeley, CA 94709-1608 +1-510-843-9542 + * USA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * from: @(#)ffs_softdep.c 9.59 (McKusick) 6/21/00 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_softdep.c 330446 2018-03-05 06:59:30Z eadler $"); + +#include "opt_ffs.h" +#include "opt_quota.h" +#include "opt_ddb.h" + +/* + * For now we want the safety net that the DEBUG flag provides. + */ +#ifndef DEBUG +#define DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#define KTR_SUJ 0 /* Define to KTR_SPARE. */ + +#ifndef SOFTUPDATES + +int +softdep_flushfiles(oldmnt, flags, td) + struct mount *oldmnt; + int flags; + struct thread *td; +{ + + panic("softdep_flushfiles called"); +} + +int +softdep_mount(devvp, mp, fs, cred) + struct vnode *devvp; + struct mount *mp; + struct fs *fs; + struct ucred *cred; +{ + + return (0); +} + +void +softdep_initialize() +{ + + return; +} + +void +softdep_uninitialize() +{ + + return; +} + +void +softdep_unmount(mp) + struct mount *mp; +{ + + panic("softdep_unmount called"); +} + +void +softdep_setup_sbupdate(ump, fs, bp) + struct ufsmount *ump; + struct fs *fs; + struct buf *bp; +{ + + panic("softdep_setup_sbupdate called"); +} + +void +softdep_setup_inomapdep(bp, ip, newinum, mode) + struct buf *bp; + struct inode *ip; + ino_t newinum; + int mode; +{ + + panic("softdep_setup_inomapdep called"); +} + +void +softdep_setup_blkmapdep(bp, mp, newblkno, frags, oldfrags) + struct buf *bp; + struct mount *mp; + ufs2_daddr_t newblkno; + int frags; + int oldfrags; +{ + + panic("softdep_setup_blkmapdep called"); +} + +void +softdep_setup_allocdirect(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp) + struct inode *ip; + ufs_lbn_t lbn; + ufs2_daddr_t newblkno; + ufs2_daddr_t oldblkno; + long newsize; + long oldsize; + struct buf *bp; +{ + + panic("softdep_setup_allocdirect called"); +} + +void +softdep_setup_allocext(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp) + struct inode *ip; + ufs_lbn_t lbn; + ufs2_daddr_t newblkno; + ufs2_daddr_t oldblkno; + long newsize; + long oldsize; + struct buf *bp; +{ + + panic("softdep_setup_allocext called"); +} + +void +softdep_setup_allocindir_page(ip, lbn, bp, ptrno, newblkno, oldblkno, nbp) + struct inode *ip; + ufs_lbn_t lbn; + struct buf *bp; + int ptrno; + ufs2_daddr_t newblkno; + ufs2_daddr_t oldblkno; + struct buf *nbp; +{ + + panic("softdep_setup_allocindir_page called"); +} + +void +softdep_setup_allocindir_meta(nbp, ip, bp, ptrno, newblkno) + struct buf *nbp; + struct inode *ip; + struct buf *bp; + int ptrno; + ufs2_daddr_t newblkno; +{ + + panic("softdep_setup_allocindir_meta called"); +} + +void +softdep_journal_freeblocks(ip, cred, length, flags) + struct inode *ip; + struct ucred *cred; + off_t length; + int flags; +{ + + panic("softdep_journal_freeblocks called"); +} + +void +softdep_journal_fsync(ip) + struct inode *ip; +{ + + panic("softdep_journal_fsync called"); +} + +void +softdep_setup_freeblocks(ip, length, flags) + struct inode *ip; + off_t length; + int flags; +{ + + panic("softdep_setup_freeblocks called"); +} + +void +softdep_freefile(pvp, ino, mode) + struct vnode *pvp; + ino_t ino; + int mode; +{ + + panic("softdep_freefile called"); +} + +int +softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp, isnewblk) + struct buf *bp; + struct inode *dp; + off_t diroffset; + ino_t newinum; + struct buf *newdirbp; + int isnewblk; +{ + + panic("softdep_setup_directory_add called"); +} + +void +softdep_change_directoryentry_offset(bp, dp, base, oldloc, newloc, entrysize) + struct buf *bp; + struct inode *dp; + caddr_t base; + caddr_t oldloc; + caddr_t newloc; + int entrysize; +{ + + panic("softdep_change_directoryentry_offset called"); +} + +void +softdep_setup_remove(bp, dp, ip, isrmdir) + struct buf *bp; + struct inode *dp; + struct inode *ip; + int isrmdir; +{ + + panic("softdep_setup_remove called"); +} + +void +softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir) + struct buf *bp; + struct inode *dp; + struct inode *ip; + ino_t newinum; + int isrmdir; +{ + + panic("softdep_setup_directory_change called"); +} + +void +softdep_setup_blkfree(mp, bp, blkno, frags, wkhd) + struct mount *mp; + struct buf *bp; + ufs2_daddr_t blkno; + int frags; + struct workhead *wkhd; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_setup_inofree(mp, bp, ino, wkhd) + struct mount *mp; + struct buf *bp; + ino_t ino; + struct workhead *wkhd; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_setup_unlink(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_setup_link(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_revert_link(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_setup_rmdir(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_revert_rmdir(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_setup_create(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_revert_create(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_setup_mkdir(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_revert_mkdir(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +void +softdep_setup_dotdot_link(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + panic("%s called", __FUNCTION__); +} + +int +softdep_prealloc(vp, waitok) + struct vnode *vp; + int waitok; +{ + + panic("%s called", __FUNCTION__); +} + +int +softdep_journal_lookup(mp, vpp) + struct mount *mp; + struct vnode **vpp; +{ + + return (ENOENT); +} + +void +softdep_change_linkcnt(ip) + struct inode *ip; +{ + + panic("softdep_change_linkcnt called"); +} + +void +softdep_load_inodeblock(ip) + struct inode *ip; +{ + + panic("softdep_load_inodeblock called"); +} + +void +softdep_update_inodeblock(ip, bp, waitfor) + struct inode *ip; + struct buf *bp; + int waitfor; +{ + + panic("softdep_update_inodeblock called"); +} + +int +softdep_fsync(vp) + struct vnode *vp; /* the "in_core" copy of the inode */ +{ + + return (0); +} + +void +softdep_fsync_mountdev(vp) + struct vnode *vp; +{ + + return; +} + +int +softdep_flushworklist(oldmnt, countp, td) + struct mount *oldmnt; + int *countp; + struct thread *td; +{ + + *countp = 0; + return (0); +} + +int +softdep_sync_metadata(struct vnode *vp) +{ + + panic("softdep_sync_metadata called"); +} + +int +softdep_sync_buf(struct vnode *vp, struct buf *bp, int waitfor) +{ + + panic("softdep_sync_buf called"); +} + +int +softdep_slowdown(vp) + struct vnode *vp; +{ + + panic("softdep_slowdown called"); +} + +int +softdep_request_cleanup(fs, vp, cred, resource) + struct fs *fs; + struct vnode *vp; + struct ucred *cred; + int resource; +{ + + return (0); +} + +int +softdep_check_suspend(struct mount *mp, + struct vnode *devvp, + int softdep_depcnt, + int softdep_accdepcnt, + int secondary_writes, + int secondary_accwrites) +{ + struct bufobj *bo; + int error; + + (void) softdep_depcnt, + (void) softdep_accdepcnt; + + bo = &devvp->v_bufobj; + ASSERT_BO_WLOCKED(bo); + + MNT_ILOCK(mp); + while (mp->mnt_secondary_writes != 0) { + BO_UNLOCK(bo); + msleep(&mp->mnt_secondary_writes, MNT_MTX(mp), + (PUSER - 1) | PDROP, "secwr", 0); + BO_LOCK(bo); + MNT_ILOCK(mp); + } + + /* + * Reasons for needing more work before suspend: + * - Dirty buffers on devvp. + * - Secondary writes occurred after start of vnode sync loop + */ + error = 0; + if (bo->bo_numoutput > 0 || + bo->bo_dirty.bv_cnt > 0 || + secondary_writes != 0 || + mp->mnt_secondary_writes != 0 || + secondary_accwrites != mp->mnt_secondary_accwrites) + error = EAGAIN; + BO_UNLOCK(bo); + return (error); +} + +void +softdep_get_depcounts(struct mount *mp, + int *softdepactivep, + int *softdepactiveaccp) +{ + (void) mp; + *softdepactivep = 0; + *softdepactiveaccp = 0; +} + +void +softdep_buf_append(bp, wkhd) + struct buf *bp; + struct workhead *wkhd; +{ + + panic("softdep_buf_appendwork called"); +} + +void +softdep_inode_append(ip, cred, wkhd) + struct inode *ip; + struct ucred *cred; + struct workhead *wkhd; +{ + + panic("softdep_inode_appendwork called"); +} + +void +softdep_freework(wkhd) + struct workhead *wkhd; +{ + + panic("softdep_freework called"); +} + +#else + +FEATURE(softupdates, "FFS soft-updates support"); + +static SYSCTL_NODE(_debug, OID_AUTO, softdep, CTLFLAG_RW, 0, + "soft updates stats"); +static SYSCTL_NODE(_debug_softdep, OID_AUTO, total, CTLFLAG_RW, 0, + "total dependencies allocated"); +static SYSCTL_NODE(_debug_softdep, OID_AUTO, highuse, CTLFLAG_RW, 0, + "high use dependencies allocated"); +static SYSCTL_NODE(_debug_softdep, OID_AUTO, current, CTLFLAG_RW, 0, + "current dependencies allocated"); +static SYSCTL_NODE(_debug_softdep, OID_AUTO, write, CTLFLAG_RW, 0, + "current dependencies written"); + +unsigned long dep_current[D_LAST + 1]; +unsigned long dep_highuse[D_LAST + 1]; +unsigned long dep_total[D_LAST + 1]; +unsigned long dep_write[D_LAST + 1]; + +#define SOFTDEP_TYPE(type, str, long) \ + static MALLOC_DEFINE(M_ ## type, #str, long); \ + SYSCTL_ULONG(_debug_softdep_total, OID_AUTO, str, CTLFLAG_RD, \ + &dep_total[D_ ## type], 0, ""); \ + SYSCTL_ULONG(_debug_softdep_current, OID_AUTO, str, CTLFLAG_RD, \ + &dep_current[D_ ## type], 0, ""); \ + SYSCTL_ULONG(_debug_softdep_highuse, OID_AUTO, str, CTLFLAG_RD, \ + &dep_highuse[D_ ## type], 0, ""); \ + SYSCTL_ULONG(_debug_softdep_write, OID_AUTO, str, CTLFLAG_RD, \ + &dep_write[D_ ## type], 0, ""); + +SOFTDEP_TYPE(PAGEDEP, pagedep, "File page dependencies"); +SOFTDEP_TYPE(INODEDEP, inodedep, "Inode dependencies"); +SOFTDEP_TYPE(BMSAFEMAP, bmsafemap, + "Block or frag allocated from cyl group map"); +SOFTDEP_TYPE(NEWBLK, newblk, "New block or frag allocation dependency"); +SOFTDEP_TYPE(ALLOCDIRECT, allocdirect, "Block or frag dependency for an inode"); +SOFTDEP_TYPE(INDIRDEP, indirdep, "Indirect block dependencies"); +SOFTDEP_TYPE(ALLOCINDIR, allocindir, "Block dependency for an indirect block"); +SOFTDEP_TYPE(FREEFRAG, freefrag, "Previously used frag for an inode"); +SOFTDEP_TYPE(FREEBLKS, freeblks, "Blocks freed from an inode"); +SOFTDEP_TYPE(FREEFILE, freefile, "Inode deallocated"); +SOFTDEP_TYPE(DIRADD, diradd, "New directory entry"); +SOFTDEP_TYPE(MKDIR, mkdir, "New directory"); +SOFTDEP_TYPE(DIRREM, dirrem, "Directory entry deleted"); +SOFTDEP_TYPE(NEWDIRBLK, newdirblk, "Unclaimed new directory block"); +SOFTDEP_TYPE(FREEWORK, freework, "free an inode block"); +SOFTDEP_TYPE(FREEDEP, freedep, "track a block free"); +SOFTDEP_TYPE(JADDREF, jaddref, "Journal inode ref add"); +SOFTDEP_TYPE(JREMREF, jremref, "Journal inode ref remove"); +SOFTDEP_TYPE(JMVREF, jmvref, "Journal inode ref move"); +SOFTDEP_TYPE(JNEWBLK, jnewblk, "Journal new block"); +SOFTDEP_TYPE(JFREEBLK, jfreeblk, "Journal free block"); +SOFTDEP_TYPE(JFREEFRAG, jfreefrag, "Journal free frag"); +SOFTDEP_TYPE(JSEG, jseg, "Journal segment"); +SOFTDEP_TYPE(JSEGDEP, jsegdep, "Journal segment complete"); +SOFTDEP_TYPE(SBDEP, sbdep, "Superblock write dependency"); +SOFTDEP_TYPE(JTRUNC, jtrunc, "Journal inode truncation"); +SOFTDEP_TYPE(JFSYNC, jfsync, "Journal fsync complete"); + +static MALLOC_DEFINE(M_SENTINEL, "sentinel", "Worklist sentinel"); + +static MALLOC_DEFINE(M_SAVEDINO, "savedino", "Saved inodes"); +static MALLOC_DEFINE(M_JBLOCKS, "jblocks", "Journal block locations"); +static MALLOC_DEFINE(M_MOUNTDATA, "softdep", "Softdep per-mount data"); + +#define M_SOFTDEP_FLAGS (M_WAITOK) + +/* + * translate from workitem type to memory type + * MUST match the defines above, such that memtype[D_XXX] == M_XXX + */ +static struct malloc_type *memtype[] = { + M_PAGEDEP, + M_INODEDEP, + M_BMSAFEMAP, + M_NEWBLK, + M_ALLOCDIRECT, + M_INDIRDEP, + M_ALLOCINDIR, + M_FREEFRAG, + M_FREEBLKS, + M_FREEFILE, + M_DIRADD, + M_MKDIR, + M_DIRREM, + M_NEWDIRBLK, + M_FREEWORK, + M_FREEDEP, + M_JADDREF, + M_JREMREF, + M_JMVREF, + M_JNEWBLK, + M_JFREEBLK, + M_JFREEFRAG, + M_JSEG, + M_JSEGDEP, + M_SBDEP, + M_JTRUNC, + M_JFSYNC, + M_SENTINEL +}; + +#define DtoM(type) (memtype[type]) + +/* + * Names of malloc types. + */ +#define TYPENAME(type) \ + ((unsigned)(type) <= D_LAST ? memtype[type]->ks_shortdesc : "???") +/* + * End system adaptation definitions. + */ + +#define DOTDOT_OFFSET offsetof(struct dirtemplate, dotdot_ino) +#define DOT_OFFSET offsetof(struct dirtemplate, dot_ino) + +/* + * Internal function prototypes. + */ +static void check_clear_deps(struct mount *); +static void softdep_error(char *, int); +static int softdep_process_worklist(struct mount *, int); +static int softdep_waitidle(struct mount *, int); +static void drain_output(struct vnode *); +static struct buf *getdirtybuf(struct buf *, struct rwlock *, int); +static int check_inodedep_free(struct inodedep *); +static void clear_remove(struct mount *); +static void clear_inodedeps(struct mount *); +static void unlinked_inodedep(struct mount *, struct inodedep *); +static void clear_unlinked_inodedep(struct inodedep *); +static struct inodedep *first_unlinked_inodedep(struct ufsmount *); +static int flush_pagedep_deps(struct vnode *, struct mount *, + struct diraddhd *); +static int free_pagedep(struct pagedep *); +static int flush_newblk_dep(struct vnode *, struct mount *, ufs_lbn_t); +static int flush_inodedep_deps(struct vnode *, struct mount *, ino_t); +static int flush_deplist(struct allocdirectlst *, int, int *); +static int sync_cgs(struct mount *, int); +static int handle_written_filepage(struct pagedep *, struct buf *, int); +static int handle_written_sbdep(struct sbdep *, struct buf *); +static void initiate_write_sbdep(struct sbdep *); +static void diradd_inode_written(struct diradd *, struct inodedep *); +static int handle_written_indirdep(struct indirdep *, struct buf *, + struct buf**, int); +static int handle_written_inodeblock(struct inodedep *, struct buf *, int); +static int jnewblk_rollforward(struct jnewblk *, struct fs *, struct cg *, + uint8_t *); +static int handle_written_bmsafemap(struct bmsafemap *, struct buf *, int); +static void handle_written_jaddref(struct jaddref *); +static void handle_written_jremref(struct jremref *); +static void handle_written_jseg(struct jseg *, struct buf *); +static void handle_written_jnewblk(struct jnewblk *); +static void handle_written_jblkdep(struct jblkdep *); +static void handle_written_jfreefrag(struct jfreefrag *); +static void complete_jseg(struct jseg *); +static void complete_jsegs(struct jseg *); +static void jseg_write(struct ufsmount *ump, struct jseg *, uint8_t *); +static void jaddref_write(struct jaddref *, struct jseg *, uint8_t *); +static void jremref_write(struct jremref *, struct jseg *, uint8_t *); +static void jmvref_write(struct jmvref *, struct jseg *, uint8_t *); +static void jtrunc_write(struct jtrunc *, struct jseg *, uint8_t *); +static void jfsync_write(struct jfsync *, struct jseg *, uint8_t *data); +static void jnewblk_write(struct jnewblk *, struct jseg *, uint8_t *); +static void jfreeblk_write(struct jfreeblk *, struct jseg *, uint8_t *); +static void jfreefrag_write(struct jfreefrag *, struct jseg *, uint8_t *); +static inline void inoref_write(struct inoref *, struct jseg *, + struct jrefrec *); +static void handle_allocdirect_partdone(struct allocdirect *, + struct workhead *); +static struct jnewblk *cancel_newblk(struct newblk *, struct worklist *, + struct workhead *); +static void indirdep_complete(struct indirdep *); +static int indirblk_lookup(struct mount *, ufs2_daddr_t); +static void indirblk_insert(struct freework *); +static void indirblk_remove(struct freework *); +static void handle_allocindir_partdone(struct allocindir *); +static void initiate_write_filepage(struct pagedep *, struct buf *); +static void initiate_write_indirdep(struct indirdep*, struct buf *); +static void handle_written_mkdir(struct mkdir *, int); +static int jnewblk_rollback(struct jnewblk *, struct fs *, struct cg *, + uint8_t *); +static void initiate_write_bmsafemap(struct bmsafemap *, struct buf *); +static void initiate_write_inodeblock_ufs1(struct inodedep *, struct buf *); +static void initiate_write_inodeblock_ufs2(struct inodedep *, struct buf *); +static void handle_workitem_freefile(struct freefile *); +static int handle_workitem_remove(struct dirrem *, int); +static struct dirrem *newdirrem(struct buf *, struct inode *, + struct inode *, int, struct dirrem **); +static struct indirdep *indirdep_lookup(struct mount *, struct inode *, + struct buf *); +static void cancel_indirdep(struct indirdep *, struct buf *, + struct freeblks *); +static void free_indirdep(struct indirdep *); +static void free_diradd(struct diradd *, struct workhead *); +static void merge_diradd(struct inodedep *, struct diradd *); +static void complete_diradd(struct diradd *); +static struct diradd *diradd_lookup(struct pagedep *, int); +static struct jremref *cancel_diradd_dotdot(struct inode *, struct dirrem *, + struct jremref *); +static struct jremref *cancel_mkdir_dotdot(struct inode *, struct dirrem *, + struct jremref *); +static void cancel_diradd(struct diradd *, struct dirrem *, struct jremref *, + struct jremref *, struct jremref *); +static void dirrem_journal(struct dirrem *, struct jremref *, struct jremref *, + struct jremref *); +static void cancel_allocindir(struct allocindir *, struct buf *bp, + struct freeblks *, int); +static int setup_trunc_indir(struct freeblks *, struct inode *, + ufs_lbn_t, ufs_lbn_t, ufs2_daddr_t); +static void complete_trunc_indir(struct freework *); +static void trunc_indirdep(struct indirdep *, struct freeblks *, struct buf *, + int); +static void complete_mkdir(struct mkdir *); +static void free_newdirblk(struct newdirblk *); +static void free_jremref(struct jremref *); +static void free_jaddref(struct jaddref *); +static void free_jsegdep(struct jsegdep *); +static void free_jsegs(struct jblocks *); +static void rele_jseg(struct jseg *); +static void free_jseg(struct jseg *, struct jblocks *); +static void free_jnewblk(struct jnewblk *); +static void free_jblkdep(struct jblkdep *); +static void free_jfreefrag(struct jfreefrag *); +static void free_freedep(struct freedep *); +static void journal_jremref(struct dirrem *, struct jremref *, + struct inodedep *); +static void cancel_jnewblk(struct jnewblk *, struct workhead *); +static int cancel_jaddref(struct jaddref *, struct inodedep *, + struct workhead *); +static void cancel_jfreefrag(struct jfreefrag *); +static inline void setup_freedirect(struct freeblks *, struct inode *, + int, int); +static inline void setup_freeext(struct freeblks *, struct inode *, int, int); +static inline void setup_freeindir(struct freeblks *, struct inode *, int, + ufs_lbn_t, int); +static inline struct freeblks *newfreeblks(struct mount *, struct inode *); +static void freeblks_free(struct ufsmount *, struct freeblks *, int); +static void indir_trunc(struct freework *, ufs2_daddr_t, ufs_lbn_t); +static ufs2_daddr_t blkcount(struct fs *, ufs2_daddr_t, off_t); +static int trunc_check_buf(struct buf *, int *, ufs_lbn_t, int, int); +static void trunc_dependencies(struct inode *, struct freeblks *, ufs_lbn_t, + int, int); +static void trunc_pages(struct inode *, off_t, ufs2_daddr_t, int); +static int cancel_pagedep(struct pagedep *, struct freeblks *, int); +static int deallocate_dependencies(struct buf *, struct freeblks *, int); +static void newblk_freefrag(struct newblk*); +static void free_newblk(struct newblk *); +static void cancel_allocdirect(struct allocdirectlst *, + struct allocdirect *, struct freeblks *); +static int check_inode_unwritten(struct inodedep *); +static int free_inodedep(struct inodedep *); +static void freework_freeblock(struct freework *); +static void freework_enqueue(struct freework *); +static int handle_workitem_freeblocks(struct freeblks *, int); +static int handle_complete_freeblocks(struct freeblks *, int); +static void handle_workitem_indirblk(struct freework *); +static void handle_written_freework(struct freework *); +static void merge_inode_lists(struct allocdirectlst *,struct allocdirectlst *); +static struct worklist *jnewblk_merge(struct worklist *, struct worklist *, + struct workhead *); +static struct freefrag *setup_allocindir_phase2(struct buf *, struct inode *, + struct inodedep *, struct allocindir *, ufs_lbn_t); +static struct allocindir *newallocindir(struct inode *, int, ufs2_daddr_t, + ufs2_daddr_t, ufs_lbn_t); +static void handle_workitem_freefrag(struct freefrag *); +static struct freefrag *newfreefrag(struct inode *, ufs2_daddr_t, long, + ufs_lbn_t); +static void allocdirect_merge(struct allocdirectlst *, + struct allocdirect *, struct allocdirect *); +static struct freefrag *allocindir_merge(struct allocindir *, + struct allocindir *); +static int bmsafemap_find(struct bmsafemap_hashhead *, int, + struct bmsafemap **); +static struct bmsafemap *bmsafemap_lookup(struct mount *, struct buf *, + int cg, struct bmsafemap *); +static int newblk_find(struct newblk_hashhead *, ufs2_daddr_t, int, + struct newblk **); +static int newblk_lookup(struct mount *, ufs2_daddr_t, int, struct newblk **); +static int inodedep_find(struct inodedep_hashhead *, ino_t, + struct inodedep **); +static int inodedep_lookup(struct mount *, ino_t, int, struct inodedep **); +static int pagedep_lookup(struct mount *, struct buf *bp, ino_t, ufs_lbn_t, + int, struct pagedep **); +static int pagedep_find(struct pagedep_hashhead *, ino_t, ufs_lbn_t, + struct pagedep **); +static void pause_timer(void *); +static int request_cleanup(struct mount *, int); +static int softdep_request_cleanup_flush(struct mount *, struct ufsmount *); +static void schedule_cleanup(struct mount *); +static void softdep_ast_cleanup_proc(struct thread *); +static struct ufsmount *softdep_bp_to_mp(struct buf *bp); +static int process_worklist_item(struct mount *, int, int); +static void process_removes(struct vnode *); +static void process_truncates(struct vnode *); +static void jwork_move(struct workhead *, struct workhead *); +static void jwork_insert(struct workhead *, struct jsegdep *); +static void add_to_worklist(struct worklist *, int); +static void wake_worklist(struct worklist *); +static void wait_worklist(struct worklist *, char *); +static void remove_from_worklist(struct worklist *); +static void softdep_flush(void *); +static void softdep_flushjournal(struct mount *); +static int softdep_speedup(struct ufsmount *); +static void worklist_speedup(struct mount *); +static int journal_mount(struct mount *, struct fs *, struct ucred *); +static void journal_unmount(struct ufsmount *); +static int journal_space(struct ufsmount *, int); +static void journal_suspend(struct ufsmount *); +static int journal_unsuspend(struct ufsmount *ump); +static void softdep_prelink(struct vnode *, struct vnode *); +static void add_to_journal(struct worklist *); +static void remove_from_journal(struct worklist *); +static bool softdep_excess_items(struct ufsmount *, int); +static void softdep_process_journal(struct mount *, struct worklist *, int); +static struct jremref *newjremref(struct dirrem *, struct inode *, + struct inode *ip, off_t, nlink_t); +static struct jaddref *newjaddref(struct inode *, ino_t, off_t, int16_t, + uint16_t); +static inline void newinoref(struct inoref *, ino_t, ino_t, off_t, nlink_t, + uint16_t); +static inline struct jsegdep *inoref_jseg(struct inoref *); +static struct jmvref *newjmvref(struct inode *, ino_t, off_t, off_t); +static struct jfreeblk *newjfreeblk(struct freeblks *, ufs_lbn_t, + ufs2_daddr_t, int); +static void adjust_newfreework(struct freeblks *, int); +static struct jtrunc *newjtrunc(struct freeblks *, off_t, int); +static void move_newblock_dep(struct jaddref *, struct inodedep *); +static void cancel_jfreeblk(struct freeblks *, ufs2_daddr_t); +static struct jfreefrag *newjfreefrag(struct freefrag *, struct inode *, + ufs2_daddr_t, long, ufs_lbn_t); +static struct freework *newfreework(struct ufsmount *, struct freeblks *, + struct freework *, ufs_lbn_t, ufs2_daddr_t, int, int, int); +static int jwait(struct worklist *, int); +static struct inodedep *inodedep_lookup_ip(struct inode *); +static int bmsafemap_backgroundwrite(struct bmsafemap *, struct buf *); +static struct freefile *handle_bufwait(struct inodedep *, struct workhead *); +static void handle_jwork(struct workhead *); +static struct mkdir *setup_newdir(struct diradd *, ino_t, ino_t, struct buf *, + struct mkdir **); +static struct jblocks *jblocks_create(void); +static ufs2_daddr_t jblocks_alloc(struct jblocks *, int, int *); +static void jblocks_free(struct jblocks *, struct mount *, int); +static void jblocks_destroy(struct jblocks *); +static void jblocks_add(struct jblocks *, ufs2_daddr_t, int); + +/* + * Exported softdep operations. + */ +static void softdep_disk_io_initiation(struct buf *); +static void softdep_disk_write_complete(struct buf *); +static void softdep_deallocate_dependencies(struct buf *); +static int softdep_count_dependencies(struct buf *bp, int); + +/* + * Global lock over all of soft updates. + */ +static struct mtx lk; +MTX_SYSINIT(softdep_lock, &lk, "Global Softdep Lock", MTX_DEF); + +#define ACQUIRE_GBLLOCK(lk) mtx_lock(lk) +#define FREE_GBLLOCK(lk) mtx_unlock(lk) +#define GBLLOCK_OWNED(lk) mtx_assert((lk), MA_OWNED) + +/* + * Per-filesystem soft-updates locking. + */ +#define LOCK_PTR(ump) (&(ump)->um_softdep->sd_fslock) +#define TRY_ACQUIRE_LOCK(ump) rw_try_wlock(&(ump)->um_softdep->sd_fslock) +#define ACQUIRE_LOCK(ump) rw_wlock(&(ump)->um_softdep->sd_fslock) +#define FREE_LOCK(ump) rw_wunlock(&(ump)->um_softdep->sd_fslock) +#define LOCK_OWNED(ump) rw_assert(&(ump)->um_softdep->sd_fslock, \ + RA_WLOCKED) + +#define BUF_AREC(bp) lockallowrecurse(&(bp)->b_lock) +#define BUF_NOREC(bp) lockdisablerecurse(&(bp)->b_lock) + +/* + * Worklist queue management. + * These routines require that the lock be held. + */ +#ifndef /* NOT */ DEBUG +#define WORKLIST_INSERT(head, item) do { \ + (item)->wk_state |= ONWORKLIST; \ + LIST_INSERT_HEAD(head, item, wk_list); \ +} while (0) +#define WORKLIST_REMOVE(item) do { \ + (item)->wk_state &= ~ONWORKLIST; \ + LIST_REMOVE(item, wk_list); \ +} while (0) +#define WORKLIST_INSERT_UNLOCKED WORKLIST_INSERT +#define WORKLIST_REMOVE_UNLOCKED WORKLIST_REMOVE + +#else /* DEBUG */ +static void worklist_insert(struct workhead *, struct worklist *, int); +static void worklist_remove(struct worklist *, int); + +#define WORKLIST_INSERT(head, item) worklist_insert(head, item, 1) +#define WORKLIST_INSERT_UNLOCKED(head, item) worklist_insert(head, item, 0) +#define WORKLIST_REMOVE(item) worklist_remove(item, 1) +#define WORKLIST_REMOVE_UNLOCKED(item) worklist_remove(item, 0) + +static void +worklist_insert(head, item, locked) + struct workhead *head; + struct worklist *item; + int locked; +{ + + if (locked) + LOCK_OWNED(VFSTOUFS(item->wk_mp)); + if (item->wk_state & ONWORKLIST) + panic("worklist_insert: %p %s(0x%X) already on list", + item, TYPENAME(item->wk_type), item->wk_state); + item->wk_state |= ONWORKLIST; + LIST_INSERT_HEAD(head, item, wk_list); +} + +static void +worklist_remove(item, locked) + struct worklist *item; + int locked; +{ + + if (locked) + LOCK_OWNED(VFSTOUFS(item->wk_mp)); + if ((item->wk_state & ONWORKLIST) == 0) + panic("worklist_remove: %p %s(0x%X) not on list", + item, TYPENAME(item->wk_type), item->wk_state); + item->wk_state &= ~ONWORKLIST; + LIST_REMOVE(item, wk_list); +} +#endif /* DEBUG */ + +/* + * Merge two jsegdeps keeping only the oldest one as newer references + * can't be discarded until after older references. + */ +static inline struct jsegdep * +jsegdep_merge(struct jsegdep *one, struct jsegdep *two) +{ + struct jsegdep *swp; + + if (two == NULL) + return (one); + + if (one->jd_seg->js_seq > two->jd_seg->js_seq) { + swp = one; + one = two; + two = swp; + } + WORKLIST_REMOVE(&two->jd_list); + free_jsegdep(two); + + return (one); +} + +/* + * If two freedeps are compatible free one to reduce list size. + */ +static inline struct freedep * +freedep_merge(struct freedep *one, struct freedep *two) +{ + if (two == NULL) + return (one); + + if (one->fd_freework == two->fd_freework) { + WORKLIST_REMOVE(&two->fd_list); + free_freedep(two); + } + return (one); +} + +/* + * Move journal work from one list to another. Duplicate freedeps and + * jsegdeps are coalesced to keep the lists as small as possible. + */ +static void +jwork_move(dst, src) + struct workhead *dst; + struct workhead *src; +{ + struct freedep *freedep; + struct jsegdep *jsegdep; + struct worklist *wkn; + struct worklist *wk; + + KASSERT(dst != src, + ("jwork_move: dst == src")); + freedep = NULL; + jsegdep = NULL; + LIST_FOREACH_SAFE(wk, dst, wk_list, wkn) { + if (wk->wk_type == D_JSEGDEP) + jsegdep = jsegdep_merge(WK_JSEGDEP(wk), jsegdep); + else if (wk->wk_type == D_FREEDEP) + freedep = freedep_merge(WK_FREEDEP(wk), freedep); + } + + while ((wk = LIST_FIRST(src)) != NULL) { + WORKLIST_REMOVE(wk); + WORKLIST_INSERT(dst, wk); + if (wk->wk_type == D_JSEGDEP) { + jsegdep = jsegdep_merge(WK_JSEGDEP(wk), jsegdep); + continue; + } + if (wk->wk_type == D_FREEDEP) + freedep = freedep_merge(WK_FREEDEP(wk), freedep); + } +} + +static void +jwork_insert(dst, jsegdep) + struct workhead *dst; + struct jsegdep *jsegdep; +{ + struct jsegdep *jsegdepn; + struct worklist *wk; + + LIST_FOREACH(wk, dst, wk_list) + if (wk->wk_type == D_JSEGDEP) + break; + if (wk == NULL) { + WORKLIST_INSERT(dst, &jsegdep->jd_list); + return; + } + jsegdepn = WK_JSEGDEP(wk); + if (jsegdep->jd_seg->js_seq < jsegdepn->jd_seg->js_seq) { + WORKLIST_REMOVE(wk); + free_jsegdep(jsegdepn); + WORKLIST_INSERT(dst, &jsegdep->jd_list); + } else + free_jsegdep(jsegdep); +} + +/* + * Routines for tracking and managing workitems. + */ +static void workitem_free(struct worklist *, int); +static void workitem_alloc(struct worklist *, int, struct mount *); +static void workitem_reassign(struct worklist *, int); + +#define WORKITEM_FREE(item, type) \ + workitem_free((struct worklist *)(item), (type)) +#define WORKITEM_REASSIGN(item, type) \ + workitem_reassign((struct worklist *)(item), (type)) + +static void +workitem_free(item, type) + struct worklist *item; + int type; +{ + struct ufsmount *ump; + +#ifdef DEBUG + if (item->wk_state & ONWORKLIST) + panic("workitem_free: %s(0x%X) still on list", + TYPENAME(item->wk_type), item->wk_state); + if (item->wk_type != type && type != D_NEWBLK) + panic("workitem_free: type mismatch %s != %s", + TYPENAME(item->wk_type), TYPENAME(type)); +#endif + if (item->wk_state & IOWAITING) + wakeup(item); + ump = VFSTOUFS(item->wk_mp); + LOCK_OWNED(ump); + KASSERT(ump->softdep_deps > 0, + ("workitem_free: %s: softdep_deps going negative", + ump->um_fs->fs_fsmnt)); + if (--ump->softdep_deps == 0 && ump->softdep_req) + wakeup(&ump->softdep_deps); + KASSERT(dep_current[item->wk_type] > 0, + ("workitem_free: %s: dep_current[%s] going negative", + ump->um_fs->fs_fsmnt, TYPENAME(item->wk_type))); + KASSERT(ump->softdep_curdeps[item->wk_type] > 0, + ("workitem_free: %s: softdep_curdeps[%s] going negative", + ump->um_fs->fs_fsmnt, TYPENAME(item->wk_type))); + atomic_subtract_long(&dep_current[item->wk_type], 1); + ump->softdep_curdeps[item->wk_type] -= 1; + free(item, DtoM(type)); +} + +static void +workitem_alloc(item, type, mp) + struct worklist *item; + int type; + struct mount *mp; +{ + struct ufsmount *ump; + + item->wk_type = type; + item->wk_mp = mp; + item->wk_state = 0; + + ump = VFSTOUFS(mp); + ACQUIRE_GBLLOCK(&lk); + dep_current[type]++; + if (dep_current[type] > dep_highuse[type]) + dep_highuse[type] = dep_current[type]; + dep_total[type]++; + FREE_GBLLOCK(&lk); + ACQUIRE_LOCK(ump); + ump->softdep_curdeps[type] += 1; + ump->softdep_deps++; + ump->softdep_accdeps++; + FREE_LOCK(ump); +} + +static void +workitem_reassign(item, newtype) + struct worklist *item; + int newtype; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(item->wk_mp); + LOCK_OWNED(ump); + KASSERT(ump->softdep_curdeps[item->wk_type] > 0, + ("workitem_reassign: %s: softdep_curdeps[%s] going negative", + VFSTOUFS(item->wk_mp)->um_fs->fs_fsmnt, TYPENAME(item->wk_type))); + ump->softdep_curdeps[item->wk_type] -= 1; + ump->softdep_curdeps[newtype] += 1; + KASSERT(dep_current[item->wk_type] > 0, + ("workitem_reassign: %s: dep_current[%s] going negative", + VFSTOUFS(item->wk_mp)->um_fs->fs_fsmnt, TYPENAME(item->wk_type))); + ACQUIRE_GBLLOCK(&lk); + dep_current[newtype]++; + dep_current[item->wk_type]--; + if (dep_current[newtype] > dep_highuse[newtype]) + dep_highuse[newtype] = dep_current[newtype]; + dep_total[newtype]++; + FREE_GBLLOCK(&lk); + item->wk_type = newtype; +} + +/* + * Workitem queue management + */ +static int max_softdeps; /* maximum number of structs before slowdown */ +static int tickdelay = 2; /* number of ticks to pause during slowdown */ +static int proc_waiting; /* tracks whether we have a timeout posted */ +static int *stat_countp; /* statistic to count in proc_waiting timeout */ +static struct callout softdep_callout; +static int req_clear_inodedeps; /* syncer process flush some inodedeps */ +static int req_clear_remove; /* syncer process flush some freeblks */ +static int softdep_flushcache = 0; /* Should we do BIO_FLUSH? */ + +/* + * runtime statistics + */ +static int stat_flush_threads; /* number of softdep flushing threads */ +static int stat_worklist_push; /* number of worklist cleanups */ +static int stat_blk_limit_push; /* number of times block limit neared */ +static int stat_ino_limit_push; /* number of times inode limit neared */ +static int stat_blk_limit_hit; /* number of times block slowdown imposed */ +static int stat_ino_limit_hit; /* number of times inode slowdown imposed */ +static int stat_sync_limit_hit; /* number of synchronous slowdowns imposed */ +static int stat_indir_blk_ptrs; /* bufs redirtied as indir ptrs not written */ +static int stat_inode_bitmap; /* bufs redirtied as inode bitmap not written */ +static int stat_direct_blk_ptrs;/* bufs redirtied as direct ptrs not written */ +static int stat_dir_entry; /* bufs redirtied as dir entry cannot write */ +static int stat_jaddref; /* bufs redirtied as ino bitmap can not write */ +static int stat_jnewblk; /* bufs redirtied as blk bitmap can not write */ +static int stat_journal_min; /* Times hit journal min threshold */ +static int stat_journal_low; /* Times hit journal low threshold */ +static int stat_journal_wait; /* Times blocked in jwait(). */ +static int stat_jwait_filepage; /* Times blocked in jwait() for filepage. */ +static int stat_jwait_freeblks; /* Times blocked in jwait() for freeblks. */ +static int stat_jwait_inode; /* Times blocked in jwait() for inodes. */ +static int stat_jwait_newblk; /* Times blocked in jwait() for newblks. */ +static int stat_cleanup_high_delay; /* Maximum cleanup delay (in ticks) */ +static int stat_cleanup_blkrequests; /* Number of block cleanup requests */ +static int stat_cleanup_inorequests; /* Number of inode cleanup requests */ +static int stat_cleanup_retries; /* Number of cleanups that needed to flush */ +static int stat_cleanup_failures; /* Number of cleanup requests that failed */ +static int stat_emptyjblocks; /* Number of potentially empty journal blocks */ + +SYSCTL_INT(_debug_softdep, OID_AUTO, max_softdeps, CTLFLAG_RW, + &max_softdeps, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, tickdelay, CTLFLAG_RW, + &tickdelay, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, flush_threads, CTLFLAG_RD, + &stat_flush_threads, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, worklist_push, CTLFLAG_RW, + &stat_worklist_push, 0,""); +SYSCTL_INT(_debug_softdep, OID_AUTO, blk_limit_push, CTLFLAG_RW, + &stat_blk_limit_push, 0,""); +SYSCTL_INT(_debug_softdep, OID_AUTO, ino_limit_push, CTLFLAG_RW, + &stat_ino_limit_push, 0,""); +SYSCTL_INT(_debug_softdep, OID_AUTO, blk_limit_hit, CTLFLAG_RW, + &stat_blk_limit_hit, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, ino_limit_hit, CTLFLAG_RW, + &stat_ino_limit_hit, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, sync_limit_hit, CTLFLAG_RW, + &stat_sync_limit_hit, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, indir_blk_ptrs, CTLFLAG_RW, + &stat_indir_blk_ptrs, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, inode_bitmap, CTLFLAG_RW, + &stat_inode_bitmap, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, direct_blk_ptrs, CTLFLAG_RW, + &stat_direct_blk_ptrs, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, dir_entry, CTLFLAG_RW, + &stat_dir_entry, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, jaddref_rollback, CTLFLAG_RW, + &stat_jaddref, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, jnewblk_rollback, CTLFLAG_RW, + &stat_jnewblk, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, journal_low, CTLFLAG_RW, + &stat_journal_low, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, journal_min, CTLFLAG_RW, + &stat_journal_min, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, journal_wait, CTLFLAG_RW, + &stat_journal_wait, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, jwait_filepage, CTLFLAG_RW, + &stat_jwait_filepage, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, jwait_freeblks, CTLFLAG_RW, + &stat_jwait_freeblks, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, jwait_inode, CTLFLAG_RW, + &stat_jwait_inode, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, jwait_newblk, CTLFLAG_RW, + &stat_jwait_newblk, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, cleanup_blkrequests, CTLFLAG_RW, + &stat_cleanup_blkrequests, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, cleanup_inorequests, CTLFLAG_RW, + &stat_cleanup_inorequests, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, cleanup_high_delay, CTLFLAG_RW, + &stat_cleanup_high_delay, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, cleanup_retries, CTLFLAG_RW, + &stat_cleanup_retries, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, cleanup_failures, CTLFLAG_RW, + &stat_cleanup_failures, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, flushcache, CTLFLAG_RW, + &softdep_flushcache, 0, ""); +SYSCTL_INT(_debug_softdep, OID_AUTO, emptyjblocks, CTLFLAG_RD, + &stat_emptyjblocks, 0, ""); + +SYSCTL_DECL(_vfs_ffs); + +/* Whether to recompute the summary at mount time */ +static int compute_summary_at_mount = 0; +SYSCTL_INT(_vfs_ffs, OID_AUTO, compute_summary_at_mount, CTLFLAG_RW, + &compute_summary_at_mount, 0, "Recompute summary at mount"); +static int print_threads = 0; +SYSCTL_INT(_debug_softdep, OID_AUTO, print_threads, CTLFLAG_RW, + &print_threads, 0, "Notify flusher thread start/stop"); + +/* List of all filesystems mounted with soft updates */ +static TAILQ_HEAD(, mount_softdeps) softdepmounts; + +/* + * This function cleans the worklist for a filesystem. + * Each filesystem running with soft dependencies gets its own + * thread to run in this function. The thread is started up in + * softdep_mount and shutdown in softdep_unmount. They show up + * as part of the kernel "bufdaemon" process whose process + * entry is available in bufdaemonproc. + */ +static int searchfailed; +extern struct proc *bufdaemonproc; +static void +softdep_flush(addr) + void *addr; +{ + struct mount *mp; + struct thread *td; + struct ufsmount *ump; + + td = curthread; + td->td_pflags |= TDP_NORUNNINGBUF; + mp = (struct mount *)addr; + ump = VFSTOUFS(mp); + atomic_add_int(&stat_flush_threads, 1); + ACQUIRE_LOCK(ump); + ump->softdep_flags &= ~FLUSH_STARTING; + wakeup(&ump->softdep_flushtd); + FREE_LOCK(ump); + if (print_threads) { + if (stat_flush_threads == 1) + printf("Running %s at pid %d\n", bufdaemonproc->p_comm, + bufdaemonproc->p_pid); + printf("Start thread %s\n", td->td_name); + } + for (;;) { + while (softdep_process_worklist(mp, 0) > 0 || + (MOUNTEDSUJ(mp) && + VFSTOUFS(mp)->softdep_jblocks->jb_suspended)) + kthread_suspend_check(); + ACQUIRE_LOCK(ump); + if ((ump->softdep_flags & (FLUSH_CLEANUP | FLUSH_EXIT)) == 0) + msleep(&ump->softdep_flushtd, LOCK_PTR(ump), PVM, + "sdflush", hz / 2); + ump->softdep_flags &= ~FLUSH_CLEANUP; + /* + * Check to see if we are done and need to exit. + */ + if ((ump->softdep_flags & FLUSH_EXIT) == 0) { + FREE_LOCK(ump); + continue; + } + ump->softdep_flags &= ~FLUSH_EXIT; + FREE_LOCK(ump); + wakeup(&ump->softdep_flags); + if (print_threads) + printf("Stop thread %s: searchfailed %d, did cleanups %d\n", td->td_name, searchfailed, ump->um_softdep->sd_cleanups); + atomic_subtract_int(&stat_flush_threads, 1); + kthread_exit(); + panic("kthread_exit failed\n"); + } +} + +static void +worklist_speedup(mp) + struct mount *mp; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + if ((ump->softdep_flags & (FLUSH_CLEANUP | FLUSH_EXIT)) == 0) + ump->softdep_flags |= FLUSH_CLEANUP; + wakeup(&ump->softdep_flushtd); +} + +static int +softdep_speedup(ump) + struct ufsmount *ump; +{ + struct ufsmount *altump; + struct mount_softdeps *sdp; + + LOCK_OWNED(ump); + worklist_speedup(ump->um_mountp); + bd_speedup(); + /* + * If we have global shortages, then we need other + * filesystems to help with the cleanup. Here we wakeup a + * flusher thread for a filesystem that is over its fair + * share of resources. + */ + if (req_clear_inodedeps || req_clear_remove) { + ACQUIRE_GBLLOCK(&lk); + TAILQ_FOREACH(sdp, &softdepmounts, sd_next) { + if ((altump = sdp->sd_ump) == ump) + continue; + if (((req_clear_inodedeps && + altump->softdep_curdeps[D_INODEDEP] > + max_softdeps / stat_flush_threads) || + (req_clear_remove && + altump->softdep_curdeps[D_DIRREM] > + (max_softdeps / 2) / stat_flush_threads)) && + TRY_ACQUIRE_LOCK(altump)) + break; + } + if (sdp == NULL) { + searchfailed++; + FREE_GBLLOCK(&lk); + } else { + /* + * Move to the end of the list so we pick a + * different one on out next try. + */ + TAILQ_REMOVE(&softdepmounts, sdp, sd_next); + TAILQ_INSERT_TAIL(&softdepmounts, sdp, sd_next); + FREE_GBLLOCK(&lk); + if ((altump->softdep_flags & + (FLUSH_CLEANUP | FLUSH_EXIT)) == 0) + altump->softdep_flags |= FLUSH_CLEANUP; + altump->um_softdep->sd_cleanups++; + wakeup(&altump->softdep_flushtd); + FREE_LOCK(altump); + } + } + return (speedup_syncer()); +} + +/* + * Add an item to the end of the work queue. + * This routine requires that the lock be held. + * This is the only routine that adds items to the list. + * The following routine is the only one that removes items + * and does so in order from first to last. + */ + +#define WK_HEAD 0x0001 /* Add to HEAD. */ +#define WK_NODELAY 0x0002 /* Process immediately. */ + +static void +add_to_worklist(wk, flags) + struct worklist *wk; + int flags; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(wk->wk_mp); + LOCK_OWNED(ump); + if (wk->wk_state & ONWORKLIST) + panic("add_to_worklist: %s(0x%X) already on list", + TYPENAME(wk->wk_type), wk->wk_state); + wk->wk_state |= ONWORKLIST; + if (ump->softdep_on_worklist == 0) { + LIST_INSERT_HEAD(&ump->softdep_workitem_pending, wk, wk_list); + ump->softdep_worklist_tail = wk; + } else if (flags & WK_HEAD) { + LIST_INSERT_HEAD(&ump->softdep_workitem_pending, wk, wk_list); + } else { + LIST_INSERT_AFTER(ump->softdep_worklist_tail, wk, wk_list); + ump->softdep_worklist_tail = wk; + } + ump->softdep_on_worklist += 1; + if (flags & WK_NODELAY) + worklist_speedup(wk->wk_mp); +} + +/* + * Remove the item to be processed. If we are removing the last + * item on the list, we need to recalculate the tail pointer. + */ +static void +remove_from_worklist(wk) + struct worklist *wk; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(wk->wk_mp); + if (ump->softdep_worklist_tail == wk) + ump->softdep_worklist_tail = + (struct worklist *)wk->wk_list.le_prev; + WORKLIST_REMOVE(wk); + ump->softdep_on_worklist -= 1; +} + +static void +wake_worklist(wk) + struct worklist *wk; +{ + if (wk->wk_state & IOWAITING) { + wk->wk_state &= ~IOWAITING; + wakeup(wk); + } +} + +static void +wait_worklist(wk, wmesg) + struct worklist *wk; + char *wmesg; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(wk->wk_mp); + wk->wk_state |= IOWAITING; + msleep(wk, LOCK_PTR(ump), PVM, wmesg, 0); +} + +/* + * Process that runs once per second to handle items in the background queue. + * + * Note that we ensure that everything is done in the order in which they + * appear in the queue. The code below depends on this property to ensure + * that blocks of a file are freed before the inode itself is freed. This + * ordering ensures that no new triples will be generated + * until all the old ones have been purged from the dependency lists. + */ +static int +softdep_process_worklist(mp, full) + struct mount *mp; + int full; +{ + int cnt, matchcnt; + struct ufsmount *ump; + long starttime; + + KASSERT(mp != NULL, ("softdep_process_worklist: NULL mp")); + if (MOUNTEDSOFTDEP(mp) == 0) + return (0); + matchcnt = 0; + ump = VFSTOUFS(mp); + ACQUIRE_LOCK(ump); + starttime = time_second; + softdep_process_journal(mp, NULL, full ? MNT_WAIT : 0); + check_clear_deps(mp); + while (ump->softdep_on_worklist > 0) { + if ((cnt = process_worklist_item(mp, 10, LK_NOWAIT)) == 0) + break; + else + matchcnt += cnt; + check_clear_deps(mp); + /* + * We do not generally want to stop for buffer space, but if + * we are really being a buffer hog, we will stop and wait. + */ + if (should_yield()) { + FREE_LOCK(ump); + kern_yield(PRI_USER); + bwillwrite(); + ACQUIRE_LOCK(ump); + } + /* + * Never allow processing to run for more than one + * second. This gives the syncer thread the opportunity + * to pause if appropriate. + */ + if (!full && starttime != time_second) + break; + } + if (full == 0) + journal_unsuspend(ump); + FREE_LOCK(ump); + return (matchcnt); +} + +/* + * Process all removes associated with a vnode if we are running out of + * journal space. Any other process which attempts to flush these will + * be unable as we have the vnodes locked. + */ +static void +process_removes(vp) + struct vnode *vp; +{ + struct inodedep *inodedep; + struct dirrem *dirrem; + struct ufsmount *ump; + struct mount *mp; + ino_t inum; + + mp = vp->v_mount; + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + inum = VTOI(vp)->i_number; + for (;;) { +top: + if (inodedep_lookup(mp, inum, 0, &inodedep) == 0) + return; + LIST_FOREACH(dirrem, &inodedep->id_dirremhd, dm_inonext) { + /* + * If another thread is trying to lock this vnode + * it will fail but we must wait for it to do so + * before we can proceed. + */ + if (dirrem->dm_state & INPROGRESS) { + wait_worklist(&dirrem->dm_list, "pwrwait"); + goto top; + } + if ((dirrem->dm_state & (COMPLETE | ONWORKLIST)) == + (COMPLETE | ONWORKLIST)) + break; + } + if (dirrem == NULL) + return; + remove_from_worklist(&dirrem->dm_list); + FREE_LOCK(ump); + if (vn_start_secondary_write(NULL, &mp, V_NOWAIT)) + panic("process_removes: suspended filesystem"); + handle_workitem_remove(dirrem, 0); + vn_finished_secondary_write(mp); + ACQUIRE_LOCK(ump); + } +} + +/* + * Process all truncations associated with a vnode if we are running out + * of journal space. This is called when the vnode lock is already held + * and no other process can clear the truncation. This function returns + * a value greater than zero if it did any work. + */ +static void +process_truncates(vp) + struct vnode *vp; +{ + struct inodedep *inodedep; + struct freeblks *freeblks; + struct ufsmount *ump; + struct mount *mp; + ino_t inum; + int cgwait; + + mp = vp->v_mount; + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + inum = VTOI(vp)->i_number; + for (;;) { + if (inodedep_lookup(mp, inum, 0, &inodedep) == 0) + return; + cgwait = 0; + TAILQ_FOREACH(freeblks, &inodedep->id_freeblklst, fb_next) { + /* Journal entries not yet written. */ + if (!LIST_EMPTY(&freeblks->fb_jblkdephd)) { + jwait(&LIST_FIRST( + &freeblks->fb_jblkdephd)->jb_list, + MNT_WAIT); + break; + } + /* Another thread is executing this item. */ + if (freeblks->fb_state & INPROGRESS) { + wait_worklist(&freeblks->fb_list, "ptrwait"); + break; + } + /* Freeblks is waiting on a inode write. */ + if ((freeblks->fb_state & COMPLETE) == 0) { + FREE_LOCK(ump); + ffs_update(vp, 1); + ACQUIRE_LOCK(ump); + break; + } + if ((freeblks->fb_state & (ALLCOMPLETE | ONWORKLIST)) == + (ALLCOMPLETE | ONWORKLIST)) { + remove_from_worklist(&freeblks->fb_list); + freeblks->fb_state |= INPROGRESS; + FREE_LOCK(ump); + if (vn_start_secondary_write(NULL, &mp, + V_NOWAIT)) + panic("process_truncates: " + "suspended filesystem"); + handle_workitem_freeblocks(freeblks, 0); + vn_finished_secondary_write(mp); + ACQUIRE_LOCK(ump); + break; + } + if (freeblks->fb_cgwait) + cgwait++; + } + if (cgwait) { + FREE_LOCK(ump); + sync_cgs(mp, MNT_WAIT); + ffs_sync_snap(mp, MNT_WAIT); + ACQUIRE_LOCK(ump); + continue; + } + if (freeblks == NULL) + break; + } + return; +} + +/* + * Process one item on the worklist. + */ +static int +process_worklist_item(mp, target, flags) + struct mount *mp; + int target; + int flags; +{ + struct worklist sentinel; + struct worklist *wk; + struct ufsmount *ump; + int matchcnt; + int error; + + KASSERT(mp != NULL, ("process_worklist_item: NULL mp")); + /* + * If we are being called because of a process doing a + * copy-on-write, then it is not safe to write as we may + * recurse into the copy-on-write routine. + */ + if (curthread->td_pflags & TDP_COWINPROGRESS) + return (-1); + PHOLD(curproc); /* Don't let the stack go away. */ + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + matchcnt = 0; + sentinel.wk_mp = NULL; + sentinel.wk_type = D_SENTINEL; + LIST_INSERT_HEAD(&ump->softdep_workitem_pending, &sentinel, wk_list); + for (wk = LIST_NEXT(&sentinel, wk_list); wk != NULL; + wk = LIST_NEXT(&sentinel, wk_list)) { + if (wk->wk_type == D_SENTINEL) { + LIST_REMOVE(&sentinel, wk_list); + LIST_INSERT_AFTER(wk, &sentinel, wk_list); + continue; + } + if (wk->wk_state & INPROGRESS) + panic("process_worklist_item: %p already in progress.", + wk); + wk->wk_state |= INPROGRESS; + remove_from_worklist(wk); + FREE_LOCK(ump); + if (vn_start_secondary_write(NULL, &mp, V_NOWAIT)) + panic("process_worklist_item: suspended filesystem"); + switch (wk->wk_type) { + case D_DIRREM: + /* removal of a directory entry */ + error = handle_workitem_remove(WK_DIRREM(wk), flags); + break; + + case D_FREEBLKS: + /* releasing blocks and/or fragments from a file */ + error = handle_workitem_freeblocks(WK_FREEBLKS(wk), + flags); + break; + + case D_FREEFRAG: + /* releasing a fragment when replaced as a file grows */ + handle_workitem_freefrag(WK_FREEFRAG(wk)); + error = 0; + break; + + case D_FREEFILE: + /* releasing an inode when its link count drops to 0 */ + handle_workitem_freefile(WK_FREEFILE(wk)); + error = 0; + break; + + default: + panic("%s_process_worklist: Unknown type %s", + "softdep", TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + vn_finished_secondary_write(mp); + ACQUIRE_LOCK(ump); + if (error == 0) { + if (++matchcnt == target) + break; + continue; + } + /* + * We have to retry the worklist item later. Wake up any + * waiters who may be able to complete it immediately and + * add the item back to the head so we don't try to execute + * it again. + */ + wk->wk_state &= ~INPROGRESS; + wake_worklist(wk); + add_to_worklist(wk, WK_HEAD); + } + /* Sentinal could've become the tail from remove_from_worklist. */ + if (ump->softdep_worklist_tail == &sentinel) + ump->softdep_worklist_tail = + (struct worklist *)sentinel.wk_list.le_prev; + LIST_REMOVE(&sentinel, wk_list); + PRELE(curproc); + return (matchcnt); +} + +/* + * Move dependencies from one buffer to another. + */ +int +softdep_move_dependencies(oldbp, newbp) + struct buf *oldbp; + struct buf *newbp; +{ + struct worklist *wk, *wktail; + struct ufsmount *ump; + int dirty; + + if ((wk = LIST_FIRST(&oldbp->b_dep)) == NULL) + return (0); + KASSERT(MOUNTEDSOFTDEP(wk->wk_mp) != 0, + ("softdep_move_dependencies called on non-softdep filesystem")); + dirty = 0; + wktail = NULL; + ump = VFSTOUFS(wk->wk_mp); + ACQUIRE_LOCK(ump); + while ((wk = LIST_FIRST(&oldbp->b_dep)) != NULL) { + LIST_REMOVE(wk, wk_list); + if (wk->wk_type == D_BMSAFEMAP && + bmsafemap_backgroundwrite(WK_BMSAFEMAP(wk), newbp)) + dirty = 1; + if (wktail == NULL) + LIST_INSERT_HEAD(&newbp->b_dep, wk, wk_list); + else + LIST_INSERT_AFTER(wktail, wk, wk_list); + wktail = wk; + } + FREE_LOCK(ump); + + return (dirty); +} + +/* + * Purge the work list of all items associated with a particular mount point. + */ +int +softdep_flushworklist(oldmnt, countp, td) + struct mount *oldmnt; + int *countp; + struct thread *td; +{ + struct vnode *devvp; + struct ufsmount *ump; + int count, error; + + /* + * Alternately flush the block device associated with the mount + * point and process any dependencies that the flushing + * creates. We continue until no more worklist dependencies + * are found. + */ + *countp = 0; + error = 0; + ump = VFSTOUFS(oldmnt); + devvp = ump->um_devvp; + while ((count = softdep_process_worklist(oldmnt, 1)) > 0) { + *countp += count; + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_FSYNC(devvp, MNT_WAIT, td); + VOP_UNLOCK(devvp, 0); + if (error != 0) + break; + } + return (error); +} + +#define SU_WAITIDLE_RETRIES 20 +static int +softdep_waitidle(struct mount *mp, int flags __unused) +{ + struct ufsmount *ump; + struct vnode *devvp; + struct thread *td; + int error, i; + + ump = VFSTOUFS(mp); + devvp = ump->um_devvp; + td = curthread; + error = 0; + ACQUIRE_LOCK(ump); + for (i = 0; i < SU_WAITIDLE_RETRIES && ump->softdep_deps != 0; i++) { + ump->softdep_req = 1; + KASSERT((flags & FORCECLOSE) == 0 || + ump->softdep_on_worklist == 0, + ("softdep_waitidle: work added after flush")); + msleep(&ump->softdep_deps, LOCK_PTR(ump), PVM | PDROP, + "softdeps", 10 * hz); + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_FSYNC(devvp, MNT_WAIT, td); + VOP_UNLOCK(devvp, 0); + ACQUIRE_LOCK(ump); + if (error != 0) + break; + } + ump->softdep_req = 0; + if (i == SU_WAITIDLE_RETRIES && error == 0 && ump->softdep_deps != 0) { + error = EBUSY; + printf("softdep_waitidle: Failed to flush worklist for %p\n", + mp); + } + FREE_LOCK(ump); + return (error); +} + +/* + * Flush all vnodes and worklist items associated with a specified mount point. + */ +int +softdep_flushfiles(oldmnt, flags, td) + struct mount *oldmnt; + int flags; + struct thread *td; +{ +#ifdef QUOTA + struct ufsmount *ump; + int i; +#endif + int error, early, depcount, loopcnt, retry_flush_count, retry; + int morework; + + KASSERT(MOUNTEDSOFTDEP(oldmnt) != 0, + ("softdep_flushfiles called on non-softdep filesystem")); + loopcnt = 10; + retry_flush_count = 3; +retry_flush: + error = 0; + + /* + * Alternately flush the vnodes associated with the mount + * point and process any dependencies that the flushing + * creates. In theory, this loop can happen at most twice, + * but we give it a few extra just to be sure. + */ + for (; loopcnt > 0; loopcnt--) { + /* + * Do another flush in case any vnodes were brought in + * as part of the cleanup operations. + */ + early = retry_flush_count == 1 || (oldmnt->mnt_kern_flag & + MNTK_UNMOUNT) == 0 ? 0 : EARLYFLUSH; + if ((error = ffs_flushfiles(oldmnt, flags | early, td)) != 0) + break; + if ((error = softdep_flushworklist(oldmnt, &depcount, td)) != 0 || + depcount == 0) + break; + } + /* + * If we are unmounting then it is an error to fail. If we + * are simply trying to downgrade to read-only, then filesystem + * activity can keep us busy forever, so we just fail with EBUSY. + */ + if (loopcnt == 0) { + if (oldmnt->mnt_kern_flag & MNTK_UNMOUNT) + panic("softdep_flushfiles: looping"); + error = EBUSY; + } + if (!error) + error = softdep_waitidle(oldmnt, flags); + if (!error) { + if (oldmnt->mnt_kern_flag & MNTK_UNMOUNT) { + retry = 0; + MNT_ILOCK(oldmnt); + KASSERT((oldmnt->mnt_kern_flag & MNTK_NOINSMNTQ) != 0, + ("softdep_flushfiles: !MNTK_NOINSMNTQ")); + morework = oldmnt->mnt_nvnodelistsize > 0; +#ifdef QUOTA + ump = VFSTOUFS(oldmnt); + UFS_LOCK(ump); + for (i = 0; i < MAXQUOTAS; i++) { + if (ump->um_quotas[i] != NULLVP) + morework = 1; + } + UFS_UNLOCK(ump); +#endif + if (morework) { + if (--retry_flush_count > 0) { + retry = 1; + loopcnt = 3; + } else + error = EBUSY; + } + MNT_IUNLOCK(oldmnt); + if (retry) + goto retry_flush; + } + } + return (error); +} + +/* + * Structure hashing. + * + * There are four types of structures that can be looked up: + * 1) pagedep structures identified by mount point, inode number, + * and logical block. + * 2) inodedep structures identified by mount point and inode number. + * 3) newblk structures identified by mount point and + * physical block number. + * 4) bmsafemap structures identified by mount point and + * cylinder group number. + * + * The "pagedep" and "inodedep" dependency structures are hashed + * separately from the file blocks and inodes to which they correspond. + * This separation helps when the in-memory copy of an inode or + * file block must be replaced. It also obviates the need to access + * an inode or file page when simply updating (or de-allocating) + * dependency structures. Lookup of newblk structures is needed to + * find newly allocated blocks when trying to associate them with + * their allocdirect or allocindir structure. + * + * The lookup routines optionally create and hash a new instance when + * an existing entry is not found. The bmsafemap lookup routine always + * allocates a new structure if an existing one is not found. + */ +#define DEPALLOC 0x0001 /* allocate structure if lookup fails */ + +/* + * Structures and routines associated with pagedep caching. + */ +#define PAGEDEP_HASH(ump, inum, lbn) \ + (&(ump)->pagedep_hashtbl[((inum) + (lbn)) & (ump)->pagedep_hash_size]) + +static int +pagedep_find(pagedephd, ino, lbn, pagedeppp) + struct pagedep_hashhead *pagedephd; + ino_t ino; + ufs_lbn_t lbn; + struct pagedep **pagedeppp; +{ + struct pagedep *pagedep; + + LIST_FOREACH(pagedep, pagedephd, pd_hash) { + if (ino == pagedep->pd_ino && lbn == pagedep->pd_lbn) { + *pagedeppp = pagedep; + return (1); + } + } + *pagedeppp = NULL; + return (0); +} +/* + * Look up a pagedep. Return 1 if found, 0 otherwise. + * If not found, allocate if DEPALLOC flag is passed. + * Found or allocated entry is returned in pagedeppp. + * This routine must be called with splbio interrupts blocked. + */ +static int +pagedep_lookup(mp, bp, ino, lbn, flags, pagedeppp) + struct mount *mp; + struct buf *bp; + ino_t ino; + ufs_lbn_t lbn; + int flags; + struct pagedep **pagedeppp; +{ + struct pagedep *pagedep; + struct pagedep_hashhead *pagedephd; + struct worklist *wk; + struct ufsmount *ump; + int ret; + int i; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + if (bp) { + LIST_FOREACH(wk, &bp->b_dep, wk_list) { + if (wk->wk_type == D_PAGEDEP) { + *pagedeppp = WK_PAGEDEP(wk); + return (1); + } + } + } + pagedephd = PAGEDEP_HASH(ump, ino, lbn); + ret = pagedep_find(pagedephd, ino, lbn, pagedeppp); + if (ret) { + if (((*pagedeppp)->pd_state & ONWORKLIST) == 0 && bp) + WORKLIST_INSERT(&bp->b_dep, &(*pagedeppp)->pd_list); + return (1); + } + if ((flags & DEPALLOC) == 0) + return (0); + FREE_LOCK(ump); + pagedep = malloc(sizeof(struct pagedep), + M_PAGEDEP, M_SOFTDEP_FLAGS|M_ZERO); + workitem_alloc(&pagedep->pd_list, D_PAGEDEP, mp); + ACQUIRE_LOCK(ump); + ret = pagedep_find(pagedephd, ino, lbn, pagedeppp); + if (*pagedeppp) { + /* + * This should never happen since we only create pagedeps + * with the vnode lock held. Could be an assert. + */ + WORKITEM_FREE(pagedep, D_PAGEDEP); + return (ret); + } + pagedep->pd_ino = ino; + pagedep->pd_lbn = lbn; + LIST_INIT(&pagedep->pd_dirremhd); + LIST_INIT(&pagedep->pd_pendinghd); + for (i = 0; i < DAHASHSZ; i++) + LIST_INIT(&pagedep->pd_diraddhd[i]); + LIST_INSERT_HEAD(pagedephd, pagedep, pd_hash); + WORKLIST_INSERT(&bp->b_dep, &pagedep->pd_list); + *pagedeppp = pagedep; + return (0); +} + +/* + * Structures and routines associated with inodedep caching. + */ +#define INODEDEP_HASH(ump, inum) \ + (&(ump)->inodedep_hashtbl[(inum) & (ump)->inodedep_hash_size]) + +static int +inodedep_find(inodedephd, inum, inodedeppp) + struct inodedep_hashhead *inodedephd; + ino_t inum; + struct inodedep **inodedeppp; +{ + struct inodedep *inodedep; + + LIST_FOREACH(inodedep, inodedephd, id_hash) + if (inum == inodedep->id_ino) + break; + if (inodedep) { + *inodedeppp = inodedep; + return (1); + } + *inodedeppp = NULL; + + return (0); +} +/* + * Look up an inodedep. Return 1 if found, 0 if not found. + * If not found, allocate if DEPALLOC flag is passed. + * Found or allocated entry is returned in inodedeppp. + * This routine must be called with splbio interrupts blocked. + */ +static int +inodedep_lookup(mp, inum, flags, inodedeppp) + struct mount *mp; + ino_t inum; + int flags; + struct inodedep **inodedeppp; +{ + struct inodedep *inodedep; + struct inodedep_hashhead *inodedephd; + struct ufsmount *ump; + struct fs *fs; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + fs = ump->um_fs; + inodedephd = INODEDEP_HASH(ump, inum); + + if (inodedep_find(inodedephd, inum, inodedeppp)) + return (1); + if ((flags & DEPALLOC) == 0) + return (0); + /* + * If the system is over its limit and our filesystem is + * responsible for more than our share of that usage and + * we are not in a rush, request some inodedep cleanup. + */ + if (softdep_excess_items(ump, D_INODEDEP)) + schedule_cleanup(mp); + else + FREE_LOCK(ump); + inodedep = malloc(sizeof(struct inodedep), + M_INODEDEP, M_SOFTDEP_FLAGS); + workitem_alloc(&inodedep->id_list, D_INODEDEP, mp); + ACQUIRE_LOCK(ump); + if (inodedep_find(inodedephd, inum, inodedeppp)) { + WORKITEM_FREE(inodedep, D_INODEDEP); + return (1); + } + inodedep->id_fs = fs; + inodedep->id_ino = inum; + inodedep->id_state = ALLCOMPLETE; + inodedep->id_nlinkdelta = 0; + inodedep->id_savedino1 = NULL; + inodedep->id_savedsize = -1; + inodedep->id_savedextsize = -1; + inodedep->id_savednlink = -1; + inodedep->id_bmsafemap = NULL; + inodedep->id_mkdiradd = NULL; + LIST_INIT(&inodedep->id_dirremhd); + LIST_INIT(&inodedep->id_pendinghd); + LIST_INIT(&inodedep->id_inowait); + LIST_INIT(&inodedep->id_bufwait); + TAILQ_INIT(&inodedep->id_inoreflst); + TAILQ_INIT(&inodedep->id_inoupdt); + TAILQ_INIT(&inodedep->id_newinoupdt); + TAILQ_INIT(&inodedep->id_extupdt); + TAILQ_INIT(&inodedep->id_newextupdt); + TAILQ_INIT(&inodedep->id_freeblklst); + LIST_INSERT_HEAD(inodedephd, inodedep, id_hash); + *inodedeppp = inodedep; + return (0); +} + +/* + * Structures and routines associated with newblk caching. + */ +#define NEWBLK_HASH(ump, inum) \ + (&(ump)->newblk_hashtbl[(inum) & (ump)->newblk_hash_size]) + +static int +newblk_find(newblkhd, newblkno, flags, newblkpp) + struct newblk_hashhead *newblkhd; + ufs2_daddr_t newblkno; + int flags; + struct newblk **newblkpp; +{ + struct newblk *newblk; + + LIST_FOREACH(newblk, newblkhd, nb_hash) { + if (newblkno != newblk->nb_newblkno) + continue; + /* + * If we're creating a new dependency don't match those that + * have already been converted to allocdirects. This is for + * a frag extend. + */ + if ((flags & DEPALLOC) && newblk->nb_list.wk_type != D_NEWBLK) + continue; + break; + } + if (newblk) { + *newblkpp = newblk; + return (1); + } + *newblkpp = NULL; + return (0); +} + +/* + * Look up a newblk. Return 1 if found, 0 if not found. + * If not found, allocate if DEPALLOC flag is passed. + * Found or allocated entry is returned in newblkpp. + */ +static int +newblk_lookup(mp, newblkno, flags, newblkpp) + struct mount *mp; + ufs2_daddr_t newblkno; + int flags; + struct newblk **newblkpp; +{ + struct newblk *newblk; + struct newblk_hashhead *newblkhd; + struct ufsmount *ump; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + newblkhd = NEWBLK_HASH(ump, newblkno); + if (newblk_find(newblkhd, newblkno, flags, newblkpp)) + return (1); + if ((flags & DEPALLOC) == 0) + return (0); + if (softdep_excess_items(ump, D_NEWBLK) || + softdep_excess_items(ump, D_ALLOCDIRECT) || + softdep_excess_items(ump, D_ALLOCINDIR)) + schedule_cleanup(mp); + else + FREE_LOCK(ump); + newblk = malloc(sizeof(union allblk), M_NEWBLK, + M_SOFTDEP_FLAGS | M_ZERO); + workitem_alloc(&newblk->nb_list, D_NEWBLK, mp); + ACQUIRE_LOCK(ump); + if (newblk_find(newblkhd, newblkno, flags, newblkpp)) { + WORKITEM_FREE(newblk, D_NEWBLK); + return (1); + } + newblk->nb_freefrag = NULL; + LIST_INIT(&newblk->nb_indirdeps); + LIST_INIT(&newblk->nb_newdirblk); + LIST_INIT(&newblk->nb_jwork); + newblk->nb_state = ATTACHED; + newblk->nb_newblkno = newblkno; + LIST_INSERT_HEAD(newblkhd, newblk, nb_hash); + *newblkpp = newblk; + return (0); +} + +/* + * Structures and routines associated with freed indirect block caching. + */ +#define INDIR_HASH(ump, blkno) \ + (&(ump)->indir_hashtbl[(blkno) & (ump)->indir_hash_size]) + +/* + * Lookup an indirect block in the indir hash table. The freework is + * removed and potentially freed. The caller must do a blocking journal + * write before writing to the blkno. + */ +static int +indirblk_lookup(mp, blkno) + struct mount *mp; + ufs2_daddr_t blkno; +{ + struct freework *freework; + struct indir_hashhead *wkhd; + struct ufsmount *ump; + + ump = VFSTOUFS(mp); + wkhd = INDIR_HASH(ump, blkno); + TAILQ_FOREACH(freework, wkhd, fw_next) { + if (freework->fw_blkno != blkno) + continue; + indirblk_remove(freework); + return (1); + } + return (0); +} + +/* + * Insert an indirect block represented by freework into the indirblk + * hash table so that it may prevent the block from being re-used prior + * to the journal being written. + */ +static void +indirblk_insert(freework) + struct freework *freework; +{ + struct jblocks *jblocks; + struct jseg *jseg; + struct ufsmount *ump; + + ump = VFSTOUFS(freework->fw_list.wk_mp); + jblocks = ump->softdep_jblocks; + jseg = TAILQ_LAST(&jblocks->jb_segs, jseglst); + if (jseg == NULL) + return; + + LIST_INSERT_HEAD(&jseg->js_indirs, freework, fw_segs); + TAILQ_INSERT_HEAD(INDIR_HASH(ump, freework->fw_blkno), freework, + fw_next); + freework->fw_state &= ~DEPCOMPLETE; +} + +static void +indirblk_remove(freework) + struct freework *freework; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(freework->fw_list.wk_mp); + LIST_REMOVE(freework, fw_segs); + TAILQ_REMOVE(INDIR_HASH(ump, freework->fw_blkno), freework, fw_next); + freework->fw_state |= DEPCOMPLETE; + if ((freework->fw_state & ALLCOMPLETE) == ALLCOMPLETE) + WORKITEM_FREE(freework, D_FREEWORK); +} + +/* + * Executed during filesystem system initialization before + * mounting any filesystems. + */ +void +softdep_initialize() +{ + + TAILQ_INIT(&softdepmounts); +#ifdef __LP64__ + max_softdeps = desiredvnodes * 4; +#else + max_softdeps = desiredvnodes * 2; +#endif + + /* initialise bioops hack */ + bioops.io_start = softdep_disk_io_initiation; + bioops.io_complete = softdep_disk_write_complete; + bioops.io_deallocate = softdep_deallocate_dependencies; + bioops.io_countdeps = softdep_count_dependencies; + softdep_ast_cleanup = softdep_ast_cleanup_proc; + + /* Initialize the callout with an mtx. */ + callout_init_mtx(&softdep_callout, &lk, 0); +} + +/* + * Executed after all filesystems have been unmounted during + * filesystem module unload. + */ +void +softdep_uninitialize() +{ + + /* clear bioops hack */ + bioops.io_start = NULL; + bioops.io_complete = NULL; + bioops.io_deallocate = NULL; + bioops.io_countdeps = NULL; + softdep_ast_cleanup = NULL; + + callout_drain(&softdep_callout); +} + +/* + * Called at mount time to notify the dependency code that a + * filesystem wishes to use it. + */ +int +softdep_mount(devvp, mp, fs, cred) + struct vnode *devvp; + struct mount *mp; + struct fs *fs; + struct ucred *cred; +{ + struct csum_total cstotal; + struct mount_softdeps *sdp; + struct ufsmount *ump; + struct cg *cgp; + struct buf *bp; + int i, error, cyl; + + sdp = malloc(sizeof(struct mount_softdeps), M_MOUNTDATA, + M_WAITOK | M_ZERO); + MNT_ILOCK(mp); + mp->mnt_flag = (mp->mnt_flag & ~MNT_ASYNC) | MNT_SOFTDEP; + if ((mp->mnt_kern_flag & MNTK_SOFTDEP) == 0) { + mp->mnt_kern_flag = (mp->mnt_kern_flag & ~MNTK_ASYNC) | + MNTK_SOFTDEP | MNTK_NOASYNC; + } + ump = VFSTOUFS(mp); + ump->um_softdep = sdp; + MNT_IUNLOCK(mp); + rw_init(LOCK_PTR(ump), "Per-Filesystem Softdep Lock"); + sdp->sd_ump = ump; + LIST_INIT(&ump->softdep_workitem_pending); + LIST_INIT(&ump->softdep_journal_pending); + TAILQ_INIT(&ump->softdep_unlinked); + LIST_INIT(&ump->softdep_dirtycg); + ump->softdep_worklist_tail = NULL; + ump->softdep_on_worklist = 0; + ump->softdep_deps = 0; + LIST_INIT(&ump->softdep_mkdirlisthd); + ump->pagedep_hashtbl = hashinit(desiredvnodes / 5, M_PAGEDEP, + &ump->pagedep_hash_size); + ump->pagedep_nextclean = 0; + ump->inodedep_hashtbl = hashinit(desiredvnodes, M_INODEDEP, + &ump->inodedep_hash_size); + ump->inodedep_nextclean = 0; + ump->newblk_hashtbl = hashinit(max_softdeps / 2, M_NEWBLK, + &ump->newblk_hash_size); + ump->bmsafemap_hashtbl = hashinit(1024, M_BMSAFEMAP, + &ump->bmsafemap_hash_size); + i = 1 << (ffs(desiredvnodes / 10) - 1); + ump->indir_hashtbl = malloc(i * sizeof(struct indir_hashhead), + M_FREEWORK, M_WAITOK); + ump->indir_hash_size = i - 1; + for (i = 0; i <= ump->indir_hash_size; i++) + TAILQ_INIT(&ump->indir_hashtbl[i]); + ACQUIRE_GBLLOCK(&lk); + TAILQ_INSERT_TAIL(&softdepmounts, sdp, sd_next); + FREE_GBLLOCK(&lk); + if ((fs->fs_flags & FS_SUJ) && + (error = journal_mount(mp, fs, cred)) != 0) { + printf("Failed to start journal: %d\n", error); + softdep_unmount(mp); + return (error); + } + /* + * Start our flushing thread in the bufdaemon process. + */ + ACQUIRE_LOCK(ump); + ump->softdep_flags |= FLUSH_STARTING; + FREE_LOCK(ump); + kproc_kthread_add(&softdep_flush, mp, &bufdaemonproc, + &ump->softdep_flushtd, 0, 0, "softdepflush", "%s worker", + mp->mnt_stat.f_mntonname); + ACQUIRE_LOCK(ump); + while ((ump->softdep_flags & FLUSH_STARTING) != 0) { + msleep(&ump->softdep_flushtd, LOCK_PTR(ump), PVM, "sdstart", + hz / 2); + } + FREE_LOCK(ump); + /* + * When doing soft updates, the counters in the + * superblock may have gotten out of sync. Recomputation + * can take a long time and can be deferred for background + * fsck. However, the old behavior of scanning the cylinder + * groups and recalculating them at mount time is available + * by setting vfs.ffs.compute_summary_at_mount to one. + */ + if (compute_summary_at_mount == 0 || fs->fs_clean != 0) + return (0); + bzero(&cstotal, sizeof cstotal); + for (cyl = 0; cyl < fs->fs_ncg; cyl++) { + if ((error = bread(devvp, fsbtodb(fs, cgtod(fs, cyl)), + fs->fs_cgsize, cred, &bp)) != 0) { + brelse(bp); + softdep_unmount(mp); + return (error); + } + cgp = (struct cg *)bp->b_data; + cstotal.cs_nffree += cgp->cg_cs.cs_nffree; + cstotal.cs_nbfree += cgp->cg_cs.cs_nbfree; + cstotal.cs_nifree += cgp->cg_cs.cs_nifree; + cstotal.cs_ndir += cgp->cg_cs.cs_ndir; + fs->fs_cs(fs, cyl) = cgp->cg_cs; + brelse(bp); + } +#ifdef DEBUG + if (bcmp(&cstotal, &fs->fs_cstotal, sizeof cstotal)) + printf("%s: superblock summary recomputed\n", fs->fs_fsmnt); +#endif + bcopy(&cstotal, &fs->fs_cstotal, sizeof cstotal); + return (0); +} + +void +softdep_unmount(mp) + struct mount *mp; +{ + struct ufsmount *ump; +#ifdef INVARIANTS + int i; +#endif + + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_unmount called on non-softdep filesystem")); + ump = VFSTOUFS(mp); + MNT_ILOCK(mp); + mp->mnt_flag &= ~MNT_SOFTDEP; + if (MOUNTEDSUJ(mp) == 0) { + MNT_IUNLOCK(mp); + } else { + mp->mnt_flag &= ~MNT_SUJ; + MNT_IUNLOCK(mp); + journal_unmount(ump); + } + /* + * Shut down our flushing thread. Check for NULL is if + * softdep_mount errors out before the thread has been created. + */ + if (ump->softdep_flushtd != NULL) { + ACQUIRE_LOCK(ump); + ump->softdep_flags |= FLUSH_EXIT; + wakeup(&ump->softdep_flushtd); + msleep(&ump->softdep_flags, LOCK_PTR(ump), PVM | PDROP, + "sdwait", 0); + KASSERT((ump->softdep_flags & FLUSH_EXIT) == 0, + ("Thread shutdown failed")); + } + /* + * Free up our resources. + */ + ACQUIRE_GBLLOCK(&lk); + TAILQ_REMOVE(&softdepmounts, ump->um_softdep, sd_next); + FREE_GBLLOCK(&lk); + rw_destroy(LOCK_PTR(ump)); + hashdestroy(ump->pagedep_hashtbl, M_PAGEDEP, ump->pagedep_hash_size); + hashdestroy(ump->inodedep_hashtbl, M_INODEDEP, ump->inodedep_hash_size); + hashdestroy(ump->newblk_hashtbl, M_NEWBLK, ump->newblk_hash_size); + hashdestroy(ump->bmsafemap_hashtbl, M_BMSAFEMAP, + ump->bmsafemap_hash_size); + free(ump->indir_hashtbl, M_FREEWORK); +#ifdef INVARIANTS + for (i = 0; i <= D_LAST; i++) + KASSERT(ump->softdep_curdeps[i] == 0, + ("Unmount %s: Dep type %s != 0 (%ld)", ump->um_fs->fs_fsmnt, + TYPENAME(i), ump->softdep_curdeps[i])); +#endif + free(ump->um_softdep, M_MOUNTDATA); +} + +static struct jblocks * +jblocks_create(void) +{ + struct jblocks *jblocks; + + jblocks = malloc(sizeof(*jblocks), M_JBLOCKS, M_WAITOK | M_ZERO); + TAILQ_INIT(&jblocks->jb_segs); + jblocks->jb_avail = 10; + jblocks->jb_extent = malloc(sizeof(struct jextent) * jblocks->jb_avail, + M_JBLOCKS, M_WAITOK | M_ZERO); + + return (jblocks); +} + +static ufs2_daddr_t +jblocks_alloc(jblocks, bytes, actual) + struct jblocks *jblocks; + int bytes; + int *actual; +{ + ufs2_daddr_t daddr; + struct jextent *jext; + int freecnt; + int blocks; + + blocks = bytes / DEV_BSIZE; + jext = &jblocks->jb_extent[jblocks->jb_head]; + freecnt = jext->je_blocks - jblocks->jb_off; + if (freecnt == 0) { + jblocks->jb_off = 0; + if (++jblocks->jb_head > jblocks->jb_used) + jblocks->jb_head = 0; + jext = &jblocks->jb_extent[jblocks->jb_head]; + freecnt = jext->je_blocks; + } + if (freecnt > blocks) + freecnt = blocks; + *actual = freecnt * DEV_BSIZE; + daddr = jext->je_daddr + jblocks->jb_off; + jblocks->jb_off += freecnt; + jblocks->jb_free -= freecnt; + + return (daddr); +} + +static void +jblocks_free(jblocks, mp, bytes) + struct jblocks *jblocks; + struct mount *mp; + int bytes; +{ + + LOCK_OWNED(VFSTOUFS(mp)); + jblocks->jb_free += bytes / DEV_BSIZE; + if (jblocks->jb_suspended) + worklist_speedup(mp); + wakeup(jblocks); +} + +static void +jblocks_destroy(jblocks) + struct jblocks *jblocks; +{ + + if (jblocks->jb_extent) + free(jblocks->jb_extent, M_JBLOCKS); + free(jblocks, M_JBLOCKS); +} + +static void +jblocks_add(jblocks, daddr, blocks) + struct jblocks *jblocks; + ufs2_daddr_t daddr; + int blocks; +{ + struct jextent *jext; + + jblocks->jb_blocks += blocks; + jblocks->jb_free += blocks; + jext = &jblocks->jb_extent[jblocks->jb_used]; + /* Adding the first block. */ + if (jext->je_daddr == 0) { + jext->je_daddr = daddr; + jext->je_blocks = blocks; + return; + } + /* Extending the last extent. */ + if (jext->je_daddr + jext->je_blocks == daddr) { + jext->je_blocks += blocks; + return; + } + /* Adding a new extent. */ + if (++jblocks->jb_used == jblocks->jb_avail) { + jblocks->jb_avail *= 2; + jext = malloc(sizeof(struct jextent) * jblocks->jb_avail, + M_JBLOCKS, M_WAITOK | M_ZERO); + memcpy(jext, jblocks->jb_extent, + sizeof(struct jextent) * jblocks->jb_used); + free(jblocks->jb_extent, M_JBLOCKS); + jblocks->jb_extent = jext; + } + jext = &jblocks->jb_extent[jblocks->jb_used]; + jext->je_daddr = daddr; + jext->je_blocks = blocks; + return; +} + +int +softdep_journal_lookup(mp, vpp) + struct mount *mp; + struct vnode **vpp; +{ + struct componentname cnp; + struct vnode *dvp; + ino_t sujournal; + int error; + + error = VFS_VGET(mp, ROOTINO, LK_EXCLUSIVE, &dvp); + if (error) + return (error); + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = LOOKUP; + cnp.cn_flags = ISLASTCN; + cnp.cn_thread = curthread; + cnp.cn_cred = curthread->td_ucred; + cnp.cn_pnbuf = SUJ_FILE; + cnp.cn_nameptr = SUJ_FILE; + cnp.cn_namelen = strlen(SUJ_FILE); + error = ufs_lookup_ino(dvp, NULL, &cnp, &sujournal); + vput(dvp); + if (error != 0) + return (error); + error = VFS_VGET(mp, sujournal, LK_EXCLUSIVE, vpp); + return (error); +} + +/* + * Open and verify the journal file. + */ +static int +journal_mount(mp, fs, cred) + struct mount *mp; + struct fs *fs; + struct ucred *cred; +{ + struct jblocks *jblocks; + struct ufsmount *ump; + struct vnode *vp; + struct inode *ip; + ufs2_daddr_t blkno; + int bcount; + int error; + int i; + + ump = VFSTOUFS(mp); + ump->softdep_journal_tail = NULL; + ump->softdep_on_journal = 0; + ump->softdep_accdeps = 0; + ump->softdep_req = 0; + ump->softdep_jblocks = NULL; + error = softdep_journal_lookup(mp, &vp); + if (error != 0) { + printf("Failed to find journal. Use tunefs to create one\n"); + return (error); + } + ip = VTOI(vp); + if (ip->i_size < SUJ_MIN) { + error = ENOSPC; + goto out; + } + bcount = lblkno(fs, ip->i_size); /* Only use whole blocks. */ + jblocks = jblocks_create(); + for (i = 0; i < bcount; i++) { + error = ufs_bmaparray(vp, i, &blkno, NULL, NULL, NULL); + if (error) + break; + jblocks_add(jblocks, blkno, fsbtodb(fs, fs->fs_frag)); + } + if (error) { + jblocks_destroy(jblocks); + goto out; + } + jblocks->jb_low = jblocks->jb_free / 3; /* Reserve 33%. */ + jblocks->jb_min = jblocks->jb_free / 10; /* Suspend at 10%. */ + ump->softdep_jblocks = jblocks; +out: + if (error == 0) { + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_SUJ; + mp->mnt_flag &= ~MNT_SOFTDEP; + MNT_IUNLOCK(mp); + /* + * Only validate the journal contents if the + * filesystem is clean, otherwise we write the logs + * but they'll never be used. If the filesystem was + * still dirty when we mounted it the journal is + * invalid and a new journal can only be valid if it + * starts from a clean mount. + */ + if (fs->fs_clean) { + DIP_SET(ip, i_modrev, fs->fs_mtime); + ip->i_flags |= IN_MODIFIED; + ffs_update(vp, 1); + } + } + vput(vp); + return (error); +} + +static void +journal_unmount(ump) + struct ufsmount *ump; +{ + + if (ump->softdep_jblocks) + jblocks_destroy(ump->softdep_jblocks); + ump->softdep_jblocks = NULL; +} + +/* + * Called when a journal record is ready to be written. Space is allocated + * and the journal entry is created when the journal is flushed to stable + * store. + */ +static void +add_to_journal(wk) + struct worklist *wk; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(wk->wk_mp); + LOCK_OWNED(ump); + if (wk->wk_state & ONWORKLIST) + panic("add_to_journal: %s(0x%X) already on list", + TYPENAME(wk->wk_type), wk->wk_state); + wk->wk_state |= ONWORKLIST | DEPCOMPLETE; + if (LIST_EMPTY(&ump->softdep_journal_pending)) { + ump->softdep_jblocks->jb_age = ticks; + LIST_INSERT_HEAD(&ump->softdep_journal_pending, wk, wk_list); + } else + LIST_INSERT_AFTER(ump->softdep_journal_tail, wk, wk_list); + ump->softdep_journal_tail = wk; + ump->softdep_on_journal += 1; +} + +/* + * Remove an arbitrary item for the journal worklist maintain the tail + * pointer. This happens when a new operation obviates the need to + * journal an old operation. + */ +static void +remove_from_journal(wk) + struct worklist *wk; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(wk->wk_mp); + LOCK_OWNED(ump); +#ifdef SUJ_DEBUG + { + struct worklist *wkn; + + LIST_FOREACH(wkn, &ump->softdep_journal_pending, wk_list) + if (wkn == wk) + break; + if (wkn == NULL) + panic("remove_from_journal: %p is not in journal", wk); + } +#endif + /* + * We emulate a TAILQ to save space in most structures which do not + * require TAILQ semantics. Here we must update the tail position + * when removing the tail which is not the final entry. This works + * only if the worklist linkage are at the beginning of the structure. + */ + if (ump->softdep_journal_tail == wk) + ump->softdep_journal_tail = + (struct worklist *)wk->wk_list.le_prev; + WORKLIST_REMOVE(wk); + ump->softdep_on_journal -= 1; +} + +/* + * Check for journal space as well as dependency limits so the prelink + * code can throttle both journaled and non-journaled filesystems. + * Threshold is 0 for low and 1 for min. + */ +static int +journal_space(ump, thresh) + struct ufsmount *ump; + int thresh; +{ + struct jblocks *jblocks; + int limit, avail; + + jblocks = ump->softdep_jblocks; + if (jblocks == NULL) + return (1); + /* + * We use a tighter restriction here to prevent request_cleanup() + * running in threads from running into locks we currently hold. + * We have to be over the limit and our filesystem has to be + * responsible for more than our share of that usage. + */ + limit = (max_softdeps / 10) * 9; + if (dep_current[D_INODEDEP] > limit && + ump->softdep_curdeps[D_INODEDEP] > limit / stat_flush_threads) + return (0); + if (thresh) + thresh = jblocks->jb_min; + else + thresh = jblocks->jb_low; + avail = (ump->softdep_on_journal * JREC_SIZE) / DEV_BSIZE; + avail = jblocks->jb_free - avail; + + return (avail > thresh); +} + +static void +journal_suspend(ump) + struct ufsmount *ump; +{ + struct jblocks *jblocks; + struct mount *mp; + + mp = UFSTOVFS(ump); + jblocks = ump->softdep_jblocks; + MNT_ILOCK(mp); + if ((mp->mnt_kern_flag & MNTK_SUSPEND) == 0) { + stat_journal_min++; + mp->mnt_kern_flag |= MNTK_SUSPEND; + mp->mnt_susp_owner = ump->softdep_flushtd; + } + jblocks->jb_suspended = 1; + MNT_IUNLOCK(mp); +} + +static int +journal_unsuspend(struct ufsmount *ump) +{ + struct jblocks *jblocks; + struct mount *mp; + + mp = UFSTOVFS(ump); + jblocks = ump->softdep_jblocks; + + if (jblocks != NULL && jblocks->jb_suspended && + journal_space(ump, jblocks->jb_min)) { + jblocks->jb_suspended = 0; + FREE_LOCK(ump); + mp->mnt_susp_owner = curthread; + vfs_write_resume(mp, 0); + ACQUIRE_LOCK(ump); + return (1); + } + return (0); +} + +/* + * Called before any allocation function to be certain that there is + * sufficient space in the journal prior to creating any new records. + * Since in the case of block allocation we may have multiple locked + * buffers at the time of the actual allocation we can not block + * when the journal records are created. Doing so would create a deadlock + * if any of these buffers needed to be flushed to reclaim space. Instead + * we require a sufficiently large amount of available space such that + * each thread in the system could have passed this allocation check and + * still have sufficient free space. With 20% of a minimum journal size + * of 1MB we have 6553 records available. + */ +int +softdep_prealloc(vp, waitok) + struct vnode *vp; + int waitok; +{ + struct ufsmount *ump; + + KASSERT(MOUNTEDSOFTDEP(vp->v_mount) != 0, + ("softdep_prealloc called on non-softdep filesystem")); + /* + * Nothing to do if we are not running journaled soft updates. + * If we currently hold the snapshot lock, we must avoid + * handling other resources that could cause deadlock. Do not + * touch quotas vnode since it is typically recursed with + * other vnode locks held. + */ + if (DOINGSUJ(vp) == 0 || IS_SNAPSHOT(VTOI(vp)) || + (vp->v_vflag & VV_SYSTEM) != 0) + return (0); + ump = VFSTOUFS(vp->v_mount); + ACQUIRE_LOCK(ump); + if (journal_space(ump, 0)) { + FREE_LOCK(ump); + return (0); + } + stat_journal_low++; + FREE_LOCK(ump); + if (waitok == MNT_NOWAIT) + return (ENOSPC); + /* + * Attempt to sync this vnode once to flush any journal + * work attached to it. + */ + if ((curthread->td_pflags & TDP_COWINPROGRESS) == 0) + ffs_syncvnode(vp, waitok, 0); + ACQUIRE_LOCK(ump); + process_removes(vp); + process_truncates(vp); + if (journal_space(ump, 0) == 0) { + softdep_speedup(ump); + if (journal_space(ump, 1) == 0) + journal_suspend(ump); + } + FREE_LOCK(ump); + + return (0); +} + +/* + * Before adjusting a link count on a vnode verify that we have sufficient + * journal space. If not, process operations that depend on the currently + * locked pair of vnodes to try to flush space as the syncer, buf daemon, + * and softdep flush threads can not acquire these locks to reclaim space. + */ +static void +softdep_prelink(dvp, vp) + struct vnode *dvp; + struct vnode *vp; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(dvp->v_mount); + LOCK_OWNED(ump); + /* + * Nothing to do if we have sufficient journal space. + * If we currently hold the snapshot lock, we must avoid + * handling other resources that could cause deadlock. + */ + if (journal_space(ump, 0) || (vp && IS_SNAPSHOT(VTOI(vp)))) + return; + stat_journal_low++; + FREE_LOCK(ump); + if (vp) + ffs_syncvnode(vp, MNT_NOWAIT, 0); + ffs_syncvnode(dvp, MNT_WAIT, 0); + ACQUIRE_LOCK(ump); + /* Process vp before dvp as it may create .. removes. */ + if (vp) { + process_removes(vp); + process_truncates(vp); + } + process_removes(dvp); + process_truncates(dvp); + softdep_speedup(ump); + process_worklist_item(UFSTOVFS(ump), 2, LK_NOWAIT); + if (journal_space(ump, 0) == 0) { + softdep_speedup(ump); + if (journal_space(ump, 1) == 0) + journal_suspend(ump); + } +} + +static void +jseg_write(ump, jseg, data) + struct ufsmount *ump; + struct jseg *jseg; + uint8_t *data; +{ + struct jsegrec *rec; + + rec = (struct jsegrec *)data; + rec->jsr_seq = jseg->js_seq; + rec->jsr_oldest = jseg->js_oldseq; + rec->jsr_cnt = jseg->js_cnt; + rec->jsr_blocks = jseg->js_size / ump->um_devvp->v_bufobj.bo_bsize; + rec->jsr_crc = 0; + rec->jsr_time = ump->um_fs->fs_mtime; +} + +static inline void +inoref_write(inoref, jseg, rec) + struct inoref *inoref; + struct jseg *jseg; + struct jrefrec *rec; +{ + + inoref->if_jsegdep->jd_seg = jseg; + rec->jr_ino = inoref->if_ino; + rec->jr_parent = inoref->if_parent; + rec->jr_nlink = inoref->if_nlink; + rec->jr_mode = inoref->if_mode; + rec->jr_diroff = inoref->if_diroff; +} + +static void +jaddref_write(jaddref, jseg, data) + struct jaddref *jaddref; + struct jseg *jseg; + uint8_t *data; +{ + struct jrefrec *rec; + + rec = (struct jrefrec *)data; + rec->jr_op = JOP_ADDREF; + inoref_write(&jaddref->ja_ref, jseg, rec); +} + +static void +jremref_write(jremref, jseg, data) + struct jremref *jremref; + struct jseg *jseg; + uint8_t *data; +{ + struct jrefrec *rec; + + rec = (struct jrefrec *)data; + rec->jr_op = JOP_REMREF; + inoref_write(&jremref->jr_ref, jseg, rec); +} + +static void +jmvref_write(jmvref, jseg, data) + struct jmvref *jmvref; + struct jseg *jseg; + uint8_t *data; +{ + struct jmvrec *rec; + + rec = (struct jmvrec *)data; + rec->jm_op = JOP_MVREF; + rec->jm_ino = jmvref->jm_ino; + rec->jm_parent = jmvref->jm_parent; + rec->jm_oldoff = jmvref->jm_oldoff; + rec->jm_newoff = jmvref->jm_newoff; +} + +static void +jnewblk_write(jnewblk, jseg, data) + struct jnewblk *jnewblk; + struct jseg *jseg; + uint8_t *data; +{ + struct jblkrec *rec; + + jnewblk->jn_jsegdep->jd_seg = jseg; + rec = (struct jblkrec *)data; + rec->jb_op = JOP_NEWBLK; + rec->jb_ino = jnewblk->jn_ino; + rec->jb_blkno = jnewblk->jn_blkno; + rec->jb_lbn = jnewblk->jn_lbn; + rec->jb_frags = jnewblk->jn_frags; + rec->jb_oldfrags = jnewblk->jn_oldfrags; +} + +static void +jfreeblk_write(jfreeblk, jseg, data) + struct jfreeblk *jfreeblk; + struct jseg *jseg; + uint8_t *data; +{ + struct jblkrec *rec; + + jfreeblk->jf_dep.jb_jsegdep->jd_seg = jseg; + rec = (struct jblkrec *)data; + rec->jb_op = JOP_FREEBLK; + rec->jb_ino = jfreeblk->jf_ino; + rec->jb_blkno = jfreeblk->jf_blkno; + rec->jb_lbn = jfreeblk->jf_lbn; + rec->jb_frags = jfreeblk->jf_frags; + rec->jb_oldfrags = 0; +} + +static void +jfreefrag_write(jfreefrag, jseg, data) + struct jfreefrag *jfreefrag; + struct jseg *jseg; + uint8_t *data; +{ + struct jblkrec *rec; + + jfreefrag->fr_jsegdep->jd_seg = jseg; + rec = (struct jblkrec *)data; + rec->jb_op = JOP_FREEBLK; + rec->jb_ino = jfreefrag->fr_ino; + rec->jb_blkno = jfreefrag->fr_blkno; + rec->jb_lbn = jfreefrag->fr_lbn; + rec->jb_frags = jfreefrag->fr_frags; + rec->jb_oldfrags = 0; +} + +static void +jtrunc_write(jtrunc, jseg, data) + struct jtrunc *jtrunc; + struct jseg *jseg; + uint8_t *data; +{ + struct jtrncrec *rec; + + jtrunc->jt_dep.jb_jsegdep->jd_seg = jseg; + rec = (struct jtrncrec *)data; + rec->jt_op = JOP_TRUNC; + rec->jt_ino = jtrunc->jt_ino; + rec->jt_size = jtrunc->jt_size; + rec->jt_extsize = jtrunc->jt_extsize; +} + +static void +jfsync_write(jfsync, jseg, data) + struct jfsync *jfsync; + struct jseg *jseg; + uint8_t *data; +{ + struct jtrncrec *rec; + + rec = (struct jtrncrec *)data; + rec->jt_op = JOP_SYNC; + rec->jt_ino = jfsync->jfs_ino; + rec->jt_size = jfsync->jfs_size; + rec->jt_extsize = jfsync->jfs_extsize; +} + +static void +softdep_flushjournal(mp) + struct mount *mp; +{ + struct jblocks *jblocks; + struct ufsmount *ump; + + if (MOUNTEDSUJ(mp) == 0) + return; + ump = VFSTOUFS(mp); + jblocks = ump->softdep_jblocks; + ACQUIRE_LOCK(ump); + while (ump->softdep_on_journal) { + jblocks->jb_needseg = 1; + softdep_process_journal(mp, NULL, MNT_WAIT); + } + FREE_LOCK(ump); +} + +static void softdep_synchronize_completed(struct bio *); +static void softdep_synchronize(struct bio *, struct ufsmount *, void *); + +static void +softdep_synchronize_completed(bp) + struct bio *bp; +{ + struct jseg *oldest; + struct jseg *jseg; + struct ufsmount *ump; + + /* + * caller1 marks the last segment written before we issued the + * synchronize cache. + */ + jseg = bp->bio_caller1; + if (jseg == NULL) { + g_destroy_bio(bp); + return; + } + ump = VFSTOUFS(jseg->js_list.wk_mp); + ACQUIRE_LOCK(ump); + oldest = NULL; + /* + * Mark all the journal entries waiting on the synchronize cache + * as completed so they may continue on. + */ + while (jseg != NULL && (jseg->js_state & COMPLETE) == 0) { + jseg->js_state |= COMPLETE; + oldest = jseg; + jseg = TAILQ_PREV(jseg, jseglst, js_next); + } + /* + * Restart deferred journal entry processing from the oldest + * completed jseg. + */ + if (oldest) + complete_jsegs(oldest); + + FREE_LOCK(ump); + g_destroy_bio(bp); +} + +/* + * Send BIO_FLUSH/SYNCHRONIZE CACHE to the device to enforce write ordering + * barriers. The journal must be written prior to any blocks that depend + * on it and the journal can not be released until the blocks have be + * written. This code handles both barriers simultaneously. + */ +static void +softdep_synchronize(bp, ump, caller1) + struct bio *bp; + struct ufsmount *ump; + void *caller1; +{ + + bp->bio_cmd = BIO_FLUSH; + bp->bio_flags |= BIO_ORDERED; + bp->bio_data = NULL; + bp->bio_offset = ump->um_cp->provider->mediasize; + bp->bio_length = 0; + bp->bio_done = softdep_synchronize_completed; + bp->bio_caller1 = caller1; + g_io_request(bp, + (struct g_consumer *)ump->um_devvp->v_bufobj.bo_private); +} + +/* + * Flush some journal records to disk. + */ +static void +softdep_process_journal(mp, needwk, flags) + struct mount *mp; + struct worklist *needwk; + int flags; +{ + struct jblocks *jblocks; + struct ufsmount *ump; + struct worklist *wk; + struct jseg *jseg; + struct buf *bp; + struct bio *bio; + uint8_t *data; + struct fs *fs; + int shouldflush; + int segwritten; + int jrecmin; /* Minimum records per block. */ + int jrecmax; /* Maximum records per block. */ + int size; + int cnt; + int off; + int devbsize; + + if (MOUNTEDSUJ(mp) == 0) + return; + shouldflush = softdep_flushcache; + bio = NULL; + jseg = NULL; + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + fs = ump->um_fs; + jblocks = ump->softdep_jblocks; + devbsize = ump->um_devvp->v_bufobj.bo_bsize; + /* + * We write anywhere between a disk block and fs block. The upper + * bound is picked to prevent buffer cache fragmentation and limit + * processing time per I/O. + */ + jrecmin = (devbsize / JREC_SIZE) - 1; /* -1 for seg header */ + jrecmax = (fs->fs_bsize / devbsize) * jrecmin; + segwritten = 0; + for (;;) { + cnt = ump->softdep_on_journal; + /* + * Criteria for writing a segment: + * 1) We have a full block. + * 2) We're called from jwait() and haven't found the + * journal item yet. + * 3) Always write if needseg is set. + * 4) If we are called from process_worklist and have + * not yet written anything we write a partial block + * to enforce a 1 second maximum latency on journal + * entries. + */ + if (cnt < (jrecmax - 1) && needwk == NULL && + jblocks->jb_needseg == 0 && (segwritten || cnt == 0)) + break; + cnt++; + /* + * Verify some free journal space. softdep_prealloc() should + * guarantee that we don't run out so this is indicative of + * a problem with the flow control. Try to recover + * gracefully in any event. + */ + while (jblocks->jb_free == 0) { + if (flags != MNT_WAIT) + break; + printf("softdep: Out of journal space!\n"); + softdep_speedup(ump); + msleep(jblocks, LOCK_PTR(ump), PRIBIO, "jblocks", hz); + } + FREE_LOCK(ump); + jseg = malloc(sizeof(*jseg), M_JSEG, M_SOFTDEP_FLAGS); + workitem_alloc(&jseg->js_list, D_JSEG, mp); + LIST_INIT(&jseg->js_entries); + LIST_INIT(&jseg->js_indirs); + jseg->js_state = ATTACHED; + if (shouldflush == 0) + jseg->js_state |= COMPLETE; + else if (bio == NULL) + bio = g_alloc_bio(); + jseg->js_jblocks = jblocks; + bp = geteblk(fs->fs_bsize, 0); + ACQUIRE_LOCK(ump); + /* + * If there was a race while we were allocating the block + * and jseg the entry we care about was likely written. + * We bail out in both the WAIT and NOWAIT case and assume + * the caller will loop if the entry it cares about is + * not written. + */ + cnt = ump->softdep_on_journal; + if (cnt + jblocks->jb_needseg == 0 || jblocks->jb_free == 0) { + bp->b_flags |= B_INVAL | B_NOCACHE; + WORKITEM_FREE(jseg, D_JSEG); + FREE_LOCK(ump); + brelse(bp); + ACQUIRE_LOCK(ump); + break; + } + /* + * Calculate the disk block size required for the available + * records rounded to the min size. + */ + if (cnt == 0) + size = devbsize; + else if (cnt < jrecmax) + size = howmany(cnt, jrecmin) * devbsize; + else + size = fs->fs_bsize; + /* + * Allocate a disk block for this journal data and account + * for truncation of the requested size if enough contiguous + * space was not available. + */ + bp->b_blkno = jblocks_alloc(jblocks, size, &size); + bp->b_lblkno = bp->b_blkno; + bp->b_offset = bp->b_blkno * DEV_BSIZE; + bp->b_bcount = size; + bp->b_flags &= ~B_INVAL; + bp->b_flags |= B_VALIDSUSPWRT | B_NOCOPY; + /* + * Initialize our jseg with cnt records. Assign the next + * sequence number to it and link it in-order. + */ + cnt = MIN(cnt, (size / devbsize) * jrecmin); + jseg->js_buf = bp; + jseg->js_cnt = cnt; + jseg->js_refs = cnt + 1; /* Self ref. */ + jseg->js_size = size; + jseg->js_seq = jblocks->jb_nextseq++; + if (jblocks->jb_oldestseg == NULL) + jblocks->jb_oldestseg = jseg; + jseg->js_oldseq = jblocks->jb_oldestseg->js_seq; + TAILQ_INSERT_TAIL(&jblocks->jb_segs, jseg, js_next); + if (jblocks->jb_writeseg == NULL) + jblocks->jb_writeseg = jseg; + /* + * Start filling in records from the pending list. + */ + data = bp->b_data; + off = 0; + + /* + * Always put a header on the first block. + * XXX As with below, there might not be a chance to get + * into the loop. Ensure that something valid is written. + */ + jseg_write(ump, jseg, data); + off += JREC_SIZE; + data = bp->b_data + off; + + /* + * XXX Something is wrong here. There's no work to do, + * but we need to perform and I/O and allow it to complete + * anyways. + */ + if (LIST_EMPTY(&ump->softdep_journal_pending)) + stat_emptyjblocks++; + + while ((wk = LIST_FIRST(&ump->softdep_journal_pending)) + != NULL) { + if (cnt == 0) + break; + /* Place a segment header on every device block. */ + if ((off % devbsize) == 0) { + jseg_write(ump, jseg, data); + off += JREC_SIZE; + data = bp->b_data + off; + } + if (wk == needwk) + needwk = NULL; + remove_from_journal(wk); + wk->wk_state |= INPROGRESS; + WORKLIST_INSERT(&jseg->js_entries, wk); + switch (wk->wk_type) { + case D_JADDREF: + jaddref_write(WK_JADDREF(wk), jseg, data); + break; + case D_JREMREF: + jremref_write(WK_JREMREF(wk), jseg, data); + break; + case D_JMVREF: + jmvref_write(WK_JMVREF(wk), jseg, data); + break; + case D_JNEWBLK: + jnewblk_write(WK_JNEWBLK(wk), jseg, data); + break; + case D_JFREEBLK: + jfreeblk_write(WK_JFREEBLK(wk), jseg, data); + break; + case D_JFREEFRAG: + jfreefrag_write(WK_JFREEFRAG(wk), jseg, data); + break; + case D_JTRUNC: + jtrunc_write(WK_JTRUNC(wk), jseg, data); + break; + case D_JFSYNC: + jfsync_write(WK_JFSYNC(wk), jseg, data); + break; + default: + panic("process_journal: Unknown type %s", + TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + off += JREC_SIZE; + data = bp->b_data + off; + cnt--; + } + + /* Clear any remaining space so we don't leak kernel data */ + if (size > off) + bzero(data, size - off); + + /* + * Write this one buffer and continue. + */ + segwritten = 1; + jblocks->jb_needseg = 0; + WORKLIST_INSERT(&bp->b_dep, &jseg->js_list); + FREE_LOCK(ump); + pbgetvp(ump->um_devvp, bp); + /* + * We only do the blocking wait once we find the journal + * entry we're looking for. + */ + if (needwk == NULL && flags == MNT_WAIT) + bwrite(bp); + else + bawrite(bp); + ACQUIRE_LOCK(ump); + } + /* + * If we wrote a segment issue a synchronize cache so the journal + * is reflected on disk before the data is written. Since reclaiming + * journal space also requires writing a journal record this + * process also enforces a barrier before reclamation. + */ + if (segwritten && shouldflush) { + softdep_synchronize(bio, ump, + TAILQ_LAST(&jblocks->jb_segs, jseglst)); + } else if (bio) + g_destroy_bio(bio); + /* + * If we've suspended the filesystem because we ran out of journal + * space either try to sync it here to make some progress or + * unsuspend it if we already have. + */ + if (flags == 0 && jblocks->jb_suspended) { + if (journal_unsuspend(ump)) + return; + FREE_LOCK(ump); + VFS_SYNC(mp, MNT_NOWAIT); + ffs_sbupdate(ump, MNT_WAIT, 0); + ACQUIRE_LOCK(ump); + } +} + +/* + * Complete a jseg, allowing all dependencies awaiting journal writes + * to proceed. Each journal dependency also attaches a jsegdep to dependent + * structures so that the journal segment can be freed to reclaim space. + */ +static void +complete_jseg(jseg) + struct jseg *jseg; +{ + struct worklist *wk; + struct jmvref *jmvref; +#ifdef INVARIANTS + int i = 0; +#endif + + while ((wk = LIST_FIRST(&jseg->js_entries)) != NULL) { + WORKLIST_REMOVE(wk); + wk->wk_state &= ~INPROGRESS; + wk->wk_state |= COMPLETE; + KASSERT(i++ < jseg->js_cnt, + ("handle_written_jseg: overflow %d >= %d", + i - 1, jseg->js_cnt)); + switch (wk->wk_type) { + case D_JADDREF: + handle_written_jaddref(WK_JADDREF(wk)); + break; + case D_JREMREF: + handle_written_jremref(WK_JREMREF(wk)); + break; + case D_JMVREF: + rele_jseg(jseg); /* No jsegdep. */ + jmvref = WK_JMVREF(wk); + LIST_REMOVE(jmvref, jm_deps); + if ((jmvref->jm_pagedep->pd_state & ONWORKLIST) == 0) + free_pagedep(jmvref->jm_pagedep); + WORKITEM_FREE(jmvref, D_JMVREF); + break; + case D_JNEWBLK: + handle_written_jnewblk(WK_JNEWBLK(wk)); + break; + case D_JFREEBLK: + handle_written_jblkdep(&WK_JFREEBLK(wk)->jf_dep); + break; + case D_JTRUNC: + handle_written_jblkdep(&WK_JTRUNC(wk)->jt_dep); + break; + case D_JFSYNC: + rele_jseg(jseg); /* No jsegdep. */ + WORKITEM_FREE(wk, D_JFSYNC); + break; + case D_JFREEFRAG: + handle_written_jfreefrag(WK_JFREEFRAG(wk)); + break; + default: + panic("handle_written_jseg: Unknown type %s", + TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + } + /* Release the self reference so the structure may be freed. */ + rele_jseg(jseg); +} + +/* + * Determine which jsegs are ready for completion processing. Waits for + * synchronize cache to complete as well as forcing in-order completion + * of journal entries. + */ +static void +complete_jsegs(jseg) + struct jseg *jseg; +{ + struct jblocks *jblocks; + struct jseg *jsegn; + + jblocks = jseg->js_jblocks; + /* + * Don't allow out of order completions. If this isn't the first + * block wait for it to write before we're done. + */ + if (jseg != jblocks->jb_writeseg) + return; + /* Iterate through available jsegs processing their entries. */ + while (jseg && (jseg->js_state & ALLCOMPLETE) == ALLCOMPLETE) { + jblocks->jb_oldestwrseq = jseg->js_oldseq; + jsegn = TAILQ_NEXT(jseg, js_next); + complete_jseg(jseg); + jseg = jsegn; + } + jblocks->jb_writeseg = jseg; + /* + * Attempt to free jsegs now that oldestwrseq may have advanced. + */ + free_jsegs(jblocks); +} + +/* + * Mark a jseg as DEPCOMPLETE and throw away the buffer. Attempt to handle + * the final completions. + */ +static void +handle_written_jseg(jseg, bp) + struct jseg *jseg; + struct buf *bp; +{ + + if (jseg->js_refs == 0) + panic("handle_written_jseg: No self-reference on %p", jseg); + jseg->js_state |= DEPCOMPLETE; + /* + * We'll never need this buffer again, set flags so it will be + * discarded. + */ + bp->b_flags |= B_INVAL | B_NOCACHE; + pbrelvp(bp); + complete_jsegs(jseg); +} + +static inline struct jsegdep * +inoref_jseg(inoref) + struct inoref *inoref; +{ + struct jsegdep *jsegdep; + + jsegdep = inoref->if_jsegdep; + inoref->if_jsegdep = NULL; + + return (jsegdep); +} + +/* + * Called once a jremref has made it to stable store. The jremref is marked + * complete and we attempt to free it. Any pagedeps writes sleeping waiting + * for the jremref to complete will be awoken by free_jremref. + */ +static void +handle_written_jremref(jremref) + struct jremref *jremref; +{ + struct inodedep *inodedep; + struct jsegdep *jsegdep; + struct dirrem *dirrem; + + /* Grab the jsegdep. */ + jsegdep = inoref_jseg(&jremref->jr_ref); + /* + * Remove us from the inoref list. + */ + if (inodedep_lookup(jremref->jr_list.wk_mp, jremref->jr_ref.if_ino, + 0, &inodedep) == 0) + panic("handle_written_jremref: Lost inodedep"); + TAILQ_REMOVE(&inodedep->id_inoreflst, &jremref->jr_ref, if_deps); + /* + * Complete the dirrem. + */ + dirrem = jremref->jr_dirrem; + jremref->jr_dirrem = NULL; + LIST_REMOVE(jremref, jr_deps); + jsegdep->jd_state |= jremref->jr_state & MKDIR_PARENT; + jwork_insert(&dirrem->dm_jwork, jsegdep); + if (LIST_EMPTY(&dirrem->dm_jremrefhd) && + (dirrem->dm_state & COMPLETE) != 0) + add_to_worklist(&dirrem->dm_list, 0); + free_jremref(jremref); +} + +/* + * Called once a jaddref has made it to stable store. The dependency is + * marked complete and any dependent structures are added to the inode + * bufwait list to be completed as soon as it is written. If a bitmap write + * depends on this entry we move the inode into the inodedephd of the + * bmsafemap dependency and attempt to remove the jaddref from the bmsafemap. + */ +static void +handle_written_jaddref(jaddref) + struct jaddref *jaddref; +{ + struct jsegdep *jsegdep; + struct inodedep *inodedep; + struct diradd *diradd; + struct mkdir *mkdir; + + /* Grab the jsegdep. */ + jsegdep = inoref_jseg(&jaddref->ja_ref); + mkdir = NULL; + diradd = NULL; + if (inodedep_lookup(jaddref->ja_list.wk_mp, jaddref->ja_ino, + 0, &inodedep) == 0) + panic("handle_written_jaddref: Lost inodedep."); + if (jaddref->ja_diradd == NULL) + panic("handle_written_jaddref: No dependency"); + if (jaddref->ja_diradd->da_list.wk_type == D_DIRADD) { + diradd = jaddref->ja_diradd; + WORKLIST_INSERT(&inodedep->id_bufwait, &diradd->da_list); + } else if (jaddref->ja_state & MKDIR_PARENT) { + mkdir = jaddref->ja_mkdir; + WORKLIST_INSERT(&inodedep->id_bufwait, &mkdir->md_list); + } else if (jaddref->ja_state & MKDIR_BODY) + mkdir = jaddref->ja_mkdir; + else + panic("handle_written_jaddref: Unknown dependency %p", + jaddref->ja_diradd); + jaddref->ja_diradd = NULL; /* also clears ja_mkdir */ + /* + * Remove us from the inode list. + */ + TAILQ_REMOVE(&inodedep->id_inoreflst, &jaddref->ja_ref, if_deps); + /* + * The mkdir may be waiting on the jaddref to clear before freeing. + */ + if (mkdir) { + KASSERT(mkdir->md_list.wk_type == D_MKDIR, + ("handle_written_jaddref: Incorrect type for mkdir %s", + TYPENAME(mkdir->md_list.wk_type))); + mkdir->md_jaddref = NULL; + diradd = mkdir->md_diradd; + mkdir->md_state |= DEPCOMPLETE; + complete_mkdir(mkdir); + } + jwork_insert(&diradd->da_jwork, jsegdep); + if (jaddref->ja_state & NEWBLOCK) { + inodedep->id_state |= ONDEPLIST; + LIST_INSERT_HEAD(&inodedep->id_bmsafemap->sm_inodedephd, + inodedep, id_deps); + } + free_jaddref(jaddref); +} + +/* + * Called once a jnewblk journal is written. The allocdirect or allocindir + * is placed in the bmsafemap to await notification of a written bitmap. If + * the operation was canceled we add the segdep to the appropriate + * dependency to free the journal space once the canceling operation + * completes. + */ +static void +handle_written_jnewblk(jnewblk) + struct jnewblk *jnewblk; +{ + struct bmsafemap *bmsafemap; + struct freefrag *freefrag; + struct freework *freework; + struct jsegdep *jsegdep; + struct newblk *newblk; + + /* Grab the jsegdep. */ + jsegdep = jnewblk->jn_jsegdep; + jnewblk->jn_jsegdep = NULL; + if (jnewblk->jn_dep == NULL) + panic("handle_written_jnewblk: No dependency for the segdep."); + switch (jnewblk->jn_dep->wk_type) { + case D_NEWBLK: + case D_ALLOCDIRECT: + case D_ALLOCINDIR: + /* + * Add the written block to the bmsafemap so it can + * be notified when the bitmap is on disk. + */ + newblk = WK_NEWBLK(jnewblk->jn_dep); + newblk->nb_jnewblk = NULL; + if ((newblk->nb_state & GOINGAWAY) == 0) { + bmsafemap = newblk->nb_bmsafemap; + newblk->nb_state |= ONDEPLIST; + LIST_INSERT_HEAD(&bmsafemap->sm_newblkhd, newblk, + nb_deps); + } + jwork_insert(&newblk->nb_jwork, jsegdep); + break; + case D_FREEFRAG: + /* + * A newblock being removed by a freefrag when replaced by + * frag extension. + */ + freefrag = WK_FREEFRAG(jnewblk->jn_dep); + freefrag->ff_jdep = NULL; + jwork_insert(&freefrag->ff_jwork, jsegdep); + break; + case D_FREEWORK: + /* + * A direct block was removed by truncate. + */ + freework = WK_FREEWORK(jnewblk->jn_dep); + freework->fw_jnewblk = NULL; + jwork_insert(&freework->fw_freeblks->fb_jwork, jsegdep); + break; + default: + panic("handle_written_jnewblk: Unknown type %d.", + jnewblk->jn_dep->wk_type); + } + jnewblk->jn_dep = NULL; + free_jnewblk(jnewblk); +} + +/* + * Cancel a jfreefrag that won't be needed, probably due to colliding with + * an in-flight allocation that has not yet been committed. Divorce us + * from the freefrag and mark it DEPCOMPLETE so that it may be added + * to the worklist. + */ +static void +cancel_jfreefrag(jfreefrag) + struct jfreefrag *jfreefrag; +{ + struct freefrag *freefrag; + + if (jfreefrag->fr_jsegdep) { + free_jsegdep(jfreefrag->fr_jsegdep); + jfreefrag->fr_jsegdep = NULL; + } + freefrag = jfreefrag->fr_freefrag; + jfreefrag->fr_freefrag = NULL; + free_jfreefrag(jfreefrag); + freefrag->ff_state |= DEPCOMPLETE; + CTR1(KTR_SUJ, "cancel_jfreefrag: blkno %jd", freefrag->ff_blkno); +} + +/* + * Free a jfreefrag when the parent freefrag is rendered obsolete. + */ +static void +free_jfreefrag(jfreefrag) + struct jfreefrag *jfreefrag; +{ + + if (jfreefrag->fr_state & INPROGRESS) + WORKLIST_REMOVE(&jfreefrag->fr_list); + else if (jfreefrag->fr_state & ONWORKLIST) + remove_from_journal(&jfreefrag->fr_list); + if (jfreefrag->fr_freefrag != NULL) + panic("free_jfreefrag: Still attached to a freefrag."); + WORKITEM_FREE(jfreefrag, D_JFREEFRAG); +} + +/* + * Called when the journal write for a jfreefrag completes. The parent + * freefrag is added to the worklist if this completes its dependencies. + */ +static void +handle_written_jfreefrag(jfreefrag) + struct jfreefrag *jfreefrag; +{ + struct jsegdep *jsegdep; + struct freefrag *freefrag; + + /* Grab the jsegdep. */ + jsegdep = jfreefrag->fr_jsegdep; + jfreefrag->fr_jsegdep = NULL; + freefrag = jfreefrag->fr_freefrag; + if (freefrag == NULL) + panic("handle_written_jfreefrag: No freefrag."); + freefrag->ff_state |= DEPCOMPLETE; + freefrag->ff_jdep = NULL; + jwork_insert(&freefrag->ff_jwork, jsegdep); + if ((freefrag->ff_state & ALLCOMPLETE) == ALLCOMPLETE) + add_to_worklist(&freefrag->ff_list, 0); + jfreefrag->fr_freefrag = NULL; + free_jfreefrag(jfreefrag); +} + +/* + * Called when the journal write for a jfreeblk completes. The jfreeblk + * is removed from the freeblks list of pending journal writes and the + * jsegdep is moved to the freeblks jwork to be completed when all blocks + * have been reclaimed. + */ +static void +handle_written_jblkdep(jblkdep) + struct jblkdep *jblkdep; +{ + struct freeblks *freeblks; + struct jsegdep *jsegdep; + + /* Grab the jsegdep. */ + jsegdep = jblkdep->jb_jsegdep; + jblkdep->jb_jsegdep = NULL; + freeblks = jblkdep->jb_freeblks; + LIST_REMOVE(jblkdep, jb_deps); + jwork_insert(&freeblks->fb_jwork, jsegdep); + /* + * If the freeblks is all journaled, we can add it to the worklist. + */ + if (LIST_EMPTY(&freeblks->fb_jblkdephd) && + (freeblks->fb_state & ALLCOMPLETE) == ALLCOMPLETE) + add_to_worklist(&freeblks->fb_list, WK_NODELAY); + + free_jblkdep(jblkdep); +} + +static struct jsegdep * +newjsegdep(struct worklist *wk) +{ + struct jsegdep *jsegdep; + + jsegdep = malloc(sizeof(*jsegdep), M_JSEGDEP, M_SOFTDEP_FLAGS); + workitem_alloc(&jsegdep->jd_list, D_JSEGDEP, wk->wk_mp); + jsegdep->jd_seg = NULL; + + return (jsegdep); +} + +static struct jmvref * +newjmvref(dp, ino, oldoff, newoff) + struct inode *dp; + ino_t ino; + off_t oldoff; + off_t newoff; +{ + struct jmvref *jmvref; + + jmvref = malloc(sizeof(*jmvref), M_JMVREF, M_SOFTDEP_FLAGS); + workitem_alloc(&jmvref->jm_list, D_JMVREF, ITOVFS(dp)); + jmvref->jm_list.wk_state = ATTACHED | DEPCOMPLETE; + jmvref->jm_parent = dp->i_number; + jmvref->jm_ino = ino; + jmvref->jm_oldoff = oldoff; + jmvref->jm_newoff = newoff; + + return (jmvref); +} + +/* + * Allocate a new jremref that tracks the removal of ip from dp with the + * directory entry offset of diroff. Mark the entry as ATTACHED and + * DEPCOMPLETE as we have all the information required for the journal write + * and the directory has already been removed from the buffer. The caller + * is responsible for linking the jremref into the pagedep and adding it + * to the journal to write. The MKDIR_PARENT flag is set if we're doing + * a DOTDOT addition so handle_workitem_remove() can properly assign + * the jsegdep when we're done. + */ +static struct jremref * +newjremref(struct dirrem *dirrem, struct inode *dp, struct inode *ip, + off_t diroff, nlink_t nlink) +{ + struct jremref *jremref; + + jremref = malloc(sizeof(*jremref), M_JREMREF, M_SOFTDEP_FLAGS); + workitem_alloc(&jremref->jr_list, D_JREMREF, ITOVFS(dp)); + jremref->jr_state = ATTACHED; + newinoref(&jremref->jr_ref, ip->i_number, dp->i_number, diroff, + nlink, ip->i_mode); + jremref->jr_dirrem = dirrem; + + return (jremref); +} + +static inline void +newinoref(struct inoref *inoref, ino_t ino, ino_t parent, off_t diroff, + nlink_t nlink, uint16_t mode) +{ + + inoref->if_jsegdep = newjsegdep(&inoref->if_list); + inoref->if_diroff = diroff; + inoref->if_ino = ino; + inoref->if_parent = parent; + inoref->if_nlink = nlink; + inoref->if_mode = mode; +} + +/* + * Allocate a new jaddref to track the addition of ino to dp at diroff. The + * directory offset may not be known until later. The caller is responsible + * adding the entry to the journal when this information is available. nlink + * should be the link count prior to the addition and mode is only required + * to have the correct FMT. + */ +static struct jaddref * +newjaddref(struct inode *dp, ino_t ino, off_t diroff, int16_t nlink, + uint16_t mode) +{ + struct jaddref *jaddref; + + jaddref = malloc(sizeof(*jaddref), M_JADDREF, M_SOFTDEP_FLAGS); + workitem_alloc(&jaddref->ja_list, D_JADDREF, ITOVFS(dp)); + jaddref->ja_state = ATTACHED; + jaddref->ja_mkdir = NULL; + newinoref(&jaddref->ja_ref, ino, dp->i_number, diroff, nlink, mode); + + return (jaddref); +} + +/* + * Create a new free dependency for a freework. The caller is responsible + * for adjusting the reference count when it has the lock held. The freedep + * will track an outstanding bitmap write that will ultimately clear the + * freework to continue. + */ +static struct freedep * +newfreedep(struct freework *freework) +{ + struct freedep *freedep; + + freedep = malloc(sizeof(*freedep), M_FREEDEP, M_SOFTDEP_FLAGS); + workitem_alloc(&freedep->fd_list, D_FREEDEP, freework->fw_list.wk_mp); + freedep->fd_freework = freework; + + return (freedep); +} + +/* + * Free a freedep structure once the buffer it is linked to is written. If + * this is the last reference to the freework schedule it for completion. + */ +static void +free_freedep(freedep) + struct freedep *freedep; +{ + struct freework *freework; + + freework = freedep->fd_freework; + freework->fw_freeblks->fb_cgwait--; + if (--freework->fw_ref == 0) + freework_enqueue(freework); + WORKITEM_FREE(freedep, D_FREEDEP); +} + +/* + * Allocate a new freework structure that may be a level in an indirect + * when parent is not NULL or a top level block when it is. The top level + * freework structures are allocated without the per-filesystem lock held + * and before the freeblks is visible outside of softdep_setup_freeblocks(). + */ +static struct freework * +newfreework(ump, freeblks, parent, lbn, nb, frags, off, journal) + struct ufsmount *ump; + struct freeblks *freeblks; + struct freework *parent; + ufs_lbn_t lbn; + ufs2_daddr_t nb; + int frags; + int off; + int journal; +{ + struct freework *freework; + + freework = malloc(sizeof(*freework), M_FREEWORK, M_SOFTDEP_FLAGS); + workitem_alloc(&freework->fw_list, D_FREEWORK, freeblks->fb_list.wk_mp); + freework->fw_state = ATTACHED; + freework->fw_jnewblk = NULL; + freework->fw_freeblks = freeblks; + freework->fw_parent = parent; + freework->fw_lbn = lbn; + freework->fw_blkno = nb; + freework->fw_frags = frags; + freework->fw_indir = NULL; + freework->fw_ref = (MOUNTEDSUJ(UFSTOVFS(ump)) == 0 || lbn >= -NXADDR) + ? 0 : NINDIR(ump->um_fs) + 1; + freework->fw_start = freework->fw_off = off; + if (journal) + newjfreeblk(freeblks, lbn, nb, frags); + if (parent == NULL) { + ACQUIRE_LOCK(ump); + WORKLIST_INSERT(&freeblks->fb_freeworkhd, &freework->fw_list); + freeblks->fb_ref++; + FREE_LOCK(ump); + } + + return (freework); +} + +/* + * Eliminate a jfreeblk for a block that does not need journaling. + */ +static void +cancel_jfreeblk(freeblks, blkno) + struct freeblks *freeblks; + ufs2_daddr_t blkno; +{ + struct jfreeblk *jfreeblk; + struct jblkdep *jblkdep; + + LIST_FOREACH(jblkdep, &freeblks->fb_jblkdephd, jb_deps) { + if (jblkdep->jb_list.wk_type != D_JFREEBLK) + continue; + jfreeblk = WK_JFREEBLK(&jblkdep->jb_list); + if (jfreeblk->jf_blkno == blkno) + break; + } + if (jblkdep == NULL) + return; + CTR1(KTR_SUJ, "cancel_jfreeblk: blkno %jd", blkno); + free_jsegdep(jblkdep->jb_jsegdep); + LIST_REMOVE(jblkdep, jb_deps); + WORKITEM_FREE(jfreeblk, D_JFREEBLK); +} + +/* + * Allocate a new jfreeblk to journal top level block pointer when truncating + * a file. The caller must add this to the worklist when the per-filesystem + * lock is held. + */ +static struct jfreeblk * +newjfreeblk(freeblks, lbn, blkno, frags) + struct freeblks *freeblks; + ufs_lbn_t lbn; + ufs2_daddr_t blkno; + int frags; +{ + struct jfreeblk *jfreeblk; + + jfreeblk = malloc(sizeof(*jfreeblk), M_JFREEBLK, M_SOFTDEP_FLAGS); + workitem_alloc(&jfreeblk->jf_dep.jb_list, D_JFREEBLK, + freeblks->fb_list.wk_mp); + jfreeblk->jf_dep.jb_jsegdep = newjsegdep(&jfreeblk->jf_dep.jb_list); + jfreeblk->jf_dep.jb_freeblks = freeblks; + jfreeblk->jf_ino = freeblks->fb_inum; + jfreeblk->jf_lbn = lbn; + jfreeblk->jf_blkno = blkno; + jfreeblk->jf_frags = frags; + LIST_INSERT_HEAD(&freeblks->fb_jblkdephd, &jfreeblk->jf_dep, jb_deps); + + return (jfreeblk); +} + +/* + * The journal is only prepared to handle full-size block numbers, so we + * have to adjust the record to reflect the change to a full-size block. + * For example, suppose we have a block made up of fragments 8-15 and + * want to free its last two fragments. We are given a request that says: + * FREEBLK ino=5, blkno=14, lbn=0, frags=2, oldfrags=0 + * where frags are the number of fragments to free and oldfrags are the + * number of fragments to keep. To block align it, we have to change it to + * have a valid full-size blkno, so it becomes: + * FREEBLK ino=5, blkno=8, lbn=0, frags=2, oldfrags=6 + */ +static void +adjust_newfreework(freeblks, frag_offset) + struct freeblks *freeblks; + int frag_offset; +{ + struct jfreeblk *jfreeblk; + + KASSERT((LIST_FIRST(&freeblks->fb_jblkdephd) != NULL && + LIST_FIRST(&freeblks->fb_jblkdephd)->jb_list.wk_type == D_JFREEBLK), + ("adjust_newfreework: Missing freeblks dependency")); + + jfreeblk = WK_JFREEBLK(LIST_FIRST(&freeblks->fb_jblkdephd)); + jfreeblk->jf_blkno -= frag_offset; + jfreeblk->jf_frags += frag_offset; +} + +/* + * Allocate a new jtrunc to track a partial truncation. + */ +static struct jtrunc * +newjtrunc(freeblks, size, extsize) + struct freeblks *freeblks; + off_t size; + int extsize; +{ + struct jtrunc *jtrunc; + + jtrunc = malloc(sizeof(*jtrunc), M_JTRUNC, M_SOFTDEP_FLAGS); + workitem_alloc(&jtrunc->jt_dep.jb_list, D_JTRUNC, + freeblks->fb_list.wk_mp); + jtrunc->jt_dep.jb_jsegdep = newjsegdep(&jtrunc->jt_dep.jb_list); + jtrunc->jt_dep.jb_freeblks = freeblks; + jtrunc->jt_ino = freeblks->fb_inum; + jtrunc->jt_size = size; + jtrunc->jt_extsize = extsize; + LIST_INSERT_HEAD(&freeblks->fb_jblkdephd, &jtrunc->jt_dep, jb_deps); + + return (jtrunc); +} + +/* + * If we're canceling a new bitmap we have to search for another ref + * to move into the bmsafemap dep. This might be better expressed + * with another structure. + */ +static void +move_newblock_dep(jaddref, inodedep) + struct jaddref *jaddref; + struct inodedep *inodedep; +{ + struct inoref *inoref; + struct jaddref *jaddrefn; + + jaddrefn = NULL; + for (inoref = TAILQ_NEXT(&jaddref->ja_ref, if_deps); inoref; + inoref = TAILQ_NEXT(inoref, if_deps)) { + if ((jaddref->ja_state & NEWBLOCK) && + inoref->if_list.wk_type == D_JADDREF) { + jaddrefn = (struct jaddref *)inoref; + break; + } + } + if (jaddrefn == NULL) + return; + jaddrefn->ja_state &= ~(ATTACHED | UNDONE); + jaddrefn->ja_state |= jaddref->ja_state & + (ATTACHED | UNDONE | NEWBLOCK); + jaddref->ja_state &= ~(ATTACHED | UNDONE | NEWBLOCK); + jaddref->ja_state |= ATTACHED; + LIST_REMOVE(jaddref, ja_bmdeps); + LIST_INSERT_HEAD(&inodedep->id_bmsafemap->sm_jaddrefhd, jaddrefn, + ja_bmdeps); +} + +/* + * Cancel a jaddref either before it has been written or while it is being + * written. This happens when a link is removed before the add reaches + * the disk. The jaddref dependency is kept linked into the bmsafemap + * and inode to prevent the link count or bitmap from reaching the disk + * until handle_workitem_remove() re-adjusts the counts and bitmaps as + * required. + * + * Returns 1 if the canceled addref requires journaling of the remove and + * 0 otherwise. + */ +static int +cancel_jaddref(jaddref, inodedep, wkhd) + struct jaddref *jaddref; + struct inodedep *inodedep; + struct workhead *wkhd; +{ + struct inoref *inoref; + struct jsegdep *jsegdep; + int needsj; + + KASSERT((jaddref->ja_state & COMPLETE) == 0, + ("cancel_jaddref: Canceling complete jaddref")); + if (jaddref->ja_state & (INPROGRESS | COMPLETE)) + needsj = 1; + else + needsj = 0; + if (inodedep == NULL) + if (inodedep_lookup(jaddref->ja_list.wk_mp, jaddref->ja_ino, + 0, &inodedep) == 0) + panic("cancel_jaddref: Lost inodedep"); + /* + * We must adjust the nlink of any reference operation that follows + * us so that it is consistent with the in-memory reference. This + * ensures that inode nlink rollbacks always have the correct link. + */ + if (needsj == 0) { + for (inoref = TAILQ_NEXT(&jaddref->ja_ref, if_deps); inoref; + inoref = TAILQ_NEXT(inoref, if_deps)) { + if (inoref->if_state & GOINGAWAY) + break; + inoref->if_nlink--; + } + } + jsegdep = inoref_jseg(&jaddref->ja_ref); + if (jaddref->ja_state & NEWBLOCK) + move_newblock_dep(jaddref, inodedep); + wake_worklist(&jaddref->ja_list); + jaddref->ja_mkdir = NULL; + if (jaddref->ja_state & INPROGRESS) { + jaddref->ja_state &= ~INPROGRESS; + WORKLIST_REMOVE(&jaddref->ja_list); + jwork_insert(wkhd, jsegdep); + } else { + free_jsegdep(jsegdep); + if (jaddref->ja_state & DEPCOMPLETE) + remove_from_journal(&jaddref->ja_list); + } + jaddref->ja_state |= (GOINGAWAY | DEPCOMPLETE); + /* + * Leave NEWBLOCK jaddrefs on the inodedep so handle_workitem_remove + * can arrange for them to be freed with the bitmap. Otherwise we + * no longer need this addref attached to the inoreflst and it + * will incorrectly adjust nlink if we leave it. + */ + if ((jaddref->ja_state & NEWBLOCK) == 0) { + TAILQ_REMOVE(&inodedep->id_inoreflst, &jaddref->ja_ref, + if_deps); + jaddref->ja_state |= COMPLETE; + free_jaddref(jaddref); + return (needsj); + } + /* + * Leave the head of the list for jsegdeps for fast merging. + */ + if (LIST_FIRST(wkhd) != NULL) { + jaddref->ja_state |= ONWORKLIST; + LIST_INSERT_AFTER(LIST_FIRST(wkhd), &jaddref->ja_list, wk_list); + } else + WORKLIST_INSERT(wkhd, &jaddref->ja_list); + + return (needsj); +} + +/* + * Attempt to free a jaddref structure when some work completes. This + * should only succeed once the entry is written and all dependencies have + * been notified. + */ +static void +free_jaddref(jaddref) + struct jaddref *jaddref; +{ + + if ((jaddref->ja_state & ALLCOMPLETE) != ALLCOMPLETE) + return; + if (jaddref->ja_ref.if_jsegdep) + panic("free_jaddref: segdep attached to jaddref %p(0x%X)\n", + jaddref, jaddref->ja_state); + if (jaddref->ja_state & NEWBLOCK) + LIST_REMOVE(jaddref, ja_bmdeps); + if (jaddref->ja_state & (INPROGRESS | ONWORKLIST)) + panic("free_jaddref: Bad state %p(0x%X)", + jaddref, jaddref->ja_state); + if (jaddref->ja_mkdir != NULL) + panic("free_jaddref: Work pending, 0x%X\n", jaddref->ja_state); + WORKITEM_FREE(jaddref, D_JADDREF); +} + +/* + * Free a jremref structure once it has been written or discarded. + */ +static void +free_jremref(jremref) + struct jremref *jremref; +{ + + if (jremref->jr_ref.if_jsegdep) + free_jsegdep(jremref->jr_ref.if_jsegdep); + if (jremref->jr_state & INPROGRESS) + panic("free_jremref: IO still pending"); + WORKITEM_FREE(jremref, D_JREMREF); +} + +/* + * Free a jnewblk structure. + */ +static void +free_jnewblk(jnewblk) + struct jnewblk *jnewblk; +{ + + if ((jnewblk->jn_state & ALLCOMPLETE) != ALLCOMPLETE) + return; + LIST_REMOVE(jnewblk, jn_deps); + if (jnewblk->jn_dep != NULL) + panic("free_jnewblk: Dependency still attached."); + WORKITEM_FREE(jnewblk, D_JNEWBLK); +} + +/* + * Cancel a jnewblk which has been been made redundant by frag extension. + */ +static void +cancel_jnewblk(jnewblk, wkhd) + struct jnewblk *jnewblk; + struct workhead *wkhd; +{ + struct jsegdep *jsegdep; + + CTR1(KTR_SUJ, "cancel_jnewblk: blkno %jd", jnewblk->jn_blkno); + jsegdep = jnewblk->jn_jsegdep; + if (jnewblk->jn_jsegdep == NULL || jnewblk->jn_dep == NULL) + panic("cancel_jnewblk: Invalid state"); + jnewblk->jn_jsegdep = NULL; + jnewblk->jn_dep = NULL; + jnewblk->jn_state |= GOINGAWAY; + if (jnewblk->jn_state & INPROGRESS) { + jnewblk->jn_state &= ~INPROGRESS; + WORKLIST_REMOVE(&jnewblk->jn_list); + jwork_insert(wkhd, jsegdep); + } else { + free_jsegdep(jsegdep); + remove_from_journal(&jnewblk->jn_list); + } + wake_worklist(&jnewblk->jn_list); + WORKLIST_INSERT(wkhd, &jnewblk->jn_list); +} + +static void +free_jblkdep(jblkdep) + struct jblkdep *jblkdep; +{ + + if (jblkdep->jb_list.wk_type == D_JFREEBLK) + WORKITEM_FREE(jblkdep, D_JFREEBLK); + else if (jblkdep->jb_list.wk_type == D_JTRUNC) + WORKITEM_FREE(jblkdep, D_JTRUNC); + else + panic("free_jblkdep: Unexpected type %s", + TYPENAME(jblkdep->jb_list.wk_type)); +} + +/* + * Free a single jseg once it is no longer referenced in memory or on + * disk. Reclaim journal blocks and dependencies waiting for the segment + * to disappear. + */ +static void +free_jseg(jseg, jblocks) + struct jseg *jseg; + struct jblocks *jblocks; +{ + struct freework *freework; + + /* + * Free freework structures that were lingering to indicate freed + * indirect blocks that forced journal write ordering on reallocate. + */ + while ((freework = LIST_FIRST(&jseg->js_indirs)) != NULL) + indirblk_remove(freework); + if (jblocks->jb_oldestseg == jseg) + jblocks->jb_oldestseg = TAILQ_NEXT(jseg, js_next); + TAILQ_REMOVE(&jblocks->jb_segs, jseg, js_next); + jblocks_free(jblocks, jseg->js_list.wk_mp, jseg->js_size); + KASSERT(LIST_EMPTY(&jseg->js_entries), + ("free_jseg: Freed jseg has valid entries.")); + WORKITEM_FREE(jseg, D_JSEG); +} + +/* + * Free all jsegs that meet the criteria for being reclaimed and update + * oldestseg. + */ +static void +free_jsegs(jblocks) + struct jblocks *jblocks; +{ + struct jseg *jseg; + + /* + * Free only those jsegs which have none allocated before them to + * preserve the journal space ordering. + */ + while ((jseg = TAILQ_FIRST(&jblocks->jb_segs)) != NULL) { + /* + * Only reclaim space when nothing depends on this journal + * set and another set has written that it is no longer + * valid. + */ + if (jseg->js_refs != 0) { + jblocks->jb_oldestseg = jseg; + return; + } + if ((jseg->js_state & ALLCOMPLETE) != ALLCOMPLETE) + break; + if (jseg->js_seq > jblocks->jb_oldestwrseq) + break; + /* + * We can free jsegs that didn't write entries when + * oldestwrseq == js_seq. + */ + if (jseg->js_seq == jblocks->jb_oldestwrseq && + jseg->js_cnt != 0) + break; + free_jseg(jseg, jblocks); + } + /* + * If we exited the loop above we still must discover the + * oldest valid segment. + */ + if (jseg) + for (jseg = jblocks->jb_oldestseg; jseg != NULL; + jseg = TAILQ_NEXT(jseg, js_next)) + if (jseg->js_refs != 0) + break; + jblocks->jb_oldestseg = jseg; + /* + * The journal has no valid records but some jsegs may still be + * waiting on oldestwrseq to advance. We force a small record + * out to permit these lingering records to be reclaimed. + */ + if (jblocks->jb_oldestseg == NULL && !TAILQ_EMPTY(&jblocks->jb_segs)) + jblocks->jb_needseg = 1; +} + +/* + * Release one reference to a jseg and free it if the count reaches 0. This + * should eventually reclaim journal space as well. + */ +static void +rele_jseg(jseg) + struct jseg *jseg; +{ + + KASSERT(jseg->js_refs > 0, + ("free_jseg: Invalid refcnt %d", jseg->js_refs)); + if (--jseg->js_refs != 0) + return; + free_jsegs(jseg->js_jblocks); +} + +/* + * Release a jsegdep and decrement the jseg count. + */ +static void +free_jsegdep(jsegdep) + struct jsegdep *jsegdep; +{ + + if (jsegdep->jd_seg) + rele_jseg(jsegdep->jd_seg); + WORKITEM_FREE(jsegdep, D_JSEGDEP); +} + +/* + * Wait for a journal item to make it to disk. Initiate journal processing + * if required. + */ +static int +jwait(wk, waitfor) + struct worklist *wk; + int waitfor; +{ + + LOCK_OWNED(VFSTOUFS(wk->wk_mp)); + /* + * Blocking journal waits cause slow synchronous behavior. Record + * stats on the frequency of these blocking operations. + */ + if (waitfor == MNT_WAIT) { + stat_journal_wait++; + switch (wk->wk_type) { + case D_JREMREF: + case D_JMVREF: + stat_jwait_filepage++; + break; + case D_JTRUNC: + case D_JFREEBLK: + stat_jwait_freeblks++; + break; + case D_JNEWBLK: + stat_jwait_newblk++; + break; + case D_JADDREF: + stat_jwait_inode++; + break; + default: + break; + } + } + /* + * If IO has not started we process the journal. We can't mark the + * worklist item as IOWAITING because we drop the lock while + * processing the journal and the worklist entry may be freed after + * this point. The caller may call back in and re-issue the request. + */ + if ((wk->wk_state & INPROGRESS) == 0) { + softdep_process_journal(wk->wk_mp, wk, waitfor); + if (waitfor != MNT_WAIT) + return (EBUSY); + return (0); + } + if (waitfor != MNT_WAIT) + return (EBUSY); + wait_worklist(wk, "jwait"); + return (0); +} + +/* + * Lookup an inodedep based on an inode pointer and set the nlinkdelta as + * appropriate. This is a convenience function to reduce duplicate code + * for the setup and revert functions below. + */ +static struct inodedep * +inodedep_lookup_ip(ip) + struct inode *ip; +{ + struct inodedep *inodedep; + + KASSERT(ip->i_nlink >= ip->i_effnlink, + ("inodedep_lookup_ip: bad delta")); + (void) inodedep_lookup(ITOVFS(ip), ip->i_number, DEPALLOC, + &inodedep); + inodedep->id_nlinkdelta = ip->i_nlink - ip->i_effnlink; + KASSERT((inodedep->id_state & UNLINKED) == 0, ("inode unlinked")); + + return (inodedep); +} + +/* + * Called prior to creating a new inode and linking it to a directory. The + * jaddref structure must already be allocated by softdep_setup_inomapdep + * and it is discovered here so we can initialize the mode and update + * nlinkdelta. + */ +void +softdep_setup_create(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct inodedep *inodedep; + struct jaddref *jaddref; + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_setup_create called on non-softdep filesystem")); + KASSERT(ip->i_nlink == 1, + ("softdep_setup_create: Invalid link count.")); + dvp = ITOV(dp); + ACQUIRE_LOCK(ITOUMP(dp)); + inodedep = inodedep_lookup_ip(ip); + if (DOINGSUJ(dvp)) { + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, + ("softdep_setup_create: No addref structure present.")); + } + softdep_prelink(dvp, NULL); + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Create a jaddref structure to track the addition of a DOTDOT link when + * we are reparenting an inode as part of a rename. This jaddref will be + * found by softdep_setup_directory_change. Adjusts nlinkdelta for + * non-journaling softdep. + */ +void +softdep_setup_dotdot_link(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct inodedep *inodedep; + struct jaddref *jaddref; + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_setup_dotdot_link called on non-softdep filesystem")); + dvp = ITOV(dp); + jaddref = NULL; + /* + * We don't set MKDIR_PARENT as this is not tied to a mkdir and + * is used as a normal link would be. + */ + if (DOINGSUJ(dvp)) + jaddref = newjaddref(ip, dp->i_number, DOTDOT_OFFSET, + dp->i_effnlink - 1, dp->i_mode); + ACQUIRE_LOCK(ITOUMP(dp)); + inodedep = inodedep_lookup_ip(dp); + if (jaddref) + TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, &jaddref->ja_ref, + if_deps); + softdep_prelink(dvp, ITOV(ip)); + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Create a jaddref structure to track a new link to an inode. The directory + * offset is not known until softdep_setup_directory_add or + * softdep_setup_directory_change. Adjusts nlinkdelta for non-journaling + * softdep. + */ +void +softdep_setup_link(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct inodedep *inodedep; + struct jaddref *jaddref; + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_setup_link called on non-softdep filesystem")); + dvp = ITOV(dp); + jaddref = NULL; + if (DOINGSUJ(dvp)) + jaddref = newjaddref(dp, ip->i_number, 0, ip->i_effnlink - 1, + ip->i_mode); + ACQUIRE_LOCK(ITOUMP(dp)); + inodedep = inodedep_lookup_ip(ip); + if (jaddref) + TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, &jaddref->ja_ref, + if_deps); + softdep_prelink(dvp, ITOV(ip)); + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Called to create the jaddref structures to track . and .. references as + * well as lookup and further initialize the incomplete jaddref created + * by softdep_setup_inomapdep when the inode was allocated. Adjusts + * nlinkdelta for non-journaling softdep. + */ +void +softdep_setup_mkdir(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct inodedep *inodedep; + struct jaddref *dotdotaddref; + struct jaddref *dotaddref; + struct jaddref *jaddref; + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_setup_mkdir called on non-softdep filesystem")); + dvp = ITOV(dp); + dotaddref = dotdotaddref = NULL; + if (DOINGSUJ(dvp)) { + dotaddref = newjaddref(ip, ip->i_number, DOT_OFFSET, 1, + ip->i_mode); + dotaddref->ja_state |= MKDIR_BODY; + dotdotaddref = newjaddref(ip, dp->i_number, DOTDOT_OFFSET, + dp->i_effnlink - 1, dp->i_mode); + dotdotaddref->ja_state |= MKDIR_PARENT; + } + ACQUIRE_LOCK(ITOUMP(dp)); + inodedep = inodedep_lookup_ip(ip); + if (DOINGSUJ(dvp)) { + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref != NULL, + ("softdep_setup_mkdir: No addref structure present.")); + KASSERT(jaddref->ja_parent == dp->i_number, + ("softdep_setup_mkdir: bad parent %ju", + (uintmax_t)jaddref->ja_parent)); + TAILQ_INSERT_BEFORE(&jaddref->ja_ref, &dotaddref->ja_ref, + if_deps); + } + inodedep = inodedep_lookup_ip(dp); + if (DOINGSUJ(dvp)) + TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, + &dotdotaddref->ja_ref, if_deps); + softdep_prelink(ITOV(dp), NULL); + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Called to track nlinkdelta of the inode and parent directories prior to + * unlinking a directory. + */ +void +softdep_setup_rmdir(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_setup_rmdir called on non-softdep filesystem")); + dvp = ITOV(dp); + ACQUIRE_LOCK(ITOUMP(dp)); + (void) inodedep_lookup_ip(ip); + (void) inodedep_lookup_ip(dp); + softdep_prelink(dvp, ITOV(ip)); + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Called to track nlinkdelta of the inode and parent directories prior to + * unlink. + */ +void +softdep_setup_unlink(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_setup_unlink called on non-softdep filesystem")); + dvp = ITOV(dp); + ACQUIRE_LOCK(ITOUMP(dp)); + (void) inodedep_lookup_ip(ip); + (void) inodedep_lookup_ip(dp); + softdep_prelink(dvp, ITOV(ip)); + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Called to release the journal structures created by a failed non-directory + * creation. Adjusts nlinkdelta for non-journaling softdep. + */ +void +softdep_revert_create(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct inodedep *inodedep; + struct jaddref *jaddref; + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS((dp))) != 0, + ("softdep_revert_create called on non-softdep filesystem")); + dvp = ITOV(dp); + ACQUIRE_LOCK(ITOUMP(dp)); + inodedep = inodedep_lookup_ip(ip); + if (DOINGSUJ(dvp)) { + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref->ja_parent == dp->i_number, + ("softdep_revert_create: addref parent mismatch")); + cancel_jaddref(jaddref, inodedep, &inodedep->id_inowait); + } + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Called to release the journal structures created by a failed link + * addition. Adjusts nlinkdelta for non-journaling softdep. + */ +void +softdep_revert_link(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct inodedep *inodedep; + struct jaddref *jaddref; + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_revert_link called on non-softdep filesystem")); + dvp = ITOV(dp); + ACQUIRE_LOCK(ITOUMP(dp)); + inodedep = inodedep_lookup_ip(ip); + if (DOINGSUJ(dvp)) { + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref->ja_parent == dp->i_number, + ("softdep_revert_link: addref parent mismatch")); + cancel_jaddref(jaddref, inodedep, &inodedep->id_inowait); + } + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Called to release the journal structures created by a failed mkdir + * attempt. Adjusts nlinkdelta for non-journaling softdep. + */ +void +softdep_revert_mkdir(dp, ip) + struct inode *dp; + struct inode *ip; +{ + struct inodedep *inodedep; + struct jaddref *jaddref; + struct jaddref *dotaddref; + struct vnode *dvp; + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_revert_mkdir called on non-softdep filesystem")); + dvp = ITOV(dp); + + ACQUIRE_LOCK(ITOUMP(dp)); + inodedep = inodedep_lookup_ip(dp); + if (DOINGSUJ(dvp)) { + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref->ja_parent == ip->i_number, + ("softdep_revert_mkdir: dotdot addref parent mismatch")); + cancel_jaddref(jaddref, inodedep, &inodedep->id_inowait); + } + inodedep = inodedep_lookup_ip(ip); + if (DOINGSUJ(dvp)) { + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref->ja_parent == dp->i_number, + ("softdep_revert_mkdir: addref parent mismatch")); + dotaddref = (struct jaddref *)TAILQ_PREV(&jaddref->ja_ref, + inoreflst, if_deps); + cancel_jaddref(jaddref, inodedep, &inodedep->id_inowait); + KASSERT(dotaddref->ja_parent == ip->i_number, + ("softdep_revert_mkdir: dot addref parent mismatch")); + cancel_jaddref(dotaddref, inodedep, &inodedep->id_inowait); + } + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Called to correct nlinkdelta after a failed rmdir. + */ +void +softdep_revert_rmdir(dp, ip) + struct inode *dp; + struct inode *ip; +{ + + KASSERT(MOUNTEDSOFTDEP(ITOVFS(dp)) != 0, + ("softdep_revert_rmdir called on non-softdep filesystem")); + ACQUIRE_LOCK(ITOUMP(dp)); + (void) inodedep_lookup_ip(ip); + (void) inodedep_lookup_ip(dp); + FREE_LOCK(ITOUMP(dp)); +} + +/* + * Protecting the freemaps (or bitmaps). + * + * To eliminate the need to execute fsck before mounting a filesystem + * after a power failure, one must (conservatively) guarantee that the + * on-disk copy of the bitmaps never indicate that a live inode or block is + * free. So, when a block or inode is allocated, the bitmap should be + * updated (on disk) before any new pointers. When a block or inode is + * freed, the bitmap should not be updated until all pointers have been + * reset. The latter dependency is handled by the delayed de-allocation + * approach described below for block and inode de-allocation. The former + * dependency is handled by calling the following procedure when a block or + * inode is allocated. When an inode is allocated an "inodedep" is created + * with its DEPCOMPLETE flag cleared until its bitmap is written to disk. + * Each "inodedep" is also inserted into the hash indexing structure so + * that any additional link additions can be made dependent on the inode + * allocation. + * + * The ufs filesystem maintains a number of free block counts (e.g., per + * cylinder group, per cylinder and per pair) + * in addition to the bitmaps. These counts are used to improve efficiency + * during allocation and therefore must be consistent with the bitmaps. + * There is no convenient way to guarantee post-crash consistency of these + * counts with simple update ordering, for two main reasons: (1) The counts + * and bitmaps for a single cylinder group block are not in the same disk + * sector. If a disk write is interrupted (e.g., by power failure), one may + * be written and the other not. (2) Some of the counts are located in the + * superblock rather than the cylinder group block. So, we focus our soft + * updates implementation on protecting the bitmaps. When mounting a + * filesystem, we recompute the auxiliary counts from the bitmaps. + */ + +/* + * Called just after updating the cylinder group block to allocate an inode. + */ +void +softdep_setup_inomapdep(bp, ip, newinum, mode) + struct buf *bp; /* buffer for cylgroup block with inode map */ + struct inode *ip; /* inode related to allocation */ + ino_t newinum; /* new inode number being allocated */ + int mode; +{ + struct inodedep *inodedep; + struct bmsafemap *bmsafemap; + struct jaddref *jaddref; + struct mount *mp; + struct fs *fs; + + mp = ITOVFS(ip); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_inomapdep called on non-softdep filesystem")); + fs = VFSTOUFS(mp)->um_fs; + jaddref = NULL; + + /* + * Allocate the journal reference add structure so that the bitmap + * can be dependent on it. + */ + if (MOUNTEDSUJ(mp)) { + jaddref = newjaddref(ip, newinum, 0, 0, mode); + jaddref->ja_state |= NEWBLOCK; + } + + /* + * Create a dependency for the newly allocated inode. + * Panic if it already exists as something is seriously wrong. + * Otherwise add it to the dependency list for the buffer holding + * the cylinder group map from which it was allocated. + * + * We have to preallocate a bmsafemap entry in case it is needed + * in bmsafemap_lookup since once we allocate the inodedep, we + * have to finish initializing it before we can FREE_LOCK(). + * By preallocating, we avoid FREE_LOCK() while doing a malloc + * in bmsafemap_lookup. We cannot call bmsafemap_lookup before + * creating the inodedep as it can be freed during the time + * that we FREE_LOCK() while allocating the inodedep. We must + * call workitem_alloc() before entering the locked section as + * it also acquires the lock and we must avoid trying doing so + * recursively. + */ + bmsafemap = malloc(sizeof(struct bmsafemap), + M_BMSAFEMAP, M_SOFTDEP_FLAGS); + workitem_alloc(&bmsafemap->sm_list, D_BMSAFEMAP, mp); + ACQUIRE_LOCK(ITOUMP(ip)); + if ((inodedep_lookup(mp, newinum, DEPALLOC, &inodedep))) + panic("softdep_setup_inomapdep: dependency %p for new" + "inode already exists", inodedep); + bmsafemap = bmsafemap_lookup(mp, bp, ino_to_cg(fs, newinum), bmsafemap); + if (jaddref) { + LIST_INSERT_HEAD(&bmsafemap->sm_jaddrefhd, jaddref, ja_bmdeps); + TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, &jaddref->ja_ref, + if_deps); + } else { + inodedep->id_state |= ONDEPLIST; + LIST_INSERT_HEAD(&bmsafemap->sm_inodedephd, inodedep, id_deps); + } + inodedep->id_bmsafemap = bmsafemap; + inodedep->id_state &= ~DEPCOMPLETE; + FREE_LOCK(ITOUMP(ip)); +} + +/* + * Called just after updating the cylinder group block to + * allocate block or fragment. + */ +void +softdep_setup_blkmapdep(bp, mp, newblkno, frags, oldfrags) + struct buf *bp; /* buffer for cylgroup block with block map */ + struct mount *mp; /* filesystem doing allocation */ + ufs2_daddr_t newblkno; /* number of newly allocated block */ + int frags; /* Number of fragments. */ + int oldfrags; /* Previous number of fragments for extend. */ +{ + struct newblk *newblk; + struct bmsafemap *bmsafemap; + struct jnewblk *jnewblk; + struct ufsmount *ump; + struct fs *fs; + + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_blkmapdep called on non-softdep filesystem")); + ump = VFSTOUFS(mp); + fs = ump->um_fs; + jnewblk = NULL; + /* + * Create a dependency for the newly allocated block. + * Add it to the dependency list for the buffer holding + * the cylinder group map from which it was allocated. + */ + if (MOUNTEDSUJ(mp)) { + jnewblk = malloc(sizeof(*jnewblk), M_JNEWBLK, M_SOFTDEP_FLAGS); + workitem_alloc(&jnewblk->jn_list, D_JNEWBLK, mp); + jnewblk->jn_jsegdep = newjsegdep(&jnewblk->jn_list); + jnewblk->jn_state = ATTACHED; + jnewblk->jn_blkno = newblkno; + jnewblk->jn_frags = frags; + jnewblk->jn_oldfrags = oldfrags; +#ifdef SUJ_DEBUG + { + struct cg *cgp; + uint8_t *blksfree; + long bno; + int i; + + cgp = (struct cg *)bp->b_data; + blksfree = cg_blksfree(cgp); + bno = dtogd(fs, jnewblk->jn_blkno); + for (i = jnewblk->jn_oldfrags; i < jnewblk->jn_frags; + i++) { + if (isset(blksfree, bno + i)) + panic("softdep_setup_blkmapdep: " + "free fragment %d from %d-%d " + "state 0x%X dep %p", i, + jnewblk->jn_oldfrags, + jnewblk->jn_frags, + jnewblk->jn_state, + jnewblk->jn_dep); + } + } +#endif + } + + CTR3(KTR_SUJ, + "softdep_setup_blkmapdep: blkno %jd frags %d oldfrags %d", + newblkno, frags, oldfrags); + ACQUIRE_LOCK(ump); + if (newblk_lookup(mp, newblkno, DEPALLOC, &newblk) != 0) + panic("softdep_setup_blkmapdep: found block"); + newblk->nb_bmsafemap = bmsafemap = bmsafemap_lookup(mp, bp, + dtog(fs, newblkno), NULL); + if (jnewblk) { + jnewblk->jn_dep = (struct worklist *)newblk; + LIST_INSERT_HEAD(&bmsafemap->sm_jnewblkhd, jnewblk, jn_deps); + } else { + newblk->nb_state |= ONDEPLIST; + LIST_INSERT_HEAD(&bmsafemap->sm_newblkhd, newblk, nb_deps); + } + newblk->nb_bmsafemap = bmsafemap; + newblk->nb_jnewblk = jnewblk; + FREE_LOCK(ump); +} + +#define BMSAFEMAP_HASH(ump, cg) \ + (&(ump)->bmsafemap_hashtbl[(cg) & (ump)->bmsafemap_hash_size]) + +static int +bmsafemap_find(bmsafemaphd, cg, bmsafemapp) + struct bmsafemap_hashhead *bmsafemaphd; + int cg; + struct bmsafemap **bmsafemapp; +{ + struct bmsafemap *bmsafemap; + + LIST_FOREACH(bmsafemap, bmsafemaphd, sm_hash) + if (bmsafemap->sm_cg == cg) + break; + if (bmsafemap) { + *bmsafemapp = bmsafemap; + return (1); + } + *bmsafemapp = NULL; + + return (0); +} + +/* + * Find the bmsafemap associated with a cylinder group buffer. + * If none exists, create one. The buffer must be locked when + * this routine is called and this routine must be called with + * the softdep lock held. To avoid giving up the lock while + * allocating a new bmsafemap, a preallocated bmsafemap may be + * provided. If it is provided but not needed, it is freed. + */ +static struct bmsafemap * +bmsafemap_lookup(mp, bp, cg, newbmsafemap) + struct mount *mp; + struct buf *bp; + int cg; + struct bmsafemap *newbmsafemap; +{ + struct bmsafemap_hashhead *bmsafemaphd; + struct bmsafemap *bmsafemap, *collision; + struct worklist *wk; + struct ufsmount *ump; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + KASSERT(bp != NULL, ("bmsafemap_lookup: missing buffer")); + LIST_FOREACH(wk, &bp->b_dep, wk_list) { + if (wk->wk_type == D_BMSAFEMAP) { + if (newbmsafemap) + WORKITEM_FREE(newbmsafemap, D_BMSAFEMAP); + return (WK_BMSAFEMAP(wk)); + } + } + bmsafemaphd = BMSAFEMAP_HASH(ump, cg); + if (bmsafemap_find(bmsafemaphd, cg, &bmsafemap) == 1) { + if (newbmsafemap) + WORKITEM_FREE(newbmsafemap, D_BMSAFEMAP); + return (bmsafemap); + } + if (newbmsafemap) { + bmsafemap = newbmsafemap; + } else { + FREE_LOCK(ump); + bmsafemap = malloc(sizeof(struct bmsafemap), + M_BMSAFEMAP, M_SOFTDEP_FLAGS); + workitem_alloc(&bmsafemap->sm_list, D_BMSAFEMAP, mp); + ACQUIRE_LOCK(ump); + } + bmsafemap->sm_buf = bp; + LIST_INIT(&bmsafemap->sm_inodedephd); + LIST_INIT(&bmsafemap->sm_inodedepwr); + LIST_INIT(&bmsafemap->sm_newblkhd); + LIST_INIT(&bmsafemap->sm_newblkwr); + LIST_INIT(&bmsafemap->sm_jaddrefhd); + LIST_INIT(&bmsafemap->sm_jnewblkhd); + LIST_INIT(&bmsafemap->sm_freehd); + LIST_INIT(&bmsafemap->sm_freewr); + if (bmsafemap_find(bmsafemaphd, cg, &collision) == 1) { + WORKITEM_FREE(bmsafemap, D_BMSAFEMAP); + return (collision); + } + bmsafemap->sm_cg = cg; + LIST_INSERT_HEAD(bmsafemaphd, bmsafemap, sm_hash); + LIST_INSERT_HEAD(&ump->softdep_dirtycg, bmsafemap, sm_next); + WORKLIST_INSERT(&bp->b_dep, &bmsafemap->sm_list); + return (bmsafemap); +} + +/* + * Direct block allocation dependencies. + * + * When a new block is allocated, the corresponding disk locations must be + * initialized (with zeros or new data) before the on-disk inode points to + * them. Also, the freemap from which the block was allocated must be + * updated (on disk) before the inode's pointer. These two dependencies are + * independent of each other and are needed for all file blocks and indirect + * blocks that are pointed to directly by the inode. Just before the + * "in-core" version of the inode is updated with a newly allocated block + * number, a procedure (below) is called to setup allocation dependency + * structures. These structures are removed when the corresponding + * dependencies are satisfied or when the block allocation becomes obsolete + * (i.e., the file is deleted, the block is de-allocated, or the block is a + * fragment that gets upgraded). All of these cases are handled in + * procedures described later. + * + * When a file extension causes a fragment to be upgraded, either to a larger + * fragment or to a full block, the on-disk location may change (if the + * previous fragment could not simply be extended). In this case, the old + * fragment must be de-allocated, but not until after the inode's pointer has + * been updated. In most cases, this is handled by later procedures, which + * will construct a "freefrag" structure to be added to the workitem queue + * when the inode update is complete (or obsolete). The main exception to + * this is when an allocation occurs while a pending allocation dependency + * (for the same block pointer) remains. This case is handled in the main + * allocation dependency setup procedure by immediately freeing the + * unreferenced fragments. + */ +void +softdep_setup_allocdirect(ip, off, newblkno, oldblkno, newsize, oldsize, bp) + struct inode *ip; /* inode to which block is being added */ + ufs_lbn_t off; /* block pointer within inode */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 unless frag */ + long newsize; /* size of new block */ + long oldsize; /* size of new block */ + struct buf *bp; /* bp for allocated block */ +{ + struct allocdirect *adp, *oldadp; + struct allocdirectlst *adphead; + struct freefrag *freefrag; + struct inodedep *inodedep; + struct pagedep *pagedep; + struct jnewblk *jnewblk; + struct newblk *newblk; + struct mount *mp; + ufs_lbn_t lbn; + + lbn = bp->b_lblkno; + mp = ITOVFS(ip); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_allocdirect called on non-softdep filesystem")); + if (oldblkno && oldblkno != newblkno) + freefrag = newfreefrag(ip, oldblkno, oldsize, lbn); + else + freefrag = NULL; + + CTR6(KTR_SUJ, + "softdep_setup_allocdirect: ino %d blkno %jd oldblkno %jd " + "off %jd newsize %ld oldsize %d", + ip->i_number, newblkno, oldblkno, off, newsize, oldsize); + ACQUIRE_LOCK(ITOUMP(ip)); + if (off >= NDADDR) { + if (lbn > 0) + panic("softdep_setup_allocdirect: bad lbn %jd, off %jd", + lbn, off); + /* allocating an indirect block */ + if (oldblkno != 0) + panic("softdep_setup_allocdirect: non-zero indir"); + } else { + if (off != lbn) + panic("softdep_setup_allocdirect: lbn %jd != off %jd", + lbn, off); + /* + * Allocating a direct block. + * + * If we are allocating a directory block, then we must + * allocate an associated pagedep to track additions and + * deletions. + */ + if ((ip->i_mode & IFMT) == IFDIR) + pagedep_lookup(mp, bp, ip->i_number, off, DEPALLOC, + &pagedep); + } + if (newblk_lookup(mp, newblkno, 0, &newblk) == 0) + panic("softdep_setup_allocdirect: lost block"); + KASSERT(newblk->nb_list.wk_type == D_NEWBLK, + ("softdep_setup_allocdirect: newblk already initialized")); + /* + * Convert the newblk to an allocdirect. + */ + WORKITEM_REASSIGN(newblk, D_ALLOCDIRECT); + adp = (struct allocdirect *)newblk; + newblk->nb_freefrag = freefrag; + adp->ad_offset = off; + adp->ad_oldblkno = oldblkno; + adp->ad_newsize = newsize; + adp->ad_oldsize = oldsize; + + /* + * Finish initializing the journal. + */ + if ((jnewblk = newblk->nb_jnewblk) != NULL) { + jnewblk->jn_ino = ip->i_number; + jnewblk->jn_lbn = lbn; + add_to_journal(&jnewblk->jn_list); + } + if (freefrag && freefrag->ff_jdep != NULL && + freefrag->ff_jdep->wk_type == D_JFREEFRAG) + add_to_journal(freefrag->ff_jdep); + inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); + adp->ad_inodedep = inodedep; + + WORKLIST_INSERT(&bp->b_dep, &newblk->nb_list); + /* + * The list of allocdirects must be kept in sorted and ascending + * order so that the rollback routines can quickly determine the + * first uncommitted block (the size of the file stored on disk + * ends at the end of the lowest committed fragment, or if there + * are no fragments, at the end of the highest committed block). + * Since files generally grow, the typical case is that the new + * block is to be added at the end of the list. We speed this + * special case by checking against the last allocdirect in the + * list before laboriously traversing the list looking for the + * insertion point. + */ + adphead = &inodedep->id_newinoupdt; + oldadp = TAILQ_LAST(adphead, allocdirectlst); + if (oldadp == NULL || oldadp->ad_offset <= off) { + /* insert at end of list */ + TAILQ_INSERT_TAIL(adphead, adp, ad_next); + if (oldadp != NULL && oldadp->ad_offset == off) + allocdirect_merge(adphead, adp, oldadp); + FREE_LOCK(ITOUMP(ip)); + return; + } + TAILQ_FOREACH(oldadp, adphead, ad_next) { + if (oldadp->ad_offset >= off) + break; + } + if (oldadp == NULL) + panic("softdep_setup_allocdirect: lost entry"); + /* insert in middle of list */ + TAILQ_INSERT_BEFORE(oldadp, adp, ad_next); + if (oldadp->ad_offset == off) + allocdirect_merge(adphead, adp, oldadp); + + FREE_LOCK(ITOUMP(ip)); +} + +/* + * Merge a newer and older journal record to be stored either in a + * newblock or freefrag. This handles aggregating journal records for + * fragment allocation into a second record as well as replacing a + * journal free with an aborted journal allocation. A segment for the + * oldest record will be placed on wkhd if it has been written. If not + * the segment for the newer record will suffice. + */ +static struct worklist * +jnewblk_merge(new, old, wkhd) + struct worklist *new; + struct worklist *old; + struct workhead *wkhd; +{ + struct jnewblk *njnewblk; + struct jnewblk *jnewblk; + + /* Handle NULLs to simplify callers. */ + if (new == NULL) + return (old); + if (old == NULL) + return (new); + /* Replace a jfreefrag with a jnewblk. */ + if (new->wk_type == D_JFREEFRAG) { + if (WK_JNEWBLK(old)->jn_blkno != WK_JFREEFRAG(new)->fr_blkno) + panic("jnewblk_merge: blkno mismatch: %p, %p", + old, new); + cancel_jfreefrag(WK_JFREEFRAG(new)); + return (old); + } + if (old->wk_type != D_JNEWBLK || new->wk_type != D_JNEWBLK) + panic("jnewblk_merge: Bad type: old %d new %d\n", + old->wk_type, new->wk_type); + /* + * Handle merging of two jnewblk records that describe + * different sets of fragments in the same block. + */ + jnewblk = WK_JNEWBLK(old); + njnewblk = WK_JNEWBLK(new); + if (jnewblk->jn_blkno != njnewblk->jn_blkno) + panic("jnewblk_merge: Merging disparate blocks."); + /* + * The record may be rolled back in the cg. + */ + if (jnewblk->jn_state & UNDONE) { + jnewblk->jn_state &= ~UNDONE; + njnewblk->jn_state |= UNDONE; + njnewblk->jn_state &= ~ATTACHED; + } + /* + * We modify the newer addref and free the older so that if neither + * has been written the most up-to-date copy will be on disk. If + * both have been written but rolled back we only temporarily need + * one of them to fix the bits when the cg write completes. + */ + jnewblk->jn_state |= ATTACHED | COMPLETE; + njnewblk->jn_oldfrags = jnewblk->jn_oldfrags; + cancel_jnewblk(jnewblk, wkhd); + WORKLIST_REMOVE(&jnewblk->jn_list); + free_jnewblk(jnewblk); + return (new); +} + +/* + * Replace an old allocdirect dependency with a newer one. + * This routine must be called with splbio interrupts blocked. + */ +static void +allocdirect_merge(adphead, newadp, oldadp) + struct allocdirectlst *adphead; /* head of list holding allocdirects */ + struct allocdirect *newadp; /* allocdirect being added */ + struct allocdirect *oldadp; /* existing allocdirect being checked */ +{ + struct worklist *wk; + struct freefrag *freefrag; + + freefrag = NULL; + LOCK_OWNED(VFSTOUFS(newadp->ad_list.wk_mp)); + if (newadp->ad_oldblkno != oldadp->ad_newblkno || + newadp->ad_oldsize != oldadp->ad_newsize || + newadp->ad_offset >= NDADDR) + panic("%s %jd != new %jd || old size %ld != new %ld", + "allocdirect_merge: old blkno", + (intmax_t)newadp->ad_oldblkno, + (intmax_t)oldadp->ad_newblkno, + newadp->ad_oldsize, oldadp->ad_newsize); + newadp->ad_oldblkno = oldadp->ad_oldblkno; + newadp->ad_oldsize = oldadp->ad_oldsize; + /* + * If the old dependency had a fragment to free or had never + * previously had a block allocated, then the new dependency + * can immediately post its freefrag and adopt the old freefrag. + * This action is done by swapping the freefrag dependencies. + * The new dependency gains the old one's freefrag, and the + * old one gets the new one and then immediately puts it on + * the worklist when it is freed by free_newblk. It is + * not possible to do this swap when the old dependency had a + * non-zero size but no previous fragment to free. This condition + * arises when the new block is an extension of the old block. + * Here, the first part of the fragment allocated to the new + * dependency is part of the block currently claimed on disk by + * the old dependency, so cannot legitimately be freed until the + * conditions for the new dependency are fulfilled. + */ + freefrag = newadp->ad_freefrag; + if (oldadp->ad_freefrag != NULL || oldadp->ad_oldblkno == 0) { + newadp->ad_freefrag = oldadp->ad_freefrag; + oldadp->ad_freefrag = freefrag; + } + /* + * If we are tracking a new directory-block allocation, + * move it from the old allocdirect to the new allocdirect. + */ + if ((wk = LIST_FIRST(&oldadp->ad_newdirblk)) != NULL) { + WORKLIST_REMOVE(wk); + if (!LIST_EMPTY(&oldadp->ad_newdirblk)) + panic("allocdirect_merge: extra newdirblk"); + WORKLIST_INSERT(&newadp->ad_newdirblk, wk); + } + TAILQ_REMOVE(adphead, oldadp, ad_next); + /* + * We need to move any journal dependencies over to the freefrag + * that releases this block if it exists. Otherwise we are + * extending an existing block and we'll wait until that is + * complete to release the journal space and extend the + * new journal to cover this old space as well. + */ + if (freefrag == NULL) { + if (oldadp->ad_newblkno != newadp->ad_newblkno) + panic("allocdirect_merge: %jd != %jd", + oldadp->ad_newblkno, newadp->ad_newblkno); + newadp->ad_block.nb_jnewblk = (struct jnewblk *) + jnewblk_merge(&newadp->ad_block.nb_jnewblk->jn_list, + &oldadp->ad_block.nb_jnewblk->jn_list, + &newadp->ad_block.nb_jwork); + oldadp->ad_block.nb_jnewblk = NULL; + cancel_newblk(&oldadp->ad_block, NULL, + &newadp->ad_block.nb_jwork); + } else { + wk = (struct worklist *) cancel_newblk(&oldadp->ad_block, + &freefrag->ff_list, &freefrag->ff_jwork); + freefrag->ff_jdep = jnewblk_merge(freefrag->ff_jdep, wk, + &freefrag->ff_jwork); + } + free_newblk(&oldadp->ad_block); +} + +/* + * Allocate a jfreefrag structure to journal a single block free. + */ +static struct jfreefrag * +newjfreefrag(freefrag, ip, blkno, size, lbn) + struct freefrag *freefrag; + struct inode *ip; + ufs2_daddr_t blkno; + long size; + ufs_lbn_t lbn; +{ + struct jfreefrag *jfreefrag; + struct fs *fs; + + fs = ITOFS(ip); + jfreefrag = malloc(sizeof(struct jfreefrag), M_JFREEFRAG, + M_SOFTDEP_FLAGS); + workitem_alloc(&jfreefrag->fr_list, D_JFREEFRAG, ITOVFS(ip)); + jfreefrag->fr_jsegdep = newjsegdep(&jfreefrag->fr_list); + jfreefrag->fr_state = ATTACHED | DEPCOMPLETE; + jfreefrag->fr_ino = ip->i_number; + jfreefrag->fr_lbn = lbn; + jfreefrag->fr_blkno = blkno; + jfreefrag->fr_frags = numfrags(fs, size); + jfreefrag->fr_freefrag = freefrag; + + return (jfreefrag); +} + +/* + * Allocate a new freefrag structure. + */ +static struct freefrag * +newfreefrag(ip, blkno, size, lbn) + struct inode *ip; + ufs2_daddr_t blkno; + long size; + ufs_lbn_t lbn; +{ + struct freefrag *freefrag; + struct ufsmount *ump; + struct fs *fs; + + CTR4(KTR_SUJ, "newfreefrag: ino %d blkno %jd size %ld lbn %jd", + ip->i_number, blkno, size, lbn); + ump = ITOUMP(ip); + fs = ump->um_fs; + if (fragnum(fs, blkno) + numfrags(fs, size) > fs->fs_frag) + panic("newfreefrag: frag size"); + freefrag = malloc(sizeof(struct freefrag), + M_FREEFRAG, M_SOFTDEP_FLAGS); + workitem_alloc(&freefrag->ff_list, D_FREEFRAG, UFSTOVFS(ump)); + freefrag->ff_state = ATTACHED; + LIST_INIT(&freefrag->ff_jwork); + freefrag->ff_inum = ip->i_number; + freefrag->ff_vtype = ITOV(ip)->v_type; + freefrag->ff_blkno = blkno; + freefrag->ff_fragsize = size; + + if (MOUNTEDSUJ(UFSTOVFS(ump))) { + freefrag->ff_jdep = (struct worklist *) + newjfreefrag(freefrag, ip, blkno, size, lbn); + } else { + freefrag->ff_state |= DEPCOMPLETE; + freefrag->ff_jdep = NULL; + } + + return (freefrag); +} + +/* + * This workitem de-allocates fragments that were replaced during + * file block allocation. + */ +static void +handle_workitem_freefrag(freefrag) + struct freefrag *freefrag; +{ + struct ufsmount *ump = VFSTOUFS(freefrag->ff_list.wk_mp); + struct workhead wkhd; + + CTR3(KTR_SUJ, + "handle_workitem_freefrag: ino %d blkno %jd size %ld", + freefrag->ff_inum, freefrag->ff_blkno, freefrag->ff_fragsize); + /* + * It would be illegal to add new completion items to the + * freefrag after it was schedule to be done so it must be + * safe to modify the list head here. + */ + LIST_INIT(&wkhd); + ACQUIRE_LOCK(ump); + LIST_SWAP(&freefrag->ff_jwork, &wkhd, worklist, wk_list); + /* + * If the journal has not been written we must cancel it here. + */ + if (freefrag->ff_jdep) { + if (freefrag->ff_jdep->wk_type != D_JNEWBLK) + panic("handle_workitem_freefrag: Unexpected type %d\n", + freefrag->ff_jdep->wk_type); + cancel_jnewblk(WK_JNEWBLK(freefrag->ff_jdep), &wkhd); + } + FREE_LOCK(ump); + ffs_blkfree(ump, ump->um_fs, ump->um_devvp, freefrag->ff_blkno, + freefrag->ff_fragsize, freefrag->ff_inum, freefrag->ff_vtype, &wkhd); + ACQUIRE_LOCK(ump); + WORKITEM_FREE(freefrag, D_FREEFRAG); + FREE_LOCK(ump); +} + +/* + * Set up a dependency structure for an external attributes data block. + * This routine follows much of the structure of softdep_setup_allocdirect. + * See the description of softdep_setup_allocdirect above for details. + */ +void +softdep_setup_allocext(ip, off, newblkno, oldblkno, newsize, oldsize, bp) + struct inode *ip; + ufs_lbn_t off; + ufs2_daddr_t newblkno; + ufs2_daddr_t oldblkno; + long newsize; + long oldsize; + struct buf *bp; +{ + struct allocdirect *adp, *oldadp; + struct allocdirectlst *adphead; + struct freefrag *freefrag; + struct inodedep *inodedep; + struct jnewblk *jnewblk; + struct newblk *newblk; + struct mount *mp; + struct ufsmount *ump; + ufs_lbn_t lbn; + + mp = ITOVFS(ip); + ump = VFSTOUFS(mp); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_allocext called on non-softdep filesystem")); + KASSERT(off < NXADDR, ("softdep_setup_allocext: lbn %lld > NXADDR", + (long long)off)); + + lbn = bp->b_lblkno; + if (oldblkno && oldblkno != newblkno) + freefrag = newfreefrag(ip, oldblkno, oldsize, lbn); + else + freefrag = NULL; + + ACQUIRE_LOCK(ump); + if (newblk_lookup(mp, newblkno, 0, &newblk) == 0) + panic("softdep_setup_allocext: lost block"); + KASSERT(newblk->nb_list.wk_type == D_NEWBLK, + ("softdep_setup_allocext: newblk already initialized")); + /* + * Convert the newblk to an allocdirect. + */ + WORKITEM_REASSIGN(newblk, D_ALLOCDIRECT); + adp = (struct allocdirect *)newblk; + newblk->nb_freefrag = freefrag; + adp->ad_offset = off; + adp->ad_oldblkno = oldblkno; + adp->ad_newsize = newsize; + adp->ad_oldsize = oldsize; + adp->ad_state |= EXTDATA; + + /* + * Finish initializing the journal. + */ + if ((jnewblk = newblk->nb_jnewblk) != NULL) { + jnewblk->jn_ino = ip->i_number; + jnewblk->jn_lbn = lbn; + add_to_journal(&jnewblk->jn_list); + } + if (freefrag && freefrag->ff_jdep != NULL && + freefrag->ff_jdep->wk_type == D_JFREEFRAG) + add_to_journal(freefrag->ff_jdep); + inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); + adp->ad_inodedep = inodedep; + + WORKLIST_INSERT(&bp->b_dep, &newblk->nb_list); + /* + * The list of allocdirects must be kept in sorted and ascending + * order so that the rollback routines can quickly determine the + * first uncommitted block (the size of the file stored on disk + * ends at the end of the lowest committed fragment, or if there + * are no fragments, at the end of the highest committed block). + * Since files generally grow, the typical case is that the new + * block is to be added at the end of the list. We speed this + * special case by checking against the last allocdirect in the + * list before laboriously traversing the list looking for the + * insertion point. + */ + adphead = &inodedep->id_newextupdt; + oldadp = TAILQ_LAST(adphead, allocdirectlst); + if (oldadp == NULL || oldadp->ad_offset <= off) { + /* insert at end of list */ + TAILQ_INSERT_TAIL(adphead, adp, ad_next); + if (oldadp != NULL && oldadp->ad_offset == off) + allocdirect_merge(adphead, adp, oldadp); + FREE_LOCK(ump); + return; + } + TAILQ_FOREACH(oldadp, adphead, ad_next) { + if (oldadp->ad_offset >= off) + break; + } + if (oldadp == NULL) + panic("softdep_setup_allocext: lost entry"); + /* insert in middle of list */ + TAILQ_INSERT_BEFORE(oldadp, adp, ad_next); + if (oldadp->ad_offset == off) + allocdirect_merge(adphead, adp, oldadp); + FREE_LOCK(ump); +} + +/* + * Indirect block allocation dependencies. + * + * The same dependencies that exist for a direct block also exist when + * a new block is allocated and pointed to by an entry in a block of + * indirect pointers. The undo/redo states described above are also + * used here. Because an indirect block contains many pointers that + * may have dependencies, a second copy of the entire in-memory indirect + * block is kept. The buffer cache copy is always completely up-to-date. + * The second copy, which is used only as a source for disk writes, + * contains only the safe pointers (i.e., those that have no remaining + * update dependencies). The second copy is freed when all pointers + * are safe. The cache is not allowed to replace indirect blocks with + * pending update dependencies. If a buffer containing an indirect + * block with dependencies is written, these routines will mark it + * dirty again. It can only be successfully written once all the + * dependencies are removed. The ffs_fsync routine in conjunction with + * softdep_sync_metadata work together to get all the dependencies + * removed so that a file can be successfully written to disk. Three + * procedures are used when setting up indirect block pointer + * dependencies. The division is necessary because of the organization + * of the "balloc" routine and because of the distinction between file + * pages and file metadata blocks. + */ + +/* + * Allocate a new allocindir structure. + */ +static struct allocindir * +newallocindir(ip, ptrno, newblkno, oldblkno, lbn) + struct inode *ip; /* inode for file being extended */ + int ptrno; /* offset of pointer in indirect block */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 if none */ + ufs_lbn_t lbn; +{ + struct newblk *newblk; + struct allocindir *aip; + struct freefrag *freefrag; + struct jnewblk *jnewblk; + + if (oldblkno) + freefrag = newfreefrag(ip, oldblkno, ITOFS(ip)->fs_bsize, lbn); + else + freefrag = NULL; + ACQUIRE_LOCK(ITOUMP(ip)); + if (newblk_lookup(ITOVFS(ip), newblkno, 0, &newblk) == 0) + panic("new_allocindir: lost block"); + KASSERT(newblk->nb_list.wk_type == D_NEWBLK, + ("newallocindir: newblk already initialized")); + WORKITEM_REASSIGN(newblk, D_ALLOCINDIR); + newblk->nb_freefrag = freefrag; + aip = (struct allocindir *)newblk; + aip->ai_offset = ptrno; + aip->ai_oldblkno = oldblkno; + aip->ai_lbn = lbn; + if ((jnewblk = newblk->nb_jnewblk) != NULL) { + jnewblk->jn_ino = ip->i_number; + jnewblk->jn_lbn = lbn; + add_to_journal(&jnewblk->jn_list); + } + if (freefrag && freefrag->ff_jdep != NULL && + freefrag->ff_jdep->wk_type == D_JFREEFRAG) + add_to_journal(freefrag->ff_jdep); + return (aip); +} + +/* + * Called just before setting an indirect block pointer + * to a newly allocated file page. + */ +void +softdep_setup_allocindir_page(ip, lbn, bp, ptrno, newblkno, oldblkno, nbp) + struct inode *ip; /* inode for file being extended */ + ufs_lbn_t lbn; /* allocated block number within file */ + struct buf *bp; /* buffer with indirect blk referencing page */ + int ptrno; /* offset of pointer in indirect block */ + ufs2_daddr_t newblkno; /* disk block number being added */ + ufs2_daddr_t oldblkno; /* previous block number, 0 if none */ + struct buf *nbp; /* buffer holding allocated page */ +{ + struct inodedep *inodedep; + struct freefrag *freefrag; + struct allocindir *aip; + struct pagedep *pagedep; + struct mount *mp; + struct ufsmount *ump; + + mp = ITOVFS(ip); + ump = VFSTOUFS(mp); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_allocindir_page called on non-softdep filesystem")); + KASSERT(lbn == nbp->b_lblkno, + ("softdep_setup_allocindir_page: lbn %jd != lblkno %jd", + lbn, bp->b_lblkno)); + CTR4(KTR_SUJ, + "softdep_setup_allocindir_page: ino %d blkno %jd oldblkno %jd " + "lbn %jd", ip->i_number, newblkno, oldblkno, lbn); + ASSERT_VOP_LOCKED(ITOV(ip), "softdep_setup_allocindir_page"); + aip = newallocindir(ip, ptrno, newblkno, oldblkno, lbn); + (void) inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); + /* + * If we are allocating a directory page, then we must + * allocate an associated pagedep to track additions and + * deletions. + */ + if ((ip->i_mode & IFMT) == IFDIR) + pagedep_lookup(mp, nbp, ip->i_number, lbn, DEPALLOC, &pagedep); + WORKLIST_INSERT(&nbp->b_dep, &aip->ai_block.nb_list); + freefrag = setup_allocindir_phase2(bp, ip, inodedep, aip, lbn); + FREE_LOCK(ump); + if (freefrag) + handle_workitem_freefrag(freefrag); +} + +/* + * Called just before setting an indirect block pointer to a + * newly allocated indirect block. + */ +void +softdep_setup_allocindir_meta(nbp, ip, bp, ptrno, newblkno) + struct buf *nbp; /* newly allocated indirect block */ + struct inode *ip; /* inode for file being extended */ + struct buf *bp; /* indirect block referencing allocated block */ + int ptrno; /* offset of pointer in indirect block */ + ufs2_daddr_t newblkno; /* disk block number being added */ +{ + struct inodedep *inodedep; + struct allocindir *aip; + struct ufsmount *ump; + ufs_lbn_t lbn; + + ump = ITOUMP(ip); + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_setup_allocindir_meta called on non-softdep filesystem")); + CTR3(KTR_SUJ, + "softdep_setup_allocindir_meta: ino %d blkno %jd ptrno %d", + ip->i_number, newblkno, ptrno); + lbn = nbp->b_lblkno; + ASSERT_VOP_LOCKED(ITOV(ip), "softdep_setup_allocindir_meta"); + aip = newallocindir(ip, ptrno, newblkno, 0, lbn); + inodedep_lookup(UFSTOVFS(ump), ip->i_number, DEPALLOC, &inodedep); + WORKLIST_INSERT(&nbp->b_dep, &aip->ai_block.nb_list); + if (setup_allocindir_phase2(bp, ip, inodedep, aip, lbn)) + panic("softdep_setup_allocindir_meta: Block already existed"); + FREE_LOCK(ump); +} + +static void +indirdep_complete(indirdep) + struct indirdep *indirdep; +{ + struct allocindir *aip; + + LIST_REMOVE(indirdep, ir_next); + indirdep->ir_state |= DEPCOMPLETE; + + while ((aip = LIST_FIRST(&indirdep->ir_completehd)) != NULL) { + LIST_REMOVE(aip, ai_next); + free_newblk(&aip->ai_block); + } + /* + * If this indirdep is not attached to a buf it was simply waiting + * on completion to clear completehd. free_indirdep() asserts + * that nothing is dangling. + */ + if ((indirdep->ir_state & ONWORKLIST) == 0) + free_indirdep(indirdep); +} + +static struct indirdep * +indirdep_lookup(mp, ip, bp) + struct mount *mp; + struct inode *ip; + struct buf *bp; +{ + struct indirdep *indirdep, *newindirdep; + struct newblk *newblk; + struct ufsmount *ump; + struct worklist *wk; + struct fs *fs; + ufs2_daddr_t blkno; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + indirdep = NULL; + newindirdep = NULL; + fs = ump->um_fs; + for (;;) { + LIST_FOREACH(wk, &bp->b_dep, wk_list) { + if (wk->wk_type != D_INDIRDEP) + continue; + indirdep = WK_INDIRDEP(wk); + break; + } + /* Found on the buffer worklist, no new structure to free. */ + if (indirdep != NULL && newindirdep == NULL) + return (indirdep); + if (indirdep != NULL && newindirdep != NULL) + panic("indirdep_lookup: simultaneous create"); + /* None found on the buffer and a new structure is ready. */ + if (indirdep == NULL && newindirdep != NULL) + break; + /* None found and no new structure available. */ + FREE_LOCK(ump); + newindirdep = malloc(sizeof(struct indirdep), + M_INDIRDEP, M_SOFTDEP_FLAGS); + workitem_alloc(&newindirdep->ir_list, D_INDIRDEP, mp); + newindirdep->ir_state = ATTACHED; + if (I_IS_UFS1(ip)) + newindirdep->ir_state |= UFS1FMT; + TAILQ_INIT(&newindirdep->ir_trunc); + newindirdep->ir_saveddata = NULL; + LIST_INIT(&newindirdep->ir_deplisthd); + LIST_INIT(&newindirdep->ir_donehd); + LIST_INIT(&newindirdep->ir_writehd); + LIST_INIT(&newindirdep->ir_completehd); + if (bp->b_blkno == bp->b_lblkno) { + ufs_bmaparray(bp->b_vp, bp->b_lblkno, &blkno, bp, + NULL, NULL); + bp->b_blkno = blkno; + } + newindirdep->ir_freeblks = NULL; + newindirdep->ir_savebp = + getblk(ump->um_devvp, bp->b_blkno, bp->b_bcount, 0, 0, 0); + newindirdep->ir_bp = bp; + BUF_KERNPROC(newindirdep->ir_savebp); + bcopy(bp->b_data, newindirdep->ir_savebp->b_data, bp->b_bcount); + ACQUIRE_LOCK(ump); + } + indirdep = newindirdep; + WORKLIST_INSERT(&bp->b_dep, &indirdep->ir_list); + /* + * If the block is not yet allocated we don't set DEPCOMPLETE so + * that we don't free dependencies until the pointers are valid. + * This could search b_dep for D_ALLOCDIRECT/D_ALLOCINDIR rather + * than using the hash. + */ + if (newblk_lookup(mp, dbtofsb(fs, bp->b_blkno), 0, &newblk)) + LIST_INSERT_HEAD(&newblk->nb_indirdeps, indirdep, ir_next); + else + indirdep->ir_state |= DEPCOMPLETE; + return (indirdep); +} + +/* + * Called to finish the allocation of the "aip" allocated + * by one of the two routines above. + */ +static struct freefrag * +setup_allocindir_phase2(bp, ip, inodedep, aip, lbn) + struct buf *bp; /* in-memory copy of the indirect block */ + struct inode *ip; /* inode for file being extended */ + struct inodedep *inodedep; /* Inodedep for ip */ + struct allocindir *aip; /* allocindir allocated by the above routines */ + ufs_lbn_t lbn; /* Logical block number for this block. */ +{ + struct fs *fs; + struct indirdep *indirdep; + struct allocindir *oldaip; + struct freefrag *freefrag; + struct mount *mp; + struct ufsmount *ump; + + mp = ITOVFS(ip); + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + fs = ump->um_fs; + if (bp->b_lblkno >= 0) + panic("setup_allocindir_phase2: not indir blk"); + KASSERT(aip->ai_offset >= 0 && aip->ai_offset < NINDIR(fs), + ("setup_allocindir_phase2: Bad offset %d", aip->ai_offset)); + indirdep = indirdep_lookup(mp, ip, bp); + KASSERT(indirdep->ir_savebp != NULL, + ("setup_allocindir_phase2 NULL ir_savebp")); + aip->ai_indirdep = indirdep; + /* + * Check for an unwritten dependency for this indirect offset. If + * there is, merge the old dependency into the new one. This happens + * as a result of reallocblk only. + */ + freefrag = NULL; + if (aip->ai_oldblkno != 0) { + LIST_FOREACH(oldaip, &indirdep->ir_deplisthd, ai_next) { + if (oldaip->ai_offset == aip->ai_offset) { + freefrag = allocindir_merge(aip, oldaip); + goto done; + } + } + LIST_FOREACH(oldaip, &indirdep->ir_donehd, ai_next) { + if (oldaip->ai_offset == aip->ai_offset) { + freefrag = allocindir_merge(aip, oldaip); + goto done; + } + } + } +done: + LIST_INSERT_HEAD(&indirdep->ir_deplisthd, aip, ai_next); + return (freefrag); +} + +/* + * Merge two allocindirs which refer to the same block. Move newblock + * dependencies and setup the freefrags appropriately. + */ +static struct freefrag * +allocindir_merge(aip, oldaip) + struct allocindir *aip; + struct allocindir *oldaip; +{ + struct freefrag *freefrag; + struct worklist *wk; + + if (oldaip->ai_newblkno != aip->ai_oldblkno) + panic("allocindir_merge: blkno"); + aip->ai_oldblkno = oldaip->ai_oldblkno; + freefrag = aip->ai_freefrag; + aip->ai_freefrag = oldaip->ai_freefrag; + oldaip->ai_freefrag = NULL; + KASSERT(freefrag != NULL, ("setup_allocindir_phase2: No freefrag")); + /* + * If we are tracking a new directory-block allocation, + * move it from the old allocindir to the new allocindir. + */ + if ((wk = LIST_FIRST(&oldaip->ai_newdirblk)) != NULL) { + WORKLIST_REMOVE(wk); + if (!LIST_EMPTY(&oldaip->ai_newdirblk)) + panic("allocindir_merge: extra newdirblk"); + WORKLIST_INSERT(&aip->ai_newdirblk, wk); + } + /* + * We can skip journaling for this freefrag and just complete + * any pending journal work for the allocindir that is being + * removed after the freefrag completes. + */ + if (freefrag->ff_jdep) + cancel_jfreefrag(WK_JFREEFRAG(freefrag->ff_jdep)); + LIST_REMOVE(oldaip, ai_next); + freefrag->ff_jdep = (struct worklist *)cancel_newblk(&oldaip->ai_block, + &freefrag->ff_list, &freefrag->ff_jwork); + free_newblk(&oldaip->ai_block); + + return (freefrag); +} + +static inline void +setup_freedirect(freeblks, ip, i, needj) + struct freeblks *freeblks; + struct inode *ip; + int i; + int needj; +{ + struct ufsmount *ump; + ufs2_daddr_t blkno; + int frags; + + blkno = DIP(ip, i_db[i]); + if (blkno == 0) + return; + DIP_SET(ip, i_db[i], 0); + ump = ITOUMP(ip); + frags = sblksize(ump->um_fs, ip->i_size, i); + frags = numfrags(ump->um_fs, frags); + newfreework(ump, freeblks, NULL, i, blkno, frags, 0, needj); +} + +static inline void +setup_freeext(freeblks, ip, i, needj) + struct freeblks *freeblks; + struct inode *ip; + int i; + int needj; +{ + struct ufsmount *ump; + ufs2_daddr_t blkno; + int frags; + + blkno = ip->i_din2->di_extb[i]; + if (blkno == 0) + return; + ip->i_din2->di_extb[i] = 0; + ump = ITOUMP(ip); + frags = sblksize(ump->um_fs, ip->i_din2->di_extsize, i); + frags = numfrags(ump->um_fs, frags); + newfreework(ump, freeblks, NULL, -1 - i, blkno, frags, 0, needj); +} + +static inline void +setup_freeindir(freeblks, ip, i, lbn, needj) + struct freeblks *freeblks; + struct inode *ip; + int i; + ufs_lbn_t lbn; + int needj; +{ + struct ufsmount *ump; + ufs2_daddr_t blkno; + + blkno = DIP(ip, i_ib[i]); + if (blkno == 0) + return; + DIP_SET(ip, i_ib[i], 0); + ump = ITOUMP(ip); + newfreework(ump, freeblks, NULL, lbn, blkno, ump->um_fs->fs_frag, + 0, needj); +} + +static inline struct freeblks * +newfreeblks(mp, ip) + struct mount *mp; + struct inode *ip; +{ + struct freeblks *freeblks; + + freeblks = malloc(sizeof(struct freeblks), + M_FREEBLKS, M_SOFTDEP_FLAGS|M_ZERO); + workitem_alloc(&freeblks->fb_list, D_FREEBLKS, mp); + LIST_INIT(&freeblks->fb_jblkdephd); + LIST_INIT(&freeblks->fb_jwork); + freeblks->fb_ref = 0; + freeblks->fb_cgwait = 0; + freeblks->fb_state = ATTACHED; + freeblks->fb_uid = ip->i_uid; + freeblks->fb_inum = ip->i_number; + freeblks->fb_vtype = ITOV(ip)->v_type; + freeblks->fb_modrev = DIP(ip, i_modrev); + freeblks->fb_devvp = ITODEVVP(ip); + freeblks->fb_chkcnt = 0; + freeblks->fb_len = 0; + + return (freeblks); +} + +static void +trunc_indirdep(indirdep, freeblks, bp, off) + struct indirdep *indirdep; + struct freeblks *freeblks; + struct buf *bp; + int off; +{ + struct allocindir *aip, *aipn; + + /* + * The first set of allocindirs won't be in savedbp. + */ + LIST_FOREACH_SAFE(aip, &indirdep->ir_deplisthd, ai_next, aipn) + if (aip->ai_offset > off) + cancel_allocindir(aip, bp, freeblks, 1); + LIST_FOREACH_SAFE(aip, &indirdep->ir_donehd, ai_next, aipn) + if (aip->ai_offset > off) + cancel_allocindir(aip, bp, freeblks, 1); + /* + * These will exist in savedbp. + */ + LIST_FOREACH_SAFE(aip, &indirdep->ir_writehd, ai_next, aipn) + if (aip->ai_offset > off) + cancel_allocindir(aip, NULL, freeblks, 0); + LIST_FOREACH_SAFE(aip, &indirdep->ir_completehd, ai_next, aipn) + if (aip->ai_offset > off) + cancel_allocindir(aip, NULL, freeblks, 0); +} + +/* + * Follow the chain of indirects down to lastlbn creating a freework + * structure for each. This will be used to start indir_trunc() at + * the right offset and create the journal records for the parrtial + * truncation. A second step will handle the truncated dependencies. + */ +static int +setup_trunc_indir(freeblks, ip, lbn, lastlbn, blkno) + struct freeblks *freeblks; + struct inode *ip; + ufs_lbn_t lbn; + ufs_lbn_t lastlbn; + ufs2_daddr_t blkno; +{ + struct indirdep *indirdep; + struct indirdep *indirn; + struct freework *freework; + struct newblk *newblk; + struct mount *mp; + struct ufsmount *ump; + struct buf *bp; + uint8_t *start; + uint8_t *end; + ufs_lbn_t lbnadd; + int level; + int error; + int off; + + + freework = NULL; + if (blkno == 0) + return (0); + mp = freeblks->fb_list.wk_mp; + ump = VFSTOUFS(mp); + bp = getblk(ITOV(ip), lbn, mp->mnt_stat.f_iosize, 0, 0, 0); + if ((bp->b_flags & B_CACHE) == 0) { + bp->b_blkno = blkptrtodb(VFSTOUFS(mp), blkno); + bp->b_iocmd = BIO_READ; + bp->b_flags &= ~B_INVAL; + bp->b_ioflags &= ~BIO_ERROR; + vfs_busy_pages(bp, 0); + bp->b_iooffset = dbtob(bp->b_blkno); + bstrategy(bp); +#ifdef RACCT + if (racct_enable) { + PROC_LOCK(curproc); + racct_add_buf(curproc, bp, 0); + PROC_UNLOCK(curproc); + } +#endif /* RACCT */ + curthread->td_ru.ru_inblock++; + error = bufwait(bp); + if (error) { + brelse(bp); + return (error); + } + } + level = lbn_level(lbn); + lbnadd = lbn_offset(ump->um_fs, level); + /* + * Compute the offset of the last block we want to keep. Store + * in the freework the first block we want to completely free. + */ + off = (lastlbn - -(lbn + level)) / lbnadd; + if (off + 1 == NINDIR(ump->um_fs)) + goto nowork; + freework = newfreework(ump, freeblks, NULL, lbn, blkno, 0, off + 1, 0); + /* + * Link the freework into the indirdep. This will prevent any new + * allocations from proceeding until we are finished with the + * truncate and the block is written. + */ + ACQUIRE_LOCK(ump); + indirdep = indirdep_lookup(mp, ip, bp); + if (indirdep->ir_freeblks) + panic("setup_trunc_indir: indirdep already truncated."); + TAILQ_INSERT_TAIL(&indirdep->ir_trunc, freework, fw_next); + freework->fw_indir = indirdep; + /* + * Cancel any allocindirs that will not make it to disk. + * We have to do this for all copies of the indirdep that + * live on this newblk. + */ + if ((indirdep->ir_state & DEPCOMPLETE) == 0) { + newblk_lookup(mp, dbtofsb(ump->um_fs, bp->b_blkno), 0, &newblk); + LIST_FOREACH(indirn, &newblk->nb_indirdeps, ir_next) + trunc_indirdep(indirn, freeblks, bp, off); + } else + trunc_indirdep(indirdep, freeblks, bp, off); + FREE_LOCK(ump); + /* + * Creation is protected by the buf lock. The saveddata is only + * needed if a full truncation follows a partial truncation but it + * is difficult to allocate in that case so we fetch it anyway. + */ + if (indirdep->ir_saveddata == NULL) + indirdep->ir_saveddata = malloc(bp->b_bcount, M_INDIRDEP, + M_SOFTDEP_FLAGS); +nowork: + /* Fetch the blkno of the child and the zero start offset. */ + if (I_IS_UFS1(ip)) { + blkno = ((ufs1_daddr_t *)bp->b_data)[off]; + start = (uint8_t *)&((ufs1_daddr_t *)bp->b_data)[off+1]; + } else { + blkno = ((ufs2_daddr_t *)bp->b_data)[off]; + start = (uint8_t *)&((ufs2_daddr_t *)bp->b_data)[off+1]; + } + if (freework) { + /* Zero the truncated pointers. */ + end = bp->b_data + bp->b_bcount; + bzero(start, end - start); + bdwrite(bp); + } else + bqrelse(bp); + if (level == 0) + return (0); + lbn++; /* adjust level */ + lbn -= (off * lbnadd); + return setup_trunc_indir(freeblks, ip, lbn, lastlbn, blkno); +} + +/* + * Complete the partial truncation of an indirect block setup by + * setup_trunc_indir(). This zeros the truncated pointers in the saved + * copy and writes them to disk before the freeblks is allowed to complete. + */ +static void +complete_trunc_indir(freework) + struct freework *freework; +{ + struct freework *fwn; + struct indirdep *indirdep; + struct ufsmount *ump; + struct buf *bp; + uintptr_t start; + int count; + + ump = VFSTOUFS(freework->fw_list.wk_mp); + LOCK_OWNED(ump); + indirdep = freework->fw_indir; + for (;;) { + bp = indirdep->ir_bp; + /* See if the block was discarded. */ + if (bp == NULL) + break; + /* Inline part of getdirtybuf(). We dont want bremfree. */ + if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) == 0) + break; + if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, + LOCK_PTR(ump)) == 0) + BUF_UNLOCK(bp); + ACQUIRE_LOCK(ump); + } + freework->fw_state |= DEPCOMPLETE; + TAILQ_REMOVE(&indirdep->ir_trunc, freework, fw_next); + /* + * Zero the pointers in the saved copy. + */ + if (indirdep->ir_state & UFS1FMT) + start = sizeof(ufs1_daddr_t); + else + start = sizeof(ufs2_daddr_t); + start *= freework->fw_start; + count = indirdep->ir_savebp->b_bcount - start; + start += (uintptr_t)indirdep->ir_savebp->b_data; + bzero((char *)start, count); + /* + * We need to start the next truncation in the list if it has not + * been started yet. + */ + fwn = TAILQ_FIRST(&indirdep->ir_trunc); + if (fwn != NULL) { + if (fwn->fw_freeblks == indirdep->ir_freeblks) + TAILQ_REMOVE(&indirdep->ir_trunc, fwn, fw_next); + if ((fwn->fw_state & ONWORKLIST) == 0) + freework_enqueue(fwn); + } + /* + * If bp is NULL the block was fully truncated, restore + * the saved block list otherwise free it if it is no + * longer needed. + */ + if (TAILQ_EMPTY(&indirdep->ir_trunc)) { + if (bp == NULL) + bcopy(indirdep->ir_saveddata, + indirdep->ir_savebp->b_data, + indirdep->ir_savebp->b_bcount); + free(indirdep->ir_saveddata, M_INDIRDEP); + indirdep->ir_saveddata = NULL; + } + /* + * When bp is NULL there is a full truncation pending. We + * must wait for this full truncation to be journaled before + * we can release this freework because the disk pointers will + * never be written as zero. + */ + if (bp == NULL) { + if (LIST_EMPTY(&indirdep->ir_freeblks->fb_jblkdephd)) + handle_written_freework(freework); + else + WORKLIST_INSERT(&indirdep->ir_freeblks->fb_freeworkhd, + &freework->fw_list); + } else { + /* Complete when the real copy is written. */ + WORKLIST_INSERT(&bp->b_dep, &freework->fw_list); + BUF_UNLOCK(bp); + } +} + +/* + * Calculate the number of blocks we are going to release where datablocks + * is the current total and length is the new file size. + */ +static ufs2_daddr_t +blkcount(fs, datablocks, length) + struct fs *fs; + ufs2_daddr_t datablocks; + off_t length; +{ + off_t totblks, numblks; + + totblks = 0; + numblks = howmany(length, fs->fs_bsize); + if (numblks <= NDADDR) { + totblks = howmany(length, fs->fs_fsize); + goto out; + } + totblks = blkstofrags(fs, numblks); + numblks -= NDADDR; + /* + * Count all single, then double, then triple indirects required. + * Subtracting one indirects worth of blocks for each pass + * acknowledges one of each pointed to by the inode. + */ + for (;;) { + totblks += blkstofrags(fs, howmany(numblks, NINDIR(fs))); + numblks -= NINDIR(fs); + if (numblks <= 0) + break; + numblks = howmany(numblks, NINDIR(fs)); + } +out: + totblks = fsbtodb(fs, totblks); + /* + * Handle sparse files. We can't reclaim more blocks than the inode + * references. We will correct it later in handle_complete_freeblks() + * when we know the real count. + */ + if (totblks > datablocks) + return (0); + return (datablocks - totblks); +} + +/* + * Handle freeblocks for journaled softupdate filesystems. + * + * Contrary to normal softupdates, we must preserve the block pointers in + * indirects until their subordinates are free. This is to avoid journaling + * every block that is freed which may consume more space than the journal + * itself. The recovery program will see the free block journals at the + * base of the truncated area and traverse them to reclaim space. The + * pointers in the inode may be cleared immediately after the journal + * records are written because each direct and indirect pointer in the + * inode is recorded in a journal. This permits full truncation to proceed + * asynchronously. The write order is journal -> inode -> cgs -> indirects. + * + * The algorithm is as follows: + * 1) Traverse the in-memory state and create journal entries to release + * the relevant blocks and full indirect trees. + * 2) Traverse the indirect block chain adding partial truncation freework + * records to indirects in the path to lastlbn. The freework will + * prevent new allocation dependencies from being satisfied in this + * indirect until the truncation completes. + * 3) Read and lock the inode block, performing an update with the new size + * and pointers. This prevents truncated data from becoming valid on + * disk through step 4. + * 4) Reap unsatisfied dependencies that are beyond the truncated area, + * eliminate journal work for those records that do not require it. + * 5) Schedule the journal records to be written followed by the inode block. + * 6) Allocate any necessary frags for the end of file. + * 7) Zero any partially truncated blocks. + * + * From this truncation proceeds asynchronously using the freework and + * indir_trunc machinery. The file will not be extended again into a + * partially truncated indirect block until all work is completed but + * the normal dependency mechanism ensures that it is rolled back/forward + * as appropriate. Further truncation may occur without delay and is + * serialized in indir_trunc(). + */ +void +softdep_journal_freeblocks(ip, cred, length, flags) + struct inode *ip; /* The inode whose length is to be reduced */ + struct ucred *cred; + off_t length; /* The new length for the file */ + int flags; /* IO_EXT and/or IO_NORMAL */ +{ + struct freeblks *freeblks, *fbn; + struct worklist *wk, *wkn; + struct inodedep *inodedep; + struct jblkdep *jblkdep; + struct allocdirect *adp, *adpn; + struct ufsmount *ump; + struct fs *fs; + struct buf *bp; + struct vnode *vp; + struct mount *mp; + ufs2_daddr_t extblocks, datablocks; + ufs_lbn_t tmpval, lbn, lastlbn; + int frags, lastoff, iboff, allocblock, needj, error, i; + + ump = ITOUMP(ip); + mp = UFSTOVFS(ump); + fs = ump->um_fs; + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_journal_freeblocks called on non-softdep filesystem")); + vp = ITOV(ip); + needj = 1; + iboff = -1; + allocblock = 0; + extblocks = 0; + datablocks = 0; + frags = 0; + freeblks = newfreeblks(mp, ip); + ACQUIRE_LOCK(ump); + /* + * If we're truncating a removed file that will never be written + * we don't need to journal the block frees. The canceled journals + * for the allocations will suffice. + */ + inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); + if ((inodedep->id_state & (UNLINKED | DEPCOMPLETE)) == UNLINKED && + length == 0) + needj = 0; + CTR3(KTR_SUJ, "softdep_journal_freeblks: ip %d length %ld needj %d", + ip->i_number, length, needj); + FREE_LOCK(ump); + /* + * Calculate the lbn that we are truncating to. This results in -1 + * if we're truncating the 0 bytes. So it is the last lbn we want + * to keep, not the first lbn we want to truncate. + */ + lastlbn = lblkno(fs, length + fs->fs_bsize - 1) - 1; + lastoff = blkoff(fs, length); + /* + * Compute frags we are keeping in lastlbn. 0 means all. + */ + if (lastlbn >= 0 && lastlbn < NDADDR) { + frags = fragroundup(fs, lastoff); + /* adp offset of last valid allocdirect. */ + iboff = lastlbn; + } else if (lastlbn > 0) + iboff = NDADDR; + if (fs->fs_magic == FS_UFS2_MAGIC) + extblocks = btodb(fragroundup(fs, ip->i_din2->di_extsize)); + /* + * Handle normal data blocks and indirects. This section saves + * values used after the inode update to complete frag and indirect + * truncation. + */ + if ((flags & IO_NORMAL) != 0) { + /* + * Handle truncation of whole direct and indirect blocks. + */ + for (i = iboff + 1; i < NDADDR; i++) + setup_freedirect(freeblks, ip, i, needj); + for (i = 0, tmpval = NINDIR(fs), lbn = NDADDR; i < NIADDR; + i++, lbn += tmpval, tmpval *= NINDIR(fs)) { + /* Release a whole indirect tree. */ + if (lbn > lastlbn) { + setup_freeindir(freeblks, ip, i, -lbn -i, + needj); + continue; + } + iboff = i + NDADDR; + /* + * Traverse partially truncated indirect tree. + */ + if (lbn <= lastlbn && lbn + tmpval - 1 > lastlbn) + setup_trunc_indir(freeblks, ip, -lbn - i, + lastlbn, DIP(ip, i_ib[i])); + } + /* + * Handle partial truncation to a frag boundary. + */ + if (frags) { + ufs2_daddr_t blkno; + long oldfrags; + + oldfrags = blksize(fs, ip, lastlbn); + blkno = DIP(ip, i_db[lastlbn]); + if (blkno && oldfrags != frags) { + oldfrags -= frags; + oldfrags = numfrags(fs, oldfrags); + blkno += numfrags(fs, frags); + newfreework(ump, freeblks, NULL, lastlbn, + blkno, oldfrags, 0, needj); + if (needj) + adjust_newfreework(freeblks, + numfrags(fs, frags)); + } else if (blkno == 0) + allocblock = 1; + } + /* + * Add a journal record for partial truncate if we are + * handling indirect blocks. Non-indirects need no extra + * journaling. + */ + if (length != 0 && lastlbn >= NDADDR) { + ip->i_flag |= IN_TRUNCATED; + newjtrunc(freeblks, length, 0); + } + ip->i_size = length; + DIP_SET(ip, i_size, ip->i_size); + datablocks = DIP(ip, i_blocks) - extblocks; + if (length != 0) + datablocks = blkcount(fs, datablocks, length); + freeblks->fb_len = length; + } + if ((flags & IO_EXT) != 0) { + for (i = 0; i < NXADDR; i++) + setup_freeext(freeblks, ip, i, needj); + ip->i_din2->di_extsize = 0; + datablocks += extblocks; + } +#ifdef QUOTA + /* Reference the quotas in case the block count is wrong in the end. */ + quotaref(vp, freeblks->fb_quota); + (void) chkdq(ip, -datablocks, NOCRED, 0); +#endif + freeblks->fb_chkcnt = -datablocks; + UFS_LOCK(ump); + fs->fs_pendingblocks += datablocks; + UFS_UNLOCK(ump); + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - datablocks); + /* + * Handle truncation of incomplete alloc direct dependencies. We + * hold the inode block locked to prevent incomplete dependencies + * from reaching the disk while we are eliminating those that + * have been truncated. This is a partially inlined ffs_update(). + */ + ufs_itimes(vp); + ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED); + error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), + (int)fs->fs_bsize, cred, &bp); + if (error) { + brelse(bp); + softdep_error("softdep_journal_freeblocks", error); + return; + } + if (bp->b_bufsize == fs->fs_bsize) + bp->b_flags |= B_CLUSTEROK; + softdep_update_inodeblock(ip, bp, 0); + if (ump->um_fstype == UFS1) + *((struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1; + else + *((struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2; + ACQUIRE_LOCK(ump); + (void) inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); + if ((inodedep->id_state & IOSTARTED) != 0) + panic("softdep_setup_freeblocks: inode busy"); + /* + * Add the freeblks structure to the list of operations that + * must await the zero'ed inode being written to disk. If we + * still have a bitmap dependency (needj), then the inode + * has never been written to disk, so we can process the + * freeblks below once we have deleted the dependencies. + */ + if (needj) + WORKLIST_INSERT(&bp->b_dep, &freeblks->fb_list); + else + freeblks->fb_state |= COMPLETE; + if ((flags & IO_NORMAL) != 0) { + TAILQ_FOREACH_SAFE(adp, &inodedep->id_inoupdt, ad_next, adpn) { + if (adp->ad_offset > iboff) + cancel_allocdirect(&inodedep->id_inoupdt, adp, + freeblks); + /* + * Truncate the allocdirect. We could eliminate + * or modify journal records as well. + */ + else if (adp->ad_offset == iboff && frags) + adp->ad_newsize = frags; + } + } + if ((flags & IO_EXT) != 0) + while ((adp = TAILQ_FIRST(&inodedep->id_extupdt)) != NULL) + cancel_allocdirect(&inodedep->id_extupdt, adp, + freeblks); + /* + * Scan the bufwait list for newblock dependencies that will never + * make it to disk. + */ + LIST_FOREACH_SAFE(wk, &inodedep->id_bufwait, wk_list, wkn) { + if (wk->wk_type != D_ALLOCDIRECT) + continue; + adp = WK_ALLOCDIRECT(wk); + if (((flags & IO_NORMAL) != 0 && (adp->ad_offset > iboff)) || + ((flags & IO_EXT) != 0 && (adp->ad_state & EXTDATA))) { + cancel_jfreeblk(freeblks, adp->ad_newblkno); + cancel_newblk(WK_NEWBLK(wk), NULL, &freeblks->fb_jwork); + WORKLIST_INSERT(&freeblks->fb_freeworkhd, wk); + } + } + /* + * Add journal work. + */ + LIST_FOREACH(jblkdep, &freeblks->fb_jblkdephd, jb_deps) + add_to_journal(&jblkdep->jb_list); + FREE_LOCK(ump); + bdwrite(bp); + /* + * Truncate dependency structures beyond length. + */ + trunc_dependencies(ip, freeblks, lastlbn, frags, flags); + /* + * This is only set when we need to allocate a fragment because + * none existed at the end of a frag-sized file. It handles only + * allocating a new, zero filled block. + */ + if (allocblock) { + ip->i_size = length - lastoff; + DIP_SET(ip, i_size, ip->i_size); + error = UFS_BALLOC(vp, length - 1, 1, cred, BA_CLRBUF, &bp); + if (error != 0) { + softdep_error("softdep_journal_freeblks", error); + return; + } + ip->i_size = length; + DIP_SET(ip, i_size, length); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + allocbuf(bp, frags); + ffs_update(vp, 0); + bawrite(bp); + } else if (lastoff != 0 && vp->v_type != VDIR) { + int size; + + /* + * Zero the end of a truncated frag or block. + */ + size = sblksize(fs, length, lastlbn); + error = bread(vp, lastlbn, size, cred, &bp); + if (error) { + softdep_error("softdep_journal_freeblks", error); + return; + } + bzero((char *)bp->b_data + lastoff, size - lastoff); + bawrite(bp); + + } + ACQUIRE_LOCK(ump); + inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); + TAILQ_INSERT_TAIL(&inodedep->id_freeblklst, freeblks, fb_next); + freeblks->fb_state |= DEPCOMPLETE | ONDEPLIST; + /* + * We zero earlier truncations so they don't erroneously + * update i_blocks. + */ + if (freeblks->fb_len == 0 && (flags & IO_NORMAL) != 0) + TAILQ_FOREACH(fbn, &inodedep->id_freeblklst, fb_next) + fbn->fb_len = 0; + if ((freeblks->fb_state & ALLCOMPLETE) == ALLCOMPLETE && + LIST_EMPTY(&freeblks->fb_jblkdephd)) + freeblks->fb_state |= INPROGRESS; + else + freeblks = NULL; + FREE_LOCK(ump); + if (freeblks) + handle_workitem_freeblocks(freeblks, 0); + trunc_pages(ip, length, extblocks, flags); + +} + +/* + * Flush a JOP_SYNC to the journal. + */ +void +softdep_journal_fsync(ip) + struct inode *ip; +{ + struct jfsync *jfsync; + struct ufsmount *ump; + + ump = ITOUMP(ip); + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_journal_fsync called on non-softdep filesystem")); + if ((ip->i_flag & IN_TRUNCATED) == 0) + return; + ip->i_flag &= ~IN_TRUNCATED; + jfsync = malloc(sizeof(*jfsync), M_JFSYNC, M_SOFTDEP_FLAGS | M_ZERO); + workitem_alloc(&jfsync->jfs_list, D_JFSYNC, UFSTOVFS(ump)); + jfsync->jfs_size = ip->i_size; + jfsync->jfs_ino = ip->i_number; + ACQUIRE_LOCK(ump); + add_to_journal(&jfsync->jfs_list); + jwait(&jfsync->jfs_list, MNT_WAIT); + FREE_LOCK(ump); +} + +/* + * Block de-allocation dependencies. + * + * When blocks are de-allocated, the on-disk pointers must be nullified before + * the blocks are made available for use by other files. (The true + * requirement is that old pointers must be nullified before new on-disk + * pointers are set. We chose this slightly more stringent requirement to + * reduce complexity.) Our implementation handles this dependency by updating + * the inode (or indirect block) appropriately but delaying the actual block + * de-allocation (i.e., freemap and free space count manipulation) until + * after the updated versions reach stable storage. After the disk is + * updated, the blocks can be safely de-allocated whenever it is convenient. + * This implementation handles only the common case of reducing a file's + * length to zero. Other cases are handled by the conventional synchronous + * write approach. + * + * The ffs implementation with which we worked double-checks + * the state of the block pointers and file size as it reduces + * a file's length. Some of this code is replicated here in our + * soft updates implementation. The freeblks->fb_chkcnt field is + * used to transfer a part of this information to the procedure + * that eventually de-allocates the blocks. + * + * This routine should be called from the routine that shortens + * a file's length, before the inode's size or block pointers + * are modified. It will save the block pointer information for + * later release and zero the inode so that the calling routine + * can release it. + */ +void +softdep_setup_freeblocks(ip, length, flags) + struct inode *ip; /* The inode whose length is to be reduced */ + off_t length; /* The new length for the file */ + int flags; /* IO_EXT and/or IO_NORMAL */ +{ + struct ufs1_dinode *dp1; + struct ufs2_dinode *dp2; + struct freeblks *freeblks; + struct inodedep *inodedep; + struct allocdirect *adp; + struct ufsmount *ump; + struct buf *bp; + struct fs *fs; + ufs2_daddr_t extblocks, datablocks; + struct mount *mp; + int i, delay, error; + ufs_lbn_t tmpval; + ufs_lbn_t lbn; + + ump = ITOUMP(ip); + mp = UFSTOVFS(ump); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_freeblocks called on non-softdep filesystem")); + CTR2(KTR_SUJ, "softdep_setup_freeblks: ip %d length %ld", + ip->i_number, length); + KASSERT(length == 0, ("softdep_setup_freeblocks: non-zero length")); + fs = ump->um_fs; + if ((error = bread(ump->um_devvp, + fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), + (int)fs->fs_bsize, NOCRED, &bp)) != 0) { + brelse(bp); + softdep_error("softdep_setup_freeblocks", error); + return; + } + freeblks = newfreeblks(mp, ip); + extblocks = 0; + datablocks = 0; + if (fs->fs_magic == FS_UFS2_MAGIC) + extblocks = btodb(fragroundup(fs, ip->i_din2->di_extsize)); + if ((flags & IO_NORMAL) != 0) { + for (i = 0; i < NDADDR; i++) + setup_freedirect(freeblks, ip, i, 0); + for (i = 0, tmpval = NINDIR(fs), lbn = NDADDR; i < NIADDR; + i++, lbn += tmpval, tmpval *= NINDIR(fs)) + setup_freeindir(freeblks, ip, i, -lbn -i, 0); + ip->i_size = 0; + DIP_SET(ip, i_size, 0); + datablocks = DIP(ip, i_blocks) - extblocks; + } + if ((flags & IO_EXT) != 0) { + for (i = 0; i < NXADDR; i++) + setup_freeext(freeblks, ip, i, 0); + ip->i_din2->di_extsize = 0; + datablocks += extblocks; + } +#ifdef QUOTA + /* Reference the quotas in case the block count is wrong in the end. */ + quotaref(ITOV(ip), freeblks->fb_quota); + (void) chkdq(ip, -datablocks, NOCRED, 0); +#endif + freeblks->fb_chkcnt = -datablocks; + UFS_LOCK(ump); + fs->fs_pendingblocks += datablocks; + UFS_UNLOCK(ump); + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - datablocks); + /* + * Push the zero'ed inode to its disk buffer so that we are free + * to delete its dependencies below. Once the dependencies are gone + * the buffer can be safely released. + */ + if (ump->um_fstype == UFS1) { + dp1 = ((struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)); + ip->i_din1->di_freelink = dp1->di_freelink; + *dp1 = *ip->i_din1; + } else { + dp2 = ((struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number)); + ip->i_din2->di_freelink = dp2->di_freelink; + *dp2 = *ip->i_din2; + } + /* + * Find and eliminate any inode dependencies. + */ + ACQUIRE_LOCK(ump); + (void) inodedep_lookup(mp, ip->i_number, DEPALLOC, &inodedep); + if ((inodedep->id_state & IOSTARTED) != 0) + panic("softdep_setup_freeblocks: inode busy"); + /* + * Add the freeblks structure to the list of operations that + * must await the zero'ed inode being written to disk. If we + * still have a bitmap dependency (delay == 0), then the inode + * has never been written to disk, so we can process the + * freeblks below once we have deleted the dependencies. + */ + delay = (inodedep->id_state & DEPCOMPLETE); + if (delay) + WORKLIST_INSERT(&bp->b_dep, &freeblks->fb_list); + else + freeblks->fb_state |= COMPLETE; + /* + * Because the file length has been truncated to zero, any + * pending block allocation dependency structures associated + * with this inode are obsolete and can simply be de-allocated. + * We must first merge the two dependency lists to get rid of + * any duplicate freefrag structures, then purge the merged list. + * If we still have a bitmap dependency, then the inode has never + * been written to disk, so we can free any fragments without delay. + */ + if (flags & IO_NORMAL) { + merge_inode_lists(&inodedep->id_newinoupdt, + &inodedep->id_inoupdt); + while ((adp = TAILQ_FIRST(&inodedep->id_inoupdt)) != NULL) + cancel_allocdirect(&inodedep->id_inoupdt, adp, + freeblks); + } + if (flags & IO_EXT) { + merge_inode_lists(&inodedep->id_newextupdt, + &inodedep->id_extupdt); + while ((adp = TAILQ_FIRST(&inodedep->id_extupdt)) != NULL) + cancel_allocdirect(&inodedep->id_extupdt, adp, + freeblks); + } + FREE_LOCK(ump); + bdwrite(bp); + trunc_dependencies(ip, freeblks, -1, 0, flags); + ACQUIRE_LOCK(ump); + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) != 0) + (void) free_inodedep(inodedep); + freeblks->fb_state |= DEPCOMPLETE; + /* + * If the inode with zeroed block pointers is now on disk + * we can start freeing blocks. + */ + if ((freeblks->fb_state & ALLCOMPLETE) == ALLCOMPLETE) + freeblks->fb_state |= INPROGRESS; + else + freeblks = NULL; + FREE_LOCK(ump); + if (freeblks) + handle_workitem_freeblocks(freeblks, 0); + trunc_pages(ip, length, extblocks, flags); +} + +/* + * Eliminate pages from the page cache that back parts of this inode and + * adjust the vnode pager's idea of our size. This prevents stale data + * from hanging around in the page cache. + */ +static void +trunc_pages(ip, length, extblocks, flags) + struct inode *ip; + off_t length; + ufs2_daddr_t extblocks; + int flags; +{ + struct vnode *vp; + struct fs *fs; + ufs_lbn_t lbn; + off_t end, extend; + + vp = ITOV(ip); + fs = ITOFS(ip); + extend = OFF_TO_IDX(lblktosize(fs, -extblocks)); + if ((flags & IO_EXT) != 0) + vn_pages_remove(vp, extend, 0); + if ((flags & IO_NORMAL) == 0) + return; + BO_LOCK(&vp->v_bufobj); + drain_output(vp); + BO_UNLOCK(&vp->v_bufobj); + /* + * The vnode pager eliminates file pages we eliminate indirects + * below. + */ + vnode_pager_setsize(vp, length); + /* + * Calculate the end based on the last indirect we want to keep. If + * the block extends into indirects we can just use the negative of + * its lbn. Doubles and triples exist at lower numbers so we must + * be careful not to remove those, if they exist. double and triple + * indirect lbns do not overlap with others so it is not important + * to verify how many levels are required. + */ + lbn = lblkno(fs, length); + if (lbn >= NDADDR) { + /* Calculate the virtual lbn of the triple indirect. */ + lbn = -lbn - (NIADDR - 1); + end = OFF_TO_IDX(lblktosize(fs, lbn)); + } else + end = extend; + vn_pages_remove(vp, OFF_TO_IDX(OFF_MAX), end); +} + +/* + * See if the buf bp is in the range eliminated by truncation. + */ +static int +trunc_check_buf(bp, blkoffp, lastlbn, lastoff, flags) + struct buf *bp; + int *blkoffp; + ufs_lbn_t lastlbn; + int lastoff; + int flags; +{ + ufs_lbn_t lbn; + + *blkoffp = 0; + /* Only match ext/normal blocks as appropriate. */ + if (((flags & IO_EXT) == 0 && (bp->b_xflags & BX_ALTDATA)) || + ((flags & IO_NORMAL) == 0 && (bp->b_xflags & BX_ALTDATA) == 0)) + return (0); + /* ALTDATA is always a full truncation. */ + if ((bp->b_xflags & BX_ALTDATA) != 0) + return (1); + /* -1 is full truncation. */ + if (lastlbn == -1) + return (1); + /* + * If this is a partial truncate we only want those + * blocks and indirect blocks that cover the range + * we're after. + */ + lbn = bp->b_lblkno; + if (lbn < 0) + lbn = -(lbn + lbn_level(lbn)); + if (lbn < lastlbn) + return (0); + /* Here we only truncate lblkno if it's partial. */ + if (lbn == lastlbn) { + if (lastoff == 0) + return (0); + *blkoffp = lastoff; + } + return (1); +} + +/* + * Eliminate any dependencies that exist in memory beyond lblkno:off + */ +static void +trunc_dependencies(ip, freeblks, lastlbn, lastoff, flags) + struct inode *ip; + struct freeblks *freeblks; + ufs_lbn_t lastlbn; + int lastoff; + int flags; +{ + struct bufobj *bo; + struct vnode *vp; + struct buf *bp; + int blkoff; + + /* + * We must wait for any I/O in progress to finish so that + * all potential buffers on the dirty list will be visible. + * Once they are all there, walk the list and get rid of + * any dependencies. + */ + vp = ITOV(ip); + bo = &vp->v_bufobj; + BO_LOCK(bo); + drain_output(vp); + TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) + bp->b_vflags &= ~BV_SCANNED; +restart: + TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) { + if (bp->b_vflags & BV_SCANNED) + continue; + if (!trunc_check_buf(bp, &blkoff, lastlbn, lastoff, flags)) { + bp->b_vflags |= BV_SCANNED; + continue; + } + KASSERT(bp->b_bufobj == bo, ("Wrong object in buffer")); + if ((bp = getdirtybuf(bp, BO_LOCKPTR(bo), MNT_WAIT)) == NULL) + goto restart; + BO_UNLOCK(bo); + if (deallocate_dependencies(bp, freeblks, blkoff)) + bqrelse(bp); + else + brelse(bp); + BO_LOCK(bo); + goto restart; + } + /* + * Now do the work of vtruncbuf while also matching indirect blocks. + */ + TAILQ_FOREACH(bp, &bo->bo_clean.bv_hd, b_bobufs) + bp->b_vflags &= ~BV_SCANNED; +cleanrestart: + TAILQ_FOREACH(bp, &bo->bo_clean.bv_hd, b_bobufs) { + if (bp->b_vflags & BV_SCANNED) + continue; + if (!trunc_check_buf(bp, &blkoff, lastlbn, lastoff, flags)) { + bp->b_vflags |= BV_SCANNED; + continue; + } + if (BUF_LOCK(bp, + LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, + BO_LOCKPTR(bo)) == ENOLCK) { + BO_LOCK(bo); + goto cleanrestart; + } + bp->b_vflags |= BV_SCANNED; + bremfree(bp); + if (blkoff != 0) { + allocbuf(bp, blkoff); + bqrelse(bp); + } else { + bp->b_flags |= B_INVAL | B_NOCACHE | B_RELBUF; + brelse(bp); + } + BO_LOCK(bo); + goto cleanrestart; + } + drain_output(vp); + BO_UNLOCK(bo); +} + +static int +cancel_pagedep(pagedep, freeblks, blkoff) + struct pagedep *pagedep; + struct freeblks *freeblks; + int blkoff; +{ + struct jremref *jremref; + struct jmvref *jmvref; + struct dirrem *dirrem, *tmp; + int i; + + /* + * Copy any directory remove dependencies to the list + * to be processed after the freeblks proceeds. If + * directory entry never made it to disk they + * can be dumped directly onto the work list. + */ + LIST_FOREACH_SAFE(dirrem, &pagedep->pd_dirremhd, dm_next, tmp) { + /* Skip this directory removal if it is intended to remain. */ + if (dirrem->dm_offset < blkoff) + continue; + /* + * If there are any dirrems we wait for the journal write + * to complete and then restart the buf scan as the lock + * has been dropped. + */ + while ((jremref = LIST_FIRST(&dirrem->dm_jremrefhd)) != NULL) { + jwait(&jremref->jr_list, MNT_WAIT); + return (ERESTART); + } + LIST_REMOVE(dirrem, dm_next); + dirrem->dm_dirinum = pagedep->pd_ino; + WORKLIST_INSERT(&freeblks->fb_freeworkhd, &dirrem->dm_list); + } + while ((jmvref = LIST_FIRST(&pagedep->pd_jmvrefhd)) != NULL) { + jwait(&jmvref->jm_list, MNT_WAIT); + return (ERESTART); + } + /* + * When we're partially truncating a pagedep we just want to flush + * journal entries and return. There can not be any adds in the + * truncated portion of the directory and newblk must remain if + * part of the block remains. + */ + if (blkoff != 0) { + struct diradd *dap; + + LIST_FOREACH(dap, &pagedep->pd_pendinghd, da_pdlist) + if (dap->da_offset > blkoff) + panic("cancel_pagedep: diradd %p off %d > %d", + dap, dap->da_offset, blkoff); + for (i = 0; i < DAHASHSZ; i++) + LIST_FOREACH(dap, &pagedep->pd_diraddhd[i], da_pdlist) + if (dap->da_offset > blkoff) + panic("cancel_pagedep: diradd %p off %d > %d", + dap, dap->da_offset, blkoff); + return (0); + } + /* + * There should be no directory add dependencies present + * as the directory could not be truncated until all + * children were removed. + */ + KASSERT(LIST_FIRST(&pagedep->pd_pendinghd) == NULL, + ("deallocate_dependencies: pendinghd != NULL")); + for (i = 0; i < DAHASHSZ; i++) + KASSERT(LIST_FIRST(&pagedep->pd_diraddhd[i]) == NULL, + ("deallocate_dependencies: diraddhd != NULL")); + if ((pagedep->pd_state & NEWBLOCK) != 0) + free_newdirblk(pagedep->pd_newdirblk); + if (free_pagedep(pagedep) == 0) + panic("Failed to free pagedep %p", pagedep); + return (0); +} + +/* + * Reclaim any dependency structures from a buffer that is about to + * be reallocated to a new vnode. The buffer must be locked, thus, + * no I/O completion operations can occur while we are manipulating + * its associated dependencies. The mutex is held so that other I/O's + * associated with related dependencies do not occur. + */ +static int +deallocate_dependencies(bp, freeblks, off) + struct buf *bp; + struct freeblks *freeblks; + int off; +{ + struct indirdep *indirdep; + struct pagedep *pagedep; + struct worklist *wk, *wkn; + struct ufsmount *ump; + + ump = softdep_bp_to_mp(bp); + if (ump == NULL) + goto done; + ACQUIRE_LOCK(ump); + LIST_FOREACH_SAFE(wk, &bp->b_dep, wk_list, wkn) { + switch (wk->wk_type) { + case D_INDIRDEP: + indirdep = WK_INDIRDEP(wk); + if (bp->b_lblkno >= 0 || + bp->b_blkno != indirdep->ir_savebp->b_lblkno) + panic("deallocate_dependencies: not indir"); + cancel_indirdep(indirdep, bp, freeblks); + continue; + + case D_PAGEDEP: + pagedep = WK_PAGEDEP(wk); + if (cancel_pagedep(pagedep, freeblks, off)) { + FREE_LOCK(ump); + return (ERESTART); + } + continue; + + case D_ALLOCINDIR: + /* + * Simply remove the allocindir, we'll find it via + * the indirdep where we can clear pointers if + * needed. + */ + WORKLIST_REMOVE(wk); + continue; + + case D_FREEWORK: + /* + * A truncation is waiting for the zero'd pointers + * to be written. It can be freed when the freeblks + * is journaled. + */ + WORKLIST_REMOVE(wk); + wk->wk_state |= ONDEPLIST; + WORKLIST_INSERT(&freeblks->fb_freeworkhd, wk); + break; + + case D_ALLOCDIRECT: + if (off != 0) + continue; + /* FALLTHROUGH */ + default: + panic("deallocate_dependencies: Unexpected type %s", + TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + } + FREE_LOCK(ump); +done: + /* + * Don't throw away this buf, we were partially truncating and + * some deps may always remain. + */ + if (off) { + allocbuf(bp, off); + bp->b_vflags |= BV_SCANNED; + return (EBUSY); + } + bp->b_flags |= B_INVAL | B_NOCACHE; + + return (0); +} + +/* + * An allocdirect is being canceled due to a truncate. We must make sure + * the journal entry is released in concert with the blkfree that releases + * the storage. Completed journal entries must not be released until the + * space is no longer pointed to by the inode or in the bitmap. + */ +static void +cancel_allocdirect(adphead, adp, freeblks) + struct allocdirectlst *adphead; + struct allocdirect *adp; + struct freeblks *freeblks; +{ + struct freework *freework; + struct newblk *newblk; + struct worklist *wk; + + TAILQ_REMOVE(adphead, adp, ad_next); + newblk = (struct newblk *)adp; + freework = NULL; + /* + * Find the correct freework structure. + */ + LIST_FOREACH(wk, &freeblks->fb_freeworkhd, wk_list) { + if (wk->wk_type != D_FREEWORK) + continue; + freework = WK_FREEWORK(wk); + if (freework->fw_blkno == newblk->nb_newblkno) + break; + } + if (freework == NULL) + panic("cancel_allocdirect: Freework not found"); + /* + * If a newblk exists at all we still have the journal entry that + * initiated the allocation so we do not need to journal the free. + */ + cancel_jfreeblk(freeblks, freework->fw_blkno); + /* + * If the journal hasn't been written the jnewblk must be passed + * to the call to ffs_blkfree that reclaims the space. We accomplish + * this by linking the journal dependency into the freework to be + * freed when freework_freeblock() is called. If the journal has + * been written we can simply reclaim the journal space when the + * freeblks work is complete. + */ + freework->fw_jnewblk = cancel_newblk(newblk, &freework->fw_list, + &freeblks->fb_jwork); + WORKLIST_INSERT(&freeblks->fb_freeworkhd, &newblk->nb_list); +} + + +/* + * Cancel a new block allocation. May be an indirect or direct block. We + * remove it from various lists and return any journal record that needs to + * be resolved by the caller. + * + * A special consideration is made for indirects which were never pointed + * at on disk and will never be found once this block is released. + */ +static struct jnewblk * +cancel_newblk(newblk, wk, wkhd) + struct newblk *newblk; + struct worklist *wk; + struct workhead *wkhd; +{ + struct jnewblk *jnewblk; + + CTR1(KTR_SUJ, "cancel_newblk: blkno %jd", newblk->nb_newblkno); + + newblk->nb_state |= GOINGAWAY; + /* + * Previously we traversed the completedhd on each indirdep + * attached to this newblk to cancel them and gather journal + * work. Since we need only the oldest journal segment and + * the lowest point on the tree will always have the oldest + * journal segment we are free to release the segments + * of any subordinates and may leave the indirdep list to + * indirdep_complete() when this newblk is freed. + */ + if (newblk->nb_state & ONDEPLIST) { + newblk->nb_state &= ~ONDEPLIST; + LIST_REMOVE(newblk, nb_deps); + } + if (newblk->nb_state & ONWORKLIST) + WORKLIST_REMOVE(&newblk->nb_list); + /* + * If the journal entry hasn't been written we save a pointer to + * the dependency that frees it until it is written or the + * superseding operation completes. + */ + jnewblk = newblk->nb_jnewblk; + if (jnewblk != NULL && wk != NULL) { + newblk->nb_jnewblk = NULL; + jnewblk->jn_dep = wk; + } + if (!LIST_EMPTY(&newblk->nb_jwork)) + jwork_move(wkhd, &newblk->nb_jwork); + /* + * When truncating we must free the newdirblk early to remove + * the pagedep from the hash before returning. + */ + if ((wk = LIST_FIRST(&newblk->nb_newdirblk)) != NULL) + free_newdirblk(WK_NEWDIRBLK(wk)); + if (!LIST_EMPTY(&newblk->nb_newdirblk)) + panic("cancel_newblk: extra newdirblk"); + + return (jnewblk); +} + +/* + * Schedule the freefrag associated with a newblk to be released once + * the pointers are written and the previous block is no longer needed. + */ +static void +newblk_freefrag(newblk) + struct newblk *newblk; +{ + struct freefrag *freefrag; + + if (newblk->nb_freefrag == NULL) + return; + freefrag = newblk->nb_freefrag; + newblk->nb_freefrag = NULL; + freefrag->ff_state |= COMPLETE; + if ((freefrag->ff_state & ALLCOMPLETE) == ALLCOMPLETE) + add_to_worklist(&freefrag->ff_list, 0); +} + +/* + * Free a newblk. Generate a new freefrag work request if appropriate. + * This must be called after the inode pointer and any direct block pointers + * are valid or fully removed via truncate or frag extension. + */ +static void +free_newblk(newblk) + struct newblk *newblk; +{ + struct indirdep *indirdep; + struct worklist *wk; + + KASSERT(newblk->nb_jnewblk == NULL, + ("free_newblk: jnewblk %p still attached", newblk->nb_jnewblk)); + KASSERT(newblk->nb_list.wk_type != D_NEWBLK, + ("free_newblk: unclaimed newblk")); + LOCK_OWNED(VFSTOUFS(newblk->nb_list.wk_mp)); + newblk_freefrag(newblk); + if (newblk->nb_state & ONDEPLIST) + LIST_REMOVE(newblk, nb_deps); + if (newblk->nb_state & ONWORKLIST) + WORKLIST_REMOVE(&newblk->nb_list); + LIST_REMOVE(newblk, nb_hash); + if ((wk = LIST_FIRST(&newblk->nb_newdirblk)) != NULL) + free_newdirblk(WK_NEWDIRBLK(wk)); + if (!LIST_EMPTY(&newblk->nb_newdirblk)) + panic("free_newblk: extra newdirblk"); + while ((indirdep = LIST_FIRST(&newblk->nb_indirdeps)) != NULL) + indirdep_complete(indirdep); + handle_jwork(&newblk->nb_jwork); + WORKITEM_FREE(newblk, D_NEWBLK); +} + +/* + * Free a newdirblk. Clear the NEWBLOCK flag on its associated pagedep. + * This routine must be called with splbio interrupts blocked. + */ +static void +free_newdirblk(newdirblk) + struct newdirblk *newdirblk; +{ + struct pagedep *pagedep; + struct diradd *dap; + struct worklist *wk; + + LOCK_OWNED(VFSTOUFS(newdirblk->db_list.wk_mp)); + WORKLIST_REMOVE(&newdirblk->db_list); + /* + * If the pagedep is still linked onto the directory buffer + * dependency chain, then some of the entries on the + * pd_pendinghd list may not be committed to disk yet. In + * this case, we will simply clear the NEWBLOCK flag and + * let the pd_pendinghd list be processed when the pagedep + * is next written. If the pagedep is no longer on the buffer + * dependency chain, then all the entries on the pd_pending + * list are committed to disk and we can free them here. + */ + pagedep = newdirblk->db_pagedep; + pagedep->pd_state &= ~NEWBLOCK; + if ((pagedep->pd_state & ONWORKLIST) == 0) { + while ((dap = LIST_FIRST(&pagedep->pd_pendinghd)) != NULL) + free_diradd(dap, NULL); + /* + * If no dependencies remain, the pagedep will be freed. + */ + free_pagedep(pagedep); + } + /* Should only ever be one item in the list. */ + while ((wk = LIST_FIRST(&newdirblk->db_mkdir)) != NULL) { + WORKLIST_REMOVE(wk); + handle_written_mkdir(WK_MKDIR(wk), MKDIR_BODY); + } + WORKITEM_FREE(newdirblk, D_NEWDIRBLK); +} + +/* + * Prepare an inode to be freed. The actual free operation is not + * done until the zero'ed inode has been written to disk. + */ +void +softdep_freefile(pvp, ino, mode) + struct vnode *pvp; + ino_t ino; + int mode; +{ + struct inode *ip = VTOI(pvp); + struct inodedep *inodedep; + struct freefile *freefile; + struct freeblks *freeblks; + struct ufsmount *ump; + + ump = ITOUMP(ip); + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_freefile called on non-softdep filesystem")); + /* + * This sets up the inode de-allocation dependency. + */ + freefile = malloc(sizeof(struct freefile), + M_FREEFILE, M_SOFTDEP_FLAGS); + workitem_alloc(&freefile->fx_list, D_FREEFILE, pvp->v_mount); + freefile->fx_mode = mode; + freefile->fx_oldinum = ino; + freefile->fx_devvp = ump->um_devvp; + LIST_INIT(&freefile->fx_jwork); + UFS_LOCK(ump); + ump->um_fs->fs_pendinginodes += 1; + UFS_UNLOCK(ump); + + /* + * If the inodedep does not exist, then the zero'ed inode has + * been written to disk. If the allocated inode has never been + * written to disk, then the on-disk inode is zero'ed. In either + * case we can free the file immediately. If the journal was + * canceled before being written the inode will never make it to + * disk and we must send the canceled journal entrys to + * ffs_freefile() to be cleared in conjunction with the bitmap. + * Any blocks waiting on the inode to write can be safely freed + * here as it will never been written. + */ + ACQUIRE_LOCK(ump); + inodedep_lookup(pvp->v_mount, ino, 0, &inodedep); + if (inodedep) { + /* + * Clear out freeblks that no longer need to reference + * this inode. + */ + while ((freeblks = + TAILQ_FIRST(&inodedep->id_freeblklst)) != NULL) { + TAILQ_REMOVE(&inodedep->id_freeblklst, freeblks, + fb_next); + freeblks->fb_state &= ~ONDEPLIST; + } + /* + * Remove this inode from the unlinked list. + */ + if (inodedep->id_state & UNLINKED) { + /* + * Save the journal work to be freed with the bitmap + * before we clear UNLINKED. Otherwise it can be lost + * if the inode block is written. + */ + handle_bufwait(inodedep, &freefile->fx_jwork); + clear_unlinked_inodedep(inodedep); + /* + * Re-acquire inodedep as we've dropped the + * per-filesystem lock in clear_unlinked_inodedep(). + */ + inodedep_lookup(pvp->v_mount, ino, 0, &inodedep); + } + } + if (inodedep == NULL || check_inode_unwritten(inodedep)) { + FREE_LOCK(ump); + handle_workitem_freefile(freefile); + return; + } + if ((inodedep->id_state & DEPCOMPLETE) == 0) + inodedep->id_state |= GOINGAWAY; + WORKLIST_INSERT(&inodedep->id_inowait, &freefile->fx_list); + FREE_LOCK(ump); + if (ip->i_number == ino) + ip->i_flag |= IN_MODIFIED; +} + +/* + * Check to see if an inode has never been written to disk. If + * so free the inodedep and return success, otherwise return failure. + * This routine must be called with splbio interrupts blocked. + * + * If we still have a bitmap dependency, then the inode has never + * been written to disk. Drop the dependency as it is no longer + * necessary since the inode is being deallocated. We set the + * ALLCOMPLETE flags since the bitmap now properly shows that the + * inode is not allocated. Even if the inode is actively being + * written, it has been rolled back to its zero'ed state, so we + * are ensured that a zero inode is what is on the disk. For short + * lived files, this change will usually result in removing all the + * dependencies from the inode so that it can be freed immediately. + */ +static int +check_inode_unwritten(inodedep) + struct inodedep *inodedep; +{ + + LOCK_OWNED(VFSTOUFS(inodedep->id_list.wk_mp)); + + if ((inodedep->id_state & (DEPCOMPLETE | UNLINKED)) != 0 || + !LIST_EMPTY(&inodedep->id_dirremhd) || + !LIST_EMPTY(&inodedep->id_pendinghd) || + !LIST_EMPTY(&inodedep->id_bufwait) || + !LIST_EMPTY(&inodedep->id_inowait) || + !TAILQ_EMPTY(&inodedep->id_inoreflst) || + !TAILQ_EMPTY(&inodedep->id_inoupdt) || + !TAILQ_EMPTY(&inodedep->id_newinoupdt) || + !TAILQ_EMPTY(&inodedep->id_extupdt) || + !TAILQ_EMPTY(&inodedep->id_newextupdt) || + !TAILQ_EMPTY(&inodedep->id_freeblklst) || + inodedep->id_mkdiradd != NULL || + inodedep->id_nlinkdelta != 0) + return (0); + /* + * Another process might be in initiate_write_inodeblock_ufs[12] + * trying to allocate memory without holding "Softdep Lock". + */ + if ((inodedep->id_state & IOSTARTED) != 0 && + inodedep->id_savedino1 == NULL) + return (0); + + if (inodedep->id_state & ONDEPLIST) + LIST_REMOVE(inodedep, id_deps); + inodedep->id_state &= ~ONDEPLIST; + inodedep->id_state |= ALLCOMPLETE; + inodedep->id_bmsafemap = NULL; + if (inodedep->id_state & ONWORKLIST) + WORKLIST_REMOVE(&inodedep->id_list); + if (inodedep->id_savedino1 != NULL) { + free(inodedep->id_savedino1, M_SAVEDINO); + inodedep->id_savedino1 = NULL; + } + if (free_inodedep(inodedep) == 0) + panic("check_inode_unwritten: busy inode"); + return (1); +} + +static int +check_inodedep_free(inodedep) + struct inodedep *inodedep; +{ + + LOCK_OWNED(VFSTOUFS(inodedep->id_list.wk_mp)); + if ((inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE || + !LIST_EMPTY(&inodedep->id_dirremhd) || + !LIST_EMPTY(&inodedep->id_pendinghd) || + !LIST_EMPTY(&inodedep->id_bufwait) || + !LIST_EMPTY(&inodedep->id_inowait) || + !TAILQ_EMPTY(&inodedep->id_inoreflst) || + !TAILQ_EMPTY(&inodedep->id_inoupdt) || + !TAILQ_EMPTY(&inodedep->id_newinoupdt) || + !TAILQ_EMPTY(&inodedep->id_extupdt) || + !TAILQ_EMPTY(&inodedep->id_newextupdt) || + !TAILQ_EMPTY(&inodedep->id_freeblklst) || + inodedep->id_mkdiradd != NULL || + inodedep->id_nlinkdelta != 0 || + inodedep->id_savedino1 != NULL) + return (0); + return (1); +} + +/* + * Try to free an inodedep structure. Return 1 if it could be freed. + */ +static int +free_inodedep(inodedep) + struct inodedep *inodedep; +{ + + LOCK_OWNED(VFSTOUFS(inodedep->id_list.wk_mp)); + if ((inodedep->id_state & (ONWORKLIST | UNLINKED)) != 0 || + !check_inodedep_free(inodedep)) + return (0); + if (inodedep->id_state & ONDEPLIST) + LIST_REMOVE(inodedep, id_deps); + LIST_REMOVE(inodedep, id_hash); + WORKITEM_FREE(inodedep, D_INODEDEP); + return (1); +} + +/* + * Free the block referenced by a freework structure. The parent freeblks + * structure is released and completed when the final cg bitmap reaches + * the disk. This routine may be freeing a jnewblk which never made it to + * disk in which case we do not have to wait as the operation is undone + * in memory immediately. + */ +static void +freework_freeblock(freework) + struct freework *freework; +{ + struct freeblks *freeblks; + struct jnewblk *jnewblk; + struct ufsmount *ump; + struct workhead wkhd; + struct fs *fs; + int bsize; + int needj; + + ump = VFSTOUFS(freework->fw_list.wk_mp); + LOCK_OWNED(ump); + /* + * Handle partial truncate separately. + */ + if (freework->fw_indir) { + complete_trunc_indir(freework); + return; + } + freeblks = freework->fw_freeblks; + fs = ump->um_fs; + needj = MOUNTEDSUJ(freeblks->fb_list.wk_mp) != 0; + bsize = lfragtosize(fs, freework->fw_frags); + LIST_INIT(&wkhd); + /* + * DEPCOMPLETE is cleared in indirblk_insert() if the block lives + * on the indirblk hashtable and prevents premature freeing. + */ + freework->fw_state |= DEPCOMPLETE; + /* + * SUJ needs to wait for the segment referencing freed indirect + * blocks to expire so that we know the checker will not confuse + * a re-allocated indirect block with its old contents. + */ + if (needj && freework->fw_lbn <= -NDADDR) + indirblk_insert(freework); + /* + * If we are canceling an existing jnewblk pass it to the free + * routine, otherwise pass the freeblk which will ultimately + * release the freeblks. If we're not journaling, we can just + * free the freeblks immediately. + */ + jnewblk = freework->fw_jnewblk; + if (jnewblk != NULL) { + cancel_jnewblk(jnewblk, &wkhd); + needj = 0; + } else if (needj) { + freework->fw_state |= DELAYEDFREE; + freeblks->fb_cgwait++; + WORKLIST_INSERT(&wkhd, &freework->fw_list); + } + FREE_LOCK(ump); + freeblks_free(ump, freeblks, btodb(bsize)); + CTR4(KTR_SUJ, + "freework_freeblock: ino %d blkno %jd lbn %jd size %ld", + freeblks->fb_inum, freework->fw_blkno, freework->fw_lbn, bsize); + ffs_blkfree(ump, fs, freeblks->fb_devvp, freework->fw_blkno, bsize, + freeblks->fb_inum, freeblks->fb_vtype, &wkhd); + ACQUIRE_LOCK(ump); + /* + * The jnewblk will be discarded and the bits in the map never + * made it to disk. We can immediately free the freeblk. + */ + if (needj == 0) + handle_written_freework(freework); +} + +/* + * We enqueue freework items that need processing back on the freeblks and + * add the freeblks to the worklist. This makes it easier to find all work + * required to flush a truncation in process_truncates(). + */ +static void +freework_enqueue(freework) + struct freework *freework; +{ + struct freeblks *freeblks; + + freeblks = freework->fw_freeblks; + if ((freework->fw_state & INPROGRESS) == 0) + WORKLIST_INSERT(&freeblks->fb_freeworkhd, &freework->fw_list); + if ((freeblks->fb_state & + (ONWORKLIST | INPROGRESS | ALLCOMPLETE)) == ALLCOMPLETE && + LIST_EMPTY(&freeblks->fb_jblkdephd)) + add_to_worklist(&freeblks->fb_list, WK_NODELAY); +} + +/* + * Start, continue, or finish the process of freeing an indirect block tree. + * The free operation may be paused at any point with fw_off containing the + * offset to restart from. This enables us to implement some flow control + * for large truncates which may fan out and generate a huge number of + * dependencies. + */ +static void +handle_workitem_indirblk(freework) + struct freework *freework; +{ + struct freeblks *freeblks; + struct ufsmount *ump; + struct fs *fs; + + freeblks = freework->fw_freeblks; + ump = VFSTOUFS(freeblks->fb_list.wk_mp); + fs = ump->um_fs; + if (freework->fw_state & DEPCOMPLETE) { + handle_written_freework(freework); + return; + } + if (freework->fw_off == NINDIR(fs)) { + freework_freeblock(freework); + return; + } + freework->fw_state |= INPROGRESS; + FREE_LOCK(ump); + indir_trunc(freework, fsbtodb(fs, freework->fw_blkno), + freework->fw_lbn); + ACQUIRE_LOCK(ump); +} + +/* + * Called when a freework structure attached to a cg buf is written. The + * ref on either the parent or the freeblks structure is released and + * the freeblks is added back to the worklist if there is more work to do. + */ +static void +handle_written_freework(freework) + struct freework *freework; +{ + struct freeblks *freeblks; + struct freework *parent; + + freeblks = freework->fw_freeblks; + parent = freework->fw_parent; + if (freework->fw_state & DELAYEDFREE) + freeblks->fb_cgwait--; + freework->fw_state |= COMPLETE; + if ((freework->fw_state & ALLCOMPLETE) == ALLCOMPLETE) + WORKITEM_FREE(freework, D_FREEWORK); + if (parent) { + if (--parent->fw_ref == 0) + freework_enqueue(parent); + return; + } + if (--freeblks->fb_ref != 0) + return; + if ((freeblks->fb_state & (ALLCOMPLETE | ONWORKLIST | INPROGRESS)) == + ALLCOMPLETE && LIST_EMPTY(&freeblks->fb_jblkdephd)) + add_to_worklist(&freeblks->fb_list, WK_NODELAY); +} + +/* + * This workitem routine performs the block de-allocation. + * The workitem is added to the pending list after the updated + * inode block has been written to disk. As mentioned above, + * checks regarding the number of blocks de-allocated (compared + * to the number of blocks allocated for the file) are also + * performed in this function. + */ +static int +handle_workitem_freeblocks(freeblks, flags) + struct freeblks *freeblks; + int flags; +{ + struct freework *freework; + struct newblk *newblk; + struct allocindir *aip; + struct ufsmount *ump; + struct worklist *wk; + + KASSERT(LIST_EMPTY(&freeblks->fb_jblkdephd), + ("handle_workitem_freeblocks: Journal entries not written.")); + ump = VFSTOUFS(freeblks->fb_list.wk_mp); + ACQUIRE_LOCK(ump); + while ((wk = LIST_FIRST(&freeblks->fb_freeworkhd)) != NULL) { + WORKLIST_REMOVE(wk); + switch (wk->wk_type) { + case D_DIRREM: + wk->wk_state |= COMPLETE; + add_to_worklist(wk, 0); + continue; + + case D_ALLOCDIRECT: + free_newblk(WK_NEWBLK(wk)); + continue; + + case D_ALLOCINDIR: + aip = WK_ALLOCINDIR(wk); + freework = NULL; + if (aip->ai_state & DELAYEDFREE) { + FREE_LOCK(ump); + freework = newfreework(ump, freeblks, NULL, + aip->ai_lbn, aip->ai_newblkno, + ump->um_fs->fs_frag, 0, 0); + ACQUIRE_LOCK(ump); + } + newblk = WK_NEWBLK(wk); + if (newblk->nb_jnewblk) { + freework->fw_jnewblk = newblk->nb_jnewblk; + newblk->nb_jnewblk->jn_dep = &freework->fw_list; + newblk->nb_jnewblk = NULL; + } + free_newblk(newblk); + continue; + + case D_FREEWORK: + freework = WK_FREEWORK(wk); + if (freework->fw_lbn <= -NDADDR) + handle_workitem_indirblk(freework); + else + freework_freeblock(freework); + continue; + default: + panic("handle_workitem_freeblocks: Unknown type %s", + TYPENAME(wk->wk_type)); + } + } + if (freeblks->fb_ref != 0) { + freeblks->fb_state &= ~INPROGRESS; + wake_worklist(&freeblks->fb_list); + freeblks = NULL; + } + FREE_LOCK(ump); + if (freeblks) + return handle_complete_freeblocks(freeblks, flags); + return (0); +} + +/* + * Handle completion of block free via truncate. This allows fs_pending + * to track the actual free block count more closely than if we only updated + * it at the end. We must be careful to handle cases where the block count + * on free was incorrect. + */ +static void +freeblks_free(ump, freeblks, blocks) + struct ufsmount *ump; + struct freeblks *freeblks; + int blocks; +{ + struct fs *fs; + ufs2_daddr_t remain; + + UFS_LOCK(ump); + remain = -freeblks->fb_chkcnt; + freeblks->fb_chkcnt += blocks; + if (remain > 0) { + if (remain < blocks) + blocks = remain; + fs = ump->um_fs; + fs->fs_pendingblocks -= blocks; + } + UFS_UNLOCK(ump); +} + +/* + * Once all of the freework workitems are complete we can retire the + * freeblocks dependency and any journal work awaiting completion. This + * can not be called until all other dependencies are stable on disk. + */ +static int +handle_complete_freeblocks(freeblks, flags) + struct freeblks *freeblks; + int flags; +{ + struct inodedep *inodedep; + struct inode *ip; + struct vnode *vp; + struct fs *fs; + struct ufsmount *ump; + ufs2_daddr_t spare; + + ump = VFSTOUFS(freeblks->fb_list.wk_mp); + fs = ump->um_fs; + flags = LK_EXCLUSIVE | flags; + spare = freeblks->fb_chkcnt; + + /* + * If we did not release the expected number of blocks we may have + * to adjust the inode block count here. Only do so if it wasn't + * a truncation to zero and the modrev still matches. + */ + if (spare && freeblks->fb_len != 0) { + if (ffs_vgetf(freeblks->fb_list.wk_mp, freeblks->fb_inum, + flags, &vp, FFSV_FORCEINSMQ) != 0) + return (EBUSY); + ip = VTOI(vp); + if (DIP(ip, i_modrev) == freeblks->fb_modrev) { + DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - spare); + ip->i_flag |= IN_CHANGE; + /* + * We must wait so this happens before the + * journal is reclaimed. + */ + ffs_update(vp, 1); + } + vput(vp); + } + if (spare < 0) { + UFS_LOCK(ump); + fs->fs_pendingblocks += spare; + UFS_UNLOCK(ump); + } +#ifdef QUOTA + /* Handle spare. */ + if (spare) + quotaadj(freeblks->fb_quota, ump, -spare); + quotarele(freeblks->fb_quota); +#endif + ACQUIRE_LOCK(ump); + if (freeblks->fb_state & ONDEPLIST) { + inodedep_lookup(freeblks->fb_list.wk_mp, freeblks->fb_inum, + 0, &inodedep); + TAILQ_REMOVE(&inodedep->id_freeblklst, freeblks, fb_next); + freeblks->fb_state &= ~ONDEPLIST; + if (TAILQ_EMPTY(&inodedep->id_freeblklst)) + free_inodedep(inodedep); + } + /* + * All of the freeblock deps must be complete prior to this call + * so it's now safe to complete earlier outstanding journal entries. + */ + handle_jwork(&freeblks->fb_jwork); + WORKITEM_FREE(freeblks, D_FREEBLKS); + FREE_LOCK(ump); + return (0); +} + +/* + * Release blocks associated with the freeblks and stored in the indirect + * block dbn. If level is greater than SINGLE, the block is an indirect block + * and recursive calls to indirtrunc must be used to cleanse other indirect + * blocks. + * + * This handles partial and complete truncation of blocks. Partial is noted + * with goingaway == 0. In this case the freework is completed after the + * zero'd indirects are written to disk. For full truncation the freework + * is completed after the block is freed. + */ +static void +indir_trunc(freework, dbn, lbn) + struct freework *freework; + ufs2_daddr_t dbn; + ufs_lbn_t lbn; +{ + struct freework *nfreework; + struct workhead wkhd; + struct freeblks *freeblks; + struct buf *bp; + struct fs *fs; + struct indirdep *indirdep; + struct ufsmount *ump; + ufs1_daddr_t *bap1; + ufs2_daddr_t nb, nnb, *bap2; + ufs_lbn_t lbnadd, nlbn; + int i, nblocks, ufs1fmt; + int freedblocks; + int goingaway; + int freedeps; + int needj; + int level; + int cnt; + + freeblks = freework->fw_freeblks; + ump = VFSTOUFS(freeblks->fb_list.wk_mp); + fs = ump->um_fs; + /* + * Get buffer of block pointers to be freed. There are three cases: + * + * 1) Partial truncate caches the indirdep pointer in the freework + * which provides us a back copy to the save bp which holds the + * pointers we want to clear. When this completes the zero + * pointers are written to the real copy. + * 2) The indirect is being completely truncated, cancel_indirdep() + * eliminated the real copy and placed the indirdep on the saved + * copy. The indirdep and buf are discarded when this completes. + * 3) The indirect was not in memory, we read a copy off of the disk + * using the devvp and drop and invalidate the buffer when we're + * done. + */ + goingaway = 1; + indirdep = NULL; + if (freework->fw_indir != NULL) { + goingaway = 0; + indirdep = freework->fw_indir; + bp = indirdep->ir_savebp; + if (bp == NULL || bp->b_blkno != dbn) + panic("indir_trunc: Bad saved buf %p blkno %jd", + bp, (intmax_t)dbn); + } else if ((bp = incore(&freeblks->fb_devvp->v_bufobj, dbn)) != NULL) { + /* + * The lock prevents the buf dep list from changing and + * indirects on devvp should only ever have one dependency. + */ + indirdep = WK_INDIRDEP(LIST_FIRST(&bp->b_dep)); + if (indirdep == NULL || (indirdep->ir_state & GOINGAWAY) == 0) + panic("indir_trunc: Bad indirdep %p from buf %p", + indirdep, bp); + } else if (bread(freeblks->fb_devvp, dbn, (int)fs->fs_bsize, + NOCRED, &bp) != 0) { + brelse(bp); + return; + } + ACQUIRE_LOCK(ump); + /* Protects against a race with complete_trunc_indir(). */ + freework->fw_state &= ~INPROGRESS; + /* + * If we have an indirdep we need to enforce the truncation order + * and discard it when it is complete. + */ + if (indirdep) { + if (freework != TAILQ_FIRST(&indirdep->ir_trunc) && + !TAILQ_EMPTY(&indirdep->ir_trunc)) { + /* + * Add the complete truncate to the list on the + * indirdep to enforce in-order processing. + */ + if (freework->fw_indir == NULL) + TAILQ_INSERT_TAIL(&indirdep->ir_trunc, + freework, fw_next); + FREE_LOCK(ump); + return; + } + /* + * If we're goingaway, free the indirdep. Otherwise it will + * linger until the write completes. + */ + if (goingaway) + free_indirdep(indirdep); + } + FREE_LOCK(ump); + /* Initialize pointers depending on block size. */ + if (ump->um_fstype == UFS1) { + bap1 = (ufs1_daddr_t *)bp->b_data; + nb = bap1[freework->fw_off]; + ufs1fmt = 1; + bap2 = NULL; + } else { + bap2 = (ufs2_daddr_t *)bp->b_data; + nb = bap2[freework->fw_off]; + ufs1fmt = 0; + bap1 = NULL; + } + level = lbn_level(lbn); + needj = MOUNTEDSUJ(UFSTOVFS(ump)) != 0; + lbnadd = lbn_offset(fs, level); + nblocks = btodb(fs->fs_bsize); + nfreework = freework; + freedeps = 0; + cnt = 0; + /* + * Reclaim blocks. Traverses into nested indirect levels and + * arranges for the current level to be freed when subordinates + * are free when journaling. + */ + for (i = freework->fw_off; i < NINDIR(fs); i++, nb = nnb) { + if (i != NINDIR(fs) - 1) { + if (ufs1fmt) + nnb = bap1[i+1]; + else + nnb = bap2[i+1]; + } else + nnb = 0; + if (nb == 0) + continue; + cnt++; + if (level != 0) { + nlbn = (lbn + 1) - (i * lbnadd); + if (needj != 0) { + nfreework = newfreework(ump, freeblks, freework, + nlbn, nb, fs->fs_frag, 0, 0); + freedeps++; + } + indir_trunc(nfreework, fsbtodb(fs, nb), nlbn); + } else { + struct freedep *freedep; + + /* + * Attempt to aggregate freedep dependencies for + * all blocks being released to the same CG. + */ + LIST_INIT(&wkhd); + if (needj != 0 && + (nnb == 0 || (dtog(fs, nb) != dtog(fs, nnb)))) { + freedep = newfreedep(freework); + WORKLIST_INSERT_UNLOCKED(&wkhd, + &freedep->fd_list); + freedeps++; + } + CTR3(KTR_SUJ, + "indir_trunc: ino %d blkno %jd size %ld", + freeblks->fb_inum, nb, fs->fs_bsize); + ffs_blkfree(ump, fs, freeblks->fb_devvp, nb, + fs->fs_bsize, freeblks->fb_inum, + freeblks->fb_vtype, &wkhd); + } + } + if (goingaway) { + bp->b_flags |= B_INVAL | B_NOCACHE; + brelse(bp); + } + freedblocks = 0; + if (level == 0) + freedblocks = (nblocks * cnt); + if (needj == 0) + freedblocks += nblocks; + freeblks_free(ump, freeblks, freedblocks); + /* + * If we are journaling set up the ref counts and offset so this + * indirect can be completed when its children are free. + */ + if (needj) { + ACQUIRE_LOCK(ump); + freework->fw_off = i; + freework->fw_ref += freedeps; + freework->fw_ref -= NINDIR(fs) + 1; + if (level == 0) + freeblks->fb_cgwait += freedeps; + if (freework->fw_ref == 0) + freework_freeblock(freework); + FREE_LOCK(ump); + return; + } + /* + * If we're not journaling we can free the indirect now. + */ + dbn = dbtofsb(fs, dbn); + CTR3(KTR_SUJ, + "indir_trunc 2: ino %d blkno %jd size %ld", + freeblks->fb_inum, dbn, fs->fs_bsize); + ffs_blkfree(ump, fs, freeblks->fb_devvp, dbn, fs->fs_bsize, + freeblks->fb_inum, freeblks->fb_vtype, NULL); + /* Non SUJ softdep does single-threaded truncations. */ + if (freework->fw_blkno == dbn) { + freework->fw_state |= ALLCOMPLETE; + ACQUIRE_LOCK(ump); + handle_written_freework(freework); + FREE_LOCK(ump); + } + return; +} + +/* + * Cancel an allocindir when it is removed via truncation. When bp is not + * NULL the indirect never appeared on disk and is scheduled to be freed + * independently of the indir so we can more easily track journal work. + */ +static void +cancel_allocindir(aip, bp, freeblks, trunc) + struct allocindir *aip; + struct buf *bp; + struct freeblks *freeblks; + int trunc; +{ + struct indirdep *indirdep; + struct freefrag *freefrag; + struct newblk *newblk; + + newblk = (struct newblk *)aip; + LIST_REMOVE(aip, ai_next); + /* + * We must eliminate the pointer in bp if it must be freed on its + * own due to partial truncate or pending journal work. + */ + if (bp && (trunc || newblk->nb_jnewblk)) { + /* + * Clear the pointer and mark the aip to be freed + * directly if it never existed on disk. + */ + aip->ai_state |= DELAYEDFREE; + indirdep = aip->ai_indirdep; + if (indirdep->ir_state & UFS1FMT) + ((ufs1_daddr_t *)bp->b_data)[aip->ai_offset] = 0; + else + ((ufs2_daddr_t *)bp->b_data)[aip->ai_offset] = 0; + } + /* + * When truncating the previous pointer will be freed via + * savedbp. Eliminate the freefrag which would dup free. + */ + if (trunc && (freefrag = newblk->nb_freefrag) != NULL) { + newblk->nb_freefrag = NULL; + if (freefrag->ff_jdep) + cancel_jfreefrag( + WK_JFREEFRAG(freefrag->ff_jdep)); + jwork_move(&freeblks->fb_jwork, &freefrag->ff_jwork); + WORKITEM_FREE(freefrag, D_FREEFRAG); + } + /* + * If the journal hasn't been written the jnewblk must be passed + * to the call to ffs_blkfree that reclaims the space. We accomplish + * this by leaving the journal dependency on the newblk to be freed + * when a freework is created in handle_workitem_freeblocks(). + */ + cancel_newblk(newblk, NULL, &freeblks->fb_jwork); + WORKLIST_INSERT(&freeblks->fb_freeworkhd, &newblk->nb_list); +} + +/* + * Create the mkdir dependencies for . and .. in a new directory. Link them + * in to a newdirblk so any subsequent additions are tracked properly. The + * caller is responsible for adding the mkdir1 dependency to the journal + * and updating id_mkdiradd. This function returns with the per-filesystem + * lock held. + */ +static struct mkdir * +setup_newdir(dap, newinum, dinum, newdirbp, mkdirp) + struct diradd *dap; + ino_t newinum; + ino_t dinum; + struct buf *newdirbp; + struct mkdir **mkdirp; +{ + struct newblk *newblk; + struct pagedep *pagedep; + struct inodedep *inodedep; + struct newdirblk *newdirblk; + struct mkdir *mkdir1, *mkdir2; + struct worklist *wk; + struct jaddref *jaddref; + struct ufsmount *ump; + struct mount *mp; + + mp = dap->da_list.wk_mp; + ump = VFSTOUFS(mp); + newdirblk = malloc(sizeof(struct newdirblk), M_NEWDIRBLK, + M_SOFTDEP_FLAGS); + workitem_alloc(&newdirblk->db_list, D_NEWDIRBLK, mp); + LIST_INIT(&newdirblk->db_mkdir); + mkdir1 = malloc(sizeof(struct mkdir), M_MKDIR, M_SOFTDEP_FLAGS); + workitem_alloc(&mkdir1->md_list, D_MKDIR, mp); + mkdir1->md_state = ATTACHED | MKDIR_BODY; + mkdir1->md_diradd = dap; + mkdir1->md_jaddref = NULL; + mkdir2 = malloc(sizeof(struct mkdir), M_MKDIR, M_SOFTDEP_FLAGS); + workitem_alloc(&mkdir2->md_list, D_MKDIR, mp); + mkdir2->md_state = ATTACHED | MKDIR_PARENT; + mkdir2->md_diradd = dap; + mkdir2->md_jaddref = NULL; + if (MOUNTEDSUJ(mp) == 0) { + mkdir1->md_state |= DEPCOMPLETE; + mkdir2->md_state |= DEPCOMPLETE; + } + /* + * Dependency on "." and ".." being written to disk. + */ + mkdir1->md_buf = newdirbp; + ACQUIRE_LOCK(VFSTOUFS(mp)); + LIST_INSERT_HEAD(&ump->softdep_mkdirlisthd, mkdir1, md_mkdirs); + /* + * We must link the pagedep, allocdirect, and newdirblk for + * the initial file page so the pointer to the new directory + * is not written until the directory contents are live and + * any subsequent additions are not marked live until the + * block is reachable via the inode. + */ + if (pagedep_lookup(mp, newdirbp, newinum, 0, 0, &pagedep) == 0) + panic("setup_newdir: lost pagedep"); + LIST_FOREACH(wk, &newdirbp->b_dep, wk_list) + if (wk->wk_type == D_ALLOCDIRECT) + break; + if (wk == NULL) + panic("setup_newdir: lost allocdirect"); + if (pagedep->pd_state & NEWBLOCK) + panic("setup_newdir: NEWBLOCK already set"); + newblk = WK_NEWBLK(wk); + pagedep->pd_state |= NEWBLOCK; + pagedep->pd_newdirblk = newdirblk; + newdirblk->db_pagedep = pagedep; + WORKLIST_INSERT(&newblk->nb_newdirblk, &newdirblk->db_list); + WORKLIST_INSERT(&newdirblk->db_mkdir, &mkdir1->md_list); + /* + * Look up the inodedep for the parent directory so that we + * can link mkdir2 into the pending dotdot jaddref or + * the inode write if there is none. If the inode is + * ALLCOMPLETE and no jaddref is present all dependencies have + * been satisfied and mkdir2 can be freed. + */ + inodedep_lookup(mp, dinum, 0, &inodedep); + if (MOUNTEDSUJ(mp)) { + if (inodedep == NULL) + panic("setup_newdir: Lost parent."); + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref != NULL && jaddref->ja_parent == newinum && + (jaddref->ja_state & MKDIR_PARENT), + ("setup_newdir: bad dotdot jaddref %p", jaddref)); + LIST_INSERT_HEAD(&ump->softdep_mkdirlisthd, mkdir2, md_mkdirs); + mkdir2->md_jaddref = jaddref; + jaddref->ja_mkdir = mkdir2; + } else if (inodedep == NULL || + (inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) { + dap->da_state &= ~MKDIR_PARENT; + WORKITEM_FREE(mkdir2, D_MKDIR); + mkdir2 = NULL; + } else { + LIST_INSERT_HEAD(&ump->softdep_mkdirlisthd, mkdir2, md_mkdirs); + WORKLIST_INSERT(&inodedep->id_bufwait, &mkdir2->md_list); + } + *mkdirp = mkdir2; + + return (mkdir1); +} + +/* + * Directory entry addition dependencies. + * + * When adding a new directory entry, the inode (with its incremented link + * count) must be written to disk before the directory entry's pointer to it. + * Also, if the inode is newly allocated, the corresponding freemap must be + * updated (on disk) before the directory entry's pointer. These requirements + * are met via undo/redo on the directory entry's pointer, which consists + * simply of the inode number. + * + * As directory entries are added and deleted, the free space within a + * directory block can become fragmented. The ufs filesystem will compact + * a fragmented directory block to make space for a new entry. When this + * occurs, the offsets of previously added entries change. Any "diradd" + * dependency structures corresponding to these entries must be updated with + * the new offsets. + */ + +/* + * This routine is called after the in-memory inode's link + * count has been incremented, but before the directory entry's + * pointer to the inode has been set. + */ +int +softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp, isnewblk) + struct buf *bp; /* buffer containing directory block */ + struct inode *dp; /* inode for directory */ + off_t diroffset; /* offset of new entry in directory */ + ino_t newinum; /* inode referenced by new directory entry */ + struct buf *newdirbp; /* non-NULL => contents of new mkdir */ + int isnewblk; /* entry is in a newly allocated block */ +{ + int offset; /* offset of new entry within directory block */ + ufs_lbn_t lbn; /* block in directory containing new entry */ + struct fs *fs; + struct diradd *dap; + struct newblk *newblk; + struct pagedep *pagedep; + struct inodedep *inodedep; + struct newdirblk *newdirblk; + struct mkdir *mkdir1, *mkdir2; + struct jaddref *jaddref; + struct ufsmount *ump; + struct mount *mp; + int isindir; + + mp = ITOVFS(dp); + ump = VFSTOUFS(mp); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_directory_add called on non-softdep filesystem")); + /* + * Whiteouts have no dependencies. + */ + if (newinum == WINO) { + if (newdirbp != NULL) + bdwrite(newdirbp); + return (0); + } + jaddref = NULL; + mkdir1 = mkdir2 = NULL; + fs = ump->um_fs; + lbn = lblkno(fs, diroffset); + offset = blkoff(fs, diroffset); + dap = malloc(sizeof(struct diradd), M_DIRADD, + M_SOFTDEP_FLAGS|M_ZERO); + workitem_alloc(&dap->da_list, D_DIRADD, mp); + dap->da_offset = offset; + dap->da_newinum = newinum; + dap->da_state = ATTACHED; + LIST_INIT(&dap->da_jwork); + isindir = bp->b_lblkno >= NDADDR; + newdirblk = NULL; + if (isnewblk && + (isindir ? blkoff(fs, diroffset) : fragoff(fs, diroffset)) == 0) { + newdirblk = malloc(sizeof(struct newdirblk), + M_NEWDIRBLK, M_SOFTDEP_FLAGS); + workitem_alloc(&newdirblk->db_list, D_NEWDIRBLK, mp); + LIST_INIT(&newdirblk->db_mkdir); + } + /* + * If we're creating a new directory setup the dependencies and set + * the dap state to wait for them. Otherwise it's COMPLETE and + * we can move on. + */ + if (newdirbp == NULL) { + dap->da_state |= DEPCOMPLETE; + ACQUIRE_LOCK(ump); + } else { + dap->da_state |= MKDIR_BODY | MKDIR_PARENT; + mkdir1 = setup_newdir(dap, newinum, dp->i_number, newdirbp, + &mkdir2); + } + /* + * Link into parent directory pagedep to await its being written. + */ + pagedep_lookup(mp, bp, dp->i_number, lbn, DEPALLOC, &pagedep); +#ifdef DEBUG + if (diradd_lookup(pagedep, offset) != NULL) + panic("softdep_setup_directory_add: %p already at off %d\n", + diradd_lookup(pagedep, offset), offset); +#endif + dap->da_pagedep = pagedep; + LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], dap, + da_pdlist); + inodedep_lookup(mp, newinum, DEPALLOC, &inodedep); + /* + * If we're journaling, link the diradd into the jaddref so it + * may be completed after the journal entry is written. Otherwise, + * link the diradd into its inodedep. If the inode is not yet + * written place it on the bufwait list, otherwise do the post-inode + * write processing to put it on the id_pendinghd list. + */ + if (MOUNTEDSUJ(mp)) { + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, + ("softdep_setup_directory_add: bad jaddref %p", jaddref)); + jaddref->ja_diroff = diroffset; + jaddref->ja_diradd = dap; + add_to_journal(&jaddref->ja_list); + } else if ((inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) + diradd_inode_written(dap, inodedep); + else + WORKLIST_INSERT(&inodedep->id_bufwait, &dap->da_list); + /* + * Add the journal entries for . and .. links now that the primary + * link is written. + */ + if (mkdir1 != NULL && MOUNTEDSUJ(mp)) { + jaddref = (struct jaddref *)TAILQ_PREV(&jaddref->ja_ref, + inoreflst, if_deps); + KASSERT(jaddref != NULL && + jaddref->ja_ino == jaddref->ja_parent && + (jaddref->ja_state & MKDIR_BODY), + ("softdep_setup_directory_add: bad dot jaddref %p", + jaddref)); + mkdir1->md_jaddref = jaddref; + jaddref->ja_mkdir = mkdir1; + /* + * It is important that the dotdot journal entry + * is added prior to the dot entry since dot writes + * both the dot and dotdot links. These both must + * be added after the primary link for the journal + * to remain consistent. + */ + add_to_journal(&mkdir2->md_jaddref->ja_list); + add_to_journal(&jaddref->ja_list); + } + /* + * If we are adding a new directory remember this diradd so that if + * we rename it we can keep the dot and dotdot dependencies. If + * we are adding a new name for an inode that has a mkdiradd we + * must be in rename and we have to move the dot and dotdot + * dependencies to this new name. The old name is being orphaned + * soon. + */ + if (mkdir1 != NULL) { + if (inodedep->id_mkdiradd != NULL) + panic("softdep_setup_directory_add: Existing mkdir"); + inodedep->id_mkdiradd = dap; + } else if (inodedep->id_mkdiradd) + merge_diradd(inodedep, dap); + if (newdirblk != NULL) { + /* + * There is nothing to do if we are already tracking + * this block. + */ + if ((pagedep->pd_state & NEWBLOCK) != 0) { + WORKITEM_FREE(newdirblk, D_NEWDIRBLK); + FREE_LOCK(ump); + return (0); + } + if (newblk_lookup(mp, dbtofsb(fs, bp->b_blkno), 0, &newblk) + == 0) + panic("softdep_setup_directory_add: lost entry"); + WORKLIST_INSERT(&newblk->nb_newdirblk, &newdirblk->db_list); + pagedep->pd_state |= NEWBLOCK; + pagedep->pd_newdirblk = newdirblk; + newdirblk->db_pagedep = pagedep; + FREE_LOCK(ump); + /* + * If we extended into an indirect signal direnter to sync. + */ + if (isindir) + return (1); + return (0); + } + FREE_LOCK(ump); + return (0); +} + +/* + * This procedure is called to change the offset of a directory + * entry when compacting a directory block which must be owned + * exclusively by the caller. Note that the actual entry movement + * must be done in this procedure to ensure that no I/O completions + * occur while the move is in progress. + */ +void +softdep_change_directoryentry_offset(bp, dp, base, oldloc, newloc, entrysize) + struct buf *bp; /* Buffer holding directory block. */ + struct inode *dp; /* inode for directory */ + caddr_t base; /* address of dp->i_offset */ + caddr_t oldloc; /* address of old directory location */ + caddr_t newloc; /* address of new directory location */ + int entrysize; /* size of directory entry */ +{ + int offset, oldoffset, newoffset; + struct pagedep *pagedep; + struct jmvref *jmvref; + struct diradd *dap; + struct direct *de; + struct mount *mp; + struct ufsmount *ump; + ufs_lbn_t lbn; + int flags; + + mp = ITOVFS(dp); + ump = VFSTOUFS(mp); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_change_directoryentry_offset called on " + "non-softdep filesystem")); + de = (struct direct *)oldloc; + jmvref = NULL; + flags = 0; + /* + * Moves are always journaled as it would be too complex to + * determine if any affected adds or removes are present in the + * journal. + */ + if (MOUNTEDSUJ(mp)) { + flags = DEPALLOC; + jmvref = newjmvref(dp, de->d_ino, + dp->i_offset + (oldloc - base), + dp->i_offset + (newloc - base)); + } + lbn = lblkno(ump->um_fs, dp->i_offset); + offset = blkoff(ump->um_fs, dp->i_offset); + oldoffset = offset + (oldloc - base); + newoffset = offset + (newloc - base); + ACQUIRE_LOCK(ump); + if (pagedep_lookup(mp, bp, dp->i_number, lbn, flags, &pagedep) == 0) + goto done; + dap = diradd_lookup(pagedep, oldoffset); + if (dap) { + dap->da_offset = newoffset; + newoffset = DIRADDHASH(newoffset); + oldoffset = DIRADDHASH(oldoffset); + if ((dap->da_state & ALLCOMPLETE) != ALLCOMPLETE && + newoffset != oldoffset) { + LIST_REMOVE(dap, da_pdlist); + LIST_INSERT_HEAD(&pagedep->pd_diraddhd[newoffset], + dap, da_pdlist); + } + } +done: + if (jmvref) { + jmvref->jm_pagedep = pagedep; + LIST_INSERT_HEAD(&pagedep->pd_jmvrefhd, jmvref, jm_deps); + add_to_journal(&jmvref->jm_list); + } + bcopy(oldloc, newloc, entrysize); + FREE_LOCK(ump); +} + +/* + * Move the mkdir dependencies and journal work from one diradd to another + * when renaming a directory. The new name must depend on the mkdir deps + * completing as the old name did. Directories can only have one valid link + * at a time so one must be canonical. + */ +static void +merge_diradd(inodedep, newdap) + struct inodedep *inodedep; + struct diradd *newdap; +{ + struct diradd *olddap; + struct mkdir *mkdir, *nextmd; + struct ufsmount *ump; + short state; + + olddap = inodedep->id_mkdiradd; + inodedep->id_mkdiradd = newdap; + if ((olddap->da_state & (MKDIR_PARENT | MKDIR_BODY)) != 0) { + newdap->da_state &= ~DEPCOMPLETE; + ump = VFSTOUFS(inodedep->id_list.wk_mp); + for (mkdir = LIST_FIRST(&ump->softdep_mkdirlisthd); mkdir; + mkdir = nextmd) { + nextmd = LIST_NEXT(mkdir, md_mkdirs); + if (mkdir->md_diradd != olddap) + continue; + mkdir->md_diradd = newdap; + state = mkdir->md_state & (MKDIR_PARENT | MKDIR_BODY); + newdap->da_state |= state; + olddap->da_state &= ~state; + if ((olddap->da_state & + (MKDIR_PARENT | MKDIR_BODY)) == 0) + break; + } + if ((olddap->da_state & (MKDIR_PARENT | MKDIR_BODY)) != 0) + panic("merge_diradd: unfound ref"); + } + /* + * Any mkdir related journal items are not safe to be freed until + * the new name is stable. + */ + jwork_move(&newdap->da_jwork, &olddap->da_jwork); + olddap->da_state |= DEPCOMPLETE; + complete_diradd(olddap); +} + +/* + * Move the diradd to the pending list when all diradd dependencies are + * complete. + */ +static void +complete_diradd(dap) + struct diradd *dap; +{ + struct pagedep *pagedep; + + if ((dap->da_state & ALLCOMPLETE) == ALLCOMPLETE) { + if (dap->da_state & DIRCHG) + pagedep = dap->da_previous->dm_pagedep; + else + pagedep = dap->da_pagedep; + LIST_REMOVE(dap, da_pdlist); + LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, da_pdlist); + } +} + +/* + * Cancel a diradd when a dirrem overlaps with it. We must cancel the journal + * add entries and conditonally journal the remove. + */ +static void +cancel_diradd(dap, dirrem, jremref, dotremref, dotdotremref) + struct diradd *dap; + struct dirrem *dirrem; + struct jremref *jremref; + struct jremref *dotremref; + struct jremref *dotdotremref; +{ + struct inodedep *inodedep; + struct jaddref *jaddref; + struct inoref *inoref; + struct ufsmount *ump; + struct mkdir *mkdir; + + /* + * If no remove references were allocated we're on a non-journaled + * filesystem and can skip the cancel step. + */ + if (jremref == NULL) { + free_diradd(dap, NULL); + return; + } + /* + * Cancel the primary name an free it if it does not require + * journaling. + */ + if (inodedep_lookup(dap->da_list.wk_mp, dap->da_newinum, + 0, &inodedep) != 0) { + /* Abort the addref that reference this diradd. */ + TAILQ_FOREACH(inoref, &inodedep->id_inoreflst, if_deps) { + if (inoref->if_list.wk_type != D_JADDREF) + continue; + jaddref = (struct jaddref *)inoref; + if (jaddref->ja_diradd != dap) + continue; + if (cancel_jaddref(jaddref, inodedep, + &dirrem->dm_jwork) == 0) { + free_jremref(jremref); + jremref = NULL; + } + break; + } + } + /* + * Cancel subordinate names and free them if they do not require + * journaling. + */ + if ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) != 0) { + ump = VFSTOUFS(dap->da_list.wk_mp); + LIST_FOREACH(mkdir, &ump->softdep_mkdirlisthd, md_mkdirs) { + if (mkdir->md_diradd != dap) + continue; + if ((jaddref = mkdir->md_jaddref) == NULL) + continue; + mkdir->md_jaddref = NULL; + if (mkdir->md_state & MKDIR_PARENT) { + if (cancel_jaddref(jaddref, NULL, + &dirrem->dm_jwork) == 0) { + free_jremref(dotdotremref); + dotdotremref = NULL; + } + } else { + if (cancel_jaddref(jaddref, inodedep, + &dirrem->dm_jwork) == 0) { + free_jremref(dotremref); + dotremref = NULL; + } + } + } + } + + if (jremref) + journal_jremref(dirrem, jremref, inodedep); + if (dotremref) + journal_jremref(dirrem, dotremref, inodedep); + if (dotdotremref) + journal_jremref(dirrem, dotdotremref, NULL); + jwork_move(&dirrem->dm_jwork, &dap->da_jwork); + free_diradd(dap, &dirrem->dm_jwork); +} + +/* + * Free a diradd dependency structure. This routine must be called + * with splbio interrupts blocked. + */ +static void +free_diradd(dap, wkhd) + struct diradd *dap; + struct workhead *wkhd; +{ + struct dirrem *dirrem; + struct pagedep *pagedep; + struct inodedep *inodedep; + struct mkdir *mkdir, *nextmd; + struct ufsmount *ump; + + ump = VFSTOUFS(dap->da_list.wk_mp); + LOCK_OWNED(ump); + LIST_REMOVE(dap, da_pdlist); + if (dap->da_state & ONWORKLIST) + WORKLIST_REMOVE(&dap->da_list); + if ((dap->da_state & DIRCHG) == 0) { + pagedep = dap->da_pagedep; + } else { + dirrem = dap->da_previous; + pagedep = dirrem->dm_pagedep; + dirrem->dm_dirinum = pagedep->pd_ino; + dirrem->dm_state |= COMPLETE; + if (LIST_EMPTY(&dirrem->dm_jremrefhd)) + add_to_worklist(&dirrem->dm_list, 0); + } + if (inodedep_lookup(pagedep->pd_list.wk_mp, dap->da_newinum, + 0, &inodedep) != 0) + if (inodedep->id_mkdiradd == dap) + inodedep->id_mkdiradd = NULL; + if ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) != 0) { + for (mkdir = LIST_FIRST(&ump->softdep_mkdirlisthd); mkdir; + mkdir = nextmd) { + nextmd = LIST_NEXT(mkdir, md_mkdirs); + if (mkdir->md_diradd != dap) + continue; + dap->da_state &= + ~(mkdir->md_state & (MKDIR_PARENT | MKDIR_BODY)); + LIST_REMOVE(mkdir, md_mkdirs); + if (mkdir->md_state & ONWORKLIST) + WORKLIST_REMOVE(&mkdir->md_list); + if (mkdir->md_jaddref != NULL) + panic("free_diradd: Unexpected jaddref"); + WORKITEM_FREE(mkdir, D_MKDIR); + if ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) == 0) + break; + } + if ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) != 0) + panic("free_diradd: unfound ref"); + } + if (inodedep) + free_inodedep(inodedep); + /* + * Free any journal segments waiting for the directory write. + */ + handle_jwork(&dap->da_jwork); + WORKITEM_FREE(dap, D_DIRADD); +} + +/* + * Directory entry removal dependencies. + * + * When removing a directory entry, the entry's inode pointer must be + * zero'ed on disk before the corresponding inode's link count is decremented + * (possibly freeing the inode for re-use). This dependency is handled by + * updating the directory entry but delaying the inode count reduction until + * after the directory block has been written to disk. After this point, the + * inode count can be decremented whenever it is convenient. + */ + +/* + * This routine should be called immediately after removing + * a directory entry. The inode's link count should not be + * decremented by the calling procedure -- the soft updates + * code will do this task when it is safe. + */ +void +softdep_setup_remove(bp, dp, ip, isrmdir) + struct buf *bp; /* buffer containing directory block */ + struct inode *dp; /* inode for the directory being modified */ + struct inode *ip; /* inode for directory entry being removed */ + int isrmdir; /* indicates if doing RMDIR */ +{ + struct dirrem *dirrem, *prevdirrem; + struct inodedep *inodedep; + struct ufsmount *ump; + int direct; + + ump = ITOUMP(ip); + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_setup_remove called on non-softdep filesystem")); + /* + * Allocate a new dirrem if appropriate and ACQUIRE_LOCK. We want + * newdirrem() to setup the full directory remove which requires + * isrmdir > 1. + */ + dirrem = newdirrem(bp, dp, ip, isrmdir, &prevdirrem); + /* + * Add the dirrem to the inodedep's pending remove list for quick + * discovery later. + */ + if (inodedep_lookup(UFSTOVFS(ump), ip->i_number, 0, &inodedep) == 0) + panic("softdep_setup_remove: Lost inodedep."); + KASSERT((inodedep->id_state & UNLINKED) == 0, ("inode unlinked")); + dirrem->dm_state |= ONDEPLIST; + LIST_INSERT_HEAD(&inodedep->id_dirremhd, dirrem, dm_inonext); + + /* + * If the COMPLETE flag is clear, then there were no active + * entries and we want to roll back to a zeroed entry until + * the new inode is committed to disk. If the COMPLETE flag is + * set then we have deleted an entry that never made it to + * disk. If the entry we deleted resulted from a name change, + * then the old name still resides on disk. We cannot delete + * its inode (returned to us in prevdirrem) until the zeroed + * directory entry gets to disk. The new inode has never been + * referenced on the disk, so can be deleted immediately. + */ + if ((dirrem->dm_state & COMPLETE) == 0) { + LIST_INSERT_HEAD(&dirrem->dm_pagedep->pd_dirremhd, dirrem, + dm_next); + FREE_LOCK(ump); + } else { + if (prevdirrem != NULL) + LIST_INSERT_HEAD(&dirrem->dm_pagedep->pd_dirremhd, + prevdirrem, dm_next); + dirrem->dm_dirinum = dirrem->dm_pagedep->pd_ino; + direct = LIST_EMPTY(&dirrem->dm_jremrefhd); + FREE_LOCK(ump); + if (direct) + handle_workitem_remove(dirrem, 0); + } +} + +/* + * Check for an entry matching 'offset' on both the pd_dirraddhd list and the + * pd_pendinghd list of a pagedep. + */ +static struct diradd * +diradd_lookup(pagedep, offset) + struct pagedep *pagedep; + int offset; +{ + struct diradd *dap; + + LIST_FOREACH(dap, &pagedep->pd_diraddhd[DIRADDHASH(offset)], da_pdlist) + if (dap->da_offset == offset) + return (dap); + LIST_FOREACH(dap, &pagedep->pd_pendinghd, da_pdlist) + if (dap->da_offset == offset) + return (dap); + return (NULL); +} + +/* + * Search for a .. diradd dependency in a directory that is being removed. + * If the directory was renamed to a new parent we have a diradd rather + * than a mkdir for the .. entry. We need to cancel it now before + * it is found in truncate(). + */ +static struct jremref * +cancel_diradd_dotdot(ip, dirrem, jremref) + struct inode *ip; + struct dirrem *dirrem; + struct jremref *jremref; +{ + struct pagedep *pagedep; + struct diradd *dap; + struct worklist *wk; + + if (pagedep_lookup(ITOVFS(ip), NULL, ip->i_number, 0, 0, &pagedep) == 0) + return (jremref); + dap = diradd_lookup(pagedep, DOTDOT_OFFSET); + if (dap == NULL) + return (jremref); + cancel_diradd(dap, dirrem, jremref, NULL, NULL); + /* + * Mark any journal work as belonging to the parent so it is freed + * with the .. reference. + */ + LIST_FOREACH(wk, &dirrem->dm_jwork, wk_list) + wk->wk_state |= MKDIR_PARENT; + return (NULL); +} + +/* + * Cancel the MKDIR_PARENT mkdir component of a diradd when we're going to + * replace it with a dirrem/diradd pair as a result of re-parenting a + * directory. This ensures that we don't simultaneously have a mkdir and + * a diradd for the same .. entry. + */ +static struct jremref * +cancel_mkdir_dotdot(ip, dirrem, jremref) + struct inode *ip; + struct dirrem *dirrem; + struct jremref *jremref; +{ + struct inodedep *inodedep; + struct jaddref *jaddref; + struct ufsmount *ump; + struct mkdir *mkdir; + struct diradd *dap; + struct mount *mp; + + mp = ITOVFS(ip); + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) == 0) + return (jremref); + dap = inodedep->id_mkdiradd; + if (dap == NULL || (dap->da_state & MKDIR_PARENT) == 0) + return (jremref); + ump = VFSTOUFS(inodedep->id_list.wk_mp); + for (mkdir = LIST_FIRST(&ump->softdep_mkdirlisthd); mkdir; + mkdir = LIST_NEXT(mkdir, md_mkdirs)) + if (mkdir->md_diradd == dap && mkdir->md_state & MKDIR_PARENT) + break; + if (mkdir == NULL) + panic("cancel_mkdir_dotdot: Unable to find mkdir\n"); + if ((jaddref = mkdir->md_jaddref) != NULL) { + mkdir->md_jaddref = NULL; + jaddref->ja_state &= ~MKDIR_PARENT; + if (inodedep_lookup(mp, jaddref->ja_ino, 0, &inodedep) == 0) + panic("cancel_mkdir_dotdot: Lost parent inodedep"); + if (cancel_jaddref(jaddref, inodedep, &dirrem->dm_jwork)) { + journal_jremref(dirrem, jremref, inodedep); + jremref = NULL; + } + } + if (mkdir->md_state & ONWORKLIST) + WORKLIST_REMOVE(&mkdir->md_list); + mkdir->md_state |= ALLCOMPLETE; + complete_mkdir(mkdir); + return (jremref); +} + +static void +journal_jremref(dirrem, jremref, inodedep) + struct dirrem *dirrem; + struct jremref *jremref; + struct inodedep *inodedep; +{ + + if (inodedep == NULL) + if (inodedep_lookup(jremref->jr_list.wk_mp, + jremref->jr_ref.if_ino, 0, &inodedep) == 0) + panic("journal_jremref: Lost inodedep"); + LIST_INSERT_HEAD(&dirrem->dm_jremrefhd, jremref, jr_deps); + TAILQ_INSERT_TAIL(&inodedep->id_inoreflst, &jremref->jr_ref, if_deps); + add_to_journal(&jremref->jr_list); +} + +static void +dirrem_journal(dirrem, jremref, dotremref, dotdotremref) + struct dirrem *dirrem; + struct jremref *jremref; + struct jremref *dotremref; + struct jremref *dotdotremref; +{ + struct inodedep *inodedep; + + + if (inodedep_lookup(jremref->jr_list.wk_mp, jremref->jr_ref.if_ino, 0, + &inodedep) == 0) + panic("dirrem_journal: Lost inodedep"); + journal_jremref(dirrem, jremref, inodedep); + if (dotremref) + journal_jremref(dirrem, dotremref, inodedep); + if (dotdotremref) + journal_jremref(dirrem, dotdotremref, NULL); +} + +/* + * Allocate a new dirrem if appropriate and return it along with + * its associated pagedep. Called without a lock, returns with lock. + */ +static struct dirrem * +newdirrem(bp, dp, ip, isrmdir, prevdirremp) + struct buf *bp; /* buffer containing directory block */ + struct inode *dp; /* inode for the directory being modified */ + struct inode *ip; /* inode for directory entry being removed */ + int isrmdir; /* indicates if doing RMDIR */ + struct dirrem **prevdirremp; /* previously referenced inode, if any */ +{ + int offset; + ufs_lbn_t lbn; + struct diradd *dap; + struct dirrem *dirrem; + struct pagedep *pagedep; + struct jremref *jremref; + struct jremref *dotremref; + struct jremref *dotdotremref; + struct vnode *dvp; + struct ufsmount *ump; + + /* + * Whiteouts have no deletion dependencies. + */ + if (ip == NULL) + panic("newdirrem: whiteout"); + dvp = ITOV(dp); + ump = ITOUMP(dp); + + /* + * If the system is over its limit and our filesystem is + * responsible for more than our share of that usage and + * we are not a snapshot, request some inodedep cleanup. + * Limiting the number of dirrem structures will also limit + * the number of freefile and freeblks structures. + */ + ACQUIRE_LOCK(ump); + if (!IS_SNAPSHOT(ip) && softdep_excess_items(ump, D_DIRREM)) + schedule_cleanup(UFSTOVFS(ump)); + else + FREE_LOCK(ump); + dirrem = malloc(sizeof(struct dirrem), M_DIRREM, M_SOFTDEP_FLAGS | + M_ZERO); + workitem_alloc(&dirrem->dm_list, D_DIRREM, dvp->v_mount); + LIST_INIT(&dirrem->dm_jremrefhd); + LIST_INIT(&dirrem->dm_jwork); + dirrem->dm_state = isrmdir ? RMDIR : 0; + dirrem->dm_oldinum = ip->i_number; + *prevdirremp = NULL; + /* + * Allocate remove reference structures to track journal write + * dependencies. We will always have one for the link and + * when doing directories we will always have one more for dot. + * When renaming a directory we skip the dotdot link change so + * this is not needed. + */ + jremref = dotremref = dotdotremref = NULL; + if (DOINGSUJ(dvp)) { + if (isrmdir) { + jremref = newjremref(dirrem, dp, ip, dp->i_offset, + ip->i_effnlink + 2); + dotremref = newjremref(dirrem, ip, ip, DOT_OFFSET, + ip->i_effnlink + 1); + dotdotremref = newjremref(dirrem, ip, dp, DOTDOT_OFFSET, + dp->i_effnlink + 1); + dotdotremref->jr_state |= MKDIR_PARENT; + } else + jremref = newjremref(dirrem, dp, ip, dp->i_offset, + ip->i_effnlink + 1); + } + ACQUIRE_LOCK(ump); + lbn = lblkno(ump->um_fs, dp->i_offset); + offset = blkoff(ump->um_fs, dp->i_offset); + pagedep_lookup(UFSTOVFS(ump), bp, dp->i_number, lbn, DEPALLOC, + &pagedep); + dirrem->dm_pagedep = pagedep; + dirrem->dm_offset = offset; + /* + * If we're renaming a .. link to a new directory, cancel any + * existing MKDIR_PARENT mkdir. If it has already been canceled + * the jremref is preserved for any potential diradd in this + * location. This can not coincide with a rmdir. + */ + if (dp->i_offset == DOTDOT_OFFSET) { + if (isrmdir) + panic("newdirrem: .. directory change during remove?"); + jremref = cancel_mkdir_dotdot(dp, dirrem, jremref); + } + /* + * If we're removing a directory search for the .. dependency now and + * cancel it. Any pending journal work will be added to the dirrem + * to be completed when the workitem remove completes. + */ + if (isrmdir) + dotdotremref = cancel_diradd_dotdot(ip, dirrem, dotdotremref); + /* + * Check for a diradd dependency for the same directory entry. + * If present, then both dependencies become obsolete and can + * be de-allocated. + */ + dap = diradd_lookup(pagedep, offset); + if (dap == NULL) { + /* + * Link the jremref structures into the dirrem so they are + * written prior to the pagedep. + */ + if (jremref) + dirrem_journal(dirrem, jremref, dotremref, + dotdotremref); + return (dirrem); + } + /* + * Must be ATTACHED at this point. + */ + if ((dap->da_state & ATTACHED) == 0) + panic("newdirrem: not ATTACHED"); + if (dap->da_newinum != ip->i_number) + panic("newdirrem: inum %ju should be %ju", + (uintmax_t)ip->i_number, (uintmax_t)dap->da_newinum); + /* + * If we are deleting a changed name that never made it to disk, + * then return the dirrem describing the previous inode (which + * represents the inode currently referenced from this entry on disk). + */ + if ((dap->da_state & DIRCHG) != 0) { + *prevdirremp = dap->da_previous; + dap->da_state &= ~DIRCHG; + dap->da_pagedep = pagedep; + } + /* + * We are deleting an entry that never made it to disk. + * Mark it COMPLETE so we can delete its inode immediately. + */ + dirrem->dm_state |= COMPLETE; + cancel_diradd(dap, dirrem, jremref, dotremref, dotdotremref); +#ifdef SUJ_DEBUG + if (isrmdir == 0) { + struct worklist *wk; + + LIST_FOREACH(wk, &dirrem->dm_jwork, wk_list) + if (wk->wk_state & (MKDIR_BODY | MKDIR_PARENT)) + panic("bad wk %p (0x%X)\n", wk, wk->wk_state); + } +#endif + + return (dirrem); +} + +/* + * Directory entry change dependencies. + * + * Changing an existing directory entry requires that an add operation + * be completed first followed by a deletion. The semantics for the addition + * are identical to the description of adding a new entry above except + * that the rollback is to the old inode number rather than zero. Once + * the addition dependency is completed, the removal is done as described + * in the removal routine above. + */ + +/* + * This routine should be called immediately after changing + * a directory entry. The inode's link count should not be + * decremented by the calling procedure -- the soft updates + * code will perform this task when it is safe. + */ +void +softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir) + struct buf *bp; /* buffer containing directory block */ + struct inode *dp; /* inode for the directory being modified */ + struct inode *ip; /* inode for directory entry being removed */ + ino_t newinum; /* new inode number for changed entry */ + int isrmdir; /* indicates if doing RMDIR */ +{ + int offset; + struct diradd *dap = NULL; + struct dirrem *dirrem, *prevdirrem; + struct pagedep *pagedep; + struct inodedep *inodedep; + struct jaddref *jaddref; + struct mount *mp; + struct ufsmount *ump; + + mp = ITOVFS(dp); + ump = VFSTOUFS(mp); + offset = blkoff(ump->um_fs, dp->i_offset); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_directory_change called on non-softdep filesystem")); + + /* + * Whiteouts do not need diradd dependencies. + */ + if (newinum != WINO) { + dap = malloc(sizeof(struct diradd), + M_DIRADD, M_SOFTDEP_FLAGS|M_ZERO); + workitem_alloc(&dap->da_list, D_DIRADD, mp); + dap->da_state = DIRCHG | ATTACHED | DEPCOMPLETE; + dap->da_offset = offset; + dap->da_newinum = newinum; + LIST_INIT(&dap->da_jwork); + } + + /* + * Allocate a new dirrem and ACQUIRE_LOCK. + */ + dirrem = newdirrem(bp, dp, ip, isrmdir, &prevdirrem); + pagedep = dirrem->dm_pagedep; + /* + * The possible values for isrmdir: + * 0 - non-directory file rename + * 1 - directory rename within same directory + * inum - directory rename to new directory of given inode number + * When renaming to a new directory, we are both deleting and + * creating a new directory entry, so the link count on the new + * directory should not change. Thus we do not need the followup + * dirrem which is usually done in handle_workitem_remove. We set + * the DIRCHG flag to tell handle_workitem_remove to skip the + * followup dirrem. + */ + if (isrmdir > 1) + dirrem->dm_state |= DIRCHG; + + /* + * Whiteouts have no additional dependencies, + * so just put the dirrem on the correct list. + */ + if (newinum == WINO) { + if ((dirrem->dm_state & COMPLETE) == 0) { + LIST_INSERT_HEAD(&pagedep->pd_dirremhd, dirrem, + dm_next); + } else { + dirrem->dm_dirinum = pagedep->pd_ino; + if (LIST_EMPTY(&dirrem->dm_jremrefhd)) + add_to_worklist(&dirrem->dm_list, 0); + } + FREE_LOCK(ump); + return; + } + /* + * Add the dirrem to the inodedep's pending remove list for quick + * discovery later. A valid nlinkdelta ensures that this lookup + * will not fail. + */ + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) == 0) + panic("softdep_setup_directory_change: Lost inodedep."); + dirrem->dm_state |= ONDEPLIST; + LIST_INSERT_HEAD(&inodedep->id_dirremhd, dirrem, dm_inonext); + + /* + * If the COMPLETE flag is clear, then there were no active + * entries and we want to roll back to the previous inode until + * the new inode is committed to disk. If the COMPLETE flag is + * set, then we have deleted an entry that never made it to disk. + * If the entry we deleted resulted from a name change, then the old + * inode reference still resides on disk. Any rollback that we do + * needs to be to that old inode (returned to us in prevdirrem). If + * the entry we deleted resulted from a create, then there is + * no entry on the disk, so we want to roll back to zero rather + * than the uncommitted inode. In either of the COMPLETE cases we + * want to immediately free the unwritten and unreferenced inode. + */ + if ((dirrem->dm_state & COMPLETE) == 0) { + dap->da_previous = dirrem; + } else { + if (prevdirrem != NULL) { + dap->da_previous = prevdirrem; + } else { + dap->da_state &= ~DIRCHG; + dap->da_pagedep = pagedep; + } + dirrem->dm_dirinum = pagedep->pd_ino; + if (LIST_EMPTY(&dirrem->dm_jremrefhd)) + add_to_worklist(&dirrem->dm_list, 0); + } + /* + * Lookup the jaddref for this journal entry. We must finish + * initializing it and make the diradd write dependent on it. + * If we're not journaling, put it on the id_bufwait list if the + * inode is not yet written. If it is written, do the post-inode + * write processing to put it on the id_pendinghd list. + */ + inodedep_lookup(mp, newinum, DEPALLOC, &inodedep); + if (MOUNTEDSUJ(mp)) { + jaddref = (struct jaddref *)TAILQ_LAST(&inodedep->id_inoreflst, + inoreflst); + KASSERT(jaddref != NULL && jaddref->ja_parent == dp->i_number, + ("softdep_setup_directory_change: bad jaddref %p", + jaddref)); + jaddref->ja_diroff = dp->i_offset; + jaddref->ja_diradd = dap; + LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], + dap, da_pdlist); + add_to_journal(&jaddref->ja_list); + } else if ((inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) { + dap->da_state |= COMPLETE; + LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, da_pdlist); + WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list); + } else { + LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], + dap, da_pdlist); + WORKLIST_INSERT(&inodedep->id_bufwait, &dap->da_list); + } + /* + * If we're making a new name for a directory that has not been + * committed when need to move the dot and dotdot references to + * this new name. + */ + if (inodedep->id_mkdiradd && dp->i_offset != DOTDOT_OFFSET) + merge_diradd(inodedep, dap); + FREE_LOCK(ump); +} + +/* + * Called whenever the link count on an inode is changed. + * It creates an inode dependency so that the new reference(s) + * to the inode cannot be committed to disk until the updated + * inode has been written. + */ +void +softdep_change_linkcnt(ip) + struct inode *ip; /* the inode with the increased link count */ +{ + struct inodedep *inodedep; + struct ufsmount *ump; + + ump = ITOUMP(ip); + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_change_linkcnt called on non-softdep filesystem")); + ACQUIRE_LOCK(ump); + inodedep_lookup(UFSTOVFS(ump), ip->i_number, DEPALLOC, &inodedep); + if (ip->i_nlink < ip->i_effnlink) + panic("softdep_change_linkcnt: bad delta"); + inodedep->id_nlinkdelta = ip->i_nlink - ip->i_effnlink; + FREE_LOCK(ump); +} + +/* + * Attach a sbdep dependency to the superblock buf so that we can keep + * track of the head of the linked list of referenced but unlinked inodes. + */ +void +softdep_setup_sbupdate(ump, fs, bp) + struct ufsmount *ump; + struct fs *fs; + struct buf *bp; +{ + struct sbdep *sbdep; + struct worklist *wk; + + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_setup_sbupdate called on non-softdep filesystem")); + LIST_FOREACH(wk, &bp->b_dep, wk_list) + if (wk->wk_type == D_SBDEP) + break; + if (wk != NULL) + return; + sbdep = malloc(sizeof(struct sbdep), M_SBDEP, M_SOFTDEP_FLAGS); + workitem_alloc(&sbdep->sb_list, D_SBDEP, UFSTOVFS(ump)); + sbdep->sb_fs = fs; + sbdep->sb_ump = ump; + ACQUIRE_LOCK(ump); + WORKLIST_INSERT(&bp->b_dep, &sbdep->sb_list); + FREE_LOCK(ump); +} + +/* + * Return the first unlinked inodedep which is ready to be the head of the + * list. The inodedep and all those after it must have valid next pointers. + */ +static struct inodedep * +first_unlinked_inodedep(ump) + struct ufsmount *ump; +{ + struct inodedep *inodedep; + struct inodedep *idp; + + LOCK_OWNED(ump); + for (inodedep = TAILQ_LAST(&ump->softdep_unlinked, inodedeplst); + inodedep; inodedep = idp) { + if ((inodedep->id_state & UNLINKNEXT) == 0) + return (NULL); + idp = TAILQ_PREV(inodedep, inodedeplst, id_unlinked); + if (idp == NULL || (idp->id_state & UNLINKNEXT) == 0) + break; + if ((inodedep->id_state & UNLINKPREV) == 0) + break; + } + return (inodedep); +} + +/* + * Set the sujfree unlinked head pointer prior to writing a superblock. + */ +static void +initiate_write_sbdep(sbdep) + struct sbdep *sbdep; +{ + struct inodedep *inodedep; + struct fs *bpfs; + struct fs *fs; + + bpfs = sbdep->sb_fs; + fs = sbdep->sb_ump->um_fs; + inodedep = first_unlinked_inodedep(sbdep->sb_ump); + if (inodedep) { + fs->fs_sujfree = inodedep->id_ino; + inodedep->id_state |= UNLINKPREV; + } else + fs->fs_sujfree = 0; + bpfs->fs_sujfree = fs->fs_sujfree; +} + +/* + * After a superblock is written determine whether it must be written again + * due to a changing unlinked list head. + */ +static int +handle_written_sbdep(sbdep, bp) + struct sbdep *sbdep; + struct buf *bp; +{ + struct inodedep *inodedep; + struct fs *fs; + + LOCK_OWNED(sbdep->sb_ump); + fs = sbdep->sb_fs; + /* + * If the superblock doesn't match the in-memory list start over. + */ + inodedep = first_unlinked_inodedep(sbdep->sb_ump); + if ((inodedep && fs->fs_sujfree != inodedep->id_ino) || + (inodedep == NULL && fs->fs_sujfree != 0)) { + bdirty(bp); + return (1); + } + WORKITEM_FREE(sbdep, D_SBDEP); + if (fs->fs_sujfree == 0) + return (0); + /* + * Now that we have a record of this inode in stable store allow it + * to be written to free up pending work. Inodes may see a lot of + * write activity after they are unlinked which we must not hold up. + */ + for (; inodedep != NULL; inodedep = TAILQ_NEXT(inodedep, id_unlinked)) { + if ((inodedep->id_state & UNLINKLINKS) != UNLINKLINKS) + panic("handle_written_sbdep: Bad inodedep %p (0x%X)", + inodedep, inodedep->id_state); + if (inodedep->id_state & UNLINKONLIST) + break; + inodedep->id_state |= DEPCOMPLETE | UNLINKONLIST; + } + + return (0); +} + +/* + * Mark an inodedep as unlinked and insert it into the in-memory unlinked list. + */ +static void +unlinked_inodedep(mp, inodedep) + struct mount *mp; + struct inodedep *inodedep; +{ + struct ufsmount *ump; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + if (MOUNTEDSUJ(mp) == 0) + return; + ump->um_fs->fs_fmod = 1; + if (inodedep->id_state & UNLINKED) + panic("unlinked_inodedep: %p already unlinked\n", inodedep); + inodedep->id_state |= UNLINKED; + TAILQ_INSERT_HEAD(&ump->softdep_unlinked, inodedep, id_unlinked); +} + +/* + * Remove an inodedep from the unlinked inodedep list. This may require + * disk writes if the inode has made it that far. + */ +static void +clear_unlinked_inodedep(inodedep) + struct inodedep *inodedep; +{ + struct ufsmount *ump; + struct inodedep *idp; + struct inodedep *idn; + struct fs *fs; + struct buf *bp; + ino_t ino; + ino_t nino; + ino_t pino; + int error; + + ump = VFSTOUFS(inodedep->id_list.wk_mp); + fs = ump->um_fs; + ino = inodedep->id_ino; + error = 0; + for (;;) { + LOCK_OWNED(ump); + KASSERT((inodedep->id_state & UNLINKED) != 0, + ("clear_unlinked_inodedep: inodedep %p not unlinked", + inodedep)); + /* + * If nothing has yet been written simply remove us from + * the in memory list and return. This is the most common + * case where handle_workitem_remove() loses the final + * reference. + */ + if ((inodedep->id_state & UNLINKLINKS) == 0) + break; + /* + * If we have a NEXT pointer and no PREV pointer we can simply + * clear NEXT's PREV and remove ourselves from the list. Be + * careful not to clear PREV if the superblock points at + * next as well. + */ + idn = TAILQ_NEXT(inodedep, id_unlinked); + if ((inodedep->id_state & UNLINKLINKS) == UNLINKNEXT) { + if (idn && fs->fs_sujfree != idn->id_ino) + idn->id_state &= ~UNLINKPREV; + break; + } + /* + * Here we have an inodedep which is actually linked into + * the list. We must remove it by forcing a write to the + * link before us, whether it be the superblock or an inode. + * Unfortunately the list may change while we're waiting + * on the buf lock for either resource so we must loop until + * we lock the right one. If both the superblock and an + * inode point to this inode we must clear the inode first + * followed by the superblock. + */ + idp = TAILQ_PREV(inodedep, inodedeplst, id_unlinked); + pino = 0; + if (idp && (idp->id_state & UNLINKNEXT)) + pino = idp->id_ino; + FREE_LOCK(ump); + if (pino == 0) { + bp = getblk(ump->um_devvp, btodb(fs->fs_sblockloc), + (int)fs->fs_sbsize, 0, 0, 0); + } else { + error = bread(ump->um_devvp, + fsbtodb(fs, ino_to_fsba(fs, pino)), + (int)fs->fs_bsize, NOCRED, &bp); + if (error) + brelse(bp); + } + ACQUIRE_LOCK(ump); + if (error) + break; + /* If the list has changed restart the loop. */ + idp = TAILQ_PREV(inodedep, inodedeplst, id_unlinked); + nino = 0; + if (idp && (idp->id_state & UNLINKNEXT)) + nino = idp->id_ino; + if (nino != pino || + (inodedep->id_state & UNLINKPREV) != UNLINKPREV) { + FREE_LOCK(ump); + brelse(bp); + ACQUIRE_LOCK(ump); + continue; + } + nino = 0; + idn = TAILQ_NEXT(inodedep, id_unlinked); + if (idn) + nino = idn->id_ino; + /* + * Remove us from the in memory list. After this we cannot + * access the inodedep. + */ + KASSERT((inodedep->id_state & UNLINKED) != 0, + ("clear_unlinked_inodedep: inodedep %p not unlinked", + inodedep)); + inodedep->id_state &= ~(UNLINKED | UNLINKLINKS | UNLINKONLIST); + TAILQ_REMOVE(&ump->softdep_unlinked, inodedep, id_unlinked); + FREE_LOCK(ump); + /* + * The predecessor's next pointer is manually updated here + * so that the NEXT flag is never cleared for an element + * that is in the list. + */ + if (pino == 0) { + bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); + ffs_oldfscompat_write((struct fs *)bp->b_data, ump); + softdep_setup_sbupdate(ump, (struct fs *)bp->b_data, + bp); + } else if (fs->fs_magic == FS_UFS1_MAGIC) + ((struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, pino))->di_freelink = nino; + else + ((struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, pino))->di_freelink = nino; + /* + * If the bwrite fails we have no recourse to recover. The + * filesystem is corrupted already. + */ + bwrite(bp); + ACQUIRE_LOCK(ump); + /* + * If the superblock pointer still needs to be cleared force + * a write here. + */ + if (fs->fs_sujfree == ino) { + FREE_LOCK(ump); + bp = getblk(ump->um_devvp, btodb(fs->fs_sblockloc), + (int)fs->fs_sbsize, 0, 0, 0); + bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); + ffs_oldfscompat_write((struct fs *)bp->b_data, ump); + softdep_setup_sbupdate(ump, (struct fs *)bp->b_data, + bp); + bwrite(bp); + ACQUIRE_LOCK(ump); + } + + if (fs->fs_sujfree != ino) + return; + panic("clear_unlinked_inodedep: Failed to clear free head"); + } + if (inodedep->id_ino == fs->fs_sujfree) + panic("clear_unlinked_inodedep: Freeing head of free list"); + inodedep->id_state &= ~(UNLINKED | UNLINKLINKS | UNLINKONLIST); + TAILQ_REMOVE(&ump->softdep_unlinked, inodedep, id_unlinked); + return; +} + +/* + * This workitem decrements the inode's link count. + * If the link count reaches zero, the file is removed. + */ +static int +handle_workitem_remove(dirrem, flags) + struct dirrem *dirrem; + int flags; +{ + struct inodedep *inodedep; + struct workhead dotdotwk; + struct worklist *wk; + struct ufsmount *ump; + struct mount *mp; + struct vnode *vp; + struct inode *ip; + ino_t oldinum; + + if (dirrem->dm_state & ONWORKLIST) + panic("handle_workitem_remove: dirrem %p still on worklist", + dirrem); + oldinum = dirrem->dm_oldinum; + mp = dirrem->dm_list.wk_mp; + ump = VFSTOUFS(mp); + flags |= LK_EXCLUSIVE; + if (ffs_vgetf(mp, oldinum, flags, &vp, FFSV_FORCEINSMQ) != 0) + return (EBUSY); + ip = VTOI(vp); + ACQUIRE_LOCK(ump); + if ((inodedep_lookup(mp, oldinum, 0, &inodedep)) == 0) + panic("handle_workitem_remove: lost inodedep"); + if (dirrem->dm_state & ONDEPLIST) + LIST_REMOVE(dirrem, dm_inonext); + KASSERT(LIST_EMPTY(&dirrem->dm_jremrefhd), + ("handle_workitem_remove: Journal entries not written.")); + + /* + * Move all dependencies waiting on the remove to complete + * from the dirrem to the inode inowait list to be completed + * after the inode has been updated and written to disk. Any + * marked MKDIR_PARENT are saved to be completed when the .. ref + * is removed. + */ + LIST_INIT(&dotdotwk); + while ((wk = LIST_FIRST(&dirrem->dm_jwork)) != NULL) { + WORKLIST_REMOVE(wk); + if (wk->wk_state & MKDIR_PARENT) { + wk->wk_state &= ~MKDIR_PARENT; + WORKLIST_INSERT(&dotdotwk, wk); + continue; + } + WORKLIST_INSERT(&inodedep->id_inowait, wk); + } + LIST_SWAP(&dirrem->dm_jwork, &dotdotwk, worklist, wk_list); + /* + * Normal file deletion. + */ + if ((dirrem->dm_state & RMDIR) == 0) { + ip->i_nlink--; + DIP_SET(ip, i_nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + if (ip->i_nlink < ip->i_effnlink) + panic("handle_workitem_remove: bad file delta"); + if (ip->i_nlink == 0) + unlinked_inodedep(mp, inodedep); + inodedep->id_nlinkdelta = ip->i_nlink - ip->i_effnlink; + KASSERT(LIST_EMPTY(&dirrem->dm_jwork), + ("handle_workitem_remove: worklist not empty. %s", + TYPENAME(LIST_FIRST(&dirrem->dm_jwork)->wk_type))); + WORKITEM_FREE(dirrem, D_DIRREM); + FREE_LOCK(ump); + goto out; + } + /* + * Directory deletion. Decrement reference count for both the + * just deleted parent directory entry and the reference for ".". + * Arrange to have the reference count on the parent decremented + * to account for the loss of "..". + */ + ip->i_nlink -= 2; + DIP_SET(ip, i_nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + if (ip->i_nlink < ip->i_effnlink) + panic("handle_workitem_remove: bad dir delta"); + if (ip->i_nlink == 0) + unlinked_inodedep(mp, inodedep); + inodedep->id_nlinkdelta = ip->i_nlink - ip->i_effnlink; + /* + * Rename a directory to a new parent. Since, we are both deleting + * and creating a new directory entry, the link count on the new + * directory should not change. Thus we skip the followup dirrem. + */ + if (dirrem->dm_state & DIRCHG) { + KASSERT(LIST_EMPTY(&dirrem->dm_jwork), + ("handle_workitem_remove: DIRCHG and worklist not empty.")); + WORKITEM_FREE(dirrem, D_DIRREM); + FREE_LOCK(ump); + goto out; + } + dirrem->dm_state = ONDEPLIST; + dirrem->dm_oldinum = dirrem->dm_dirinum; + /* + * Place the dirrem on the parent's diremhd list. + */ + if (inodedep_lookup(mp, dirrem->dm_oldinum, 0, &inodedep) == 0) + panic("handle_workitem_remove: lost dir inodedep"); + LIST_INSERT_HEAD(&inodedep->id_dirremhd, dirrem, dm_inonext); + /* + * If the allocated inode has never been written to disk, then + * the on-disk inode is zero'ed and we can remove the file + * immediately. When journaling if the inode has been marked + * unlinked and not DEPCOMPLETE we know it can never be written. + */ + inodedep_lookup(mp, oldinum, 0, &inodedep); + if (inodedep == NULL || + (inodedep->id_state & (DEPCOMPLETE | UNLINKED)) == UNLINKED || + check_inode_unwritten(inodedep)) { + FREE_LOCK(ump); + vput(vp); + return handle_workitem_remove(dirrem, flags); + } + WORKLIST_INSERT(&inodedep->id_inowait, &dirrem->dm_list); + FREE_LOCK(ump); + ip->i_flag |= IN_CHANGE; +out: + ffs_update(vp, 0); + vput(vp); + return (0); +} + +/* + * Inode de-allocation dependencies. + * + * When an inode's link count is reduced to zero, it can be de-allocated. We + * found it convenient to postpone de-allocation until after the inode is + * written to disk with its new link count (zero). At this point, all of the + * on-disk inode's block pointers are nullified and, with careful dependency + * list ordering, all dependencies related to the inode will be satisfied and + * the corresponding dependency structures de-allocated. So, if/when the + * inode is reused, there will be no mixing of old dependencies with new + * ones. This artificial dependency is set up by the block de-allocation + * procedure above (softdep_setup_freeblocks) and completed by the + * following procedure. + */ +static void +handle_workitem_freefile(freefile) + struct freefile *freefile; +{ + struct workhead wkhd; + struct fs *fs; + struct inodedep *idp; + struct ufsmount *ump; + int error; + + ump = VFSTOUFS(freefile->fx_list.wk_mp); + fs = ump->um_fs; +#ifdef DEBUG + ACQUIRE_LOCK(ump); + error = inodedep_lookup(UFSTOVFS(ump), freefile->fx_oldinum, 0, &idp); + FREE_LOCK(ump); + if (error) + panic("handle_workitem_freefile: inodedep %p survived", idp); +#endif + UFS_LOCK(ump); + fs->fs_pendinginodes -= 1; + UFS_UNLOCK(ump); + LIST_INIT(&wkhd); + LIST_SWAP(&freefile->fx_jwork, &wkhd, worklist, wk_list); + if ((error = ffs_freefile(ump, fs, freefile->fx_devvp, + freefile->fx_oldinum, freefile->fx_mode, &wkhd)) != 0) + softdep_error("handle_workitem_freefile", error); + ACQUIRE_LOCK(ump); + WORKITEM_FREE(freefile, D_FREEFILE); + FREE_LOCK(ump); +} + + +/* + * Helper function which unlinks marker element from work list and returns + * the next element on the list. + */ +static __inline struct worklist * +markernext(struct worklist *marker) +{ + struct worklist *next; + + next = LIST_NEXT(marker, wk_list); + LIST_REMOVE(marker, wk_list); + return next; +} + +/* + * Disk writes. + * + * The dependency structures constructed above are most actively used when file + * system blocks are written to disk. No constraints are placed on when a + * block can be written, but unsatisfied update dependencies are made safe by + * modifying (or replacing) the source memory for the duration of the disk + * write. When the disk write completes, the memory block is again brought + * up-to-date. + * + * In-core inode structure reclamation. + * + * Because there are a finite number of "in-core" inode structures, they are + * reused regularly. By transferring all inode-related dependencies to the + * in-memory inode block and indexing them separately (via "inodedep"s), we + * can allow "in-core" inode structures to be reused at any time and avoid + * any increase in contention. + * + * Called just before entering the device driver to initiate a new disk I/O. + * The buffer must be locked, thus, no I/O completion operations can occur + * while we are manipulating its associated dependencies. + */ +static void +softdep_disk_io_initiation(bp) + struct buf *bp; /* structure describing disk write to occur */ +{ + struct worklist *wk; + struct worklist marker; + struct inodedep *inodedep; + struct freeblks *freeblks; + struct jblkdep *jblkdep; + struct newblk *newblk; + struct ufsmount *ump; + + /* + * We only care about write operations. There should never + * be dependencies for reads. + */ + if (bp->b_iocmd != BIO_WRITE) + panic("softdep_disk_io_initiation: not write"); + + if (bp->b_vflags & BV_BKGRDINPROG) + panic("softdep_disk_io_initiation: Writing buffer with " + "background write in progress: %p", bp); + + ump = softdep_bp_to_mp(bp); + if (ump == NULL) + return; + + marker.wk_type = D_LAST + 1; /* Not a normal workitem */ + PHOLD(curproc); /* Don't swap out kernel stack */ + ACQUIRE_LOCK(ump); + /* + * Do any necessary pre-I/O processing. + */ + for (wk = LIST_FIRST(&bp->b_dep); wk != NULL; + wk = markernext(&marker)) { + LIST_INSERT_AFTER(wk, &marker, wk_list); + switch (wk->wk_type) { + + case D_PAGEDEP: + initiate_write_filepage(WK_PAGEDEP(wk), bp); + continue; + + case D_INODEDEP: + inodedep = WK_INODEDEP(wk); + if (inodedep->id_fs->fs_magic == FS_UFS1_MAGIC) + initiate_write_inodeblock_ufs1(inodedep, bp); + else + initiate_write_inodeblock_ufs2(inodedep, bp); + continue; + + case D_INDIRDEP: + initiate_write_indirdep(WK_INDIRDEP(wk), bp); + continue; + + case D_BMSAFEMAP: + initiate_write_bmsafemap(WK_BMSAFEMAP(wk), bp); + continue; + + case D_JSEG: + WK_JSEG(wk)->js_buf = NULL; + continue; + + case D_FREEBLKS: + freeblks = WK_FREEBLKS(wk); + jblkdep = LIST_FIRST(&freeblks->fb_jblkdephd); + /* + * We have to wait for the freeblks to be journaled + * before we can write an inodeblock with updated + * pointers. Be careful to arrange the marker so + * we revisit the freeblks if it's not removed by + * the first jwait(). + */ + if (jblkdep != NULL) { + LIST_REMOVE(&marker, wk_list); + LIST_INSERT_BEFORE(wk, &marker, wk_list); + jwait(&jblkdep->jb_list, MNT_WAIT); + } + continue; + case D_ALLOCDIRECT: + case D_ALLOCINDIR: + /* + * We have to wait for the jnewblk to be journaled + * before we can write to a block if the contents + * may be confused with an earlier file's indirect + * at recovery time. Handle the marker as described + * above. + */ + newblk = WK_NEWBLK(wk); + if (newblk->nb_jnewblk != NULL && + indirblk_lookup(newblk->nb_list.wk_mp, + newblk->nb_newblkno)) { + LIST_REMOVE(&marker, wk_list); + LIST_INSERT_BEFORE(wk, &marker, wk_list); + jwait(&newblk->nb_jnewblk->jn_list, MNT_WAIT); + } + continue; + + case D_SBDEP: + initiate_write_sbdep(WK_SBDEP(wk)); + continue; + + case D_MKDIR: + case D_FREEWORK: + case D_FREEDEP: + case D_JSEGDEP: + continue; + + default: + panic("handle_disk_io_initiation: Unexpected type %s", + TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + } + FREE_LOCK(ump); + PRELE(curproc); /* Allow swapout of kernel stack */ +} + +/* + * Called from within the procedure above to deal with unsatisfied + * allocation dependencies in a directory. The buffer must be locked, + * thus, no I/O completion operations can occur while we are + * manipulating its associated dependencies. + */ +static void +initiate_write_filepage(pagedep, bp) + struct pagedep *pagedep; + struct buf *bp; +{ + struct jremref *jremref; + struct jmvref *jmvref; + struct dirrem *dirrem; + struct diradd *dap; + struct direct *ep; + int i; + + if (pagedep->pd_state & IOSTARTED) { + /* + * This can only happen if there is a driver that does not + * understand chaining. Here biodone will reissue the call + * to strategy for the incomplete buffers. + */ + printf("initiate_write_filepage: already started\n"); + return; + } + pagedep->pd_state |= IOSTARTED; + /* + * Wait for all journal remove dependencies to hit the disk. + * We can not allow any potentially conflicting directory adds + * to be visible before removes and rollback is too difficult. + * The per-filesystem lock may be dropped and re-acquired, however + * we hold the buf locked so the dependency can not go away. + */ + LIST_FOREACH(dirrem, &pagedep->pd_dirremhd, dm_next) + while ((jremref = LIST_FIRST(&dirrem->dm_jremrefhd)) != NULL) + jwait(&jremref->jr_list, MNT_WAIT); + while ((jmvref = LIST_FIRST(&pagedep->pd_jmvrefhd)) != NULL) + jwait(&jmvref->jm_list, MNT_WAIT); + for (i = 0; i < DAHASHSZ; i++) { + LIST_FOREACH(dap, &pagedep->pd_diraddhd[i], da_pdlist) { + ep = (struct direct *) + ((char *)bp->b_data + dap->da_offset); + if (ep->d_ino != dap->da_newinum) + panic("%s: dir inum %ju != new %ju", + "initiate_write_filepage", + (uintmax_t)ep->d_ino, + (uintmax_t)dap->da_newinum); + if (dap->da_state & DIRCHG) + ep->d_ino = dap->da_previous->dm_oldinum; + else + ep->d_ino = 0; + dap->da_state &= ~ATTACHED; + dap->da_state |= UNDONE; + } + } +} + +/* + * Version of initiate_write_inodeblock that handles UFS1 dinodes. + * Note that any bug fixes made to this routine must be done in the + * version found below. + * + * Called from within the procedure above to deal with unsatisfied + * allocation dependencies in an inodeblock. The buffer must be + * locked, thus, no I/O completion operations can occur while we + * are manipulating its associated dependencies. + */ +static void +initiate_write_inodeblock_ufs1(inodedep, bp) + struct inodedep *inodedep; + struct buf *bp; /* The inode block */ +{ + struct allocdirect *adp, *lastadp; + struct ufs1_dinode *dp; + struct ufs1_dinode *sip; + struct inoref *inoref; + struct ufsmount *ump; + struct fs *fs; + ufs_lbn_t i; +#ifdef INVARIANTS + ufs_lbn_t prevlbn = 0; +#endif + int deplist; + + if (inodedep->id_state & IOSTARTED) + panic("initiate_write_inodeblock_ufs1: already started"); + inodedep->id_state |= IOSTARTED; + fs = inodedep->id_fs; + ump = VFSTOUFS(inodedep->id_list.wk_mp); + LOCK_OWNED(ump); + dp = (struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, inodedep->id_ino); + + /* + * If we're on the unlinked list but have not yet written our + * next pointer initialize it here. + */ + if ((inodedep->id_state & (UNLINKED | UNLINKNEXT)) == UNLINKED) { + struct inodedep *inon; + + inon = TAILQ_NEXT(inodedep, id_unlinked); + dp->di_freelink = inon ? inon->id_ino : 0; + } + /* + * If the bitmap is not yet written, then the allocated + * inode cannot be written to disk. + */ + if ((inodedep->id_state & DEPCOMPLETE) == 0) { + if (inodedep->id_savedino1 != NULL) + panic("initiate_write_inodeblock_ufs1: I/O underway"); + FREE_LOCK(ump); + sip = malloc(sizeof(struct ufs1_dinode), + M_SAVEDINO, M_SOFTDEP_FLAGS); + ACQUIRE_LOCK(ump); + inodedep->id_savedino1 = sip; + *inodedep->id_savedino1 = *dp; + bzero((caddr_t)dp, sizeof(struct ufs1_dinode)); + dp->di_gen = inodedep->id_savedino1->di_gen; + dp->di_freelink = inodedep->id_savedino1->di_freelink; + return; + } + /* + * If no dependencies, then there is nothing to roll back. + */ + inodedep->id_savedsize = dp->di_size; + inodedep->id_savedextsize = 0; + inodedep->id_savednlink = dp->di_nlink; + if (TAILQ_EMPTY(&inodedep->id_inoupdt) && + TAILQ_EMPTY(&inodedep->id_inoreflst)) + return; + /* + * Revert the link count to that of the first unwritten journal entry. + */ + inoref = TAILQ_FIRST(&inodedep->id_inoreflst); + if (inoref) + dp->di_nlink = inoref->if_nlink; + /* + * Set the dependencies to busy. + */ + for (deplist = 0, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; + adp = TAILQ_NEXT(adp, ad_next)) { +#ifdef INVARIANTS + if (deplist != 0 && prevlbn >= adp->ad_offset) + panic("softdep_write_inodeblock: lbn order"); + prevlbn = adp->ad_offset; + if (adp->ad_offset < NDADDR && + dp->di_db[adp->ad_offset] != adp->ad_newblkno) + panic("%s: direct pointer #%jd mismatch %d != %jd", + "softdep_write_inodeblock", + (intmax_t)adp->ad_offset, + dp->di_db[adp->ad_offset], + (intmax_t)adp->ad_newblkno); + if (adp->ad_offset >= NDADDR && + dp->di_ib[adp->ad_offset - NDADDR] != adp->ad_newblkno) + panic("%s: indirect pointer #%jd mismatch %d != %jd", + "softdep_write_inodeblock", + (intmax_t)adp->ad_offset - NDADDR, + dp->di_ib[adp->ad_offset - NDADDR], + (intmax_t)adp->ad_newblkno); + deplist |= 1 << adp->ad_offset; + if ((adp->ad_state & ATTACHED) == 0) + panic("softdep_write_inodeblock: Unknown state 0x%x", + adp->ad_state); +#endif /* INVARIANTS */ + adp->ad_state &= ~ATTACHED; + adp->ad_state |= UNDONE; + } + /* + * The on-disk inode cannot claim to be any larger than the last + * fragment that has been written. Otherwise, the on-disk inode + * might have fragments that were not the last block in the file + * which would corrupt the filesystem. + */ + for (lastadp = NULL, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; + lastadp = adp, adp = TAILQ_NEXT(adp, ad_next)) { + if (adp->ad_offset >= NDADDR) + break; + dp->di_db[adp->ad_offset] = adp->ad_oldblkno; + /* keep going until hitting a rollback to a frag */ + if (adp->ad_oldsize == 0 || adp->ad_oldsize == fs->fs_bsize) + continue; + dp->di_size = fs->fs_bsize * adp->ad_offset + adp->ad_oldsize; + for (i = adp->ad_offset + 1; i < NDADDR; i++) { +#ifdef INVARIANTS + if (dp->di_db[i] != 0 && (deplist & (1 << i)) == 0) + panic("softdep_write_inodeblock: lost dep1"); +#endif /* INVARIANTS */ + dp->di_db[i] = 0; + } + for (i = 0; i < NIADDR; i++) { +#ifdef INVARIANTS + if (dp->di_ib[i] != 0 && + (deplist & ((1 << NDADDR) << i)) == 0) + panic("softdep_write_inodeblock: lost dep2"); +#endif /* INVARIANTS */ + dp->di_ib[i] = 0; + } + return; + } + /* + * If we have zero'ed out the last allocated block of the file, + * roll back the size to the last currently allocated block. + * We know that this last allocated block is a full-sized as + * we already checked for fragments in the loop above. + */ + if (lastadp != NULL && + dp->di_size <= (lastadp->ad_offset + 1) * fs->fs_bsize) { + for (i = lastadp->ad_offset; i >= 0; i--) + if (dp->di_db[i] != 0) + break; + dp->di_size = (i + 1) * fs->fs_bsize; + } + /* + * The only dependencies are for indirect blocks. + * + * The file size for indirect block additions is not guaranteed. + * Such a guarantee would be non-trivial to achieve. The conventional + * synchronous write implementation also does not make this guarantee. + * Fsck should catch and fix discrepancies. Arguably, the file size + * can be over-estimated without destroying integrity when the file + * moves into the indirect blocks (i.e., is large). If we want to + * postpone fsck, we are stuck with this argument. + */ + for (; adp; adp = TAILQ_NEXT(adp, ad_next)) + dp->di_ib[adp->ad_offset - NDADDR] = 0; +} + +/* + * Version of initiate_write_inodeblock that handles UFS2 dinodes. + * Note that any bug fixes made to this routine must be done in the + * version found above. + * + * Called from within the procedure above to deal with unsatisfied + * allocation dependencies in an inodeblock. The buffer must be + * locked, thus, no I/O completion operations can occur while we + * are manipulating its associated dependencies. + */ +static void +initiate_write_inodeblock_ufs2(inodedep, bp) + struct inodedep *inodedep; + struct buf *bp; /* The inode block */ +{ + struct allocdirect *adp, *lastadp; + struct ufs2_dinode *dp; + struct ufs2_dinode *sip; + struct inoref *inoref; + struct ufsmount *ump; + struct fs *fs; + ufs_lbn_t i; +#ifdef INVARIANTS + ufs_lbn_t prevlbn = 0; +#endif + int deplist; + + if (inodedep->id_state & IOSTARTED) + panic("initiate_write_inodeblock_ufs2: already started"); + inodedep->id_state |= IOSTARTED; + fs = inodedep->id_fs; + ump = VFSTOUFS(inodedep->id_list.wk_mp); + LOCK_OWNED(ump); + dp = (struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, inodedep->id_ino); + + /* + * If we're on the unlinked list but have not yet written our + * next pointer initialize it here. + */ + if ((inodedep->id_state & (UNLINKED | UNLINKNEXT)) == UNLINKED) { + struct inodedep *inon; + + inon = TAILQ_NEXT(inodedep, id_unlinked); + dp->di_freelink = inon ? inon->id_ino : 0; + } + /* + * If the bitmap is not yet written, then the allocated + * inode cannot be written to disk. + */ + if ((inodedep->id_state & DEPCOMPLETE) == 0) { + if (inodedep->id_savedino2 != NULL) + panic("initiate_write_inodeblock_ufs2: I/O underway"); + FREE_LOCK(ump); + sip = malloc(sizeof(struct ufs2_dinode), + M_SAVEDINO, M_SOFTDEP_FLAGS); + ACQUIRE_LOCK(ump); + inodedep->id_savedino2 = sip; + *inodedep->id_savedino2 = *dp; + bzero((caddr_t)dp, sizeof(struct ufs2_dinode)); + dp->di_gen = inodedep->id_savedino2->di_gen; + dp->di_freelink = inodedep->id_savedino2->di_freelink; + return; + } + /* + * If no dependencies, then there is nothing to roll back. + */ + inodedep->id_savedsize = dp->di_size; + inodedep->id_savedextsize = dp->di_extsize; + inodedep->id_savednlink = dp->di_nlink; + if (TAILQ_EMPTY(&inodedep->id_inoupdt) && + TAILQ_EMPTY(&inodedep->id_extupdt) && + TAILQ_EMPTY(&inodedep->id_inoreflst)) + return; + /* + * Revert the link count to that of the first unwritten journal entry. + */ + inoref = TAILQ_FIRST(&inodedep->id_inoreflst); + if (inoref) + dp->di_nlink = inoref->if_nlink; + + /* + * Set the ext data dependencies to busy. + */ + for (deplist = 0, adp = TAILQ_FIRST(&inodedep->id_extupdt); adp; + adp = TAILQ_NEXT(adp, ad_next)) { +#ifdef INVARIANTS + if (deplist != 0 && prevlbn >= adp->ad_offset) + panic("softdep_write_inodeblock: lbn order"); + prevlbn = adp->ad_offset; + if (dp->di_extb[adp->ad_offset] != adp->ad_newblkno) + panic("%s: direct pointer #%jd mismatch %jd != %jd", + "softdep_write_inodeblock", + (intmax_t)adp->ad_offset, + (intmax_t)dp->di_extb[adp->ad_offset], + (intmax_t)adp->ad_newblkno); + deplist |= 1 << adp->ad_offset; + if ((adp->ad_state & ATTACHED) == 0) + panic("softdep_write_inodeblock: Unknown state 0x%x", + adp->ad_state); +#endif /* INVARIANTS */ + adp->ad_state &= ~ATTACHED; + adp->ad_state |= UNDONE; + } + /* + * The on-disk inode cannot claim to be any larger than the last + * fragment that has been written. Otherwise, the on-disk inode + * might have fragments that were not the last block in the ext + * data which would corrupt the filesystem. + */ + for (lastadp = NULL, adp = TAILQ_FIRST(&inodedep->id_extupdt); adp; + lastadp = adp, adp = TAILQ_NEXT(adp, ad_next)) { + dp->di_extb[adp->ad_offset] = adp->ad_oldblkno; + /* keep going until hitting a rollback to a frag */ + if (adp->ad_oldsize == 0 || adp->ad_oldsize == fs->fs_bsize) + continue; + dp->di_extsize = fs->fs_bsize * adp->ad_offset + adp->ad_oldsize; + for (i = adp->ad_offset + 1; i < NXADDR; i++) { +#ifdef INVARIANTS + if (dp->di_extb[i] != 0 && (deplist & (1 << i)) == 0) + panic("softdep_write_inodeblock: lost dep1"); +#endif /* INVARIANTS */ + dp->di_extb[i] = 0; + } + lastadp = NULL; + break; + } + /* + * If we have zero'ed out the last allocated block of the ext + * data, roll back the size to the last currently allocated block. + * We know that this last allocated block is a full-sized as + * we already checked for fragments in the loop above. + */ + if (lastadp != NULL && + dp->di_extsize <= (lastadp->ad_offset + 1) * fs->fs_bsize) { + for (i = lastadp->ad_offset; i >= 0; i--) + if (dp->di_extb[i] != 0) + break; + dp->di_extsize = (i + 1) * fs->fs_bsize; + } + /* + * Set the file data dependencies to busy. + */ + for (deplist = 0, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; + adp = TAILQ_NEXT(adp, ad_next)) { +#ifdef INVARIANTS + if (deplist != 0 && prevlbn >= adp->ad_offset) + panic("softdep_write_inodeblock: lbn order"); + if ((adp->ad_state & ATTACHED) == 0) + panic("inodedep %p and adp %p not attached", inodedep, adp); + prevlbn = adp->ad_offset; + if (adp->ad_offset < NDADDR && + dp->di_db[adp->ad_offset] != adp->ad_newblkno) + panic("%s: direct pointer #%jd mismatch %jd != %jd", + "softdep_write_inodeblock", + (intmax_t)adp->ad_offset, + (intmax_t)dp->di_db[adp->ad_offset], + (intmax_t)adp->ad_newblkno); + if (adp->ad_offset >= NDADDR && + dp->di_ib[adp->ad_offset - NDADDR] != adp->ad_newblkno) + panic("%s indirect pointer #%jd mismatch %jd != %jd", + "softdep_write_inodeblock:", + (intmax_t)adp->ad_offset - NDADDR, + (intmax_t)dp->di_ib[adp->ad_offset - NDADDR], + (intmax_t)adp->ad_newblkno); + deplist |= 1 << adp->ad_offset; + if ((adp->ad_state & ATTACHED) == 0) + panic("softdep_write_inodeblock: Unknown state 0x%x", + adp->ad_state); +#endif /* INVARIANTS */ + adp->ad_state &= ~ATTACHED; + adp->ad_state |= UNDONE; + } + /* + * The on-disk inode cannot claim to be any larger than the last + * fragment that has been written. Otherwise, the on-disk inode + * might have fragments that were not the last block in the file + * which would corrupt the filesystem. + */ + for (lastadp = NULL, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; + lastadp = adp, adp = TAILQ_NEXT(adp, ad_next)) { + if (adp->ad_offset >= NDADDR) + break; + dp->di_db[adp->ad_offset] = adp->ad_oldblkno; + /* keep going until hitting a rollback to a frag */ + if (adp->ad_oldsize == 0 || adp->ad_oldsize == fs->fs_bsize) + continue; + dp->di_size = fs->fs_bsize * adp->ad_offset + adp->ad_oldsize; + for (i = adp->ad_offset + 1; i < NDADDR; i++) { +#ifdef INVARIANTS + if (dp->di_db[i] != 0 && (deplist & (1 << i)) == 0) + panic("softdep_write_inodeblock: lost dep2"); +#endif /* INVARIANTS */ + dp->di_db[i] = 0; + } + for (i = 0; i < NIADDR; i++) { +#ifdef INVARIANTS + if (dp->di_ib[i] != 0 && + (deplist & ((1 << NDADDR) << i)) == 0) + panic("softdep_write_inodeblock: lost dep3"); +#endif /* INVARIANTS */ + dp->di_ib[i] = 0; + } + return; + } + /* + * If we have zero'ed out the last allocated block of the file, + * roll back the size to the last currently allocated block. + * We know that this last allocated block is a full-sized as + * we already checked for fragments in the loop above. + */ + if (lastadp != NULL && + dp->di_size <= (lastadp->ad_offset + 1) * fs->fs_bsize) { + for (i = lastadp->ad_offset; i >= 0; i--) + if (dp->di_db[i] != 0) + break; + dp->di_size = (i + 1) * fs->fs_bsize; + } + /* + * The only dependencies are for indirect blocks. + * + * The file size for indirect block additions is not guaranteed. + * Such a guarantee would be non-trivial to achieve. The conventional + * synchronous write implementation also does not make this guarantee. + * Fsck should catch and fix discrepancies. Arguably, the file size + * can be over-estimated without destroying integrity when the file + * moves into the indirect blocks (i.e., is large). If we want to + * postpone fsck, we are stuck with this argument. + */ + for (; adp; adp = TAILQ_NEXT(adp, ad_next)) + dp->di_ib[adp->ad_offset - NDADDR] = 0; +} + +/* + * Cancel an indirdep as a result of truncation. Release all of the + * children allocindirs and place their journal work on the appropriate + * list. + */ +static void +cancel_indirdep(indirdep, bp, freeblks) + struct indirdep *indirdep; + struct buf *bp; + struct freeblks *freeblks; +{ + struct allocindir *aip; + + /* + * None of the indirect pointers will ever be visible, + * so they can simply be tossed. GOINGAWAY ensures + * that allocated pointers will be saved in the buffer + * cache until they are freed. Note that they will + * only be able to be found by their physical address + * since the inode mapping the logical address will + * be gone. The save buffer used for the safe copy + * was allocated in setup_allocindir_phase2 using + * the physical address so it could be used for this + * purpose. Hence we swap the safe copy with the real + * copy, allowing the safe copy to be freed and holding + * on to the real copy for later use in indir_trunc. + */ + if (indirdep->ir_state & GOINGAWAY) + panic("cancel_indirdep: already gone"); + if ((indirdep->ir_state & DEPCOMPLETE) == 0) { + indirdep->ir_state |= DEPCOMPLETE; + LIST_REMOVE(indirdep, ir_next); + } + indirdep->ir_state |= GOINGAWAY; + /* + * Pass in bp for blocks still have journal writes + * pending so we can cancel them on their own. + */ + while ((aip = LIST_FIRST(&indirdep->ir_deplisthd)) != NULL) + cancel_allocindir(aip, bp, freeblks, 0); + while ((aip = LIST_FIRST(&indirdep->ir_donehd)) != NULL) + cancel_allocindir(aip, NULL, freeblks, 0); + while ((aip = LIST_FIRST(&indirdep->ir_writehd)) != NULL) + cancel_allocindir(aip, NULL, freeblks, 0); + while ((aip = LIST_FIRST(&indirdep->ir_completehd)) != NULL) + cancel_allocindir(aip, NULL, freeblks, 0); + /* + * If there are pending partial truncations we need to keep the + * old block copy around until they complete. This is because + * the current b_data is not a perfect superset of the available + * blocks. + */ + if (TAILQ_EMPTY(&indirdep->ir_trunc)) + bcopy(bp->b_data, indirdep->ir_savebp->b_data, bp->b_bcount); + else + bcopy(bp->b_data, indirdep->ir_saveddata, bp->b_bcount); + WORKLIST_REMOVE(&indirdep->ir_list); + WORKLIST_INSERT(&indirdep->ir_savebp->b_dep, &indirdep->ir_list); + indirdep->ir_bp = NULL; + indirdep->ir_freeblks = freeblks; +} + +/* + * Free an indirdep once it no longer has new pointers to track. + */ +static void +free_indirdep(indirdep) + struct indirdep *indirdep; +{ + + KASSERT(TAILQ_EMPTY(&indirdep->ir_trunc), + ("free_indirdep: Indir trunc list not empty.")); + KASSERT(LIST_EMPTY(&indirdep->ir_completehd), + ("free_indirdep: Complete head not empty.")); + KASSERT(LIST_EMPTY(&indirdep->ir_writehd), + ("free_indirdep: write head not empty.")); + KASSERT(LIST_EMPTY(&indirdep->ir_donehd), + ("free_indirdep: done head not empty.")); + KASSERT(LIST_EMPTY(&indirdep->ir_deplisthd), + ("free_indirdep: deplist head not empty.")); + KASSERT((indirdep->ir_state & DEPCOMPLETE), + ("free_indirdep: %p still on newblk list.", indirdep)); + KASSERT(indirdep->ir_saveddata == NULL, + ("free_indirdep: %p still has saved data.", indirdep)); + if (indirdep->ir_state & ONWORKLIST) + WORKLIST_REMOVE(&indirdep->ir_list); + WORKITEM_FREE(indirdep, D_INDIRDEP); +} + +/* + * Called before a write to an indirdep. This routine is responsible for + * rolling back pointers to a safe state which includes only those + * allocindirs which have been completed. + */ +static void +initiate_write_indirdep(indirdep, bp) + struct indirdep *indirdep; + struct buf *bp; +{ + struct ufsmount *ump; + + indirdep->ir_state |= IOSTARTED; + if (indirdep->ir_state & GOINGAWAY) + panic("disk_io_initiation: indirdep gone"); + /* + * If there are no remaining dependencies, this will be writing + * the real pointers. + */ + if (LIST_EMPTY(&indirdep->ir_deplisthd) && + TAILQ_EMPTY(&indirdep->ir_trunc)) + return; + /* + * Replace up-to-date version with safe version. + */ + if (indirdep->ir_saveddata == NULL) { + ump = VFSTOUFS(indirdep->ir_list.wk_mp); + LOCK_OWNED(ump); + FREE_LOCK(ump); + indirdep->ir_saveddata = malloc(bp->b_bcount, M_INDIRDEP, + M_SOFTDEP_FLAGS); + ACQUIRE_LOCK(ump); + } + indirdep->ir_state &= ~ATTACHED; + indirdep->ir_state |= UNDONE; + bcopy(bp->b_data, indirdep->ir_saveddata, bp->b_bcount); + bcopy(indirdep->ir_savebp->b_data, bp->b_data, + bp->b_bcount); +} + +/* + * Called when an inode has been cleared in a cg bitmap. This finally + * eliminates any canceled jaddrefs + */ +void +softdep_setup_inofree(mp, bp, ino, wkhd) + struct mount *mp; + struct buf *bp; + ino_t ino; + struct workhead *wkhd; +{ + struct worklist *wk, *wkn; + struct inodedep *inodedep; + struct ufsmount *ump; + uint8_t *inosused; + struct cg *cgp; + struct fs *fs; + + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_setup_inofree called on non-softdep filesystem")); + ump = VFSTOUFS(mp); + ACQUIRE_LOCK(ump); + fs = ump->um_fs; + cgp = (struct cg *)bp->b_data; + inosused = cg_inosused(cgp); + if (isset(inosused, ino % fs->fs_ipg)) + panic("softdep_setup_inofree: inode %ju not freed.", + (uintmax_t)ino); + if (inodedep_lookup(mp, ino, 0, &inodedep)) + panic("softdep_setup_inofree: ino %ju has existing inodedep %p", + (uintmax_t)ino, inodedep); + if (wkhd) { + LIST_FOREACH_SAFE(wk, wkhd, wk_list, wkn) { + if (wk->wk_type != D_JADDREF) + continue; + WORKLIST_REMOVE(wk); + /* + * We can free immediately even if the jaddref + * isn't attached in a background write as now + * the bitmaps are reconciled. + */ + wk->wk_state |= COMPLETE | ATTACHED; + free_jaddref(WK_JADDREF(wk)); + } + jwork_move(&bp->b_dep, wkhd); + } + FREE_LOCK(ump); +} + + +/* + * Called via ffs_blkfree() after a set of frags has been cleared from a cg + * map. Any dependencies waiting for the write to clear are added to the + * buf's list and any jnewblks that are being canceled are discarded + * immediately. + */ +void +softdep_setup_blkfree(mp, bp, blkno, frags, wkhd) + struct mount *mp; + struct buf *bp; + ufs2_daddr_t blkno; + int frags; + struct workhead *wkhd; +{ + struct bmsafemap *bmsafemap; + struct jnewblk *jnewblk; + struct ufsmount *ump; + struct worklist *wk; + struct fs *fs; +#ifdef SUJ_DEBUG + uint8_t *blksfree; + struct cg *cgp; + ufs2_daddr_t jstart; + ufs2_daddr_t jend; + ufs2_daddr_t end; + long bno; + int i; +#endif + + CTR3(KTR_SUJ, + "softdep_setup_blkfree: blkno %jd frags %d wk head %p", + blkno, frags, wkhd); + + ump = VFSTOUFS(mp); + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_setup_blkfree called on non-softdep filesystem")); + ACQUIRE_LOCK(ump); + /* Lookup the bmsafemap so we track when it is dirty. */ + fs = ump->um_fs; + bmsafemap = bmsafemap_lookup(mp, bp, dtog(fs, blkno), NULL); + /* + * Detach any jnewblks which have been canceled. They must linger + * until the bitmap is cleared again by ffs_blkfree() to prevent + * an unjournaled allocation from hitting the disk. + */ + if (wkhd) { + while ((wk = LIST_FIRST(wkhd)) != NULL) { + CTR2(KTR_SUJ, + "softdep_setup_blkfree: blkno %jd wk type %d", + blkno, wk->wk_type); + WORKLIST_REMOVE(wk); + if (wk->wk_type != D_JNEWBLK) { + WORKLIST_INSERT(&bmsafemap->sm_freehd, wk); + continue; + } + jnewblk = WK_JNEWBLK(wk); + KASSERT(jnewblk->jn_state & GOINGAWAY, + ("softdep_setup_blkfree: jnewblk not canceled.")); +#ifdef SUJ_DEBUG + /* + * Assert that this block is free in the bitmap + * before we discard the jnewblk. + */ + cgp = (struct cg *)bp->b_data; + blksfree = cg_blksfree(cgp); + bno = dtogd(fs, jnewblk->jn_blkno); + for (i = jnewblk->jn_oldfrags; + i < jnewblk->jn_frags; i++) { + if (isset(blksfree, bno + i)) + continue; + panic("softdep_setup_blkfree: not free"); + } +#endif + /* + * Even if it's not attached we can free immediately + * as the new bitmap is correct. + */ + wk->wk_state |= COMPLETE | ATTACHED; + free_jnewblk(jnewblk); + } + } + +#ifdef SUJ_DEBUG + /* + * Assert that we are not freeing a block which has an outstanding + * allocation dependency. + */ + fs = VFSTOUFS(mp)->um_fs; + bmsafemap = bmsafemap_lookup(mp, bp, dtog(fs, blkno), NULL); + end = blkno + frags; + LIST_FOREACH(jnewblk, &bmsafemap->sm_jnewblkhd, jn_deps) { + /* + * Don't match against blocks that will be freed when the + * background write is done. + */ + if ((jnewblk->jn_state & (ATTACHED | COMPLETE | DEPCOMPLETE)) == + (COMPLETE | DEPCOMPLETE)) + continue; + jstart = jnewblk->jn_blkno + jnewblk->jn_oldfrags; + jend = jnewblk->jn_blkno + jnewblk->jn_frags; + if ((blkno >= jstart && blkno < jend) || + (end > jstart && end <= jend)) { + printf("state 0x%X %jd - %d %d dep %p\n", + jnewblk->jn_state, jnewblk->jn_blkno, + jnewblk->jn_oldfrags, jnewblk->jn_frags, + jnewblk->jn_dep); + panic("softdep_setup_blkfree: " + "%jd-%jd(%d) overlaps with %jd-%jd", + blkno, end, frags, jstart, jend); + } + } +#endif + FREE_LOCK(ump); +} + +/* + * Revert a block allocation when the journal record that describes it + * is not yet written. + */ +static int +jnewblk_rollback(jnewblk, fs, cgp, blksfree) + struct jnewblk *jnewblk; + struct fs *fs; + struct cg *cgp; + uint8_t *blksfree; +{ + ufs1_daddr_t fragno; + long cgbno, bbase; + int frags, blk; + int i; + + frags = 0; + cgbno = dtogd(fs, jnewblk->jn_blkno); + /* + * We have to test which frags need to be rolled back. We may + * be operating on a stale copy when doing background writes. + */ + for (i = jnewblk->jn_oldfrags; i < jnewblk->jn_frags; i++) + if (isclr(blksfree, cgbno + i)) + frags++; + if (frags == 0) + return (0); + /* + * This is mostly ffs_blkfree() sans some validation and + * superblock updates. + */ + if (frags == fs->fs_frag) { + fragno = fragstoblks(fs, cgbno); + ffs_setblock(fs, blksfree, fragno); + ffs_clusteracct(fs, cgp, fragno, 1); + cgp->cg_cs.cs_nbfree++; + } else { + cgbno += jnewblk->jn_oldfrags; + bbase = cgbno - fragnum(fs, cgbno); + /* Decrement the old frags. */ + blk = blkmap(fs, blksfree, bbase); + ffs_fragacct(fs, blk, cgp->cg_frsum, -1); + /* Deallocate the fragment */ + for (i = 0; i < frags; i++) + setbit(blksfree, cgbno + i); + cgp->cg_cs.cs_nffree += frags; + /* Add back in counts associated with the new frags */ + blk = blkmap(fs, blksfree, bbase); + ffs_fragacct(fs, blk, cgp->cg_frsum, 1); + /* If a complete block has been reassembled, account for it. */ + fragno = fragstoblks(fs, bbase); + if (ffs_isblock(fs, blksfree, fragno)) { + cgp->cg_cs.cs_nffree -= fs->fs_frag; + ffs_clusteracct(fs, cgp, fragno, 1); + cgp->cg_cs.cs_nbfree++; + } + } + stat_jnewblk++; + jnewblk->jn_state &= ~ATTACHED; + jnewblk->jn_state |= UNDONE; + + return (frags); +} + +static void +initiate_write_bmsafemap(bmsafemap, bp) + struct bmsafemap *bmsafemap; + struct buf *bp; /* The cg block. */ +{ + struct jaddref *jaddref; + struct jnewblk *jnewblk; + uint8_t *inosused; + uint8_t *blksfree; + struct cg *cgp; + struct fs *fs; + ino_t ino; + + /* + * If this is a background write, we did this at the time that + * the copy was made, so do not need to do it again. + */ + if (bmsafemap->sm_state & IOSTARTED) + return; + bmsafemap->sm_state |= IOSTARTED; + /* + * Clear any inode allocations which are pending journal writes. + */ + if (LIST_FIRST(&bmsafemap->sm_jaddrefhd) != NULL) { + cgp = (struct cg *)bp->b_data; + fs = VFSTOUFS(bmsafemap->sm_list.wk_mp)->um_fs; + inosused = cg_inosused(cgp); + LIST_FOREACH(jaddref, &bmsafemap->sm_jaddrefhd, ja_bmdeps) { + ino = jaddref->ja_ino % fs->fs_ipg; + if (isset(inosused, ino)) { + if ((jaddref->ja_mode & IFMT) == IFDIR) + cgp->cg_cs.cs_ndir--; + cgp->cg_cs.cs_nifree++; + clrbit(inosused, ino); + jaddref->ja_state &= ~ATTACHED; + jaddref->ja_state |= UNDONE; + stat_jaddref++; + } else + panic("initiate_write_bmsafemap: inode %ju " + "marked free", (uintmax_t)jaddref->ja_ino); + } + } + /* + * Clear any block allocations which are pending journal writes. + */ + if (LIST_FIRST(&bmsafemap->sm_jnewblkhd) != NULL) { + cgp = (struct cg *)bp->b_data; + fs = VFSTOUFS(bmsafemap->sm_list.wk_mp)->um_fs; + blksfree = cg_blksfree(cgp); + LIST_FOREACH(jnewblk, &bmsafemap->sm_jnewblkhd, jn_deps) { + if (jnewblk_rollback(jnewblk, fs, cgp, blksfree)) + continue; + panic("initiate_write_bmsafemap: block %jd " + "marked free", jnewblk->jn_blkno); + } + } + /* + * Move allocation lists to the written lists so they can be + * cleared once the block write is complete. + */ + LIST_SWAP(&bmsafemap->sm_inodedephd, &bmsafemap->sm_inodedepwr, + inodedep, id_deps); + LIST_SWAP(&bmsafemap->sm_newblkhd, &bmsafemap->sm_newblkwr, + newblk, nb_deps); + LIST_SWAP(&bmsafemap->sm_freehd, &bmsafemap->sm_freewr, worklist, + wk_list); +} + +/* + * This routine is called during the completion interrupt + * service routine for a disk write (from the procedure called + * by the device driver to inform the filesystem caches of + * a request completion). It should be called early in this + * procedure, before the block is made available to other + * processes or other routines are called. + * + */ +static void +softdep_disk_write_complete(bp) + struct buf *bp; /* describes the completed disk write */ +{ + struct worklist *wk; + struct worklist *owk; + struct ufsmount *ump; + struct workhead reattach; + struct freeblks *freeblks; + struct buf *sbp; + + ump = softdep_bp_to_mp(bp); + if (ump == NULL) + return; + + /* + * If an error occurred while doing the write, then the data + * has not hit the disk and the dependencies cannot be processed. + * But we do have to go through and roll forward any dependencies + * that were rolled back before the disk write. + */ + ACQUIRE_LOCK(ump); + if ((bp->b_ioflags & BIO_ERROR) != 0 && (bp->b_flags & B_INVAL) == 0) { + LIST_FOREACH(wk, &bp->b_dep, wk_list) { + switch (wk->wk_type) { + + case D_PAGEDEP: + handle_written_filepage(WK_PAGEDEP(wk), bp, 0); + continue; + + case D_INODEDEP: + handle_written_inodeblock(WK_INODEDEP(wk), + bp, 0); + continue; + + case D_BMSAFEMAP: + handle_written_bmsafemap(WK_BMSAFEMAP(wk), + bp, 0); + continue; + + case D_INDIRDEP: + handle_written_indirdep(WK_INDIRDEP(wk), + bp, &sbp, 0); + continue; + default: + /* nothing to roll forward */ + continue; + } + } + FREE_LOCK(ump); + return; + } + LIST_INIT(&reattach); + + /* + * Ump SU lock must not be released anywhere in this code segment. + */ + sbp = NULL; + owk = NULL; + while ((wk = LIST_FIRST(&bp->b_dep)) != NULL) { + WORKLIST_REMOVE(wk); + atomic_add_long(&dep_write[wk->wk_type], 1); + if (wk == owk) + panic("duplicate worklist: %p\n", wk); + owk = wk; + switch (wk->wk_type) { + + case D_PAGEDEP: + if (handle_written_filepage(WK_PAGEDEP(wk), bp, + WRITESUCCEEDED)) + WORKLIST_INSERT(&reattach, wk); + continue; + + case D_INODEDEP: + if (handle_written_inodeblock(WK_INODEDEP(wk), bp, + WRITESUCCEEDED)) + WORKLIST_INSERT(&reattach, wk); + continue; + + case D_BMSAFEMAP: + if (handle_written_bmsafemap(WK_BMSAFEMAP(wk), bp, + WRITESUCCEEDED)) + WORKLIST_INSERT(&reattach, wk); + continue; + + case D_MKDIR: + handle_written_mkdir(WK_MKDIR(wk), MKDIR_BODY); + continue; + + case D_ALLOCDIRECT: + wk->wk_state |= COMPLETE; + handle_allocdirect_partdone(WK_ALLOCDIRECT(wk), NULL); + continue; + + case D_ALLOCINDIR: + wk->wk_state |= COMPLETE; + handle_allocindir_partdone(WK_ALLOCINDIR(wk)); + continue; + + case D_INDIRDEP: + if (handle_written_indirdep(WK_INDIRDEP(wk), bp, &sbp, + WRITESUCCEEDED)) + WORKLIST_INSERT(&reattach, wk); + continue; + + case D_FREEBLKS: + wk->wk_state |= COMPLETE; + freeblks = WK_FREEBLKS(wk); + if ((wk->wk_state & ALLCOMPLETE) == ALLCOMPLETE && + LIST_EMPTY(&freeblks->fb_jblkdephd)) + add_to_worklist(wk, WK_NODELAY); + continue; + + case D_FREEWORK: + handle_written_freework(WK_FREEWORK(wk)); + break; + + case D_JSEGDEP: + free_jsegdep(WK_JSEGDEP(wk)); + continue; + + case D_JSEG: + handle_written_jseg(WK_JSEG(wk), bp); + continue; + + case D_SBDEP: + if (handle_written_sbdep(WK_SBDEP(wk), bp)) + WORKLIST_INSERT(&reattach, wk); + continue; + + case D_FREEDEP: + free_freedep(WK_FREEDEP(wk)); + continue; + + default: + panic("handle_disk_write_complete: Unknown type %s", + TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + } + /* + * Reattach any requests that must be redone. + */ + while ((wk = LIST_FIRST(&reattach)) != NULL) { + WORKLIST_REMOVE(wk); + WORKLIST_INSERT(&bp->b_dep, wk); + } + FREE_LOCK(ump); + if (sbp) + brelse(sbp); +} + +/* + * Called from within softdep_disk_write_complete above. Note that + * this routine is always called from interrupt level with further + * splbio interrupts blocked. + */ +static void +handle_allocdirect_partdone(adp, wkhd) + struct allocdirect *adp; /* the completed allocdirect */ + struct workhead *wkhd; /* Work to do when inode is writtne. */ +{ + struct allocdirectlst *listhead; + struct allocdirect *listadp; + struct inodedep *inodedep; + long bsize; + + if ((adp->ad_state & ALLCOMPLETE) != ALLCOMPLETE) + return; + /* + * The on-disk inode cannot claim to be any larger than the last + * fragment that has been written. Otherwise, the on-disk inode + * might have fragments that were not the last block in the file + * which would corrupt the filesystem. Thus, we cannot free any + * allocdirects after one whose ad_oldblkno claims a fragment as + * these blocks must be rolled back to zero before writing the inode. + * We check the currently active set of allocdirects in id_inoupdt + * or id_extupdt as appropriate. + */ + inodedep = adp->ad_inodedep; + bsize = inodedep->id_fs->fs_bsize; + if (adp->ad_state & EXTDATA) + listhead = &inodedep->id_extupdt; + else + listhead = &inodedep->id_inoupdt; + TAILQ_FOREACH(listadp, listhead, ad_next) { + /* found our block */ + if (listadp == adp) + break; + /* continue if ad_oldlbn is not a fragment */ + if (listadp->ad_oldsize == 0 || + listadp->ad_oldsize == bsize) + continue; + /* hit a fragment */ + return; + } + /* + * If we have reached the end of the current list without + * finding the just finished dependency, then it must be + * on the future dependency list. Future dependencies cannot + * be freed until they are moved to the current list. + */ + if (listadp == NULL) { +#ifdef DEBUG + if (adp->ad_state & EXTDATA) + listhead = &inodedep->id_newextupdt; + else + listhead = &inodedep->id_newinoupdt; + TAILQ_FOREACH(listadp, listhead, ad_next) + /* found our block */ + if (listadp == adp) + break; + if (listadp == NULL) + panic("handle_allocdirect_partdone: lost dep"); +#endif /* DEBUG */ + return; + } + /* + * If we have found the just finished dependency, then queue + * it along with anything that follows it that is complete. + * Since the pointer has not yet been written in the inode + * as the dependency prevents it, place the allocdirect on the + * bufwait list where it will be freed once the pointer is + * valid. + */ + if (wkhd == NULL) + wkhd = &inodedep->id_bufwait; + for (; adp; adp = listadp) { + listadp = TAILQ_NEXT(adp, ad_next); + if ((adp->ad_state & ALLCOMPLETE) != ALLCOMPLETE) + return; + TAILQ_REMOVE(listhead, adp, ad_next); + WORKLIST_INSERT(wkhd, &adp->ad_block.nb_list); + } +} + +/* + * Called from within softdep_disk_write_complete above. This routine + * completes successfully written allocindirs. + */ +static void +handle_allocindir_partdone(aip) + struct allocindir *aip; /* the completed allocindir */ +{ + struct indirdep *indirdep; + + if ((aip->ai_state & ALLCOMPLETE) != ALLCOMPLETE) + return; + indirdep = aip->ai_indirdep; + LIST_REMOVE(aip, ai_next); + /* + * Don't set a pointer while the buffer is undergoing IO or while + * we have active truncations. + */ + if (indirdep->ir_state & UNDONE || !TAILQ_EMPTY(&indirdep->ir_trunc)) { + LIST_INSERT_HEAD(&indirdep->ir_donehd, aip, ai_next); + return; + } + if (indirdep->ir_state & UFS1FMT) + ((ufs1_daddr_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] = + aip->ai_newblkno; + else + ((ufs2_daddr_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] = + aip->ai_newblkno; + /* + * Await the pointer write before freeing the allocindir. + */ + LIST_INSERT_HEAD(&indirdep->ir_writehd, aip, ai_next); +} + +/* + * Release segments held on a jwork list. + */ +static void +handle_jwork(wkhd) + struct workhead *wkhd; +{ + struct worklist *wk; + + while ((wk = LIST_FIRST(wkhd)) != NULL) { + WORKLIST_REMOVE(wk); + switch (wk->wk_type) { + case D_JSEGDEP: + free_jsegdep(WK_JSEGDEP(wk)); + continue; + case D_FREEDEP: + free_freedep(WK_FREEDEP(wk)); + continue; + case D_FREEFRAG: + rele_jseg(WK_JSEG(WK_FREEFRAG(wk)->ff_jdep)); + WORKITEM_FREE(wk, D_FREEFRAG); + continue; + case D_FREEWORK: + handle_written_freework(WK_FREEWORK(wk)); + continue; + default: + panic("handle_jwork: Unknown type %s\n", + TYPENAME(wk->wk_type)); + } + } +} + +/* + * Handle the bufwait list on an inode when it is safe to release items + * held there. This normally happens after an inode block is written but + * may be delayed and handled later if there are pending journal items that + * are not yet safe to be released. + */ +static struct freefile * +handle_bufwait(inodedep, refhd) + struct inodedep *inodedep; + struct workhead *refhd; +{ + struct jaddref *jaddref; + struct freefile *freefile; + struct worklist *wk; + + freefile = NULL; + while ((wk = LIST_FIRST(&inodedep->id_bufwait)) != NULL) { + WORKLIST_REMOVE(wk); + switch (wk->wk_type) { + case D_FREEFILE: + /* + * We defer adding freefile to the worklist + * until all other additions have been made to + * ensure that it will be done after all the + * old blocks have been freed. + */ + if (freefile != NULL) + panic("handle_bufwait: freefile"); + freefile = WK_FREEFILE(wk); + continue; + + case D_MKDIR: + handle_written_mkdir(WK_MKDIR(wk), MKDIR_PARENT); + continue; + + case D_DIRADD: + diradd_inode_written(WK_DIRADD(wk), inodedep); + continue; + + case D_FREEFRAG: + wk->wk_state |= COMPLETE; + if ((wk->wk_state & ALLCOMPLETE) == ALLCOMPLETE) + add_to_worklist(wk, 0); + continue; + + case D_DIRREM: + wk->wk_state |= COMPLETE; + add_to_worklist(wk, 0); + continue; + + case D_ALLOCDIRECT: + case D_ALLOCINDIR: + free_newblk(WK_NEWBLK(wk)); + continue; + + case D_JNEWBLK: + wk->wk_state |= COMPLETE; + free_jnewblk(WK_JNEWBLK(wk)); + continue; + + /* + * Save freed journal segments and add references on + * the supplied list which will delay their release + * until the cg bitmap is cleared on disk. + */ + case D_JSEGDEP: + if (refhd == NULL) + free_jsegdep(WK_JSEGDEP(wk)); + else + WORKLIST_INSERT(refhd, wk); + continue; + + case D_JADDREF: + jaddref = WK_JADDREF(wk); + TAILQ_REMOVE(&inodedep->id_inoreflst, &jaddref->ja_ref, + if_deps); + /* + * Transfer any jaddrefs to the list to be freed with + * the bitmap if we're handling a removed file. + */ + if (refhd == NULL) { + wk->wk_state |= COMPLETE; + free_jaddref(jaddref); + } else + WORKLIST_INSERT(refhd, wk); + continue; + + default: + panic("handle_bufwait: Unknown type %p(%s)", + wk, TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + } + return (freefile); +} +/* + * Called from within softdep_disk_write_complete above to restore + * in-memory inode block contents to their most up-to-date state. Note + * that this routine is always called from interrupt level with further + * interrupts from this device blocked. + * + * If the write did not succeed, we will do all the roll-forward + * operations, but we will not take the actions that will allow its + * dependencies to be processed. + */ +static int +handle_written_inodeblock(inodedep, bp, flags) + struct inodedep *inodedep; + struct buf *bp; /* buffer containing the inode block */ + int flags; +{ + struct freefile *freefile; + struct allocdirect *adp, *nextadp; + struct ufs1_dinode *dp1 = NULL; + struct ufs2_dinode *dp2 = NULL; + struct workhead wkhd; + int hadchanges, fstype; + ino_t freelink; + + LIST_INIT(&wkhd); + hadchanges = 0; + freefile = NULL; + if ((inodedep->id_state & IOSTARTED) == 0) + panic("handle_written_inodeblock: not started"); + inodedep->id_state &= ~IOSTARTED; + if (inodedep->id_fs->fs_magic == FS_UFS1_MAGIC) { + fstype = UFS1; + dp1 = (struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(inodedep->id_fs, inodedep->id_ino); + freelink = dp1->di_freelink; + } else { + fstype = UFS2; + dp2 = (struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(inodedep->id_fs, inodedep->id_ino); + freelink = dp2->di_freelink; + } + /* + * Leave this inodeblock dirty until it's in the list. + */ + if ((inodedep->id_state & (UNLINKED | UNLINKONLIST)) == UNLINKED && + (flags & WRITESUCCEEDED)) { + struct inodedep *inon; + + inon = TAILQ_NEXT(inodedep, id_unlinked); + if ((inon == NULL && freelink == 0) || + (inon && inon->id_ino == freelink)) { + if (inon) + inon->id_state |= UNLINKPREV; + inodedep->id_state |= UNLINKNEXT; + } + hadchanges = 1; + } + /* + * If we had to rollback the inode allocation because of + * bitmaps being incomplete, then simply restore it. + * Keep the block dirty so that it will not be reclaimed until + * all associated dependencies have been cleared and the + * corresponding updates written to disk. + */ + if (inodedep->id_savedino1 != NULL) { + hadchanges = 1; + if (fstype == UFS1) + *dp1 = *inodedep->id_savedino1; + else + *dp2 = *inodedep->id_savedino2; + free(inodedep->id_savedino1, M_SAVEDINO); + inodedep->id_savedino1 = NULL; + if ((bp->b_flags & B_DELWRI) == 0) + stat_inode_bitmap++; + bdirty(bp); + /* + * If the inode is clear here and GOINGAWAY it will never + * be written. Process the bufwait and clear any pending + * work which may include the freefile. + */ + if (inodedep->id_state & GOINGAWAY) + goto bufwait; + return (1); + } + if (flags & WRITESUCCEEDED) + inodedep->id_state |= COMPLETE; + /* + * Roll forward anything that had to be rolled back before + * the inode could be updated. + */ + for (adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; adp = nextadp) { + nextadp = TAILQ_NEXT(adp, ad_next); + if (adp->ad_state & ATTACHED) + panic("handle_written_inodeblock: new entry"); + if (fstype == UFS1) { + if (adp->ad_offset < NDADDR) { + if (dp1->di_db[adp->ad_offset]!=adp->ad_oldblkno) + panic("%s %s #%jd mismatch %d != %jd", + "handle_written_inodeblock:", + "direct pointer", + (intmax_t)adp->ad_offset, + dp1->di_db[adp->ad_offset], + (intmax_t)adp->ad_oldblkno); + dp1->di_db[adp->ad_offset] = adp->ad_newblkno; + } else { + if (dp1->di_ib[adp->ad_offset - NDADDR] != 0) + panic("%s: %s #%jd allocated as %d", + "handle_written_inodeblock", + "indirect pointer", + (intmax_t)adp->ad_offset - NDADDR, + dp1->di_ib[adp->ad_offset - NDADDR]); + dp1->di_ib[adp->ad_offset - NDADDR] = + adp->ad_newblkno; + } + } else { + if (adp->ad_offset < NDADDR) { + if (dp2->di_db[adp->ad_offset]!=adp->ad_oldblkno) + panic("%s: %s #%jd %s %jd != %jd", + "handle_written_inodeblock", + "direct pointer", + (intmax_t)adp->ad_offset, "mismatch", + (intmax_t)dp2->di_db[adp->ad_offset], + (intmax_t)adp->ad_oldblkno); + dp2->di_db[adp->ad_offset] = adp->ad_newblkno; + } else { + if (dp2->di_ib[adp->ad_offset - NDADDR] != 0) + panic("%s: %s #%jd allocated as %jd", + "handle_written_inodeblock", + "indirect pointer", + (intmax_t)adp->ad_offset - NDADDR, + (intmax_t) + dp2->di_ib[adp->ad_offset - NDADDR]); + dp2->di_ib[adp->ad_offset - NDADDR] = + adp->ad_newblkno; + } + } + adp->ad_state &= ~UNDONE; + adp->ad_state |= ATTACHED; + hadchanges = 1; + } + for (adp = TAILQ_FIRST(&inodedep->id_extupdt); adp; adp = nextadp) { + nextadp = TAILQ_NEXT(adp, ad_next); + if (adp->ad_state & ATTACHED) + panic("handle_written_inodeblock: new entry"); + if (dp2->di_extb[adp->ad_offset] != adp->ad_oldblkno) + panic("%s: direct pointers #%jd %s %jd != %jd", + "handle_written_inodeblock", + (intmax_t)adp->ad_offset, "mismatch", + (intmax_t)dp2->di_extb[adp->ad_offset], + (intmax_t)adp->ad_oldblkno); + dp2->di_extb[adp->ad_offset] = adp->ad_newblkno; + adp->ad_state &= ~UNDONE; + adp->ad_state |= ATTACHED; + hadchanges = 1; + } + if (hadchanges && (bp->b_flags & B_DELWRI) == 0) + stat_direct_blk_ptrs++; + /* + * Reset the file size to its most up-to-date value. + */ + if (inodedep->id_savedsize == -1 || inodedep->id_savedextsize == -1) + panic("handle_written_inodeblock: bad size"); + if (inodedep->id_savednlink > LINK_MAX) + panic("handle_written_inodeblock: Invalid link count " + "%jd for inodedep %p", (uintmax_t)inodedep->id_savednlink, + inodedep); + if (fstype == UFS1) { + if (dp1->di_nlink != inodedep->id_savednlink) { + dp1->di_nlink = inodedep->id_savednlink; + hadchanges = 1; + } + if (dp1->di_size != inodedep->id_savedsize) { + dp1->di_size = inodedep->id_savedsize; + hadchanges = 1; + } + } else { + if (dp2->di_nlink != inodedep->id_savednlink) { + dp2->di_nlink = inodedep->id_savednlink; + hadchanges = 1; + } + if (dp2->di_size != inodedep->id_savedsize) { + dp2->di_size = inodedep->id_savedsize; + hadchanges = 1; + } + if (dp2->di_extsize != inodedep->id_savedextsize) { + dp2->di_extsize = inodedep->id_savedextsize; + hadchanges = 1; + } + } + inodedep->id_savedsize = -1; + inodedep->id_savedextsize = -1; + inodedep->id_savednlink = -1; + /* + * If there were any rollbacks in the inode block, then it must be + * marked dirty so that its will eventually get written back in + * its correct form. + */ + if (hadchanges) + bdirty(bp); +bufwait: + /* + * If the write did not succeed, we have done all the roll-forward + * operations, but we cannot take the actions that will allow its + * dependencies to be processed. + */ + if ((flags & WRITESUCCEEDED) == 0) + return (hadchanges); + /* + * Process any allocdirects that completed during the update. + */ + if ((adp = TAILQ_FIRST(&inodedep->id_inoupdt)) != NULL) + handle_allocdirect_partdone(adp, &wkhd); + if ((adp = TAILQ_FIRST(&inodedep->id_extupdt)) != NULL) + handle_allocdirect_partdone(adp, &wkhd); + /* + * Process deallocations that were held pending until the + * inode had been written to disk. Freeing of the inode + * is delayed until after all blocks have been freed to + * avoid creation of new triples + * before the old ones have been deleted. Completely + * unlinked inodes are not processed until the unlinked + * inode list is written or the last reference is removed. + */ + if ((inodedep->id_state & (UNLINKED | UNLINKONLIST)) != UNLINKED) { + freefile = handle_bufwait(inodedep, NULL); + if (freefile && !LIST_EMPTY(&wkhd)) { + WORKLIST_INSERT(&wkhd, &freefile->fx_list); + freefile = NULL; + } + } + /* + * Move rolled forward dependency completions to the bufwait list + * now that those that were already written have been processed. + */ + if (!LIST_EMPTY(&wkhd) && hadchanges == 0) + panic("handle_written_inodeblock: bufwait but no changes"); + jwork_move(&inodedep->id_bufwait, &wkhd); + + if (freefile != NULL) { + /* + * If the inode is goingaway it was never written. Fake up + * the state here so free_inodedep() can succeed. + */ + if (inodedep->id_state & GOINGAWAY) + inodedep->id_state |= COMPLETE | DEPCOMPLETE; + if (free_inodedep(inodedep) == 0) + panic("handle_written_inodeblock: live inodedep %p", + inodedep); + add_to_worklist(&freefile->fx_list, 0); + return (0); + } + + /* + * If no outstanding dependencies, free it. + */ + if (free_inodedep(inodedep) || + (TAILQ_FIRST(&inodedep->id_inoreflst) == 0 && + TAILQ_FIRST(&inodedep->id_inoupdt) == 0 && + TAILQ_FIRST(&inodedep->id_extupdt) == 0 && + LIST_FIRST(&inodedep->id_bufwait) == 0)) + return (0); + return (hadchanges); +} + +/* + * Perform needed roll-forwards and kick off any dependencies that + * can now be processed. + * + * If the write did not succeed, we will do all the roll-forward + * operations, but we will not take the actions that will allow its + * dependencies to be processed. + */ +static int +handle_written_indirdep(indirdep, bp, bpp, flags) + struct indirdep *indirdep; + struct buf *bp; + struct buf **bpp; + int flags; +{ + struct allocindir *aip; + struct buf *sbp; + int chgs; + + if (indirdep->ir_state & GOINGAWAY) + panic("handle_written_indirdep: indirdep gone"); + if ((indirdep->ir_state & IOSTARTED) == 0) + panic("handle_written_indirdep: IO not started"); + chgs = 0; + /* + * If there were rollbacks revert them here. + */ + if (indirdep->ir_saveddata) { + bcopy(indirdep->ir_saveddata, bp->b_data, bp->b_bcount); + if (TAILQ_EMPTY(&indirdep->ir_trunc)) { + free(indirdep->ir_saveddata, M_INDIRDEP); + indirdep->ir_saveddata = NULL; + } + chgs = 1; + } + indirdep->ir_state &= ~(UNDONE | IOSTARTED); + indirdep->ir_state |= ATTACHED; + /* + * If the write did not succeed, we have done all the roll-forward + * operations, but we cannot take the actions that will allow its + * dependencies to be processed. + */ + if ((flags & WRITESUCCEEDED) == 0) { + stat_indir_blk_ptrs++; + bdirty(bp); + return (1); + } + /* + * Move allocindirs with written pointers to the completehd if + * the indirdep's pointer is not yet written. Otherwise + * free them here. + */ + while ((aip = LIST_FIRST(&indirdep->ir_writehd)) != NULL) { + LIST_REMOVE(aip, ai_next); + if ((indirdep->ir_state & DEPCOMPLETE) == 0) { + LIST_INSERT_HEAD(&indirdep->ir_completehd, aip, + ai_next); + newblk_freefrag(&aip->ai_block); + continue; + } + free_newblk(&aip->ai_block); + } + /* + * Move allocindirs that have finished dependency processing from + * the done list to the write list after updating the pointers. + */ + if (TAILQ_EMPTY(&indirdep->ir_trunc)) { + while ((aip = LIST_FIRST(&indirdep->ir_donehd)) != NULL) { + handle_allocindir_partdone(aip); + if (aip == LIST_FIRST(&indirdep->ir_donehd)) + panic("disk_write_complete: not gone"); + chgs = 1; + } + } + /* + * Preserve the indirdep if there were any changes or if it is not + * yet valid on disk. + */ + if (chgs) { + stat_indir_blk_ptrs++; + bdirty(bp); + return (1); + } + /* + * If there were no changes we can discard the savedbp and detach + * ourselves from the buf. We are only carrying completed pointers + * in this case. + */ + sbp = indirdep->ir_savebp; + sbp->b_flags |= B_INVAL | B_NOCACHE; + indirdep->ir_savebp = NULL; + indirdep->ir_bp = NULL; + if (*bpp != NULL) + panic("handle_written_indirdep: bp already exists."); + *bpp = sbp; + /* + * The indirdep may not be freed until its parent points at it. + */ + if (indirdep->ir_state & DEPCOMPLETE) + free_indirdep(indirdep); + + return (0); +} + +/* + * Process a diradd entry after its dependent inode has been written. + * This routine must be called with splbio interrupts blocked. + */ +static void +diradd_inode_written(dap, inodedep) + struct diradd *dap; + struct inodedep *inodedep; +{ + + dap->da_state |= COMPLETE; + complete_diradd(dap); + WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list); +} + +/* + * Returns true if the bmsafemap will have rollbacks when written. Must only + * be called with the per-filesystem lock and the buf lock on the cg held. + */ +static int +bmsafemap_backgroundwrite(bmsafemap, bp) + struct bmsafemap *bmsafemap; + struct buf *bp; +{ + int dirty; + + LOCK_OWNED(VFSTOUFS(bmsafemap->sm_list.wk_mp)); + dirty = !LIST_EMPTY(&bmsafemap->sm_jaddrefhd) | + !LIST_EMPTY(&bmsafemap->sm_jnewblkhd); + /* + * If we're initiating a background write we need to process the + * rollbacks as they exist now, not as they exist when IO starts. + * No other consumers will look at the contents of the shadowed + * buf so this is safe to do here. + */ + if (bp->b_xflags & BX_BKGRDMARKER) + initiate_write_bmsafemap(bmsafemap, bp); + + return (dirty); +} + +/* + * Re-apply an allocation when a cg write is complete. + */ +static int +jnewblk_rollforward(jnewblk, fs, cgp, blksfree) + struct jnewblk *jnewblk; + struct fs *fs; + struct cg *cgp; + uint8_t *blksfree; +{ + ufs1_daddr_t fragno; + ufs2_daddr_t blkno; + long cgbno, bbase; + int frags, blk; + int i; + + frags = 0; + cgbno = dtogd(fs, jnewblk->jn_blkno); + for (i = jnewblk->jn_oldfrags; i < jnewblk->jn_frags; i++) { + if (isclr(blksfree, cgbno + i)) + panic("jnewblk_rollforward: re-allocated fragment"); + frags++; + } + if (frags == fs->fs_frag) { + blkno = fragstoblks(fs, cgbno); + ffs_clrblock(fs, blksfree, (long)blkno); + ffs_clusteracct(fs, cgp, blkno, -1); + cgp->cg_cs.cs_nbfree--; + } else { + bbase = cgbno - fragnum(fs, cgbno); + cgbno += jnewblk->jn_oldfrags; + /* If a complete block had been reassembled, account for it. */ + fragno = fragstoblks(fs, bbase); + if (ffs_isblock(fs, blksfree, fragno)) { + cgp->cg_cs.cs_nffree += fs->fs_frag; + ffs_clusteracct(fs, cgp, fragno, -1); + cgp->cg_cs.cs_nbfree--; + } + /* Decrement the old frags. */ + blk = blkmap(fs, blksfree, bbase); + ffs_fragacct(fs, blk, cgp->cg_frsum, -1); + /* Allocate the fragment */ + for (i = 0; i < frags; i++) + clrbit(blksfree, cgbno + i); + cgp->cg_cs.cs_nffree -= frags; + /* Add back in counts associated with the new frags */ + blk = blkmap(fs, blksfree, bbase); + ffs_fragacct(fs, blk, cgp->cg_frsum, 1); + } + return (frags); +} + +/* + * Complete a write to a bmsafemap structure. Roll forward any bitmap + * changes if it's not a background write. Set all written dependencies + * to DEPCOMPLETE and free the structure if possible. + * + * If the write did not succeed, we will do all the roll-forward + * operations, but we will not take the actions that will allow its + * dependencies to be processed. + */ +static int +handle_written_bmsafemap(bmsafemap, bp, flags) + struct bmsafemap *bmsafemap; + struct buf *bp; + int flags; +{ + struct newblk *newblk; + struct inodedep *inodedep; + struct jaddref *jaddref, *jatmp; + struct jnewblk *jnewblk, *jntmp; + struct ufsmount *ump; + uint8_t *inosused; + uint8_t *blksfree; + struct cg *cgp; + struct fs *fs; + ino_t ino; + int foreground; + int chgs; + + if ((bmsafemap->sm_state & IOSTARTED) == 0) + panic("handle_written_bmsafemap: Not started\n"); + ump = VFSTOUFS(bmsafemap->sm_list.wk_mp); + chgs = 0; + bmsafemap->sm_state &= ~IOSTARTED; + foreground = (bp->b_xflags & BX_BKGRDMARKER) == 0; + /* + * If write was successful, release journal work that was waiting + * on the write. Otherwise move the work back. + */ + if (flags & WRITESUCCEEDED) + handle_jwork(&bmsafemap->sm_freewr); + else + LIST_CONCAT(&bmsafemap->sm_freehd, &bmsafemap->sm_freewr, + worklist, wk_list); + + /* + * Restore unwritten inode allocation pending jaddref writes. + */ + if (!LIST_EMPTY(&bmsafemap->sm_jaddrefhd)) { + cgp = (struct cg *)bp->b_data; + fs = VFSTOUFS(bmsafemap->sm_list.wk_mp)->um_fs; + inosused = cg_inosused(cgp); + LIST_FOREACH_SAFE(jaddref, &bmsafemap->sm_jaddrefhd, + ja_bmdeps, jatmp) { + if ((jaddref->ja_state & UNDONE) == 0) + continue; + ino = jaddref->ja_ino % fs->fs_ipg; + if (isset(inosused, ino)) + panic("handle_written_bmsafemap: " + "re-allocated inode"); + /* Do the roll-forward only if it's a real copy. */ + if (foreground) { + if ((jaddref->ja_mode & IFMT) == IFDIR) + cgp->cg_cs.cs_ndir++; + cgp->cg_cs.cs_nifree--; + setbit(inosused, ino); + chgs = 1; + } + jaddref->ja_state &= ~UNDONE; + jaddref->ja_state |= ATTACHED; + free_jaddref(jaddref); + } + } + /* + * Restore any block allocations which are pending journal writes. + */ + if (LIST_FIRST(&bmsafemap->sm_jnewblkhd) != NULL) { + cgp = (struct cg *)bp->b_data; + fs = VFSTOUFS(bmsafemap->sm_list.wk_mp)->um_fs; + blksfree = cg_blksfree(cgp); + LIST_FOREACH_SAFE(jnewblk, &bmsafemap->sm_jnewblkhd, jn_deps, + jntmp) { + if ((jnewblk->jn_state & UNDONE) == 0) + continue; + /* Do the roll-forward only if it's a real copy. */ + if (foreground && + jnewblk_rollforward(jnewblk, fs, cgp, blksfree)) + chgs = 1; + jnewblk->jn_state &= ~(UNDONE | NEWBLOCK); + jnewblk->jn_state |= ATTACHED; + free_jnewblk(jnewblk); + } + } + /* + * If the write did not succeed, we have done all the roll-forward + * operations, but we cannot take the actions that will allow its + * dependencies to be processed. + */ + if ((flags & WRITESUCCEEDED) == 0) { + LIST_CONCAT(&bmsafemap->sm_newblkhd, &bmsafemap->sm_newblkwr, + newblk, nb_deps); + LIST_CONCAT(&bmsafemap->sm_freehd, &bmsafemap->sm_freewr, + worklist, wk_list); + if (foreground) + bdirty(bp); + return (1); + } + while ((newblk = LIST_FIRST(&bmsafemap->sm_newblkwr))) { + newblk->nb_state |= DEPCOMPLETE; + newblk->nb_state &= ~ONDEPLIST; + newblk->nb_bmsafemap = NULL; + LIST_REMOVE(newblk, nb_deps); + if (newblk->nb_list.wk_type == D_ALLOCDIRECT) + handle_allocdirect_partdone( + WK_ALLOCDIRECT(&newblk->nb_list), NULL); + else if (newblk->nb_list.wk_type == D_ALLOCINDIR) + handle_allocindir_partdone( + WK_ALLOCINDIR(&newblk->nb_list)); + else if (newblk->nb_list.wk_type != D_NEWBLK) + panic("handle_written_bmsafemap: Unexpected type: %s", + TYPENAME(newblk->nb_list.wk_type)); + } + while ((inodedep = LIST_FIRST(&bmsafemap->sm_inodedepwr)) != NULL) { + inodedep->id_state |= DEPCOMPLETE; + inodedep->id_state &= ~ONDEPLIST; + LIST_REMOVE(inodedep, id_deps); + inodedep->id_bmsafemap = NULL; + } + LIST_REMOVE(bmsafemap, sm_next); + if (chgs == 0 && LIST_EMPTY(&bmsafemap->sm_jaddrefhd) && + LIST_EMPTY(&bmsafemap->sm_jnewblkhd) && + LIST_EMPTY(&bmsafemap->sm_newblkhd) && + LIST_EMPTY(&bmsafemap->sm_inodedephd) && + LIST_EMPTY(&bmsafemap->sm_freehd)) { + LIST_REMOVE(bmsafemap, sm_hash); + WORKITEM_FREE(bmsafemap, D_BMSAFEMAP); + return (0); + } + LIST_INSERT_HEAD(&ump->softdep_dirtycg, bmsafemap, sm_next); + if (foreground) + bdirty(bp); + return (1); +} + +/* + * Try to free a mkdir dependency. + */ +static void +complete_mkdir(mkdir) + struct mkdir *mkdir; +{ + struct diradd *dap; + + if ((mkdir->md_state & ALLCOMPLETE) != ALLCOMPLETE) + return; + LIST_REMOVE(mkdir, md_mkdirs); + dap = mkdir->md_diradd; + dap->da_state &= ~(mkdir->md_state & (MKDIR_PARENT | MKDIR_BODY)); + if ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) == 0) { + dap->da_state |= DEPCOMPLETE; + complete_diradd(dap); + } + WORKITEM_FREE(mkdir, D_MKDIR); +} + +/* + * Handle the completion of a mkdir dependency. + */ +static void +handle_written_mkdir(mkdir, type) + struct mkdir *mkdir; + int type; +{ + + if ((mkdir->md_state & (MKDIR_PARENT | MKDIR_BODY)) != type) + panic("handle_written_mkdir: bad type"); + mkdir->md_state |= COMPLETE; + complete_mkdir(mkdir); +} + +static int +free_pagedep(pagedep) + struct pagedep *pagedep; +{ + int i; + + if (pagedep->pd_state & NEWBLOCK) + return (0); + if (!LIST_EMPTY(&pagedep->pd_dirremhd)) + return (0); + for (i = 0; i < DAHASHSZ; i++) + if (!LIST_EMPTY(&pagedep->pd_diraddhd[i])) + return (0); + if (!LIST_EMPTY(&pagedep->pd_pendinghd)) + return (0); + if (!LIST_EMPTY(&pagedep->pd_jmvrefhd)) + return (0); + if (pagedep->pd_state & ONWORKLIST) + WORKLIST_REMOVE(&pagedep->pd_list); + LIST_REMOVE(pagedep, pd_hash); + WORKITEM_FREE(pagedep, D_PAGEDEP); + + return (1); +} + +/* + * Called from within softdep_disk_write_complete above. + * A write operation was just completed. Removed inodes can + * now be freed and associated block pointers may be committed. + * Note that this routine is always called from interrupt level + * with further interrupts from this device blocked. + * + * If the write did not succeed, we will do all the roll-forward + * operations, but we will not take the actions that will allow its + * dependencies to be processed. + */ +static int +handle_written_filepage(pagedep, bp, flags) + struct pagedep *pagedep; + struct buf *bp; /* buffer containing the written page */ + int flags; +{ + struct dirrem *dirrem; + struct diradd *dap, *nextdap; + struct direct *ep; + int i, chgs; + + if ((pagedep->pd_state & IOSTARTED) == 0) + panic("handle_written_filepage: not started"); + pagedep->pd_state &= ~IOSTARTED; + if ((flags & WRITESUCCEEDED) == 0) + goto rollforward; + /* + * Process any directory removals that have been committed. + */ + while ((dirrem = LIST_FIRST(&pagedep->pd_dirremhd)) != NULL) { + LIST_REMOVE(dirrem, dm_next); + dirrem->dm_state |= COMPLETE; + dirrem->dm_dirinum = pagedep->pd_ino; + KASSERT(LIST_EMPTY(&dirrem->dm_jremrefhd), + ("handle_written_filepage: Journal entries not written.")); + add_to_worklist(&dirrem->dm_list, 0); + } + /* + * Free any directory additions that have been committed. + * If it is a newly allocated block, we have to wait until + * the on-disk directory inode claims the new block. + */ + if ((pagedep->pd_state & NEWBLOCK) == 0) + while ((dap = LIST_FIRST(&pagedep->pd_pendinghd)) != NULL) + free_diradd(dap, NULL); +rollforward: + /* + * Uncommitted directory entries must be restored. + */ + for (chgs = 0, i = 0; i < DAHASHSZ; i++) { + for (dap = LIST_FIRST(&pagedep->pd_diraddhd[i]); dap; + dap = nextdap) { + nextdap = LIST_NEXT(dap, da_pdlist); + if (dap->da_state & ATTACHED) + panic("handle_written_filepage: attached"); + ep = (struct direct *) + ((char *)bp->b_data + dap->da_offset); + ep->d_ino = dap->da_newinum; + dap->da_state &= ~UNDONE; + dap->da_state |= ATTACHED; + chgs = 1; + /* + * If the inode referenced by the directory has + * been written out, then the dependency can be + * moved to the pending list. + */ + if ((dap->da_state & ALLCOMPLETE) == ALLCOMPLETE) { + LIST_REMOVE(dap, da_pdlist); + LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, + da_pdlist); + } + } + } + /* + * If there were any rollbacks in the directory, then it must be + * marked dirty so that its will eventually get written back in + * its correct form. + */ + if (chgs || (flags & WRITESUCCEEDED) == 0) { + if ((bp->b_flags & B_DELWRI) == 0) + stat_dir_entry++; + bdirty(bp); + return (1); + } + /* + * If we are not waiting for a new directory block to be + * claimed by its inode, then the pagedep will be freed. + * Otherwise it will remain to track any new entries on + * the page in case they are fsync'ed. + */ + free_pagedep(pagedep); + return (0); +} + +/* + * Writing back in-core inode structures. + * + * The filesystem only accesses an inode's contents when it occupies an + * "in-core" inode structure. These "in-core" structures are separate from + * the page frames used to cache inode blocks. Only the latter are + * transferred to/from the disk. So, when the updated contents of the + * "in-core" inode structure are copied to the corresponding in-memory inode + * block, the dependencies are also transferred. The following procedure is + * called when copying a dirty "in-core" inode to a cached inode block. + */ + +/* + * Called when an inode is loaded from disk. If the effective link count + * differed from the actual link count when it was last flushed, then we + * need to ensure that the correct effective link count is put back. + */ +void +softdep_load_inodeblock(ip) + struct inode *ip; /* the "in_core" copy of the inode */ +{ + struct inodedep *inodedep; + struct ufsmount *ump; + + ump = ITOUMP(ip); + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_load_inodeblock called on non-softdep filesystem")); + /* + * Check for alternate nlink count. + */ + ip->i_effnlink = ip->i_nlink; + ACQUIRE_LOCK(ump); + if (inodedep_lookup(UFSTOVFS(ump), ip->i_number, 0, &inodedep) == 0) { + FREE_LOCK(ump); + return; + } + ip->i_effnlink -= inodedep->id_nlinkdelta; + FREE_LOCK(ump); +} + +/* + * This routine is called just before the "in-core" inode + * information is to be copied to the in-memory inode block. + * Recall that an inode block contains several inodes. If + * the force flag is set, then the dependencies will be + * cleared so that the update can always be made. Note that + * the buffer is locked when this routine is called, so we + * will never be in the middle of writing the inode block + * to disk. + */ +void +softdep_update_inodeblock(ip, bp, waitfor) + struct inode *ip; /* the "in_core" copy of the inode */ + struct buf *bp; /* the buffer containing the inode block */ + int waitfor; /* nonzero => update must be allowed */ +{ + struct inodedep *inodedep; + struct inoref *inoref; + struct ufsmount *ump; + struct worklist *wk; + struct mount *mp; + struct buf *ibp; + struct fs *fs; + int error; + + ump = ITOUMP(ip); + mp = UFSTOVFS(ump); + KASSERT(MOUNTEDSOFTDEP(mp) != 0, + ("softdep_update_inodeblock called on non-softdep filesystem")); + fs = ump->um_fs; + /* + * Preserve the freelink that is on disk. clear_unlinked_inodedep() + * does not have access to the in-core ip so must write directly into + * the inode block buffer when setting freelink. + */ + if (fs->fs_magic == FS_UFS1_MAGIC) + DIP_SET(ip, i_freelink, ((struct ufs1_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number))->di_freelink); + else + DIP_SET(ip, i_freelink, ((struct ufs2_dinode *)bp->b_data + + ino_to_fsbo(fs, ip->i_number))->di_freelink); + /* + * If the effective link count is not equal to the actual link + * count, then we must track the difference in an inodedep while + * the inode is (potentially) tossed out of the cache. Otherwise, + * if there is no existing inodedep, then there are no dependencies + * to track. + */ + ACQUIRE_LOCK(ump); +again: + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) == 0) { + FREE_LOCK(ump); + if (ip->i_effnlink != ip->i_nlink) + panic("softdep_update_inodeblock: bad link count"); + return; + } + if (inodedep->id_nlinkdelta != ip->i_nlink - ip->i_effnlink) + panic("softdep_update_inodeblock: bad delta"); + /* + * If we're flushing all dependencies we must also move any waiting + * for journal writes onto the bufwait list prior to I/O. + */ + if (waitfor) { + TAILQ_FOREACH(inoref, &inodedep->id_inoreflst, if_deps) { + if ((inoref->if_state & (DEPCOMPLETE | GOINGAWAY)) + == DEPCOMPLETE) { + jwait(&inoref->if_list, MNT_WAIT); + goto again; + } + } + } + /* + * Changes have been initiated. Anything depending on these + * changes cannot occur until this inode has been written. + */ + inodedep->id_state &= ~COMPLETE; + if ((inodedep->id_state & ONWORKLIST) == 0) + WORKLIST_INSERT(&bp->b_dep, &inodedep->id_list); + /* + * Any new dependencies associated with the incore inode must + * now be moved to the list associated with the buffer holding + * the in-memory copy of the inode. Once merged process any + * allocdirects that are completed by the merger. + */ + merge_inode_lists(&inodedep->id_newinoupdt, &inodedep->id_inoupdt); + if (!TAILQ_EMPTY(&inodedep->id_inoupdt)) + handle_allocdirect_partdone(TAILQ_FIRST(&inodedep->id_inoupdt), + NULL); + merge_inode_lists(&inodedep->id_newextupdt, &inodedep->id_extupdt); + if (!TAILQ_EMPTY(&inodedep->id_extupdt)) + handle_allocdirect_partdone(TAILQ_FIRST(&inodedep->id_extupdt), + NULL); + /* + * Now that the inode has been pushed into the buffer, the + * operations dependent on the inode being written to disk + * can be moved to the id_bufwait so that they will be + * processed when the buffer I/O completes. + */ + while ((wk = LIST_FIRST(&inodedep->id_inowait)) != NULL) { + WORKLIST_REMOVE(wk); + WORKLIST_INSERT(&inodedep->id_bufwait, wk); + } + /* + * Newly allocated inodes cannot be written until the bitmap + * that allocates them have been written (indicated by + * DEPCOMPLETE being set in id_state). If we are doing a + * forced sync (e.g., an fsync on a file), we force the bitmap + * to be written so that the update can be done. + */ + if (waitfor == 0) { + FREE_LOCK(ump); + return; + } +retry: + if ((inodedep->id_state & (DEPCOMPLETE | GOINGAWAY)) != 0) { + FREE_LOCK(ump); + return; + } + ibp = inodedep->id_bmsafemap->sm_buf; + ibp = getdirtybuf(ibp, LOCK_PTR(ump), MNT_WAIT); + if (ibp == NULL) { + /* + * If ibp came back as NULL, the dependency could have been + * freed while we slept. Look it up again, and check to see + * that it has completed. + */ + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) != 0) + goto retry; + FREE_LOCK(ump); + return; + } + FREE_LOCK(ump); + if ((error = bwrite(ibp)) != 0) + softdep_error("softdep_update_inodeblock: bwrite", error); +} + +/* + * Merge the a new inode dependency list (such as id_newinoupdt) into an + * old inode dependency list (such as id_inoupdt). This routine must be + * called with splbio interrupts blocked. + */ +static void +merge_inode_lists(newlisthead, oldlisthead) + struct allocdirectlst *newlisthead; + struct allocdirectlst *oldlisthead; +{ + struct allocdirect *listadp, *newadp; + + newadp = TAILQ_FIRST(newlisthead); + for (listadp = TAILQ_FIRST(oldlisthead); listadp && newadp;) { + if (listadp->ad_offset < newadp->ad_offset) { + listadp = TAILQ_NEXT(listadp, ad_next); + continue; + } + TAILQ_REMOVE(newlisthead, newadp, ad_next); + TAILQ_INSERT_BEFORE(listadp, newadp, ad_next); + if (listadp->ad_offset == newadp->ad_offset) { + allocdirect_merge(oldlisthead, newadp, + listadp); + listadp = newadp; + } + newadp = TAILQ_FIRST(newlisthead); + } + while ((newadp = TAILQ_FIRST(newlisthead)) != NULL) { + TAILQ_REMOVE(newlisthead, newadp, ad_next); + TAILQ_INSERT_TAIL(oldlisthead, newadp, ad_next); + } +} + +/* + * If we are doing an fsync, then we must ensure that any directory + * entries for the inode have been written after the inode gets to disk. + */ +int +softdep_fsync(vp) + struct vnode *vp; /* the "in_core" copy of the inode */ +{ + struct inodedep *inodedep; + struct pagedep *pagedep; + struct inoref *inoref; + struct ufsmount *ump; + struct worklist *wk; + struct diradd *dap; + struct mount *mp; + struct vnode *pvp; + struct inode *ip; + struct buf *bp; + struct fs *fs; + struct thread *td = curthread; + int error, flushparent, pagedep_new_block; + ino_t parentino; + ufs_lbn_t lbn; + + ip = VTOI(vp); + mp = vp->v_mount; + ump = VFSTOUFS(mp); + fs = ump->um_fs; + if (MOUNTEDSOFTDEP(mp) == 0) + return (0); + ACQUIRE_LOCK(ump); +restart: + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) == 0) { + FREE_LOCK(ump); + return (0); + } + TAILQ_FOREACH(inoref, &inodedep->id_inoreflst, if_deps) { + if ((inoref->if_state & (DEPCOMPLETE | GOINGAWAY)) + == DEPCOMPLETE) { + jwait(&inoref->if_list, MNT_WAIT); + goto restart; + } + } + if (!LIST_EMPTY(&inodedep->id_inowait) || + !TAILQ_EMPTY(&inodedep->id_extupdt) || + !TAILQ_EMPTY(&inodedep->id_newextupdt) || + !TAILQ_EMPTY(&inodedep->id_inoupdt) || + !TAILQ_EMPTY(&inodedep->id_newinoupdt)) + panic("softdep_fsync: pending ops %p", inodedep); + for (error = 0, flushparent = 0; ; ) { + if ((wk = LIST_FIRST(&inodedep->id_pendinghd)) == NULL) + break; + if (wk->wk_type != D_DIRADD) + panic("softdep_fsync: Unexpected type %s", + TYPENAME(wk->wk_type)); + dap = WK_DIRADD(wk); + /* + * Flush our parent if this directory entry has a MKDIR_PARENT + * dependency or is contained in a newly allocated block. + */ + if (dap->da_state & DIRCHG) + pagedep = dap->da_previous->dm_pagedep; + else + pagedep = dap->da_pagedep; + parentino = pagedep->pd_ino; + lbn = pagedep->pd_lbn; + if ((dap->da_state & (MKDIR_BODY | COMPLETE)) != COMPLETE) + panic("softdep_fsync: dirty"); + if ((dap->da_state & MKDIR_PARENT) || + (pagedep->pd_state & NEWBLOCK)) + flushparent = 1; + else + flushparent = 0; + /* + * If we are being fsync'ed as part of vgone'ing this vnode, + * then we will not be able to release and recover the + * vnode below, so we just have to give up on writing its + * directory entry out. It will eventually be written, just + * not now, but then the user was not asking to have it + * written, so we are not breaking any promises. + */ + if (vp->v_iflag & VI_DOOMED) + break; + /* + * We prevent deadlock by always fetching inodes from the + * root, moving down the directory tree. Thus, when fetching + * our parent directory, we first try to get the lock. If + * that fails, we must unlock ourselves before requesting + * the lock on our parent. See the comment in ufs_lookup + * for details on possible races. + */ + FREE_LOCK(ump); + if (ffs_vgetf(mp, parentino, LK_NOWAIT | LK_EXCLUSIVE, &pvp, + FFSV_FORCEINSMQ)) { + error = vfs_busy(mp, MBF_NOWAIT); + if (error != 0) { + vfs_ref(mp); + VOP_UNLOCK(vp, 0); + error = vfs_busy(mp, 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + vfs_rel(mp); + if (error != 0) + return (ENOENT); + if (vp->v_iflag & VI_DOOMED) { + vfs_unbusy(mp); + return (ENOENT); + } + } + VOP_UNLOCK(vp, 0); + error = ffs_vgetf(mp, parentino, LK_EXCLUSIVE, + &pvp, FFSV_FORCEINSMQ); + vfs_unbusy(mp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + if (vp->v_iflag & VI_DOOMED) { + if (error == 0) + vput(pvp); + error = ENOENT; + } + if (error != 0) + return (error); + } + /* + * All MKDIR_PARENT dependencies and all the NEWBLOCK pagedeps + * that are contained in direct blocks will be resolved by + * doing a ffs_update. Pagedeps contained in indirect blocks + * may require a complete sync'ing of the directory. So, we + * try the cheap and fast ffs_update first, and if that fails, + * then we do the slower ffs_syncvnode of the directory. + */ + if (flushparent) { + int locked; + + if ((error = ffs_update(pvp, 1)) != 0) { + vput(pvp); + return (error); + } + ACQUIRE_LOCK(ump); + locked = 1; + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) != 0) { + if ((wk = LIST_FIRST(&inodedep->id_pendinghd)) != NULL) { + if (wk->wk_type != D_DIRADD) + panic("softdep_fsync: Unexpected type %s", + TYPENAME(wk->wk_type)); + dap = WK_DIRADD(wk); + if (dap->da_state & DIRCHG) + pagedep = dap->da_previous->dm_pagedep; + else + pagedep = dap->da_pagedep; + pagedep_new_block = pagedep->pd_state & NEWBLOCK; + FREE_LOCK(ump); + locked = 0; + if (pagedep_new_block && (error = + ffs_syncvnode(pvp, MNT_WAIT, 0))) { + vput(pvp); + return (error); + } + } + } + if (locked) + FREE_LOCK(ump); + } + /* + * Flush directory page containing the inode's name. + */ + error = bread(pvp, lbn, blksize(fs, VTOI(pvp), lbn), td->td_ucred, + &bp); + if (error == 0) + error = bwrite(bp); + else + brelse(bp); + vput(pvp); + if (error != 0) + return (error); + ACQUIRE_LOCK(ump); + if (inodedep_lookup(mp, ip->i_number, 0, &inodedep) == 0) + break; + } + FREE_LOCK(ump); + return (0); +} + +/* + * Flush all the dirty bitmaps associated with the block device + * before flushing the rest of the dirty blocks so as to reduce + * the number of dependencies that will have to be rolled back. + * + * XXX Unused? + */ +void +softdep_fsync_mountdev(vp) + struct vnode *vp; +{ + struct buf *bp, *nbp; + struct worklist *wk; + struct bufobj *bo; + + if (!vn_isdisk(vp, NULL)) + panic("softdep_fsync_mountdev: vnode not a disk"); + bo = &vp->v_bufobj; +restart: + BO_LOCK(bo); + TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { + /* + * If it is already scheduled, skip to the next buffer. + */ + if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) + continue; + + if ((bp->b_flags & B_DELWRI) == 0) + panic("softdep_fsync_mountdev: not dirty"); + /* + * We are only interested in bitmaps with outstanding + * dependencies. + */ + if ((wk = LIST_FIRST(&bp->b_dep)) == NULL || + wk->wk_type != D_BMSAFEMAP || + (bp->b_vflags & BV_BKGRDINPROG)) { + BUF_UNLOCK(bp); + continue; + } + BO_UNLOCK(bo); + bremfree(bp); + (void) bawrite(bp); + goto restart; + } + drain_output(vp); + BO_UNLOCK(bo); +} + +/* + * Sync all cylinder groups that were dirty at the time this function is + * called. Newly dirtied cgs will be inserted before the sentinel. This + * is used to flush freedep activity that may be holding up writes to a + * indirect block. + */ +static int +sync_cgs(mp, waitfor) + struct mount *mp; + int waitfor; +{ + struct bmsafemap *bmsafemap; + struct bmsafemap *sentinel; + struct ufsmount *ump; + struct buf *bp; + int error; + + sentinel = malloc(sizeof(*sentinel), M_BMSAFEMAP, M_ZERO | M_WAITOK); + sentinel->sm_cg = -1; + ump = VFSTOUFS(mp); + error = 0; + ACQUIRE_LOCK(ump); + LIST_INSERT_HEAD(&ump->softdep_dirtycg, sentinel, sm_next); + for (bmsafemap = LIST_NEXT(sentinel, sm_next); bmsafemap != NULL; + bmsafemap = LIST_NEXT(sentinel, sm_next)) { + /* Skip sentinels and cgs with no work to release. */ + if (bmsafemap->sm_cg == -1 || + (LIST_EMPTY(&bmsafemap->sm_freehd) && + LIST_EMPTY(&bmsafemap->sm_freewr))) { + LIST_REMOVE(sentinel, sm_next); + LIST_INSERT_AFTER(bmsafemap, sentinel, sm_next); + continue; + } + /* + * If we don't get the lock and we're waiting try again, if + * not move on to the next buf and try to sync it. + */ + bp = getdirtybuf(bmsafemap->sm_buf, LOCK_PTR(ump), waitfor); + if (bp == NULL && waitfor == MNT_WAIT) + continue; + LIST_REMOVE(sentinel, sm_next); + LIST_INSERT_AFTER(bmsafemap, sentinel, sm_next); + if (bp == NULL) + continue; + FREE_LOCK(ump); + if (waitfor == MNT_NOWAIT) + bawrite(bp); + else + error = bwrite(bp); + ACQUIRE_LOCK(ump); + if (error) + break; + } + LIST_REMOVE(sentinel, sm_next); + FREE_LOCK(ump); + free(sentinel, M_BMSAFEMAP); + return (error); +} + +/* + * This routine is called when we are trying to synchronously flush a + * file. This routine must eliminate any filesystem metadata dependencies + * so that the syncing routine can succeed. + */ +int +softdep_sync_metadata(struct vnode *vp) +{ + struct inode *ip; + int error; + + ip = VTOI(vp); + KASSERT(MOUNTEDSOFTDEP(vp->v_mount) != 0, + ("softdep_sync_metadata called on non-softdep filesystem")); + /* + * Ensure that any direct block dependencies have been cleared, + * truncations are started, and inode references are journaled. + */ + ACQUIRE_LOCK(VFSTOUFS(vp->v_mount)); + /* + * Write all journal records to prevent rollbacks on devvp. + */ + if (vp->v_type == VCHR) + softdep_flushjournal(vp->v_mount); + error = flush_inodedep_deps(vp, vp->v_mount, ip->i_number); + /* + * Ensure that all truncates are written so we won't find deps on + * indirect blocks. + */ + process_truncates(vp); + FREE_LOCK(VFSTOUFS(vp->v_mount)); + + return (error); +} + +/* + * This routine is called when we are attempting to sync a buf with + * dependencies. If waitfor is MNT_NOWAIT it attempts to schedule any + * other IO it can but returns EBUSY if the buffer is not yet able to + * be written. Dependencies which will not cause rollbacks will always + * return 0. + */ +int +softdep_sync_buf(struct vnode *vp, struct buf *bp, int waitfor) +{ + struct indirdep *indirdep; + struct pagedep *pagedep; + struct allocindir *aip; + struct newblk *newblk; + struct ufsmount *ump; + struct buf *nbp; + struct worklist *wk; + int i, error; + + KASSERT(MOUNTEDSOFTDEP(vp->v_mount) != 0, + ("softdep_sync_buf called on non-softdep filesystem")); + /* + * For VCHR we just don't want to force flush any dependencies that + * will cause rollbacks. + */ + if (vp->v_type == VCHR) { + if (waitfor == MNT_NOWAIT && softdep_count_dependencies(bp, 0)) + return (EBUSY); + return (0); + } + ump = VFSTOUFS(vp->v_mount); + ACQUIRE_LOCK(ump); + /* + * As we hold the buffer locked, none of its dependencies + * will disappear. + */ + error = 0; +top: + LIST_FOREACH(wk, &bp->b_dep, wk_list) { + switch (wk->wk_type) { + + case D_ALLOCDIRECT: + case D_ALLOCINDIR: + newblk = WK_NEWBLK(wk); + if (newblk->nb_jnewblk != NULL) { + if (waitfor == MNT_NOWAIT) { + error = EBUSY; + goto out_unlock; + } + jwait(&newblk->nb_jnewblk->jn_list, waitfor); + goto top; + } + if (newblk->nb_state & DEPCOMPLETE || + waitfor == MNT_NOWAIT) + continue; + nbp = newblk->nb_bmsafemap->sm_buf; + nbp = getdirtybuf(nbp, LOCK_PTR(ump), waitfor); + if (nbp == NULL) + goto top; + FREE_LOCK(ump); + if ((error = bwrite(nbp)) != 0) + goto out; + ACQUIRE_LOCK(ump); + continue; + + case D_INDIRDEP: + indirdep = WK_INDIRDEP(wk); + if (waitfor == MNT_NOWAIT) { + if (!TAILQ_EMPTY(&indirdep->ir_trunc) || + !LIST_EMPTY(&indirdep->ir_deplisthd)) { + error = EBUSY; + goto out_unlock; + } + } + if (!TAILQ_EMPTY(&indirdep->ir_trunc)) + panic("softdep_sync_buf: truncation pending."); + restart: + LIST_FOREACH(aip, &indirdep->ir_deplisthd, ai_next) { + newblk = (struct newblk *)aip; + if (newblk->nb_jnewblk != NULL) { + jwait(&newblk->nb_jnewblk->jn_list, + waitfor); + goto restart; + } + if (newblk->nb_state & DEPCOMPLETE) + continue; + nbp = newblk->nb_bmsafemap->sm_buf; + nbp = getdirtybuf(nbp, LOCK_PTR(ump), waitfor); + if (nbp == NULL) + goto restart; + FREE_LOCK(ump); + if ((error = bwrite(nbp)) != 0) + goto out; + ACQUIRE_LOCK(ump); + goto restart; + } + continue; + + case D_PAGEDEP: + /* + * Only flush directory entries in synchronous passes. + */ + if (waitfor != MNT_WAIT) { + error = EBUSY; + goto out_unlock; + } + /* + * While syncing snapshots, we must allow recursive + * lookups. + */ + BUF_AREC(bp); + /* + * We are trying to sync a directory that may + * have dependencies on both its own metadata + * and/or dependencies on the inodes of any + * recently allocated files. We walk its diradd + * lists pushing out the associated inode. + */ + pagedep = WK_PAGEDEP(wk); + for (i = 0; i < DAHASHSZ; i++) { + if (LIST_FIRST(&pagedep->pd_diraddhd[i]) == 0) + continue; + if ((error = flush_pagedep_deps(vp, wk->wk_mp, + &pagedep->pd_diraddhd[i]))) { + BUF_NOREC(bp); + goto out_unlock; + } + } + BUF_NOREC(bp); + continue; + + case D_FREEWORK: + case D_FREEDEP: + case D_JSEGDEP: + case D_JNEWBLK: + continue; + + default: + panic("softdep_sync_buf: Unknown type %s", + TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + } +out_unlock: + FREE_LOCK(ump); +out: + return (error); +} + +/* + * Flush the dependencies associated with an inodedep. + * Called with splbio blocked. + */ +static int +flush_inodedep_deps(vp, mp, ino) + struct vnode *vp; + struct mount *mp; + ino_t ino; +{ + struct inodedep *inodedep; + struct inoref *inoref; + struct ufsmount *ump; + int error, waitfor; + + /* + * This work is done in two passes. The first pass grabs most + * of the buffers and begins asynchronously writing them. The + * only way to wait for these asynchronous writes is to sleep + * on the filesystem vnode which may stay busy for a long time + * if the filesystem is active. So, instead, we make a second + * pass over the dependencies blocking on each write. In the + * usual case we will be blocking against a write that we + * initiated, so when it is done the dependency will have been + * resolved. Thus the second pass is expected to end quickly. + * We give a brief window at the top of the loop to allow + * any pending I/O to complete. + */ + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + for (error = 0, waitfor = MNT_NOWAIT; ; ) { + if (error) + return (error); + FREE_LOCK(ump); + ACQUIRE_LOCK(ump); +restart: + if (inodedep_lookup(mp, ino, 0, &inodedep) == 0) + return (0); + TAILQ_FOREACH(inoref, &inodedep->id_inoreflst, if_deps) { + if ((inoref->if_state & (DEPCOMPLETE | GOINGAWAY)) + == DEPCOMPLETE) { + jwait(&inoref->if_list, MNT_WAIT); + goto restart; + } + } + if (flush_deplist(&inodedep->id_inoupdt, waitfor, &error) || + flush_deplist(&inodedep->id_newinoupdt, waitfor, &error) || + flush_deplist(&inodedep->id_extupdt, waitfor, &error) || + flush_deplist(&inodedep->id_newextupdt, waitfor, &error)) + continue; + /* + * If pass2, we are done, otherwise do pass 2. + */ + if (waitfor == MNT_WAIT) + break; + waitfor = MNT_WAIT; + } + /* + * Try freeing inodedep in case all dependencies have been removed. + */ + if (inodedep_lookup(mp, ino, 0, &inodedep) != 0) + (void) free_inodedep(inodedep); + return (0); +} + +/* + * Flush an inode dependency list. + * Called with splbio blocked. + */ +static int +flush_deplist(listhead, waitfor, errorp) + struct allocdirectlst *listhead; + int waitfor; + int *errorp; +{ + struct allocdirect *adp; + struct newblk *newblk; + struct ufsmount *ump; + struct buf *bp; + + if ((adp = TAILQ_FIRST(listhead)) == NULL) + return (0); + ump = VFSTOUFS(adp->ad_list.wk_mp); + LOCK_OWNED(ump); + TAILQ_FOREACH(adp, listhead, ad_next) { + newblk = (struct newblk *)adp; + if (newblk->nb_jnewblk != NULL) { + jwait(&newblk->nb_jnewblk->jn_list, MNT_WAIT); + return (1); + } + if (newblk->nb_state & DEPCOMPLETE) + continue; + bp = newblk->nb_bmsafemap->sm_buf; + bp = getdirtybuf(bp, LOCK_PTR(ump), waitfor); + if (bp == NULL) { + if (waitfor == MNT_NOWAIT) + continue; + return (1); + } + FREE_LOCK(ump); + if (waitfor == MNT_NOWAIT) + bawrite(bp); + else + *errorp = bwrite(bp); + ACQUIRE_LOCK(ump); + return (1); + } + return (0); +} + +/* + * Flush dependencies associated with an allocdirect block. + */ +static int +flush_newblk_dep(vp, mp, lbn) + struct vnode *vp; + struct mount *mp; + ufs_lbn_t lbn; +{ + struct newblk *newblk; + struct ufsmount *ump; + struct bufobj *bo; + struct inode *ip; + struct buf *bp; + ufs2_daddr_t blkno; + int error; + + error = 0; + bo = &vp->v_bufobj; + ip = VTOI(vp); + blkno = DIP(ip, i_db[lbn]); + if (blkno == 0) + panic("flush_newblk_dep: Missing block"); + ump = VFSTOUFS(mp); + ACQUIRE_LOCK(ump); + /* + * Loop until all dependencies related to this block are satisfied. + * We must be careful to restart after each sleep in case a write + * completes some part of this process for us. + */ + for (;;) { + if (newblk_lookup(mp, blkno, 0, &newblk) == 0) { + FREE_LOCK(ump); + break; + } + if (newblk->nb_list.wk_type != D_ALLOCDIRECT) + panic("flush_newblk_deps: Bad newblk %p", newblk); + /* + * Flush the journal. + */ + if (newblk->nb_jnewblk != NULL) { + jwait(&newblk->nb_jnewblk->jn_list, MNT_WAIT); + continue; + } + /* + * Write the bitmap dependency. + */ + if ((newblk->nb_state & DEPCOMPLETE) == 0) { + bp = newblk->nb_bmsafemap->sm_buf; + bp = getdirtybuf(bp, LOCK_PTR(ump), MNT_WAIT); + if (bp == NULL) + continue; + FREE_LOCK(ump); + error = bwrite(bp); + if (error) + break; + ACQUIRE_LOCK(ump); + continue; + } + /* + * Write the buffer. + */ + FREE_LOCK(ump); + BO_LOCK(bo); + bp = gbincore(bo, lbn); + if (bp != NULL) { + error = BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL | + LK_INTERLOCK, BO_LOCKPTR(bo)); + if (error == ENOLCK) { + ACQUIRE_LOCK(ump); + error = 0; + continue; /* Slept, retry */ + } + if (error != 0) + break; /* Failed */ + if (bp->b_flags & B_DELWRI) { + bremfree(bp); + error = bwrite(bp); + if (error) + break; + } else + BUF_UNLOCK(bp); + } else + BO_UNLOCK(bo); + /* + * We have to wait for the direct pointers to + * point at the newdirblk before the dependency + * will go away. + */ + error = ffs_update(vp, 1); + if (error) + break; + ACQUIRE_LOCK(ump); + } + return (error); +} + +/* + * Eliminate a pagedep dependency by flushing out all its diradd dependencies. + * Called with splbio blocked. + */ +static int +flush_pagedep_deps(pvp, mp, diraddhdp) + struct vnode *pvp; + struct mount *mp; + struct diraddhd *diraddhdp; +{ + struct inodedep *inodedep; + struct inoref *inoref; + struct ufsmount *ump; + struct diradd *dap; + struct vnode *vp; + int error = 0; + struct buf *bp; + ino_t inum; + struct diraddhd unfinished; + + LIST_INIT(&unfinished); + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); +restart: + while ((dap = LIST_FIRST(diraddhdp)) != NULL) { + /* + * Flush ourselves if this directory entry + * has a MKDIR_PARENT dependency. + */ + if (dap->da_state & MKDIR_PARENT) { + FREE_LOCK(ump); + if ((error = ffs_update(pvp, 1)) != 0) + break; + ACQUIRE_LOCK(ump); + /* + * If that cleared dependencies, go on to next. + */ + if (dap != LIST_FIRST(diraddhdp)) + continue; + /* + * All MKDIR_PARENT dependencies and all the + * NEWBLOCK pagedeps that are contained in direct + * blocks were resolved by doing above ffs_update. + * Pagedeps contained in indirect blocks may + * require a complete sync'ing of the directory. + * We are in the midst of doing a complete sync, + * so if they are not resolved in this pass we + * defer them for now as they will be sync'ed by + * our caller shortly. + */ + LIST_REMOVE(dap, da_pdlist); + LIST_INSERT_HEAD(&unfinished, dap, da_pdlist); + continue; + } + /* + * A newly allocated directory must have its "." and + * ".." entries written out before its name can be + * committed in its parent. + */ + inum = dap->da_newinum; + if (inodedep_lookup(UFSTOVFS(ump), inum, 0, &inodedep) == 0) + panic("flush_pagedep_deps: lost inode1"); + /* + * Wait for any pending journal adds to complete so we don't + * cause rollbacks while syncing. + */ + TAILQ_FOREACH(inoref, &inodedep->id_inoreflst, if_deps) { + if ((inoref->if_state & (DEPCOMPLETE | GOINGAWAY)) + == DEPCOMPLETE) { + jwait(&inoref->if_list, MNT_WAIT); + goto restart; + } + } + if (dap->da_state & MKDIR_BODY) { + FREE_LOCK(ump); + if ((error = ffs_vgetf(mp, inum, LK_EXCLUSIVE, &vp, + FFSV_FORCEINSMQ))) + break; + error = flush_newblk_dep(vp, mp, 0); + /* + * If we still have the dependency we might need to + * update the vnode to sync the new link count to + * disk. + */ + if (error == 0 && dap == LIST_FIRST(diraddhdp)) + error = ffs_update(vp, 1); + vput(vp); + if (error != 0) + break; + ACQUIRE_LOCK(ump); + /* + * If that cleared dependencies, go on to next. + */ + if (dap != LIST_FIRST(diraddhdp)) + continue; + if (dap->da_state & MKDIR_BODY) { + inodedep_lookup(UFSTOVFS(ump), inum, 0, + &inodedep); + panic("flush_pagedep_deps: MKDIR_BODY " + "inodedep %p dap %p vp %p", + inodedep, dap, vp); + } + } + /* + * Flush the inode on which the directory entry depends. + * Having accounted for MKDIR_PARENT and MKDIR_BODY above, + * the only remaining dependency is that the updated inode + * count must get pushed to disk. The inode has already + * been pushed into its inode buffer (via VOP_UPDATE) at + * the time of the reference count change. So we need only + * locate that buffer, ensure that there will be no rollback + * caused by a bitmap dependency, then write the inode buffer. + */ +retry: + if (inodedep_lookup(UFSTOVFS(ump), inum, 0, &inodedep) == 0) + panic("flush_pagedep_deps: lost inode"); + /* + * If the inode still has bitmap dependencies, + * push them to disk. + */ + if ((inodedep->id_state & (DEPCOMPLETE | GOINGAWAY)) == 0) { + bp = inodedep->id_bmsafemap->sm_buf; + bp = getdirtybuf(bp, LOCK_PTR(ump), MNT_WAIT); + if (bp == NULL) + goto retry; + FREE_LOCK(ump); + if ((error = bwrite(bp)) != 0) + break; + ACQUIRE_LOCK(ump); + if (dap != LIST_FIRST(diraddhdp)) + continue; + } + /* + * If the inode is still sitting in a buffer waiting + * to be written or waiting for the link count to be + * adjusted update it here to flush it to disk. + */ + if (dap == LIST_FIRST(diraddhdp)) { + FREE_LOCK(ump); + if ((error = ffs_vgetf(mp, inum, LK_EXCLUSIVE, &vp, + FFSV_FORCEINSMQ))) + break; + error = ffs_update(vp, 1); + vput(vp); + if (error) + break; + ACQUIRE_LOCK(ump); + } + /* + * If we have failed to get rid of all the dependencies + * then something is seriously wrong. + */ + if (dap == LIST_FIRST(diraddhdp)) { + inodedep_lookup(UFSTOVFS(ump), inum, 0, &inodedep); + panic("flush_pagedep_deps: failed to flush " + "inodedep %p ino %ju dap %p", + inodedep, (uintmax_t)inum, dap); + } + } + if (error) + ACQUIRE_LOCK(ump); + while ((dap = LIST_FIRST(&unfinished)) != NULL) { + LIST_REMOVE(dap, da_pdlist); + LIST_INSERT_HEAD(diraddhdp, dap, da_pdlist); + } + return (error); +} + +/* + * A large burst of file addition or deletion activity can drive the + * memory load excessively high. First attempt to slow things down + * using the techniques below. If that fails, this routine requests + * the offending operations to fall back to running synchronously + * until the memory load returns to a reasonable level. + */ +int +softdep_slowdown(vp) + struct vnode *vp; +{ + struct ufsmount *ump; + int jlow; + int max_softdeps_hard; + + KASSERT(MOUNTEDSOFTDEP(vp->v_mount) != 0, + ("softdep_slowdown called on non-softdep filesystem")); + ump = VFSTOUFS(vp->v_mount); + ACQUIRE_LOCK(ump); + jlow = 0; + /* + * Check for journal space if needed. + */ + if (DOINGSUJ(vp)) { + if (journal_space(ump, 0) == 0) + jlow = 1; + } + /* + * If the system is under its limits and our filesystem is + * not responsible for more than our share of the usage and + * we are not low on journal space, then no need to slow down. + */ + max_softdeps_hard = max_softdeps * 11 / 10; + if (dep_current[D_DIRREM] < max_softdeps_hard / 2 && + dep_current[D_INODEDEP] < max_softdeps_hard && + dep_current[D_INDIRDEP] < max_softdeps_hard / 1000 && + dep_current[D_FREEBLKS] < max_softdeps_hard && jlow == 0 && + ump->softdep_curdeps[D_DIRREM] < + (max_softdeps_hard / 2) / stat_flush_threads && + ump->softdep_curdeps[D_INODEDEP] < + max_softdeps_hard / stat_flush_threads && + ump->softdep_curdeps[D_INDIRDEP] < + (max_softdeps_hard / 1000) / stat_flush_threads && + ump->softdep_curdeps[D_FREEBLKS] < + max_softdeps_hard / stat_flush_threads) { + FREE_LOCK(ump); + return (0); + } + /* + * If the journal is low or our filesystem is over its limit + * then speedup the cleanup. + */ + if (ump->softdep_curdeps[D_INDIRDEP] < + (max_softdeps_hard / 1000) / stat_flush_threads || jlow) + softdep_speedup(ump); + stat_sync_limit_hit += 1; + FREE_LOCK(ump); + /* + * We only slow down the rate at which new dependencies are + * generated if we are not using journaling. With journaling, + * the cleanup should always be sufficient to keep things + * under control. + */ + if (DOINGSUJ(vp)) + return (0); + return (1); +} + +/* + * Called by the allocation routines when they are about to fail + * in the hope that we can free up the requested resource (inodes + * or disk space). + * + * First check to see if the work list has anything on it. If it has, + * clean up entries until we successfully free the requested resource. + * Because this process holds inodes locked, we cannot handle any remove + * requests that might block on a locked inode as that could lead to + * deadlock. If the worklist yields none of the requested resource, + * start syncing out vnodes to free up the needed space. + */ +int +softdep_request_cleanup(fs, vp, cred, resource) + struct fs *fs; + struct vnode *vp; + struct ucred *cred; + int resource; +{ + struct ufsmount *ump; + struct mount *mp; + long starttime; + ufs2_daddr_t needed; + int error, failed_vnode; + + /* + * If we are being called because of a process doing a + * copy-on-write, then it is not safe to process any + * worklist items as we will recurse into the copyonwrite + * routine. This will result in an incoherent snapshot. + * If the vnode that we hold is a snapshot, we must avoid + * handling other resources that could cause deadlock. + */ + if ((curthread->td_pflags & TDP_COWINPROGRESS) || IS_SNAPSHOT(VTOI(vp))) + return (0); + + if (resource == FLUSH_BLOCKS_WAIT) + stat_cleanup_blkrequests += 1; + else + stat_cleanup_inorequests += 1; + + mp = vp->v_mount; + ump = VFSTOUFS(mp); + mtx_assert(UFS_MTX(ump), MA_OWNED); + UFS_UNLOCK(ump); + error = ffs_update(vp, 1); + if (error != 0 || MOUNTEDSOFTDEP(mp) == 0) { + UFS_LOCK(ump); + return (0); + } + /* + * If we are in need of resources, start by cleaning up + * any block removals associated with our inode. + */ + ACQUIRE_LOCK(ump); + process_removes(vp); + process_truncates(vp); + FREE_LOCK(ump); + /* + * Now clean up at least as many resources as we will need. + * + * When requested to clean up inodes, the number that are needed + * is set by the number of simultaneous writers (mnt_writeopcount) + * plus a bit of slop (2) in case some more writers show up while + * we are cleaning. + * + * When requested to free up space, the amount of space that + * we need is enough blocks to allocate a full-sized segment + * (fs_contigsumsize). The number of such segments that will + * be needed is set by the number of simultaneous writers + * (mnt_writeopcount) plus a bit of slop (2) in case some more + * writers show up while we are cleaning. + * + * Additionally, if we are unpriviledged and allocating space, + * we need to ensure that we clean up enough blocks to get the + * needed number of blocks over the threshold of the minimum + * number of blocks required to be kept free by the filesystem + * (fs_minfree). + */ + if (resource == FLUSH_INODES_WAIT) { + needed = vp->v_mount->mnt_writeopcount + 2; + } else if (resource == FLUSH_BLOCKS_WAIT) { + needed = (vp->v_mount->mnt_writeopcount + 2) * + fs->fs_contigsumsize; + if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) + needed += fragstoblks(fs, + roundup((fs->fs_dsize * fs->fs_minfree / 100) - + fs->fs_cstotal.cs_nffree, fs->fs_frag)); + } else { + UFS_LOCK(ump); + printf("softdep_request_cleanup: Unknown resource type %d\n", + resource); + return (0); + } + starttime = time_second; +retry: + if ((resource == FLUSH_BLOCKS_WAIT && ump->softdep_on_worklist > 0 && + fs->fs_cstotal.cs_nbfree <= needed) || + (resource == FLUSH_INODES_WAIT && fs->fs_pendinginodes > 0 && + fs->fs_cstotal.cs_nifree <= needed)) { + ACQUIRE_LOCK(ump); + if (ump->softdep_on_worklist > 0 && + process_worklist_item(UFSTOVFS(ump), + ump->softdep_on_worklist, LK_NOWAIT) != 0) + stat_worklist_push += 1; + FREE_LOCK(ump); + } + /* + * If we still need resources and there are no more worklist + * entries to process to obtain them, we have to start flushing + * the dirty vnodes to force the release of additional requests + * to the worklist that we can then process to reap addition + * resources. We walk the vnodes associated with the mount point + * until we get the needed worklist requests that we can reap. + * + * If there are several threads all needing to clean the same + * mount point, only one is allowed to walk the mount list. + * When several threads all try to walk the same mount list, + * they end up competing with each other and often end up in + * livelock. This approach ensures that forward progress is + * made at the cost of occational ENOSPC errors being returned + * that might otherwise have been avoided. + */ + error = 1; + if ((resource == FLUSH_BLOCKS_WAIT && + fs->fs_cstotal.cs_nbfree <= needed) || + (resource == FLUSH_INODES_WAIT && fs->fs_pendinginodes > 0 && + fs->fs_cstotal.cs_nifree <= needed)) { + ACQUIRE_LOCK(ump); + if ((ump->um_softdep->sd_flags & FLUSH_RC_ACTIVE) == 0) { + ump->um_softdep->sd_flags |= FLUSH_RC_ACTIVE; + FREE_LOCK(ump); + failed_vnode = softdep_request_cleanup_flush(mp, ump); + ACQUIRE_LOCK(ump); + ump->um_softdep->sd_flags &= ~FLUSH_RC_ACTIVE; + FREE_LOCK(ump); + if (ump->softdep_on_worklist > 0) { + stat_cleanup_retries += 1; + if (!failed_vnode) + goto retry; + } + } else { + FREE_LOCK(ump); + error = 0; + } + stat_cleanup_failures += 1; + } + if (time_second - starttime > stat_cleanup_high_delay) + stat_cleanup_high_delay = time_second - starttime; + UFS_LOCK(ump); + return (error); +} + +/* + * Scan the vnodes for the specified mount point flushing out any + * vnodes that can be locked without waiting. Finally, try to flush + * the device associated with the mount point if it can be locked + * without waiting. + * + * We return 0 if we were able to lock every vnode in our scan. + * If we had to skip one or more vnodes, we return 1. + */ +static int +softdep_request_cleanup_flush(mp, ump) + struct mount *mp; + struct ufsmount *ump; +{ + struct thread *td; + struct vnode *lvp, *mvp; + int failed_vnode; + + failed_vnode = 0; + td = curthread; + MNT_VNODE_FOREACH_ALL(lvp, mp, mvp) { + if (TAILQ_FIRST(&lvp->v_bufobj.bo_dirty.bv_hd) == 0) { + VI_UNLOCK(lvp); + continue; + } + if (vget(lvp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, + td) != 0) { + failed_vnode = 1; + continue; + } + if (lvp->v_vflag & VV_NOSYNC) { /* unlinked */ + vput(lvp); + continue; + } + (void) ffs_syncvnode(lvp, MNT_NOWAIT, 0); + vput(lvp); + } + lvp = ump->um_devvp; + if (vn_lock(lvp, LK_EXCLUSIVE | LK_NOWAIT) == 0) { + VOP_FSYNC(lvp, MNT_NOWAIT, td); + VOP_UNLOCK(lvp, 0); + } + return (failed_vnode); +} + +static bool +softdep_excess_items(struct ufsmount *ump, int item) +{ + + KASSERT(item >= 0 && item < D_LAST, ("item %d", item)); + return (dep_current[item] > max_softdeps && + ump->softdep_curdeps[item] > max_softdeps / + stat_flush_threads); +} + +static void +schedule_cleanup(struct mount *mp) +{ + struct ufsmount *ump; + struct thread *td; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + FREE_LOCK(ump); + td = curthread; + if ((td->td_pflags & TDP_KTHREAD) != 0 && + (td->td_proc->p_flag2 & P2_AST_SU) == 0) { + /* + * No ast is delivered to kernel threads, so nobody + * would deref the mp. Some kernel threads + * explicitely check for AST, e.g. NFS daemon does + * this in the serving loop. + */ + return; + } + if (td->td_su != NULL) + vfs_rel(td->td_su); + vfs_ref(mp); + td->td_su = mp; + thread_lock(td); + td->td_flags |= TDF_ASTPENDING; + thread_unlock(td); +} + +static void +softdep_ast_cleanup_proc(struct thread *td) +{ + struct mount *mp; + struct ufsmount *ump; + int error; + bool req; + + while ((mp = td->td_su) != NULL) { + td->td_su = NULL; + error = vfs_busy(mp, MBF_NOWAIT); + vfs_rel(mp); + if (error != 0) + return; + if (ffs_own_mount(mp) && MOUNTEDSOFTDEP(mp)) { + ump = VFSTOUFS(mp); + for (;;) { + req = false; + ACQUIRE_LOCK(ump); + if (softdep_excess_items(ump, D_INODEDEP)) { + req = true; + request_cleanup(mp, FLUSH_INODES); + } + if (softdep_excess_items(ump, D_DIRREM)) { + req = true; + request_cleanup(mp, FLUSH_BLOCKS); + } + FREE_LOCK(ump); + if (softdep_excess_items(ump, D_NEWBLK) || + softdep_excess_items(ump, D_ALLOCDIRECT) || + softdep_excess_items(ump, D_ALLOCINDIR)) { + error = vn_start_write(NULL, &mp, + V_WAIT); + if (error == 0) { + req = true; + VFS_SYNC(mp, MNT_WAIT); + vn_finished_write(mp); + } + } + if ((td->td_pflags & TDP_KTHREAD) != 0 || !req) + break; + } + } + vfs_unbusy(mp); + } + if ((mp = td->td_su) != NULL) { + td->td_su = NULL; + vfs_rel(mp); + } +} + +/* + * If memory utilization has gotten too high, deliberately slow things + * down and speed up the I/O processing. + */ +static int +request_cleanup(mp, resource) + struct mount *mp; + int resource; +{ + struct thread *td = curthread; + struct ufsmount *ump; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + /* + * We never hold up the filesystem syncer or buf daemon. + */ + if (td->td_pflags & (TDP_SOFTDEP|TDP_NORUNNINGBUF)) + return (0); + /* + * First check to see if the work list has gotten backlogged. + * If it has, co-opt this process to help clean up two entries. + * Because this process may hold inodes locked, we cannot + * handle any remove requests that might block on a locked + * inode as that could lead to deadlock. We set TDP_SOFTDEP + * to avoid recursively processing the worklist. + */ + if (ump->softdep_on_worklist > max_softdeps / 10) { + td->td_pflags |= TDP_SOFTDEP; + process_worklist_item(mp, 2, LK_NOWAIT); + td->td_pflags &= ~TDP_SOFTDEP; + stat_worklist_push += 2; + return(1); + } + /* + * Next, we attempt to speed up the syncer process. If that + * is successful, then we allow the process to continue. + */ + if (softdep_speedup(ump) && + resource != FLUSH_BLOCKS_WAIT && + resource != FLUSH_INODES_WAIT) + return(0); + /* + * If we are resource constrained on inode dependencies, try + * flushing some dirty inodes. Otherwise, we are constrained + * by file deletions, so try accelerating flushes of directories + * with removal dependencies. We would like to do the cleanup + * here, but we probably hold an inode locked at this point and + * that might deadlock against one that we try to clean. So, + * the best that we can do is request the syncer daemon to do + * the cleanup for us. + */ + switch (resource) { + + case FLUSH_INODES: + case FLUSH_INODES_WAIT: + ACQUIRE_GBLLOCK(&lk); + stat_ino_limit_push += 1; + req_clear_inodedeps += 1; + FREE_GBLLOCK(&lk); + stat_countp = &stat_ino_limit_hit; + break; + + case FLUSH_BLOCKS: + case FLUSH_BLOCKS_WAIT: + ACQUIRE_GBLLOCK(&lk); + stat_blk_limit_push += 1; + req_clear_remove += 1; + FREE_GBLLOCK(&lk); + stat_countp = &stat_blk_limit_hit; + break; + + default: + panic("request_cleanup: unknown type"); + } + /* + * Hopefully the syncer daemon will catch up and awaken us. + * We wait at most tickdelay before proceeding in any case. + */ + ACQUIRE_GBLLOCK(&lk); + FREE_LOCK(ump); + proc_waiting += 1; + if (callout_pending(&softdep_callout) == FALSE) + callout_reset(&softdep_callout, tickdelay > 2 ? tickdelay : 2, + pause_timer, 0); + + if ((td->td_pflags & TDP_KTHREAD) == 0) + msleep((caddr_t)&proc_waiting, &lk, PPAUSE, "softupdate", 0); + proc_waiting -= 1; + FREE_GBLLOCK(&lk); + ACQUIRE_LOCK(ump); + return (1); +} + +/* + * Awaken processes pausing in request_cleanup and clear proc_waiting + * to indicate that there is no longer a timer running. Pause_timer + * will be called with the global softdep mutex (&lk) locked. + */ +static void +pause_timer(arg) + void *arg; +{ + + GBLLOCK_OWNED(&lk); + /* + * The callout_ API has acquired mtx and will hold it around this + * function call. + */ + *stat_countp += proc_waiting; + wakeup(&proc_waiting); +} + +/* + * If requested, try removing inode or removal dependencies. + */ +static void +check_clear_deps(mp) + struct mount *mp; +{ + + /* + * If we are suspended, it may be because of our using + * too many inodedeps, so help clear them out. + */ + if (MOUNTEDSUJ(mp) && VFSTOUFS(mp)->softdep_jblocks->jb_suspended) + clear_inodedeps(mp); + /* + * General requests for cleanup of backed up dependencies + */ + ACQUIRE_GBLLOCK(&lk); + if (req_clear_inodedeps) { + req_clear_inodedeps -= 1; + FREE_GBLLOCK(&lk); + clear_inodedeps(mp); + ACQUIRE_GBLLOCK(&lk); + wakeup(&proc_waiting); + } + if (req_clear_remove) { + req_clear_remove -= 1; + FREE_GBLLOCK(&lk); + clear_remove(mp); + ACQUIRE_GBLLOCK(&lk); + wakeup(&proc_waiting); + } + FREE_GBLLOCK(&lk); +} + +/* + * Flush out a directory with at least one removal dependency in an effort to + * reduce the number of dirrem, freefile, and freeblks dependency structures. + */ +static void +clear_remove(mp) + struct mount *mp; +{ + struct pagedep_hashhead *pagedephd; + struct pagedep *pagedep; + struct ufsmount *ump; + struct vnode *vp; + struct bufobj *bo; + int error, cnt; + ino_t ino; + + ump = VFSTOUFS(mp); + LOCK_OWNED(ump); + + for (cnt = 0; cnt <= ump->pagedep_hash_size; cnt++) { + pagedephd = &ump->pagedep_hashtbl[ump->pagedep_nextclean++]; + if (ump->pagedep_nextclean > ump->pagedep_hash_size) + ump->pagedep_nextclean = 0; + LIST_FOREACH(pagedep, pagedephd, pd_hash) { + if (LIST_EMPTY(&pagedep->pd_dirremhd)) + continue; + ino = pagedep->pd_ino; + if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) + continue; + FREE_LOCK(ump); + + /* + * Let unmount clear deps + */ + error = vfs_busy(mp, MBF_NOWAIT); + if (error != 0) + goto finish_write; + error = ffs_vgetf(mp, ino, LK_EXCLUSIVE, &vp, + FFSV_FORCEINSMQ); + vfs_unbusy(mp); + if (error != 0) { + softdep_error("clear_remove: vget", error); + goto finish_write; + } + if ((error = ffs_syncvnode(vp, MNT_NOWAIT, 0))) + softdep_error("clear_remove: fsync", error); + bo = &vp->v_bufobj; + BO_LOCK(bo); + drain_output(vp); + BO_UNLOCK(bo); + vput(vp); + finish_write: + vn_finished_write(mp); + ACQUIRE_LOCK(ump); + return; + } + } +} + +/* + * Clear out a block of dirty inodes in an effort to reduce + * the number of inodedep dependency structures. + */ +static void +clear_inodedeps(mp) + struct mount *mp; +{ + struct inodedep_hashhead *inodedephd; + struct inodedep *inodedep; + struct ufsmount *ump; + struct vnode *vp; + struct fs *fs; + int error, cnt; + ino_t firstino, lastino, ino; + + ump = VFSTOUFS(mp); + fs = ump->um_fs; + LOCK_OWNED(ump); + /* + * Pick a random inode dependency to be cleared. + * We will then gather up all the inodes in its block + * that have dependencies and flush them out. + */ + for (cnt = 0; cnt <= ump->inodedep_hash_size; cnt++) { + inodedephd = &ump->inodedep_hashtbl[ump->inodedep_nextclean++]; + if (ump->inodedep_nextclean > ump->inodedep_hash_size) + ump->inodedep_nextclean = 0; + if ((inodedep = LIST_FIRST(inodedephd)) != NULL) + break; + } + if (inodedep == NULL) + return; + /* + * Find the last inode in the block with dependencies. + */ + firstino = rounddown2(inodedep->id_ino, INOPB(fs)); + for (lastino = firstino + INOPB(fs) - 1; lastino > firstino; lastino--) + if (inodedep_lookup(mp, lastino, 0, &inodedep) != 0) + break; + /* + * Asynchronously push all but the last inode with dependencies. + * Synchronously push the last inode with dependencies to ensure + * that the inode block gets written to free up the inodedeps. + */ + for (ino = firstino; ino <= lastino; ino++) { + if (inodedep_lookup(mp, ino, 0, &inodedep) == 0) + continue; + if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) + continue; + FREE_LOCK(ump); + error = vfs_busy(mp, MBF_NOWAIT); /* Let unmount clear deps */ + if (error != 0) { + vn_finished_write(mp); + ACQUIRE_LOCK(ump); + return; + } + if ((error = ffs_vgetf(mp, ino, LK_EXCLUSIVE, &vp, + FFSV_FORCEINSMQ)) != 0) { + softdep_error("clear_inodedeps: vget", error); + vfs_unbusy(mp); + vn_finished_write(mp); + ACQUIRE_LOCK(ump); + return; + } + vfs_unbusy(mp); + if (ino == lastino) { + if ((error = ffs_syncvnode(vp, MNT_WAIT, 0))) + softdep_error("clear_inodedeps: fsync1", error); + } else { + if ((error = ffs_syncvnode(vp, MNT_NOWAIT, 0))) + softdep_error("clear_inodedeps: fsync2", error); + BO_LOCK(&vp->v_bufobj); + drain_output(vp); + BO_UNLOCK(&vp->v_bufobj); + } + vput(vp); + vn_finished_write(mp); + ACQUIRE_LOCK(ump); + } +} + +void +softdep_buf_append(bp, wkhd) + struct buf *bp; + struct workhead *wkhd; +{ + struct worklist *wk; + struct ufsmount *ump; + + if ((wk = LIST_FIRST(wkhd)) == NULL) + return; + KASSERT(MOUNTEDSOFTDEP(wk->wk_mp) != 0, + ("softdep_buf_append called on non-softdep filesystem")); + ump = VFSTOUFS(wk->wk_mp); + ACQUIRE_LOCK(ump); + while ((wk = LIST_FIRST(wkhd)) != NULL) { + WORKLIST_REMOVE(wk); + WORKLIST_INSERT(&bp->b_dep, wk); + } + FREE_LOCK(ump); + +} + +void +softdep_inode_append(ip, cred, wkhd) + struct inode *ip; + struct ucred *cred; + struct workhead *wkhd; +{ + struct buf *bp; + struct fs *fs; + struct ufsmount *ump; + int error; + + ump = ITOUMP(ip); + KASSERT(MOUNTEDSOFTDEP(UFSTOVFS(ump)) != 0, + ("softdep_inode_append called on non-softdep filesystem")); + fs = ump->um_fs; + error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), + (int)fs->fs_bsize, cred, &bp); + if (error) { + bqrelse(bp); + softdep_freework(wkhd); + return; + } + softdep_buf_append(bp, wkhd); + bqrelse(bp); +} + +void +softdep_freework(wkhd) + struct workhead *wkhd; +{ + struct worklist *wk; + struct ufsmount *ump; + + if ((wk = LIST_FIRST(wkhd)) == NULL) + return; + KASSERT(MOUNTEDSOFTDEP(wk->wk_mp) != 0, + ("softdep_freework called on non-softdep filesystem")); + ump = VFSTOUFS(wk->wk_mp); + ACQUIRE_LOCK(ump); + handle_jwork(wkhd); + FREE_LOCK(ump); +} + +static struct ufsmount * +softdep_bp_to_mp(bp) + struct buf *bp; +{ + struct mount *mp; + struct vnode *vp; + + if (LIST_EMPTY(&bp->b_dep)) + return (NULL); + vp = bp->b_vp; + + /* + * The ump mount point is stable after we get a correct + * pointer, since bp is locked and this prevents unmount from + * proceeding. But to get to it, we cannot dereference bp->b_dep + * head wk_mp, because we do not yet own SU ump lock and + * workitem might be freed while dereferenced. + */ +retry: + if (vp->v_type == VCHR) { + VI_LOCK(vp); + mp = vp->v_type == VCHR ? vp->v_rdev->si_mountpt : NULL; + VI_UNLOCK(vp); + if (mp == NULL) + goto retry; + } else if (vp->v_type == VREG || vp->v_type == VDIR || + vp->v_type == VLNK) { + mp = vp->v_mount; + } else { + return (NULL); + } + return (VFSTOUFS(mp)); +} + +/* + * Function to determine if the buffer has outstanding dependencies + * that will cause a roll-back if the buffer is written. If wantcount + * is set, return number of dependencies, otherwise just yes or no. + */ +static int +softdep_count_dependencies(bp, wantcount) + struct buf *bp; + int wantcount; +{ + struct worklist *wk; + struct ufsmount *ump; + struct bmsafemap *bmsafemap; + struct freework *freework; + struct inodedep *inodedep; + struct indirdep *indirdep; + struct freeblks *freeblks; + struct allocindir *aip; + struct pagedep *pagedep; + struct dirrem *dirrem; + struct newblk *newblk; + struct mkdir *mkdir; + struct diradd *dap; + int i, retval; + + ump = softdep_bp_to_mp(bp); + if (ump == NULL) + return (0); + retval = 0; + ACQUIRE_LOCK(ump); + LIST_FOREACH(wk, &bp->b_dep, wk_list) { + switch (wk->wk_type) { + + case D_INODEDEP: + inodedep = WK_INODEDEP(wk); + if ((inodedep->id_state & DEPCOMPLETE) == 0) { + /* bitmap allocation dependency */ + retval += 1; + if (!wantcount) + goto out; + } + if (TAILQ_FIRST(&inodedep->id_inoupdt)) { + /* direct block pointer dependency */ + retval += 1; + if (!wantcount) + goto out; + } + if (TAILQ_FIRST(&inodedep->id_extupdt)) { + /* direct block pointer dependency */ + retval += 1; + if (!wantcount) + goto out; + } + if (TAILQ_FIRST(&inodedep->id_inoreflst)) { + /* Add reference dependency. */ + retval += 1; + if (!wantcount) + goto out; + } + continue; + + case D_INDIRDEP: + indirdep = WK_INDIRDEP(wk); + + TAILQ_FOREACH(freework, &indirdep->ir_trunc, fw_next) { + /* indirect truncation dependency */ + retval += 1; + if (!wantcount) + goto out; + } + + LIST_FOREACH(aip, &indirdep->ir_deplisthd, ai_next) { + /* indirect block pointer dependency */ + retval += 1; + if (!wantcount) + goto out; + } + continue; + + case D_PAGEDEP: + pagedep = WK_PAGEDEP(wk); + LIST_FOREACH(dirrem, &pagedep->pd_dirremhd, dm_next) { + if (LIST_FIRST(&dirrem->dm_jremrefhd)) { + /* Journal remove ref dependency. */ + retval += 1; + if (!wantcount) + goto out; + } + } + for (i = 0; i < DAHASHSZ; i++) { + + LIST_FOREACH(dap, &pagedep->pd_diraddhd[i], da_pdlist) { + /* directory entry dependency */ + retval += 1; + if (!wantcount) + goto out; + } + } + continue; + + case D_BMSAFEMAP: + bmsafemap = WK_BMSAFEMAP(wk); + if (LIST_FIRST(&bmsafemap->sm_jaddrefhd)) { + /* Add reference dependency. */ + retval += 1; + if (!wantcount) + goto out; + } + if (LIST_FIRST(&bmsafemap->sm_jnewblkhd)) { + /* Allocate block dependency. */ + retval += 1; + if (!wantcount) + goto out; + } + continue; + + case D_FREEBLKS: + freeblks = WK_FREEBLKS(wk); + if (LIST_FIRST(&freeblks->fb_jblkdephd)) { + /* Freeblk journal dependency. */ + retval += 1; + if (!wantcount) + goto out; + } + continue; + + case D_ALLOCDIRECT: + case D_ALLOCINDIR: + newblk = WK_NEWBLK(wk); + if (newblk->nb_jnewblk) { + /* Journal allocate dependency. */ + retval += 1; + if (!wantcount) + goto out; + } + continue; + + case D_MKDIR: + mkdir = WK_MKDIR(wk); + if (mkdir->md_jaddref) { + /* Journal reference dependency. */ + retval += 1; + if (!wantcount) + goto out; + } + continue; + + case D_FREEWORK: + case D_FREEDEP: + case D_JSEGDEP: + case D_JSEG: + case D_SBDEP: + /* never a dependency on these blocks */ + continue; + + default: + panic("softdep_count_dependencies: Unexpected type %s", + TYPENAME(wk->wk_type)); + /* NOTREACHED */ + } + } +out: + FREE_LOCK(ump); + return (retval); +} + +/* + * Acquire exclusive access to a buffer. + * Must be called with a locked mtx parameter. + * Return acquired buffer or NULL on failure. + */ +static struct buf * +getdirtybuf(bp, lock, waitfor) + struct buf *bp; + struct rwlock *lock; + int waitfor; +{ + int error; + + if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) != 0) { + if (waitfor != MNT_WAIT) + return (NULL); + error = BUF_LOCK(bp, + LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, lock); + /* + * Even if we successfully acquire bp here, we have dropped + * lock, which may violates our guarantee. + */ + if (error == 0) + BUF_UNLOCK(bp); + else if (error != ENOLCK) + panic("getdirtybuf: inconsistent lock: %d", error); + rw_wlock(lock); + return (NULL); + } + if ((bp->b_vflags & BV_BKGRDINPROG) != 0) { + if (lock != BO_LOCKPTR(bp->b_bufobj) && waitfor == MNT_WAIT) { + rw_wunlock(lock); + BO_LOCK(bp->b_bufobj); + BUF_UNLOCK(bp); + if ((bp->b_vflags & BV_BKGRDINPROG) != 0) { + bp->b_vflags |= BV_BKGRDWAIT; + msleep(&bp->b_xflags, BO_LOCKPTR(bp->b_bufobj), + PRIBIO | PDROP, "getbuf", 0); + } else + BO_UNLOCK(bp->b_bufobj); + rw_wlock(lock); + return (NULL); + } + BUF_UNLOCK(bp); + if (waitfor != MNT_WAIT) + return (NULL); +#ifdef DEBUG_VFS_LOCKS + if (bp->b_vp->v_type != VCHR) + ASSERT_BO_WLOCKED(bp->b_bufobj); +#endif + bp->b_vflags |= BV_BKGRDWAIT; + rw_sleep(&bp->b_xflags, lock, PRIBIO, "getbuf", 0); + return (NULL); + } + if ((bp->b_flags & B_DELWRI) == 0) { + BUF_UNLOCK(bp); + return (NULL); + } + bremfree(bp); + return (bp); +} + + +/* + * Check if it is safe to suspend the file system now. On entry, + * the vnode interlock for devvp should be held. Return 0 with + * the mount interlock held if the file system can be suspended now, + * otherwise return EAGAIN with the mount interlock held. + */ +int +softdep_check_suspend(struct mount *mp, + struct vnode *devvp, + int softdep_depcnt, + int softdep_accdepcnt, + int secondary_writes, + int secondary_accwrites) +{ + struct bufobj *bo; + struct ufsmount *ump; + struct inodedep *inodedep; + int error, unlinked; + + bo = &devvp->v_bufobj; + ASSERT_BO_WLOCKED(bo); + + /* + * If we are not running with soft updates, then we need only + * deal with secondary writes as we try to suspend. + */ + if (MOUNTEDSOFTDEP(mp) == 0) { + MNT_ILOCK(mp); + while (mp->mnt_secondary_writes != 0) { + BO_UNLOCK(bo); + msleep(&mp->mnt_secondary_writes, MNT_MTX(mp), + (PUSER - 1) | PDROP, "secwr", 0); + BO_LOCK(bo); + MNT_ILOCK(mp); + } + + /* + * Reasons for needing more work before suspend: + * - Dirty buffers on devvp. + * - Secondary writes occurred after start of vnode sync loop + */ + error = 0; + if (bo->bo_numoutput > 0 || + bo->bo_dirty.bv_cnt > 0 || + secondary_writes != 0 || + mp->mnt_secondary_writes != 0 || + secondary_accwrites != mp->mnt_secondary_accwrites) + error = EAGAIN; + BO_UNLOCK(bo); + return (error); + } + + /* + * If we are running with soft updates, then we need to coordinate + * with them as we try to suspend. + */ + ump = VFSTOUFS(mp); + for (;;) { + if (!TRY_ACQUIRE_LOCK(ump)) { + BO_UNLOCK(bo); + ACQUIRE_LOCK(ump); + FREE_LOCK(ump); + BO_LOCK(bo); + continue; + } + MNT_ILOCK(mp); + if (mp->mnt_secondary_writes != 0) { + FREE_LOCK(ump); + BO_UNLOCK(bo); + msleep(&mp->mnt_secondary_writes, + MNT_MTX(mp), + (PUSER - 1) | PDROP, "secwr", 0); + BO_LOCK(bo); + continue; + } + break; + } + + unlinked = 0; + if (MOUNTEDSUJ(mp)) { + for (inodedep = TAILQ_FIRST(&ump->softdep_unlinked); + inodedep != NULL; + inodedep = TAILQ_NEXT(inodedep, id_unlinked)) { + if ((inodedep->id_state & (UNLINKED | UNLINKLINKS | + UNLINKONLIST)) != (UNLINKED | UNLINKLINKS | + UNLINKONLIST) || + !check_inodedep_free(inodedep)) + continue; + unlinked++; + } + } + + /* + * Reasons for needing more work before suspend: + * - Dirty buffers on devvp. + * - Softdep activity occurred after start of vnode sync loop + * - Secondary writes occurred after start of vnode sync loop + */ + error = 0; + if (bo->bo_numoutput > 0 || + bo->bo_dirty.bv_cnt > 0 || + softdep_depcnt != unlinked || + ump->softdep_deps != unlinked || + softdep_accdepcnt != ump->softdep_accdeps || + secondary_writes != 0 || + mp->mnt_secondary_writes != 0 || + secondary_accwrites != mp->mnt_secondary_accwrites) + error = EAGAIN; + FREE_LOCK(ump); + BO_UNLOCK(bo); + return (error); +} + + +/* + * Get the number of dependency structures for the file system, both + * the current number and the total number allocated. These will + * later be used to detect that softdep processing has occurred. + */ +void +softdep_get_depcounts(struct mount *mp, + int *softdep_depsp, + int *softdep_accdepsp) +{ + struct ufsmount *ump; + + if (MOUNTEDSOFTDEP(mp) == 0) { + *softdep_depsp = 0; + *softdep_accdepsp = 0; + return; + } + ump = VFSTOUFS(mp); + ACQUIRE_LOCK(ump); + *softdep_depsp = ump->softdep_deps; + *softdep_accdepsp = ump->softdep_accdeps; + FREE_LOCK(ump); +} + +/* + * Wait for pending output on a vnode to complete. + */ +static void +drain_output(vp) + struct vnode *vp; +{ + + ASSERT_VOP_LOCKED(vp, "drain_output"); + (void)bufobj_wwait(&vp->v_bufobj, 0, 0); +} + +/* + * Called whenever a buffer that is being invalidated or reallocated + * contains dependencies. This should only happen if an I/O error has + * occurred. The routine is called with the buffer locked. + */ +static void +softdep_deallocate_dependencies(bp) + struct buf *bp; +{ + + if ((bp->b_ioflags & BIO_ERROR) == 0) + panic("softdep_deallocate_dependencies: dangling deps"); + if (bp->b_vp != NULL && bp->b_vp->v_mount != NULL) + softdep_error(bp->b_vp->v_mount->mnt_stat.f_mntonname, bp->b_error); + else + printf("softdep_deallocate_dependencies: " + "got error %d while accessing filesystem\n", bp->b_error); + if (bp->b_error != ENXIO) + panic("softdep_deallocate_dependencies: unrecovered I/O error"); +} + +/* + * Function to handle asynchronous write errors in the filesystem. + */ +static void +softdep_error(func, error) + char *func; + int error; +{ + + /* XXX should do something better! */ + printf("%s: got error %d while accessing filesystem\n", func, error); +} + +#ifdef DDB + +static void +inodedep_print(struct inodedep *inodedep, int verbose) +{ + db_printf("%p fs %p st %x ino %jd inoblk %jd delta %jd nlink %jd" + " saveino %p\n", + inodedep, inodedep->id_fs, inodedep->id_state, + (intmax_t)inodedep->id_ino, + (intmax_t)fsbtodb(inodedep->id_fs, + ino_to_fsba(inodedep->id_fs, inodedep->id_ino)), + (intmax_t)inodedep->id_nlinkdelta, + (intmax_t)inodedep->id_savednlink, + inodedep->id_savedino1); + + if (verbose == 0) + return; + + db_printf("\tpendinghd %p, bufwait %p, inowait %p, inoreflst %p, " + "mkdiradd %p\n", + LIST_FIRST(&inodedep->id_pendinghd), + LIST_FIRST(&inodedep->id_bufwait), + LIST_FIRST(&inodedep->id_inowait), + TAILQ_FIRST(&inodedep->id_inoreflst), + inodedep->id_mkdiradd); + db_printf("\tinoupdt %p, newinoupdt %p, extupdt %p, newextupdt %p\n", + TAILQ_FIRST(&inodedep->id_inoupdt), + TAILQ_FIRST(&inodedep->id_newinoupdt), + TAILQ_FIRST(&inodedep->id_extupdt), + TAILQ_FIRST(&inodedep->id_newextupdt)); +} + +DB_SHOW_COMMAND(inodedep, db_show_inodedep) +{ + + if (have_addr == 0) { + db_printf("Address required\n"); + return; + } + inodedep_print((struct inodedep*)addr, 1); +} + +DB_SHOW_COMMAND(inodedeps, db_show_inodedeps) +{ + struct inodedep_hashhead *inodedephd; + struct inodedep *inodedep; + struct ufsmount *ump; + int cnt; + + if (have_addr == 0) { + db_printf("Address required\n"); + return; + } + ump = (struct ufsmount *)addr; + for (cnt = 0; cnt < ump->inodedep_hash_size; cnt++) { + inodedephd = &ump->inodedep_hashtbl[cnt]; + LIST_FOREACH(inodedep, inodedephd, id_hash) { + inodedep_print(inodedep, 0); + } + } +} + +DB_SHOW_COMMAND(worklist, db_show_worklist) +{ + struct worklist *wk; + + if (have_addr == 0) { + db_printf("Address required\n"); + return; + } + wk = (struct worklist *)addr; + printf("worklist: %p type %s state 0x%X\n", + wk, TYPENAME(wk->wk_type), wk->wk_state); +} + +DB_SHOW_COMMAND(workhead, db_show_workhead) +{ + struct workhead *wkhd; + struct worklist *wk; + int i; + + if (have_addr == 0) { + db_printf("Address required\n"); + return; + } + wkhd = (struct workhead *)addr; + wk = LIST_FIRST(wkhd); + for (i = 0; i < 100 && wk != NULL; i++, wk = LIST_NEXT(wk, wk_list)) + db_printf("worklist: %p type %s state 0x%X", + wk, TYPENAME(wk->wk_type), wk->wk_state); + if (i == 100) + db_printf("workhead overflow"); + printf("\n"); +} + + +DB_SHOW_COMMAND(mkdirs, db_show_mkdirs) +{ + struct mkdirlist *mkdirlisthd; + struct jaddref *jaddref; + struct diradd *diradd; + struct mkdir *mkdir; + + if (have_addr == 0) { + db_printf("Address required\n"); + return; + } + mkdirlisthd = (struct mkdirlist *)addr; + LIST_FOREACH(mkdir, mkdirlisthd, md_mkdirs) { + diradd = mkdir->md_diradd; + db_printf("mkdir: %p state 0x%X dap %p state 0x%X", + mkdir, mkdir->md_state, diradd, diradd->da_state); + if ((jaddref = mkdir->md_jaddref) != NULL) + db_printf(" jaddref %p jaddref state 0x%X", + jaddref, jaddref->ja_state); + db_printf("\n"); + } +} + +/* exported to ffs_vfsops.c */ +extern void db_print_ffs(struct ufsmount *ump); +void +db_print_ffs(struct ufsmount *ump) +{ + db_printf("mp %p %s devvp %p fs %p su_wl %d su_deps %d su_req %d\n", + ump->um_mountp, ump->um_mountp->mnt_stat.f_mntonname, + ump->um_devvp, ump->um_fs, ump->softdep_on_worklist, + ump->softdep_deps, ump->softdep_req); +} + +#endif /* DDB */ + +#endif /* SOFTUPDATES */ diff --git a/Dump/ufs/ffs/ffs_subr.c b/Dump/ufs/ffs/ffs_subr.c new file mode 100644 index 0000000..e75b89f --- /dev/null +++ b/Dump/ufs/ffs/ffs_subr.c @@ -0,0 +1,379 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_subr.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include + +#ifndef _KERNEL +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Return buffer with the contents of block "offset" from the beginning of + * directory "ip". If "res" is non-zero, fill it in with a pointer to the + * remaining space in the directory. + */ +int +ffs_blkatoff(vp, offset, res, bpp) + struct vnode *vp; + off_t offset; + char **res; + struct buf **bpp; +{ + struct inode *ip; + struct fs *fs; + struct buf *bp; + ufs_lbn_t lbn; + int bsize, error; + + ip = VTOI(vp); + fs = ITOFS(ip); + lbn = lblkno(fs, offset); + bsize = blksize(fs, ip, lbn); + + *bpp = NULL; + error = bread(vp, lbn, bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + if (res) + *res = (char *)bp->b_data + blkoff(fs, offset); + *bpp = bp; + return (0); +} + +/* + * Load up the contents of an inode and copy the appropriate pieces + * to the incore copy. + */ +void +ffs_load_inode(bp, ip, fs, ino) + struct buf *bp; + struct inode *ip; + struct fs *fs; + ino_t ino; +{ + + if (I_IS_UFS1(ip)) { + *ip->i_din1 = + *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); + ip->i_mode = ip->i_din1->di_mode; + ip->i_nlink = ip->i_din1->di_nlink; + ip->i_size = ip->i_din1->di_size; + ip->i_flags = ip->i_din1->di_flags; + ip->i_gen = ip->i_din1->di_gen; + ip->i_uid = ip->i_din1->di_uid; + ip->i_gid = ip->i_din1->di_gid; + } else { + *ip->i_din2 = + *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino)); + ip->i_mode = ip->i_din2->di_mode; + ip->i_nlink = ip->i_din2->di_nlink; + ip->i_size = ip->i_din2->di_size; + ip->i_flags = ip->i_din2->di_flags; + ip->i_gen = ip->i_din2->di_gen; + ip->i_uid = ip->i_din2->di_uid; + ip->i_gid = ip->i_din2->di_gid; + } +} +#endif /* KERNEL */ + +/* + * Update the frsum fields to reflect addition or deletion + * of some frags. + */ +void +ffs_fragacct(fs, fragmap, fraglist, cnt) + struct fs *fs; + int fragmap; + int32_t fraglist[]; + int cnt; +{ + int inblk; + int field, subfield; + int siz, pos; + + inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; + fragmap <<= 1; + for (siz = 1; siz < fs->fs_frag; siz++) { + if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0) + continue; + field = around[siz]; + subfield = inside[siz]; + for (pos = siz; pos <= fs->fs_frag; pos++) { + if ((fragmap & field) == subfield) { + fraglist[siz] += cnt; + pos += siz; + field <<= siz; + subfield <<= siz; + } + field <<= 1; + subfield <<= 1; + } + } +} + +/* + * block operations + * + * check if a block is available + */ +int +ffs_isblock(fs, cp, h) + struct fs *fs; + unsigned char *cp; + ufs1_daddr_t h; +{ + unsigned char mask; + + switch ((int)fs->fs_frag) { + case 8: + return (cp[h] == 0xff); + case 4: + mask = 0x0f << ((h & 0x1) << 2); + return ((cp[h >> 1] & mask) == mask); + case 2: + mask = 0x03 << ((h & 0x3) << 1); + return ((cp[h >> 2] & mask) == mask); + case 1: + mask = 0x01 << (h & 0x7); + return ((cp[h >> 3] & mask) == mask); + default: +#ifdef _KERNEL + panic("ffs_isblock"); +#endif + break; + } + return (0); +} + +/* + * check if a block is free + */ +int +ffs_isfreeblock(fs, cp, h) + struct fs *fs; + u_char *cp; + ufs1_daddr_t h; +{ + + switch ((int)fs->fs_frag) { + case 8: + return (cp[h] == 0); + case 4: + return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); + case 2: + return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); + case 1: + return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); + default: +#ifdef _KERNEL + panic("ffs_isfreeblock"); +#endif + break; + } + return (0); +} + +/* + * take a block out of the map + */ +void +ffs_clrblock(fs, cp, h) + struct fs *fs; + u_char *cp; + ufs1_daddr_t h; +{ + + switch ((int)fs->fs_frag) { + case 8: + cp[h] = 0; + return; + case 4: + cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); + return; + case 2: + cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); + return; + case 1: + cp[h >> 3] &= ~(0x01 << (h & 0x7)); + return; + default: +#ifdef _KERNEL + panic("ffs_clrblock"); +#endif + break; + } +} + +/* + * put a block into the map + */ +void +ffs_setblock(fs, cp, h) + struct fs *fs; + unsigned char *cp; + ufs1_daddr_t h; +{ + + switch ((int)fs->fs_frag) { + + case 8: + cp[h] = 0xff; + return; + case 4: + cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); + return; + case 2: + cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); + return; + case 1: + cp[h >> 3] |= (0x01 << (h & 0x7)); + return; + default: +#ifdef _KERNEL + panic("ffs_setblock"); +#endif + break; + } +} + +/* + * Update the cluster map because of an allocation or free. + * + * Cnt == 1 means free; cnt == -1 means allocating. + */ +void +ffs_clusteracct(fs, cgp, blkno, cnt) + struct fs *fs; + struct cg *cgp; + ufs1_daddr_t blkno; + int cnt; +{ + int32_t *sump; + int32_t *lp; + u_char *freemapp, *mapp; + int i, start, end, forw, back, map, bit; + + if (fs->fs_contigsumsize <= 0) + return; + freemapp = cg_clustersfree(cgp); + sump = cg_clustersum(cgp); + /* + * Allocate or clear the actual block. + */ + if (cnt > 0) + setbit(freemapp, blkno); + else + clrbit(freemapp, blkno); + /* + * Find the size of the cluster going forward. + */ + start = blkno + 1; + end = start + fs->fs_contigsumsize; + if (end >= cgp->cg_nclusterblks) + end = cgp->cg_nclusterblks; + mapp = &freemapp[start / NBBY]; + map = *mapp++; + bit = 1 << (start % NBBY); + for (i = start; i < end; i++) { + if ((map & bit) == 0) + break; + if ((i & (NBBY - 1)) != (NBBY - 1)) { + bit <<= 1; + } else { + map = *mapp++; + bit = 1; + } + } + forw = i - start; + /* + * Find the size of the cluster going backward. + */ + start = blkno - 1; + end = start - fs->fs_contigsumsize; + if (end < 0) + end = -1; + mapp = &freemapp[start / NBBY]; + map = *mapp--; + bit = 1 << (start % NBBY); + for (i = start; i > end; i--) { + if ((map & bit) == 0) + break; + if ((i & (NBBY - 1)) != 0) { + bit >>= 1; + } else { + map = *mapp--; + bit = 1 << (NBBY - 1); + } + } + back = start - i; + /* + * Account for old cluster and the possibly new forward and + * back clusters. + */ + i = back + forw + 1; + if (i > fs->fs_contigsumsize) + i = fs->fs_contigsumsize; + sump[i] += cnt; + if (back > 0) + sump[back] -= cnt; + if (forw > 0) + sump[forw] -= cnt; + /* + * Update cluster summary information. + */ + lp = &sump[fs->fs_contigsumsize]; + for (i = fs->fs_contigsumsize; i > 0; i--) + if (*lp-- > 0) + break; + fs->fs_maxcluster[cgp->cg_cgx] = i; +} diff --git a/Dump/ufs/ffs/ffs_suspend.c b/Dump/ufs/ffs/ffs_suspend.c new file mode 100644 index 0000000..a714c1f --- /dev/null +++ b/Dump/ufs/ffs/ffs_suspend.c @@ -0,0 +1,337 @@ +/*- + * Copyright (c) 2012 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Edward Tomasz Napierala under sponsorship + * from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: releng/11.2/sys/ufs/ffs/ffs_suspend.c 306165 2016-09-22 08:56:54Z kib $ + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_suspend.c 306165 2016-09-22 08:56:54Z kib $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +static d_open_t ffs_susp_open; +static d_write_t ffs_susp_rdwr; +static d_ioctl_t ffs_susp_ioctl; + +static struct cdevsw ffs_susp_cdevsw = { + .d_version = D_VERSION, + .d_open = ffs_susp_open, + .d_read = ffs_susp_rdwr, + .d_write = ffs_susp_rdwr, + .d_ioctl = ffs_susp_ioctl, + .d_name = "ffs_susp", +}; + +static struct cdev *ffs_susp_dev; +static struct sx ffs_susp_lock; + +static int +ffs_susp_suspended(struct mount *mp) +{ + struct ufsmount *ump; + + sx_assert(&ffs_susp_lock, SA_LOCKED); + + ump = VFSTOUFS(mp); + if (ump->um_writesuspended) + return (1); + return (0); +} + +static int +ffs_susp_open(struct cdev *dev __unused, int flags __unused, + int fmt __unused, struct thread *td __unused) +{ + + return (0); +} + +static int +ffs_susp_rdwr(struct cdev *dev, struct uio *uio, int ioflag) +{ + int error, i; + struct vnode *devvp; + struct mount *mp; + struct ufsmount *ump; + struct buf *bp; + void *base; + size_t len; + ssize_t cnt; + struct fs *fs; + + sx_slock(&ffs_susp_lock); + + error = devfs_get_cdevpriv((void **)&mp); + if (error != 0) { + sx_sunlock(&ffs_susp_lock); + return (ENXIO); + } + + ump = VFSTOUFS(mp); + devvp = ump->um_devvp; + fs = ump->um_fs; + + if (ffs_susp_suspended(mp) == 0) { + sx_sunlock(&ffs_susp_lock); + return (ENXIO); + } + + KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE, + ("neither UIO_READ or UIO_WRITE")); + KASSERT(uio->uio_segflg == UIO_USERSPACE, + ("uio->uio_segflg != UIO_USERSPACE")); + + cnt = uio->uio_resid; + + for (i = 0; i < uio->uio_iovcnt; i++) { + while (uio->uio_iov[i].iov_len) { + base = uio->uio_iov[i].iov_base; + len = uio->uio_iov[i].iov_len; + if (len > fs->fs_bsize) + len = fs->fs_bsize; + if (fragoff(fs, uio->uio_offset) != 0 || + fragoff(fs, len) != 0) { + error = EINVAL; + goto out; + } + error = bread(devvp, btodb(uio->uio_offset), len, + NOCRED, &bp); + if (error != 0) + goto out; + if (uio->uio_rw == UIO_WRITE) { + error = copyin(base, bp->b_data, len); + if (error != 0) { + bp->b_flags |= B_INVAL | B_NOCACHE; + brelse(bp); + goto out; + } + error = bwrite(bp); + if (error != 0) + goto out; + } else { + error = copyout(bp->b_data, base, len); + brelse(bp); + if (error != 0) + goto out; + } + uio->uio_iov[i].iov_base = + (char *)uio->uio_iov[i].iov_base + len; + uio->uio_iov[i].iov_len -= len; + uio->uio_resid -= len; + uio->uio_offset += len; + } + } + +out: + sx_sunlock(&ffs_susp_lock); + + if (uio->uio_resid < cnt) + return (0); + + return (error); +} + +static int +ffs_susp_suspend(struct mount *mp) +{ + struct ufsmount *ump; + int error; + + sx_assert(&ffs_susp_lock, SA_XLOCKED); + + if (!ffs_own_mount(mp)) + return (EINVAL); + if (ffs_susp_suspended(mp)) + return (EBUSY); + + ump = VFSTOUFS(mp); + + /* + * Make sure the calling thread is permitted to access the mounted + * device. The permissions can change after we unlock the vnode; + * it's harmless. + */ + vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_ACCESS(ump->um_devvp, VREAD | VWRITE, + curthread->td_ucred, curthread); + VOP_UNLOCK(ump->um_devvp, 0); + if (error != 0) + return (error); +#ifdef MAC + if (mac_mount_check_stat(curthread->td_ucred, mp) != 0) + return (EPERM); +#endif + + if ((error = vfs_write_suspend(mp, VS_SKIP_UNMOUNT)) != 0) + return (error); + + ump->um_writesuspended = 1; + + return (0); +} + +static void +ffs_susp_dtor(void *data) +{ + struct fs *fs; + struct ufsmount *ump; + struct mount *mp; + int error; + + sx_xlock(&ffs_susp_lock); + + mp = (struct mount *)data; + ump = VFSTOUFS(mp); + fs = ump->um_fs; + + if (ffs_susp_suspended(mp) == 0) { + sx_xunlock(&ffs_susp_lock); + return; + } + + KASSERT((mp->mnt_kern_flag & MNTK_SUSPEND) != 0, + ("MNTK_SUSPEND not set")); + + error = ffs_reload(mp, curthread, FFSR_FORCE | FFSR_UNSUSPEND); + if (error != 0) + panic("failed to unsuspend writes on %s", fs->fs_fsmnt); + + /* + * XXX: The status is kept per-process; the vfs_write_resume() routine + * asserts that the resuming thread is the same one that called + * vfs_write_suspend(). The cdevpriv data, however, is attached + * to the file descriptor, e.g. is inherited during fork. Thus, + * it's possible that the resuming process will be different from + * the one that started the suspension. + * + * Work around by fooling the check in vfs_write_resume(). + */ + mp->mnt_susp_owner = curthread; + + vfs_write_resume(mp, 0); + vfs_unbusy(mp); + ump->um_writesuspended = 0; + + sx_xunlock(&ffs_susp_lock); +} + +static int +ffs_susp_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, + struct thread *td) +{ + struct mount *mp; + fsid_t *fsidp; + int error; + + /* + * No suspend inside the jail. Allowing it would require making + * sure that e.g. the devfs ruleset for that jail permits access + * to the devvp. + */ + if (jailed(td->td_ucred)) + return (EPERM); + + sx_xlock(&ffs_susp_lock); + + switch (cmd) { + case UFSSUSPEND: + fsidp = (fsid_t *)addr; + mp = vfs_getvfs(fsidp); + if (mp == NULL) { + error = ENOENT; + break; + } + error = vfs_busy(mp, 0); + vfs_rel(mp); + if (error != 0) + break; + error = ffs_susp_suspend(mp); + if (error != 0) { + vfs_unbusy(mp); + break; + } + error = devfs_set_cdevpriv(mp, ffs_susp_dtor); + KASSERT(error == 0, ("devfs_set_cdevpriv failed")); + break; + case UFSRESUME: + error = devfs_get_cdevpriv((void **)&mp); + if (error != 0) + break; + /* + * This calls ffs_susp_dtor, which in turn unsuspends the fs. + * The dtor expects to be called without lock held, because + * sometimes it's called from here, and sometimes due to the + * file being closed or process exiting. + */ + sx_xunlock(&ffs_susp_lock); + devfs_clear_cdevpriv(); + return (0); + default: + error = ENXIO; + break; + } + + sx_xunlock(&ffs_susp_lock); + + return (error); +} + +void +ffs_susp_initialize(void) +{ + + sx_init(&ffs_susp_lock, "ffs_susp"); + ffs_susp_dev = make_dev(&ffs_susp_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, + "ufssuspend"); +} + +void +ffs_susp_uninitialize(void) +{ + + destroy_dev(ffs_susp_dev); + sx_destroy(&ffs_susp_lock); +} diff --git a/Dump/ufs/ffs/ffs_tables.c b/Dump/ufs/ffs/ffs_tables.c new file mode 100644 index 0000000..ea4b15b --- /dev/null +++ b/Dump/ufs/ffs/ffs_tables.c @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_tables.c 8.1 (Berkeley) 6/11/93 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_tables.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include +#include +#include + +/* + * Bit patterns for identifying fragments in the block map + * used as ((map & around) == inside) + */ +int around[9] = { + 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff +}; +int inside[9] = { + 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe +}; + +/* + * Given a block map bit pattern, the frag tables tell whether a + * particular size fragment is available. + * + * used as: + * if ((1 << (size - 1)) & fragtbl[fs->fs_frag][map] { + * at least one fragment of the indicated size is available + * } + * + * These tables are used by the scanc instruction on the VAX to + * quickly find an appropriate fragment. + */ +static u_char fragtbl124[256] = { + 0x00, 0x16, 0x16, 0x2a, 0x16, 0x16, 0x26, 0x4e, + 0x16, 0x16, 0x16, 0x3e, 0x2a, 0x3e, 0x4e, 0x8a, + 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e, + 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e, + 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e, + 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e, + 0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa, + 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e, + 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e, + 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e, + 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e, + 0x26, 0x36, 0x36, 0x2e, 0x36, 0x36, 0x26, 0x6e, + 0x36, 0x36, 0x36, 0x3e, 0x2e, 0x3e, 0x6e, 0xae, + 0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e, + 0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce, + 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e, + 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e, + 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e, + 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e, + 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e, + 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe, + 0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe, + 0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e, + 0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce, + 0x8a, 0x9e, 0x9e, 0xaa, 0x9e, 0x9e, 0xae, 0xce, + 0x9e, 0x9e, 0x9e, 0xbe, 0xaa, 0xbe, 0xce, 0x8a, +}; + +static u_char fragtbl8[256] = { + 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, + 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, + 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, + 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, + 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, + 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11, + 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, + 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, + 0x08, 0x09, 0x09, 0x0a, 0x10, 0x11, 0x20, 0x40, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, + 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, + 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11, + 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, + 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, + 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21, + 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, + 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, + 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0a, 0x12, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, + 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0c, + 0x08, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x0a, 0x0c, + 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80, +}; + +/* + * The actual fragtbl array. + */ +u_char *fragtbl[MAXFRAG + 1] = { + 0, fragtbl124, fragtbl124, 0, fragtbl124, 0, 0, 0, fragtbl8, +}; diff --git a/Dump/ufs/ffs/ffs_vfsops.c b/Dump/ufs/ffs/ffs_vfsops.c new file mode 100644 index 0000000..b3d822a --- /dev/null +++ b/Dump/ufs/ffs/ffs_vfsops.c @@ -0,0 +1,2289 @@ +/*- + * Copyright (c) 1989, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ffs_vfsops.c 8.31 (Berkeley) 5/20/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_vfsops.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include "opt_quota.h" +#include "opt_ufs.h" +#include "opt_ffs.h" +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +static uma_zone_t uma_inode, uma_ufs1, uma_ufs2; + +static int ffs_mountfs(struct vnode *, struct mount *, struct thread *); +static void ffs_oldfscompat_read(struct fs *, struct ufsmount *, + ufs2_daddr_t); +static void ffs_ifree(struct ufsmount *ump, struct inode *ip); +static int ffs_sync_lazy(struct mount *mp); + +static vfs_init_t ffs_init; +static vfs_uninit_t ffs_uninit; +static vfs_extattrctl_t ffs_extattrctl; +static vfs_cmount_t ffs_cmount; +static vfs_unmount_t ffs_unmount; +static vfs_mount_t ffs_mount; +static vfs_statfs_t ffs_statfs; +static vfs_fhtovp_t ffs_fhtovp; +static vfs_sync_t ffs_sync; + +static struct vfsops ufs_vfsops = { + .vfs_extattrctl = ffs_extattrctl, + .vfs_fhtovp = ffs_fhtovp, + .vfs_init = ffs_init, + .vfs_mount = ffs_mount, + .vfs_cmount = ffs_cmount, + .vfs_quotactl = ufs_quotactl, + .vfs_root = ufs_root, + .vfs_statfs = ffs_statfs, + .vfs_sync = ffs_sync, + .vfs_uninit = ffs_uninit, + .vfs_unmount = ffs_unmount, + .vfs_vget = ffs_vget, + .vfs_susp_clean = process_deferred_inactive, +}; + +VFS_SET(ufs_vfsops, ufs, 0); +MODULE_VERSION(ufs, 1); + +static b_strategy_t ffs_geom_strategy; +static b_write_t ffs_bufwrite; + +static struct buf_ops ffs_ops = { + .bop_name = "FFS", + .bop_write = ffs_bufwrite, + .bop_strategy = ffs_geom_strategy, + .bop_sync = bufsync, +#ifdef NO_FFS_SNAPSHOT + .bop_bdflush = bufbdflush, +#else + .bop_bdflush = ffs_bdflush, +#endif +}; + +/* + * Note that userquota and groupquota options are not currently used + * by UFS/FFS code and generally mount(8) does not pass those options + * from userland, but they can be passed by loader(8) via + * vfs.root.mountfrom.options. + */ +static const char *ffs_opts[] = { "acls", "async", "noatime", "noclusterr", + "noclusterw", "noexec", "export", "force", "from", "groupquota", + "multilabel", "nfsv4acls", "fsckpid", "snapshot", "nosuid", "suiddir", + "nosymfollow", "sync", "union", "userquota", NULL }; + +static int +ffs_mount(struct mount *mp) +{ + struct vnode *devvp; + struct thread *td; + struct ufsmount *ump = NULL; + struct fs *fs; + pid_t fsckpid = 0; + int error, error1, flags; + uint64_t mntorflags; + accmode_t accmode; + struct nameidata ndp; + char *fspec; + + td = curthread; + if (vfs_filteropt(mp->mnt_optnew, ffs_opts)) + return (EINVAL); + if (uma_inode == NULL) { + uma_inode = uma_zcreate("FFS inode", + sizeof(struct inode), NULL, NULL, NULL, NULL, + UMA_ALIGN_PTR, 0); + uma_ufs1 = uma_zcreate("FFS1 dinode", + sizeof(struct ufs1_dinode), NULL, NULL, NULL, NULL, + UMA_ALIGN_PTR, 0); + uma_ufs2 = uma_zcreate("FFS2 dinode", + sizeof(struct ufs2_dinode), NULL, NULL, NULL, NULL, + UMA_ALIGN_PTR, 0); + } + + vfs_deleteopt(mp->mnt_optnew, "groupquota"); + vfs_deleteopt(mp->mnt_optnew, "userquota"); + + fspec = vfs_getopts(mp->mnt_optnew, "from", &error); + if (error) + return (error); + + mntorflags = 0; + if (vfs_getopt(mp->mnt_optnew, "acls", NULL, NULL) == 0) + mntorflags |= MNT_ACLS; + + if (vfs_getopt(mp->mnt_optnew, "snapshot", NULL, NULL) == 0) { + mntorflags |= MNT_SNAPSHOT; + /* + * Once we have set the MNT_SNAPSHOT flag, do not + * persist "snapshot" in the options list. + */ + vfs_deleteopt(mp->mnt_optnew, "snapshot"); + vfs_deleteopt(mp->mnt_opt, "snapshot"); + } + + if (vfs_getopt(mp->mnt_optnew, "fsckpid", NULL, NULL) == 0 && + vfs_scanopt(mp->mnt_optnew, "fsckpid", "%d", &fsckpid) == 1) { + /* + * Once we have set the restricted PID, do not + * persist "fsckpid" in the options list. + */ + vfs_deleteopt(mp->mnt_optnew, "fsckpid"); + vfs_deleteopt(mp->mnt_opt, "fsckpid"); + if (mp->mnt_flag & MNT_UPDATE) { + if (VFSTOUFS(mp)->um_fs->fs_ronly == 0 && + vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0) == 0) { + vfs_mount_error(mp, + "Checker enable: Must be read-only"); + return (EINVAL); + } + } else if (vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0) == 0) { + vfs_mount_error(mp, + "Checker enable: Must be read-only"); + return (EINVAL); + } + /* Set to -1 if we are done */ + if (fsckpid == 0) + fsckpid = -1; + } + + if (vfs_getopt(mp->mnt_optnew, "nfsv4acls", NULL, NULL) == 0) { + if (mntorflags & MNT_ACLS) { + vfs_mount_error(mp, + "\"acls\" and \"nfsv4acls\" options " + "are mutually exclusive"); + return (EINVAL); + } + mntorflags |= MNT_NFS4ACLS; + } + + MNT_ILOCK(mp); + mp->mnt_flag |= mntorflags; + MNT_IUNLOCK(mp); + /* + * If updating, check whether changing from read-only to + * read/write; if there is no device name, that's all we do. + */ + if (mp->mnt_flag & MNT_UPDATE) { + ump = VFSTOUFS(mp); + fs = ump->um_fs; + devvp = ump->um_devvp; + if (fsckpid == -1 && ump->um_fsckpid > 0) { + if ((error = ffs_flushfiles(mp, WRITECLOSE, td)) != 0 || + (error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) + return (error); + g_topology_lock(); + /* + * Return to normal read-only mode. + */ + error = g_access(ump->um_cp, 0, -1, 0); + g_topology_unlock(); + ump->um_fsckpid = 0; + } + if (fs->fs_ronly == 0 && + vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { + /* + * Flush any dirty data and suspend filesystem. + */ + if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) + return (error); + error = vfs_write_suspend_umnt(mp); + if (error != 0) + return (error); + /* + * Check for and optionally get rid of files open + * for writing. + */ + flags = WRITECLOSE; + if (mp->mnt_flag & MNT_FORCE) + flags |= FORCECLOSE; + if (MOUNTEDSOFTDEP(mp)) { + error = softdep_flushfiles(mp, flags, td); + } else { + error = ffs_flushfiles(mp, flags, td); + } + if (error) { + vfs_write_resume(mp, 0); + return (error); + } + if (fs->fs_pendingblocks != 0 || + fs->fs_pendinginodes != 0) { + printf("WARNING: %s Update error: blocks %jd " + "files %d\n", fs->fs_fsmnt, + (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); + fs->fs_pendingblocks = 0; + fs->fs_pendinginodes = 0; + } + if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) + fs->fs_clean = 1; + if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) { + fs->fs_ronly = 0; + fs->fs_clean = 0; + vfs_write_resume(mp, 0); + return (error); + } + if (MOUNTEDSOFTDEP(mp)) + softdep_unmount(mp); + g_topology_lock(); + /* + * Drop our write and exclusive access. + */ + g_access(ump->um_cp, 0, -1, -1); + g_topology_unlock(); + fs->fs_ronly = 1; + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_RDONLY; + MNT_IUNLOCK(mp); + /* + * Allow the writers to note that filesystem + * is ro now. + */ + vfs_write_resume(mp, 0); + } + if ((mp->mnt_flag & MNT_RELOAD) && + (error = ffs_reload(mp, td, 0)) != 0) + return (error); + if (fs->fs_ronly && + !vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { + /* + * If we are running a checker, do not allow upgrade. + */ + if (ump->um_fsckpid > 0) { + vfs_mount_error(mp, + "Active checker, cannot upgrade to write"); + return (EINVAL); + } + /* + * If upgrade to read-write by non-root, then verify + * that user has necessary permissions on the device. + */ + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_ACCESS(devvp, VREAD | VWRITE, + td->td_ucred, td); + if (error) + error = priv_check(td, PRIV_VFS_MOUNT_PERM); + if (error) { + VOP_UNLOCK(devvp, 0); + return (error); + } + VOP_UNLOCK(devvp, 0); + fs->fs_flags &= ~FS_UNCLEAN; + if (fs->fs_clean == 0) { + fs->fs_flags |= FS_UNCLEAN; + if ((mp->mnt_flag & MNT_FORCE) || + ((fs->fs_flags & + (FS_SUJ | FS_NEEDSFSCK)) == 0 && + (fs->fs_flags & FS_DOSOFTDEP))) { + printf("WARNING: %s was not properly " + "dismounted\n", fs->fs_fsmnt); + } else { + vfs_mount_error(mp, + "R/W mount of %s denied. %s.%s", + fs->fs_fsmnt, + "Filesystem is not clean - run fsck", + (fs->fs_flags & FS_SUJ) == 0 ? "" : + " Forced mount will invalidate" + " journal contents"); + return (EPERM); + } + } + g_topology_lock(); + /* + * Request exclusive write access. + */ + error = g_access(ump->um_cp, 0, 1, 1); + g_topology_unlock(); + if (error) + return (error); + if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0) + return (error); + fs->fs_ronly = 0; + MNT_ILOCK(mp); + mp->mnt_flag &= ~MNT_RDONLY; + MNT_IUNLOCK(mp); + fs->fs_mtime = time_second; + /* check to see if we need to start softdep */ + if ((fs->fs_flags & FS_DOSOFTDEP) && + (error = softdep_mount(devvp, mp, fs, td->td_ucred))){ + vn_finished_write(mp); + return (error); + } + fs->fs_clean = 0; + if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) { + vn_finished_write(mp); + return (error); + } + if (fs->fs_snapinum[0] != 0) + ffs_snapshot_mount(mp); + vn_finished_write(mp); + } + /* + * Soft updates is incompatible with "async", + * so if we are doing softupdates stop the user + * from setting the async flag in an update. + * Softdep_mount() clears it in an initial mount + * or ro->rw remount. + */ + if (MOUNTEDSOFTDEP(mp)) { + /* XXX: Reset too late ? */ + MNT_ILOCK(mp); + mp->mnt_flag &= ~MNT_ASYNC; + MNT_IUNLOCK(mp); + } + /* + * Keep MNT_ACLS flag if it is stored in superblock. + */ + if ((fs->fs_flags & FS_ACLS) != 0) { + /* XXX: Set too late ? */ + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_ACLS; + MNT_IUNLOCK(mp); + } + + if ((fs->fs_flags & FS_NFS4ACLS) != 0) { + /* XXX: Set too late ? */ + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_NFS4ACLS; + MNT_IUNLOCK(mp); + } + /* + * If this is a request from fsck to clean up the filesystem, + * then allow the specified pid to proceed. + */ + if (fsckpid > 0) { + if (ump->um_fsckpid != 0) { + vfs_mount_error(mp, + "Active checker already running on %s", + fs->fs_fsmnt); + return (EINVAL); + } + KASSERT(MOUNTEDSOFTDEP(mp) == 0, + ("soft updates enabled on read-only file system")); + g_topology_lock(); + /* + * Request write access. + */ + error = g_access(ump->um_cp, 0, 1, 0); + g_topology_unlock(); + if (error) { + vfs_mount_error(mp, + "Checker activation failed on %s", + fs->fs_fsmnt); + return (error); + } + ump->um_fsckpid = fsckpid; + if (fs->fs_snapinum[0] != 0) + ffs_snapshot_mount(mp); + fs->fs_mtime = time_second; + fs->fs_fmod = 1; + fs->fs_clean = 0; + (void) ffs_sbupdate(ump, MNT_WAIT, 0); + } + + /* + * If this is a snapshot request, take the snapshot. + */ + if (mp->mnt_flag & MNT_SNAPSHOT) + return (ffs_snapshot(mp, fspec)); + + /* + * Must not call namei() while owning busy ref. + */ + vfs_unbusy(mp); + } + + /* + * Not an update, or updating the name: look up the name + * and verify that it refers to a sensible disk device. + */ + NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td); + error = namei(&ndp); + if ((mp->mnt_flag & MNT_UPDATE) != 0) { + /* + * Unmount does not start if MNT_UPDATE is set. Mount + * update busies mp before setting MNT_UPDATE. We + * must be able to retain our busy ref succesfully, + * without sleep. + */ + error1 = vfs_busy(mp, MBF_NOWAIT); + MPASS(error1 == 0); + } + if (error != 0) + return (error); + NDFREE(&ndp, NDF_ONLY_PNBUF); + devvp = ndp.ni_vp; + if (!vn_isdisk(devvp, &error)) { + vput(devvp); + return (error); + } + + /* + * If mount by non-root, then verify that user has necessary + * permissions on the device. + */ + accmode = VREAD; + if ((mp->mnt_flag & MNT_RDONLY) == 0) + accmode |= VWRITE; + error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); + if (error) + error = priv_check(td, PRIV_VFS_MOUNT_PERM); + if (error) { + vput(devvp); + return (error); + } + + if (mp->mnt_flag & MNT_UPDATE) { + /* + * Update only + * + * If it's not the same vnode, or at least the same device + * then it's not correct. + */ + + if (devvp->v_rdev != ump->um_devvp->v_rdev) + error = EINVAL; /* needs translation */ + vput(devvp); + if (error) + return (error); + } else { + /* + * New mount + * + * We need the name for the mount point (also used for + * "last mounted on") copied in. If an error occurs, + * the mount point is discarded by the upper level code. + * Note that vfs_mount_alloc() populates f_mntonname for us. + */ + if ((error = ffs_mountfs(devvp, mp, td)) != 0) { + vrele(devvp); + return (error); + } + if (fsckpid > 0) { + KASSERT(MOUNTEDSOFTDEP(mp) == 0, + ("soft updates enabled on read-only file system")); + ump = VFSTOUFS(mp); + fs = ump->um_fs; + g_topology_lock(); + /* + * Request write access. + */ + error = g_access(ump->um_cp, 0, 1, 0); + g_topology_unlock(); + if (error) { + printf("WARNING: %s: Checker activation " + "failed\n", fs->fs_fsmnt); + } else { + ump->um_fsckpid = fsckpid; + if (fs->fs_snapinum[0] != 0) + ffs_snapshot_mount(mp); + fs->fs_mtime = time_second; + fs->fs_clean = 0; + (void) ffs_sbupdate(ump, MNT_WAIT, 0); + } + } + } + vfs_mountedfrom(mp, fspec); + return (0); +} + +/* + * Compatibility with old mount system call. + */ + +static int +ffs_cmount(struct mntarg *ma, void *data, uint64_t flags) +{ + struct ufs_args args; + struct export_args exp; + int error; + + if (data == NULL) + return (EINVAL); + error = copyin(data, &args, sizeof args); + if (error) + return (error); + vfs_oexport_conv(&args.export, &exp); + + ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); + ma = mount_arg(ma, "export", &exp, sizeof(exp)); + error = kernel_mount(ma, flags); + + return (error); +} + +/* + * Reload all incore data for a filesystem (used after running fsck on + * the root filesystem and finding things to fix). If the 'force' flag + * is 0, the filesystem must be mounted read-only. + * + * Things to do to update the mount: + * 1) invalidate all cached meta-data. + * 2) re-read superblock from disk. + * 3) re-read summary information from disk. + * 4) invalidate all inactive vnodes. + * 5) clear MNTK_SUSPEND2 and MNTK_SUSPENDED flags, allowing secondary + * writers, if requested. + * 6) invalidate all cached file data. + * 7) re-read inode data for all active vnodes. + */ +int +ffs_reload(struct mount *mp, struct thread *td, int flags) +{ + struct vnode *vp, *mvp, *devvp; + struct inode *ip; + void *space; + struct buf *bp; + struct fs *fs, *newfs; + struct ufsmount *ump; + ufs2_daddr_t sblockloc; + int i, blks, error; + u_long size; + int32_t *lp; + + ump = VFSTOUFS(mp); + + MNT_ILOCK(mp); + if ((mp->mnt_flag & MNT_RDONLY) == 0 && (flags & FFSR_FORCE) == 0) { + MNT_IUNLOCK(mp); + return (EINVAL); + } + MNT_IUNLOCK(mp); + + /* + * Step 1: invalidate all cached meta-data. + */ + devvp = VFSTOUFS(mp)->um_devvp; + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); + if (vinvalbuf(devvp, 0, 0, 0) != 0) + panic("ffs_reload: dirty1"); + VOP_UNLOCK(devvp, 0); + + /* + * Step 2: re-read superblock from disk. + */ + fs = VFSTOUFS(mp)->um_fs; + if ((error = bread(devvp, btodb(fs->fs_sblockloc), fs->fs_sbsize, + NOCRED, &bp)) != 0) + return (error); + newfs = (struct fs *)bp->b_data; + if ((newfs->fs_magic != FS_UFS1_MAGIC && + newfs->fs_magic != FS_UFS2_MAGIC) || + newfs->fs_bsize > MAXBSIZE || + newfs->fs_bsize < sizeof(struct fs)) { + brelse(bp); + return (EIO); /* XXX needs translation */ + } + /* + * Copy pointer fields back into superblock before copying in XXX + * new superblock. These should really be in the ufsmount. XXX + * Note that important parameters (eg fs_ncg) are unchanged. + */ + newfs->fs_csp = fs->fs_csp; + newfs->fs_maxcluster = fs->fs_maxcluster; + newfs->fs_contigdirs = fs->fs_contigdirs; + newfs->fs_active = fs->fs_active; + newfs->fs_ronly = fs->fs_ronly; + sblockloc = fs->fs_sblockloc; + bcopy(newfs, fs, (u_int)fs->fs_sbsize); + brelse(bp); + mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; + ffs_oldfscompat_read(fs, VFSTOUFS(mp), sblockloc); + UFS_LOCK(ump); + if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { + printf("WARNING: %s: reload pending error: blocks %jd " + "files %d\n", fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); + fs->fs_pendingblocks = 0; + fs->fs_pendinginodes = 0; + } + UFS_UNLOCK(ump); + + /* + * Step 3: re-read summary information from disk. + */ + size = fs->fs_cssize; + blks = howmany(size, fs->fs_fsize); + if (fs->fs_contigsumsize > 0) + size += fs->fs_ncg * sizeof(int32_t); + size += fs->fs_ncg * sizeof(u_int8_t); + free(fs->fs_csp, M_UFSMNT); + space = malloc(size, M_UFSMNT, M_WAITOK); + fs->fs_csp = space; + for (i = 0; i < blks; i += fs->fs_frag) { + size = fs->fs_bsize; + if (i + fs->fs_frag > blks) + size = (blks - i) * fs->fs_fsize; + error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, + NOCRED, &bp); + if (error) + return (error); + bcopy(bp->b_data, space, (u_int)size); + space = (char *)space + size; + brelse(bp); + } + /* + * We no longer know anything about clusters per cylinder group. + */ + if (fs->fs_contigsumsize > 0) { + fs->fs_maxcluster = lp = space; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + space = lp; + } + size = fs->fs_ncg * sizeof(u_int8_t); + fs->fs_contigdirs = (u_int8_t *)space; + bzero(fs->fs_contigdirs, size); + if ((flags & FFSR_UNSUSPEND) != 0) { + MNT_ILOCK(mp); + mp->mnt_kern_flag &= ~(MNTK_SUSPENDED | MNTK_SUSPEND2); + wakeup(&mp->mnt_flag); + MNT_IUNLOCK(mp); + } + +loop: + MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { + /* + * Skip syncer vnode. + */ + if (vp->v_type == VNON) { + VI_UNLOCK(vp); + continue; + } + /* + * Step 4: invalidate all cached file data. + */ + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + goto loop; + } + if (vinvalbuf(vp, 0, 0, 0)) + panic("ffs_reload: dirty2"); + /* + * Step 5: re-read inode data for all active vnodes. + */ + ip = VTOI(vp); + error = + bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), + (int)fs->fs_bsize, NOCRED, &bp); + if (error) { + VOP_UNLOCK(vp, 0); + vrele(vp); + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + return (error); + } + ffs_load_inode(bp, ip, fs, ip->i_number); + ip->i_effnlink = ip->i_nlink; + brelse(bp); + VOP_UNLOCK(vp, 0); + vrele(vp); + } + return (0); +} + +/* + * Possible superblock locations ordered from most to least likely. + */ +static int sblock_try[] = SBLOCKSEARCH; + +/* + * Common code for mount and mountroot + */ +static int +ffs_mountfs(devvp, mp, td) + struct vnode *devvp; + struct mount *mp; + struct thread *td; +{ + struct ufsmount *ump; + struct buf *bp; + struct fs *fs; + struct cdev *dev; + void *space; + ufs2_daddr_t sblockloc; + int error, i, blks, len, ronly; + u_long size; + int32_t *lp; + struct ucred *cred; + struct g_consumer *cp; + struct mount *nmp; + + bp = NULL; + ump = NULL; + cred = td ? td->td_ucred : NOCRED; + ronly = (mp->mnt_flag & MNT_RDONLY) != 0; + + KASSERT(devvp->v_type == VCHR, ("reclaimed devvp")); + dev = devvp->v_rdev; + if (atomic_cmpset_acq_ptr((uintptr_t *)&dev->si_mountpt, 0, + (uintptr_t)mp) == 0) { + VOP_UNLOCK(devvp, 0); + return (EBUSY); + } + g_topology_lock(); + error = g_vfs_open(devvp, &cp, "ffs", ronly ? 0 : 1); + g_topology_unlock(); + if (error != 0) { + atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); + VOP_UNLOCK(devvp, 0); + return (error); + } + dev_ref(dev); + devvp->v_bufobj.bo_ops = &ffs_ops; + VOP_UNLOCK(devvp, 0); + if (dev->si_iosize_max != 0) + mp->mnt_iosize_max = dev->si_iosize_max; + if (mp->mnt_iosize_max > MAXPHYS) + mp->mnt_iosize_max = MAXPHYS; + + fs = NULL; + sblockloc = 0; + /* + * Try reading the superblock in each of its possible locations. + */ + for (i = 0; sblock_try[i] != -1; i++) { + if ((SBLOCKSIZE % cp->provider->sectorsize) != 0) { + error = EINVAL; + vfs_mount_error(mp, + "Invalid sectorsize %d for superblock size %d", + cp->provider->sectorsize, SBLOCKSIZE); + goto out; + } + if ((error = bread(devvp, btodb(sblock_try[i]), SBLOCKSIZE, + cred, &bp)) != 0) + goto out; + fs = (struct fs *)bp->b_data; + sblockloc = sblock_try[i]; + if ((fs->fs_magic == FS_UFS1_MAGIC || + (fs->fs_magic == FS_UFS2_MAGIC && + (fs->fs_sblockloc == sblockloc || + (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0))) && + fs->fs_bsize <= MAXBSIZE && + fs->fs_bsize >= sizeof(struct fs)) + break; + brelse(bp); + bp = NULL; + } + if (sblock_try[i] == -1) { + error = EINVAL; /* XXX needs translation */ + goto out; + } + fs->fs_fmod = 0; + fs->fs_flags &= ~FS_INDEXDIRS; /* no support for directory indices */ + fs->fs_flags &= ~FS_UNCLEAN; + if (fs->fs_clean == 0) { + fs->fs_flags |= FS_UNCLEAN; + if (ronly || (mp->mnt_flag & MNT_FORCE) || + ((fs->fs_flags & (FS_SUJ | FS_NEEDSFSCK)) == 0 && + (fs->fs_flags & FS_DOSOFTDEP))) { + printf("WARNING: %s was not properly dismounted\n", + fs->fs_fsmnt); + } else { + vfs_mount_error(mp, "R/W mount of %s denied. %s%s", + fs->fs_fsmnt, "Filesystem is not clean - run fsck.", + (fs->fs_flags & FS_SUJ) == 0 ? "" : + " Forced mount will invalidate journal contents"); + error = EPERM; + goto out; + } + if ((fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) && + (mp->mnt_flag & MNT_FORCE)) { + printf("WARNING: %s: lost blocks %jd files %d\n", + fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); + fs->fs_pendingblocks = 0; + fs->fs_pendinginodes = 0; + } + } + if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { + printf("WARNING: %s: mount pending error: blocks %jd " + "files %d\n", fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); + fs->fs_pendingblocks = 0; + fs->fs_pendinginodes = 0; + } + if ((fs->fs_flags & FS_GJOURNAL) != 0) { +#ifdef UFS_GJOURNAL + /* + * Get journal provider name. + */ + len = 1024; + mp->mnt_gjprovider = malloc((u_long)len, M_UFSMNT, M_WAITOK); + if (g_io_getattr("GJOURNAL::provider", cp, &len, + mp->mnt_gjprovider) == 0) { + mp->mnt_gjprovider = realloc(mp->mnt_gjprovider, len, + M_UFSMNT, M_WAITOK); + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_GJOURNAL; + MNT_IUNLOCK(mp); + } else { + printf("WARNING: %s: GJOURNAL flag on fs " + "but no gjournal provider below\n", + mp->mnt_stat.f_mntonname); + free(mp->mnt_gjprovider, M_UFSMNT); + mp->mnt_gjprovider = NULL; + } +#else + printf("WARNING: %s: GJOURNAL flag on fs but no " + "UFS_GJOURNAL support\n", mp->mnt_stat.f_mntonname); +#endif + } else { + mp->mnt_gjprovider = NULL; + } + ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO); + ump->um_cp = cp; + ump->um_bo = &devvp->v_bufobj; + ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, M_WAITOK); + if (fs->fs_magic == FS_UFS1_MAGIC) { + ump->um_fstype = UFS1; + ump->um_balloc = ffs_balloc_ufs1; + } else { + ump->um_fstype = UFS2; + ump->um_balloc = ffs_balloc_ufs2; + } + ump->um_blkatoff = ffs_blkatoff; + ump->um_truncate = ffs_truncate; + ump->um_update = ffs_update; + ump->um_valloc = ffs_valloc; + ump->um_vfree = ffs_vfree; + ump->um_ifree = ffs_ifree; + ump->um_rdonly = ffs_rdonly; + ump->um_snapgone = ffs_snapgone; + mtx_init(UFS_MTX(ump), "FFS", "FFS Lock", MTX_DEF); + bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); + if (fs->fs_sbsize < SBLOCKSIZE) + bp->b_flags |= B_INVAL | B_NOCACHE; + brelse(bp); + bp = NULL; + fs = ump->um_fs; + ffs_oldfscompat_read(fs, ump, sblockloc); + fs->fs_ronly = ronly; + size = fs->fs_cssize; + blks = howmany(size, fs->fs_fsize); + if (fs->fs_contigsumsize > 0) + size += fs->fs_ncg * sizeof(int32_t); + size += fs->fs_ncg * sizeof(u_int8_t); + space = malloc(size, M_UFSMNT, M_WAITOK); + fs->fs_csp = space; + for (i = 0; i < blks; i += fs->fs_frag) { + size = fs->fs_bsize; + if (i + fs->fs_frag > blks) + size = (blks - i) * fs->fs_fsize; + if ((error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, + cred, &bp)) != 0) { + free(fs->fs_csp, M_UFSMNT); + goto out; + } + bcopy(bp->b_data, space, (u_int)size); + space = (char *)space + size; + brelse(bp); + bp = NULL; + } + if (fs->fs_contigsumsize > 0) { + fs->fs_maxcluster = lp = space; + for (i = 0; i < fs->fs_ncg; i++) + *lp++ = fs->fs_contigsumsize; + space = lp; + } + size = fs->fs_ncg * sizeof(u_int8_t); + fs->fs_contigdirs = (u_int8_t *)space; + bzero(fs->fs_contigdirs, size); + fs->fs_active = NULL; + mp->mnt_data = ump; + mp->mnt_stat.f_fsid.val[0] = fs->fs_id[0]; + mp->mnt_stat.f_fsid.val[1] = fs->fs_id[1]; + nmp = NULL; + if (fs->fs_id[0] == 0 || fs->fs_id[1] == 0 || + (nmp = vfs_getvfs(&mp->mnt_stat.f_fsid))) { + if (nmp) + vfs_rel(nmp); + vfs_getnewfsid(mp); + } + mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_LOCAL; + MNT_IUNLOCK(mp); + if ((fs->fs_flags & FS_MULTILABEL) != 0) { +#ifdef MAC + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_MULTILABEL; + MNT_IUNLOCK(mp); +#else + printf("WARNING: %s: multilabel flag on fs but " + "no MAC support\n", mp->mnt_stat.f_mntonname); +#endif + } + if ((fs->fs_flags & FS_ACLS) != 0) { +#ifdef UFS_ACL + MNT_ILOCK(mp); + + if (mp->mnt_flag & MNT_NFS4ACLS) + printf("WARNING: %s: ACLs flag on fs conflicts with " + "\"nfsv4acls\" mount option; option ignored\n", + mp->mnt_stat.f_mntonname); + mp->mnt_flag &= ~MNT_NFS4ACLS; + mp->mnt_flag |= MNT_ACLS; + + MNT_IUNLOCK(mp); +#else + printf("WARNING: %s: ACLs flag on fs but no ACLs support\n", + mp->mnt_stat.f_mntonname); +#endif + } + if ((fs->fs_flags & FS_NFS4ACLS) != 0) { +#ifdef UFS_ACL + MNT_ILOCK(mp); + + if (mp->mnt_flag & MNT_ACLS) + printf("WARNING: %s: NFSv4 ACLs flag on fs conflicts " + "with \"acls\" mount option; option ignored\n", + mp->mnt_stat.f_mntonname); + mp->mnt_flag &= ~MNT_ACLS; + mp->mnt_flag |= MNT_NFS4ACLS; + + MNT_IUNLOCK(mp); +#else + printf("WARNING: %s: NFSv4 ACLs flag on fs but no " + "ACLs support\n", mp->mnt_stat.f_mntonname); +#endif + } + if ((fs->fs_flags & FS_TRIM) != 0) { + len = sizeof(int); + if (g_io_getattr("GEOM::candelete", cp, &len, + &ump->um_candelete) == 0) { + if (!ump->um_candelete) + printf("WARNING: %s: TRIM flag on fs but disk " + "does not support TRIM\n", + mp->mnt_stat.f_mntonname); + } else { + printf("WARNING: %s: TRIM flag on fs but disk does " + "not confirm that it supports TRIM\n", + mp->mnt_stat.f_mntonname); + ump->um_candelete = 0; + } + if (ump->um_candelete) { + ump->um_trim_tq = taskqueue_create("trim", M_WAITOK, + taskqueue_thread_enqueue, &ump->um_trim_tq); + taskqueue_start_threads(&ump->um_trim_tq, 1, PVFS, + "%s trim", mp->mnt_stat.f_mntonname); + } + } + + ump->um_mountp = mp; + ump->um_dev = dev; + ump->um_devvp = devvp; + ump->um_nindir = fs->fs_nindir; + ump->um_bptrtodb = fs->fs_fsbtodb; + ump->um_seqinc = fs->fs_frag; + for (i = 0; i < MAXQUOTAS; i++) + ump->um_quotas[i] = NULLVP; +#ifdef UFS_EXTATTR + ufs_extattr_uepm_init(&ump->um_extattr); +#endif + /* + * Set FS local "last mounted on" information (NULL pad) + */ + bzero(fs->fs_fsmnt, MAXMNTLEN); + strlcpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname, MAXMNTLEN); + mp->mnt_stat.f_iosize = fs->fs_bsize; + + if (mp->mnt_flag & MNT_ROOTFS) { + /* + * Root mount; update timestamp in mount structure. + * this will be used by the common root mount code + * to update the system clock. + */ + mp->mnt_time = fs->fs_time; + } + + if (ronly == 0) { + fs->fs_mtime = time_second; + if ((fs->fs_flags & FS_DOSOFTDEP) && + (error = softdep_mount(devvp, mp, fs, cred)) != 0) { + free(fs->fs_csp, M_UFSMNT); + ffs_flushfiles(mp, FORCECLOSE, td); + goto out; + } + if (fs->fs_snapinum[0] != 0) + ffs_snapshot_mount(mp); + fs->fs_fmod = 1; + fs->fs_clean = 0; + (void) ffs_sbupdate(ump, MNT_WAIT, 0); + } + /* + * Initialize filesystem state information in mount struct. + */ + MNT_ILOCK(mp); + mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED | + MNTK_NO_IOPF | MNTK_UNMAPPED_BUFS | MNTK_USES_BCACHE; + MNT_IUNLOCK(mp); +#ifdef UFS_EXTATTR +#ifdef UFS_EXTATTR_AUTOSTART + /* + * + * Auto-starting does the following: + * - check for /.attribute in the fs, and extattr_start if so + * - for each file in .attribute, enable that file with + * an attribute of the same name. + * Not clear how to report errors -- probably eat them. + * This would all happen while the filesystem was busy/not + * available, so would effectively be "atomic". + */ + (void) ufs_extattr_autostart(mp, td); +#endif /* !UFS_EXTATTR_AUTOSTART */ +#endif /* !UFS_EXTATTR */ + return (0); +out: + if (bp) + brelse(bp); + if (cp != NULL) { + g_topology_lock(); + g_vfs_close(cp); + g_topology_unlock(); + } + if (ump) { + mtx_destroy(UFS_MTX(ump)); + if (mp->mnt_gjprovider != NULL) { + free(mp->mnt_gjprovider, M_UFSMNT); + mp->mnt_gjprovider = NULL; + } + free(ump->um_fs, M_UFSMNT); + free(ump, M_UFSMNT); + mp->mnt_data = NULL; + } + atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); + dev_rel(dev); + return (error); +} + +#include +static int bigcgs = 0; +SYSCTL_INT(_debug, OID_AUTO, bigcgs, CTLFLAG_RW, &bigcgs, 0, ""); + +/* + * Sanity checks for loading old filesystem superblocks. + * See ffs_oldfscompat_write below for unwound actions. + * + * XXX - Parts get retired eventually. + * Unfortunately new bits get added. + */ +static void +ffs_oldfscompat_read(fs, ump, sblockloc) + struct fs *fs; + struct ufsmount *ump; + ufs2_daddr_t sblockloc; +{ + off_t maxfilesize; + + /* + * If not yet done, update fs_flags location and value of fs_sblockloc. + */ + if ((fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) { + fs->fs_flags = fs->fs_old_flags; + fs->fs_old_flags |= FS_FLAGS_UPDATED; + fs->fs_sblockloc = sblockloc; + } + /* + * If not yet done, update UFS1 superblock with new wider fields. + */ + if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_maxbsize != fs->fs_bsize) { + fs->fs_maxbsize = fs->fs_bsize; + fs->fs_time = fs->fs_old_time; + fs->fs_size = fs->fs_old_size; + fs->fs_dsize = fs->fs_old_dsize; + fs->fs_csaddr = fs->fs_old_csaddr; + fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir; + fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree; + fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree; + fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree; + } + if (fs->fs_magic == FS_UFS1_MAGIC && + fs->fs_old_inodefmt < FS_44INODEFMT) { + fs->fs_maxfilesize = ((uint64_t)1 << 31) - 1; + fs->fs_qbmask = ~fs->fs_bmask; + fs->fs_qfmask = ~fs->fs_fmask; + } + if (fs->fs_magic == FS_UFS1_MAGIC) { + ump->um_savedmaxfilesize = fs->fs_maxfilesize; + maxfilesize = (uint64_t)0x80000000 * fs->fs_bsize - 1; + if (fs->fs_maxfilesize > maxfilesize) + fs->fs_maxfilesize = maxfilesize; + } + /* Compatibility for old filesystems */ + if (fs->fs_avgfilesize <= 0) + fs->fs_avgfilesize = AVFILESIZ; + if (fs->fs_avgfpdir <= 0) + fs->fs_avgfpdir = AFPDIR; + if (bigcgs) { + fs->fs_save_cgsize = fs->fs_cgsize; + fs->fs_cgsize = fs->fs_bsize; + } +} + +/* + * Unwinding superblock updates for old filesystems. + * See ffs_oldfscompat_read above for details. + * + * XXX - Parts get retired eventually. + * Unfortunately new bits get added. + */ +void +ffs_oldfscompat_write(fs, ump) + struct fs *fs; + struct ufsmount *ump; +{ + + /* + * Copy back UFS2 updated fields that UFS1 inspects. + */ + if (fs->fs_magic == FS_UFS1_MAGIC) { + fs->fs_old_time = fs->fs_time; + fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir; + fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree; + fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree; + fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree; + fs->fs_maxfilesize = ump->um_savedmaxfilesize; + } + if (bigcgs) { + fs->fs_cgsize = fs->fs_save_cgsize; + fs->fs_save_cgsize = 0; + } +} + +/* + * unmount system call + */ +static int +ffs_unmount(mp, mntflags) + struct mount *mp; + int mntflags; +{ + struct thread *td; + struct ufsmount *ump = VFSTOUFS(mp); + struct fs *fs; + int error, flags, susp; +#ifdef UFS_EXTATTR + int e_restart; +#endif + + flags = 0; + td = curthread; + fs = ump->um_fs; + susp = 0; + if (mntflags & MNT_FORCE) { + flags |= FORCECLOSE; + susp = fs->fs_ronly == 0; + } +#ifdef UFS_EXTATTR + if ((error = ufs_extattr_stop(mp, td))) { + if (error != EOPNOTSUPP) + printf("WARNING: unmount %s: ufs_extattr_stop " + "returned errno %d\n", mp->mnt_stat.f_mntonname, + error); + e_restart = 0; + } else { + ufs_extattr_uepm_destroy(&ump->um_extattr); + e_restart = 1; + } +#endif + if (susp) { + error = vfs_write_suspend_umnt(mp); + if (error != 0) + goto fail1; + } + if (MOUNTEDSOFTDEP(mp)) + error = softdep_flushfiles(mp, flags, td); + else + error = ffs_flushfiles(mp, flags, td); + if (error != 0 && error != ENXIO) + goto fail; + + UFS_LOCK(ump); + if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) { + printf("WARNING: unmount %s: pending error: blocks %jd " + "files %d\n", fs->fs_fsmnt, (intmax_t)fs->fs_pendingblocks, + fs->fs_pendinginodes); + fs->fs_pendingblocks = 0; + fs->fs_pendinginodes = 0; + } + UFS_UNLOCK(ump); + if (MOUNTEDSOFTDEP(mp)) + softdep_unmount(mp); + if (fs->fs_ronly == 0 || ump->um_fsckpid > 0) { + fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1; + error = ffs_sbupdate(ump, MNT_WAIT, 0); + if (error && error != ENXIO) { + fs->fs_clean = 0; + goto fail; + } + } + if (susp) + vfs_write_resume(mp, VR_START_WRITE); + if (ump->um_trim_tq != NULL) { + while (ump->um_trim_inflight != 0) + pause("ufsutr", hz); + taskqueue_drain_all(ump->um_trim_tq); + taskqueue_free(ump->um_trim_tq); + } + g_topology_lock(); + if (ump->um_fsckpid > 0) { + /* + * Return to normal read-only mode. + */ + error = g_access(ump->um_cp, 0, -1, 0); + ump->um_fsckpid = 0; + } + g_vfs_close(ump->um_cp); + g_topology_unlock(); + atomic_store_rel_ptr((uintptr_t *)&ump->um_dev->si_mountpt, 0); + vrele(ump->um_devvp); + dev_rel(ump->um_dev); + mtx_destroy(UFS_MTX(ump)); + if (mp->mnt_gjprovider != NULL) { + free(mp->mnt_gjprovider, M_UFSMNT); + mp->mnt_gjprovider = NULL; + } + free(fs->fs_csp, M_UFSMNT); + free(fs, M_UFSMNT); + free(ump, M_UFSMNT); + mp->mnt_data = NULL; + MNT_ILOCK(mp); + mp->mnt_flag &= ~MNT_LOCAL; + MNT_IUNLOCK(mp); + if (td->td_su == mp) { + td->td_su = NULL; + vfs_rel(mp); + } + return (error); + +fail: + if (susp) + vfs_write_resume(mp, VR_START_WRITE); +fail1: +#ifdef UFS_EXTATTR + if (e_restart) { + ufs_extattr_uepm_init(&ump->um_extattr); +#ifdef UFS_EXTATTR_AUTOSTART + (void) ufs_extattr_autostart(mp, td); +#endif + } +#endif + + return (error); +} + +/* + * Flush out all the files in a filesystem. + */ +int +ffs_flushfiles(mp, flags, td) + struct mount *mp; + int flags; + struct thread *td; +{ + struct ufsmount *ump; + int qerror, error; + + ump = VFSTOUFS(mp); + qerror = 0; +#ifdef QUOTA + if (mp->mnt_flag & MNT_QUOTA) { + int i; + error = vflush(mp, 0, SKIPSYSTEM|flags, td); + if (error) + return (error); + for (i = 0; i < MAXQUOTAS; i++) { + error = quotaoff(td, mp, i); + if (error != 0) { + if ((flags & EARLYFLUSH) == 0) + return (error); + else + qerror = error; + } + } + + /* + * Here we fall through to vflush again to ensure that + * we have gotten rid of all the system vnodes, unless + * quotas must not be closed. + */ + } +#endif + ASSERT_VOP_LOCKED(ump->um_devvp, "ffs_flushfiles"); + if (ump->um_devvp->v_vflag & VV_COPYONWRITE) { + if ((error = vflush(mp, 0, SKIPSYSTEM | flags, td)) != 0) + return (error); + ffs_snapshot_unmount(mp); + flags |= FORCECLOSE; + /* + * Here we fall through to vflush again to ensure + * that we have gotten rid of all the system vnodes. + */ + } + + /* + * Do not close system files if quotas were not closed, to be + * able to sync the remaining dquots. The freeblks softupdate + * workitems might hold a reference on a dquot, preventing + * quotaoff() from completing. Next round of + * softdep_flushworklist() iteration should process the + * blockers, allowing the next run of quotaoff() to finally + * flush held dquots. + * + * Otherwise, flush all the files. + */ + if (qerror == 0 && (error = vflush(mp, 0, flags, td)) != 0) + return (error); + + /* + * Flush filesystem metadata. + */ + vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_FSYNC(ump->um_devvp, MNT_WAIT, td); + VOP_UNLOCK(ump->um_devvp, 0); + return (error); +} + +/* + * Get filesystem statistics. + */ +static int +ffs_statfs(mp, sbp) + struct mount *mp; + struct statfs *sbp; +{ + struct ufsmount *ump; + struct fs *fs; + + ump = VFSTOUFS(mp); + fs = ump->um_fs; + if (fs->fs_magic != FS_UFS1_MAGIC && fs->fs_magic != FS_UFS2_MAGIC) + panic("ffs_statfs"); + sbp->f_version = STATFS_VERSION; + sbp->f_bsize = fs->fs_fsize; + sbp->f_iosize = fs->fs_bsize; + sbp->f_blocks = fs->fs_dsize; + UFS_LOCK(ump); + sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + + fs->fs_cstotal.cs_nffree + dbtofsb(fs, fs->fs_pendingblocks); + sbp->f_bavail = freespace(fs, fs->fs_minfree) + + dbtofsb(fs, fs->fs_pendingblocks); + sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; + sbp->f_ffree = fs->fs_cstotal.cs_nifree + fs->fs_pendinginodes; + UFS_UNLOCK(ump); + sbp->f_namemax = NAME_MAX; + return (0); +} + +static bool +sync_doupdate(struct inode *ip) +{ + + return ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | + IN_UPDATE)) != 0); +} + +/* + * For a lazy sync, we only care about access times, quotas and the + * superblock. Other filesystem changes are already converted to + * cylinder group blocks or inode blocks updates and are written to + * disk by syncer. + */ +static int +ffs_sync_lazy(mp) + struct mount *mp; +{ + struct vnode *mvp, *vp; + struct inode *ip; + struct thread *td; + int allerror, error; + + allerror = 0; + td = curthread; + if ((mp->mnt_flag & MNT_NOATIME) != 0) + goto qupdate; + MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { + if (vp->v_type == VNON) { + VI_UNLOCK(vp); + continue; + } + ip = VTOI(vp); + + /* + * The IN_ACCESS flag is converted to IN_MODIFIED by + * ufs_close() and ufs_getattr() by the calls to + * ufs_itimes_locked(), without subsequent UFS_UPDATE(). + * Test also all the other timestamp flags too, to pick up + * any other cases that could be missed. + */ + if (!sync_doupdate(ip) && (vp->v_iflag & VI_OWEINACT) == 0) { + VI_UNLOCK(vp); + continue; + } + if ((error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, + td)) != 0) + continue; + if (sync_doupdate(ip)) + error = ffs_update(vp, 0); + if (error != 0) + allerror = error; + vput(vp); + } + +qupdate: +#ifdef QUOTA + qsync(mp); +#endif + + if (VFSTOUFS(mp)->um_fs->fs_fmod != 0 && + (error = ffs_sbupdate(VFSTOUFS(mp), MNT_LAZY, 0)) != 0) + allerror = error; + return (allerror); +} + +/* + * Go through the disk queues to initiate sandbagged IO; + * go through the inodes to write those that have been modified; + * initiate the writing of the super block if it has been modified. + * + * Note: we are always called with the filesystem marked busy using + * vfs_busy(). + */ +static int +ffs_sync(mp, waitfor) + struct mount *mp; + int waitfor; +{ + struct vnode *mvp, *vp, *devvp; + struct thread *td; + struct inode *ip; + struct ufsmount *ump = VFSTOUFS(mp); + struct fs *fs; + int error, count, lockreq, allerror = 0; + int suspend; + int suspended; + int secondary_writes; + int secondary_accwrites; + int softdep_deps; + int softdep_accdeps; + struct bufobj *bo; + + suspend = 0; + suspended = 0; + td = curthread; + fs = ump->um_fs; + if (fs->fs_fmod != 0 && fs->fs_ronly != 0 && ump->um_fsckpid == 0) + panic("%s: ffs_sync: modification on read-only filesystem", + fs->fs_fsmnt); + if (waitfor == MNT_LAZY) { + if (!rebooting) + return (ffs_sync_lazy(mp)); + waitfor = MNT_NOWAIT; + } + + /* + * Write back each (modified) inode. + */ + lockreq = LK_EXCLUSIVE | LK_NOWAIT; + if (waitfor == MNT_SUSPEND) { + suspend = 1; + waitfor = MNT_WAIT; + } + if (waitfor == MNT_WAIT) + lockreq = LK_EXCLUSIVE; + lockreq |= LK_INTERLOCK | LK_SLEEPFAIL; +loop: + /* Grab snapshot of secondary write counts */ + MNT_ILOCK(mp); + secondary_writes = mp->mnt_secondary_writes; + secondary_accwrites = mp->mnt_secondary_accwrites; + MNT_IUNLOCK(mp); + + /* Grab snapshot of softdep dependency counts */ + softdep_get_depcounts(mp, &softdep_deps, &softdep_accdeps); + + MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { + /* + * Depend on the vnode interlock to keep things stable enough + * for a quick test. Since there might be hundreds of + * thousands of vnodes, we cannot afford even a subroutine + * call unless there's a good chance that we have work to do. + */ + if (vp->v_type == VNON) { + VI_UNLOCK(vp); + continue; + } + ip = VTOI(vp); + if ((ip->i_flag & + (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && + vp->v_bufobj.bo_dirty.bv_cnt == 0) { + VI_UNLOCK(vp); + continue; + } + if ((error = vget(vp, lockreq, td)) != 0) { + if (error == ENOENT || error == ENOLCK) { + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + goto loop; + } + continue; + } + if ((error = ffs_syncvnode(vp, waitfor, 0)) != 0) + allerror = error; + vput(vp); + } + /* + * Force stale filesystem control information to be flushed. + */ + if (waitfor == MNT_WAIT || rebooting) { + if ((error = softdep_flushworklist(ump->um_mountp, &count, td))) + allerror = error; + /* Flushed work items may create new vnodes to clean */ + if (allerror == 0 && count) + goto loop; + } +#ifdef QUOTA + qsync(mp); +#endif + + devvp = ump->um_devvp; + bo = &devvp->v_bufobj; + BO_LOCK(bo); + if (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0) { + BO_UNLOCK(bo); + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_FSYNC(devvp, waitfor, td); + VOP_UNLOCK(devvp, 0); + if (MOUNTEDSOFTDEP(mp) && (error == 0 || error == EAGAIN)) + error = ffs_sbupdate(ump, waitfor, 0); + if (error != 0) + allerror = error; + if (allerror == 0 && waitfor == MNT_WAIT) + goto loop; + } else if (suspend != 0) { + if (softdep_check_suspend(mp, + devvp, + softdep_deps, + softdep_accdeps, + secondary_writes, + secondary_accwrites) != 0) { + MNT_IUNLOCK(mp); + goto loop; /* More work needed */ + } + mtx_assert(MNT_MTX(mp), MA_OWNED); + mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED; + MNT_IUNLOCK(mp); + suspended = 1; + } else + BO_UNLOCK(bo); + /* + * Write back modified superblock. + */ + if (fs->fs_fmod != 0 && + (error = ffs_sbupdate(ump, waitfor, suspended)) != 0) + allerror = error; + return (allerror); +} + +int +ffs_vget(mp, ino, flags, vpp) + struct mount *mp; + ino_t ino; + int flags; + struct vnode **vpp; +{ + return (ffs_vgetf(mp, ino, flags, vpp, 0)); +} + +int +ffs_vgetf(mp, ino, flags, vpp, ffs_flags) + struct mount *mp; + ino_t ino; + int flags; + struct vnode **vpp; + int ffs_flags; +{ + struct fs *fs; + struct inode *ip; + struct ufsmount *ump; + struct buf *bp; + struct vnode *vp; + int error; + + error = vfs_hash_get(mp, ino, flags, curthread, vpp, NULL, NULL); + if (error || *vpp != NULL) + return (error); + + /* + * We must promote to an exclusive lock for vnode creation. This + * can happen if lookup is passed LOCKSHARED. + */ + if ((flags & LK_TYPE_MASK) == LK_SHARED) { + flags &= ~LK_TYPE_MASK; + flags |= LK_EXCLUSIVE; + } + + /* + * We do not lock vnode creation as it is believed to be too + * expensive for such rare case as simultaneous creation of vnode + * for same ino by different processes. We just allow them to race + * and check later to decide who wins. Let the race begin! + */ + + ump = VFSTOUFS(mp); + fs = ump->um_fs; + ip = uma_zalloc(uma_inode, M_WAITOK | M_ZERO); + + /* Allocate a new vnode/inode. */ + error = getnewvnode("ufs", mp, fs->fs_magic == FS_UFS1_MAGIC ? + &ffs_vnodeops1 : &ffs_vnodeops2, &vp); + if (error) { + *vpp = NULL; + uma_zfree(uma_inode, ip); + return (error); + } + /* + * FFS supports recursive locking. + */ + lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); + VN_LOCK_AREC(vp); + vp->v_data = ip; + vp->v_bufobj.bo_bsize = fs->fs_bsize; + ip->i_vnode = vp; + ip->i_ump = ump; + ip->i_number = ino; + ip->i_ea_refs = 0; + ip->i_nextclustercg = -1; + ip->i_flag = fs->fs_magic == FS_UFS1_MAGIC ? 0 : IN_UFS2; +#ifdef QUOTA + { + int i; + for (i = 0; i < MAXQUOTAS; i++) + ip->i_dquot[i] = NODQUOT; + } +#endif + + if (ffs_flags & FFSV_FORCEINSMQ) + vp->v_vflag |= VV_FORCEINSMQ; + error = insmntque(vp, mp); + if (error != 0) { + uma_zfree(uma_inode, ip); + *vpp = NULL; + return (error); + } + vp->v_vflag &= ~VV_FORCEINSMQ; + error = vfs_hash_insert(vp, ino, flags, curthread, vpp, NULL, NULL); + if (error || *vpp != NULL) + return (error); + + /* Read in the disk contents for the inode, copy into the inode. */ + error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), + (int)fs->fs_bsize, NOCRED, &bp); + if (error) { + /* + * The inode does not contain anything useful, so it would + * be misleading to leave it on its hash chain. With mode + * still zero, it will be unlinked and returned to the free + * list by vput(). + */ + brelse(bp); + vput(vp); + *vpp = NULL; + return (error); + } + if (I_IS_UFS1(ip)) + ip->i_din1 = uma_zalloc(uma_ufs1, M_WAITOK); + else + ip->i_din2 = uma_zalloc(uma_ufs2, M_WAITOK); + ffs_load_inode(bp, ip, fs, ino); + if (DOINGSOFTDEP(vp)) + softdep_load_inodeblock(ip); + else + ip->i_effnlink = ip->i_nlink; + bqrelse(bp); + + /* + * Initialize the vnode from the inode, check for aliases. + * Note that the underlying vnode may have changed. + */ + error = ufs_vinit(mp, I_IS_UFS1(ip) ? &ffs_fifoops1 : &ffs_fifoops2, + &vp); + if (error) { + vput(vp); + *vpp = NULL; + return (error); + } + + /* + * Finish inode initialization. + */ + if (vp->v_type != VFIFO) { + /* FFS supports shared locking for all files except fifos. */ + VN_LOCK_ASHARE(vp); + } + + /* + * Set up a generation number for this inode if it does not + * already have one. This should only happen on old filesystems. + */ + if (ip->i_gen == 0) { + while (ip->i_gen == 0) + ip->i_gen = arc4random(); + if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { + ip->i_flag |= IN_MODIFIED; + DIP_SET(ip, i_gen, ip->i_gen); + } + } +#ifdef MAC + if ((mp->mnt_flag & MNT_MULTILABEL) && ip->i_mode) { + /* + * If this vnode is already allocated, and we're running + * multi-label, attempt to perform a label association + * from the extended attributes on the inode. + */ + error = mac_vnode_associate_extattr(mp, vp); + if (error) { + /* ufs_inactive will release ip->i_devvp ref. */ + vput(vp); + *vpp = NULL; + return (error); + } + } +#endif + + *vpp = vp; + return (0); +} + +/* + * File handle to vnode + * + * Have to be really careful about stale file handles: + * - check that the inode number is valid + * - for UFS2 check that the inode number is initialized + * - call ffs_vget() to get the locked inode + * - check for an unallocated inode (i_mode == 0) + * - check that the given client host has export rights and return + * those rights via. exflagsp and credanonp + */ +static int +ffs_fhtovp(mp, fhp, flags, vpp) + struct mount *mp; + struct fid *fhp; + int flags; + struct vnode **vpp; +{ + struct ufid *ufhp; + struct ufsmount *ump; + struct fs *fs; + struct cg *cgp; + struct buf *bp; + ino_t ino; + u_int cg; + int error; + + ufhp = (struct ufid *)fhp; + ino = ufhp->ufid_ino; + ump = VFSTOUFS(mp); + fs = ump->um_fs; + if (ino < ROOTINO || ino >= fs->fs_ncg * fs->fs_ipg) + return (ESTALE); + /* + * Need to check if inode is initialized because UFS2 does lazy + * initialization and nfs_fhtovp can offer arbitrary inode numbers. + */ + if (fs->fs_magic != FS_UFS2_MAGIC) + return (ufs_fhtovp(mp, ufhp, flags, vpp)); + cg = ino_to_cg(fs, ino); + error = bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) + return (error); + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp) || ino >= cg * fs->fs_ipg + cgp->cg_initediblk) { + brelse(bp); + return (ESTALE); + } + brelse(bp); + return (ufs_fhtovp(mp, ufhp, flags, vpp)); +} + +/* + * Initialize the filesystem. + */ +static int +ffs_init(vfsp) + struct vfsconf *vfsp; +{ + + ffs_susp_initialize(); + softdep_initialize(); + return (ufs_init(vfsp)); +} + +/* + * Undo the work of ffs_init(). + */ +static int +ffs_uninit(vfsp) + struct vfsconf *vfsp; +{ + int ret; + + ret = ufs_uninit(vfsp); + softdep_uninitialize(); + ffs_susp_uninitialize(); + return (ret); +} + +/* + * Write a superblock and associated information back to disk. + */ +int +ffs_sbupdate(ump, waitfor, suspended) + struct ufsmount *ump; + int waitfor; + int suspended; +{ + struct fs *fs = ump->um_fs; + struct buf *sbbp; + struct buf *bp; + int blks; + void *space; + int i, size, error, allerror = 0; + + if (fs->fs_ronly == 1 && + (ump->um_mountp->mnt_flag & (MNT_RDONLY | MNT_UPDATE)) != + (MNT_RDONLY | MNT_UPDATE) && ump->um_fsckpid == 0) + panic("ffs_sbupdate: write read-only filesystem"); + /* + * We use the superblock's buf to serialize calls to ffs_sbupdate(). + */ + sbbp = getblk(ump->um_devvp, btodb(fs->fs_sblockloc), + (int)fs->fs_sbsize, 0, 0, 0); + /* + * First write back the summary information. + */ + blks = howmany(fs->fs_cssize, fs->fs_fsize); + space = fs->fs_csp; + for (i = 0; i < blks; i += fs->fs_frag) { + size = fs->fs_bsize; + if (i + fs->fs_frag > blks) + size = (blks - i) * fs->fs_fsize; + bp = getblk(ump->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), + size, 0, 0, 0); + bcopy(space, bp->b_data, (u_int)size); + space = (char *)space + size; + if (suspended) + bp->b_flags |= B_VALIDSUSPWRT; + if (waitfor != MNT_WAIT) + bawrite(bp); + else if ((error = bwrite(bp)) != 0) + allerror = error; + } + /* + * Now write back the superblock itself. If any errors occurred + * up to this point, then fail so that the superblock avoids + * being written out as clean. + */ + if (allerror) { + brelse(sbbp); + return (allerror); + } + bp = sbbp; + if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_sblockloc != SBLOCK_UFS1 && + (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) { + printf("WARNING: %s: correcting fs_sblockloc from %jd to %d\n", + fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS1); + fs->fs_sblockloc = SBLOCK_UFS1; + } + if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_sblockloc != SBLOCK_UFS2 && + (fs->fs_old_flags & FS_FLAGS_UPDATED) == 0) { + printf("WARNING: %s: correcting fs_sblockloc from %jd to %d\n", + fs->fs_fsmnt, fs->fs_sblockloc, SBLOCK_UFS2); + fs->fs_sblockloc = SBLOCK_UFS2; + } + fs->fs_fmod = 0; + fs->fs_time = time_second; + if (MOUNTEDSOFTDEP(ump->um_mountp)) + softdep_setup_sbupdate(ump, (struct fs *)bp->b_data, bp); + bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); + ffs_oldfscompat_write((struct fs *)bp->b_data, ump); + if (suspended) + bp->b_flags |= B_VALIDSUSPWRT; + if (waitfor != MNT_WAIT) + bawrite(bp); + else if ((error = bwrite(bp)) != 0) + allerror = error; + return (allerror); +} + +static int +ffs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, + int attrnamespace, const char *attrname) +{ + +#ifdef UFS_EXTATTR + return (ufs_extattrctl(mp, cmd, filename_vp, attrnamespace, + attrname)); +#else + return (vfs_stdextattrctl(mp, cmd, filename_vp, attrnamespace, + attrname)); +#endif +} + +static void +ffs_ifree(struct ufsmount *ump, struct inode *ip) +{ + + if (ump->um_fstype == UFS1 && ip->i_din1 != NULL) + uma_zfree(uma_ufs1, ip->i_din1); + else if (ip->i_din2 != NULL) + uma_zfree(uma_ufs2, ip->i_din2); + uma_zfree(uma_inode, ip); +} + +static int dobkgrdwrite = 1; +SYSCTL_INT(_debug, OID_AUTO, dobkgrdwrite, CTLFLAG_RW, &dobkgrdwrite, 0, + "Do background writes (honoring the BV_BKGRDWRITE flag)?"); + +/* + * Complete a background write started from bwrite. + */ +static void +ffs_backgroundwritedone(struct buf *bp) +{ + struct bufobj *bufobj; + struct buf *origbp; + + /* + * Find the original buffer that we are writing. + */ + bufobj = bp->b_bufobj; + BO_LOCK(bufobj); + if ((origbp = gbincore(bp->b_bufobj, bp->b_lblkno)) == NULL) + panic("backgroundwritedone: lost buffer"); + + /* + * We should mark the cylinder group buffer origbp as + * dirty, to not loose the failed write. + */ + if ((bp->b_ioflags & BIO_ERROR) != 0) + origbp->b_vflags |= BV_BKGRDERR; + BO_UNLOCK(bufobj); + /* + * Process dependencies then return any unfinished ones. + */ + if (!LIST_EMPTY(&bp->b_dep) && (bp->b_ioflags & BIO_ERROR) == 0) + buf_complete(bp); +#ifdef SOFTUPDATES + if (!LIST_EMPTY(&bp->b_dep)) + softdep_move_dependencies(bp, origbp); +#endif + /* + * This buffer is marked B_NOCACHE so when it is released + * by biodone it will be tossed. + */ + bp->b_flags |= B_NOCACHE; + bp->b_flags &= ~B_CACHE; + pbrelvp(bp); + + /* + * Prevent brelse() from trying to keep and re-dirtying bp on + * errors. It causes b_bufobj dereference in + * bdirty()/reassignbuf(), and b_bufobj was cleared in + * pbrelvp() above. + */ + if ((bp->b_ioflags & BIO_ERROR) != 0) + bp->b_flags |= B_INVAL; + bufdone(bp); + BO_LOCK(bufobj); + /* + * Clear the BV_BKGRDINPROG flag in the original buffer + * and awaken it if it is waiting for the write to complete. + * If BV_BKGRDINPROG is not set in the original buffer it must + * have been released and re-instantiated - which is not legal. + */ + KASSERT((origbp->b_vflags & BV_BKGRDINPROG), + ("backgroundwritedone: lost buffer2")); + origbp->b_vflags &= ~BV_BKGRDINPROG; + if (origbp->b_vflags & BV_BKGRDWAIT) { + origbp->b_vflags &= ~BV_BKGRDWAIT; + wakeup(&origbp->b_xflags); + } + BO_UNLOCK(bufobj); +} + + +/* + * Write, release buffer on completion. (Done by iodone + * if async). Do not bother writing anything if the buffer + * is invalid. + * + * Note that we set B_CACHE here, indicating that buffer is + * fully valid and thus cacheable. This is true even of NFS + * now so we set it generally. This could be set either here + * or in biodone() since the I/O is synchronous. We put it + * here. + */ +static int +ffs_bufwrite(struct buf *bp) +{ + struct buf *newbp; + + CTR3(KTR_BUF, "bufwrite(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags); + if (bp->b_flags & B_INVAL) { + brelse(bp); + return (0); + } + + if (!BUF_ISLOCKED(bp)) + panic("bufwrite: buffer is not busy???"); + /* + * If a background write is already in progress, delay + * writing this block if it is asynchronous. Otherwise + * wait for the background write to complete. + */ + BO_LOCK(bp->b_bufobj); + if (bp->b_vflags & BV_BKGRDINPROG) { + if (bp->b_flags & B_ASYNC) { + BO_UNLOCK(bp->b_bufobj); + bdwrite(bp); + return (0); + } + bp->b_vflags |= BV_BKGRDWAIT; + msleep(&bp->b_xflags, BO_LOCKPTR(bp->b_bufobj), PRIBIO, + "bwrbg", 0); + if (bp->b_vflags & BV_BKGRDINPROG) + panic("bufwrite: still writing"); + } + bp->b_vflags &= ~BV_BKGRDERR; + BO_UNLOCK(bp->b_bufobj); + + /* + * If this buffer is marked for background writing and we + * do not have to wait for it, make a copy and write the + * copy so as to leave this buffer ready for further use. + * + * This optimization eats a lot of memory. If we have a page + * or buffer shortfall we can't do it. + */ + if (dobkgrdwrite && (bp->b_xflags & BX_BKGRDWRITE) && + (bp->b_flags & B_ASYNC) && + !vm_page_count_severe() && + !buf_dirty_count_severe()) { + KASSERT(bp->b_iodone == NULL, + ("bufwrite: needs chained iodone (%p)", bp->b_iodone)); + + /* get a new block */ + newbp = geteblk(bp->b_bufsize, GB_NOWAIT_BD); + if (newbp == NULL) + goto normal_write; + + KASSERT(buf_mapped(bp), ("Unmapped cg")); + memcpy(newbp->b_data, bp->b_data, bp->b_bufsize); + BO_LOCK(bp->b_bufobj); + bp->b_vflags |= BV_BKGRDINPROG; + BO_UNLOCK(bp->b_bufobj); + newbp->b_xflags |= BX_BKGRDMARKER; + newbp->b_lblkno = bp->b_lblkno; + newbp->b_blkno = bp->b_blkno; + newbp->b_offset = bp->b_offset; + newbp->b_iodone = ffs_backgroundwritedone; + newbp->b_flags |= B_ASYNC; + newbp->b_flags &= ~B_INVAL; + pbgetvp(bp->b_vp, newbp); + +#ifdef SOFTUPDATES + /* + * Move over the dependencies. If there are rollbacks, + * leave the parent buffer dirtied as it will need to + * be written again. + */ + if (LIST_EMPTY(&bp->b_dep) || + softdep_move_dependencies(bp, newbp) == 0) + bundirty(bp); +#else + bundirty(bp); +#endif + + /* + * Initiate write on the copy, release the original. The + * BKGRDINPROG flag prevents it from going away until + * the background write completes. + */ + bqrelse(bp); + bp = newbp; + } else + /* Mark the buffer clean */ + bundirty(bp); + + + /* Let the normal bufwrite do the rest for us */ +normal_write: + return (bufwrite(bp)); +} + + +static void +ffs_geom_strategy(struct bufobj *bo, struct buf *bp) +{ + struct vnode *vp; + int error; + struct buf *tbp; + int nocopy; + + vp = bo->__bo_vnode; + if (bp->b_iocmd == BIO_WRITE) { + if ((bp->b_flags & B_VALIDSUSPWRT) == 0 && + bp->b_vp != NULL && bp->b_vp->v_mount != NULL && + (bp->b_vp->v_mount->mnt_kern_flag & MNTK_SUSPENDED) != 0) + panic("ffs_geom_strategy: bad I/O"); + nocopy = bp->b_flags & B_NOCOPY; + bp->b_flags &= ~(B_VALIDSUSPWRT | B_NOCOPY); + if ((vp->v_vflag & VV_COPYONWRITE) && nocopy == 0 && + vp->v_rdev->si_snapdata != NULL) { + if ((bp->b_flags & B_CLUSTER) != 0) { + runningbufwakeup(bp); + TAILQ_FOREACH(tbp, &bp->b_cluster.cluster_head, + b_cluster.cluster_entry) { + error = ffs_copyonwrite(vp, tbp); + if (error != 0 && + error != EOPNOTSUPP) { + bp->b_error = error; + bp->b_ioflags |= BIO_ERROR; + bufdone(bp); + return; + } + } + bp->b_runningbufspace = bp->b_bufsize; + atomic_add_long(&runningbufspace, + bp->b_runningbufspace); + } else { + error = ffs_copyonwrite(vp, bp); + if (error != 0 && error != EOPNOTSUPP) { + bp->b_error = error; + bp->b_ioflags |= BIO_ERROR; + bufdone(bp); + return; + } + } + } +#ifdef SOFTUPDATES + if ((bp->b_flags & B_CLUSTER) != 0) { + TAILQ_FOREACH(tbp, &bp->b_cluster.cluster_head, + b_cluster.cluster_entry) { + if (!LIST_EMPTY(&tbp->b_dep)) + buf_start(tbp); + } + } else { + if (!LIST_EMPTY(&bp->b_dep)) + buf_start(bp); + } + +#endif + } + g_vfs_strategy(bo, bp); +} + +int +ffs_own_mount(const struct mount *mp) +{ + + if (mp->mnt_op == &ufs_vfsops) + return (1); + return (0); +} + +#ifdef DDB +#ifdef SOFTUPDATES + +/* defined in ffs_softdep.c */ +extern void db_print_ffs(struct ufsmount *ump); + +DB_SHOW_COMMAND(ffs, db_show_ffs) +{ + struct mount *mp; + struct ufsmount *ump; + + if (have_addr) { + ump = VFSTOUFS((struct mount *)addr); + db_print_ffs(ump); + return; + } + + TAILQ_FOREACH(mp, &mountlist, mnt_list) { + if (!strcmp(mp->mnt_stat.f_fstypename, ufs_vfsconf.vfc_name)) + db_print_ffs(VFSTOUFS(mp)); + } +} + +#endif /* SOFTUPDATES */ +#endif /* DDB */ diff --git a/Dump/ufs/ffs/ffs_vnops.c b/Dump/ufs/ffs/ffs_vnops.c new file mode 100644 index 0000000..50ceebe --- /dev/null +++ b/Dump/ufs/ffs/ffs_vnops.c @@ -0,0 +1,1745 @@ +/*- + * Copyright (c) 2002, 2003 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)ufs_readwrite.c 8.11 (Berkeley) 5/8/95 + * from: $FreeBSD: .../ufs/ufs_readwrite.c,v 1.96 2002/08/12 09:22:11 phk ... + * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ffs/ffs_vnops.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include "opt_directio.h" +#include "opt_ffs.h" + +#ifdef DIRECTIO +extern int ffs_rawread(struct vnode *vp, struct uio *uio, int *workdone); +#endif +static vop_fdatasync_t ffs_fdatasync; +static vop_fsync_t ffs_fsync; +static vop_getpages_t ffs_getpages; +static vop_lock1_t ffs_lock; +static vop_read_t ffs_read; +static vop_write_t ffs_write; +static int ffs_extread(struct vnode *vp, struct uio *uio, int ioflag); +static int ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, + struct ucred *cred); +static vop_strategy_t ffsext_strategy; +static vop_closeextattr_t ffs_closeextattr; +static vop_deleteextattr_t ffs_deleteextattr; +static vop_getextattr_t ffs_getextattr; +static vop_listextattr_t ffs_listextattr; +static vop_openextattr_t ffs_openextattr; +static vop_setextattr_t ffs_setextattr; +static vop_vptofh_t ffs_vptofh; + +/* Global vfs data structures for ufs. */ +struct vop_vector ffs_vnodeops1 = { + .vop_default = &ufs_vnodeops, + .vop_fsync = ffs_fsync, + .vop_fdatasync = ffs_fdatasync, + .vop_getpages = ffs_getpages, + .vop_getpages_async = vnode_pager_local_getpages_async, + .vop_lock1 = ffs_lock, + .vop_read = ffs_read, + .vop_reallocblks = ffs_reallocblks, + .vop_write = ffs_write, + .vop_vptofh = ffs_vptofh, +}; + +struct vop_vector ffs_fifoops1 = { + .vop_default = &ufs_fifoops, + .vop_fsync = ffs_fsync, + .vop_fdatasync = ffs_fdatasync, + .vop_reallocblks = ffs_reallocblks, /* XXX: really ??? */ + .vop_vptofh = ffs_vptofh, +}; + +/* Global vfs data structures for ufs. */ +struct vop_vector ffs_vnodeops2 = { + .vop_default = &ufs_vnodeops, + .vop_fsync = ffs_fsync, + .vop_fdatasync = ffs_fdatasync, + .vop_getpages = ffs_getpages, + .vop_getpages_async = vnode_pager_local_getpages_async, + .vop_lock1 = ffs_lock, + .vop_read = ffs_read, + .vop_reallocblks = ffs_reallocblks, + .vop_write = ffs_write, + .vop_closeextattr = ffs_closeextattr, + .vop_deleteextattr = ffs_deleteextattr, + .vop_getextattr = ffs_getextattr, + .vop_listextattr = ffs_listextattr, + .vop_openextattr = ffs_openextattr, + .vop_setextattr = ffs_setextattr, + .vop_vptofh = ffs_vptofh, +}; + +struct vop_vector ffs_fifoops2 = { + .vop_default = &ufs_fifoops, + .vop_fsync = ffs_fsync, + .vop_fdatasync = ffs_fdatasync, + .vop_lock1 = ffs_lock, + .vop_reallocblks = ffs_reallocblks, + .vop_strategy = ffsext_strategy, + .vop_closeextattr = ffs_closeextattr, + .vop_deleteextattr = ffs_deleteextattr, + .vop_getextattr = ffs_getextattr, + .vop_listextattr = ffs_listextattr, + .vop_openextattr = ffs_openextattr, + .vop_setextattr = ffs_setextattr, + .vop_vptofh = ffs_vptofh, +}; + +/* + * Synch an open file. + */ +/* ARGSUSED */ +static int +ffs_fsync(struct vop_fsync_args *ap) +{ + struct vnode *vp; + struct bufobj *bo; + int error; + + vp = ap->a_vp; + bo = &vp->v_bufobj; +retry: + error = ffs_syncvnode(vp, ap->a_waitfor, 0); + if (error) + return (error); + if (ap->a_waitfor == MNT_WAIT && DOINGSOFTDEP(vp)) { + error = softdep_fsync(vp); + if (error) + return (error); + + /* + * The softdep_fsync() function may drop vp lock, + * allowing for dirty buffers to reappear on the + * bo_dirty list. Recheck and resync as needed. + */ + BO_LOCK(bo); + if ((vp->v_type == VREG || vp->v_type == VDIR) && + (bo->bo_numoutput > 0 || bo->bo_dirty.bv_cnt > 0)) { + BO_UNLOCK(bo); + goto retry; + } + BO_UNLOCK(bo); + } + return (0); +} + +int +ffs_syncvnode(struct vnode *vp, int waitfor, int flags) +{ + struct inode *ip; + struct bufobj *bo; + struct buf *bp, *nbp; + ufs_lbn_t lbn; + int error, passes; + bool still_dirty, wait; + + ip = VTOI(vp); + ip->i_flag &= ~IN_NEEDSYNC; + bo = &vp->v_bufobj; + + /* + * When doing MNT_WAIT we must first flush all dependencies + * on the inode. + */ + if (DOINGSOFTDEP(vp) && waitfor == MNT_WAIT && + (error = softdep_sync_metadata(vp)) != 0) + return (error); + + /* + * Flush all dirty buffers associated with a vnode. + */ + error = 0; + passes = 0; + wait = false; /* Always do an async pass first. */ + lbn = lblkno(ITOFS(ip), (ip->i_size + ITOFS(ip)->fs_bsize - 1)); + BO_LOCK(bo); +loop: + TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) + bp->b_vflags &= ~BV_SCANNED; + TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { + /* + * Reasons to skip this buffer: it has already been considered + * on this pass, the buffer has dependencies that will cause + * it to be redirtied and it has not already been deferred, + * or it is already being written. + */ + if ((bp->b_vflags & BV_SCANNED) != 0) + continue; + bp->b_vflags |= BV_SCANNED; + /* + * Flush indirects in order, if requested. + * + * Note that if only datasync is requested, we can + * skip indirect blocks when softupdates are not + * active. Otherwise we must flush them with data, + * since dependencies prevent data block writes. + */ + if (waitfor == MNT_WAIT && bp->b_lblkno <= -NDADDR && + (lbn_level(bp->b_lblkno) >= passes || + ((flags & DATA_ONLY) != 0 && !DOINGSOFTDEP(vp)))) + continue; + if (bp->b_lblkno > lbn) + panic("ffs_syncvnode: syncing truncated data."); + if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) == 0) { + BO_UNLOCK(bo); + } else if (wait) { + if (BUF_LOCK(bp, + LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, + BO_LOCKPTR(bo)) != 0) { + bp->b_vflags &= ~BV_SCANNED; + goto next; + } + } else + continue; + if ((bp->b_flags & B_DELWRI) == 0) + panic("ffs_fsync: not dirty"); + /* + * Check for dependencies and potentially complete them. + */ + if (!LIST_EMPTY(&bp->b_dep) && + (error = softdep_sync_buf(vp, bp, + wait ? MNT_WAIT : MNT_NOWAIT)) != 0) { + /* I/O error. */ + if (error != EBUSY) { + BUF_UNLOCK(bp); + return (error); + } + /* If we deferred once, don't defer again. */ + if ((bp->b_flags & B_DEFERRED) == 0) { + bp->b_flags |= B_DEFERRED; + BUF_UNLOCK(bp); + goto next; + } + } + if (wait) { + bremfree(bp); + if ((error = bwrite(bp)) != 0) + return (error); + } else if ((bp->b_flags & B_CLUSTEROK)) { + (void) vfs_bio_awrite(bp); + } else { + bremfree(bp); + (void) bawrite(bp); + } +next: + /* + * Since we may have slept during the I/O, we need + * to start from a known point. + */ + BO_LOCK(bo); + nbp = TAILQ_FIRST(&bo->bo_dirty.bv_hd); + } + if (waitfor != MNT_WAIT) { + BO_UNLOCK(bo); + if ((flags & NO_INO_UPDT) != 0) + return (0); + else + return (ffs_update(vp, 0)); + } + /* Drain IO to see if we're done. */ + bufobj_wwait(bo, 0, 0); + /* + * Block devices associated with filesystems may have new I/O + * requests posted for them even if the vnode is locked, so no + * amount of trying will get them clean. We make several passes + * as a best effort. + * + * Regular files may need multiple passes to flush all dependency + * work as it is possible that we must write once per indirect + * level, once for the leaf, and once for the inode and each of + * these will be done with one sync and one async pass. + */ + if (bo->bo_dirty.bv_cnt > 0) { + if ((flags & DATA_ONLY) == 0) { + still_dirty = true; + } else { + /* + * For data-only sync, dirty indirect buffers + * are ignored. + */ + still_dirty = false; + TAILQ_FOREACH(bp, &bo->bo_dirty.bv_hd, b_bobufs) { + if (bp->b_lblkno > -NDADDR) { + still_dirty = true; + break; + } + } + } + + if (still_dirty) { + /* Write the inode after sync passes to flush deps. */ + if (wait && DOINGSOFTDEP(vp) && + (flags & NO_INO_UPDT) == 0) { + BO_UNLOCK(bo); + ffs_update(vp, 1); + BO_LOCK(bo); + } + /* switch between sync/async. */ + wait = !wait; + if (wait || ++passes < NIADDR + 2) + goto loop; +#ifdef INVARIANTS + if (!vn_isdisk(vp, NULL)) + vn_printf(vp, "ffs_fsync: dirty "); +#endif + } + } + BO_UNLOCK(bo); + error = 0; + if ((flags & DATA_ONLY) == 0) { + if ((flags & NO_INO_UPDT) == 0) + error = ffs_update(vp, 1); + if (DOINGSUJ(vp)) + softdep_journal_fsync(VTOI(vp)); + } + return (error); +} + +static int +ffs_fdatasync(struct vop_fdatasync_args *ap) +{ + + return (ffs_syncvnode(ap->a_vp, MNT_WAIT, DATA_ONLY)); +} + +static int +ffs_lock(ap) + struct vop_lock1_args /* { + struct vnode *a_vp; + int a_flags; + struct thread *a_td; + char *file; + int line; + } */ *ap; +{ +#ifndef NO_FFS_SNAPSHOT + struct vnode *vp; + int flags; + struct lock *lkp; + int result; + + switch (ap->a_flags & LK_TYPE_MASK) { + case LK_SHARED: + case LK_UPGRADE: + case LK_EXCLUSIVE: + vp = ap->a_vp; + flags = ap->a_flags; + for (;;) { +#ifdef DEBUG_VFS_LOCKS + KASSERT(vp->v_holdcnt != 0, + ("ffs_lock %p: zero hold count", vp)); +#endif + lkp = vp->v_vnlock; + result = _lockmgr_args(lkp, flags, VI_MTX(vp), + LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT, + ap->a_file, ap->a_line); + if (lkp == vp->v_vnlock || result != 0) + break; + /* + * Apparent success, except that the vnode + * mutated between snapshot file vnode and + * regular file vnode while this process + * slept. The lock currently held is not the + * right lock. Release it, and try to get the + * new lock. + */ + (void) _lockmgr_args(lkp, LK_RELEASE, NULL, + LK_WMESG_DEFAULT, LK_PRIO_DEFAULT, LK_TIMO_DEFAULT, + ap->a_file, ap->a_line); + if ((flags & (LK_INTERLOCK | LK_NOWAIT)) == + (LK_INTERLOCK | LK_NOWAIT)) + return (EBUSY); + if ((flags & LK_TYPE_MASK) == LK_UPGRADE) + flags = (flags & ~LK_TYPE_MASK) | LK_EXCLUSIVE; + flags &= ~LK_INTERLOCK; + } + break; + default: + result = VOP_LOCK1_APV(&ufs_vnodeops, ap); + } + return (result); +#else + return (VOP_LOCK1_APV(&ufs_vnodeops, ap)); +#endif +} + +/* + * Vnode op for reading. + */ +static int +ffs_read(ap) + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + struct vnode *vp; + struct inode *ip; + struct uio *uio; + struct fs *fs; + struct buf *bp; + ufs_lbn_t lbn, nextlbn; + off_t bytesinfile; + long size, xfersize, blkoffset; + ssize_t orig_resid; + int error; + int seqcount; + int ioflag; + + vp = ap->a_vp; + uio = ap->a_uio; + ioflag = ap->a_ioflag; + if (ap->a_ioflag & IO_EXT) +#ifdef notyet + return (ffs_extread(vp, uio, ioflag)); +#else + panic("ffs_read+IO_EXT"); +#endif +#ifdef DIRECTIO + if ((ioflag & IO_DIRECT) != 0) { + int workdone; + + error = ffs_rawread(vp, uio, &workdone); + if (error != 0 || workdone != 0) + return error; + } +#endif + + seqcount = ap->a_ioflag >> IO_SEQSHIFT; + ip = VTOI(vp); + +#ifdef INVARIANTS + if (uio->uio_rw != UIO_READ) + panic("ffs_read: mode"); + + if (vp->v_type == VLNK) { + if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen) + panic("ffs_read: short symlink"); + } else if (vp->v_type != VREG && vp->v_type != VDIR) + panic("ffs_read: type %d", vp->v_type); +#endif + orig_resid = uio->uio_resid; + KASSERT(orig_resid >= 0, ("ffs_read: uio->uio_resid < 0")); + if (orig_resid == 0) + return (0); + KASSERT(uio->uio_offset >= 0, ("ffs_read: uio->uio_offset < 0")); + fs = ITOFS(ip); + if (uio->uio_offset < ip->i_size && + uio->uio_offset >= fs->fs_maxfilesize) + return (EOVERFLOW); + + for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { + if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0) + break; + lbn = lblkno(fs, uio->uio_offset); + nextlbn = lbn + 1; + + /* + * size of buffer. The buffer representing the + * end of the file is rounded up to the size of + * the block type ( fragment or full block, + * depending ). + */ + size = blksize(fs, ip, lbn); + blkoffset = blkoff(fs, uio->uio_offset); + + /* + * The amount we want to transfer in this iteration is + * one FS block less the amount of the data before + * our startpoint (duh!) + */ + xfersize = fs->fs_bsize - blkoffset; + + /* + * But if we actually want less than the block, + * or the file doesn't have a whole block more of data, + * then use the lesser number. + */ + if (uio->uio_resid < xfersize) + xfersize = uio->uio_resid; + if (bytesinfile < xfersize) + xfersize = bytesinfile; + + if (lblktosize(fs, nextlbn) >= ip->i_size) { + /* + * Don't do readahead if this is the end of the file. + */ + error = bread_gb(vp, lbn, size, NOCRED, + GB_UNMAPPED, &bp); + } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { + /* + * Otherwise if we are allowed to cluster, + * grab as much as we can. + * + * XXX This may not be a win if we are not + * doing sequential access. + */ + error = cluster_read(vp, ip->i_size, lbn, + size, NOCRED, blkoffset + uio->uio_resid, + seqcount, GB_UNMAPPED, &bp); + } else if (seqcount > 1) { + /* + * If we are NOT allowed to cluster, then + * if we appear to be acting sequentially, + * fire off a request for a readahead + * as well as a read. Note that the 4th and 5th + * arguments point to arrays of the size specified in + * the 6th argument. + */ + u_int nextsize = blksize(fs, ip, nextlbn); + error = breadn_flags(vp, lbn, size, &nextlbn, + &nextsize, 1, NOCRED, GB_UNMAPPED, &bp); + } else { + /* + * Failing all of the above, just read what the + * user asked for. Interestingly, the same as + * the first option above. + */ + error = bread_gb(vp, lbn, size, NOCRED, + GB_UNMAPPED, &bp); + } + if (error) { + brelse(bp); + bp = NULL; + break; + } + + /* + * We should only get non-zero b_resid when an I/O error + * has occurred, which should cause us to break above. + * However, if the short read did not cause an error, + * then we want to ensure that we do not uiomove bad + * or uninitialized data. + */ + size -= bp->b_resid; + if (size < xfersize) { + if (size == 0) + break; + xfersize = size; + } + + if (buf_mapped(bp)) { + error = vn_io_fault_uiomove((char *)bp->b_data + + blkoffset, (int)xfersize, uio); + } else { + error = vn_io_fault_pgmove(bp->b_pages, blkoffset, + (int)xfersize, uio); + } + if (error) + break; + + vfs_bio_brelse(bp, ioflag); + } + + /* + * This can only happen in the case of an error + * because the loop above resets bp to NULL on each iteration + * and on normal completion has not set a new value into it. + * so it must have come from a 'break' statement + */ + if (bp != NULL) + vfs_bio_brelse(bp, ioflag); + + if ((error == 0 || uio->uio_resid != orig_resid) && + (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0 && + (ip->i_flag & IN_ACCESS) == 0) { + VI_LOCK(vp); + ip->i_flag |= IN_ACCESS; + VI_UNLOCK(vp); + } + return (error); +} + +/* + * Vnode op for writing. + */ +static int +ffs_write(ap) + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + struct vnode *vp; + struct uio *uio; + struct inode *ip; + struct fs *fs; + struct buf *bp; + ufs_lbn_t lbn; + off_t osize; + ssize_t resid; + int seqcount; + int blkoffset, error, flags, ioflag, size, xfersize; + + vp = ap->a_vp; + uio = ap->a_uio; + ioflag = ap->a_ioflag; + if (ap->a_ioflag & IO_EXT) +#ifdef notyet + return (ffs_extwrite(vp, uio, ioflag, ap->a_cred)); +#else + panic("ffs_write+IO_EXT"); +#endif + + seqcount = ap->a_ioflag >> IO_SEQSHIFT; + ip = VTOI(vp); + +#ifdef INVARIANTS + if (uio->uio_rw != UIO_WRITE) + panic("ffs_write: mode"); +#endif + + switch (vp->v_type) { + case VREG: + if (ioflag & IO_APPEND) + uio->uio_offset = ip->i_size; + if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size) + return (EPERM); + /* FALLTHROUGH */ + case VLNK: + break; + case VDIR: + panic("ffs_write: dir write"); + break; + default: + panic("ffs_write: type %p %d (%d,%d)", vp, (int)vp->v_type, + (int)uio->uio_offset, + (int)uio->uio_resid + ); + } + + KASSERT(uio->uio_resid >= 0, ("ffs_write: uio->uio_resid < 0")); + KASSERT(uio->uio_offset >= 0, ("ffs_write: uio->uio_offset < 0")); + fs = ITOFS(ip); + if ((uoff_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) + return (EFBIG); + /* + * Maybe this should be above the vnode op call, but so long as + * file servers have no limits, I don't think it matters. + */ + if (vn_rlimit_fsize(vp, uio, uio->uio_td)) + return (EFBIG); + + resid = uio->uio_resid; + osize = ip->i_size; + if (seqcount > BA_SEQMAX) + flags = BA_SEQMAX << BA_SEQSHIFT; + else + flags = seqcount << BA_SEQSHIFT; + if ((ioflag & IO_SYNC) && !DOINGASYNC(vp)) + flags |= IO_SYNC; + flags |= BA_UNMAPPED; + + for (error = 0; uio->uio_resid > 0;) { + lbn = lblkno(fs, uio->uio_offset); + blkoffset = blkoff(fs, uio->uio_offset); + xfersize = fs->fs_bsize - blkoffset; + if (uio->uio_resid < xfersize) + xfersize = uio->uio_resid; + if (uio->uio_offset + xfersize > ip->i_size) + vnode_pager_setsize(vp, uio->uio_offset + xfersize); + + /* + * We must perform a read-before-write if the transfer size + * does not cover the entire buffer. + */ + if (fs->fs_bsize > xfersize) + flags |= BA_CLRBUF; + else + flags &= ~BA_CLRBUF; +/* XXX is uio->uio_offset the right thing here? */ + error = UFS_BALLOC(vp, uio->uio_offset, xfersize, + ap->a_cred, flags, &bp); + if (error != 0) { + vnode_pager_setsize(vp, ip->i_size); + break; + } + if ((ioflag & (IO_SYNC|IO_INVAL)) == (IO_SYNC|IO_INVAL)) + bp->b_flags |= B_NOCACHE; + + if (uio->uio_offset + xfersize > ip->i_size) { + ip->i_size = uio->uio_offset + xfersize; + DIP_SET(ip, i_size, ip->i_size); + } + + size = blksize(fs, ip, lbn) - bp->b_resid; + if (size < xfersize) + xfersize = size; + + if (buf_mapped(bp)) { + error = vn_io_fault_uiomove((char *)bp->b_data + + blkoffset, (int)xfersize, uio); + } else { + error = vn_io_fault_pgmove(bp->b_pages, blkoffset, + (int)xfersize, uio); + } + /* + * If the buffer is not already filled and we encounter an + * error while trying to fill it, we have to clear out any + * garbage data from the pages instantiated for the buffer. + * If we do not, a failed uiomove() during a write can leave + * the prior contents of the pages exposed to a userland mmap. + * + * Note that we need only clear buffers with a transfer size + * equal to the block size because buffers with a shorter + * transfer size were cleared above by the call to UFS_BALLOC() + * with the BA_CLRBUF flag set. + * + * If the source region for uiomove identically mmaps the + * buffer, uiomove() performed the NOP copy, and the buffer + * content remains valid because the page fault handler + * validated the pages. + */ + if (error != 0 && (bp->b_flags & B_CACHE) == 0 && + fs->fs_bsize == xfersize) + vfs_bio_clrbuf(bp); + + vfs_bio_set_flags(bp, ioflag); + + /* + * If IO_SYNC each buffer is written synchronously. Otherwise + * if we have a severe page deficiency write the buffer + * asynchronously. Otherwise try to cluster, and if that + * doesn't do it then either do an async write (if O_DIRECT), + * or a delayed write (if not). + */ + if (ioflag & IO_SYNC) { + (void)bwrite(bp); + } else if (vm_page_count_severe() || + buf_dirty_count_severe() || + (ioflag & IO_ASYNC)) { + bp->b_flags |= B_CLUSTEROK; + bawrite(bp); + } else if (xfersize + blkoffset == fs->fs_bsize) { + if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) { + bp->b_flags |= B_CLUSTEROK; + cluster_write(vp, bp, ip->i_size, seqcount, + GB_UNMAPPED); + } else { + bawrite(bp); + } + } else if (ioflag & IO_DIRECT) { + bp->b_flags |= B_CLUSTEROK; + bawrite(bp); + } else { + bp->b_flags |= B_CLUSTEROK; + bdwrite(bp); + } + if (error || xfersize == 0) + break; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + } + /* + * If we successfully wrote any data, and we are not the superuser + * we clear the setuid and setgid bits as a precaution against + * tampering. + */ + if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && + ap->a_cred) { + if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID, 0)) { + ip->i_mode &= ~(ISUID | ISGID); + DIP_SET(ip, i_mode, ip->i_mode); + } + } + if (error) { + if (ioflag & IO_UNIT) { + (void)ffs_truncate(vp, osize, + IO_NORMAL | (ioflag & IO_SYNC), ap->a_cred); + uio->uio_offset -= resid - uio->uio_resid; + uio->uio_resid = resid; + } + } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) + error = ffs_update(vp, 1); + return (error); +} + +/* + * Extended attribute area reading. + */ +static int +ffs_extread(struct vnode *vp, struct uio *uio, int ioflag) +{ + struct inode *ip; + struct ufs2_dinode *dp; + struct fs *fs; + struct buf *bp; + ufs_lbn_t lbn, nextlbn; + off_t bytesinfile; + long size, xfersize, blkoffset; + ssize_t orig_resid; + int error; + + ip = VTOI(vp); + fs = ITOFS(ip); + dp = ip->i_din2; + +#ifdef INVARIANTS + if (uio->uio_rw != UIO_READ || fs->fs_magic != FS_UFS2_MAGIC) + panic("ffs_extread: mode"); + +#endif + orig_resid = uio->uio_resid; + KASSERT(orig_resid >= 0, ("ffs_extread: uio->uio_resid < 0")); + if (orig_resid == 0) + return (0); + KASSERT(uio->uio_offset >= 0, ("ffs_extread: uio->uio_offset < 0")); + + for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { + if ((bytesinfile = dp->di_extsize - uio->uio_offset) <= 0) + break; + lbn = lblkno(fs, uio->uio_offset); + nextlbn = lbn + 1; + + /* + * size of buffer. The buffer representing the + * end of the file is rounded up to the size of + * the block type ( fragment or full block, + * depending ). + */ + size = sblksize(fs, dp->di_extsize, lbn); + blkoffset = blkoff(fs, uio->uio_offset); + + /* + * The amount we want to transfer in this iteration is + * one FS block less the amount of the data before + * our startpoint (duh!) + */ + xfersize = fs->fs_bsize - blkoffset; + + /* + * But if we actually want less than the block, + * or the file doesn't have a whole block more of data, + * then use the lesser number. + */ + if (uio->uio_resid < xfersize) + xfersize = uio->uio_resid; + if (bytesinfile < xfersize) + xfersize = bytesinfile; + + if (lblktosize(fs, nextlbn) >= dp->di_extsize) { + /* + * Don't do readahead if this is the end of the info. + */ + error = bread(vp, -1 - lbn, size, NOCRED, &bp); + } else { + /* + * If we have a second block, then + * fire off a request for a readahead + * as well as a read. Note that the 4th and 5th + * arguments point to arrays of the size specified in + * the 6th argument. + */ + u_int nextsize = sblksize(fs, dp->di_extsize, nextlbn); + + nextlbn = -1 - nextlbn; + error = breadn(vp, -1 - lbn, + size, &nextlbn, &nextsize, 1, NOCRED, &bp); + } + if (error) { + brelse(bp); + bp = NULL; + break; + } + + /* + * We should only get non-zero b_resid when an I/O error + * has occurred, which should cause us to break above. + * However, if the short read did not cause an error, + * then we want to ensure that we do not uiomove bad + * or uninitialized data. + */ + size -= bp->b_resid; + if (size < xfersize) { + if (size == 0) + break; + xfersize = size; + } + + error = uiomove((char *)bp->b_data + blkoffset, + (int)xfersize, uio); + if (error) + break; + vfs_bio_brelse(bp, ioflag); + } + + /* + * This can only happen in the case of an error + * because the loop above resets bp to NULL on each iteration + * and on normal completion has not set a new value into it. + * so it must have come from a 'break' statement + */ + if (bp != NULL) + vfs_bio_brelse(bp, ioflag); + return (error); +} + +/* + * Extended attribute area writing. + */ +static int +ffs_extwrite(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *ucred) +{ + struct inode *ip; + struct ufs2_dinode *dp; + struct fs *fs; + struct buf *bp; + ufs_lbn_t lbn; + off_t osize; + ssize_t resid; + int blkoffset, error, flags, size, xfersize; + + ip = VTOI(vp); + fs = ITOFS(ip); + dp = ip->i_din2; + +#ifdef INVARIANTS + if (uio->uio_rw != UIO_WRITE || fs->fs_magic != FS_UFS2_MAGIC) + panic("ffs_extwrite: mode"); +#endif + + if (ioflag & IO_APPEND) + uio->uio_offset = dp->di_extsize; + KASSERT(uio->uio_offset >= 0, ("ffs_extwrite: uio->uio_offset < 0")); + KASSERT(uio->uio_resid >= 0, ("ffs_extwrite: uio->uio_resid < 0")); + if ((uoff_t)uio->uio_offset + uio->uio_resid > NXADDR * fs->fs_bsize) + return (EFBIG); + + resid = uio->uio_resid; + osize = dp->di_extsize; + flags = IO_EXT; + if ((ioflag & IO_SYNC) && !DOINGASYNC(vp)) + flags |= IO_SYNC; + + for (error = 0; uio->uio_resid > 0;) { + lbn = lblkno(fs, uio->uio_offset); + blkoffset = blkoff(fs, uio->uio_offset); + xfersize = fs->fs_bsize - blkoffset; + if (uio->uio_resid < xfersize) + xfersize = uio->uio_resid; + + /* + * We must perform a read-before-write if the transfer size + * does not cover the entire buffer. + */ + if (fs->fs_bsize > xfersize) + flags |= BA_CLRBUF; + else + flags &= ~BA_CLRBUF; + error = UFS_BALLOC(vp, uio->uio_offset, xfersize, + ucred, flags, &bp); + if (error != 0) + break; + /* + * If the buffer is not valid we have to clear out any + * garbage data from the pages instantiated for the buffer. + * If we do not, a failed uiomove() during a write can leave + * the prior contents of the pages exposed to a userland + * mmap(). XXX deal with uiomove() errors a better way. + */ + if ((bp->b_flags & B_CACHE) == 0 && fs->fs_bsize <= xfersize) + vfs_bio_clrbuf(bp); + + if (uio->uio_offset + xfersize > dp->di_extsize) + dp->di_extsize = uio->uio_offset + xfersize; + + size = sblksize(fs, dp->di_extsize, lbn) - bp->b_resid; + if (size < xfersize) + xfersize = size; + + error = + uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio); + + vfs_bio_set_flags(bp, ioflag); + + /* + * If IO_SYNC each buffer is written synchronously. Otherwise + * if we have a severe page deficiency write the buffer + * asynchronously. Otherwise try to cluster, and if that + * doesn't do it then either do an async write (if O_DIRECT), + * or a delayed write (if not). + */ + if (ioflag & IO_SYNC) { + (void)bwrite(bp); + } else if (vm_page_count_severe() || + buf_dirty_count_severe() || + xfersize + blkoffset == fs->fs_bsize || + (ioflag & (IO_ASYNC | IO_DIRECT))) + bawrite(bp); + else + bdwrite(bp); + if (error || xfersize == 0) + break; + ip->i_flag |= IN_CHANGE; + } + /* + * If we successfully wrote any data, and we are not the superuser + * we clear the setuid and setgid bits as a precaution against + * tampering. + */ + if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid && ucred) { + if (priv_check_cred(ucred, PRIV_VFS_RETAINSUGID, 0)) { + ip->i_mode &= ~(ISUID | ISGID); + dp->di_mode = ip->i_mode; + } + } + if (error) { + if (ioflag & IO_UNIT) { + (void)ffs_truncate(vp, osize, + IO_EXT | (ioflag&IO_SYNC), ucred); + uio->uio_offset -= resid - uio->uio_resid; + uio->uio_resid = resid; + } + } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) + error = ffs_update(vp, 1); + return (error); +} + + +/* + * Vnode operating to retrieve a named extended attribute. + * + * Locate a particular EA (nspace:name) in the area (ptr:length), and return + * the length of the EA, and possibly the pointer to the entry and to the data. + */ +static int +ffs_findextattr(u_char *ptr, u_int length, int nspace, const char *name, u_char **eap, u_char **eac) +{ + u_char *p, *pe, *pn, *p0; + int eapad1, eapad2, ealength, ealen, nlen; + uint32_t ul; + + pe = ptr + length; + nlen = strlen(name); + + for (p = ptr; p < pe; p = pn) { + p0 = p; + bcopy(p, &ul, sizeof(ul)); + pn = p + ul; + /* make sure this entry is complete */ + if (pn > pe) + break; + p += sizeof(uint32_t); + if (*p != nspace) + continue; + p++; + eapad2 = *p++; + if (*p != nlen) + continue; + p++; + if (bcmp(p, name, nlen)) + continue; + ealength = sizeof(uint32_t) + 3 + nlen; + eapad1 = 8 - (ealength % 8); + if (eapad1 == 8) + eapad1 = 0; + ealength += eapad1; + ealen = ul - ealength - eapad2; + p += nlen + eapad1; + if (eap != NULL) + *eap = p0; + if (eac != NULL) + *eac = p; + return (ealen); + } + return(-1); +} + +static int +ffs_rdextattr(u_char **p, struct vnode *vp, struct thread *td, int extra) +{ + struct inode *ip; + struct ufs2_dinode *dp; + struct fs *fs; + struct uio luio; + struct iovec liovec; + u_int easize; + int error; + u_char *eae; + + ip = VTOI(vp); + fs = ITOFS(ip); + dp = ip->i_din2; + easize = dp->di_extsize; + if ((uoff_t)easize + extra > NXADDR * fs->fs_bsize) + return (EFBIG); + + eae = malloc(easize + extra, M_TEMP, M_WAITOK); + + liovec.iov_base = eae; + liovec.iov_len = easize; + luio.uio_iov = &liovec; + luio.uio_iovcnt = 1; + luio.uio_offset = 0; + luio.uio_resid = easize; + luio.uio_segflg = UIO_SYSSPACE; + luio.uio_rw = UIO_READ; + luio.uio_td = td; + + error = ffs_extread(vp, &luio, IO_EXT | IO_SYNC); + if (error) { + free(eae, M_TEMP); + return(error); + } + *p = eae; + return (0); +} + +static void +ffs_lock_ea(struct vnode *vp) +{ + struct inode *ip; + + ip = VTOI(vp); + VI_LOCK(vp); + while (ip->i_flag & IN_EA_LOCKED) { + ip->i_flag |= IN_EA_LOCKWAIT; + msleep(&ip->i_ea_refs, &vp->v_interlock, PINOD + 2, "ufs_ea", + 0); + } + ip->i_flag |= IN_EA_LOCKED; + VI_UNLOCK(vp); +} + +static void +ffs_unlock_ea(struct vnode *vp) +{ + struct inode *ip; + + ip = VTOI(vp); + VI_LOCK(vp); + if (ip->i_flag & IN_EA_LOCKWAIT) + wakeup(&ip->i_ea_refs); + ip->i_flag &= ~(IN_EA_LOCKED | IN_EA_LOCKWAIT); + VI_UNLOCK(vp); +} + +static int +ffs_open_ea(struct vnode *vp, struct ucred *cred, struct thread *td) +{ + struct inode *ip; + struct ufs2_dinode *dp; + int error; + + ip = VTOI(vp); + + ffs_lock_ea(vp); + if (ip->i_ea_area != NULL) { + ip->i_ea_refs++; + ffs_unlock_ea(vp); + return (0); + } + dp = ip->i_din2; + error = ffs_rdextattr(&ip->i_ea_area, vp, td, 0); + if (error) { + ffs_unlock_ea(vp); + return (error); + } + ip->i_ea_len = dp->di_extsize; + ip->i_ea_error = 0; + ip->i_ea_refs++; + ffs_unlock_ea(vp); + return (0); +} + +/* + * Vnode extattr transaction commit/abort + */ +static int +ffs_close_ea(struct vnode *vp, int commit, struct ucred *cred, struct thread *td) +{ + struct inode *ip; + struct uio luio; + struct iovec liovec; + int error; + struct ufs2_dinode *dp; + + ip = VTOI(vp); + + ffs_lock_ea(vp); + if (ip->i_ea_area == NULL) { + ffs_unlock_ea(vp); + return (EINVAL); + } + dp = ip->i_din2; + error = ip->i_ea_error; + if (commit && error == 0) { + ASSERT_VOP_ELOCKED(vp, "ffs_close_ea commit"); + if (cred == NOCRED) + cred = vp->v_mount->mnt_cred; + liovec.iov_base = ip->i_ea_area; + liovec.iov_len = ip->i_ea_len; + luio.uio_iov = &liovec; + luio.uio_iovcnt = 1; + luio.uio_offset = 0; + luio.uio_resid = ip->i_ea_len; + luio.uio_segflg = UIO_SYSSPACE; + luio.uio_rw = UIO_WRITE; + luio.uio_td = td; + /* XXX: I'm not happy about truncating to zero size */ + if (ip->i_ea_len < dp->di_extsize) + error = ffs_truncate(vp, 0, IO_EXT, cred); + error = ffs_extwrite(vp, &luio, IO_EXT | IO_SYNC, cred); + } + if (--ip->i_ea_refs == 0) { + free(ip->i_ea_area, M_TEMP); + ip->i_ea_area = NULL; + ip->i_ea_len = 0; + ip->i_ea_error = 0; + } + ffs_unlock_ea(vp); + return (error); +} + +/* + * Vnode extattr strategy routine for fifos. + * + * We need to check for a read or write of the external attributes. + * Otherwise we just fall through and do the usual thing. + */ +static int +ffsext_strategy(struct vop_strategy_args *ap) +/* +struct vop_strategy_args { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + struct buf *a_bp; +}; +*/ +{ + struct vnode *vp; + daddr_t lbn; + + vp = ap->a_vp; + lbn = ap->a_bp->b_lblkno; + if (I_IS_UFS2(VTOI(vp)) && lbn < 0 && lbn >= -NXADDR) + return (VOP_STRATEGY_APV(&ufs_vnodeops, ap)); + if (vp->v_type == VFIFO) + return (VOP_STRATEGY_APV(&ufs_fifoops, ap)); + panic("spec nodes went here"); +} + +/* + * Vnode extattr transaction commit/abort + */ +static int +ffs_openextattr(struct vop_openextattr_args *ap) +/* +struct vop_openextattr_args { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + + if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + return (EOPNOTSUPP); + + return (ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td)); +} + + +/* + * Vnode extattr transaction commit/abort + */ +static int +ffs_closeextattr(struct vop_closeextattr_args *ap) +/* +struct vop_closeextattr_args { + struct vnodeop_desc *a_desc; + struct vnode *a_vp; + int a_commit; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + + if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + return (EOPNOTSUPP); + + if (ap->a_commit && (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)) + return (EROFS); + + return (ffs_close_ea(ap->a_vp, ap->a_commit, ap->a_cred, ap->a_td)); +} + +/* + * Vnode operation to remove a named attribute. + */ +static int +ffs_deleteextattr(struct vop_deleteextattr_args *ap) +/* +vop_deleteextattr { + IN struct vnode *a_vp; + IN int a_attrnamespace; + IN const char *a_name; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct inode *ip; + struct fs *fs; + uint32_t ealength, ul; + int ealen, olen, eapad1, eapad2, error, i, easize; + u_char *eae, *p; + + ip = VTOI(ap->a_vp); + fs = ITOFS(ip); + + if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + return (EOPNOTSUPP); + + if (strlen(ap->a_name) == 0) + return (EINVAL); + + if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + + error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, + ap->a_cred, ap->a_td, VWRITE); + if (error) { + + /* + * ffs_lock_ea is not needed there, because the vnode + * must be exclusively locked. + */ + if (ip->i_ea_area != NULL && ip->i_ea_error == 0) + ip->i_ea_error = error; + return (error); + } + + error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); + if (error) + return (error); + + ealength = eapad1 = ealen = eapad2 = 0; + + eae = malloc(ip->i_ea_len, M_TEMP, M_WAITOK); + bcopy(ip->i_ea_area, eae, ip->i_ea_len); + easize = ip->i_ea_len; + + olen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name, + &p, NULL); + if (olen == -1) { + /* delete but nonexistent */ + free(eae, M_TEMP); + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); + return(ENOATTR); + } + bcopy(p, &ul, sizeof ul); + i = p - eae + ul; + if (ul != ealength) { + bcopy(p + ul, p + ealength, easize - i); + easize += (ealength - ul); + } + if (easize > NXADDR * fs->fs_bsize) { + free(eae, M_TEMP); + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); + if (ip->i_ea_area != NULL && ip->i_ea_error == 0) + ip->i_ea_error = ENOSPC; + return(ENOSPC); + } + p = ip->i_ea_area; + ip->i_ea_area = eae; + ip->i_ea_len = easize; + free(p, M_TEMP); + error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td); + return(error); +} + +/* + * Vnode operation to retrieve a named extended attribute. + */ +static int +ffs_getextattr(struct vop_getextattr_args *ap) +/* +vop_getextattr { + IN struct vnode *a_vp; + IN int a_attrnamespace; + IN const char *a_name; + INOUT struct uio *a_uio; + OUT size_t *a_size; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct inode *ip; + u_char *eae, *p; + unsigned easize; + int error, ealen; + + ip = VTOI(ap->a_vp); + + if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + return (EOPNOTSUPP); + + error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, + ap->a_cred, ap->a_td, VREAD); + if (error) + return (error); + + error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); + if (error) + return (error); + + eae = ip->i_ea_area; + easize = ip->i_ea_len; + + ealen = ffs_findextattr(eae, easize, ap->a_attrnamespace, ap->a_name, + NULL, &p); + if (ealen >= 0) { + error = 0; + if (ap->a_size != NULL) + *ap->a_size = ealen; + else if (ap->a_uio != NULL) + error = uiomove(p, ealen, ap->a_uio); + } else + error = ENOATTR; + + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); + return(error); +} + +/* + * Vnode operation to retrieve extended attributes on a vnode. + */ +static int +ffs_listextattr(struct vop_listextattr_args *ap) +/* +vop_listextattr { + IN struct vnode *a_vp; + IN int a_attrnamespace; + INOUT struct uio *a_uio; + OUT size_t *a_size; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct inode *ip; + u_char *eae, *p, *pe, *pn; + unsigned easize; + uint32_t ul; + int error, ealen; + + ip = VTOI(ap->a_vp); + + if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + return (EOPNOTSUPP); + + error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, + ap->a_cred, ap->a_td, VREAD); + if (error) + return (error); + + error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); + if (error) + return (error); + eae = ip->i_ea_area; + easize = ip->i_ea_len; + + error = 0; + if (ap->a_size != NULL) + *ap->a_size = 0; + pe = eae + easize; + for(p = eae; error == 0 && p < pe; p = pn) { + bcopy(p, &ul, sizeof(ul)); + pn = p + ul; + if (pn > pe) + break; + p += sizeof(ul); + if (*p++ != ap->a_attrnamespace) + continue; + p++; /* pad2 */ + ealen = *p; + if (ap->a_size != NULL) { + *ap->a_size += ealen + 1; + } else if (ap->a_uio != NULL) { + error = uiomove(p, ealen + 1, ap->a_uio); + } + } + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); + return(error); +} + +/* + * Vnode operation to set a named attribute. + */ +static int +ffs_setextattr(struct vop_setextattr_args *ap) +/* +vop_setextattr { + IN struct vnode *a_vp; + IN int a_attrnamespace; + IN const char *a_name; + INOUT struct uio *a_uio; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct inode *ip; + struct fs *fs; + uint32_t ealength, ul; + ssize_t ealen; + int olen, eapad1, eapad2, error, i, easize; + u_char *eae, *p; + + ip = VTOI(ap->a_vp); + fs = ITOFS(ip); + + if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK) + return (EOPNOTSUPP); + + if (strlen(ap->a_name) == 0) + return (EINVAL); + + /* XXX Now unsupported API to delete EAs using NULL uio. */ + if (ap->a_uio == NULL) + return (EOPNOTSUPP); + + if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + + ealen = ap->a_uio->uio_resid; + if (ealen < 0 || ealen > lblktosize(fs, NXADDR)) + return (EINVAL); + + error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace, + ap->a_cred, ap->a_td, VWRITE); + if (error) { + + /* + * ffs_lock_ea is not needed there, because the vnode + * must be exclusively locked. + */ + if (ip->i_ea_area != NULL && ip->i_ea_error == 0) + ip->i_ea_error = error; + return (error); + } + + error = ffs_open_ea(ap->a_vp, ap->a_cred, ap->a_td); + if (error) + return (error); + + ealength = sizeof(uint32_t) + 3 + strlen(ap->a_name); + eapad1 = 8 - (ealength % 8); + if (eapad1 == 8) + eapad1 = 0; + eapad2 = 8 - (ealen % 8); + if (eapad2 == 8) + eapad2 = 0; + ealength += eapad1 + ealen + eapad2; + + eae = malloc(ip->i_ea_len + ealength, M_TEMP, M_WAITOK); + bcopy(ip->i_ea_area, eae, ip->i_ea_len); + easize = ip->i_ea_len; + + olen = ffs_findextattr(eae, easize, + ap->a_attrnamespace, ap->a_name, &p, NULL); + if (olen == -1) { + /* new, append at end */ + p = eae + easize; + easize += ealength; + } else { + bcopy(p, &ul, sizeof ul); + i = p - eae + ul; + if (ul != ealength) { + bcopy(p + ul, p + ealength, easize - i); + easize += (ealength - ul); + } + } + if (easize > lblktosize(fs, NXADDR)) { + free(eae, M_TEMP); + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); + if (ip->i_ea_area != NULL && ip->i_ea_error == 0) + ip->i_ea_error = ENOSPC; + return(ENOSPC); + } + bcopy(&ealength, p, sizeof(ealength)); + p += sizeof(ealength); + *p++ = ap->a_attrnamespace; + *p++ = eapad2; + *p++ = strlen(ap->a_name); + strcpy(p, ap->a_name); + p += strlen(ap->a_name); + bzero(p, eapad1); + p += eapad1; + error = uiomove(p, ealen, ap->a_uio); + if (error) { + free(eae, M_TEMP); + ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); + if (ip->i_ea_area != NULL && ip->i_ea_error == 0) + ip->i_ea_error = error; + return(error); + } + p += ealen; + bzero(p, eapad2); + + p = ip->i_ea_area; + ip->i_ea_area = eae; + ip->i_ea_len = easize; + free(p, M_TEMP); + error = ffs_close_ea(ap->a_vp, 1, ap->a_cred, ap->a_td); + return(error); +} + +/* + * Vnode pointer to File handle + */ +static int +ffs_vptofh(struct vop_vptofh_args *ap) +/* +vop_vptofh { + IN struct vnode *a_vp; + IN struct fid *a_fhp; +}; +*/ +{ + struct inode *ip; + struct ufid *ufhp; + + ip = VTOI(ap->a_vp); + ufhp = (struct ufid *)ap->a_fhp; + ufhp->ufid_len = sizeof(struct ufid); + ufhp->ufid_ino = ip->i_number; + ufhp->ufid_gen = ip->i_gen; + return (0); +} + +SYSCTL_DECL(_vfs_ffs); +static int use_buf_pager = 0; +SYSCTL_INT(_vfs_ffs, OID_AUTO, use_buf_pager, CTLFLAG_RWTUN, &use_buf_pager, 0, + "Always use buffer pager instead of bmap"); + +static daddr_t +ffs_gbp_getblkno(struct vnode *vp, vm_ooffset_t off) +{ + + return (lblkno(VFSTOUFS(vp->v_mount)->um_fs, off)); +} + +static int +ffs_gbp_getblksz(struct vnode *vp, daddr_t lbn) +{ + + return (blksize(VFSTOUFS(vp->v_mount)->um_fs, VTOI(vp), lbn)); +} + +static int +ffs_getpages(struct vop_getpages_args *ap) +{ + struct vnode *vp; + struct ufsmount *um; + + vp = ap->a_vp; + um = VFSTOUFS(vp->v_mount); + + if (!use_buf_pager && um->um_devvp->v_bufobj.bo_bsize <= PAGE_SIZE) + return (vnode_pager_generic_getpages(vp, ap->a_m, ap->a_count, + ap->a_rbehind, ap->a_rahead, NULL, NULL)); + return (vfs_bio_getpages(vp, ap->a_m, ap->a_count, ap->a_rbehind, + ap->a_rahead, ffs_gbp_getblkno, ffs_gbp_getblksz)); +} diff --git a/Dump/ufs/ffs/fs.h b/Dump/ufs/ffs/fs.h new file mode 100644 index 0000000..233b347 --- /dev/null +++ b/Dump/ufs/ffs/fs.h @@ -0,0 +1,792 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fs.h 8.13 (Berkeley) 3/21/95 + * $FreeBSD: releng/11.2/sys/ufs/ffs/fs.h 331722 2018-03-29 02:50:57Z eadler $ + */ + +#ifndef _UFS_FFS_FS_H_ +#define _UFS_FFS_FS_H_ + +#include +#include + +/* + * Each disk drive contains some number of filesystems. + * A filesystem consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A filesystem is described by its super-block, which in turn + * describes the cylinder groups. The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss. This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For filesystem fs, the offsets of the various blocks of interest + * are given in the super block as: + * [fs->fs_sblkno] Super-block + * [fs->fs_cblkno] Cylinder group block + * [fs->fs_iblkno] Inode blocks + * [fs->fs_dblkno] Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * Depending on the architecture and the media, the superblock may + * reside in any one of four places. For tiny media where every block + * counts, it is placed at the very front of the partition. Historically, + * UFS1 placed it 8K from the front to leave room for the disk label and + * a small bootstrap. For UFS2 it got moved to 64K from the front to leave + * room for the disk label and a bigger bootstrap, and for really piggy + * systems we check at 256K from the front if the first three fail. In + * all cases the size of the superblock will be SBLOCKSIZE. All values are + * given in byte-offset form, so they do not imply a sector size. The + * SBLOCKSEARCH specifies the order in which the locations should be searched. + */ +#define SBLOCK_FLOPPY 0 +#define SBLOCK_UFS1 8192 +#define SBLOCK_UFS2 65536 +#define SBLOCK_PIGGY 262144 +#define SBLOCKSIZE 8192 +#define SBLOCKSEARCH \ + { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 } + +/* + * Max number of fragments per block. This value is NOT tweakable. + */ +#define MAXFRAG 8 + +/* + * Addresses stored in inodes are capable of addressing fragments + * of `blocks'. File system blocks of at most size MAXBSIZE can + * be optionally broken into 2, 4, or 8 pieces, each of which is + * addressable; these pieces may be DEV_BSIZE, or some multiple of + * a DEV_BSIZE unit. + * + * Large files consist of exclusively large data blocks. To avoid + * undue wasted disk space, the last data block of a small file may be + * allocated as only as many fragments of a large block as are + * necessary. The filesystem format retains only a single pointer + * to such a fragment, which is a piece of a single large block that + * has been divided. The size of such a fragment is determinable from + * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. + * + * The filesystem records space availability at the fragment level; + * to determine block availability, aligned fragments are examined. + */ + +/* + * MINBSIZE is the smallest allowable block size. + * In order to insure that it is possible to create files of size + * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. + * MINBSIZE must be big enough to hold a cylinder group block, + * thus changes to (struct cg) must keep its size within MINBSIZE. + * Note that super blocks are always of size SBLOCKSIZE, + * and that both SBLOCKSIZE and MAXBSIZE must be >= MINBSIZE. + */ +#define MINBSIZE 4096 + +/* + * The path name on which the filesystem is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + */ +#define MAXMNTLEN 468 + +/* + * The volume name for this filesystem is maintained in fs_volname. + * MAXVOLLEN defines the length of the buffer allocated. + */ +#define MAXVOLLEN 32 + +/* + * There is a 128-byte region in the superblock reserved for in-core + * pointers to summary information. Originally this included an array + * of pointers to blocks of struct csum; now there are just a few + * pointers and the remaining space is padded with fs_ocsp[]. + * + * NOCSPTRS determines the size of this padding. One pointer (fs_csp) + * is taken away to point to a contiguous array of struct csum for + * all cylinder groups; a second (fs_maxcluster) points to an array + * of cluster sizes that is computed as cylinder groups are inspected, + * and the third points to an array that tracks the creation of new + * directories. A fourth pointer, fs_active, is used when creating + * snapshots; it points to a bitmap of cylinder groups for which the + * free-block bitmap has changed since the snapshot operation began. + */ +#define NOCSPTRS ((128 / sizeof(void *)) - 4) + +/* + * A summary of contiguous blocks of various sizes is maintained + * in each cylinder group. Normally this is set by the initial + * value of fs_maxcontig. To conserve space, a maximum summary size + * is set by FS_MAXCONTIG. + */ +#define FS_MAXCONTIG 16 + +/* + * MINFREE gives the minimum acceptable percentage of filesystem + * blocks which may be free. If the freelist drops below this level + * only the superuser may continue to allocate blocks. This may + * be set to 0 if no reserve of free blocks is deemed necessary, + * however throughput drops by fifty percent if the filesystem + * is run at between 95% and 100% full; thus the minimum default + * value of fs_minfree is 5%. However, to get good clustering + * performance, 10% is a better choice. hence we use 10% as our + * default value. With 10% free space, fragmentation is not a + * problem, so we choose to optimize for time. + */ +#define MINFREE 8 +#define DEFAULTOPT FS_OPTTIME + +/* + * Grigoriy Orlov has done some extensive work to fine + * tune the layout preferences for directories within a filesystem. + * His algorithm can be tuned by adjusting the following parameters + * which tell the system the average file size and the average number + * of files per directory. These defaults are well selected for typical + * filesystems, but may need to be tuned for odd cases like filesystems + * being used for squid caches or news spools. + */ +#define AVFILESIZ 16384 /* expected average file size */ +#define AFPDIR 64 /* expected number of files per directory */ + +/* + * The maximum number of snapshot nodes that can be associated + * with each filesystem. This limit affects only the number of + * snapshot files that can be recorded within the superblock so + * that they can be found when the filesystem is mounted. However, + * maintaining too many will slow the filesystem performance, so + * having this limit is a good idea. + */ +#define FSMAXSNAP 20 + +/* + * Used to identify special blocks in snapshots: + * + * BLK_NOCOPY - A block that was unallocated at the time the snapshot + * was taken, hence does not need to be copied when written. + * BLK_SNAP - A block held by another snapshot that is not needed by this + * snapshot. When the other snapshot is freed, the BLK_SNAP entries + * are converted to BLK_NOCOPY. These are needed to allow fsck to + * identify blocks that are in use by other snapshots (which are + * expunged from this snapshot). + */ +#define BLK_NOCOPY ((ufs2_daddr_t)(1)) +#define BLK_SNAP ((ufs2_daddr_t)(2)) + +/* + * Sysctl values for the fast filesystem. + */ +#define FFS_ADJ_REFCNT 1 /* adjust inode reference count */ +#define FFS_ADJ_BLKCNT 2 /* adjust inode used block count */ +#define FFS_BLK_FREE 3 /* free range of blocks in map */ +#define FFS_DIR_FREE 4 /* free specified dir inodes in map */ +#define FFS_FILE_FREE 5 /* free specified file inodes in map */ +#define FFS_SET_FLAGS 6 /* set filesystem flags */ +#define FFS_ADJ_NDIR 7 /* adjust number of directories */ +#define FFS_ADJ_NBFREE 8 /* adjust number of free blocks */ +#define FFS_ADJ_NIFREE 9 /* adjust number of free inodes */ +#define FFS_ADJ_NFFREE 10 /* adjust number of free frags */ +#define FFS_ADJ_NUMCLUSTERS 11 /* adjust number of free clusters */ +#define FFS_SET_CWD 12 /* set current directory */ +#define FFS_SET_DOTDOT 13 /* set inode number for ".." */ +#define FFS_UNLINK 14 /* remove a name in the filesystem */ +#define FFS_SET_INODE 15 /* update an on-disk inode */ +#define FFS_SET_BUFOUTPUT 16 /* set buffered writing on descriptor */ +#define FFS_MAXID 16 /* number of valid ffs ids */ + +/* + * Command structure passed in to the filesystem to adjust filesystem values. + */ +#define FFS_CMD_VERSION 0x19790518 /* version ID */ +struct fsck_cmd { + int32_t version; /* version of command structure */ + int32_t handle; /* reference to filesystem to be changed */ + int64_t value; /* inode or block number to be affected */ + int64_t size; /* amount or range to be adjusted */ + int64_t spare; /* reserved for future use */ +}; + +/* + * A recovery structure placed at the end of the boot block area by newfs + * that can be used by fsck to search for alternate superblocks. + */ +#define RESID (4096 - 20) /* disk sector size minus recovery area size */ +struct fsrecovery { + char block[RESID]; /* unused part of sector */ + int32_t fsr_magic; /* magic number */ + int32_t fsr_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + int32_t fsr_sblkno; /* offset of super-block in filesys */ + int32_t fsr_fpg; /* blocks per group * fs_frag */ + u_int32_t fsr_ncg; /* number of cylinder groups */ +}; + +/* + * Per cylinder group information; summarized in blocks allocated + * from first cylinder group data blocks. These blocks have to be + * read in from fs_csaddr (size fs_cssize) in addition to the + * super block. + */ +struct csum { + int32_t cs_ndir; /* number of directories */ + int32_t cs_nbfree; /* number of free blocks */ + int32_t cs_nifree; /* number of free inodes */ + int32_t cs_nffree; /* number of free frags */ +}; +struct csum_total { + int64_t cs_ndir; /* number of directories */ + int64_t cs_nbfree; /* number of free blocks */ + int64_t cs_nifree; /* number of free inodes */ + int64_t cs_nffree; /* number of free frags */ + int64_t cs_numclusters; /* number of free clusters */ + int64_t cs_spare[3]; /* future expansion */ +}; + +/* + * Super block for an FFS filesystem. + */ +struct fs { + int32_t fs_firstfield; /* historic filesystem linked list, */ + int32_t fs_unused_1; /* used for incore super blocks */ + int32_t fs_sblkno; /* offset of super-block in filesys */ + int32_t fs_cblkno; /* offset of cyl-block in filesys */ + int32_t fs_iblkno; /* offset of inode-blocks in filesys */ + int32_t fs_dblkno; /* offset of first data after cg */ + int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */ + int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */ + int32_t fs_old_time; /* last time written */ + int32_t fs_old_size; /* number of blocks in fs */ + int32_t fs_old_dsize; /* number of data blocks in fs */ + u_int32_t fs_ncg; /* number of cylinder groups */ + int32_t fs_bsize; /* size of basic blocks in fs */ + int32_t fs_fsize; /* size of frag blocks in fs */ + int32_t fs_frag; /* number of frags in a block in fs */ +/* these are configuration parameters */ + int32_t fs_minfree; /* minimum percentage of free blocks */ + int32_t fs_old_rotdelay; /* num of ms for optimal next block */ + int32_t fs_old_rps; /* disk revolutions per second */ +/* these fields can be computed from the others */ + int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */ + int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */ + int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */ + int32_t fs_fshift; /* ``numfrags'' calc number of frags */ +/* these are configuration parameters */ + int32_t fs_maxcontig; /* max number of contiguous blks */ + int32_t fs_maxbpg; /* max number of blks per cyl group */ +/* these fields can be computed from the others */ + int32_t fs_fragshift; /* block to frag shift */ + int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + int32_t fs_sbsize; /* actual size of super block */ + int32_t fs_spare1[2]; /* old fs_csmask */ + /* old fs_csshift */ + int32_t fs_nindir; /* value of NINDIR */ + u_int32_t fs_inopb; /* value of INOPB */ + int32_t fs_old_nspf; /* value of NSPF */ +/* yet another configuration parameter */ + int32_t fs_optim; /* optimization preference, see below */ + int32_t fs_old_npsect; /* # sectors/track including spares */ + int32_t fs_old_interleave; /* hardware sector interleave */ + int32_t fs_old_trackskew; /* sector 0 skew, per track */ + int32_t fs_id[2]; /* unique filesystem id */ +/* sizes determined by number of cylinder groups and their sizes */ + int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */ + int32_t fs_cssize; /* size of cyl grp summary area */ + int32_t fs_cgsize; /* cylinder group size */ + int32_t fs_spare2; /* old fs_ntrak */ + int32_t fs_old_nsect; /* sectors per track */ + int32_t fs_old_spc; /* sectors per cylinder */ + int32_t fs_old_ncyl; /* cylinders in filesystem */ + int32_t fs_old_cpg; /* cylinders per group */ + u_int32_t fs_ipg; /* inodes per group */ + int32_t fs_fpg; /* blocks per group * fs_frag */ +/* this data must be re-computed after crashes */ + struct csum fs_old_cstotal; /* cylinder summary information */ +/* these fields are cleared at mount time */ + int8_t fs_fmod; /* super block modified flag */ + int8_t fs_clean; /* filesystem is clean flag */ + int8_t fs_ronly; /* mounted read-only flag */ + int8_t fs_old_flags; /* old FS_ flags */ + u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ + u_char fs_volname[MAXVOLLEN]; /* volume name */ + u_int64_t fs_swuid; /* system-wide uid */ + int32_t fs_pad; /* due to alignment of fs_swuid */ +/* these fields retain the current block allocation info */ + int32_t fs_cgrotor; /* last cg searched */ + void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */ + u_int8_t *fs_contigdirs; /* (u) # of contig. allocated dirs */ + struct csum *fs_csp; /* (u) cg summary info buffer */ + int32_t *fs_maxcluster; /* (u) max cluster in each cyl group */ + u_int *fs_active; /* (u) used by snapshots to track fs */ + int32_t fs_old_cpc; /* cyl per cycle in postbl */ + int32_t fs_maxbsize; /* maximum blocking factor permitted */ + int64_t fs_unrefs; /* number of unreferenced inodes */ + int64_t fs_providersize; /* size of underlying GEOM provider */ + int64_t fs_metaspace; /* size of area reserved for metadata */ + int64_t fs_sparecon64[14]; /* old rotation block list head */ + int64_t fs_sblockloc; /* byte offset of standard superblock */ + struct csum_total fs_cstotal; /* (u) cylinder summary information */ + ufs_time_t fs_time; /* last time written */ + int64_t fs_size; /* number of blocks in fs */ + int64_t fs_dsize; /* number of data blocks in fs */ + ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ + int64_t fs_pendingblocks; /* (u) blocks being freed */ + u_int32_t fs_pendinginodes; /* (u) inodes being freed */ + uint32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */ + u_int32_t fs_avgfilesize; /* expected average file size */ + u_int32_t fs_avgfpdir; /* expected # of files per directory */ + int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */ + ufs_time_t fs_mtime; /* Last mount or fsck time. */ + int32_t fs_sujfree; /* SUJ free list */ + int32_t fs_sparecon32[23]; /* reserved for future constants */ + int32_t fs_flags; /* see FS_ flags below */ + int32_t fs_contigsumsize; /* size of cluster summary array */ + int32_t fs_maxsymlinklen; /* max length of an internal symlink */ + int32_t fs_old_inodefmt; /* format of on-disk inodes */ + u_int64_t fs_maxfilesize; /* maximum representable file size */ + int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */ + int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */ + int32_t fs_state; /* validate fs_clean field */ + int32_t fs_old_postblformat; /* format of positional layout tables */ + int32_t fs_old_nrpos; /* number of rotational positions */ + int32_t fs_spare5[2]; /* old fs_postbloff */ + /* old fs_rotbloff */ + int32_t fs_magic; /* magic number */ +}; + +/* Sanity checking. */ +#ifdef CTASSERT +CTASSERT(sizeof(struct fs) == 1376); +#endif + +/* + * Filesystem identification + */ +#define FS_UFS1_MAGIC 0x011954 /* UFS1 fast filesystem magic number */ +#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast filesystem magic number */ +#define FS_BAD_MAGIC 0x19960408 /* UFS incomplete newfs magic number */ +#define FS_OKAY 0x7c269d38 /* superblock checksum */ +#define FS_42INODEFMT -1 /* 4.2BSD inode format */ +#define FS_44INODEFMT 2 /* 4.4BSD inode format */ + +/* + * Preference for optimization. + */ +#define FS_OPTTIME 0 /* minimize allocation time */ +#define FS_OPTSPACE 1 /* minimize disk fragmentation */ + +/* + * Filesystem flags. + * + * The FS_UNCLEAN flag is set by the kernel when the filesystem was + * mounted with fs_clean set to zero. The FS_DOSOFTDEP flag indicates + * that the filesystem should be managed by the soft updates code. + * Note that the FS_NEEDSFSCK flag is set and cleared only by the + * fsck utility. It is set when background fsck finds an unexpected + * inconsistency which requires a traditional foreground fsck to be + * run. Such inconsistencies should only be found after an uncorrectable + * disk error. A foreground fsck will clear the FS_NEEDSFSCK flag when + * it has successfully cleaned up the filesystem. The kernel uses this + * flag to enforce that inconsistent filesystems be mounted read-only. + * The FS_INDEXDIRS flag when set indicates that the kernel maintains + * on-disk auxiliary indexes (such as B-trees) for speeding directory + * accesses. Kernels that do not support auxiliary indices clear the + * flag to indicate that the indices need to be rebuilt (by fsck) before + * they can be used. + * + * FS_ACLS indicates that POSIX.1e ACLs are administratively enabled + * for the file system, so they should be loaded from extended attributes, + * observed for access control purposes, and be administered by object + * owners. FS_NFS4ACLS indicates that NFSv4 ACLs are administratively + * enabled. This flag is mutually exclusive with FS_ACLS. FS_MULTILABEL + * indicates that the TrustedBSD MAC Framework should attempt to back MAC + * labels into extended attributes on the file system rather than maintain + * a single mount label for all objects. + */ +#define FS_UNCLEAN 0x0001 /* filesystem not clean at mount */ +#define FS_DOSOFTDEP 0x0002 /* filesystem using soft dependencies */ +#define FS_NEEDSFSCK 0x0004 /* filesystem needs sync fsck before mount */ +#define FS_SUJ 0x0008 /* Filesystem using softupdate journal */ +#define FS_ACLS 0x0010 /* file system has POSIX.1e ACLs enabled */ +#define FS_MULTILABEL 0x0020 /* file system is MAC multi-label */ +#define FS_GJOURNAL 0x0040 /* gjournaled file system */ +#define FS_FLAGS_UPDATED 0x0080 /* flags have been moved to new location */ +#define FS_NFS4ACLS 0x0100 /* file system has NFSv4 ACLs enabled */ +#define FS_INDEXDIRS 0x0200 /* kernel supports indexed directories */ +#define FS_TRIM 0x0400 /* issue BIO_DELETE for deleted blocks */ + +/* + * Macros to access bits in the fs_active array. + */ +#define ACTIVECGNUM(fs, cg) ((fs)->fs_active[(cg) / (NBBY * sizeof(int))]) +#define ACTIVECGOFF(cg) (1 << ((cg) % (NBBY * sizeof(int)))) +#define ACTIVESET(fs, cg) do { \ + if ((fs)->fs_active) \ + ACTIVECGNUM((fs), (cg)) |= ACTIVECGOFF((cg)); \ +} while (0) +#define ACTIVECLEAR(fs, cg) do { \ + if ((fs)->fs_active) \ + ACTIVECGNUM((fs), (cg)) &= ~ACTIVECGOFF((cg)); \ +} while (0) + +/* + * The size of a cylinder group is calculated by CGSIZE. The maximum size + * is limited by the fact that cylinder groups are at most one block. + * Its size is derived from the size of the maps maintained in the + * cylinder group and the (struct cg) size. + */ +#define CGSIZE(fs) \ + /* base cg */ (sizeof(struct cg) + sizeof(int32_t) + \ + /* old btotoff */ (fs)->fs_old_cpg * sizeof(int32_t) + \ + /* old boff */ (fs)->fs_old_cpg * sizeof(u_int16_t) + \ + /* inode map */ howmany((fs)->fs_ipg, NBBY) + \ + /* block map */ howmany((fs)->fs_fpg, NBBY) +\ + /* if present */ ((fs)->fs_contigsumsize <= 0 ? 0 : \ + /* cluster sum */ (fs)->fs_contigsumsize * sizeof(int32_t) + \ + /* cluster map */ howmany(fragstoblks(fs, (fs)->fs_fpg), NBBY))) + +/* + * The minimal number of cylinder groups that should be created. + */ +#define MINCYLGRPS 4 + +/* + * Convert cylinder group to base address of its global summary info. + */ +#define fs_cs(fs, indx) fs_csp[indx] + +/* + * Cylinder group block for a filesystem. + */ +#define CG_MAGIC 0x090255 +struct cg { + int32_t cg_firstfield; /* historic cyl groups linked list */ + int32_t cg_magic; /* magic number */ + int32_t cg_old_time; /* time last written */ + u_int32_t cg_cgx; /* we are the cgx'th cylinder group */ + int16_t cg_old_ncyl; /* number of cyl's this cg */ + int16_t cg_old_niblk; /* number of inode blocks this cg */ + u_int32_t cg_ndblk; /* number of data blocks this cg */ + struct csum cg_cs; /* cylinder summary information */ + u_int32_t cg_rotor; /* position of last used block */ + u_int32_t cg_frotor; /* position of last used frag */ + u_int32_t cg_irotor; /* position of last used inode */ + u_int32_t cg_frsum[MAXFRAG]; /* counts of available frags */ + int32_t cg_old_btotoff; /* (int32) block totals per cylinder */ + int32_t cg_old_boff; /* (u_int16) free block positions */ + u_int32_t cg_iusedoff; /* (u_int8) used inode map */ + u_int32_t cg_freeoff; /* (u_int8) free block map */ + u_int32_t cg_nextfreeoff; /* (u_int8) next available space */ + u_int32_t cg_clustersumoff; /* (u_int32) counts of avail clusters */ + u_int32_t cg_clusteroff; /* (u_int8) free cluster map */ + u_int32_t cg_nclusterblks; /* number of clusters this cg */ + u_int32_t cg_niblk; /* number of inode blocks this cg */ + u_int32_t cg_initediblk; /* last initialized inode */ + u_int32_t cg_unrefs; /* number of unreferenced inodes */ + int32_t cg_sparecon32[2]; /* reserved for future use */ + ufs_time_t cg_time; /* time last written */ + int64_t cg_sparecon64[3]; /* reserved for future use */ + u_int8_t cg_space[1]; /* space for cylinder group maps */ +/* actually longer */ +}; + +/* + * Macros for access to cylinder group array structures + */ +#define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC) +#define cg_inosused(cgp) \ + ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_iusedoff)) +#define cg_blksfree(cgp) \ + ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_freeoff)) +#define cg_clustersfree(cgp) \ + ((u_int8_t *)((u_int8_t *)(cgp) + (cgp)->cg_clusteroff)) +#define cg_clustersum(cgp) \ + ((int32_t *)((uintptr_t)(cgp) + (cgp)->cg_clustersumoff)) + +/* + * Turn filesystem block numbers into disk block addresses. + * This maps filesystem blocks to device size blocks. + */ +#define fsbtodb(fs, b) ((daddr_t)(b) << (fs)->fs_fsbtodb) +#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb) + +/* + * Cylinder group macros to locate things in cylinder groups. + * They calc filesystem addresses of cylinder group data structures. + */ +#define cgbase(fs, c) (((ufs2_daddr_t)(fs)->fs_fpg) * (c)) +#define cgdata(fs, c) (cgdmin(fs, c) + (fs)->fs_metaspace) /* data zone */ +#define cgmeta(fs, c) (cgdmin(fs, c)) /* meta data */ +#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ +#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ +#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ +#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */ +#define cgstart(fs, c) \ + ((fs)->fs_magic == FS_UFS2_MAGIC ? cgbase(fs, c) : \ + (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask)))) + +/* + * Macros for handling inode numbers: + * inode number to filesystem block offset. + * inode number to cylinder group number. + * inode number to filesystem block address. + */ +#define ino_to_cg(fs, x) (((ino_t)(x)) / (fs)->fs_ipg) +#define ino_to_fsba(fs, x) \ + ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, (ino_t)(x))) + \ + (blkstofrags((fs), ((((ino_t)(x)) % (fs)->fs_ipg) / INOPB(fs)))))) +#define ino_to_fsbo(fs, x) (((ino_t)(x)) % INOPB(fs)) + +/* + * Give cylinder group number for a filesystem block. + * Give cylinder group block number for a filesystem block. + */ +#define dtog(fs, d) ((d) / (fs)->fs_fpg) +#define dtogd(fs, d) ((d) % (fs)->fs_fpg) + +/* + * Extract the bits for a block from a map. + * Compute the cylinder and rotational position of a cyl block addr. + */ +#define blkmap(fs, map, loc) \ + (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \ + ((loc) & (fs)->fs_qbmask) +#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \ + ((loc) & (fs)->fs_qfmask) +#define lfragtosize(fs, frag) /* calculates ((off_t)frag * fs->fs_fsize) */ \ + (((off_t)(frag)) << (fs)->fs_fshift) +#define lblktosize(fs, blk) /* calculates ((off_t)blk * fs->fs_bsize) */ \ + (((off_t)(blk)) << (fs)->fs_bshift) +/* Use this only when `blk' is known to be small, e.g., < NDADDR. */ +#define smalllblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \ + ((blk) << (fs)->fs_bshift) +#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \ + ((loc) >> (fs)->fs_bshift) +#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \ + ((loc) >> (fs)->fs_fshift) +#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \ + (((size) + (fs)->fs_qbmask) & (fs)->fs_bmask) +#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \ + (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask) +#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \ + ((frags) >> (fs)->fs_fragshift) +#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \ + ((blks) << (fs)->fs_fragshift) +#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \ + ((fsb) & ((fs)->fs_frag - 1)) +#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \ + ((fsb) &~ ((fs)->fs_frag - 1)) + +/* + * Determine the number of available frags given a + * percentage to hold in reserve. + */ +#define freespace(fs, percentreserved) \ + (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ + (fs)->fs_cstotal.cs_nffree - \ + (((off_t)((fs)->fs_dsize)) * (percentreserved) / 100)) + +/* + * Determining the size of a file block in the filesystem. + */ +#define blksize(fs, ip, lbn) \ + (((lbn) >= NDADDR || (ip)->i_size >= smalllblktosize(fs, (lbn) + 1)) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) +#define sblksize(fs, size, lbn) \ + (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (size))))) + +/* + * Number of indirects in a filesystem block. + */ +#define NINDIR(fs) ((fs)->fs_nindir) + +/* + * Indirect lbns are aligned on NDADDR addresses where single indirects + * are the negated address of the lowest lbn reachable, double indirects + * are this lbn - 1 and triple indirects are this lbn - 2. This yields + * an unusual bit order to determine level. + */ +static inline int +lbn_level(ufs_lbn_t lbn) +{ + if (lbn >= 0) + return 0; + switch (lbn & 0x3) { + case 0: + return (0); + case 1: + break; + case 2: + return (2); + case 3: + return (1); + default: + break; + } + return (-1); +} + +static inline ufs_lbn_t +lbn_offset(struct fs *fs, int level) +{ + ufs_lbn_t res; + + for (res = 1; level > 0; level--) + res *= NINDIR(fs); + return (res); +} + +/* + * Number of inodes in a secondary storage block/fragment. + */ +#define INOPB(fs) ((fs)->fs_inopb) +#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) + +/* + * Softdep journal record format. + */ + +#define JOP_ADDREF 1 /* Add a reference to an inode. */ +#define JOP_REMREF 2 /* Remove a reference from an inode. */ +#define JOP_NEWBLK 3 /* Allocate a block. */ +#define JOP_FREEBLK 4 /* Free a block or a tree of blocks. */ +#define JOP_MVREF 5 /* Move a reference from one off to another. */ +#define JOP_TRUNC 6 /* Partial truncation record. */ +#define JOP_SYNC 7 /* fsync() complete record. */ + +#define JREC_SIZE 32 /* Record and segment header size. */ + +#define SUJ_MIN (4 * 1024 * 1024) /* Minimum journal size */ +#define SUJ_MAX (32 * 1024 * 1024) /* Maximum journal size */ +#define SUJ_FILE ".sujournal" /* Journal file name */ + +/* + * Size of the segment record header. There is at most one for each disk + * block in the journal. The segment header is followed by an array of + * records. fsck depends on the first element in each record being 'op' + * and the second being 'ino'. Segments may span multiple disk blocks but + * the header is present on each. + */ +struct jsegrec { + uint64_t jsr_seq; /* Our sequence number */ + uint64_t jsr_oldest; /* Oldest valid sequence number */ + uint16_t jsr_cnt; /* Count of valid records */ + uint16_t jsr_blocks; /* Count of device bsize blocks. */ + uint32_t jsr_crc; /* 32bit crc of the valid space */ + ufs_time_t jsr_time; /* timestamp for mount instance */ +}; + +/* + * Reference record. Records a single link count modification. + */ +struct jrefrec { + uint32_t jr_op; + uint32_t jr_ino; + uint32_t jr_parent; + uint16_t jr_nlink; + uint16_t jr_mode; + int64_t jr_diroff; + uint64_t jr_unused; +}; + +/* + * Move record. Records a reference moving within a directory block. The + * nlink is unchanged but we must search both locations. + */ +struct jmvrec { + uint32_t jm_op; + uint32_t jm_ino; + uint32_t jm_parent; + uint16_t jm_unused; + int64_t jm_oldoff; + int64_t jm_newoff; +}; + +/* + * Block record. A set of frags or tree of blocks starting at an indirect are + * freed or a set of frags are allocated. + */ +struct jblkrec { + uint32_t jb_op; + uint32_t jb_ino; + ufs2_daddr_t jb_blkno; + ufs_lbn_t jb_lbn; + uint16_t jb_frags; + uint16_t jb_oldfrags; + uint32_t jb_unused; +}; + +/* + * Truncation record. Records a partial truncation so that it may be + * completed at check time. Also used for sync records. + */ +struct jtrncrec { + uint32_t jt_op; + uint32_t jt_ino; + int64_t jt_size; + uint32_t jt_extsize; + uint32_t jt_pad[3]; +}; + +union jrec { + struct jsegrec rec_jsegrec; + struct jrefrec rec_jrefrec; + struct jmvrec rec_jmvrec; + struct jblkrec rec_jblkrec; + struct jtrncrec rec_jtrncrec; +}; + +#ifdef CTASSERT +CTASSERT(sizeof(struct jsegrec) == JREC_SIZE); +CTASSERT(sizeof(struct jrefrec) == JREC_SIZE); +CTASSERT(sizeof(struct jmvrec) == JREC_SIZE); +CTASSERT(sizeof(struct jblkrec) == JREC_SIZE); +CTASSERT(sizeof(struct jtrncrec) == JREC_SIZE); +CTASSERT(sizeof(union jrec) == JREC_SIZE); +#endif + +extern int inside[], around[]; +extern u_char *fragtbl[]; + +/* + * IOCTLs used for filesystem write suspension. + */ +#define UFSSUSPEND _IOW('U', 1, fsid_t) +#define UFSRESUME _IO('U', 2) + +#endif diff --git a/Dump/ufs/ffs/softdep.h b/Dump/ufs/ffs/softdep.h new file mode 100644 index 0000000..8f5222e --- /dev/null +++ b/Dump/ufs/ffs/softdep.h @@ -0,0 +1,1100 @@ +/*- + * Copyright 1998, 2000 Marshall Kirk McKusick. All Rights Reserved. + * + * The soft updates code is derived from the appendix of a University + * of Michigan technical report (Gregory R. Ganger and Yale N. Patt, + * "Soft Updates: A Solution to the Metadata Update Problem in File + * Systems", CSE-TR-254-95, August 1995). + * + * Further information about soft updates can be obtained from: + * + * Marshall Kirk McKusick http://www.mckusick.com/softdep/ + * 1614 Oxford Street mckusick@mckusick.com + * Berkeley, CA 94709-1608 +1-510-843-9542 + * USA + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY MARSHALL KIRK MCKUSICK ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL MARSHALL KIRK MCKUSICK BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)softdep.h 9.7 (McKusick) 6/21/00 + * $FreeBSD: releng/11.2/sys/ufs/ffs/softdep.h 320057 2017-06-17 17:10:50Z kib $ + */ + +#include + +/* + * Allocation dependencies are handled with undo/redo on the in-memory + * copy of the data. A particular data dependency is eliminated when + * it is ALLCOMPLETE: that is ATTACHED, DEPCOMPLETE, and COMPLETE. + * + * The ATTACHED flag means that the data is not currently being written + * to disk. + * + * The UNDONE flag means that the data has been rolled back to a safe + * state for writing to the disk. When the I/O completes, the data is + * restored to its current form and the state reverts to ATTACHED. + * The data must be locked throughout the rollback, I/O, and roll + * forward so that the rolled back information is never visible to + * user processes. + * + * The COMPLETE flag indicates that the item has been written. For example, + * a dependency that requires that an inode be written will be marked + * COMPLETE after the inode has been written to disk. + * + * The DEPCOMPLETE flag indicates the completion of any other + * dependencies such as the writing of a cylinder group map has been + * completed. A dependency structure may be freed only when both it + * and its dependencies have completed and any rollbacks that are in + * progress have finished as indicated by the set of ALLCOMPLETE flags + * all being set. + * + * The two MKDIR flags indicate additional dependencies that must be done + * when creating a new directory. MKDIR_BODY is cleared when the directory + * data block containing the "." and ".." entries has been written. + * MKDIR_PARENT is cleared when the parent inode with the increased link + * count for ".." has been written. When both MKDIR flags have been + * cleared, the DEPCOMPLETE flag is set to indicate that the directory + * dependencies have been completed. The writing of the directory inode + * itself sets the COMPLETE flag which then allows the directory entry for + * the new directory to be written to disk. The RMDIR flag marks a dirrem + * structure as representing the removal of a directory rather than a + * file. When the removal dependencies are completed, additional work needs + * to be done* (an additional decrement of the associated inode, and a + * decrement of the parent inode). + * + * The DIRCHG flag marks a diradd structure as representing the changing + * of an existing entry rather than the addition of a new one. When + * the update is complete the dirrem associated with the inode for + * the old name must be added to the worklist to do the necessary + * reference count decrement. + * + * The GOINGAWAY flag indicates that the data structure is frozen from + * further change until its dependencies have been completed and its + * resources freed after which it will be discarded. + * + * The IOSTARTED flag prevents multiple calls to the I/O start routine from + * doing multiple rollbacks. + * + * The NEWBLOCK flag marks pagedep structures that have just been allocated, + * so must be claimed by the inode before all dependencies are complete. + * + * The INPROGRESS flag marks worklist structures that are still on the + * worklist, but are being considered for action by some process. + * + * The UFS1FMT flag indicates that the inode being processed is a ufs1 format. + * + * The EXTDATA flag indicates that the allocdirect describes an + * extended-attributes dependency. + * + * The ONWORKLIST flag shows whether the structure is currently linked + * onto a worklist. + * + * The UNLINK* flags track the progress of updating the on-disk linked + * list of active but unlinked inodes. When an inode is first unlinked + * it is marked as UNLINKED. When its on-disk di_freelink has been + * written its UNLINKNEXT flags is set. When its predecessor in the + * list has its di_freelink pointing at us its UNLINKPREV is set. + * When the on-disk list can reach it from the superblock, its + * UNLINKONLIST flag is set. Once all of these flags are set, it + * is safe to let its last name be removed. + */ +#define ATTACHED 0x000001 +#define UNDONE 0x000002 +#define COMPLETE 0x000004 +#define DEPCOMPLETE 0x000008 +#define MKDIR_PARENT 0x000010 /* diradd, mkdir, jaddref, jsegdep only */ +#define MKDIR_BODY 0x000020 /* diradd, mkdir, jaddref only */ +#define RMDIR 0x000040 /* dirrem only */ +#define DIRCHG 0x000080 /* diradd, dirrem only */ +#define GOINGAWAY 0x000100 /* indirdep, jremref only */ +#define IOSTARTED 0x000200 /* inodedep, pagedep, bmsafemap only */ +#define DELAYEDFREE 0x000400 /* allocindirect free delayed. */ +#define NEWBLOCK 0x000800 /* pagedep, jaddref only */ +#define INPROGRESS 0x001000 /* dirrem, freeblks, freefrag, freefile only */ +#define UFS1FMT 0x002000 /* indirdep only */ +#define EXTDATA 0x004000 /* allocdirect only */ +#define ONWORKLIST 0x008000 +#define IOWAITING 0x010000 /* Thread is waiting for IO to complete. */ +#define ONDEPLIST 0x020000 /* Structure is on a dependency list. */ +#define UNLINKED 0x040000 /* inodedep has been unlinked. */ +#define UNLINKNEXT 0x080000 /* inodedep has valid di_freelink */ +#define UNLINKPREV 0x100000 /* inodedep is pointed at in the unlink list */ +#define UNLINKONLIST 0x200000 /* inodedep is in the unlinked list on disk */ +#define UNLINKLINKS (UNLINKNEXT | UNLINKPREV) +#define WRITESUCCEEDED 0x400000 /* the disk write completed successfully */ + +#define ALLCOMPLETE (ATTACHED | COMPLETE | DEPCOMPLETE) + +/* + * Values for each of the soft dependency types. + */ +#define D_PAGEDEP 0 +#define D_INODEDEP 1 +#define D_BMSAFEMAP 2 +#define D_NEWBLK 3 +#define D_ALLOCDIRECT 4 +#define D_INDIRDEP 5 +#define D_ALLOCINDIR 6 +#define D_FREEFRAG 7 +#define D_FREEBLKS 8 +#define D_FREEFILE 9 +#define D_DIRADD 10 +#define D_MKDIR 11 +#define D_DIRREM 12 +#define D_NEWDIRBLK 13 +#define D_FREEWORK 14 +#define D_FREEDEP 15 +#define D_JADDREF 16 +#define D_JREMREF 17 +#define D_JMVREF 18 +#define D_JNEWBLK 19 +#define D_JFREEBLK 20 +#define D_JFREEFRAG 21 +#define D_JSEG 22 +#define D_JSEGDEP 23 +#define D_SBDEP 24 +#define D_JTRUNC 25 +#define D_JFSYNC 26 +#define D_SENTINEL 27 +#define D_LAST D_SENTINEL + +/* + * The workitem queue. + * + * It is sometimes useful and/or necessary to clean up certain dependencies + * in the background rather than during execution of an application process + * or interrupt service routine. To realize this, we append dependency + * structures corresponding to such tasks to a "workitem" queue. In a soft + * updates implementation, most pending workitems should not wait for more + * than a couple of seconds, so the filesystem syncer process awakens once + * per second to process the items on the queue. + */ + +/* LIST_HEAD(workhead, worklist); -- declared in buf.h */ + +/* + * Each request can be linked onto a work queue through its worklist structure. + * To avoid the need for a pointer to the structure itself, this structure + * MUST be declared FIRST in each type in which it appears! If more than one + * worklist is needed in the structure, then a wk_data field must be added + * and the macros below changed to use it. + */ +struct worklist { + LIST_ENTRY(worklist) wk_list; /* list of work requests */ + struct mount *wk_mp; /* Mount we live in */ + unsigned int wk_type:8, /* type of request */ + wk_state:24; /* state flags */ +}; +#define WK_DATA(wk) ((void *)(wk)) +#define WK_PAGEDEP(wk) ((struct pagedep *)(wk)) +#define WK_INODEDEP(wk) ((struct inodedep *)(wk)) +#define WK_BMSAFEMAP(wk) ((struct bmsafemap *)(wk)) +#define WK_NEWBLK(wk) ((struct newblk *)(wk)) +#define WK_ALLOCDIRECT(wk) ((struct allocdirect *)(wk)) +#define WK_INDIRDEP(wk) ((struct indirdep *)(wk)) +#define WK_ALLOCINDIR(wk) ((struct allocindir *)(wk)) +#define WK_FREEFRAG(wk) ((struct freefrag *)(wk)) +#define WK_FREEBLKS(wk) ((struct freeblks *)(wk)) +#define WK_FREEWORK(wk) ((struct freework *)(wk)) +#define WK_FREEFILE(wk) ((struct freefile *)(wk)) +#define WK_DIRADD(wk) ((struct diradd *)(wk)) +#define WK_MKDIR(wk) ((struct mkdir *)(wk)) +#define WK_DIRREM(wk) ((struct dirrem *)(wk)) +#define WK_NEWDIRBLK(wk) ((struct newdirblk *)(wk)) +#define WK_JADDREF(wk) ((struct jaddref *)(wk)) +#define WK_JREMREF(wk) ((struct jremref *)(wk)) +#define WK_JMVREF(wk) ((struct jmvref *)(wk)) +#define WK_JSEGDEP(wk) ((struct jsegdep *)(wk)) +#define WK_JSEG(wk) ((struct jseg *)(wk)) +#define WK_JNEWBLK(wk) ((struct jnewblk *)(wk)) +#define WK_JFREEBLK(wk) ((struct jfreeblk *)(wk)) +#define WK_FREEDEP(wk) ((struct freedep *)(wk)) +#define WK_JFREEFRAG(wk) ((struct jfreefrag *)(wk)) +#define WK_SBDEP(wk) ((struct sbdep *)(wk)) +#define WK_JTRUNC(wk) ((struct jtrunc *)(wk)) +#define WK_JFSYNC(wk) ((struct jfsync *)(wk)) + +/* + * Various types of lists + */ +LIST_HEAD(dirremhd, dirrem); +LIST_HEAD(diraddhd, diradd); +LIST_HEAD(newblkhd, newblk); +LIST_HEAD(inodedephd, inodedep); +LIST_HEAD(allocindirhd, allocindir); +LIST_HEAD(allocdirecthd, allocdirect); +TAILQ_HEAD(allocdirectlst, allocdirect); +LIST_HEAD(indirdephd, indirdep); +LIST_HEAD(jaddrefhd, jaddref); +LIST_HEAD(jremrefhd, jremref); +LIST_HEAD(jmvrefhd, jmvref); +LIST_HEAD(jnewblkhd, jnewblk); +LIST_HEAD(jblkdephd, jblkdep); +LIST_HEAD(freeworkhd, freework); +TAILQ_HEAD(freeworklst, freework); +TAILQ_HEAD(jseglst, jseg); +TAILQ_HEAD(inoreflst, inoref); +TAILQ_HEAD(freeblklst, freeblks); + +/* + * The "pagedep" structure tracks the various dependencies related to + * a particular directory page. If a directory page has any dependencies, + * it will have a pagedep linked to its associated buffer. The + * pd_dirremhd list holds the list of dirrem requests which decrement + * inode reference counts. These requests are processed after the + * directory page with the corresponding zero'ed entries has been + * written. The pd_diraddhd list maintains the list of diradd requests + * which cannot be committed until their corresponding inode has been + * written to disk. Because a directory may have many new entries + * being created, several lists are maintained hashed on bits of the + * offset of the entry into the directory page to keep the lists from + * getting too long. Once a new directory entry has been cleared to + * be written, it is moved to the pd_pendinghd list. After the new + * entry has been written to disk it is removed from the pd_pendinghd + * list, any removed operations are done, and the dependency structure + * is freed. + */ +#define DAHASHSZ 5 +#define DIRADDHASH(offset) (((offset) >> 2) % DAHASHSZ) +struct pagedep { + struct worklist pd_list; /* page buffer */ +# define pd_state pd_list.wk_state /* check for multiple I/O starts */ + LIST_ENTRY(pagedep) pd_hash; /* hashed lookup */ + ino_t pd_ino; /* associated file */ + ufs_lbn_t pd_lbn; /* block within file */ + struct newdirblk *pd_newdirblk; /* associated newdirblk if NEWBLOCK */ + struct dirremhd pd_dirremhd; /* dirrem's waiting for page */ + struct diraddhd pd_diraddhd[DAHASHSZ]; /* diradd dir entry updates */ + struct diraddhd pd_pendinghd; /* directory entries awaiting write */ + struct jmvrefhd pd_jmvrefhd; /* Dependent journal writes. */ +}; + +/* + * The "inodedep" structure tracks the set of dependencies associated + * with an inode. One task that it must manage is delayed operations + * (i.e., work requests that must be held until the inodedep's associated + * inode has been written to disk). Getting an inode from its incore + * state to the disk requires two steps to be taken by the filesystem + * in this order: first the inode must be copied to its disk buffer by + * the VOP_UPDATE operation; second the inode's buffer must be written + * to disk. To ensure that both operations have happened in the required + * order, the inodedep maintains two lists. Delayed operations are + * placed on the id_inowait list. When the VOP_UPDATE is done, all + * operations on the id_inowait list are moved to the id_bufwait list. + * When the buffer is written, the items on the id_bufwait list can be + * safely moved to the work queue to be processed. A second task of the + * inodedep structure is to track the status of block allocation within + * the inode. Each block that is allocated is represented by an + * "allocdirect" structure (see below). It is linked onto the id_newinoupdt + * list until both its contents and its allocation in the cylinder + * group map have been written to disk. Once these dependencies have been + * satisfied, it is removed from the id_newinoupdt list and any followup + * actions such as releasing the previous block or fragment are placed + * on the id_inowait list. When an inode is updated (a VOP_UPDATE is + * done), the "inodedep" structure is linked onto the buffer through + * its worklist. Thus, it will be notified when the buffer is about + * to be written and when it is done. At the update time, all the + * elements on the id_newinoupdt list are moved to the id_inoupdt list + * since those changes are now relevant to the copy of the inode in the + * buffer. Also at update time, the tasks on the id_inowait list are + * moved to the id_bufwait list so that they will be executed when + * the updated inode has been written to disk. When the buffer containing + * the inode is written to disk, any updates listed on the id_inoupdt + * list are rolled back as they are not yet safe. Following the write, + * the changes are once again rolled forward and any actions on the + * id_bufwait list are processed (since those actions are now safe). + * The entries on the id_inoupdt and id_newinoupdt lists must be kept + * sorted by logical block number to speed the calculation of the size + * of the rolled back inode (see explanation in initiate_write_inodeblock). + * When a directory entry is created, it is represented by a diradd. + * The diradd is added to the id_inowait list as it cannot be safely + * written to disk until the inode that it represents is on disk. After + * the inode is written, the id_bufwait list is processed and the diradd + * entries are moved to the id_pendinghd list where they remain until + * the directory block containing the name has been written to disk. + * The purpose of keeping the entries on the id_pendinghd list is so that + * the softdep_fsync function can find and push the inode's directory + * name(s) as part of the fsync operation for that file. + */ +struct inodedep { + struct worklist id_list; /* buffer holding inode block */ +# define id_state id_list.wk_state /* inode dependency state */ + LIST_ENTRY(inodedep) id_hash; /* hashed lookup */ + TAILQ_ENTRY(inodedep) id_unlinked; /* Unlinked but ref'd inodes */ + struct fs *id_fs; /* associated filesystem */ + ino_t id_ino; /* dependent inode */ + nlink_t id_nlinkdelta; /* saved effective link count */ + nlink_t id_savednlink; /* Link saved during rollback */ + LIST_ENTRY(inodedep) id_deps; /* bmsafemap's list of inodedep's */ + struct bmsafemap *id_bmsafemap; /* related bmsafemap (if pending) */ + struct diradd *id_mkdiradd; /* diradd for a mkdir. */ + struct inoreflst id_inoreflst; /* Inode reference adjustments. */ + long id_savedextsize; /* ext size saved during rollback */ + off_t id_savedsize; /* file size saved during rollback */ + struct dirremhd id_dirremhd; /* Removals pending. */ + struct workhead id_pendinghd; /* entries awaiting directory write */ + struct workhead id_bufwait; /* operations after inode written */ + struct workhead id_inowait; /* operations waiting inode update */ + struct allocdirectlst id_inoupdt; /* updates before inode written */ + struct allocdirectlst id_newinoupdt; /* updates when inode written */ + struct allocdirectlst id_extupdt; /* extdata updates pre-inode write */ + struct allocdirectlst id_newextupdt; /* extdata updates at ino write */ + struct freeblklst id_freeblklst; /* List of partial truncates. */ + union { + struct ufs1_dinode *idu_savedino1; /* saved ufs1_dinode contents */ + struct ufs2_dinode *idu_savedino2; /* saved ufs2_dinode contents */ + } id_un; +}; +#define id_savedino1 id_un.idu_savedino1 +#define id_savedino2 id_un.idu_savedino2 + +/* + * A "bmsafemap" structure maintains a list of dependency structures + * that depend on the update of a particular cylinder group map. + * It has lists for newblks, allocdirects, allocindirs, and inodedeps. + * It is attached to the buffer of a cylinder group block when any of + * these things are allocated from the cylinder group. It is freed + * after the cylinder group map is written and the state of its + * dependencies are updated with DEPCOMPLETE to indicate that it has + * been processed. + */ +struct bmsafemap { + struct worklist sm_list; /* cylgrp buffer */ +# define sm_state sm_list.wk_state + LIST_ENTRY(bmsafemap) sm_hash; /* Hash links. */ + LIST_ENTRY(bmsafemap) sm_next; /* Mount list. */ + int sm_cg; + struct buf *sm_buf; /* associated buffer */ + struct allocdirecthd sm_allocdirecthd; /* allocdirect deps */ + struct allocdirecthd sm_allocdirectwr; /* writing allocdirect deps */ + struct allocindirhd sm_allocindirhd; /* allocindir deps */ + struct allocindirhd sm_allocindirwr; /* writing allocindir deps */ + struct inodedephd sm_inodedephd; /* inodedep deps */ + struct inodedephd sm_inodedepwr; /* writing inodedep deps */ + struct newblkhd sm_newblkhd; /* newblk deps */ + struct newblkhd sm_newblkwr; /* writing newblk deps */ + struct jaddrefhd sm_jaddrefhd; /* Pending inode allocations. */ + struct jnewblkhd sm_jnewblkhd; /* Pending block allocations. */ + struct workhead sm_freehd; /* Freedep deps. */ + struct workhead sm_freewr; /* Written freedeps. */ +}; + +/* + * A "newblk" structure is attached to a bmsafemap structure when a block + * or fragment is allocated from a cylinder group. Its state is set to + * DEPCOMPLETE when its cylinder group map is written. It is converted to + * an allocdirect or allocindir allocation once the allocator calls the + * appropriate setup function. It will initially be linked onto a bmsafemap + * list. Once converted it can be linked onto the lists described for + * allocdirect or allocindir as described below. + */ +struct newblk { + struct worklist nb_list; /* See comment above. */ +# define nb_state nb_list.wk_state + LIST_ENTRY(newblk) nb_hash; /* Hashed lookup. */ + LIST_ENTRY(newblk) nb_deps; /* Bmsafemap's list of newblks. */ + struct jnewblk *nb_jnewblk; /* New block journal entry. */ + struct bmsafemap *nb_bmsafemap;/* Cylgrp dep (if pending). */ + struct freefrag *nb_freefrag; /* Fragment to be freed (if any). */ + struct indirdephd nb_indirdeps; /* Children indirect blocks. */ + struct workhead nb_newdirblk; /* Dir block to notify when written. */ + struct workhead nb_jwork; /* Journal work pending. */ + ufs2_daddr_t nb_newblkno; /* New value of block pointer. */ +}; + +/* + * An "allocdirect" structure is attached to an "inodedep" when a new block + * or fragment is allocated and pointed to by the inode described by + * "inodedep". The worklist is linked to the buffer that holds the block. + * When the block is first allocated, it is linked to the bmsafemap + * structure associated with the buffer holding the cylinder group map + * from which it was allocated. When the cylinder group map is written + * to disk, ad_state has the DEPCOMPLETE flag set. When the block itself + * is written, the COMPLETE flag is set. Once both the cylinder group map + * and the data itself have been written, it is safe to write the inode + * that claims the block. If there was a previous fragment that had been + * allocated before the file was increased in size, the old fragment may + * be freed once the inode claiming the new block is written to disk. + * This ad_fragfree request is attached to the id_inowait list of the + * associated inodedep (pointed to by ad_inodedep) for processing after + * the inode is written. When a block is allocated to a directory, an + * fsync of a file whose name is within that block must ensure not only + * that the block containing the file name has been written, but also + * that the on-disk inode references that block. When a new directory + * block is created, we allocate a newdirblk structure which is linked + * to the associated allocdirect (on its ad_newdirblk list). When the + * allocdirect has been satisfied, the newdirblk structure is moved to + * the inodedep id_bufwait list of its directory to await the inode + * being written. When the inode is written, the directory entries are + * fully committed and can be deleted from their pagedep->id_pendinghd + * and inodedep->id_pendinghd lists. + */ +struct allocdirect { + struct newblk ad_block; /* Common block logic */ +# define ad_list ad_block.nb_list /* block pointer worklist */ +# define ad_state ad_list.wk_state /* block pointer state */ + TAILQ_ENTRY(allocdirect) ad_next; /* inodedep's list of allocdirect's */ + struct inodedep *ad_inodedep; /* associated inodedep */ + ufs2_daddr_t ad_oldblkno; /* old value of block pointer */ + int ad_offset; /* Pointer offset in parent. */ + long ad_newsize; /* size of new block */ + long ad_oldsize; /* size of old block */ +}; +#define ad_newblkno ad_block.nb_newblkno +#define ad_freefrag ad_block.nb_freefrag +#define ad_newdirblk ad_block.nb_newdirblk + +/* + * A single "indirdep" structure manages all allocation dependencies for + * pointers in an indirect block. The up-to-date state of the indirect + * block is stored in ir_savedata. The set of pointers that may be safely + * written to the disk is stored in ir_safecopy. The state field is used + * only to track whether the buffer is currently being written (in which + * case it is not safe to update ir_safecopy). Ir_deplisthd contains the + * list of allocindir structures, one for each block that needs to be + * written to disk. Once the block and its bitmap allocation have been + * written the safecopy can be updated to reflect the allocation and the + * allocindir structure freed. If ir_state indicates that an I/O on the + * indirect block is in progress when ir_safecopy is to be updated, the + * update is deferred by placing the allocindir on the ir_donehd list. + * When the I/O on the indirect block completes, the entries on the + * ir_donehd list are processed by updating their corresponding ir_safecopy + * pointers and then freeing the allocindir structure. + */ +struct indirdep { + struct worklist ir_list; /* buffer holding indirect block */ +# define ir_state ir_list.wk_state /* indirect block pointer state */ + LIST_ENTRY(indirdep) ir_next; /* alloc{direct,indir} list */ + TAILQ_HEAD(, freework) ir_trunc; /* List of truncations. */ + caddr_t ir_saveddata; /* buffer cache contents */ + struct buf *ir_savebp; /* buffer holding safe copy */ + struct buf *ir_bp; /* buffer holding live copy */ + struct allocindirhd ir_completehd; /* waiting for indirdep complete */ + struct allocindirhd ir_writehd; /* Waiting for the pointer write. */ + struct allocindirhd ir_donehd; /* done waiting to update safecopy */ + struct allocindirhd ir_deplisthd; /* allocindir deps for this block */ + struct freeblks *ir_freeblks; /* Freeblks that frees this indir. */ +}; + +/* + * An "allocindir" structure is attached to an "indirdep" when a new block + * is allocated and pointed to by the indirect block described by the + * "indirdep". The worklist is linked to the buffer that holds the new block. + * When the block is first allocated, it is linked to the bmsafemap + * structure associated with the buffer holding the cylinder group map + * from which it was allocated. When the cylinder group map is written + * to disk, ai_state has the DEPCOMPLETE flag set. When the block itself + * is written, the COMPLETE flag is set. Once both the cylinder group map + * and the data itself have been written, it is safe to write the entry in + * the indirect block that claims the block; the "allocindir" dependency + * can then be freed as it is no longer applicable. + */ +struct allocindir { + struct newblk ai_block; /* Common block area */ +# define ai_state ai_block.nb_list.wk_state /* indirect pointer state */ + LIST_ENTRY(allocindir) ai_next; /* indirdep's list of allocindir's */ + struct indirdep *ai_indirdep; /* address of associated indirdep */ + ufs2_daddr_t ai_oldblkno; /* old value of block pointer */ + ufs_lbn_t ai_lbn; /* Logical block number. */ + int ai_offset; /* Pointer offset in parent. */ +}; +#define ai_newblkno ai_block.nb_newblkno +#define ai_freefrag ai_block.nb_freefrag +#define ai_newdirblk ai_block.nb_newdirblk + +/* + * The allblk union is used to size the newblk structure on allocation so + * that it may be any one of three types. + */ +union allblk { + struct allocindir ab_allocindir; + struct allocdirect ab_allocdirect; + struct newblk ab_newblk; +}; + +/* + * A "freefrag" structure is attached to an "inodedep" when a previously + * allocated fragment is replaced with a larger fragment, rather than extended. + * The "freefrag" structure is constructed and attached when the replacement + * block is first allocated. It is processed after the inode claiming the + * bigger block that replaces it has been written to disk. + */ +struct freefrag { + struct worklist ff_list; /* id_inowait or delayed worklist */ +# define ff_state ff_list.wk_state + struct worklist *ff_jdep; /* Associated journal entry. */ + struct workhead ff_jwork; /* Journal work pending. */ + ufs2_daddr_t ff_blkno; /* fragment physical block number */ + long ff_fragsize; /* size of fragment being deleted */ + ino_t ff_inum; /* owning inode number */ + enum vtype ff_vtype; /* owning inode's file type */ +}; + +/* + * A "freeblks" structure is attached to an "inodedep" when the + * corresponding file's length is reduced to zero. It records all + * the information needed to free the blocks of a file after its + * zero'ed inode has been written to disk. The actual work is done + * by child freework structures which are responsible for individual + * inode pointers while freeblks is responsible for retiring the + * entire operation when it is complete and holding common members. + */ +struct freeblks { + struct worklist fb_list; /* id_inowait or delayed worklist */ +# define fb_state fb_list.wk_state /* inode and dirty block state */ + TAILQ_ENTRY(freeblks) fb_next; /* List of inode truncates. */ + struct jblkdephd fb_jblkdephd; /* Journal entries pending */ + struct workhead fb_freeworkhd; /* Work items pending */ + struct workhead fb_jwork; /* Journal work pending */ + struct vnode *fb_devvp; /* filesystem device vnode */ +#ifdef QUOTA + struct dquot *fb_quota[MAXQUOTAS]; /* quotas to be adjusted */ +#endif + uint64_t fb_modrev; /* Inode revision at start of trunc. */ + off_t fb_len; /* Length we're truncating to. */ + ufs2_daddr_t fb_chkcnt; /* Blocks released. */ + ino_t fb_inum; /* inode owner of blocks */ + enum vtype fb_vtype; /* inode owner's file type */ + uid_t fb_uid; /* uid of previous owner of blocks */ + int fb_ref; /* Children outstanding. */ + int fb_cgwait; /* cg writes outstanding. */ +}; + +/* + * A "freework" structure handles the release of a tree of blocks or a single + * block. Each indirect block in a tree is allocated its own freework + * structure so that the indirect block may be freed only when all of its + * children are freed. In this way we enforce the rule that an allocated + * block must have a valid path to a root that is journaled. Each child + * block acquires a reference and when the ref hits zero the parent ref + * is decremented. If there is no parent the freeblks ref is decremented. + */ +struct freework { + struct worklist fw_list; /* Delayed worklist. */ +# define fw_state fw_list.wk_state + LIST_ENTRY(freework) fw_segs; /* Seg list. */ + TAILQ_ENTRY(freework) fw_next; /* Hash/Trunc list. */ + struct jnewblk *fw_jnewblk; /* Journal entry to cancel. */ + struct freeblks *fw_freeblks; /* Root of operation. */ + struct freework *fw_parent; /* Parent indirect. */ + struct indirdep *fw_indir; /* indirect block. */ + ufs2_daddr_t fw_blkno; /* Our block #. */ + ufs_lbn_t fw_lbn; /* Original lbn before free. */ + uint16_t fw_frags; /* Number of frags. */ + uint16_t fw_ref; /* Number of children out. */ + uint16_t fw_off; /* Current working position. */ + uint16_t fw_start; /* Start of partial truncate. */ +}; + +/* + * A "freedep" structure is allocated to track the completion of a bitmap + * write for a freework. One freedep may cover many freed blocks so long + * as they reside in the same cylinder group. When the cg is written + * the freedep decrements the ref on the freework which may permit it + * to be freed as well. + */ +struct freedep { + struct worklist fd_list; /* Delayed worklist. */ + struct freework *fd_freework; /* Parent freework. */ +}; + +/* + * A "freefile" structure is attached to an inode when its + * link count is reduced to zero. It marks the inode as free in + * the cylinder group map after the zero'ed inode has been written + * to disk and any associated blocks and fragments have been freed. + */ +struct freefile { + struct worklist fx_list; /* id_inowait or delayed worklist */ + mode_t fx_mode; /* mode of inode */ + ino_t fx_oldinum; /* inum of the unlinked file */ + struct vnode *fx_devvp; /* filesystem device vnode */ + struct workhead fx_jwork; /* journal work pending. */ +}; + +/* + * A "diradd" structure is linked to an "inodedep" id_inowait list when a + * new directory entry is allocated that references the inode described + * by "inodedep". When the inode itself is written (either the initial + * allocation for new inodes or with the increased link count for + * existing inodes), the COMPLETE flag is set in da_state. If the entry + * is for a newly allocated inode, the "inodedep" structure is associated + * with a bmsafemap which prevents the inode from being written to disk + * until the cylinder group has been updated. Thus the da_state COMPLETE + * flag cannot be set until the inode bitmap dependency has been removed. + * When creating a new file, it is safe to write the directory entry that + * claims the inode once the referenced inode has been written. Since + * writing the inode clears the bitmap dependencies, the DEPCOMPLETE flag + * in the diradd can be set unconditionally when creating a file. When + * creating a directory, there are two additional dependencies described by + * mkdir structures (see their description below). When these dependencies + * are resolved the DEPCOMPLETE flag is set in the diradd structure. + * If there are multiple links created to the same inode, there will be + * a separate diradd structure created for each link. The diradd is + * linked onto the pg_diraddhd list of the pagedep for the directory + * page that contains the entry. When a directory page is written, + * the pg_diraddhd list is traversed to rollback any entries that are + * not yet ready to be written to disk. If a directory entry is being + * changed (by rename) rather than added, the DIRCHG flag is set and + * the da_previous entry points to the entry that will be "removed" + * once the new entry has been committed. During rollback, entries + * with da_previous are replaced with the previous inode number rather + * than zero. + * + * The overlaying of da_pagedep and da_previous is done to keep the + * structure down. If a da_previous entry is present, the pointer to its + * pagedep is available in the associated dirrem entry. If the DIRCHG flag + * is set, the da_previous entry is valid; if not set the da_pagedep entry + * is valid. The DIRCHG flag never changes; it is set when the structure + * is created if appropriate and is never cleared. + */ +struct diradd { + struct worklist da_list; /* id_inowait or id_pendinghd list */ +# define da_state da_list.wk_state /* state of the new directory entry */ + LIST_ENTRY(diradd) da_pdlist; /* pagedep holding directory block */ + doff_t da_offset; /* offset of new dir entry in dir blk */ + ino_t da_newinum; /* inode number for the new dir entry */ + union { + struct dirrem *dau_previous; /* entry being replaced in dir change */ + struct pagedep *dau_pagedep; /* pagedep dependency for addition */ + } da_un; + struct workhead da_jwork; /* Journal work awaiting completion. */ +}; +#define da_previous da_un.dau_previous +#define da_pagedep da_un.dau_pagedep + +/* + * Two "mkdir" structures are needed to track the additional dependencies + * associated with creating a new directory entry. Normally a directory + * addition can be committed as soon as the newly referenced inode has been + * written to disk with its increased link count. When a directory is + * created there are two additional dependencies: writing the directory + * data block containing the "." and ".." entries (MKDIR_BODY) and writing + * the parent inode with the increased link count for ".." (MKDIR_PARENT). + * These additional dependencies are tracked by two mkdir structures that + * reference the associated "diradd" structure. When they have completed, + * they set the DEPCOMPLETE flag on the diradd so that it knows that its + * extra dependencies have been completed. The md_state field is used only + * to identify which type of dependency the mkdir structure is tracking. + * It is not used in the mainline code for any purpose other than consistency + * checking. All the mkdir structures in the system are linked together on + * a list. This list is needed so that a diradd can find its associated + * mkdir structures and deallocate them if it is prematurely freed (as for + * example if a mkdir is immediately followed by a rmdir of the same directory). + * Here, the free of the diradd must traverse the list to find the associated + * mkdir structures that reference it. The deletion would be faster if the + * diradd structure were simply augmented to have two pointers that referenced + * the associated mkdir's. However, this would increase the size of the diradd + * structure to speed a very infrequent operation. + */ +struct mkdir { + struct worklist md_list; /* id_inowait or buffer holding dir */ +# define md_state md_list.wk_state /* type: MKDIR_PARENT or MKDIR_BODY */ + struct diradd *md_diradd; /* associated diradd */ + struct jaddref *md_jaddref; /* dependent jaddref. */ + struct buf *md_buf; /* MKDIR_BODY: buffer holding dir */ + LIST_ENTRY(mkdir) md_mkdirs; /* list of all mkdirs */ +}; + +/* + * A "dirrem" structure describes an operation to decrement the link + * count on an inode. The dirrem structure is attached to the pg_dirremhd + * list of the pagedep for the directory page that contains the entry. + * It is processed after the directory page with the deleted entry has + * been written to disk. + */ +struct dirrem { + struct worklist dm_list; /* delayed worklist */ +# define dm_state dm_list.wk_state /* state of the old directory entry */ + LIST_ENTRY(dirrem) dm_next; /* pagedep's list of dirrem's */ + LIST_ENTRY(dirrem) dm_inonext; /* inodedep's list of dirrem's */ + struct jremrefhd dm_jremrefhd; /* Pending remove reference deps. */ + ino_t dm_oldinum; /* inum of the removed dir entry */ + doff_t dm_offset; /* offset of removed dir entry in blk */ + union { + struct pagedep *dmu_pagedep; /* pagedep dependency for remove */ + ino_t dmu_dirinum; /* parent inode number (for rmdir) */ + } dm_un; + struct workhead dm_jwork; /* Journal work awaiting completion. */ +}; +#define dm_pagedep dm_un.dmu_pagedep +#define dm_dirinum dm_un.dmu_dirinum + +/* + * A "newdirblk" structure tracks the progress of a newly allocated + * directory block from its creation until it is claimed by its on-disk + * inode. When a block is allocated to a directory, an fsync of a file + * whose name is within that block must ensure not only that the block + * containing the file name has been written, but also that the on-disk + * inode references that block. When a new directory block is created, + * we allocate a newdirblk structure which is linked to the associated + * allocdirect (on its ad_newdirblk list). When the allocdirect has been + * satisfied, the newdirblk structure is moved to the inodedep id_bufwait + * list of its directory to await the inode being written. When the inode + * is written, the directory entries are fully committed and can be + * deleted from their pagedep->id_pendinghd and inodedep->id_pendinghd + * lists. Note that we could track directory blocks allocated to indirect + * blocks using a similar scheme with the allocindir structures. Rather + * than adding this level of complexity, we simply write those newly + * allocated indirect blocks synchronously as such allocations are rare. + * In the case of a new directory the . and .. links are tracked with + * a mkdir rather than a pagedep. In this case we track the mkdir + * so it can be released when it is written. A workhead is used + * to simplify canceling a mkdir that is removed by a subsequent dirrem. + */ +struct newdirblk { + struct worklist db_list; /* id_inowait or pg_newdirblk */ +# define db_state db_list.wk_state + struct pagedep *db_pagedep; /* associated pagedep */ + struct workhead db_mkdir; +}; + +/* + * The inoref structure holds the elements common to jaddref and jremref + * so they may easily be queued in-order on the inodedep. + */ +struct inoref { + struct worklist if_list; /* Journal pending or jseg entries. */ +# define if_state if_list.wk_state + TAILQ_ENTRY(inoref) if_deps; /* Links for inodedep. */ + struct jsegdep *if_jsegdep; /* Will track our journal record. */ + off_t if_diroff; /* Directory offset. */ + ino_t if_ino; /* Inode number. */ + ino_t if_parent; /* Parent inode number. */ + nlink_t if_nlink; /* nlink before addition. */ + uint16_t if_mode; /* File mode, needed for IFMT. */ +}; + +/* + * A "jaddref" structure tracks a new reference (link count) on an inode + * and prevents the link count increase and bitmap allocation until a + * journal entry can be written. Once the journal entry is written, + * the inode is put on the pendinghd of the bmsafemap and a diradd or + * mkdir entry is placed on the bufwait list of the inode. The DEPCOMPLETE + * flag is used to indicate that all of the required information for writing + * the journal entry is present. MKDIR_BODY and MKDIR_PARENT are used to + * differentiate . and .. links from regular file names. NEWBLOCK indicates + * a bitmap is still pending. If a new reference is canceled by a delete + * prior to writing the journal the jaddref write is canceled and the + * structure persists to prevent any disk-visible changes until it is + * ultimately released when the file is freed or the link is dropped again. + */ +struct jaddref { + struct inoref ja_ref; /* see inoref above. */ +# define ja_list ja_ref.if_list /* Jrnl pending, id_inowait, dm_jwork.*/ +# define ja_state ja_ref.if_list.wk_state + LIST_ENTRY(jaddref) ja_bmdeps; /* Links for bmsafemap. */ + union { + struct diradd *jau_diradd; /* Pending diradd. */ + struct mkdir *jau_mkdir; /* MKDIR_{PARENT,BODY} */ + } ja_un; +}; +#define ja_diradd ja_un.jau_diradd +#define ja_mkdir ja_un.jau_mkdir +#define ja_diroff ja_ref.if_diroff +#define ja_ino ja_ref.if_ino +#define ja_parent ja_ref.if_parent +#define ja_mode ja_ref.if_mode + +/* + * A "jremref" structure tracks a removed reference (unlink) on an + * inode and prevents the directory remove from proceeding until the + * journal entry is written. Once the journal has been written the remove + * may proceed as normal. + */ +struct jremref { + struct inoref jr_ref; /* see inoref above. */ +# define jr_list jr_ref.if_list /* Linked to softdep_journal_pending. */ +# define jr_state jr_ref.if_list.wk_state + LIST_ENTRY(jremref) jr_deps; /* Links for dirrem. */ + struct dirrem *jr_dirrem; /* Back pointer to dirrem. */ +}; + +/* + * A "jmvref" structure tracks a name relocations within the same + * directory block that occur as a result of directory compaction. + * It prevents the updated directory entry from being written to disk + * until the journal entry is written. Once the journal has been + * written the compacted directory may be written to disk. + */ +struct jmvref { + struct worklist jm_list; /* Linked to softdep_journal_pending. */ + LIST_ENTRY(jmvref) jm_deps; /* Jmvref on pagedep. */ + struct pagedep *jm_pagedep; /* Back pointer to pagedep. */ + ino_t jm_parent; /* Containing directory inode number. */ + ino_t jm_ino; /* Inode number of our entry. */ + off_t jm_oldoff; /* Our old offset in directory. */ + off_t jm_newoff; /* Our new offset in directory. */ +}; + +/* + * A "jnewblk" structure tracks a newly allocated block or fragment and + * prevents the direct or indirect block pointer as well as the cg bitmap + * from being written until it is logged. After it is logged the jsegdep + * is attached to the allocdirect or allocindir until the operation is + * completed or reverted. If the operation is reverted prior to the journal + * write the jnewblk structure is maintained to prevent the bitmaps from + * reaching the disk. Ultimately the jnewblk structure will be passed + * to the free routine as the in memory cg is modified back to the free + * state at which time it can be released. It may be held on any of the + * fx_jwork, fw_jwork, fb_jwork, ff_jwork, nb_jwork, or ir_jwork lists. + */ +struct jnewblk { + struct worklist jn_list; /* See lists above. */ +# define jn_state jn_list.wk_state + struct jsegdep *jn_jsegdep; /* Will track our journal record. */ + LIST_ENTRY(jnewblk) jn_deps; /* Jnewblks on sm_jnewblkhd. */ + struct worklist *jn_dep; /* Dependency to ref completed seg. */ + ufs_lbn_t jn_lbn; /* Lbn to which allocated. */ + ufs2_daddr_t jn_blkno; /* Blkno allocated */ + ino_t jn_ino; /* Ino to which allocated. */ + int jn_oldfrags; /* Previous fragments when extended. */ + int jn_frags; /* Number of fragments. */ +}; + +/* + * A "jblkdep" structure tracks jfreeblk and jtrunc records attached to a + * freeblks structure. + */ +struct jblkdep { + struct worklist jb_list; /* For softdep journal pending. */ + struct jsegdep *jb_jsegdep; /* Reference to the jseg. */ + struct freeblks *jb_freeblks; /* Back pointer to freeblks. */ + LIST_ENTRY(jblkdep) jb_deps; /* Dep list on freeblks. */ + +}; + +/* + * A "jfreeblk" structure tracks the journal write for freeing a block + * or tree of blocks. The block pointer must not be cleared in the inode + * or indirect prior to the jfreeblk being written to the journal. + */ +struct jfreeblk { + struct jblkdep jf_dep; /* freeblks linkage. */ + ufs_lbn_t jf_lbn; /* Lbn from which blocks freed. */ + ufs2_daddr_t jf_blkno; /* Blkno being freed. */ + ino_t jf_ino; /* Ino from which blocks freed. */ + int jf_frags; /* Number of frags being freed. */ +}; + +/* + * A "jfreefrag" tracks the freeing of a single block when a fragment is + * extended or an indirect page is replaced. It is not part of a larger + * freeblks operation. + */ +struct jfreefrag { + struct worklist fr_list; /* Linked to softdep_journal_pending. */ +# define fr_state fr_list.wk_state + struct jsegdep *fr_jsegdep; /* Will track our journal record. */ + struct freefrag *fr_freefrag; /* Back pointer to freefrag. */ + ufs_lbn_t fr_lbn; /* Lbn from which frag freed. */ + ufs2_daddr_t fr_blkno; /* Blkno being freed. */ + ino_t fr_ino; /* Ino from which frag freed. */ + int fr_frags; /* Size of frag being freed. */ +}; + +/* + * A "jtrunc" journals the intent to truncate an inode's data or extent area. + */ +struct jtrunc { + struct jblkdep jt_dep; /* freeblks linkage. */ + off_t jt_size; /* Final file size. */ + int jt_extsize; /* Final extent size. */ + ino_t jt_ino; /* Ino being truncated. */ +}; + +/* + * A "jfsync" journals the completion of an fsync which invalidates earlier + * jtrunc records in the journal. + */ +struct jfsync { + struct worklist jfs_list; /* For softdep journal pending. */ + off_t jfs_size; /* Sync file size. */ + int jfs_extsize; /* Sync extent size. */ + ino_t jfs_ino; /* ino being synced. */ +}; + +/* + * A "jsegdep" structure tracks a single reference to a written journal + * segment so the journal space can be reclaimed when all dependencies + * have been written. It can hang off of id_inowait, dm_jwork, da_jwork, + * nb_jwork, ff_jwork, or fb_jwork lists. + */ +struct jsegdep { + struct worklist jd_list; /* See above for lists. */ +# define jd_state jd_list.wk_state + struct jseg *jd_seg; /* Our journal record. */ +}; + +/* + * A "jseg" structure contains all of the journal records written in a + * single disk write. The jaddref and jremref structures are linked into + * js_entries so thay may be completed when the write completes. The + * js_entries also include the write dependency structures: jmvref, + * jnewblk, jfreeblk, jfreefrag, and jtrunc. The js_refs field counts + * the number of entries on the js_entries list. Thus there is a single + * jseg entry to describe each journal write. + */ +struct jseg { + struct worklist js_list; /* b_deps link for journal */ +# define js_state js_list.wk_state + struct workhead js_entries; /* Entries awaiting write */ + LIST_HEAD(, freework) js_indirs;/* List of indirects in this seg. */ + TAILQ_ENTRY(jseg) js_next; /* List of all unfinished segments. */ + struct jblocks *js_jblocks; /* Back pointer to block/seg list */ + struct buf *js_buf; /* Buffer while unwritten */ + uint64_t js_seq; /* Journal record sequence number. */ + uint64_t js_oldseq; /* Oldest valid sequence number. */ + int js_size; /* Size of journal record in bytes. */ + int js_cnt; /* Total items allocated. */ + int js_refs; /* Count of js_entries items. */ +}; + +/* + * A 'sbdep' structure tracks the head of the free inode list and + * superblock writes. This makes sure the superblock is always pointing at + * the first possible unlinked inode for the suj recovery process. If a + * block write completes and we discover a new head is available the buf + * is dirtied and the dep is kept. See the description of the UNLINK* + * flags above for more details. + */ +struct sbdep { + struct worklist sb_list; /* b_dep linkage */ + struct fs *sb_fs; /* Filesystem pointer within buf. */ + struct ufsmount *sb_ump; /* Our mount structure */ +}; + +/* + * Private journaling structures. + */ +struct jblocks { + struct jseglst jb_segs; /* TAILQ of current segments. */ + struct jseg *jb_writeseg; /* Next write to complete. */ + struct jseg *jb_oldestseg; /* Oldest segment with valid entries. */ + struct jextent *jb_extent; /* Extent array. */ + uint64_t jb_nextseq; /* Next sequence number. */ + uint64_t jb_oldestwrseq; /* Oldest written sequence number. */ + uint8_t jb_needseg; /* Need a forced segment. */ + uint8_t jb_suspended; /* Did journal suspend writes? */ + int jb_avail; /* Available extents. */ + int jb_used; /* Last used extent. */ + int jb_head; /* Allocator head. */ + int jb_off; /* Allocator extent offset. */ + int jb_blocks; /* Total disk blocks covered. */ + int jb_free; /* Total disk blocks free. */ + int jb_min; /* Minimum free space. */ + int jb_low; /* Low on space. */ + int jb_age; /* Insertion time of oldest rec. */ +}; + +struct jextent { + ufs2_daddr_t je_daddr; /* Disk block address. */ + int je_blocks; /* Disk block count. */ +}; + +/* + * Hash table declarations. + */ +LIST_HEAD(mkdirlist, mkdir); +LIST_HEAD(pagedep_hashhead, pagedep); +LIST_HEAD(inodedep_hashhead, inodedep); +LIST_HEAD(newblk_hashhead, newblk); +LIST_HEAD(bmsafemap_hashhead, bmsafemap); +TAILQ_HEAD(indir_hashhead, freework); + +/* + * Per-filesystem soft dependency data. + * Allocated at mount and freed at unmount. + */ +struct mount_softdeps { + struct rwlock sd_fslock; /* softdep lock */ + struct workhead sd_workitem_pending; /* softdep work queue */ + struct worklist *sd_worklist_tail; /* Tail pointer for above */ + struct workhead sd_journal_pending; /* journal work queue */ + struct worklist *sd_journal_tail; /* Tail pointer for above */ + struct jblocks *sd_jblocks; /* Journal block information */ + struct inodedeplst sd_unlinked; /* Unlinked inodes */ + struct bmsafemaphd sd_dirtycg; /* Dirty CGs */ + struct mkdirlist sd_mkdirlisthd; /* Track mkdirs */ + struct pagedep_hashhead *sd_pdhash; /* pagedep hash table */ + u_long sd_pdhashsize; /* pagedep hash table size-1 */ + long sd_pdnextclean; /* next hash bucket to clean */ + struct inodedep_hashhead *sd_idhash; /* inodedep hash table */ + u_long sd_idhashsize; /* inodedep hash table size-1 */ + long sd_idnextclean; /* next hash bucket to clean */ + struct newblk_hashhead *sd_newblkhash; /* newblk hash table */ + u_long sd_newblkhashsize; /* newblk hash table size-1 */ + struct bmsafemap_hashhead *sd_bmhash; /* bmsafemap hash table */ + u_long sd_bmhashsize; /* bmsafemap hash table size-1*/ + struct indir_hashhead *sd_indirhash; /* indir hash table */ + u_long sd_indirhashsize; /* indir hash table size-1 */ + int sd_on_journal; /* Items on the journal list */ + int sd_on_worklist; /* Items on the worklist */ + int sd_deps; /* Total dependency count */ + int sd_accdeps; /* accumulated dep count */ + int sd_req; /* Wakeup when deps hits 0. */ + int sd_flags; /* comm with flushing thread */ + int sd_cleanups; /* Calls to cleanup */ + struct thread *sd_flushtd; /* thread handling flushing */ + TAILQ_ENTRY(mount_softdeps) sd_next; /* List of softdep filesystem */ + struct ufsmount *sd_ump; /* our ufsmount structure */ + u_long sd_curdeps[D_LAST + 1]; /* count of current deps */ +}; +/* + * Flags for communicating with the syncer thread. + */ +#define FLUSH_EXIT 0x0001 /* time to exit */ +#define FLUSH_CLEANUP 0x0002 /* need to clear out softdep structures */ +#define FLUSH_STARTING 0x0004 /* flush thread not yet started */ +#define FLUSH_RC_ACTIVE 0x0008 /* a thread is flushing the mount point */ + +/* + * Keep the old names from when these were in the ufsmount structure. + */ +#define softdep_workitem_pending um_softdep->sd_workitem_pending +#define softdep_worklist_tail um_softdep->sd_worklist_tail +#define softdep_journal_pending um_softdep->sd_journal_pending +#define softdep_journal_tail um_softdep->sd_journal_tail +#define softdep_jblocks um_softdep->sd_jblocks +#define softdep_unlinked um_softdep->sd_unlinked +#define softdep_dirtycg um_softdep->sd_dirtycg +#define softdep_mkdirlisthd um_softdep->sd_mkdirlisthd +#define pagedep_hashtbl um_softdep->sd_pdhash +#define pagedep_hash_size um_softdep->sd_pdhashsize +#define pagedep_nextclean um_softdep->sd_pdnextclean +#define inodedep_hashtbl um_softdep->sd_idhash +#define inodedep_hash_size um_softdep->sd_idhashsize +#define inodedep_nextclean um_softdep->sd_idnextclean +#define newblk_hashtbl um_softdep->sd_newblkhash +#define newblk_hash_size um_softdep->sd_newblkhashsize +#define bmsafemap_hashtbl um_softdep->sd_bmhash +#define bmsafemap_hash_size um_softdep->sd_bmhashsize +#define indir_hashtbl um_softdep->sd_indirhash +#define indir_hash_size um_softdep->sd_indirhashsize +#define softdep_on_journal um_softdep->sd_on_journal +#define softdep_on_worklist um_softdep->sd_on_worklist +#define softdep_deps um_softdep->sd_deps +#define softdep_accdeps um_softdep->sd_accdeps +#define softdep_req um_softdep->sd_req +#define softdep_flags um_softdep->sd_flags +#define softdep_flushtd um_softdep->sd_flushtd +#define softdep_curdeps um_softdep->sd_curdeps diff --git a/Dump/ufs/test.txt b/Dump/ufs/test.txt new file mode 100644 index 0000000..3cd9a6e --- /dev/null +++ b/Dump/ufs/test.txt @@ -0,0 +1 @@ +Sync diff --git a/Dump/ufs/ufs/README.acls b/Dump/ufs/ufs/README.acls new file mode 100644 index 0000000..0e8a9d5 --- /dev/null +++ b/Dump/ufs/ufs/README.acls @@ -0,0 +1,79 @@ +$FreeBSD: releng/11.2/sys/ufs/ufs/README.acls 105456 2002-10-19 16:09:16Z rwatson $ + + UFS Access Control Lists Copyright + +The UFS Access Control Lists implementation is copyright Robert Watson, +and is made available under a Berkeley-style license. + + About UFS Access Control Lists (ACLs) + +Access control lists allow the association of fine-grained discretionary +access control information with files and directories, extending the +base UNIX permission model in a (mostly) compatible way. This +implementation largely follows the POSIX.1e model, and relies on the +availability of extended attributes to store extended components of +the ACL, while maintaining the base permission information in the inode. + + Using UFS Access Control Lists (ACLs) + +Support for UFS access control lists may be enabled by adding: + + options UFS_ACL + +to your kernel configuration. As ACLs rely on the availability of extended +attributes, your file systems must have support for extended attributes. +For UFS2, this is supported natively, so no further configuration is +necessary. For UFS1, you must also enable the optional extended attributes +support documented in README.extattr. A summary of the instructions +and ACL-specific information follows. + +To enable support for ACLs on a file system, the 'acls' mount flag +must be set for the file system. This may be set using the tunefs +'-a' flag: + + tunefs -a enable /dev/md0a + +Or by using the mount-time flag: + + mount -o acls /dev/md0a /mnt + +The flag may also be set in /etc/fstab. Note that mounting a file +system previously configured for ACLs without ACL-support will result +in incorrect application of discretionary protections. Likewise, +mounting an ACL-enabled file system without kernel support for ACLs +will result in incorrect application of discretionary protections. If +the kernel is not configured for ACL support, a warning will be +printed by the kernel at mount-time. For reliability purposes, it +is recommended that the superblock flag be used instead of the +mount-time flag, as this will avoid re-mount isses with the root file +system. For reliability and performance reasons, the use of ACLs on +UFS1 is discouraged; UFS2 extended attributes provide a more reliable +storage mechanism for ACLs. + +Currently, support for ACLs on UFS1 requires the use of UFS1 EAs, which may +be enabled by adding: + + options UFS_EXTATTR + +to your kernel configuration file and rebuilding. Because of filesystem +mount atomicity requirements, it is also recommended that: + + options UFS_EXTATTR_AUTOSTART + +be added to the kernel so as to support the atomic enabling of the +required extended attributes with the filesystem mount operation. To +enable ACLs, two extended attributes must be available in the +EXTATTR_NAMESPACE_SYSTEM namespace: "posix1e.acl_access", which holds +the access ACL, and "posix1e.acl_default" which holds the default ACL +for directories. If you're using UFS1 Extended Attributes, the following +commands may be used to create the necessary EA backing files for +ACLs in the filesystem root of each filesystem. In these examples, +the root filesystem is used; see README.extattr for more details. + + mkdir -p /.attribute/system + cd /.attribute/system + extattrctl initattr -p / 388 posix1e.acl_access + extattrctl initattr -p / 388 posix1e.acl_default + +On the next mount of the root filesystem, the attributes will be +automatically started, and ACLs will be enabled. diff --git a/Dump/ufs/ufs/README.extattr b/Dump/ufs/ufs/README.extattr new file mode 100644 index 0000000..eea7628 --- /dev/null +++ b/Dump/ufs/ufs/README.extattr @@ -0,0 +1,91 @@ +$FreeBSD: releng/11.2/sys/ufs/ufs/README.extattr 105417 2002-10-18 21:11:36Z rwatson $ + + UFS Extended Attributes Copyright + +The UFS Extended Attributes implementation is copyright Robert Watson, and +is made available under a Berkeley-style license. + + About UFS Extended Attributes + +Extended attributes allow the association of additional arbitrary +meta-data with files and directories. Extended attributes are defined in +the form name=value, where name is an nul-terminated string in the style +of a filename, and value is a binary blob of zero or more bytes. The UFS +extended attribute service layers support for extended attributes onto a +backing file, in the style of the quota implementation, meaning that it +requires no underlying format changes in the filesystem. This design +choice exchanges simplicity, usability and easy deployment for +performance. When defined, extended attribute names exist in a series of +disjoint namespaces: currently, two namespaces are defined: +EXTATTR_NAMESPACE_SYSTEM and EXTATTR_NAMESPACE_USER. The primary +distinction lies in the protection model: USER EAs are protected using the +normal inode protections, whereas SYSTEM EAs require privilege to access +or modify. + + Using UFS Extended Attributes + +Support for UFS extended attributes is natively available in UFS2, and +requires no special configuration. For reliability, administrative, +and performance reasons, if you plan to use extended attributes, it +is recommended that you use UFS2 in preference to UFS1. + +Support for UFS extended attributes may be enabled for UFS1 by adding: + + options UFS_EXTATTR + +to your kernel configuration file. This allows UFS-based filesystems to +support extended attributes, but requires manual administration of EAs +using the extattrctl tool, including the starting of EA support for each +filesystem, and the enabling of individual attributes for the file +system. The extattrctl utility may be used to initialize backing files +before first use, to start and stop EA service on a filesystem, and to +enable and disable named attributes. The command lines for extattrctl +take the following forms: + + extattrctl start [path] + extattrctl stop [path] + extattrctl initattr [-f] [-p path] [attrsize] [attrfile] + extattrctl enable [path] [attrnamespace] [attrname] [attrfile] + extattrctl disable [path] [attrnamespace] [attrname] + +In each case, [path] is used to indicate the mounted filesystem on which +to perform the operation. [attrnamespace] refers to the namespace in +which the attribute is being manipulated, and may be "system" or "user". +The [attrname] is the attribute name to use for the operation. The +[attrfile] argument specifies the attribute backing file to use. When +using the "initattr" function to initialize a backing file, the maximum +size of attribute data must be defined in bytes using the [attrsize] +field. Optionally, the [-p path] argument may be used to indicate to +extattrctl that it should pre-allocate space for EA data, rather than +creating a sparse backing file. This prevents attribute operations from +failing in low disk-space conditions (which can be important when EAs are +used for security purposes), but pre-allocation will consume space +proportional to the product of the defined maximum attribute size and +number of attributes on the specified filesystem. + +Manual configuration increases administrative overhead, but also +introduces the possibility of race conditions during filesystem mount, if +EAs are used to support other features, as starting the EAs manually is +not atomic with the mount operation. To address this problem, an +additional kernel option may be defined to auto-start EAs on a UFS file +system based on special directories at mount-time: + + options UFS_EXTATTR_AUTOSTART + +If this option is defined, UFS will search for a ".attribute" +sub-directory of the filesystem root during the mount operation. If it +is found, EA support will be started for the filesystem. UFS will then +search for "system" and "user" sub-directories of the ".attribute" +directory for any potential backing files, and enable an EA for each valid +backing file with the name of the backing file as the attribute name. +For example, by creating the following tree, the two EAs, +posix1e.acl_access and posix1e.acl_default will be enabled in the system +namespace of the root filesystem, reserving space for attribute data: + + mkdir -p /.attribute/system + cd /.attribute/system + extattrctl initattr -p / 388 posix1e.acl_access + extattrctl initattr -p / 388 posix1e.acl_default + +On the next mount of the root filesystem, the attributes will be +automatically started. diff --git a/Dump/ufs/ufs/acl.h b/Dump/ufs/ufs/acl.h new file mode 100644 index 0000000..63b32dd --- /dev/null +++ b/Dump/ufs/ufs/acl.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1999-2001 Robert N. M. Watson + * All rights reserved. + * + * This software was developed by Robert Watson for the TrustedBSD Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: releng/11.2/sys/ufs/ufs/acl.h 200796 2009-12-21 19:39:10Z trasz $ + */ +/* + * Developed by the TrustedBSD Project. + * Support for POSIX.1e access control lists. + */ + +#ifndef _UFS_UFS_ACL_H_ +#define _UFS_UFS_ACL_H_ + +#ifdef _KERNEL + +int ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td); +int ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td); +void ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl); +void ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip); + +int ufs_getacl(struct vop_getacl_args *); +int ufs_setacl(struct vop_setacl_args *); +int ufs_aclcheck(struct vop_aclcheck_args *); + +#endif /* !_KERNEL */ + +#endif /* !_UFS_UFS_ACL_H_ */ diff --git a/Dump/ufs/ufs/dinode.h b/Dump/ufs/ufs/dinode.h new file mode 100644 index 0000000..386ac8c --- /dev/null +++ b/Dump/ufs/ufs/dinode.h @@ -0,0 +1,189 @@ +/*- + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by Marshall + * Kirk McKusick and Network Associates Laboratories, the Security + * Research Division of Network Associates, Inc. under DARPA/SPAWAR + * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS + * research program + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The names of the authors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dinode.h 8.3 (Berkeley) 1/21/94 + * $FreeBSD: releng/11.2/sys/ufs/ufs/dinode.h 257029 2013-10-24 00:33:29Z pfg $ + */ + +#ifndef _UFS_UFS_DINODE_H_ +#define _UFS_UFS_DINODE_H_ + +/* + * The root inode is the root of the filesystem. Inode 0 can't be used for + * normal purposes and historically bad blocks were linked to inode 1, thus + * the root inode is 2. (Inode 1 is no longer used for this purpose, however + * numerous dump tapes make this assumption, so we are stuck with it). + */ +#define ROOTINO ((ino_t)2) + +/* + * The Whiteout inode# is a dummy non-zero inode number which will + * never be allocated to a real file. It is used as a place holder + * in the directory entry which has been tagged as a DT_WHT entry. + * See the comments about ROOTINO above. + */ +#define WINO ((ino_t)1) + +/* + * The size of physical and logical block numbers and time fields in UFS. + */ +typedef int32_t ufs1_daddr_t; +typedef int64_t ufs2_daddr_t; +typedef int64_t ufs_lbn_t; +typedef int64_t ufs_time_t; + +/* File permissions. */ +#define IEXEC 0000100 /* Executable. */ +#define IWRITE 0000200 /* Writeable. */ +#define IREAD 0000400 /* Readable. */ +#define ISVTX 0001000 /* Sticky bit. */ +#define ISGID 0002000 /* Set-gid. */ +#define ISUID 0004000 /* Set-uid. */ + +/* File types. */ +#define IFMT 0170000 /* Mask of file type. */ +#define IFIFO 0010000 /* Named pipe (fifo). */ +#define IFCHR 0020000 /* Character device. */ +#define IFDIR 0040000 /* Directory file. */ +#define IFBLK 0060000 /* Block device. */ +#define IFREG 0100000 /* Regular file. */ +#define IFLNK 0120000 /* Symbolic link. */ +#define IFSOCK 0140000 /* UNIX domain socket. */ +#define IFWHT 0160000 /* Whiteout. */ + +/* + * A dinode contains all the meta-data associated with a UFS2 file. + * This structure defines the on-disk format of a dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ + +#define NXADDR 2 /* External addresses in inode. */ +#define NDADDR 12 /* Direct addresses in inode. */ +#define NIADDR 3 /* Indirect addresses in inode. */ + +struct ufs2_dinode { + u_int16_t di_mode; /* 0: IFMT, permissions; see below. */ + int16_t di_nlink; /* 2: File link count. */ + u_int32_t di_uid; /* 4: File owner. */ + u_int32_t di_gid; /* 8: File group. */ + u_int32_t di_blksize; /* 12: Inode blocksize. */ + u_int64_t di_size; /* 16: File byte count. */ + u_int64_t di_blocks; /* 24: Blocks actually held. */ + ufs_time_t di_atime; /* 32: Last access time. */ + ufs_time_t di_mtime; /* 40: Last modified time. */ + ufs_time_t di_ctime; /* 48: Last inode change time. */ + ufs_time_t di_birthtime; /* 56: Inode creation time. */ + int32_t di_mtimensec; /* 64: Last modified time. */ + int32_t di_atimensec; /* 68: Last access time. */ + int32_t di_ctimensec; /* 72: Last inode change time. */ + int32_t di_birthnsec; /* 76: Inode creation time. */ + u_int32_t di_gen; /* 80: Generation number. */ + u_int32_t di_kernflags; /* 84: Kernel flags. */ + u_int32_t di_flags; /* 88: Status flags (chflags). */ + u_int32_t di_extsize; /* 92: External attributes size. */ + ufs2_daddr_t di_extb[NXADDR];/* 96: External attributes block. */ + ufs2_daddr_t di_db[NDADDR]; /* 112: Direct disk blocks. */ + ufs2_daddr_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */ + u_int64_t di_modrev; /* 232: i_modrev for NFSv4 */ + uint32_t di_freelink; /* 240: SUJ: Next unlinked inode. */ + uint32_t di_spare[3]; /* 244: Reserved; currently unused */ +}; + +/* + * The di_db fields may be overlaid with other information for + * file types that do not have associated disk storage. Block + * and character devices overlay the first data block with their + * dev_t value. Short symbolic links place their path in the + * di_db area. + */ +#define di_rdev di_db[0] + +/* + * A UFS1 dinode contains all the meta-data associated with a UFS1 file. + * This structure defines the on-disk format of a UFS1 dinode. Since + * this structure describes an on-disk structure, all its fields + * are defined by types with precise widths. + */ +struct ufs1_dinode { + u_int16_t di_mode; /* 0: IFMT, permissions; see below. */ + int16_t di_nlink; /* 2: File link count. */ + uint32_t di_freelink; /* 4: SUJ: Next unlinked inode. */ + u_int64_t di_size; /* 8: File byte count. */ + int32_t di_atime; /* 16: Last access time. */ + int32_t di_atimensec; /* 20: Last access time. */ + int32_t di_mtime; /* 24: Last modified time. */ + int32_t di_mtimensec; /* 28: Last modified time. */ + int32_t di_ctime; /* 32: Last inode change time. */ + int32_t di_ctimensec; /* 36: Last inode change time. */ + ufs1_daddr_t di_db[NDADDR]; /* 40: Direct disk blocks. */ + ufs1_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */ + u_int32_t di_flags; /* 100: Status flags (chflags). */ + u_int32_t di_blocks; /* 104: Blocks actually held. */ + u_int32_t di_gen; /* 108: Generation number. */ + u_int32_t di_uid; /* 112: File owner. */ + u_int32_t di_gid; /* 116: File group. */ + u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */ +}; + +#endif /* _UFS_UFS_DINODE_H_ */ diff --git a/Dump/ufs/ufs/dir.h b/Dump/ufs/ufs/dir.h new file mode 100644 index 0000000..77aa5c7 --- /dev/null +++ b/Dump/ufs/ufs/dir.h @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)dir.h 8.2 (Berkeley) 1/21/94 + * $FreeBSD: releng/11.2/sys/ufs/ufs/dir.h 331722 2018-03-29 02:50:57Z eadler $ + */ + +#ifndef _UFS_UFS_DIR_H_ +#define _UFS_UFS_DIR_H_ + +/* + * Theoretically, directories can be more than 2Gb in length, however, in + * practice this seems unlikely. So, we define the type doff_t as a 32-bit + * quantity to keep down the cost of doing lookup on a 32-bit machine. + */ +#define doff_t int32_t +#define MAXDIRSIZE (0x7fffffff) + +/* + * A directory consists of some number of blocks of DIRBLKSIZ + * bytes, where DIRBLKSIZ is chosen such that it can be transferred + * to disk in a single atomic operation (e.g. 512 bytes on most machines). + * + * Each DIRBLKSIZ byte block contains some number of directory entry + * structures, which are of variable length. Each directory entry has + * a struct direct at the front of it, containing its inode number, + * the length of the entry, and the length of the name contained in + * the entry. These are followed by the name padded to a 4 byte boundary + * with null bytes. All names are guaranteed null terminated. + * The maximum length of a name in a directory is MAXNAMLEN. + * + * The macro DIRSIZ(fmt, dp) gives the amount of space required to represent + * a directory entry. Free space in a directory is represented by + * entries which have dp->d_reclen > DIRSIZ(fmt, dp). All DIRBLKSIZ bytes + * in a directory block are claimed by the directory entries. This + * usually results in the last entry in a directory having a large + * dp->d_reclen. When entries are deleted from a directory, the + * space is returned to the previous entry in the same directory + * block by increasing its dp->d_reclen. If the first entry of + * a directory block is free, then its dp->d_ino is set to 0. + * Entries other than the first in a directory do not normally have + * dp->d_ino set to 0. + */ +#define DIRBLKSIZ DEV_BSIZE +#define MAXNAMLEN 255 + +struct direct { + u_int32_t d_ino; /* inode number of entry */ + u_int16_t d_reclen; /* length of this record */ + u_int8_t d_type; /* file type, see below */ + u_int8_t d_namlen; /* length of string in d_name */ + char d_name[MAXNAMLEN + 1];/* name with length <= MAXNAMLEN */ +}; + +/* + * File types + */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +/* + * Convert between stat structure types and directory types. + */ +#define IFTODT(mode) (((mode) & 0170000) >> 12) +#define DTTOIF(dirtype) ((dirtype) << 12) + +/* + * The DIRSIZ macro gives the minimum record length which will hold + * the directory entry. This requires the amount of space in struct direct + * without the d_name field, plus enough space for the name with a terminating + * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. + * + * + */ +#define DIRECTSIZ(namlen) \ + ((__offsetof(struct direct, d_name) + \ + ((namlen)+1)*sizeof(((struct direct *)0)->d_name[0]) + 3) & ~3) +#if (BYTE_ORDER == LITTLE_ENDIAN) +#define DIRSIZ(oldfmt, dp) \ + ((oldfmt) ? DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen)) +#else +#define DIRSIZ(oldfmt, dp) \ + DIRECTSIZ((dp)->d_namlen) +#endif +#define OLDDIRFMT 1 +#define NEWDIRFMT 0 + +/* + * Template for manipulating directories. Should use struct direct's, + * but the name field is MAXNAMLEN - 1, and this just won't do. + */ +struct dirtemplate { + u_int32_t dot_ino; + int16_t dot_reclen; + u_int8_t dot_type; + u_int8_t dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int32_t dotdot_ino; + int16_t dotdot_reclen; + u_int8_t dotdot_type; + u_int8_t dotdot_namlen; + char dotdot_name[4]; /* ditto */ +}; + +/* + * This is the old format of directories, sanz type element. + */ +struct odirtemplate { + u_int32_t dot_ino; + int16_t dot_reclen; + u_int16_t dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int32_t dotdot_ino; + int16_t dotdot_reclen; + u_int16_t dotdot_namlen; + char dotdot_name[4]; /* ditto */ +}; +#endif /* !_DIR_H_ */ diff --git a/Dump/ufs/ufs/dirhash.h b/Dump/ufs/ufs/dirhash.h new file mode 100644 index 0000000..f58e2df --- /dev/null +++ b/Dump/ufs/ufs/dirhash.h @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 2001 Ian Dowse. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: releng/11.2/sys/ufs/ufs/dirhash.h 298804 2016-04-29 20:43:51Z pfg $ + */ + +#ifndef _UFS_UFS_DIRHASH_H_ +#define _UFS_UFS_DIRHASH_H_ + +#include +#include + +/* + * For fast operations on large directories, we maintain a hash + * that maps the file name to the offset of the directory entry within + * the directory file. + * + * The hashing uses a dumb spillover to the next free slot on + * collisions, so we must keep the utilisation low to avoid + * long linear searches. Deleted entries that are not the last + * in a chain must be marked DIRHASH_DEL. + * + * We also maintain information about free space in each block + * to speed up creations. + */ +#define DIRHASH_EMPTY (-1) /* entry unused */ +#define DIRHASH_DEL (-2) /* deleted entry; may be part of chain */ + +#define DIRALIGN 4 +#define DH_NFSTATS (DIRECTSIZ(MAXNAMLEN + 1) / DIRALIGN) + /* max DIRALIGN words in a directory entry */ + +/* + * Dirhash uses a score mechanism to achieve a hybrid between a + * least-recently-used and a least-often-used algorithm for entry + * recycling. The score is incremented when a directory is used, and + * decremented when the directory is a candidate for recycling. When + * the score reaches zero, the hash is recycled. Hashes are linked + * together on a TAILQ list, and hashes with higher scores filter + * towards the tail (most recently used) end of the list. + * + * New hash entries are given an initial score of DH_SCOREINIT and are + * placed at the most-recently-used end of the list. This helps a lot + * in the worst-case case scenario where every directory access is + * to a directory that is not hashed (i.e. the working set of hash + * candidates is much larger than the configured memry limit). In this + * case it limits the number of hash builds to 1/DH_SCOREINIT of the + * number of accesses. + */ +#define DH_SCOREINIT 8 /* initial dh_score when dirhash built */ +#define DH_SCOREMAX 64 /* max dh_score value */ + +/* + * The main hash table has 2 levels. It is an array of pointers to + * blocks of DH_NBLKOFF offsets. + */ +#define DH_BLKOFFSHIFT 8 +#define DH_NBLKOFF (1 << DH_BLKOFFSHIFT) +#define DH_BLKOFFMASK (DH_NBLKOFF - 1) + +#define DH_ENTRY(dh, slot) \ + ((dh)->dh_hash[(slot) >> DH_BLKOFFSHIFT][(slot) & DH_BLKOFFMASK]) + +struct dirhash { + struct sx dh_lock; /* protects all fields except list & score */ + int dh_refcount; + + doff_t **dh_hash; /* the hash array (2-level) */ + int dh_narrays; /* number of entries in dh_hash */ + int dh_hlen; /* total slots in the 2-level hash array */ + int dh_hused; /* entries in use */ + int dh_memreq; /* Memory used. */ + + /* Free space statistics. XXX assumes DIRBLKSIZ is 512. */ + u_int8_t *dh_blkfree; /* free DIRALIGN words in each dir block */ + int dh_nblk; /* size of dh_blkfree array */ + int dh_dirblks; /* number of DIRBLKSIZ blocks in dir */ + int dh_firstfree[DH_NFSTATS + 1]; /* first blk with N words free */ + + doff_t dh_seqoff; /* sequential access optimisation offset */ + + int dh_score; /* access count for this dirhash */ + + int dh_onlist; /* true if on the ufsdirhash_list chain */ + + time_t dh_lastused; /* time the dirhash was last read or written*/ + + /* Protected by ufsdirhash_mtx. */ + TAILQ_ENTRY(dirhash) dh_list; /* chain of all dirhashes */ +}; + + +/* + * Dirhash functions. + */ +void ufsdirhash_init(void); +void ufsdirhash_uninit(void); +int ufsdirhash_build(struct inode *); +doff_t ufsdirhash_findfree(struct inode *, int, int *); +doff_t ufsdirhash_enduseful(struct inode *); +int ufsdirhash_lookup(struct inode *, char *, int, doff_t *, struct buf **, + doff_t *); +void ufsdirhash_newblk(struct inode *, doff_t); +void ufsdirhash_add(struct inode *, struct direct *, doff_t); +void ufsdirhash_remove(struct inode *, struct direct *, doff_t); +void ufsdirhash_move(struct inode *, struct direct *, doff_t, doff_t); +void ufsdirhash_dirtrunc(struct inode *, doff_t); +void ufsdirhash_free(struct inode *); + +void ufsdirhash_checkblock(struct inode *, char *, doff_t); + +#endif /* !_UFS_UFS_DIRHASH_H_ */ diff --git a/Dump/ufs/ufs/extattr.h b/Dump/ufs/ufs/extattr.h new file mode 100644 index 0000000..61a6939 --- /dev/null +++ b/Dump/ufs/ufs/extattr.h @@ -0,0 +1,161 @@ +/*- + * Copyright (c) 1999-2001 Robert N. M. Watson + * All rights reserved. + * + * This software was developed by Robert Watson for the TrustedBSD Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: releng/11.2/sys/ufs/ufs/extattr.h 306553 2016-10-01 09:19:43Z kib $ + */ +/* + * Developed by the TrustedBSD Project. + * Support for extended filesystem attributes. + */ + +#ifndef _UFS_UFS_EXTATTR_H_ +#define _UFS_UFS_EXTATTR_H_ + +#define UFS_EXTATTR_MAGIC 0x00b5d5ec +#define UFS_EXTATTR_VERSION 0x00000003 +#define UFS_EXTATTR_FSROOTSUBDIR ".attribute" +#define UFS_EXTATTR_SUBDIR_SYSTEM "system" +#define UFS_EXTATTR_SUBDIR_USER "user" +#define UFS_EXTATTR_MAXEXTATTRNAME 65 /* including null */ + +#define UFS_EXTATTR_ATTR_FLAG_INUSE 0x00000001 /* attr has been set */ +#define UFS_EXTATTR_PERM_KERNEL 0x00000000 +#define UFS_EXTATTR_PERM_ROOT 0x00000001 +#define UFS_EXTATTR_PERM_OWNER 0x00000002 +#define UFS_EXTATTR_PERM_ANYONE 0x00000003 + +#define UFS_EXTATTR_UEPM_INITIALIZED 0x00000001 +#define UFS_EXTATTR_UEPM_STARTED 0x00000002 + +#define UFS_EXTATTR_CMD_START 0x00000001 +#define UFS_EXTATTR_CMD_STOP 0x00000002 +#define UFS_EXTATTR_CMD_ENABLE 0x00000003 +#define UFS_EXTATTR_CMD_DISABLE 0x00000004 + +struct ufs_extattr_fileheader { + u_int uef_magic; /* magic number for sanity checking */ + u_int uef_version; /* version of attribute file */ + u_int uef_size; /* size of attributes, w/o header */ +}; + +struct ufs_extattr_header { + u_int ueh_flags; /* flags for attribute */ + u_int ueh_len; /* local defined length; <= uef_size */ + u_int32_t ueh_i_gen; /* generation number for sanity */ + /* data follows the header */ +}; + +/* + * This structure defines the required fields of an extended-attribute header. + */ +struct extattr { + int32_t ea_length; /* length of this attribute */ + int8_t ea_namespace; /* name space of this attribute */ + int8_t ea_contentpadlen; /* bytes of padding at end of attribute */ + int8_t ea_namelength; /* length of attribute name */ + char ea_name[1]; /* null-terminated attribute name */ + /* extended attribute content follows */ +}; + +/* + * These macros are used to access and manipulate an extended attribute: + * + * EXTATTR_NEXT(eap) returns a pointer to the next extended attribute + * following eap. + * EXTATTR_CONTENT(eap) returns a pointer to the extended attribute + * content referenced by eap. + * EXTATTR_CONTENT_SIZE(eap) returns the size of the extended attribute + * content referenced by eap. + * EXTATTR_SET_LENGTHS(eap, contentsize) called after initializing the + * attribute name to calculate and set the ea_length, ea_namelength, + * and ea_contentpadlen fields of the extended attribute structure. + */ +#define EXTATTR_NEXT(eap) \ + ((struct extattr *)(((void *)(eap)) + (eap)->ea_length)) +#define EXTATTR_CONTENT(eap) (((void *)(eap)) + EXTATTR_BASE_LENGTH(eap)) +#define EXTATTR_CONTENT_SIZE(eap) \ + ((eap)->ea_length - EXTATTR_BASE_LENGTH(eap) - (eap)->ea_contentpadlen) +#define EXTATTR_BASE_LENGTH(eap) \ + ((sizeof(struct extattr) + (eap)->ea_namelength + 7) & ~7) +#define EXTATTR_SET_LENGTHS(eap, contentsize) do { \ + KASSERT(((eap)->ea_name[0] != 0), \ + ("Must initialize name before setting lengths")); \ + (eap)->ea_namelength = strlen((eap)->ea_name); \ + (eap)->ea_contentpadlen = ((contentsize) % 8) ? \ + 8 - ((contentsize) % 8) : 0; \ + (eap)->ea_length = EXTATTR_BASE_LENGTH(eap) + \ + (contentsize) + (eap)->ea_contentpadlen; \ +} while (0) + +#ifdef _KERNEL + +#include + +struct vnode; +LIST_HEAD(ufs_extattr_list_head, ufs_extattr_list_entry); +struct ufs_extattr_list_entry { + LIST_ENTRY(ufs_extattr_list_entry) uele_entries; + struct ufs_extattr_fileheader uele_fileheader; + int uele_attrnamespace; + char uele_attrname[UFS_EXTATTR_MAXEXTATTRNAME]; + struct vnode *uele_backing_vnode; +}; + +struct ucred; +struct ufs_extattr_per_mount { + struct sx uepm_lock; + struct ufs_extattr_list_head uepm_list; + struct ucred *uepm_ucred; + int uepm_flags; +}; + +struct vop_getextattr_args; +struct vop_deleteextattr_args; +struct vop_setextattr_args; + +void ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm); +void ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm); +int ufs_extattr_start(struct mount *mp, struct thread *td); +int ufs_extattr_autostart(struct mount *mp, struct thread *td); +int ufs_extattr_stop(struct mount *mp, struct thread *td); +int ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename, + int attrnamespace, const char *attrname); +int ufs_getextattr(struct vop_getextattr_args *ap); +int ufs_deleteextattr(struct vop_deleteextattr_args *ap); +int ufs_setextattr(struct vop_setextattr_args *ap); +void ufs_extattr_vnode_inactive(struct vnode *vp, struct thread *td); + +#else + +/* User-level definition of KASSERT for macros above */ +#define KASSERT(cond, str) do { \ + if (!(cond)) { printf("panic: "); printf(str); printf("\n"); exit(1); }\ +} while (0) + +#endif /* !_KERNEL */ + +#endif /* !_UFS_UFS_EXTATTR_H_ */ diff --git a/Dump/ufs/ufs/gjournal.h b/Dump/ufs/ufs/gjournal.h new file mode 100644 index 0000000..cd57fd8 --- /dev/null +++ b/Dump/ufs/ufs/gjournal.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2005-2006 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: releng/11.2/sys/ufs/ufs/gjournal.h 262678 2014-03-02 02:52:34Z pfg $ + */ + +#ifndef _UFS_UFS_GJOURNAL_H_ +#define _UFS_UFS_GJOURNAL_H_ + +/* + * GEOM journal function prototypes. + */ +void ufs_gjournal_orphan(struct vnode *fvp); +void ufs_gjournal_close(struct vnode *vp); +#endif /* !_UFS_UFS_GJOURNAL_H_ */ diff --git a/Dump/ufs/ufs/inode.h b/Dump/ufs/ufs/inode.h new file mode 100644 index 0000000..6c9bd06 --- /dev/null +++ b/Dump/ufs/ufs/inode.h @@ -0,0 +1,207 @@ +/*- + * Copyright (c) 1982, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)inode.h 8.9 (Berkeley) 5/14/95 + * $FreeBSD: releng/11.2/sys/ufs/ufs/inode.h 331722 2018-03-29 02:50:57Z eadler $ + */ + +#ifndef _UFS_UFS_INODE_H_ +#define _UFS_UFS_INODE_H_ + +#include +#include +#include + +/* + * This must agree with the definition in . + */ +#define doff_t int32_t + +/* + * The inode is used to describe each active (or recently active) file in the + * UFS filesystem. It is composed of two types of information. The first part + * is the information that is needed only while the file is active (such as + * the identity of the file and linkage to speed its lookup). The second part + * is the permanent meta-data associated with the file which is read in + * from the permanent dinode from long term storage when the file becomes + * active, and is put back when the file is no longer being used. + * + * An inode may only be changed while holding either the exclusive + * vnode lock or the shared vnode lock and the vnode interlock. We use + * the latter only for "read" and "get" operations that require + * changing i_flag, or a timestamp. This locking protocol allows executing + * those operations without having to upgrade the vnode lock from shared to + * exclusive. + */ +struct inode { + TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list. */ + struct vnode *i_vnode;/* Vnode associated with this inode. */ + struct ufsmount *i_ump;/* Ufsmount point associated with this inode. */ + struct dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */ + union { + struct dirhash *dirhash; /* Hashing for large directories. */ + daddr_t *snapblklist; /* Collect expunged snapshot blocks. */ + } i_un; + /* + * The real copy of the on-disk inode. + */ + union { + struct ufs1_dinode *din1; /* UFS1 on-disk dinode. */ + struct ufs2_dinode *din2; /* UFS2 on-disk dinode. */ + } dinode_u; + + ino_t i_number; /* The identity of the inode. */ + u_int32_t i_flag; /* flags, see below */ + int i_effnlink; /* i_nlink when I/O completes */ + + + /* + * Side effects; used during directory lookup. + */ + int32_t i_count; /* Size of free slot in directory. */ + doff_t i_endoff; /* End of useful stuff in directory. */ + doff_t i_diroff; /* Offset in dir, where we found last entry. */ + doff_t i_offset; /* Offset of free space in directory. */ + + int i_nextclustercg; /* last cg searched for cluster */ + + /* + * Data for extended attribute modification. + */ + u_char *i_ea_area; /* Pointer to malloced copy of EA area */ + unsigned i_ea_len; /* Length of i_ea_area */ + int i_ea_error; /* First errno in transaction */ + int i_ea_refs; /* Number of users of EA area */ + + /* + * Copies from the on-disk dinode itself. + */ + u_int64_t i_size; /* File byte count. */ + u_int64_t i_gen; /* Generation number. */ + u_int32_t i_flags; /* Status flags (chflags). */ + u_int32_t i_uid; /* File owner. */ + u_int32_t i_gid; /* File group. */ + u_int16_t i_mode; /* IFMT, permissions; see below. */ + int16_t i_nlink; /* File link count. */ +}; +/* + * These flags are kept in i_flag. + */ +#define IN_ACCESS 0x0001 /* Access time update request. */ +#define IN_CHANGE 0x0002 /* Inode change time update request. */ +#define IN_UPDATE 0x0004 /* Modification time update request. */ +#define IN_MODIFIED 0x0008 /* Inode has been modified. */ +#define IN_NEEDSYNC 0x0010 /* Inode requires fsync. */ +#define IN_LAZYMOD 0x0020 /* Modified, but don't write yet. */ +#define IN_LAZYACCESS 0x0040 /* Process IN_ACCESS after the + suspension finished */ +#define IN_EA_LOCKED 0x0080 +#define IN_EA_LOCKWAIT 0x0100 + +#define IN_TRUNCATED 0x0200 /* Journaled truncation pending. */ + +#define IN_UFS2 0x0400 /* UFS2 vs UFS1 */ + +#define i_dirhash i_un.dirhash +#define i_snapblklist i_un.snapblklist +#define i_din1 dinode_u.din1 +#define i_din2 dinode_u.din2 + +#ifdef _KERNEL + +#define ITOUMP(ip) ((ip)->i_ump) +#define ITODEV(ip) (ITOUMP(ip)->um_dev) +#define ITODEVVP(ip) (ITOUMP(ip)->um_devvp) +#define ITOFS(ip) (ITOUMP(ip)->um_fs) +#define ITOVFS(ip) ((ip)->i_vnode->v_mount) + +static inline _Bool +I_IS_UFS1(const struct inode *ip) +{ + + return ((ip->i_flag & IN_UFS2) == 0); +} + +static inline _Bool +I_IS_UFS2(const struct inode *ip) +{ + + return ((ip->i_flag & IN_UFS2) != 0); +} + +/* + * The DIP macro is used to access fields in the dinode that are + * not cached in the inode itself. + */ +#define DIP(ip, field) (I_IS_UFS1(ip) ? (ip)->i_din1->d##field : \ + (ip)->i_din2->d##field) +#define DIP_SET(ip, field, val) do { \ + if (I_IS_UFS1(ip)) \ + (ip)->i_din1->d##field = (val); \ + else \ + (ip)->i_din2->d##field = (val); \ + } while (0) + +#define SHORTLINK(ip) (I_IS_UFS1(ip) ? \ + (caddr_t)(ip)->i_din1->di_db : (caddr_t)(ip)->i_din2->di_db) +#define IS_SNAPSHOT(ip) ((ip)->i_flags & SF_SNAPSHOT) + +/* + * Structure used to pass around logical block paths generated by + * ufs_getlbns and used by truncate and bmap code. + */ +struct indir { + ufs2_daddr_t in_lbn; /* Logical block number. */ + int in_off; /* Offset in buffer. */ +}; + +/* Convert between inode pointers and vnode pointers. */ +#define VTOI(vp) ((struct inode *)(vp)->v_data) +#define ITOV(ip) ((ip)->i_vnode) + +/* Determine if soft dependencies are being done */ +#define DOINGSOFTDEP(vp) ((vp)->v_mount->mnt_flag & (MNT_SOFTDEP | MNT_SUJ)) +#define MOUNTEDSOFTDEP(mp) ((mp)->mnt_flag & (MNT_SOFTDEP | MNT_SUJ)) +#define DOINGSUJ(vp) ((vp)->v_mount->mnt_flag & MNT_SUJ) +#define MOUNTEDSUJ(mp) ((mp)->mnt_flag & MNT_SUJ) + +/* This overlays the fid structure (see mount.h). */ +struct ufid { + u_int16_t ufid_len; /* Length of structure. */ + u_int16_t ufid_pad; /* Force 32-bit alignment. */ + uint32_t ufid_ino; /* File number (ino). */ + uint32_t ufid_gen; /* Generation number. */ +}; +#endif /* _KERNEL */ + +#endif /* !_UFS_UFS_INODE_H_ */ diff --git a/Dump/ufs/ufs/quota.h b/Dump/ufs/ufs/quota.h new file mode 100644 index 0000000..71cbb70 --- /dev/null +++ b/Dump/ufs/ufs/quota.h @@ -0,0 +1,259 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)quota.h 8.3 (Berkeley) 8/19/94 + * $FreeBSD: releng/11.2/sys/ufs/ufs/quota.h 331722 2018-03-29 02:50:57Z eadler $ + */ + +#ifndef _UFS_UFS_QUOTA_H_ +#define _UFS_UFS_QUOTA_H_ + +/* + * Definitions for disk quotas imposed on the average user + * (big brother finally hits UNIX). + * + * The following constants define the amount of time given a user before the + * soft limits are treated as hard limits (usually resulting in an allocation + * failure). The timer is started when the user crosses their soft limit, it + * is reset when they go below their soft limit. + */ +#define MAX_IQ_TIME (7*24*60*60) /* seconds in 1 week */ +#define MAX_DQ_TIME (7*24*60*60) /* seconds in 1 week */ + +/* + * The following constants define the usage of the quota file array in the + * ufsmount structure and dquot array in the inode structure. The semantics + * of the elements of these arrays are defined in the routine getinoquota; + * the remainder of the quota code treats them generically and need not be + * inspected when changing the size of the array. + */ +#define MAXQUOTAS 2 +#define USRQUOTA 0 /* element used for user quotas */ +#define GRPQUOTA 1 /* element used for group quotas */ + +/* + * Definitions for the default names of the quotas files. + */ +#define INITQFNAMES { \ + "user", /* USRQUOTA */ \ + "group", /* GRPQUOTA */ \ + "undefined", \ +} +#define QUOTAFILENAME "quota" +#define QUOTAGROUP "operator" + +/* + * Command definitions for the 'quotactl' system call. The commands are + * broken into a main command defined below and a subcommand that is used + * to convey the type of quota that is being manipulated (see above). + */ +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) + +#define Q_QUOTAON 0x0100 /* enable quotas */ +#define Q_QUOTAOFF 0x0200 /* disable quotas */ +#define Q_GETQUOTA32 0x0300 /* get limits and usage (32-bit version) */ +#define Q_SETQUOTA32 0x0400 /* set limits and usage (32-bit version) */ +#define Q_SETUSE32 0x0500 /* set usage (32-bit version) */ +#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ +#define Q_GETQUOTA 0x0700 /* get limits and usage (64-bit version) */ +#define Q_SETQUOTA 0x0800 /* set limits and usage (64-bit version) */ +#define Q_SETUSE 0x0900 /* set usage (64-bit version) */ +#define Q_GETQUOTASIZE 0x0A00 /* get bit-size of quota file fields */ + +/* + * The following structure defines the format of the disk quota file + * (as it appears on disk) - the file is an array of these structures + * indexed by user or group number. The setquota system call establishes + * the vnode for each quota file (a pointer is retained in the ufsmount + * structure). + */ +struct dqblk32 { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes + 1 */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + int32_t dqb_btime; /* time limit for excessive disk use */ + int32_t dqb_itime; /* time limit for excessive files */ +}; + +struct dqblk64 { + u_int64_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int64_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int64_t dqb_curblocks; /* current block count */ + u_int64_t dqb_ihardlimit; /* maximum # allocated inodes + 1 */ + u_int64_t dqb_isoftlimit; /* preferred inode limit */ + u_int64_t dqb_curinodes; /* current # allocated inodes */ + int64_t dqb_btime; /* time limit for excessive disk use */ + int64_t dqb_itime; /* time limit for excessive files */ +}; + +#define dqblk dqblk64 + +#define Q_DQHDR64_MAGIC "QUOTA64" +#define Q_DQHDR64_VERSION 0x20081104 + +struct dqhdr64 { + char dqh_magic[8]; /* Q_DQHDR64_MAGIC */ + uint32_t dqh_version; /* Q_DQHDR64_VERSION */ + uint32_t dqh_hdrlen; /* header length */ + uint32_t dqh_reclen; /* record length */ + char dqh_unused[44]; /* reserved for future extension */ +}; + +#ifdef _KERNEL + +#include + +/* + * The following structure records disk usage for a user or group on a + * filesystem. There is one allocated for each quota that exists on any + * filesystem for the current user or group. A cache is kept of recently + * used entries. + * (h) protected by dqhlock + */ +struct dquot { + LIST_ENTRY(dquot) dq_hash; /* (h) hash list */ + TAILQ_ENTRY(dquot) dq_freelist; /* (h) free list */ + struct mtx dq_lock; /* lock for concurrency */ + u_int16_t dq_flags; /* flags, see below */ + u_int16_t dq_type; /* quota type of this dquot */ + u_int32_t dq_cnt; /* (h) count of active references */ + u_int32_t dq_id; /* identifier this applies to */ + struct ufsmount *dq_ump; /* (h) filesystem that this is + taken from */ + struct dqblk64 dq_dqb; /* actual usage & quotas */ +}; +/* + * Flag values. + */ +#define DQ_LOCK 0x01 /* this quota locked (no MODS) */ +#define DQ_WANT 0x02 /* wakeup on unlock */ +#define DQ_MOD 0x04 /* this quota modified since read */ +#define DQ_FAKE 0x08 /* no limits here, just usage */ +#define DQ_BLKS 0x10 /* has been warned about blk limit */ +#define DQ_INODS 0x20 /* has been warned about inode limit */ +/* + * Shorthand notation. + */ +#define dq_bhardlimit dq_dqb.dqb_bhardlimit +#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit +#define dq_curblocks dq_dqb.dqb_curblocks +#define dq_ihardlimit dq_dqb.dqb_ihardlimit +#define dq_isoftlimit dq_dqb.dqb_isoftlimit +#define dq_curinodes dq_dqb.dqb_curinodes +#define dq_btime dq_dqb.dqb_btime +#define dq_itime dq_dqb.dqb_itime + +/* + * If the system has never checked for a quota for this file, then it is + * set to NODQUOT. Once a write attempt is made the inode pointer is set + * to reference a dquot structure. + */ +#define NODQUOT NULL + +/* + * Flags to chkdq() and chkiq() + */ +#define FORCE 0x01 /* force usage changes independent of limits */ +#define CHOWN 0x02 /* (advisory) change initiated by chown */ + +/* + * Macros to avoid subroutine calls to trivial functions. + */ +#ifdef DIAGNOSTIC +#define DQREF(dq) dqref(dq) +#else +#define DQREF(dq) (dq)->dq_cnt++ +#endif + +#define DQI_LOCK(dq) mtx_lock(&(dq)->dq_lock) +#define DQI_UNLOCK(dq) mtx_unlock(&(dq)->dq_lock) + +#define DQI_WAIT(dq, prio, msg) do { \ + while ((dq)->dq_flags & DQ_LOCK) { \ + (dq)->dq_flags |= DQ_WANT; \ + (void) msleep((dq), \ + &(dq)->dq_lock, (prio), (msg), 0); \ + } \ +} while (0) + +#define DQI_WAKEUP(dq) do { \ + if ((dq)->dq_flags & DQ_WANT) \ + wakeup((dq)); \ + (dq)->dq_flags &= ~(DQ_WANT|DQ_LOCK); \ +} while (0) + +struct inode; +struct mount; +struct thread; +struct ucred; +struct vnode; + +int chkdq(struct inode *, int64_t, struct ucred *, int); +int chkiq(struct inode *, int, struct ucred *, int); +void dqinit(void); +void dqrele(struct vnode *, struct dquot *); +void dquninit(void); +int getinoquota(struct inode *); +int qsync(struct mount *); +int qsyncvp(struct vnode *); +int quotaoff(struct thread *, struct mount *, int); +int quotaon(struct thread *, struct mount *, int, void *); +int getquota32(struct thread *, struct mount *, u_long, int, void *); +int setquota32(struct thread *, struct mount *, u_long, int, void *); +int setuse32(struct thread *, struct mount *, u_long, int, void *); +int getquota(struct thread *, struct mount *, u_long, int, void *); +int setquota(struct thread *, struct mount *, u_long, int, void *); +int setuse(struct thread *, struct mount *, u_long, int, void *); +int getquotasize(struct thread *, struct mount *, u_long, int, void *); +vfs_quotactl_t ufs_quotactl; + +#ifdef SOFTUPDATES +int quotaref(struct vnode *, struct dquot **); +void quotarele(struct dquot **); +void quotaadj(struct dquot **, struct ufsmount *, int64_t); +#endif /* SOFTUPDATES */ + +#else /* !_KERNEL */ + +#include + +__BEGIN_DECLS +int quotactl(const char *, int, int, void *); +__END_DECLS + +#endif /* _KERNEL */ + +#endif /* !_UFS_UFS_QUOTA_H_ */ diff --git a/Dump/ufs/ufs/ufs_acl.c b/Dump/ufs/ufs/ufs_acl.c new file mode 100644 index 0000000..5c7b11a --- /dev/null +++ b/Dump/ufs/ufs/ufs_acl.c @@ -0,0 +1,698 @@ +/*- + * Copyright (c) 1999-2003 Robert N. M. Watson + * All rights reserved. + * + * This software was developed by Robert Watson for the TrustedBSD Project. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Support for POSIX.1e access control lists: UFS-specific support functions. + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_acl.c 306553 2016-10-01 09:19:43Z kib $"); + +#include "opt_ufs.h" +#include "opt_quota.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef UFS_ACL + +FEATURE(ufs_acl, "ACL support for UFS"); + +/* + * Synchronize an ACL and an inode by copying over appropriate inode fields + * to the passed ACL. Assumes an ACL that would satisfy acl_posix1e_check(), + * and may panic if not. + */ +void +ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl) +{ + struct acl_entry *acl_mask, *acl_group_obj; + int i; + + /* + * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK + * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is + * present. + */ + acl_mask = NULL; + acl_group_obj = NULL; + for (i = 0; i < acl->acl_cnt; i++) { + switch (acl->acl_entry[i].ae_tag) { + case ACL_USER_OBJ: + acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( + ACL_USER_OBJ, ip->i_mode); + acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; + break; + + case ACL_GROUP_OBJ: + acl_group_obj = &acl->acl_entry[i]; + acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; + break; + + case ACL_OTHER: + acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm( + ACL_OTHER, ip->i_mode); + acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; + break; + + case ACL_MASK: + acl_mask = &acl->acl_entry[i]; + acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID; + break; + + case ACL_USER: + case ACL_GROUP: + break; + + default: + panic("ufs_sync_acl_from_inode(): bad ae_tag"); + } + } + + if (acl_group_obj == NULL) + panic("ufs_sync_acl_from_inode(): no ACL_GROUP_OBJ"); + + if (acl_mask == NULL) { + /* + * There is no ACL_MASK, so update ACL_GROUP_OBJ. + */ + acl_group_obj->ae_perm = acl_posix1e_mode_to_perm( + ACL_GROUP_OBJ, ip->i_mode); + } else { + /* + * Update the ACL_MASK entry instead of ACL_GROUP_OBJ. + */ + acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ, + ip->i_mode); + } +} + +/* + * Calculate what the inode mode should look like based on an authoritative + * ACL for the inode. Replace only the fields in the inode that the ACL + * can represent. + */ +void +ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip) +{ + + ip->i_mode &= ACL_PRESERVE_MASK; + ip->i_mode |= acl_posix1e_acl_to_mode(acl); + DIP_SET(ip, i_mode, ip->i_mode); +} + +/* + * Retrieve NFSv4 ACL, skipping access checks. Must be used in UFS code + * instead of VOP_GETACL() when we don't want to be restricted by the user + * not having ACL_READ_ACL permission, e.g. when calculating inherited ACL + * or in ufs_vnops.c:ufs_accessx(). + */ +int +ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) +{ + int error, len; + struct inode *ip = VTOI(vp); + + len = sizeof(*aclp); + bzero(aclp, len); + + error = vn_extattr_get(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, + &len, (char *) aclp, td); + aclp->acl_maxcnt = ACL_MAX_ENTRIES; + if (error == ENOATTR) { + /* + * Legitimately no ACL set on object, purely + * emulate it through the inode. + */ + acl_nfs4_sync_acl_from_mode(aclp, ip->i_mode, ip->i_uid); + + return (0); + } + + if (error) + return (error); + + if (len != sizeof(*aclp)) { + /* + * A short (or long) read, meaning that for + * some reason the ACL is corrupted. Return + * EPERM since the object DAC protections + * are unsafe. + */ + printf("ufs_getacl_nfs4(): Loaded invalid ACL (" + "%d bytes), inumber %ju on %s\n", len, + (uintmax_t)ip->i_number, ITOFS(ip)->fs_fsmnt); + + return (EPERM); + } + + error = acl_nfs4_check(aclp, vp->v_type == VDIR); + if (error) { + printf("ufs_getacl_nfs4(): Loaded invalid ACL " + "(failed acl_nfs4_check), inumber %ju on %s\n", + (uintmax_t)ip->i_number, ITOFS(ip)->fs_fsmnt); + + return (EPERM); + } + + return (0); +} + +static int +ufs_getacl_nfs4(struct vop_getacl_args *ap) +{ + int error; + + if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) + return (EINVAL); + + error = VOP_ACCESSX(ap->a_vp, VREAD_ACL, ap->a_td->td_ucred, ap->a_td); + if (error) + return (error); + + error = ufs_getacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td); + + return (error); +} + +/* + * Read POSIX.1e ACL from an EA. Return error if its not found + * or if any other error has occurred. + */ +static int +ufs_get_oldacl(acl_type_t type, struct oldacl *old, struct vnode *vp, + struct thread *td) +{ + int error, len; + struct inode *ip = VTOI(vp); + + len = sizeof(*old); + + switch (type) { + case ACL_TYPE_ACCESS: + error = vn_extattr_get(vp, IO_NODELOCKED, + POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, + POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) old, + td); + break; + case ACL_TYPE_DEFAULT: + if (vp->v_type != VDIR) + return (EINVAL); + error = vn_extattr_get(vp, IO_NODELOCKED, + POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, + POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len, (char *) old, + td); + break; + default: + return (EINVAL); + } + + if (error != 0) + return (error); + + if (len != sizeof(*old)) { + /* + * A short (or long) read, meaning that for some reason + * the ACL is corrupted. Return EPERM since the object + * DAC protections are unsafe. + */ + printf("ufs_get_oldacl(): Loaded invalid ACL " + "(len = %d), inumber %ju on %s\n", len, + (uintmax_t)ip->i_number, ITOFS(ip)->fs_fsmnt); + return (EPERM); + } + + return (0); +} + +/* + * Retrieve the ACL on a file. + * + * As part of the ACL is stored in the inode, and the rest in an EA, + * assemble both into a final ACL product. Right now this is not done + * very efficiently. + */ +static int +ufs_getacl_posix1e(struct vop_getacl_args *ap) +{ + struct inode *ip = VTOI(ap->a_vp); + int error; + struct oldacl *old; + + /* + * XXX: If ufs_getacl() should work on file systems not supporting + * ACLs, remove this check. + */ + if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) + return (EINVAL); + + old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); + + /* + * Attempt to retrieve the ACL from the extended attributes. + */ + error = ufs_get_oldacl(ap->a_type, old, ap->a_vp, ap->a_td); + switch (error) { + /* + * XXX: If ufs_getacl() should work on filesystems + * without the EA configured, add case EOPNOTSUPP here. + */ + case ENOATTR: + switch (ap->a_type) { + case ACL_TYPE_ACCESS: + /* + * Legitimately no ACL set on object, purely + * emulate it through the inode. These fields will + * be updated when the ACL is synchronized with + * the inode later. + */ + old->acl_cnt = 3; + old->acl_entry[0].ae_tag = ACL_USER_OBJ; + old->acl_entry[0].ae_id = ACL_UNDEFINED_ID; + old->acl_entry[0].ae_perm = ACL_PERM_NONE; + old->acl_entry[1].ae_tag = ACL_GROUP_OBJ; + old->acl_entry[1].ae_id = ACL_UNDEFINED_ID; + old->acl_entry[1].ae_perm = ACL_PERM_NONE; + old->acl_entry[2].ae_tag = ACL_OTHER; + old->acl_entry[2].ae_id = ACL_UNDEFINED_ID; + old->acl_entry[2].ae_perm = ACL_PERM_NONE; + break; + + case ACL_TYPE_DEFAULT: + /* + * Unlike ACL_TYPE_ACCESS, there is no relationship + * between the inode contents and the ACL, and it is + * therefore possible for the request for the ACL + * to fail since the ACL is undefined. In this + * situation, return success and an empty ACL, + * as required by POSIX.1e. + */ + old->acl_cnt = 0; + break; + } + /* FALLTHROUGH */ + case 0: + error = acl_copy_oldacl_into_acl(old, ap->a_aclp); + if (error != 0) + break; + + if (ap->a_type == ACL_TYPE_ACCESS) + ufs_sync_acl_from_inode(ip, ap->a_aclp); + default: + break; + } + + free(old, M_ACL); + return (error); +} + +int +ufs_getacl(ap) + struct vop_getacl_args /* { + struct vnode *vp; + acl_type_t type; + struct acl *aclp; + struct ucred *cred; + struct thread *td; + } */ *ap; +{ + + if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) + return (EOPNOTSUPP); + + if (ap->a_type == ACL_TYPE_NFS4) + return (ufs_getacl_nfs4(ap)); + + return (ufs_getacl_posix1e(ap)); +} + +/* + * Set NFSv4 ACL without doing any access checking. This is required + * e.g. by the UFS code that implements ACL inheritance, or from + * ufs_vnops.c:ufs_chmod(), as some of the checks have to be skipped + * in that case, and others are redundant. + */ +int +ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td) +{ + int error; + mode_t mode; + struct inode *ip = VTOI(vp); + + KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0, + ("invalid ACL passed to ufs_setacl_nfs4_internal")); + + if (acl_nfs4_is_trivial(aclp, ip->i_uid)) { + error = vn_extattr_rm(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, td); + + /* + * An attempt to remove ACL from a file that didn't have + * any extended entries is not an error. + */ + if (error == ENOATTR) + error = 0; + + } else { + error = vn_extattr_set(vp, IO_NODELOCKED, + NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, + sizeof(*aclp), (char *) aclp, td); + } + + /* + * Map lack of attribute definition in UFS_EXTATTR into lack of + * support for ACLs on the filesystem. + */ + if (error == ENOATTR) + return (EOPNOTSUPP); + + if (error) + return (error); + + mode = ip->i_mode; + + acl_nfs4_sync_mode_from_acl(&mode, aclp); + + ip->i_mode &= ACL_PRESERVE_MASK; + ip->i_mode |= mode; + DIP_SET(ip, i_mode, ip->i_mode); + ip->i_flag |= IN_CHANGE; + + VN_KNOTE_UNLOCKED(vp, NOTE_ATTRIB); + + error = UFS_UPDATE(vp, 0); + return (error); +} + +static int +ufs_setacl_nfs4(struct vop_setacl_args *ap) +{ + int error; + struct inode *ip = VTOI(ap->a_vp); + + if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) + return (EINVAL); + + if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + + if (ap->a_aclp == NULL) + return (EINVAL); + + error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred, + ap->a_td); + if (error) + return (error); + + /* + * Authorize the ACL operation. + */ + if (ip->i_flags & (IMMUTABLE | APPEND)) + return (EPERM); + + /* + * Must hold VWRITE_ACL or have appropriate privilege. + */ + if ((error = VOP_ACCESSX(ap->a_vp, VWRITE_ACL, ap->a_cred, ap->a_td))) + return (error); + + /* + * With NFSv4 ACLs, chmod(2) may need to add additional entries. + * Make sure it has enough room for that - splitting every entry + * into two and appending "canonical six" entries at the end. + */ + if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) + return (ENOSPC); + + error = ufs_setacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td); + + return (error); +} + +/* + * Set the ACL on a file. + * + * As part of the ACL is stored in the inode, and the rest in an EA, + * this is necessarily non-atomic, and has complex authorization. + * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(), + * a fair number of different access checks may be required to go ahead + * with the operation at all. + */ +static int +ufs_setacl_posix1e(struct vop_setacl_args *ap) +{ + struct inode *ip = VTOI(ap->a_vp); + int error; + struct oldacl *old; + + if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) + return (EINVAL); + + /* + * If this is a set operation rather than a delete operation, + * invoke VOP_ACLCHECK() on the passed ACL to determine if it is + * valid for the target. This will include a check on ap->a_type. + */ + if (ap->a_aclp != NULL) { + /* + * Set operation. + */ + error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, + ap->a_cred, ap->a_td); + if (error != 0) + return (error); + } else { + /* + * Delete operation. + * POSIX.1e allows only deletion of the default ACL on a + * directory (ACL_TYPE_DEFAULT). + */ + if (ap->a_type != ACL_TYPE_DEFAULT) + return (EINVAL); + if (ap->a_vp->v_type != VDIR) + return (ENOTDIR); + } + + if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + + /* + * Authorize the ACL operation. + */ + if (ip->i_flags & (IMMUTABLE | APPEND)) + return (EPERM); + + /* + * Must hold VADMIN (be file owner) or have appropriate privilege. + */ + if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td))) + return (error); + + switch(ap->a_type) { + case ACL_TYPE_ACCESS: + old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); + error = acl_copy_acl_into_oldacl(ap->a_aclp, old); + if (error == 0) { + error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, + POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, + POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*old), + (char *) old, ap->a_td); + } + free(old, M_ACL); + break; + + case ACL_TYPE_DEFAULT: + if (ap->a_aclp == NULL) { + error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED, + POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, + POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td); + /* + * Attempting to delete a non-present default ACL + * will return success for portability purposes. + * (TRIX) + * + * XXX: Note that since we can't distinguish + * "that EA is not supported" from "that EA is not + * defined", the success case here overlaps the + * the ENOATTR->EOPNOTSUPP case below. + */ + if (error == ENOATTR) + error = 0; + } else { + old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); + error = acl_copy_acl_into_oldacl(ap->a_aclp, old); + if (error == 0) { + error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, + POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, + POSIX1E_ACL_DEFAULT_EXTATTR_NAME, + sizeof(*old), (char *) old, ap->a_td); + } + free(old, M_ACL); + } + break; + + default: + error = EINVAL; + } + /* + * Map lack of attribute definition in UFS_EXTATTR into lack of + * support for ACLs on the filesystem. + */ + if (error == ENOATTR) + return (EOPNOTSUPP); + if (error != 0) + return (error); + + if (ap->a_type == ACL_TYPE_ACCESS) { + /* + * Now that the EA is successfully updated, update the + * inode and mark it as changed. + */ + ufs_sync_inode_from_acl(ap->a_aclp, ip); + ip->i_flag |= IN_CHANGE; + error = UFS_UPDATE(ap->a_vp, 0); + } + + VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB); + return (error); +} + +int +ufs_setacl(ap) + struct vop_setacl_args /* { + struct vnode *vp; + acl_type_t type; + struct acl *aclp; + struct ucred *cred; + struct thread *td; + } */ *ap; +{ + if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) + return (EOPNOTSUPP); + + if (ap->a_type == ACL_TYPE_NFS4) + return (ufs_setacl_nfs4(ap)); + + return (ufs_setacl_posix1e(ap)); +} + +static int +ufs_aclcheck_nfs4(struct vop_aclcheck_args *ap) +{ + int is_directory = 0; + + if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0) + return (EINVAL); + + /* + * With NFSv4 ACLs, chmod(2) may need to add additional entries. + * Make sure it has enough room for that - splitting every entry + * into two and appending "canonical six" entries at the end. + */ + if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2) + return (ENOSPC); + + if (ap->a_vp->v_type == VDIR) + is_directory = 1; + + return (acl_nfs4_check(ap->a_aclp, is_directory)); +} + +static int +ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap) +{ + + if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) + return (EINVAL); + + /* + * Verify we understand this type of ACL, and that it applies + * to this kind of object. + * Rely on the acl_posix1e_check() routine to verify the contents. + */ + switch(ap->a_type) { + case ACL_TYPE_ACCESS: + break; + + case ACL_TYPE_DEFAULT: + if (ap->a_vp->v_type != VDIR) + return (EINVAL); + break; + + default: + return (EINVAL); + } + + if (ap->a_aclp->acl_cnt > OLDACL_MAX_ENTRIES) + return (EINVAL); + + return (acl_posix1e_check(ap->a_aclp)); +} + +/* + * Check the validity of an ACL for a file. + */ +int +ufs_aclcheck(ap) + struct vop_aclcheck_args /* { + struct vnode *vp; + acl_type_t type; + struct acl *aclp; + struct ucred *cred; + struct thread *td; + } */ *ap; +{ + + if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0) + return (EOPNOTSUPP); + + if (ap->a_type == ACL_TYPE_NFS4) + return (ufs_aclcheck_nfs4(ap)); + + return (ufs_aclcheck_posix1e(ap)); +} + +#endif /* !UFS_ACL */ diff --git a/Dump/ufs/ufs/ufs_bmap.c b/Dump/ufs/ufs/ufs_bmap.c new file mode 100644 index 0000000..501529d --- /dev/null +++ b/Dump/ufs/ufs/ufs_bmap.c @@ -0,0 +1,384 @@ +/*- + * Copyright (c) 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_bmap.c 8.7 (Berkeley) 3/21/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_bmap.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Bmap converts the logical block number of a file to its physical block + * number on the disk. The conversion is done by using the logical block + * number to index into the array of block pointers described by the dinode. + */ +int +ufs_bmap(ap) + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct bufobj **a_bop; + daddr_t *a_bnp; + int *a_runp; + int *a_runb; + } */ *ap; +{ + ufs2_daddr_t blkno; + int error; + + /* + * Check for underlying vnode requests and ensure that logical + * to physical mapping is requested. + */ + if (ap->a_bop != NULL) + *ap->a_bop = &VFSTOUFS(ap->a_vp->v_mount)->um_devvp->v_bufobj; + if (ap->a_bnp == NULL) + return (0); + + error = ufs_bmaparray(ap->a_vp, ap->a_bn, &blkno, NULL, + ap->a_runp, ap->a_runb); + *ap->a_bnp = blkno; + return (error); +} + +/* + * Indirect blocks are now on the vnode for the file. They are given negative + * logical block numbers. Indirect blocks are addressed by the negative + * address of the first data block to which they point. Double indirect blocks + * are addressed by one less than the address of the first indirect block to + * which they point. Triple indirect blocks are addressed by one less than + * the address of the first double indirect block to which they point. + * + * ufs_bmaparray does the bmap conversion, and if requested returns the + * array of logical blocks which must be traversed to get to a block. + * Each entry contains the offset into that block that gets you to the + * next block and the disk address of the block (if it is assigned). + */ + +int +ufs_bmaparray(vp, bn, bnp, nbp, runp, runb) + struct vnode *vp; + ufs2_daddr_t bn; + ufs2_daddr_t *bnp; + struct buf *nbp; + int *runp; + int *runb; +{ + struct inode *ip; + struct buf *bp; + struct ufsmount *ump; + struct mount *mp; + struct indir a[NIADDR+1], *ap; + ufs2_daddr_t daddr; + ufs_lbn_t metalbn; + int error, num, maxrun = 0; + int *nump; + + ap = NULL; + ip = VTOI(vp); + mp = vp->v_mount; + ump = VFSTOUFS(mp); + + if (runp) { + maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1; + *runp = 0; + } + + if (runb) { + *runb = 0; + } + + + ap = a; + nump = # + error = ufs_getlbns(vp, bn, ap, nump); + if (error) + return (error); + + num = *nump; + if (num == 0) { + if (bn >= 0 && bn < NDADDR) { + *bnp = blkptrtodb(ump, DIP(ip, i_db[bn])); + } else if (bn < 0 && bn >= -NXADDR) { + *bnp = blkptrtodb(ump, ip->i_din2->di_extb[-1 - bn]); + if (*bnp == 0) + *bnp = -1; + if (nbp == NULL) + panic("ufs_bmaparray: mapping ext data"); + nbp->b_xflags |= BX_ALTDATA; + return (0); + } else { + panic("ufs_bmaparray: blkno out of range"); + } + /* + * Since this is FFS independent code, we are out of + * scope for the definitions of BLK_NOCOPY and + * BLK_SNAP, but we do know that they will fall in + * the range 1..um_seqinc, so we use that test and + * return a request for a zeroed out buffer if attempts + * are made to read a BLK_NOCOPY or BLK_SNAP block. + */ + if ((ip->i_flags & SF_SNAPSHOT) && DIP(ip, i_db[bn]) > 0 && + DIP(ip, i_db[bn]) < ump->um_seqinc) { + *bnp = -1; + } else if (*bnp == 0) { + if (ip->i_flags & SF_SNAPSHOT) + *bnp = blkptrtodb(ump, bn * ump->um_seqinc); + else + *bnp = -1; + } else if (runp) { + ufs2_daddr_t bnb = bn; + for (++bn; bn < NDADDR && *runp < maxrun && + is_sequential(ump, DIP(ip, i_db[bn - 1]), + DIP(ip, i_db[bn])); + ++bn, ++*runp); + bn = bnb; + if (runb && (bn > 0)) { + for (--bn; (bn >= 0) && (*runb < maxrun) && + is_sequential(ump, DIP(ip, i_db[bn]), + DIP(ip, i_db[bn+1])); + --bn, ++*runb); + } + } + return (0); + } + + + /* Get disk address out of indirect block array */ + daddr = DIP(ip, i_ib[ap->in_off]); + + for (bp = NULL, ++ap; --num; ++ap) { + /* + * Exit the loop if there is no disk address assigned yet and + * the indirect block isn't in the cache, or if we were + * looking for an indirect block and we've found it. + */ + + metalbn = ap->in_lbn; + if ((daddr == 0 && !incore(&vp->v_bufobj, metalbn)) || metalbn == bn) + break; + /* + * If we get here, we've either got the block in the cache + * or we have a disk address for it, go fetch it. + */ + if (bp) + bqrelse(bp); + + bp = getblk(vp, metalbn, mp->mnt_stat.f_iosize, 0, 0, 0); + if ((bp->b_flags & B_CACHE) == 0) { +#ifdef INVARIANTS + if (!daddr) + panic("ufs_bmaparray: indirect block not in cache"); +#endif + bp->b_blkno = blkptrtodb(ump, daddr); + bp->b_iocmd = BIO_READ; + bp->b_flags &= ~B_INVAL; + bp->b_ioflags &= ~BIO_ERROR; + vfs_busy_pages(bp, 0); + bp->b_iooffset = dbtob(bp->b_blkno); + bstrategy(bp); +#ifdef RACCT + if (racct_enable) { + PROC_LOCK(curproc); + racct_add_buf(curproc, bp, 0); + PROC_UNLOCK(curproc); + } +#endif /* RACCT */ + curthread->td_ru.ru_inblock++; + error = bufwait(bp); + if (error) { + brelse(bp); + return (error); + } + } + + if (I_IS_UFS1(ip)) { + daddr = ((ufs1_daddr_t *)bp->b_data)[ap->in_off]; + if (num == 1 && daddr && runp) { + for (bn = ap->in_off + 1; + bn < MNINDIR(ump) && *runp < maxrun && + is_sequential(ump, + ((ufs1_daddr_t *)bp->b_data)[bn - 1], + ((ufs1_daddr_t *)bp->b_data)[bn]); + ++bn, ++*runp); + bn = ap->in_off; + if (runb && bn) { + for (--bn; bn >= 0 && *runb < maxrun && + is_sequential(ump, + ((ufs1_daddr_t *)bp->b_data)[bn], + ((ufs1_daddr_t *)bp->b_data)[bn+1]); + --bn, ++*runb); + } + } + continue; + } + daddr = ((ufs2_daddr_t *)bp->b_data)[ap->in_off]; + if (num == 1 && daddr && runp) { + for (bn = ap->in_off + 1; + bn < MNINDIR(ump) && *runp < maxrun && + is_sequential(ump, + ((ufs2_daddr_t *)bp->b_data)[bn - 1], + ((ufs2_daddr_t *)bp->b_data)[bn]); + ++bn, ++*runp); + bn = ap->in_off; + if (runb && bn) { + for (--bn; bn >= 0 && *runb < maxrun && + is_sequential(ump, + ((ufs2_daddr_t *)bp->b_data)[bn], + ((ufs2_daddr_t *)bp->b_data)[bn + 1]); + --bn, ++*runb); + } + } + } + if (bp) + bqrelse(bp); + + /* + * Since this is FFS independent code, we are out of scope for the + * definitions of BLK_NOCOPY and BLK_SNAP, but we do know that they + * will fall in the range 1..um_seqinc, so we use that test and + * return a request for a zeroed out buffer if attempts are made + * to read a BLK_NOCOPY or BLK_SNAP block. + */ + if ((ip->i_flags & SF_SNAPSHOT) && daddr > 0 && daddr < ump->um_seqinc){ + *bnp = -1; + return (0); + } + *bnp = blkptrtodb(ump, daddr); + if (*bnp == 0) { + if (ip->i_flags & SF_SNAPSHOT) + *bnp = blkptrtodb(ump, bn * ump->um_seqinc); + else + *bnp = -1; + } + return (0); +} + +/* + * Create an array of logical block number/offset pairs which represent the + * path of indirect blocks required to access a data block. The first "pair" + * contains the logical block number of the appropriate single, double or + * triple indirect block and the offset into the inode indirect block array. + * Note, the logical block number of the inode single/double/triple indirect + * block appears twice in the array, once with the offset into the i_ib and + * once with the offset into the page itself. + */ +int +ufs_getlbns(vp, bn, ap, nump) + struct vnode *vp; + ufs2_daddr_t bn; + struct indir *ap; + int *nump; +{ + ufs2_daddr_t blockcnt; + ufs_lbn_t metalbn, realbn; + struct ufsmount *ump; + int i, numlevels, off; + + ump = VFSTOUFS(vp->v_mount); + if (nump) + *nump = 0; + numlevels = 0; + realbn = bn; + if (bn < 0) + bn = -bn; + + /* The first NDADDR blocks are direct blocks. */ + if (bn < NDADDR) + return (0); + + /* + * Determine the number of levels of indirection. After this loop + * is done, blockcnt indicates the number of data blocks possible + * at the previous level of indirection, and NIADDR - i is the number + * of levels of indirection needed to locate the requested block. + */ + for (blockcnt = 1, i = NIADDR, bn -= NDADDR;; i--, bn -= blockcnt) { + if (i == 0) + return (EFBIG); + blockcnt *= MNINDIR(ump); + if (bn < blockcnt) + break; + } + + /* Calculate the address of the first meta-block. */ + if (realbn >= 0) + metalbn = -(realbn - bn + NIADDR - i); + else + metalbn = -(-realbn - bn + NIADDR - i); + + /* + * At each iteration, off is the offset into the bap array which is + * an array of disk addresses at the current level of indirection. + * The logical block number and the offset in that block are stored + * into the argument array. + */ + ap->in_lbn = metalbn; + ap->in_off = off = NIADDR - i; + ap++; + for (++numlevels; i <= NIADDR; i++) { + /* If searching for a meta-data block, quit when found. */ + if (metalbn == realbn) + break; + + blockcnt /= MNINDIR(ump); + off = (bn / blockcnt) % MNINDIR(ump); + + ++numlevels; + ap->in_lbn = metalbn; + ap->in_off = off; + ++ap; + + metalbn -= -1 + off * blockcnt; + } + if (nump) + *nump = numlevels; + return (0); +} diff --git a/Dump/ufs/ufs/ufs_dirhash.c b/Dump/ufs/ufs/ufs_dirhash.c new file mode 100644 index 0000000..18f7cc9 --- /dev/null +++ b/Dump/ufs/ufs/ufs_dirhash.c @@ -0,0 +1,1324 @@ +/*- + * Copyright (c) 2001, 2002 Ian Dowse. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This implements a hash-based lookup scheme for UFS directories. + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_dirhash.c 326845 2017-12-14 11:41:12Z kib $"); + +#include "opt_ufs.h" + +#ifdef UFS_DIRHASH + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define WRAPINCR(val, limit) (((val) + 1 == (limit)) ? 0 : ((val) + 1)) +#define WRAPDECR(val, limit) (((val) == 0) ? ((limit) - 1) : ((val) - 1)) +#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0) +#define BLKFREE2IDX(n) ((n) > DH_NFSTATS ? DH_NFSTATS : (n)) + +static MALLOC_DEFINE(M_DIRHASH, "ufs_dirhash", "UFS directory hash tables"); + +static int ufs_mindirhashsize = DIRBLKSIZ * 5; +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_minsize, CTLFLAG_RW, + &ufs_mindirhashsize, + 0, "minimum directory size in bytes for which to use hashed lookup"); +static int ufs_dirhashmaxmem = 2 * 1024 * 1024; /* NOTE: initial value. It is + tuned in ufsdirhash_init() */ +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_maxmem, CTLFLAG_RW, &ufs_dirhashmaxmem, + 0, "maximum allowed dirhash memory usage"); +static int ufs_dirhashmem; +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_mem, CTLFLAG_RD, &ufs_dirhashmem, + 0, "current dirhash memory usage"); +static int ufs_dirhashcheck = 0; +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_docheck, CTLFLAG_RW, &ufs_dirhashcheck, + 0, "enable extra sanity tests"); +static int ufs_dirhashlowmemcount = 0; +SYSCTL_INT(_vfs_ufs, OID_AUTO, dirhash_lowmemcount, CTLFLAG_RD, + &ufs_dirhashlowmemcount, 0, "number of times low memory hook called"); +static int ufs_dirhashreclaimpercent = 10; +static int ufsdirhash_set_reclaimpercent(SYSCTL_HANDLER_ARGS); +SYSCTL_PROC(_vfs_ufs, OID_AUTO, dirhash_reclaimpercent, + CTLTYPE_INT | CTLFLAG_RW, 0, 0, ufsdirhash_set_reclaimpercent, "I", + "set percentage of dirhash cache to be removed in low VM events"); + + +static int ufsdirhash_hash(struct dirhash *dh, char *name, int namelen); +static void ufsdirhash_adjfree(struct dirhash *dh, doff_t offset, int diff); +static void ufsdirhash_delslot(struct dirhash *dh, int slot); +static int ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen, + doff_t offset); +static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset); +static int ufsdirhash_recycle(int wanted); +static void ufsdirhash_lowmem(void); +static void ufsdirhash_free_locked(struct inode *ip); + +static uma_zone_t ufsdirhash_zone; + +#define DIRHASHLIST_LOCK() mtx_lock(&ufsdirhash_mtx) +#define DIRHASHLIST_UNLOCK() mtx_unlock(&ufsdirhash_mtx) +#define DIRHASH_BLKALLOC_WAITOK() uma_zalloc(ufsdirhash_zone, M_WAITOK) +#define DIRHASH_BLKFREE(ptr) uma_zfree(ufsdirhash_zone, (ptr)) +#define DIRHASH_ASSERT_LOCKED(dh) \ + sx_assert(&(dh)->dh_lock, SA_LOCKED) + +/* Dirhash list; recently-used entries are near the tail. */ +static TAILQ_HEAD(, dirhash) ufsdirhash_list; + +/* Protects: ufsdirhash_list, `dh_list' field, ufs_dirhashmem. */ +static struct mtx ufsdirhash_mtx; + +/* + * Locking: + * + * The relationship between inode and dirhash is protected either by an + * exclusive vnode lock or the vnode interlock where a shared vnode lock + * may be used. The dirhash_mtx is acquired after the dirhash lock. To + * handle teardown races, code wishing to lock the dirhash for an inode + * when using a shared vnode lock must obtain a private reference on the + * dirhash while holding the vnode interlock. They can drop it once they + * have obtained the dirhash lock and verified that the dirhash wasn't + * recycled while they waited for the dirhash lock. + * + * ufsdirhash_build() acquires a shared lock on the dirhash when it is + * successful. This lock is released after a call to ufsdirhash_lookup(). + * + * Functions requiring exclusive access use ufsdirhash_acquire() which may + * free a dirhash structure that was recycled by ufsdirhash_recycle(). + * + * The dirhash lock may be held across io operations. + * + * WITNESS reports a lock order reversal between the "bufwait" lock + * and the "dirhash" lock. However, this specific reversal will not + * cause a deadlock. To get a deadlock, one would have to lock a + * buffer followed by the dirhash while a second thread locked a + * buffer while holding the dirhash lock. The second order can happen + * under a shared or exclusive vnode lock for the associated directory + * in lookup(). The first order, however, can only happen under an + * exclusive vnode lock (e.g. unlink(), rename(), etc.). Thus, for + * a thread to be doing a "bufwait" -> "dirhash" order, it has to hold + * an exclusive vnode lock. That exclusive vnode lock will prevent + * any other threads from doing a "dirhash" -> "bufwait" order. + */ + +static void +ufsdirhash_hold(struct dirhash *dh) +{ + + refcount_acquire(&dh->dh_refcount); +} + +static void +ufsdirhash_drop(struct dirhash *dh) +{ + + if (refcount_release(&dh->dh_refcount)) { + sx_destroy(&dh->dh_lock); + free(dh, M_DIRHASH); + } +} + +/* + * Release the lock on a dirhash. + */ +static void +ufsdirhash_release(struct dirhash *dh) +{ + + sx_unlock(&dh->dh_lock); +} + +/* + * Either acquire an existing hash locked shared or create a new hash and + * return it exclusively locked. May return NULL if the allocation fails. + * + * The vnode interlock is used to protect the i_dirhash pointer from + * simultaneous access while only a shared vnode lock is held. + */ +static struct dirhash * +ufsdirhash_create(struct inode *ip) +{ + struct dirhash *ndh; + struct dirhash *dh; + struct vnode *vp; + bool excl; + + ndh = dh = NULL; + vp = ip->i_vnode; + excl = false; + for (;;) { + /* Racy check for i_dirhash to prefetch a dirhash structure. */ + if (ip->i_dirhash == NULL && ndh == NULL) { + ndh = malloc(sizeof *dh, M_DIRHASH, + M_NOWAIT | M_ZERO); + if (ndh == NULL) + return (NULL); + refcount_init(&ndh->dh_refcount, 1); + + /* + * The DUPOK is to prevent warnings from the + * sx_slock() a few lines down which is safe + * since the duplicate lock in that case is + * the one for this dirhash we are creating + * now which has no external references until + * after this function returns. + */ + sx_init_flags(&ndh->dh_lock, "dirhash", SX_DUPOK); + sx_xlock(&ndh->dh_lock); + } + /* + * Check i_dirhash. If it's NULL just try to use a + * preallocated structure. If none exists loop and try again. + */ + VI_LOCK(vp); + dh = ip->i_dirhash; + if (dh == NULL) { + ip->i_dirhash = ndh; + VI_UNLOCK(vp); + if (ndh == NULL) + continue; + return (ndh); + } + ufsdirhash_hold(dh); + VI_UNLOCK(vp); + + /* Acquire a lock on existing hashes. */ + if (excl) + sx_xlock(&dh->dh_lock); + else + sx_slock(&dh->dh_lock); + + /* The hash could've been recycled while we were waiting. */ + VI_LOCK(vp); + if (ip->i_dirhash != dh) { + VI_UNLOCK(vp); + ufsdirhash_release(dh); + ufsdirhash_drop(dh); + continue; + } + VI_UNLOCK(vp); + ufsdirhash_drop(dh); + + /* If the hash is still valid we've succeeded. */ + if (dh->dh_hash != NULL) + break; + /* + * If the hash is NULL it has been recycled. Try to upgrade + * so we can recreate it. If we fail the upgrade, drop our + * lock and try again. + */ + if (excl || sx_try_upgrade(&dh->dh_lock)) + break; + sx_sunlock(&dh->dh_lock); + excl = true; + } + /* Free the preallocated structure if it was not necessary. */ + if (ndh) { + ufsdirhash_release(ndh); + ufsdirhash_drop(ndh); + } + return (dh); +} + +/* + * Acquire an exclusive lock on an existing hash. Requires an exclusive + * vnode lock to protect the i_dirhash pointer. hashes that have been + * recycled are reclaimed here and NULL is returned. + */ +static struct dirhash * +ufsdirhash_acquire(struct inode *ip) +{ + struct dirhash *dh; + + ASSERT_VOP_ELOCKED(ip->i_vnode, __FUNCTION__); + + dh = ip->i_dirhash; + if (dh == NULL) + return (NULL); + sx_xlock(&dh->dh_lock); + if (dh->dh_hash != NULL) + return (dh); + ufsdirhash_free_locked(ip); + return (NULL); +} + +/* + * Acquire exclusively and free the hash pointed to by ip. Works with a + * shared or exclusive vnode lock. + */ +void +ufsdirhash_free(struct inode *ip) +{ + struct dirhash *dh; + struct vnode *vp; + + vp = ip->i_vnode; + for (;;) { + /* Grab a reference on this inode's dirhash if it has one. */ + VI_LOCK(vp); + dh = ip->i_dirhash; + if (dh == NULL) { + VI_UNLOCK(vp); + return; + } + ufsdirhash_hold(dh); + VI_UNLOCK(vp); + + /* Exclusively lock the dirhash. */ + sx_xlock(&dh->dh_lock); + + /* If this dirhash still belongs to this inode, then free it. */ + VI_LOCK(vp); + if (ip->i_dirhash == dh) { + VI_UNLOCK(vp); + ufsdirhash_drop(dh); + break; + } + VI_UNLOCK(vp); + + /* + * This inode's dirhash has changed while we were + * waiting for the dirhash lock, so try again. + */ + ufsdirhash_release(dh); + ufsdirhash_drop(dh); + } + ufsdirhash_free_locked(ip); +} + +/* + * Attempt to build up a hash table for the directory contents in + * inode 'ip'. Returns 0 on success, or -1 of the operation failed. + */ +int +ufsdirhash_build(struct inode *ip) +{ + struct dirhash *dh; + struct buf *bp = NULL; + struct direct *ep; + struct vnode *vp; + doff_t bmask, pos; + int dirblocks, i, j, memreqd, nblocks, narrays, nslots, slot; + + /* Take care of a decreased sysctl value. */ + while (ufs_dirhashmem > ufs_dirhashmaxmem) { + if (ufsdirhash_recycle(0) != 0) + return (-1); + /* Recycled enough memory, so unlock the list. */ + DIRHASHLIST_UNLOCK(); + } + + /* Check if we can/should use dirhash. */ + if (ip->i_size < ufs_mindirhashsize || OFSFMT(ip->i_vnode) || + ip->i_effnlink == 0) { + if (ip->i_dirhash) + ufsdirhash_free(ip); + return (-1); + } + dh = ufsdirhash_create(ip); + if (dh == NULL) + return (-1); + if (dh->dh_hash != NULL) + return (0); + + vp = ip->i_vnode; + /* Allocate 50% more entries than this dir size could ever need. */ + KASSERT(ip->i_size >= DIRBLKSIZ, ("ufsdirhash_build size")); + nslots = ip->i_size / DIRECTSIZ(1); + nslots = (nslots * 3 + 1) / 2; + narrays = howmany(nslots, DH_NBLKOFF); + nslots = narrays * DH_NBLKOFF; + dirblocks = howmany(ip->i_size, DIRBLKSIZ); + nblocks = (dirblocks * 3 + 1) / 2; + memreqd = sizeof(*dh) + narrays * sizeof(*dh->dh_hash) + + narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) + + nblocks * sizeof(*dh->dh_blkfree); + DIRHASHLIST_LOCK(); + if (memreqd + ufs_dirhashmem > ufs_dirhashmaxmem) { + DIRHASHLIST_UNLOCK(); + if (memreqd > ufs_dirhashmaxmem / 2) + goto fail; + /* Try to free some space. */ + if (ufsdirhash_recycle(memreqd) != 0) + goto fail; + /* Enough was freed, and list has been locked. */ + } + ufs_dirhashmem += memreqd; + DIRHASHLIST_UNLOCK(); + + /* Initialise the hash table and block statistics. */ + dh->dh_memreq = memreqd; + dh->dh_narrays = narrays; + dh->dh_hlen = nslots; + dh->dh_nblk = nblocks; + dh->dh_dirblks = dirblocks; + for (i = 0; i < DH_NFSTATS; i++) + dh->dh_firstfree[i] = -1; + dh->dh_firstfree[DH_NFSTATS] = 0; + dh->dh_hused = 0; + dh->dh_seqoff = -1; + dh->dh_score = DH_SCOREINIT; + dh->dh_lastused = time_second; + + /* + * Use non-blocking mallocs so that we will revert to a linear + * lookup on failure rather than potentially blocking forever. + */ + dh->dh_hash = malloc(narrays * sizeof(dh->dh_hash[0]), + M_DIRHASH, M_NOWAIT | M_ZERO); + if (dh->dh_hash == NULL) + goto fail; + dh->dh_blkfree = malloc(nblocks * sizeof(dh->dh_blkfree[0]), + M_DIRHASH, M_NOWAIT); + if (dh->dh_blkfree == NULL) + goto fail; + for (i = 0; i < narrays; i++) { + if ((dh->dh_hash[i] = DIRHASH_BLKALLOC_WAITOK()) == NULL) + goto fail; + for (j = 0; j < DH_NBLKOFF; j++) + dh->dh_hash[i][j] = DIRHASH_EMPTY; + } + for (i = 0; i < dirblocks; i++) + dh->dh_blkfree[i] = DIRBLKSIZ / DIRALIGN; + bmask = vp->v_mount->mnt_stat.f_iosize - 1; + pos = 0; + while (pos < ip->i_size) { + /* If necessary, get the next directory block. */ + if ((pos & bmask) == 0) { + if (bp != NULL) + brelse(bp); + if (UFS_BLKATOFF(vp, (off_t)pos, NULL, &bp) != 0) + goto fail; + } + + /* Add this entry to the hash. */ + ep = (struct direct *)((char *)bp->b_data + (pos & bmask)); + if (ep->d_reclen == 0 || ep->d_reclen > + DIRBLKSIZ - (pos & (DIRBLKSIZ - 1))) { + /* Corrupted directory. */ + brelse(bp); + goto fail; + } + if (ep->d_ino != 0) { + /* Add the entry (simplified ufsdirhash_add). */ + slot = ufsdirhash_hash(dh, ep->d_name, ep->d_namlen); + while (DH_ENTRY(dh, slot) != DIRHASH_EMPTY) + slot = WRAPINCR(slot, dh->dh_hlen); + dh->dh_hused++; + DH_ENTRY(dh, slot) = pos; + ufsdirhash_adjfree(dh, pos, -DIRSIZ(0, ep)); + } + pos += ep->d_reclen; + } + + if (bp != NULL) + brelse(bp); + DIRHASHLIST_LOCK(); + TAILQ_INSERT_TAIL(&ufsdirhash_list, dh, dh_list); + dh->dh_onlist = 1; + DIRHASHLIST_UNLOCK(); + sx_downgrade(&dh->dh_lock); + return (0); + +fail: + ufsdirhash_free_locked(ip); + return (-1); +} + +/* + * Free any hash table associated with inode 'ip'. + */ +static void +ufsdirhash_free_locked(struct inode *ip) +{ + struct dirhash *dh; + struct vnode *vp; + int i; + + DIRHASH_ASSERT_LOCKED(ip->i_dirhash); + + /* + * Clear the pointer in the inode to prevent new threads from + * finding the dead structure. + */ + vp = ip->i_vnode; + VI_LOCK(vp); + dh = ip->i_dirhash; + ip->i_dirhash = NULL; + VI_UNLOCK(vp); + + /* + * Remove the hash from the list since we are going to free its + * memory. + */ + DIRHASHLIST_LOCK(); + if (dh->dh_onlist) + TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list); + ufs_dirhashmem -= dh->dh_memreq; + DIRHASHLIST_UNLOCK(); + + /* + * At this point, any waiters for the lock should hold their + * own reference on the dirhash structure. They will drop + * that reference once they grab the vnode interlock and see + * that ip->i_dirhash is NULL. + */ + sx_xunlock(&dh->dh_lock); + + /* + * Handle partially recycled as well as fully constructed hashes. + */ + if (dh->dh_hash != NULL) { + for (i = 0; i < dh->dh_narrays; i++) + if (dh->dh_hash[i] != NULL) + DIRHASH_BLKFREE(dh->dh_hash[i]); + free(dh->dh_hash, M_DIRHASH); + if (dh->dh_blkfree != NULL) + free(dh->dh_blkfree, M_DIRHASH); + } + + /* + * Drop the inode's reference to the data structure. + */ + ufsdirhash_drop(dh); +} + +/* + * Find the offset of the specified name within the given inode. + * Returns 0 on success, ENOENT if the entry does not exist, or + * EJUSTRETURN if the caller should revert to a linear search. + * + * If successful, the directory offset is stored in *offp, and a + * pointer to a struct buf containing the entry is stored in *bpp. If + * prevoffp is non-NULL, the offset of the previous entry within + * the DIRBLKSIZ-sized block is stored in *prevoffp (if the entry + * is the first in a block, the start of the block is used). + * + * Must be called with the hash locked. Returns with the hash unlocked. + */ +int +ufsdirhash_lookup(struct inode *ip, char *name, int namelen, doff_t *offp, + struct buf **bpp, doff_t *prevoffp) +{ + struct dirhash *dh, *dh_next; + struct direct *dp; + struct vnode *vp; + struct buf *bp; + doff_t blkoff, bmask, offset, prevoff, seqoff; + int i, slot; + int error; + + dh = ip->i_dirhash; + KASSERT(dh != NULL && dh->dh_hash != NULL, + ("ufsdirhash_lookup: Invalid dirhash %p\n", dh)); + DIRHASH_ASSERT_LOCKED(dh); + /* + * Move this dirhash towards the end of the list if it has a + * score higher than the next entry, and acquire the dh_lock. + */ + DIRHASHLIST_LOCK(); + if (TAILQ_NEXT(dh, dh_list) != NULL) { + /* + * If the new score will be greater than that of the next + * entry, then move this entry past it. With both mutexes + * held, dh_next won't go away, but its dh_score could + * change; that's not important since it is just a hint. + */ + if ((dh_next = TAILQ_NEXT(dh, dh_list)) != NULL && + dh->dh_score >= dh_next->dh_score) { + KASSERT(dh->dh_onlist, ("dirhash: not on list")); + TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list); + TAILQ_INSERT_AFTER(&ufsdirhash_list, dh_next, dh, + dh_list); + } + } + /* Update the score. */ + if (dh->dh_score < DH_SCOREMAX) + dh->dh_score++; + + /* Update last used time. */ + dh->dh_lastused = time_second; + DIRHASHLIST_UNLOCK(); + + vp = ip->i_vnode; + bmask = vp->v_mount->mnt_stat.f_iosize - 1; + blkoff = -1; + bp = NULL; + seqoff = dh->dh_seqoff; +restart: + slot = ufsdirhash_hash(dh, name, namelen); + + if (seqoff != -1) { + /* + * Sequential access optimisation. seqoff contains the + * offset of the directory entry immediately following + * the last entry that was looked up. Check if this offset + * appears in the hash chain for the name we are looking for. + */ + for (i = slot; (offset = DH_ENTRY(dh, i)) != DIRHASH_EMPTY; + i = WRAPINCR(i, dh->dh_hlen)) + if (offset == seqoff) + break; + if (offset == seqoff) { + /* + * We found an entry with the expected offset. This + * is probably the entry we want, but if not, the + * code below will retry. + */ + slot = i; + } else + seqoff = -1; + } + + for (; (offset = DH_ENTRY(dh, slot)) != DIRHASH_EMPTY; + slot = WRAPINCR(slot, dh->dh_hlen)) { + if (offset == DIRHASH_DEL) + continue; + if (offset < 0 || offset >= ip->i_size) + panic("ufsdirhash_lookup: bad offset in hash array"); + if ((offset & ~bmask) != blkoff) { + if (bp != NULL) + brelse(bp); + blkoff = offset & ~bmask; + if (UFS_BLKATOFF(vp, (off_t)blkoff, NULL, &bp) != 0) { + error = EJUSTRETURN; + goto fail; + } + } + KASSERT(bp != NULL, ("no buffer allocated")); + dp = (struct direct *)(bp->b_data + (offset & bmask)); + if (dp->d_reclen == 0 || dp->d_reclen > + DIRBLKSIZ - (offset & (DIRBLKSIZ - 1))) { + /* Corrupted directory. */ + error = EJUSTRETURN; + goto fail; + } + if (dp->d_namlen == namelen && + bcmp(dp->d_name, name, namelen) == 0) { + /* Found. Get the prev offset if needed. */ + if (prevoffp != NULL) { + if (offset & (DIRBLKSIZ - 1)) { + prevoff = ufsdirhash_getprev(dp, + offset); + if (prevoff == -1) { + error = EJUSTRETURN; + goto fail; + } + } else + prevoff = offset; + *prevoffp = prevoff; + } + + /* Update offset. */ + dh->dh_seqoff = offset + DIRSIZ(0, dp); + *bpp = bp; + *offp = offset; + ufsdirhash_release(dh); + return (0); + } + + /* + * When the name doesn't match in the sequential + * optimization case, go back and search normally. + */ + if (seqoff != -1) { + seqoff = -1; + goto restart; + } + } + error = ENOENT; +fail: + ufsdirhash_release(dh); + if (bp != NULL) + brelse(bp); + return (error); +} + +/* + * Find a directory block with room for 'slotneeded' bytes. Returns + * the offset of the directory entry that begins the free space. + * This will either be the offset of an existing entry that has free + * space at the end, or the offset of an entry with d_ino == 0 at + * the start of a DIRBLKSIZ block. + * + * To use the space, the caller may need to compact existing entries in + * the directory. The total number of bytes in all of the entries involved + * in the compaction is stored in *slotsize. In other words, all of + * the entries that must be compacted are exactly contained in the + * region beginning at the returned offset and spanning *slotsize bytes. + * + * Returns -1 if no space was found, indicating that the directory + * must be extended. + */ +doff_t +ufsdirhash_findfree(struct inode *ip, int slotneeded, int *slotsize) +{ + struct direct *dp; + struct dirhash *dh; + struct buf *bp; + doff_t pos, slotstart; + int dirblock, error, freebytes, i; + + dh = ip->i_dirhash; + KASSERT(dh != NULL && dh->dh_hash != NULL, + ("ufsdirhash_findfree: Invalid dirhash %p\n", dh)); + DIRHASH_ASSERT_LOCKED(dh); + + /* Find a directory block with the desired free space. */ + dirblock = -1; + for (i = howmany(slotneeded, DIRALIGN); i <= DH_NFSTATS; i++) + if ((dirblock = dh->dh_firstfree[i]) != -1) + break; + if (dirblock == -1) + return (-1); + + KASSERT(dirblock < dh->dh_nblk && + dh->dh_blkfree[dirblock] >= howmany(slotneeded, DIRALIGN), + ("ufsdirhash_findfree: bad stats")); + pos = dirblock * DIRBLKSIZ; + error = UFS_BLKATOFF(ip->i_vnode, (off_t)pos, (char **)&dp, &bp); + if (error) + return (-1); + + /* Find the first entry with free space. */ + for (i = 0; i < DIRBLKSIZ; ) { + if (dp->d_reclen == 0) { + brelse(bp); + return (-1); + } + if (dp->d_ino == 0 || dp->d_reclen > DIRSIZ(0, dp)) + break; + i += dp->d_reclen; + dp = (struct direct *)((char *)dp + dp->d_reclen); + } + if (i > DIRBLKSIZ) { + brelse(bp); + return (-1); + } + slotstart = pos + i; + + /* Find the range of entries needed to get enough space */ + freebytes = 0; + while (i < DIRBLKSIZ && freebytes < slotneeded) { + freebytes += dp->d_reclen; + if (dp->d_ino != 0) + freebytes -= DIRSIZ(0, dp); + if (dp->d_reclen == 0) { + brelse(bp); + return (-1); + } + i += dp->d_reclen; + dp = (struct direct *)((char *)dp + dp->d_reclen); + } + if (i > DIRBLKSIZ) { + brelse(bp); + return (-1); + } + if (freebytes < slotneeded) + panic("ufsdirhash_findfree: free mismatch"); + brelse(bp); + *slotsize = pos + i - slotstart; + return (slotstart); +} + +/* + * Return the start of the unused space at the end of a directory, or + * -1 if there are no trailing unused blocks. + */ +doff_t +ufsdirhash_enduseful(struct inode *ip) +{ + + struct dirhash *dh; + int i; + + dh = ip->i_dirhash; + DIRHASH_ASSERT_LOCKED(dh); + KASSERT(dh != NULL && dh->dh_hash != NULL, + ("ufsdirhash_enduseful: Invalid dirhash %p\n", dh)); + + if (dh->dh_blkfree[dh->dh_dirblks - 1] != DIRBLKSIZ / DIRALIGN) + return (-1); + + for (i = dh->dh_dirblks - 1; i >= 0; i--) + if (dh->dh_blkfree[i] != DIRBLKSIZ / DIRALIGN) + break; + + return ((doff_t)(i + 1) * DIRBLKSIZ); +} + +/* + * Insert information into the hash about a new directory entry. dirp + * points to a struct direct containing the entry, and offset specifies + * the offset of this entry. + */ +void +ufsdirhash_add(struct inode *ip, struct direct *dirp, doff_t offset) +{ + struct dirhash *dh; + int slot; + + if ((dh = ufsdirhash_acquire(ip)) == NULL) + return; + + KASSERT(offset < dh->dh_dirblks * DIRBLKSIZ, + ("ufsdirhash_add: bad offset")); + /* + * Normal hash usage is < 66%. If the usage gets too high then + * remove the hash entirely and let it be rebuilt later. + */ + if (dh->dh_hused >= (dh->dh_hlen * 3) / 4) { + ufsdirhash_free_locked(ip); + return; + } + + /* Find a free hash slot (empty or deleted), and add the entry. */ + slot = ufsdirhash_hash(dh, dirp->d_name, dirp->d_namlen); + while (DH_ENTRY(dh, slot) >= 0) + slot = WRAPINCR(slot, dh->dh_hlen); + if (DH_ENTRY(dh, slot) == DIRHASH_EMPTY) + dh->dh_hused++; + DH_ENTRY(dh, slot) = offset; + + /* Update last used time. */ + dh->dh_lastused = time_second; + + /* Update the per-block summary info. */ + ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp)); + ufsdirhash_release(dh); +} + +/* + * Remove the specified directory entry from the hash. The entry to remove + * is defined by the name in `dirp', which must exist at the specified + * `offset' within the directory. + */ +void +ufsdirhash_remove(struct inode *ip, struct direct *dirp, doff_t offset) +{ + struct dirhash *dh; + int slot; + + if ((dh = ufsdirhash_acquire(ip)) == NULL) + return; + + KASSERT(offset < dh->dh_dirblks * DIRBLKSIZ, + ("ufsdirhash_remove: bad offset")); + /* Find the entry */ + slot = ufsdirhash_findslot(dh, dirp->d_name, dirp->d_namlen, offset); + + /* Remove the hash entry. */ + ufsdirhash_delslot(dh, slot); + + /* Update the per-block summary info. */ + ufsdirhash_adjfree(dh, offset, DIRSIZ(0, dirp)); + ufsdirhash_release(dh); +} + +/* + * Change the offset associated with a directory entry in the hash. Used + * when compacting directory blocks. + */ +void +ufsdirhash_move(struct inode *ip, struct direct *dirp, doff_t oldoff, + doff_t newoff) +{ + struct dirhash *dh; + int slot; + + if ((dh = ufsdirhash_acquire(ip)) == NULL) + return; + + KASSERT(oldoff < dh->dh_dirblks * DIRBLKSIZ && + newoff < dh->dh_dirblks * DIRBLKSIZ, + ("ufsdirhash_move: bad offset")); + /* Find the entry, and update the offset. */ + slot = ufsdirhash_findslot(dh, dirp->d_name, dirp->d_namlen, oldoff); + DH_ENTRY(dh, slot) = newoff; + ufsdirhash_release(dh); +} + +/* + * Inform dirhash that the directory has grown by one block that + * begins at offset (i.e. the new length is offset + DIRBLKSIZ). + */ +void +ufsdirhash_newblk(struct inode *ip, doff_t offset) +{ + struct dirhash *dh; + int block; + + if ((dh = ufsdirhash_acquire(ip)) == NULL) + return; + + KASSERT(offset == dh->dh_dirblks * DIRBLKSIZ, + ("ufsdirhash_newblk: bad offset")); + block = offset / DIRBLKSIZ; + if (block >= dh->dh_nblk) { + /* Out of space; must rebuild. */ + ufsdirhash_free_locked(ip); + return; + } + dh->dh_dirblks = block + 1; + + /* Account for the new free block. */ + dh->dh_blkfree[block] = DIRBLKSIZ / DIRALIGN; + if (dh->dh_firstfree[DH_NFSTATS] == -1) + dh->dh_firstfree[DH_NFSTATS] = block; + ufsdirhash_release(dh); +} + +/* + * Inform dirhash that the directory is being truncated. + */ +void +ufsdirhash_dirtrunc(struct inode *ip, doff_t offset) +{ + struct dirhash *dh; + int block, i; + + if ((dh = ufsdirhash_acquire(ip)) == NULL) + return; + + KASSERT(offset <= dh->dh_dirblks * DIRBLKSIZ, + ("ufsdirhash_dirtrunc: bad offset")); + block = howmany(offset, DIRBLKSIZ); + /* + * If the directory shrinks to less than 1/8 of dh_nblk blocks + * (about 20% of its original size due to the 50% extra added in + * ufsdirhash_build) then free it, and let the caller rebuild + * if necessary. + */ + if (block < dh->dh_nblk / 8 && dh->dh_narrays > 1) { + ufsdirhash_free_locked(ip); + return; + } + + /* + * Remove any `first free' information pertaining to the + * truncated blocks. All blocks we're removing should be + * completely unused. + */ + if (dh->dh_firstfree[DH_NFSTATS] >= block) + dh->dh_firstfree[DH_NFSTATS] = -1; + for (i = block; i < dh->dh_dirblks; i++) + if (dh->dh_blkfree[i] != DIRBLKSIZ / DIRALIGN) + panic("ufsdirhash_dirtrunc: blocks in use"); + for (i = 0; i < DH_NFSTATS; i++) + if (dh->dh_firstfree[i] >= block) + panic("ufsdirhash_dirtrunc: first free corrupt"); + dh->dh_dirblks = block; + ufsdirhash_release(dh); +} + +/* + * Debugging function to check that the dirhash information about + * a directory block matches its actual contents. Panics if a mismatch + * is detected. + * + * On entry, `buf' should point to the start of an in-core + * DIRBLKSIZ-sized directory block, and `offset' should contain the + * offset from the start of the directory of that block. + */ +void +ufsdirhash_checkblock(struct inode *ip, char *buf, doff_t offset) +{ + struct dirhash *dh; + struct direct *dp; + int block, ffslot, i, nfree; + + if (!ufs_dirhashcheck) + return; + if ((dh = ufsdirhash_acquire(ip)) == NULL) + return; + + block = offset / DIRBLKSIZ; + if ((offset & (DIRBLKSIZ - 1)) != 0 || block >= dh->dh_dirblks) + panic("ufsdirhash_checkblock: bad offset"); + + nfree = 0; + for (i = 0; i < DIRBLKSIZ; i += dp->d_reclen) { + dp = (struct direct *)(buf + i); + if (dp->d_reclen == 0 || i + dp->d_reclen > DIRBLKSIZ) + panic("ufsdirhash_checkblock: bad dir"); + + if (dp->d_ino == 0) { +#if 0 + /* + * XXX entries with d_ino == 0 should only occur + * at the start of a DIRBLKSIZ block. However the + * ufs code is tolerant of such entries at other + * offsets, and fsck does not fix them. + */ + if (i != 0) + panic("ufsdirhash_checkblock: bad dir inode"); +#endif + nfree += dp->d_reclen; + continue; + } + + /* Check that the entry exists (will panic if it doesn't). */ + ufsdirhash_findslot(dh, dp->d_name, dp->d_namlen, offset + i); + + nfree += dp->d_reclen - DIRSIZ(0, dp); + } + if (i != DIRBLKSIZ) + panic("ufsdirhash_checkblock: bad dir end"); + + if (dh->dh_blkfree[block] * DIRALIGN != nfree) + panic("ufsdirhash_checkblock: bad free count"); + + ffslot = BLKFREE2IDX(nfree / DIRALIGN); + for (i = 0; i <= DH_NFSTATS; i++) + if (dh->dh_firstfree[i] == block && i != ffslot) + panic("ufsdirhash_checkblock: bad first-free"); + if (dh->dh_firstfree[ffslot] == -1) + panic("ufsdirhash_checkblock: missing first-free entry"); + ufsdirhash_release(dh); +} + +/* + * Hash the specified filename into a dirhash slot. + */ +static int +ufsdirhash_hash(struct dirhash *dh, char *name, int namelen) +{ + u_int32_t hash; + + /* + * We hash the name and then some other bit of data that is + * invariant over the dirhash's lifetime. Otherwise names + * differing only in the last byte are placed close to one + * another in the table, which is bad for linear probing. + */ + hash = fnv_32_buf(name, namelen, FNV1_32_INIT); + hash = fnv_32_buf(&dh, sizeof(dh), hash); + return (hash % dh->dh_hlen); +} + +/* + * Adjust the number of free bytes in the block containing `offset' + * by the value specified by `diff'. + * + * The caller must ensure we have exclusive access to `dh'; normally + * that means that dh_lock should be held, but this is also called + * from ufsdirhash_build() where exclusive access can be assumed. + */ +static void +ufsdirhash_adjfree(struct dirhash *dh, doff_t offset, int diff) +{ + int block, i, nfidx, ofidx; + + /* Update the per-block summary info. */ + block = offset / DIRBLKSIZ; + KASSERT(block < dh->dh_nblk && block < dh->dh_dirblks, + ("dirhash bad offset")); + ofidx = BLKFREE2IDX(dh->dh_blkfree[block]); + dh->dh_blkfree[block] = (int)dh->dh_blkfree[block] + (diff / DIRALIGN); + nfidx = BLKFREE2IDX(dh->dh_blkfree[block]); + + /* Update the `first free' list if necessary. */ + if (ofidx != nfidx) { + /* If removing, scan forward for the next block. */ + if (dh->dh_firstfree[ofidx] == block) { + for (i = block + 1; i < dh->dh_dirblks; i++) + if (BLKFREE2IDX(dh->dh_blkfree[i]) == ofidx) + break; + dh->dh_firstfree[ofidx] = (i < dh->dh_dirblks) ? i : -1; + } + + /* Make this the new `first free' if necessary */ + if (dh->dh_firstfree[nfidx] > block || + dh->dh_firstfree[nfidx] == -1) + dh->dh_firstfree[nfidx] = block; + } +} + +/* + * Find the specified name which should have the specified offset. + * Returns a slot number, and panics on failure. + * + * `dh' must be locked on entry and remains so on return. + */ +static int +ufsdirhash_findslot(struct dirhash *dh, char *name, int namelen, doff_t offset) +{ + int slot; + + DIRHASH_ASSERT_LOCKED(dh); + + /* Find the entry. */ + KASSERT(dh->dh_hused < dh->dh_hlen, ("dirhash find full")); + slot = ufsdirhash_hash(dh, name, namelen); + while (DH_ENTRY(dh, slot) != offset && + DH_ENTRY(dh, slot) != DIRHASH_EMPTY) + slot = WRAPINCR(slot, dh->dh_hlen); + if (DH_ENTRY(dh, slot) != offset) + panic("ufsdirhash_findslot: '%.*s' not found", namelen, name); + + return (slot); +} + +/* + * Remove the entry corresponding to the specified slot from the hash array. + * + * `dh' must be locked on entry and remains so on return. + */ +static void +ufsdirhash_delslot(struct dirhash *dh, int slot) +{ + int i; + + DIRHASH_ASSERT_LOCKED(dh); + + /* Mark the entry as deleted. */ + DH_ENTRY(dh, slot) = DIRHASH_DEL; + + /* If this is the end of a chain of DIRHASH_DEL slots, remove them. */ + for (i = slot; DH_ENTRY(dh, i) == DIRHASH_DEL; ) + i = WRAPINCR(i, dh->dh_hlen); + if (DH_ENTRY(dh, i) == DIRHASH_EMPTY) { + i = WRAPDECR(i, dh->dh_hlen); + while (DH_ENTRY(dh, i) == DIRHASH_DEL) { + DH_ENTRY(dh, i) = DIRHASH_EMPTY; + dh->dh_hused--; + i = WRAPDECR(i, dh->dh_hlen); + } + KASSERT(dh->dh_hused >= 0, ("ufsdirhash_delslot neg hlen")); + } +} + +/* + * Given a directory entry and its offset, find the offset of the + * previous entry in the same DIRBLKSIZ-sized block. Returns an + * offset, or -1 if there is no previous entry in the block or some + * other problem occurred. + */ +static doff_t +ufsdirhash_getprev(struct direct *dirp, doff_t offset) +{ + struct direct *dp; + char *blkbuf; + doff_t blkoff, prevoff; + int entrypos, i; + + blkoff = rounddown2(offset, DIRBLKSIZ); /* offset of start of block */ + entrypos = offset & (DIRBLKSIZ - 1); /* entry relative to block */ + blkbuf = (char *)dirp - entrypos; + prevoff = blkoff; + + /* If `offset' is the start of a block, there is no previous entry. */ + if (entrypos == 0) + return (-1); + + /* Scan from the start of the block until we get to the entry. */ + for (i = 0; i < entrypos; i += dp->d_reclen) { + dp = (struct direct *)(blkbuf + i); + if (dp->d_reclen == 0 || i + dp->d_reclen > entrypos) + return (-1); /* Corrupted directory. */ + prevoff = blkoff + i; + } + return (prevoff); +} + +/* + * Delete the given dirhash and reclaim its memory. Assumes that + * ufsdirhash_list is locked, and leaves it locked. Also assumes + * that dh is locked. Returns the amount of memory freed. + */ +static int +ufsdirhash_destroy(struct dirhash *dh) +{ + doff_t **hash; + u_int8_t *blkfree; + int i, mem, narrays; + + KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list")); + + /* Remove it from the list and detach its memory. */ + TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list); + dh->dh_onlist = 0; + hash = dh->dh_hash; + dh->dh_hash = NULL; + blkfree = dh->dh_blkfree; + dh->dh_blkfree = NULL; + narrays = dh->dh_narrays; + mem = dh->dh_memreq; + dh->dh_memreq = 0; + + /* Unlock dirhash and free the detached memory. */ + ufsdirhash_release(dh); + for (i = 0; i < narrays; i++) + DIRHASH_BLKFREE(hash[i]); + free(hash, M_DIRHASH); + free(blkfree, M_DIRHASH); + + /* Account for the returned memory. */ + ufs_dirhashmem -= mem; + + return (mem); +} + +/* + * Try to free up `wanted' bytes by stealing memory from existing + * dirhashes. Returns zero with list locked if successful. + */ +static int +ufsdirhash_recycle(int wanted) +{ + struct dirhash *dh; + + DIRHASHLIST_LOCK(); + dh = TAILQ_FIRST(&ufsdirhash_list); + while (wanted + ufs_dirhashmem > ufs_dirhashmaxmem) { + /* Decrement the score; only recycle if it becomes zero. */ + if (dh == NULL || --dh->dh_score > 0) { + DIRHASHLIST_UNLOCK(); + return (-1); + } + /* + * If we can't lock it it's in use and we don't want to + * recycle it anyway. + */ + if (!sx_try_xlock(&dh->dh_lock)) { + dh = TAILQ_NEXT(dh, dh_list); + continue; + } + + ufsdirhash_destroy(dh); + + /* Repeat if necessary. */ + dh = TAILQ_FIRST(&ufsdirhash_list); + } + /* Success; return with list locked. */ + return (0); +} + +/* + * Callback that frees some dirhashes when the system is low on virtual memory. + */ +static void +ufsdirhash_lowmem() +{ + struct dirhash *dh, *dh_temp; + int memfreed, memwanted; + + ufs_dirhashlowmemcount++; + memfreed = 0; + memwanted = ufs_dirhashmem * ufs_dirhashreclaimpercent / 100; + + DIRHASHLIST_LOCK(); + + /* + * Reclaim up to memwanted from the oldest dirhashes. This will allow + * us to make some progress when the system is running out of memory + * without compromising the dinamicity of maximum age. If the situation + * does not improve lowmem will be eventually retriggered and free some + * other entry in the cache. The entries on the head of the list should + * be the oldest. If during list traversal we can't get a lock on the + * dirhash, it will be skipped. + */ + TAILQ_FOREACH_SAFE(dh, &ufsdirhash_list, dh_list, dh_temp) { + if (sx_try_xlock(&dh->dh_lock)) + memfreed += ufsdirhash_destroy(dh); + if (memfreed >= memwanted) + break; + } + DIRHASHLIST_UNLOCK(); +} + +static int +ufsdirhash_set_reclaimpercent(SYSCTL_HANDLER_ARGS) +{ + int error, v; + + v = ufs_dirhashreclaimpercent; + error = sysctl_handle_int(oidp, &v, v, req); + if (error) + return (error); + if (req->newptr == NULL) + return (error); + if (v == ufs_dirhashreclaimpercent) + return (0); + + /* Refuse invalid percentages */ + if (v < 0 || v > 100) + return (EINVAL); + ufs_dirhashreclaimpercent = v; + return (0); +} + +void +ufsdirhash_init() +{ + ufs_dirhashmaxmem = lmax(roundup(hibufspace / 64, PAGE_SIZE), + 2 * 1024 * 1024); + + ufsdirhash_zone = uma_zcreate("DIRHASH", DH_NBLKOFF * sizeof(doff_t), + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + mtx_init(&ufsdirhash_mtx, "dirhash list", NULL, MTX_DEF); + TAILQ_INIT(&ufsdirhash_list); + + /* Register a callback function to handle low memory signals */ + EVENTHANDLER_REGISTER(vm_lowmem, ufsdirhash_lowmem, NULL, + EVENTHANDLER_PRI_FIRST); +} + +void +ufsdirhash_uninit() +{ + KASSERT(TAILQ_EMPTY(&ufsdirhash_list), ("ufsdirhash_uninit")); + uma_zdestroy(ufsdirhash_zone); + mtx_destroy(&ufsdirhash_mtx); +} + +#endif /* UFS_DIRHASH */ diff --git a/Dump/ufs/ufs/ufs_extattr.c b/Dump/ufs/ufs/ufs_extattr.c new file mode 100644 index 0000000..bb3bcca --- /dev/null +++ b/Dump/ufs/ufs/ufs_extattr.c @@ -0,0 +1,1300 @@ +/*- + * Copyright (c) 1999-2002 Robert N. M. Watson + * Copyright (c) 2002-2003 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed by Robert Watson for the TrustedBSD Project. + * + * This software was developed for the FreeBSD Project in part by Network + * Associates Laboratories, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), + * as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * Support for filesystem extended attribute: UFS-specific support functions. + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_extattr.c 298463 2016-04-22 08:09:27Z ngie $"); + +#include "opt_ufs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef UFS_EXTATTR + +FEATURE(ufs_extattr, "ufs extended attribute support"); + +static MALLOC_DEFINE(M_UFS_EXTATTR, "ufs_extattr", "ufs extended attribute"); + +static int ufs_extattr_sync = 0; +SYSCTL_INT(_debug, OID_AUTO, ufs_extattr_sync, CTLFLAG_RW, &ufs_extattr_sync, + 0, ""); + +static int ufs_extattr_valid_attrname(int attrnamespace, + const char *attrname); +static int ufs_extattr_enable_with_open(struct ufsmount *ump, + struct vnode *vp, int attrnamespace, const char *attrname, + struct thread *td); +static int ufs_extattr_enable(struct ufsmount *ump, int attrnamespace, + const char *attrname, struct vnode *backing_vnode, + struct thread *td); +static int ufs_extattr_disable(struct ufsmount *ump, int attrnamespace, + const char *attrname, struct thread *td); +static int ufs_extattr_get(struct vnode *vp, int attrnamespace, + const char *name, struct uio *uio, size_t *size, + struct ucred *cred, struct thread *td); +static int ufs_extattr_set(struct vnode *vp, int attrnamespace, + const char *name, struct uio *uio, struct ucred *cred, + struct thread *td); +static int ufs_extattr_rm(struct vnode *vp, int attrnamespace, + const char *name, struct ucred *cred, struct thread *td); +#ifdef UFS_EXTATTR_AUTOSTART +static int ufs_extattr_autostart_locked(struct mount *mp, + struct thread *td); +#endif +static int ufs_extattr_start_locked(struct ufsmount *ump, + struct thread *td); + +/* + * Per-FS attribute lock protecting attribute operations. + * + * XXXRW: Perhaps something more fine-grained would be appropriate, but at + * the end of the day we're going to contend on the vnode lock for the + * backing file anyway. + */ +static void +ufs_extattr_uepm_lock(struct ufsmount *ump) +{ + + sx_xlock(&ump->um_extattr.uepm_lock); +} + +static void +ufs_extattr_uepm_unlock(struct ufsmount *ump) +{ + + sx_xunlock(&ump->um_extattr.uepm_lock); +} + +/*- + * Determine whether the name passed is a valid name for an actual + * attribute. + * + * Invalid currently consists of: + * NULL pointer for attrname + * zero-length attrname (used to retrieve application attribute list) + */ +static int +ufs_extattr_valid_attrname(int attrnamespace, const char *attrname) +{ + + if (attrname == NULL) + return (0); + if (strlen(attrname) == 0) + return (0); + return (1); +} + +/* + * Locate an attribute given a name and mountpoint. + * Must be holding uepm lock for the mount point. + */ +static struct ufs_extattr_list_entry * +ufs_extattr_find_attr(struct ufsmount *ump, int attrnamespace, + const char *attrname) +{ + struct ufs_extattr_list_entry *search_attribute; + + sx_assert(&ump->um_extattr.uepm_lock, SA_XLOCKED); + + for (search_attribute = LIST_FIRST(&ump->um_extattr.uepm_list); + search_attribute != NULL; + search_attribute = LIST_NEXT(search_attribute, uele_entries)) { + if (!(strncmp(attrname, search_attribute->uele_attrname, + UFS_EXTATTR_MAXEXTATTRNAME)) && + (attrnamespace == search_attribute->uele_attrnamespace)) { + return (search_attribute); + } + } + + return (0); +} + +/* + * Initialize per-FS structures supporting extended attributes. Do not + * start extended attributes yet. + */ +void +ufs_extattr_uepm_init(struct ufs_extattr_per_mount *uepm) +{ + + uepm->uepm_flags = 0; + LIST_INIT(&uepm->uepm_list); + sx_init(&uepm->uepm_lock, "ufs_extattr_sx"); + uepm->uepm_flags |= UFS_EXTATTR_UEPM_INITIALIZED; +} + +/* + * Destroy per-FS structures supporting extended attributes. Assumes + * that EAs have already been stopped, and will panic if not. + */ +void +ufs_extattr_uepm_destroy(struct ufs_extattr_per_mount *uepm) +{ + + if (!(uepm->uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) + panic("ufs_extattr_uepm_destroy: not initialized"); + + if ((uepm->uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + panic("ufs_extattr_uepm_destroy: called while still started"); + + /* + * It's not clear that either order for the next two lines is + * ideal, and it should never be a problem if this is only called + * during unmount, and with vfs_busy(). + */ + uepm->uepm_flags &= ~UFS_EXTATTR_UEPM_INITIALIZED; + sx_destroy(&uepm->uepm_lock); +} + +/* + * Start extended attribute support on an FS. + */ +int +ufs_extattr_start(struct mount *mp, struct thread *td) +{ + struct ufsmount *ump; + int error = 0; + + ump = VFSTOUFS(mp); + + ufs_extattr_uepm_lock(ump); + error = ufs_extattr_start_locked(ump, td); + ufs_extattr_uepm_unlock(ump); + return (error); +} + +static int +ufs_extattr_start_locked(struct ufsmount *ump, struct thread *td) +{ + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) + return (EOPNOTSUPP); + if (ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED) + return (EBUSY); + + ump->um_extattr.uepm_flags |= UFS_EXTATTR_UEPM_STARTED; + ump->um_extattr.uepm_ucred = crhold(td->td_ucred); + return (0); +} + +#ifdef UFS_EXTATTR_AUTOSTART +/* + * Helper routine: given a locked parent directory and filename, return + * the locked vnode of the inode associated with the name. Will not + * follow symlinks, may return any type of vnode. Lock on parent will + * be released even in the event of a failure. In the event that the + * target is the parent (i.e., "."), there will be two references and + * one lock, requiring the caller to possibly special-case. + */ +#define UE_GETDIR_LOCKPARENT 1 +#define UE_GETDIR_LOCKPARENT_DONT 2 +static int +ufs_extattr_lookup(struct vnode *start_dvp, int lockparent, char *dirname, + struct vnode **vp, struct thread *td) +{ + struct vop_cachedlookup_args vargs; + struct componentname cnp; + struct vnode *target_vp; + int error; + + bzero(&cnp, sizeof(cnp)); + cnp.cn_nameiop = LOOKUP; + cnp.cn_flags = ISLASTCN; + if (lockparent == UE_GETDIR_LOCKPARENT) + cnp.cn_flags |= LOCKPARENT; + cnp.cn_lkflags = LK_EXCLUSIVE; + cnp.cn_thread = td; + cnp.cn_cred = td->td_ucred; + cnp.cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); + cnp.cn_nameptr = cnp.cn_pnbuf; + error = copystr(dirname, cnp.cn_pnbuf, MAXPATHLEN, + (size_t *) &cnp.cn_namelen); + if (error) { + if (lockparent == UE_GETDIR_LOCKPARENT_DONT) { + VOP_UNLOCK(start_dvp, 0); + } + uma_zfree(namei_zone, cnp.cn_pnbuf); + printf("ufs_extattr_lookup: copystr failed\n"); + return (error); + } + cnp.cn_namelen--; /* trim nul termination */ + vargs.a_gen.a_desc = NULL; + vargs.a_dvp = start_dvp; + vargs.a_vpp = &target_vp; + vargs.a_cnp = &cnp; + error = ufs_lookup(&vargs); + uma_zfree(namei_zone, cnp.cn_pnbuf); + if (error) { + /* + * Error condition, may have to release the lock on the parent + * if ufs_lookup() didn't. + */ + if (lockparent == UE_GETDIR_LOCKPARENT_DONT) + VOP_UNLOCK(start_dvp, 0); + + /* + * Check that ufs_lookup() didn't release the lock when we + * didn't want it to. + */ + if (lockparent == UE_GETDIR_LOCKPARENT) + ASSERT_VOP_LOCKED(start_dvp, "ufs_extattr_lookup"); + + return (error); + } +/* + if (target_vp == start_dvp) + panic("ufs_extattr_lookup: target_vp == start_dvp"); +*/ + + if (target_vp != start_dvp && lockparent == UE_GETDIR_LOCKPARENT_DONT) + VOP_UNLOCK(start_dvp, 0); + + if (lockparent == UE_GETDIR_LOCKPARENT) + ASSERT_VOP_LOCKED(start_dvp, "ufs_extattr_lookup"); + + /* printf("ufs_extattr_lookup: success\n"); */ + *vp = target_vp; + return (0); +} +#endif /* !UFS_EXTATTR_AUTOSTART */ + +/* + * Enable an EA using the passed filesystem, backing vnode, attribute name, + * namespace, and proc. Will perform a VOP_OPEN() on the vp, so expects vp + * to be locked when passed in. The vnode will be returned unlocked, + * regardless of success/failure of the function. As a result, the caller + * will always need to vrele(), but not vput(). + */ +static int +ufs_extattr_enable_with_open(struct ufsmount *ump, struct vnode *vp, + int attrnamespace, const char *attrname, struct thread *td) +{ + int error; + + error = VOP_OPEN(vp, FREAD|FWRITE, td->td_ucred, td, NULL); + if (error) { + printf("ufs_extattr_enable_with_open.VOP_OPEN(): failed " + "with %d\n", error); + VOP_UNLOCK(vp, 0); + return (error); + } + + VOP_ADD_WRITECOUNT(vp, 1); + CTR3(KTR_VFS, "%s: vp %p v_writecount increased to %d", __func__, vp, + vp->v_writecount); + + vref(vp); + + VOP_UNLOCK(vp, 0); + + error = ufs_extattr_enable(ump, attrnamespace, attrname, vp, td); + if (error != 0) + vn_close(vp, FREAD|FWRITE, td->td_ucred, td); + return (error); +} + +#ifdef UFS_EXTATTR_AUTOSTART +/* + * Given a locked directory vnode, iterate over the names in the directory + * and use ufs_extattr_lookup() to retrieve locked vnodes of potential + * attribute files. Then invoke ufs_extattr_enable_with_open() on each + * to attempt to start the attribute. Leaves the directory locked on + * exit. + */ +static int +ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp, + int attrnamespace, struct thread *td) +{ + struct vop_readdir_args vargs; + struct dirent *dp, *edp; + struct vnode *attr_vp; + struct uio auio; + struct iovec aiov; + char *dirbuf; + int error, eofflag = 0; + + if (dvp->v_type != VDIR) + return (ENOTDIR); + + dirbuf = malloc(DIRBLKSIZ, M_TEMP, M_WAITOK); + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_td = td; + auio.uio_offset = 0; + + vargs.a_gen.a_desc = NULL; + vargs.a_vp = dvp; + vargs.a_uio = &auio; + vargs.a_cred = td->td_ucred; + vargs.a_eofflag = &eofflag; + vargs.a_ncookies = NULL; + vargs.a_cookies = NULL; + + while (!eofflag) { + auio.uio_resid = DIRBLKSIZ; + aiov.iov_base = dirbuf; + aiov.iov_len = DIRBLKSIZ; + error = ufs_readdir(&vargs); + if (error) { + printf("ufs_extattr_iterate_directory: ufs_readdir " + "%d\n", error); + return (error); + } + + edp = (struct dirent *)&dirbuf[DIRBLKSIZ - auio.uio_resid]; + for (dp = (struct dirent *)dirbuf; dp < edp; ) { + if (dp->d_reclen == 0) + break; + error = ufs_extattr_lookup(dvp, UE_GETDIR_LOCKPARENT, + dp->d_name, &attr_vp, td); + if (error) { + printf("ufs_extattr_iterate_directory: lookup " + "%s %d\n", dp->d_name, error); + } else if (attr_vp == dvp) { + vrele(attr_vp); + } else if (attr_vp->v_type != VREG) { + vput(attr_vp); + } else { + error = ufs_extattr_enable_with_open(ump, + attr_vp, attrnamespace, dp->d_name, td); + vrele(attr_vp); + if (error) { + printf("ufs_extattr_iterate_directory: " + "enable %s %d\n", dp->d_name, + error); + } else if (bootverbose) { + printf("UFS autostarted EA %s\n", + dp->d_name); + } + } + dp = (struct dirent *) ((char *)dp + dp->d_reclen); + if (dp >= edp) + break; + } + } + free(dirbuf, M_TEMP); + + return (0); +} + +/* + * Auto-start of extended attributes, to be executed (optionally) at + * mount-time. + */ +int +ufs_extattr_autostart(struct mount *mp, struct thread *td) +{ + struct ufsmount *ump; + int error; + + ump = VFSTOUFS(mp); + ufs_extattr_uepm_lock(ump); + error = ufs_extattr_autostart_locked(mp, td); + ufs_extattr_uepm_unlock(ump); + return (error); +} + +static int +ufs_extattr_autostart_locked(struct mount *mp, struct thread *td) +{ + struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp; + struct ufsmount *ump = VFSTOUFS(mp); + int error; + + /* + * UFS_EXTATTR applies only to UFS1, as UFS2 uses native extended + * attributes, so don't autostart. + */ + if (ump->um_fstype != UFS1) + return (0); + + /* + * Does UFS_EXTATTR_FSROOTSUBDIR exist off the filesystem root? + * If so, automatically start EA's. + */ + error = VFS_ROOT(mp, LK_EXCLUSIVE, &rvp); + if (error) { + printf("ufs_extattr_autostart.VFS_ROOT() returned %d\n", + error); + return (error); + } + + error = ufs_extattr_lookup(rvp, UE_GETDIR_LOCKPARENT_DONT, + UFS_EXTATTR_FSROOTSUBDIR, &attr_dvp, td); + if (error) { + /* rvp ref'd but now unlocked */ + vrele(rvp); + return (error); + } + if (rvp == attr_dvp) { + /* Should never happen. */ + vput(rvp); + vrele(attr_dvp); + return (EINVAL); + } + vrele(rvp); + + if (attr_dvp->v_type != VDIR) { + printf("ufs_extattr_autostart: %s != VDIR\n", + UFS_EXTATTR_FSROOTSUBDIR); + goto return_vput_attr_dvp; + } + + error = ufs_extattr_start_locked(ump, td); + if (error) { + printf("ufs_extattr_autostart: ufs_extattr_start failed (%d)\n", + error); + goto return_vput_attr_dvp; + } + + /* + * Look for two subdirectories: UFS_EXTATTR_SUBDIR_SYSTEM, + * UFS_EXTATTR_SUBDIR_USER. For each, iterate over the sub-directory, + * and start with appropriate type. Failures in either don't + * result in an over-all failure. attr_dvp is left locked to + * be cleaned up on exit. + */ + error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT, + UFS_EXTATTR_SUBDIR_SYSTEM, &attr_system_dvp, td); + if (!error) { + error = ufs_extattr_iterate_directory(VFSTOUFS(mp), + attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, td); + if (error) + printf("ufs_extattr_iterate_directory returned %d\n", + error); + vput(attr_system_dvp); + } + + error = ufs_extattr_lookup(attr_dvp, UE_GETDIR_LOCKPARENT, + UFS_EXTATTR_SUBDIR_USER, &attr_user_dvp, td); + if (!error) { + error = ufs_extattr_iterate_directory(VFSTOUFS(mp), + attr_user_dvp, EXTATTR_NAMESPACE_USER, td); + if (error) + printf("ufs_extattr_iterate_directory returned %d\n", + error); + vput(attr_user_dvp); + } + + /* Mask startup failures in sub-directories. */ + error = 0; + +return_vput_attr_dvp: + vput(attr_dvp); + + return (error); +} +#endif /* !UFS_EXTATTR_AUTOSTART */ + +/* + * Stop extended attribute support on an FS. + */ +int +ufs_extattr_stop(struct mount *mp, struct thread *td) +{ + struct ufs_extattr_list_entry *uele; + struct ufsmount *ump = VFSTOUFS(mp); + int error = 0; + + ufs_extattr_uepm_lock(ump); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) { + error = EOPNOTSUPP; + goto unlock; + } + + while ((uele = LIST_FIRST(&ump->um_extattr.uepm_list)) != NULL) { + ufs_extattr_disable(ump, uele->uele_attrnamespace, + uele->uele_attrname, td); + } + + ump->um_extattr.uepm_flags &= ~UFS_EXTATTR_UEPM_STARTED; + + crfree(ump->um_extattr.uepm_ucred); + ump->um_extattr.uepm_ucred = NULL; + +unlock: + ufs_extattr_uepm_unlock(ump); + + return (error); +} + +/* + * Enable a named attribute on the specified filesystem; provide an + * unlocked backing vnode to hold the attribute data. + */ +static int +ufs_extattr_enable(struct ufsmount *ump, int attrnamespace, + const char *attrname, struct vnode *backing_vnode, struct thread *td) +{ + struct ufs_extattr_list_entry *attribute; + struct iovec aiov; + struct uio auio; + int error = 0; + + if (!ufs_extattr_valid_attrname(attrnamespace, attrname)) + return (EINVAL); + if (backing_vnode->v_type != VREG) + return (EINVAL); + + attribute = malloc(sizeof(struct ufs_extattr_list_entry), + M_UFS_EXTATTR, M_WAITOK); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) { + error = EOPNOTSUPP; + goto free_exit; + } + + if (ufs_extattr_find_attr(ump, attrnamespace, attrname)) { + error = EEXIST; + goto free_exit; + } + + strncpy(attribute->uele_attrname, attrname, + UFS_EXTATTR_MAXEXTATTRNAME); + attribute->uele_attrnamespace = attrnamespace; + bzero(&attribute->uele_fileheader, + sizeof(struct ufs_extattr_fileheader)); + + attribute->uele_backing_vnode = backing_vnode; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = (caddr_t) &attribute->uele_fileheader; + aiov.iov_len = sizeof(struct ufs_extattr_fileheader); + auio.uio_resid = sizeof(struct ufs_extattr_fileheader); + auio.uio_offset = (off_t) 0; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_READ; + auio.uio_td = td; + + vn_lock(backing_vnode, LK_SHARED | LK_RETRY); + error = VOP_READ(backing_vnode, &auio, IO_NODELOCKED, + ump->um_extattr.uepm_ucred); + + if (error) + goto unlock_free_exit; + + if (auio.uio_resid != 0) { + printf("ufs_extattr_enable: malformed attribute header\n"); + error = EINVAL; + goto unlock_free_exit; + } + + if (attribute->uele_fileheader.uef_magic != UFS_EXTATTR_MAGIC) { + printf("ufs_extattr_enable: invalid attribute header magic\n"); + error = EINVAL; + goto unlock_free_exit; + } + + if (attribute->uele_fileheader.uef_version != UFS_EXTATTR_VERSION) { + printf("ufs_extattr_enable: incorrect attribute header " + "version\n"); + error = EINVAL; + goto unlock_free_exit; + } + + ASSERT_VOP_LOCKED(backing_vnode, "ufs_extattr_enable"); + LIST_INSERT_HEAD(&ump->um_extattr.uepm_list, attribute, + uele_entries); + + VOP_UNLOCK(backing_vnode, 0); + return (0); + +unlock_free_exit: + VOP_UNLOCK(backing_vnode, 0); + +free_exit: + free(attribute, M_UFS_EXTATTR); + return (error); +} + +/* + * Disable extended attribute support on an FS. + */ +static int +ufs_extattr_disable(struct ufsmount *ump, int attrnamespace, + const char *attrname, struct thread *td) +{ + struct ufs_extattr_list_entry *uele; + int error = 0; + + if (!ufs_extattr_valid_attrname(attrnamespace, attrname)) + return (EINVAL); + + uele = ufs_extattr_find_attr(ump, attrnamespace, attrname); + if (!uele) + return (ENOATTR); + + LIST_REMOVE(uele, uele_entries); + + vn_lock(uele->uele_backing_vnode, LK_SHARED | LK_RETRY); + ASSERT_VOP_LOCKED(uele->uele_backing_vnode, "ufs_extattr_disable"); + VOP_UNLOCK(uele->uele_backing_vnode, 0); + error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE, + td->td_ucred, td); + + free(uele, M_UFS_EXTATTR); + + return (error); +} + +/* + * VFS call to manage extended attributes in UFS. If filename_vp is + * non-NULL, it must be passed in locked, and regardless of errors in + * processing, will be unlocked. + */ +int +ufs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, + int attrnamespace, const char *attrname) +{ + struct ufsmount *ump = VFSTOUFS(mp); + struct thread *td = curthread; + int error; + + /* + * Processes with privilege, but in jail, are not allowed to + * configure extended attributes. + */ + error = priv_check(td, PRIV_UFS_EXTATTRCTL); + if (error) { + if (filename_vp != NULL) + VOP_UNLOCK(filename_vp, 0); + return (error); + } + + /* + * We only allow extattrctl(2) on UFS1 file systems, as UFS2 uses + * native extended attributes. + */ + if (ump->um_fstype != UFS1) { + if (filename_vp != NULL) + VOP_UNLOCK(filename_vp, 0); + return (EOPNOTSUPP); + } + + switch(cmd) { + case UFS_EXTATTR_CMD_START: + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0); + return (EINVAL); + } + if (attrname != NULL) + return (EINVAL); + + error = ufs_extattr_start(mp, td); + + return (error); + + case UFS_EXTATTR_CMD_STOP: + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0); + return (EINVAL); + } + if (attrname != NULL) + return (EINVAL); + + error = ufs_extattr_stop(mp, td); + + return (error); + + case UFS_EXTATTR_CMD_ENABLE: + + if (filename_vp == NULL) + return (EINVAL); + if (attrname == NULL) { + VOP_UNLOCK(filename_vp, 0); + return (EINVAL); + } + + /* + * ufs_extattr_enable_with_open() will always unlock the + * vnode, regardless of failure. + */ + ufs_extattr_uepm_lock(ump); + error = ufs_extattr_enable_with_open(ump, filename_vp, + attrnamespace, attrname, td); + ufs_extattr_uepm_unlock(ump); + + return (error); + + case UFS_EXTATTR_CMD_DISABLE: + + if (filename_vp != NULL) { + VOP_UNLOCK(filename_vp, 0); + return (EINVAL); + } + if (attrname == NULL) + return (EINVAL); + + ufs_extattr_uepm_lock(ump); + error = ufs_extattr_disable(ump, attrnamespace, attrname, + td); + ufs_extattr_uepm_unlock(ump); + + return (error); + + default: + return (EINVAL); + } +} + +/* + * Vnode operating to retrieve a named extended attribute. + */ +int +ufs_getextattr(struct vop_getextattr_args *ap) +/* +vop_getextattr { + IN struct vnode *a_vp; + IN int a_attrnamespace; + IN const char *a_name; + INOUT struct uio *a_uio; + OUT size_t *a_size; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct mount *mp = ap->a_vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + int error; + + ufs_extattr_uepm_lock(ump); + + error = ufs_extattr_get(ap->a_vp, ap->a_attrnamespace, ap->a_name, + ap->a_uio, ap->a_size, ap->a_cred, ap->a_td); + + ufs_extattr_uepm_unlock(ump); + + return (error); +} + +/* + * Real work associated with retrieving a named attribute--assumes that + * the attribute lock has already been grabbed. + */ +static int +ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name, + struct uio *uio, size_t *size, struct ucred *cred, struct thread *td) +{ + struct ufs_extattr_list_entry *attribute; + struct ufs_extattr_header ueh; + struct iovec local_aiov; + struct uio local_aio; + struct mount *mp = vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + struct inode *ip = VTOI(vp); + off_t base_offset; + size_t len, old_len; + int error = 0; + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + + if (strlen(name) == 0) + return (EINVAL); + + error = extattr_check_cred(vp, attrnamespace, cred, td, VREAD); + if (error) + return (error); + + attribute = ufs_extattr_find_attr(ump, attrnamespace, name); + if (!attribute) + return (ENOATTR); + + /* + * Allow only offsets of zero to encourage the read/replace + * extended attribute semantic. Otherwise we can't guarantee + * atomicity, as we don't provide locks for extended attributes. + */ + if (uio != NULL && uio->uio_offset != 0) + return (ENXIO); + + /* + * Find base offset of header in file based on file header size, and + * data header size + maximum data size, indexed by inode number. + */ + base_offset = sizeof(struct ufs_extattr_fileheader) + + ip->i_number * (sizeof(struct ufs_extattr_header) + + attribute->uele_fileheader.uef_size); + + /* + * Read in the data header to see if the data is defined, and if so + * how much. + */ + bzero(&ueh, sizeof(struct ufs_extattr_header)); + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct ufs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_READ; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_td = td; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct ufs_extattr_header); + + /* + * Acquire locks. + * + * Don't need to get a lock on the backing file if the getattr is + * being applied to the backing file, as the lock is already held. + */ + if (attribute->uele_backing_vnode != vp) + vn_lock(attribute->uele_backing_vnode, LK_SHARED | LK_RETRY); + + error = VOP_READ(attribute->uele_backing_vnode, &local_aio, + IO_NODELOCKED, ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + /* Defined? */ + if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) { + error = ENOATTR; + goto vopunlock_exit; + } + + /* Valid for the current inode generation? */ + if (ueh.ueh_i_gen != ip->i_gen) { + /* + * The inode itself has a different generation number + * than the attribute data. For now, the best solution + * is to coerce this to undefined, and let it get cleaned + * up by the next write or extattrctl clean. + */ + printf("ufs_extattr_get (%s): inode number inconsistency (%d, %ju)\n", + mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (uintmax_t)ip->i_gen); + error = ENOATTR; + goto vopunlock_exit; + } + + /* Local size consistency check. */ + if (ueh.ueh_len > attribute->uele_fileheader.uef_size) { + error = ENXIO; + goto vopunlock_exit; + } + + /* Return full data size if caller requested it. */ + if (size != NULL) + *size = ueh.ueh_len; + + /* Return data if the caller requested it. */ + if (uio != NULL) { + /* Allow for offset into the attribute data. */ + uio->uio_offset = base_offset + sizeof(struct + ufs_extattr_header); + + /* + * Figure out maximum to transfer -- use buffer size and + * local data limit. + */ + len = MIN(uio->uio_resid, ueh.ueh_len); + old_len = uio->uio_resid; + uio->uio_resid = len; + + error = VOP_READ(attribute->uele_backing_vnode, uio, + IO_NODELOCKED, ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + uio->uio_resid = old_len - (len - uio->uio_resid); + } + +vopunlock_exit: + + if (uio != NULL) + uio->uio_offset = 0; + + if (attribute->uele_backing_vnode != vp) + VOP_UNLOCK(attribute->uele_backing_vnode, 0); + + return (error); +} + +/* + * Vnode operation to remove a named attribute. + */ +int +ufs_deleteextattr(struct vop_deleteextattr_args *ap) +/* +vop_deleteextattr { + IN struct vnode *a_vp; + IN int a_attrnamespace; + IN const char *a_name; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct mount *mp = ap->a_vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + int error; + + ufs_extattr_uepm_lock(ump); + + error = ufs_extattr_rm(ap->a_vp, ap->a_attrnamespace, ap->a_name, + ap->a_cred, ap->a_td); + + + ufs_extattr_uepm_unlock(ump); + + return (error); +} + +/* + * Vnode operation to set a named attribute. + */ +int +ufs_setextattr(struct vop_setextattr_args *ap) +/* +vop_setextattr { + IN struct vnode *a_vp; + IN int a_attrnamespace; + IN const char *a_name; + INOUT struct uio *a_uio; + IN struct ucred *a_cred; + IN struct thread *a_td; +}; +*/ +{ + struct mount *mp = ap->a_vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + int error; + + /* + * XXX: No longer a supported way to delete extended attributes. + */ + if (ap->a_uio == NULL) + return (EINVAL); + + ufs_extattr_uepm_lock(ump); + + error = ufs_extattr_set(ap->a_vp, ap->a_attrnamespace, ap->a_name, + ap->a_uio, ap->a_cred, ap->a_td); + + ufs_extattr_uepm_unlock(ump); + + return (error); +} + +/* + * Real work associated with setting a vnode's extended attributes; + * assumes that the attribute lock has already been grabbed. + */ +static int +ufs_extattr_set(struct vnode *vp, int attrnamespace, const char *name, + struct uio *uio, struct ucred *cred, struct thread *td) +{ + struct ufs_extattr_list_entry *attribute; + struct ufs_extattr_header ueh; + struct iovec local_aiov; + struct uio local_aio; + struct mount *mp = vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + struct inode *ip = VTOI(vp); + off_t base_offset; + int error = 0, ioflag; + + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + if (!ufs_extattr_valid_attrname(attrnamespace, name)) + return (EINVAL); + + error = extattr_check_cred(vp, attrnamespace, cred, td, VWRITE); + if (error) + return (error); + + attribute = ufs_extattr_find_attr(ump, attrnamespace, name); + if (!attribute) + return (ENOATTR); + + /* + * Early rejection of invalid offsets/length. + * Reject: any offset but 0 (replace) + * Any size greater than attribute size limit + */ + if (uio->uio_offset != 0 || + uio->uio_resid > attribute->uele_fileheader.uef_size) + return (ENXIO); + + /* + * Find base offset of header in file based on file header size, and + * data header size + maximum data size, indexed by inode number. + */ + base_offset = sizeof(struct ufs_extattr_fileheader) + + ip->i_number * (sizeof(struct ufs_extattr_header) + + attribute->uele_fileheader.uef_size); + + /* + * Write out a data header for the data. + */ + ueh.ueh_len = uio->uio_resid; + ueh.ueh_flags = UFS_EXTATTR_ATTR_FLAG_INUSE; + ueh.ueh_i_gen = ip->i_gen; + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct ufs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_WRITE; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_td = td; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct ufs_extattr_header); + + /* + * Acquire locks. + * + * Don't need to get a lock on the backing file if the setattr is + * being applied to the backing file, as the lock is already held. + */ + if (attribute->uele_backing_vnode != vp) + vn_lock(attribute->uele_backing_vnode, LK_EXCLUSIVE | LK_RETRY); + + ioflag = IO_NODELOCKED; + if (ufs_extattr_sync) + ioflag |= IO_SYNC; + error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag, + ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + if (local_aio.uio_resid != 0) { + error = ENXIO; + goto vopunlock_exit; + } + + /* + * Write out user data. + */ + uio->uio_offset = base_offset + sizeof(struct ufs_extattr_header); + + ioflag = IO_NODELOCKED; + if (ufs_extattr_sync) + ioflag |= IO_SYNC; + error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag, + ump->um_extattr.uepm_ucred); + +vopunlock_exit: + uio->uio_offset = 0; + + if (attribute->uele_backing_vnode != vp) + VOP_UNLOCK(attribute->uele_backing_vnode, 0); + + return (error); +} + +/* + * Real work associated with removing an extended attribute from a vnode. + * Assumes the attribute lock has already been grabbed. + */ +static int +ufs_extattr_rm(struct vnode *vp, int attrnamespace, const char *name, + struct ucred *cred, struct thread *td) +{ + struct ufs_extattr_list_entry *attribute; + struct ufs_extattr_header ueh; + struct iovec local_aiov; + struct uio local_aio; + struct mount *mp = vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + struct inode *ip = VTOI(vp); + off_t base_offset; + int error = 0, ioflag; + + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) + return (EOPNOTSUPP); + if (!ufs_extattr_valid_attrname(attrnamespace, name)) + return (EINVAL); + + error = extattr_check_cred(vp, attrnamespace, cred, td, VWRITE); + if (error) + return (error); + + attribute = ufs_extattr_find_attr(ump, attrnamespace, name); + if (!attribute) + return (ENOATTR); + + /* + * Find base offset of header in file based on file header size, and + * data header size + maximum data size, indexed by inode number. + */ + base_offset = sizeof(struct ufs_extattr_fileheader) + + ip->i_number * (sizeof(struct ufs_extattr_header) + + attribute->uele_fileheader.uef_size); + + /* + * Check to see if currently defined. + */ + bzero(&ueh, sizeof(struct ufs_extattr_header)); + + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct ufs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_READ; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_td = td; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct ufs_extattr_header); + + /* + * Don't need to get the lock on the backing vnode if the vnode we're + * modifying is it, as we already hold the lock. + */ + if (attribute->uele_backing_vnode != vp) + vn_lock(attribute->uele_backing_vnode, LK_EXCLUSIVE | LK_RETRY); + + error = VOP_READ(attribute->uele_backing_vnode, &local_aio, + IO_NODELOCKED, ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + /* Defined? */ + if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) { + error = ENOATTR; + goto vopunlock_exit; + } + + /* Valid for the current inode generation? */ + if (ueh.ueh_i_gen != ip->i_gen) { + /* + * The inode itself has a different generation number than + * the attribute data. For now, the best solution is to + * coerce this to undefined, and let it get cleaned up by + * the next write or extattrctl clean. + */ + printf("ufs_extattr_rm (%s): inode number inconsistency (%d, %jd)\n", + mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen); + error = ENOATTR; + goto vopunlock_exit; + } + + /* Flag it as not in use. */ + ueh.ueh_flags = 0; + ueh.ueh_len = 0; + + local_aiov.iov_base = (caddr_t) &ueh; + local_aiov.iov_len = sizeof(struct ufs_extattr_header); + local_aio.uio_iov = &local_aiov; + local_aio.uio_iovcnt = 1; + local_aio.uio_rw = UIO_WRITE; + local_aio.uio_segflg = UIO_SYSSPACE; + local_aio.uio_td = td; + local_aio.uio_offset = base_offset; + local_aio.uio_resid = sizeof(struct ufs_extattr_header); + + ioflag = IO_NODELOCKED; + if (ufs_extattr_sync) + ioflag |= IO_SYNC; + error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag, + ump->um_extattr.uepm_ucred); + if (error) + goto vopunlock_exit; + + if (local_aio.uio_resid != 0) + error = ENXIO; + +vopunlock_exit: + VOP_UNLOCK(attribute->uele_backing_vnode, 0); + + return (error); +} + +/* + * Called by UFS when an inode is no longer active and should have its + * attributes stripped. + */ +void +ufs_extattr_vnode_inactive(struct vnode *vp, struct thread *td) +{ + struct ufs_extattr_list_entry *uele; + struct mount *mp = vp->v_mount; + struct ufsmount *ump = VFSTOUFS(mp); + + /* + * In that case, we cannot lock. We should not have any active vnodes + * on the fs if this is not yet initialized but is going to be, so + * this can go unlocked. + */ + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_INITIALIZED)) + return; + + ufs_extattr_uepm_lock(ump); + + if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) { + ufs_extattr_uepm_unlock(ump); + return; + } + + LIST_FOREACH(uele, &ump->um_extattr.uepm_list, uele_entries) + ufs_extattr_rm(vp, uele->uele_attrnamespace, + uele->uele_attrname, NULL, td); + + ufs_extattr_uepm_unlock(ump); +} + +#endif /* !UFS_EXTATTR */ diff --git a/Dump/ufs/ufs/ufs_extern.h b/Dump/ufs/ufs/ufs_extern.h new file mode 100644 index 0000000..ea2ee8a --- /dev/null +++ b/Dump/ufs/ufs/ufs_extern.h @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_extern.h 8.10 (Berkeley) 5/14/95 + * $FreeBSD: releng/11.2/sys/ufs/ufs/ufs_extern.h 331722 2018-03-29 02:50:57Z eadler $ + */ + +#ifndef _UFS_UFS_EXTERN_H_ +#define _UFS_UFS_EXTERN_H_ + +struct componentname; +struct direct; +struct indir; +struct inode; +struct mount; +struct thread; +struct sockaddr; +struct ucred; +struct ufid; +struct vfsconf; +struct vnode; +struct vop_bmap_args; +struct vop_cachedlookup_args; +struct vop_generic_args; +struct vop_inactive_args; +struct vop_reclaim_args; + +extern struct vop_vector ufs_fifoops; +extern struct vop_vector ufs_vnodeops; + +int ufs_bmap(struct vop_bmap_args *); +int ufs_bmaparray(struct vnode *, ufs2_daddr_t, ufs2_daddr_t *, + struct buf *, int *, int *); +int ufs_fhtovp(struct mount *, struct ufid *, int, struct vnode **); +int ufs_checkpath(ino_t, ino_t, struct inode *, struct ucred *, ino_t *); +void ufs_dirbad(struct inode *, doff_t, char *); +int ufs_dirbadentry(struct vnode *, struct direct *, int); +int ufs_dirempty(struct inode *, ino_t, struct ucred *); +int ufs_extread(struct vop_read_args *); +int ufs_extwrite(struct vop_write_args *); +void ufs_makedirentry(struct inode *, struct componentname *, + struct direct *); +int ufs_direnter(struct vnode *, struct vnode *, struct direct *, + struct componentname *, struct buf *, int); +int ufs_dirremove(struct vnode *, struct inode *, int, int); +int ufs_dirrewrite(struct inode *, struct inode *, ino_t, int, int); +int ufs_lookup_ino(struct vnode *, struct vnode **, struct componentname *, + ino_t *); +int ufs_getlbns(struct vnode *, ufs2_daddr_t, struct indir *, int *); +int ufs_inactive(struct vop_inactive_args *); +int ufs_init(struct vfsconf *); +void ufs_itimes(struct vnode *vp); +int ufs_lookup(struct vop_cachedlookup_args *); +void ufs_prepare_reclaim(struct vnode *vp); +int ufs_readdir(struct vop_readdir_args *); +int ufs_reclaim(struct vop_reclaim_args *); +void ffs_snapgone(struct inode *); +vfs_root_t ufs_root; +int ufs_uninit(struct vfsconf *); +int ufs_vinit(struct mount *, struct vop_vector *, struct vnode **); + +#include +SYSCTL_DECL(_vfs_ufs); + +/* + * Soft update function prototypes. + */ +int softdep_setup_directory_add(struct buf *, struct inode *, off_t, + ino_t, struct buf *, int); +void softdep_change_directoryentry_offset(struct buf *, struct inode *, + caddr_t, caddr_t, caddr_t, int); +void softdep_setup_remove(struct buf *,struct inode *, struct inode *, int); +void softdep_setup_directory_change(struct buf *, struct inode *, + struct inode *, ino_t, int); +void softdep_change_linkcnt(struct inode *); +int softdep_slowdown(struct vnode *); +void softdep_setup_create(struct inode *, struct inode *); +void softdep_setup_dotdot_link(struct inode *, struct inode *); +void softdep_setup_link(struct inode *, struct inode *); +void softdep_setup_mkdir(struct inode *, struct inode *); +void softdep_setup_rmdir(struct inode *, struct inode *); +void softdep_setup_unlink(struct inode *, struct inode *); +void softdep_revert_create(struct inode *, struct inode *); +void softdep_revert_link(struct inode *, struct inode *); +void softdep_revert_mkdir(struct inode *, struct inode *); +void softdep_revert_rmdir(struct inode *, struct inode *); + +/* + * Flags to low-level allocation routines. The low 16-bits are reserved + * for IO_ flags from vnode.h. + * + * Note: The general vfs code typically limits the sequential heuristic + * count to 127. See sequential_heuristic() in kern/vfs_vnops.c + */ +#define BA_CLRBUF 0x00010000 /* Clear invalid areas of buffer. */ +#define BA_METAONLY 0x00020000 /* Return indirect block buffer. */ +#define BA_UNMAPPED 0x00040000 /* Do not mmap resulted buffer. */ +#define BA_SEQMASK 0x7F000000 /* Bits holding seq heuristic. */ +#define BA_SEQSHIFT 24 +#define BA_SEQMAX 0x7F + +#endif /* !_UFS_UFS_EXTERN_H_ */ diff --git a/Dump/ufs/ufs/ufs_gjournal.c b/Dump/ufs/ufs/ufs_gjournal.c new file mode 100644 index 0000000..fd4c584 --- /dev/null +++ b/Dump/ufs/ufs/ufs_gjournal.c @@ -0,0 +1,141 @@ +/*- + * Copyright (c) 2005-2006 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_gjournal.c 306627 2016-10-03 09:37:56Z kib $"); + +#include "opt_ufs.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/* + * Change the number of unreferenced inodes. + */ +static int +ufs_gjournal_modref(struct vnode *vp, int count) +{ + struct cg *cgp; + struct buf *bp; + ufs2_daddr_t cgbno; + int error, cg; + struct cdev *dev; + struct inode *ip; + struct ufsmount *ump; + struct fs *fs; + struct vnode *devvp; + ino_t ino; + + ip = VTOI(vp); + ump = VFSTOUFS(vp->v_mount); + fs = ump->um_fs; + devvp = ump->um_devvp; + ino = ip->i_number; + + cg = ino_to_cg(fs, ino); + if (devvp->v_type == VREG) { + /* devvp is a snapshot */ + dev = VFSTOUFS(devvp->v_mount)->um_devvp->v_rdev; + cgbno = fragstoblks(fs, cgtod(fs, cg)); + } else if (devvp->v_type == VCHR) { + /* devvp is a normal disk device */ + dev = devvp->v_rdev; + cgbno = fsbtodb(fs, cgtod(fs, cg)); + } else { + bp = NULL; + return (EIO); + } + if ((u_int)ino >= fs->fs_ipg * fs->fs_ncg) + panic("ufs_gjournal_modref: range: dev = %s, ino = %lu, fs = %s", + devtoname(dev), (u_long)ino, fs->fs_fsmnt); + if ((error = bread(devvp, cgbno, (int)fs->fs_cgsize, NOCRED, &bp))) { + brelse(bp); + return (error); + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) { + brelse(bp); + return (0); + } + bp->b_xflags |= BX_BKGRDWRITE; + cgp->cg_unrefs += count; + UFS_LOCK(ump); + fs->fs_unrefs += count; + fs->fs_fmod = 1; + ACTIVECLEAR(fs, cg); + UFS_UNLOCK(ump); + bdwrite(bp); + return (0); +} + +void +ufs_gjournal_orphan(struct vnode *vp) +{ + struct inode *ip; + + if (vp->v_mount->mnt_gjprovider == NULL) + return; + if (vp->v_usecount < 2 || (vp->v_vflag & VV_DELETED)) + return; + ip = VTOI(vp); + if ((vp->v_type == VDIR && ip->i_nlink > 2) || + (vp->v_type != VDIR && ip->i_nlink > 1)) { + return; + } + vp->v_vflag |= VV_DELETED; + + ufs_gjournal_modref(vp, 1); +} + +void +ufs_gjournal_close(struct vnode *vp) +{ + struct inode *ip; + + if (vp->v_mount->mnt_gjprovider == NULL) + return; + if (!(vp->v_vflag & VV_DELETED)) + return; + ip = VTOI(vp); + if (ip->i_nlink > 0) + return; + ufs_gjournal_modref(vp, -1); +} diff --git a/Dump/ufs/ufs/ufs_inode.c b/Dump/ufs/ufs/ufs_inode.c new file mode 100644 index 0000000..46a11d9 --- /dev/null +++ b/Dump/ufs/ufs/ufs_inode.c @@ -0,0 +1,237 @@ +/*- + * Copyright (c) 1991, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_inode.c 8.9 (Berkeley) 5/14/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_inode.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include "opt_quota.h" +#include "opt_ufs.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef UFS_DIRHASH +#include +#include +#endif +#ifdef UFS_GJOURNAL +#include +#endif + +/* + * Last reference to an inode. If necessary, write or delete it. + */ +int +ufs_inactive(ap) + struct vop_inactive_args /* { + struct vnode *a_vp; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + mode_t mode; + int error = 0; + off_t isize; + struct mount *mp; + + mp = NULL; + /* + * Ignore inodes related to stale file handles. + */ + if (ip->i_mode == 0) + goto out; +#ifdef UFS_GJOURNAL + ufs_gjournal_close(vp); +#endif +#ifdef QUOTA + /* + * Before moving off the active list, we must be sure that + * any modified quotas have been pushed since these will no + * longer be checked once the vnode is on the inactive list. + */ + qsyncvp(vp); +#endif + if ((ip->i_effnlink == 0 && DOINGSOFTDEP(vp)) || + (ip->i_nlink <= 0 && !UFS_RDONLY(ip))) { + loop: + if (vn_start_secondary_write(vp, &mp, V_NOWAIT) != 0) { + /* Cannot delete file while file system is suspended */ + if ((vp->v_iflag & VI_DOOMED) != 0) { + /* Cannot return before file is deleted */ + (void) vn_start_secondary_write(vp, &mp, + V_WAIT); + } else { + MNT_ILOCK(mp); + if ((mp->mnt_kern_flag & + (MNTK_SUSPEND2 | MNTK_SUSPENDED)) == 0) { + MNT_IUNLOCK(mp); + goto loop; + } + /* + * Fail to inactivate vnode now and + * let ffs_snapshot() clean up after + * it has resumed the file system. + */ + VI_LOCK(vp); + vp->v_iflag |= VI_OWEINACT; + VI_UNLOCK(vp); + MNT_IUNLOCK(mp); + return (0); + } + } + } + isize = ip->i_size; + if (I_IS_UFS2(ip)) + isize += ip->i_din2->di_extsize; + if (ip->i_effnlink <= 0 && isize && !UFS_RDONLY(ip)) + error = UFS_TRUNCATE(vp, (off_t)0, IO_EXT | IO_NORMAL, NOCRED); + if (ip->i_nlink <= 0 && ip->i_mode && !UFS_RDONLY(ip)) { +#ifdef QUOTA + if (!getinoquota(ip)) + (void)chkiq(ip, -1, NOCRED, FORCE); +#endif +#ifdef UFS_EXTATTR + ufs_extattr_vnode_inactive(vp, ap->a_td); +#endif + /* + * Setting the mode to zero needs to wait for the inode + * to be written just as does a change to the link count. + * So, rather than creating a new entry point to do the + * same thing, we just use softdep_change_linkcnt(). + */ + DIP_SET(ip, i_rdev, 0); + mode = ip->i_mode; + ip->i_mode = 0; + DIP_SET(ip, i_mode, 0); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + if (DOINGSOFTDEP(vp)) + softdep_change_linkcnt(ip); + UFS_VFREE(vp, ip->i_number, mode); + } + if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { + if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 && + mp == NULL && + vn_start_secondary_write(vp, &mp, V_NOWAIT)) { + mp = NULL; + ip->i_flag &= ~IN_ACCESS; + } else { + if (mp == NULL) + (void) vn_start_secondary_write(vp, &mp, + V_WAIT); + UFS_UPDATE(vp, 0); + } + } +out: + /* + * If we are done with the inode, reclaim it + * so that it can be reused immediately. + */ + if (ip->i_mode == 0) + vrecycle(vp); + if (mp != NULL) + vn_finished_secondary_write(mp); + return (error); +} + +void +ufs_prepare_reclaim(struct vnode *vp) +{ + struct inode *ip; +#ifdef QUOTA + int i; +#endif + + ip = VTOI(vp); + + vnode_destroy_vobject(vp); +#ifdef QUOTA + for (i = 0; i < MAXQUOTAS; i++) { + if (ip->i_dquot[i] != NODQUOT) { + dqrele(vp, ip->i_dquot[i]); + ip->i_dquot[i] = NODQUOT; + } + } +#endif +#ifdef UFS_DIRHASH + if (ip->i_dirhash != NULL) + ufsdirhash_free(ip); +#endif +} + +/* + * Reclaim an inode so that it can be used for other purposes. + */ +int +ufs_reclaim(ap) + struct vop_reclaim_args /* { + struct vnode *a_vp; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + + ufs_prepare_reclaim(vp); + + if (ip->i_flag & IN_LAZYMOD) + ip->i_flag |= IN_MODIFIED; + UFS_UPDATE(vp, 0); + /* + * Remove the inode from its hash chain. + */ + vfs_hash_remove(vp); + + /* + * Lock the clearing of v_data so ffs_lock() can inspect it + * prior to obtaining the lock. + */ + VI_LOCK(vp); + vp->v_data = 0; + VI_UNLOCK(vp); + UFS_IFREE(ITOUMP(ip), ip); + return (0); +} diff --git a/Dump/ufs/ufs/ufs_lookup.c b/Dump/ufs/ufs/ufs_lookup.c new file mode 100644 index 0000000..5c9967b --- /dev/null +++ b/Dump/ufs/ufs/ufs_lookup.c @@ -0,0 +1,1486 @@ +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_lookup.c 8.15 (Berkeley) 6/16/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_lookup.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include "opt_ufs.h" +#include "opt_quota.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#ifdef UFS_DIRHASH +#include +#endif +#include +#include + +#ifdef DIAGNOSTIC +static int dirchk = 1; +#else +static int dirchk = 0; +#endif + +SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); + +/* true if old FS format...*/ +#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0) + +static int +ufs_delete_denied(struct vnode *vdp, struct vnode *tdp, struct ucred *cred, + struct thread *td) +{ + int error; + +#ifdef UFS_ACL + /* + * NFSv4 Minor Version 1, draft-ietf-nfsv4-minorversion1-03.txt + * + * 3.16.2.1. ACE4_DELETE vs. ACE4_DELETE_CHILD + */ + + /* + * XXX: Is this check required? + */ + error = VOP_ACCESS(vdp, VEXEC, cred, td); + if (error) + return (error); + + error = VOP_ACCESSX(tdp, VDELETE, cred, td); + if (error == 0) + return (0); + + error = VOP_ACCESSX(vdp, VDELETE_CHILD, cred, td); + if (error == 0) + return (0); + + error = VOP_ACCESSX(vdp, VEXPLICIT_DENY | VDELETE_CHILD, cred, td); + if (error) + return (error); + +#endif /* !UFS_ACL */ + + /* + * Standard Unix access control - delete access requires VWRITE. + */ + error = VOP_ACCESS(vdp, VWRITE, cred, td); + if (error) + return (error); + + /* + * If directory is "sticky", then user must own + * the directory, or the file in it, else she + * may not delete it (unless she's root). This + * implements append-only directories. + */ + if ((VTOI(vdp)->i_mode & ISVTX) && + VOP_ACCESS(vdp, VADMIN, cred, td) && + VOP_ACCESS(tdp, VADMIN, cred, td)) + return (EPERM); + + return (0); +} + +/* + * Convert a component of a pathname into a pointer to a locked inode. + * This is a very central and rather complicated routine. + * If the filesystem is not maintained in a strict tree hierarchy, + * this can result in a deadlock situation (see comments in code below). + * + * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending + * on whether the name is to be looked up, created, renamed, or deleted. + * When CREATE, RENAME, or DELETE is specified, information usable in + * creating, renaming, or deleting a directory entry may be calculated. + * If flag has LOCKPARENT or'ed into it and the target of the pathname + * exists, lookup returns both the target and its parent directory locked. + * When creating or renaming and LOCKPARENT is specified, the target may + * not be ".". When deleting and LOCKPARENT is specified, the target may + * be "."., but the caller must check to ensure it does an vrele and vput + * instead of two vputs. + * + * This routine is actually used as VOP_CACHEDLOOKUP method, and the + * filesystem employs the generic vfs_cache_lookup() as VOP_LOOKUP + * method. + * + * vfs_cache_lookup() performs the following for us: + * check that it is a directory + * check accessibility of directory + * check for modification attempts on read-only mounts + * if name found in cache + * if at end of path and deleting or creating + * drop it + * else + * return name. + * return VOP_CACHEDLOOKUP() + * + * Overall outline of ufs_lookup: + * + * search for name in directory, to found or notfound + * notfound: + * if creating, return locked directory, leaving info on available slots + * else return error + * found: + * if at end of path and deleting, return information to allow delete + * if at end of path and rewriting (RENAME and LOCKPARENT), lock target + * inode and return info to allow rewrite + * if not at end, add name to cache; if at end and neither creating + * nor deleting, add name to cache + */ +int +ufs_lookup(ap) + struct vop_cachedlookup_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + } */ *ap; +{ + + return (ufs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL)); +} + +int +ufs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, + ino_t *dd_ino) +{ + struct inode *dp; /* inode for directory being searched */ + struct buf *bp; /* a buffer of directory entries */ + struct direct *ep; /* the current directory entry */ + int entryoffsetinblock; /* offset of ep in bp's buffer */ + enum {NONE, COMPACT, FOUND} slotstatus; + doff_t slotoffset; /* offset of area with free space */ + doff_t i_diroff; /* cached i_diroff value. */ + doff_t i_offset; /* cached i_offset value. */ + int slotsize; /* size of area at slotoffset */ + int slotfreespace; /* amount of space free in slot */ + int slotneeded; /* size of the entry we're seeking */ + int numdirpasses; /* strategy for directory search */ + doff_t endsearch; /* offset to end directory search */ + doff_t prevoff; /* prev entry dp->i_offset */ + struct vnode *pdp; /* saved dp during symlink work */ + struct vnode *tdp; /* returned by VFS_VGET */ + doff_t enduseful; /* pointer past last used dir slot */ + u_long bmask; /* block offset mask */ + int namlen, error; + struct ucred *cred = cnp->cn_cred; + int flags = cnp->cn_flags; + int nameiop = cnp->cn_nameiop; + ino_t ino, ino1; + int ltype; + + if (vpp != NULL) + *vpp = NULL; + + dp = VTOI(vdp); + if (dp->i_effnlink == 0) + return (ENOENT); + + /* + * Create a vm object if vmiodirenable is enabled. + * Alternatively we could call vnode_create_vobject + * in VFS_VGET but we could end up creating objects + * that are never used. + */ + vnode_create_vobject(vdp, DIP(dp, i_size), cnp->cn_thread); + + bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; + +#ifdef DEBUG_VFS_LOCKS + /* + * Assert that the directory vnode is locked, and locked + * exclusively for the last component lookup for modifying + * operations. + * + * The directory-modifying operations need to save + * intermediate state in the inode between namei() call and + * actual directory manipulations. See fields in the struct + * inode marked as 'used during directory lookup'. We must + * ensure that upgrade in namei() does not happen, since + * upgrade might need to unlock vdp. If quotas are enabled, + * getinoquota() also requires exclusive lock to modify inode. + */ + ASSERT_VOP_LOCKED(vdp, "ufs_lookup1"); + if ((nameiop == CREATE || nameiop == DELETE || nameiop == RENAME) && + (flags & (LOCKPARENT | ISLASTCN)) == (LOCKPARENT | ISLASTCN)) + ASSERT_VOP_ELOCKED(vdp, "ufs_lookup2"); +#endif + +restart: + bp = NULL; + slotoffset = -1; + + /* + * We now have a segment name to search for, and a directory to search. + * + * Suppress search for slots unless creating + * file and at end of pathname, in which case + * we watch for a place to put the new file in + * case it doesn't already exist. + */ + ino = 0; + i_diroff = dp->i_diroff; + slotstatus = FOUND; + slotfreespace = slotsize = slotneeded = 0; + if ((nameiop == CREATE || nameiop == RENAME) && + (flags & ISLASTCN)) { + slotstatus = NONE; + slotneeded = DIRECTSIZ(cnp->cn_namelen); + } + +#ifdef UFS_DIRHASH + /* + * Use dirhash for fast operations on large directories. The logic + * to determine whether to hash the directory is contained within + * ufsdirhash_build(); a zero return means that it decided to hash + * this directory and it successfully built up the hash table. + */ + if (ufsdirhash_build(dp) == 0) { + /* Look for a free slot if needed. */ + enduseful = dp->i_size; + if (slotstatus != FOUND) { + slotoffset = ufsdirhash_findfree(dp, slotneeded, + &slotsize); + if (slotoffset >= 0) { + slotstatus = COMPACT; + enduseful = ufsdirhash_enduseful(dp); + if (enduseful < 0) + enduseful = dp->i_size; + } + } + /* Look up the component. */ + numdirpasses = 1; + entryoffsetinblock = 0; /* silence compiler warning */ + switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen, + &i_offset, &bp, nameiop == DELETE ? &prevoff : NULL)) { + case 0: + ep = (struct direct *)((char *)bp->b_data + + (i_offset & bmask)); + goto foundentry; + case ENOENT: + i_offset = roundup2(dp->i_size, DIRBLKSIZ); + goto notfound; + default: + /* Something failed; just do a linear search. */ + break; + } + } +#endif /* UFS_DIRHASH */ + /* + * If there is cached information on a previous search of + * this directory, pick up where we last left off. + * We cache only lookups as these are the most common + * and have the greatest payoff. Caching CREATE has little + * benefit as it usually must search the entire directory + * to determine that the entry does not exist. Caching the + * location of the last DELETE or RENAME has not reduced + * profiling time and hence has been removed in the interest + * of simplicity. + */ + if (nameiop != LOOKUP || i_diroff == 0 || i_diroff >= dp->i_size) { + entryoffsetinblock = 0; + i_offset = 0; + numdirpasses = 1; + } else { + i_offset = i_diroff; + if ((entryoffsetinblock = i_offset & bmask) && + (error = UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp))) + return (error); + numdirpasses = 2; + nchstats.ncs_2passes++; + } + prevoff = i_offset; + endsearch = roundup2(dp->i_size, DIRBLKSIZ); + enduseful = 0; + +searchloop: + while (i_offset < endsearch) { + /* + * If necessary, get the next directory block. + */ + if ((i_offset & bmask) == 0) { + if (bp != NULL) + brelse(bp); + error = + UFS_BLKATOFF(vdp, (off_t)i_offset, NULL, &bp); + if (error) + return (error); + entryoffsetinblock = 0; + } + /* + * If still looking for a slot, and at a DIRBLKSIZE + * boundary, have to start looking for free space again. + */ + if (slotstatus == NONE && + (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { + slotoffset = -1; + slotfreespace = 0; + } + /* + * Get pointer to next entry. + * Full validation checks are slow, so we only check + * enough to insure forward progress through the + * directory. Complete checks can be run by patching + * "dirchk" to be true. + */ + ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock); + if (ep->d_reclen == 0 || ep->d_reclen > + DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || + (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) { + int i; + + ufs_dirbad(dp, i_offset, "mangled entry"); + i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); + i_offset += i; + entryoffsetinblock += i; + continue; + } + + /* + * If an appropriate sized slot has not yet been found, + * check to see if one is available. Also accumulate space + * in the current block so that we can determine if + * compaction is viable. + */ + if (slotstatus != FOUND) { + int size = ep->d_reclen; + + if (ep->d_ino != 0) + size -= DIRSIZ(OFSFMT(vdp), ep); + if (size > 0) { + if (size >= slotneeded) { + slotstatus = FOUND; + slotoffset = i_offset; + slotsize = ep->d_reclen; + } else if (slotstatus == NONE) { + slotfreespace += size; + if (slotoffset == -1) + slotoffset = i_offset; + if (slotfreespace >= slotneeded) { + slotstatus = COMPACT; + slotsize = i_offset + + ep->d_reclen - slotoffset; + } + } + } + } + + /* + * Check for a name match. + */ + if (ep->d_ino) { +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (OFSFMT(vdp)) + namlen = ep->d_type; + else + namlen = ep->d_namlen; +# else + namlen = ep->d_namlen; +# endif + if (namlen == cnp->cn_namelen && + (cnp->cn_nameptr[0] == ep->d_name[0]) && + !bcmp(cnp->cn_nameptr, ep->d_name, + (unsigned)namlen)) { +#ifdef UFS_DIRHASH +foundentry: +#endif + /* + * Save directory entry's inode number and + * reclen in ndp->ni_ufs area, and release + * directory buffer. + */ + if (vdp->v_mount->mnt_maxsymlinklen > 0 && + ep->d_type == DT_WHT) { + slotstatus = FOUND; + slotoffset = i_offset; + slotsize = ep->d_reclen; + enduseful = dp->i_size; + cnp->cn_flags |= ISWHITEOUT; + numdirpasses--; + goto notfound; + } + ino = ep->d_ino; + goto found; + } + } + prevoff = i_offset; + i_offset += ep->d_reclen; + entryoffsetinblock += ep->d_reclen; + if (ep->d_ino) + enduseful = i_offset; + } +notfound: + /* + * If we started in the middle of the directory and failed + * to find our target, we must check the beginning as well. + */ + if (numdirpasses == 2) { + numdirpasses--; + i_offset = 0; + endsearch = i_diroff; + goto searchloop; + } + if (bp != NULL) + brelse(bp); + /* + * If creating, and at end of pathname and current + * directory has not been removed, then can consider + * allowing file to be created. + */ + if ((nameiop == CREATE || nameiop == RENAME || + (nameiop == DELETE && + (cnp->cn_flags & DOWHITEOUT) && + (cnp->cn_flags & ISWHITEOUT))) && + (flags & ISLASTCN) && dp->i_effnlink != 0) { + /* + * Access for write is interpreted as allowing + * creation of files in the directory. + * + * XXX: Fix the comment above. + */ + if (flags & WILLBEDIR) + error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); + else + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); + if (error) + return (error); + /* + * Return an indication of where the new directory + * entry should be put. If we didn't find a slot, + * then set dp->i_count to 0 indicating + * that the new slot belongs at the end of the + * directory. If we found a slot, then the new entry + * can be put in the range from dp->i_offset to + * dp->i_offset + dp->i_count. + */ + if (slotstatus == NONE) { + dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ); + dp->i_count = 0; + enduseful = dp->i_offset; + } else if (nameiop == DELETE) { + dp->i_offset = slotoffset; + if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) + dp->i_count = 0; + else + dp->i_count = dp->i_offset - prevoff; + } else { + dp->i_offset = slotoffset; + dp->i_count = slotsize; + if (enduseful < slotoffset + slotsize) + enduseful = slotoffset + slotsize; + } + dp->i_endoff = roundup2(enduseful, DIRBLKSIZ); + /* + * We return with the directory locked, so that + * the parameters we set up above will still be + * valid if we actually decide to do a direnter(). + * We return ni_vp == NULL to indicate that the entry + * does not currently exist; we leave a pointer to + * the (locked) directory inode in ndp->ni_dvp. + * The pathname buffer is saved so that the name + * can be obtained later. + * + * NB - if the directory is unlocked, then this + * information cannot be used. + */ + cnp->cn_flags |= SAVENAME; + return (EJUSTRETURN); + } + /* + * Insert name into cache (as non-existent) if appropriate. + */ + if ((cnp->cn_flags & MAKEENTRY) != 0) + cache_enter(vdp, NULL, cnp); + return (ENOENT); + +found: + if (dd_ino != NULL) + *dd_ino = ino; + if (numdirpasses == 2) + nchstats.ncs_pass2++; + /* + * Check that directory length properly reflects presence + * of this entry. + */ + if (i_offset + DIRSIZ(OFSFMT(vdp), ep) > dp->i_size) { + ufs_dirbad(dp, i_offset, "i_size too small"); + dp->i_size = i_offset + DIRSIZ(OFSFMT(vdp), ep); + DIP_SET(dp, i_size, dp->i_size); + dp->i_flag |= IN_CHANGE | IN_UPDATE; + } + brelse(bp); + + /* + * Found component in pathname. + * If the final component of path name, save information + * in the cache as to where the entry was found. + */ + if ((flags & ISLASTCN) && nameiop == LOOKUP) + dp->i_diroff = rounddown2(i_offset, DIRBLKSIZ); + + /* + * If deleting, and at end of pathname, return + * parameters which can be used to remove file. + */ + if (nameiop == DELETE && (flags & ISLASTCN)) { + if (flags & LOCKPARENT) + ASSERT_VOP_ELOCKED(vdp, __FUNCTION__); + /* + * Return pointer to current entry in dp->i_offset, + * and distance past previous entry (if there + * is a previous entry in this block) in dp->i_count. + * Save directory inode pointer in ndp->ni_dvp for dirremove(). + * + * Technically we shouldn't be setting these in the + * WANTPARENT case (first lookup in rename()), but any + * lookups that will result in directory changes will + * overwrite these. + */ + dp->i_offset = i_offset; + if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) + dp->i_count = 0; + else + dp->i_count = dp->i_offset - prevoff; + if (dd_ino != NULL) + return (0); + if ((error = VFS_VGET(vdp->v_mount, ino, + LK_EXCLUSIVE, &tdp)) != 0) + return (error); + error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); + if (error) { + vput(tdp); + return (error); + } + if (dp->i_number == ino) { + VREF(vdp); + *vpp = vdp; + vput(tdp); + return (0); + } + + *vpp = tdp; + return (0); + } + + /* + * If rewriting (RENAME), return the inode and the + * information required to rewrite the present directory + * Must get inode of directory entry to verify it's a + * regular file, or empty directory. + */ + if (nameiop == RENAME && (flags & ISLASTCN)) { + if (flags & WILLBEDIR) + error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); + else + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); + if (error) + return (error); + /* + * Careful about locking second inode. + * This can only occur if the target is ".". + */ + dp->i_offset = i_offset; + if (dp->i_number == ino) + return (EISDIR); + if (dd_ino != NULL) + return (0); + if ((error = VFS_VGET(vdp->v_mount, ino, + LK_EXCLUSIVE, &tdp)) != 0) + return (error); + + error = ufs_delete_denied(vdp, tdp, cred, cnp->cn_thread); + if (error) { + vput(tdp); + return (error); + } + +#ifdef SunOS_doesnt_do_that + /* + * The only purpose of this check is to return the correct + * error. Assume that we want to rename directory "a" + * to a file "b", and that we have no ACL_WRITE_DATA on + * a containing directory, but we _do_ have ACL_APPEND_DATA. + * In that case, the VOP_ACCESS check above will return 0, + * and the operation will fail with ENOTDIR instead + * of EACCESS. + */ + if (tdp->v_type == VDIR) + error = VOP_ACCESSX(vdp, VWRITE | VAPPEND, cred, cnp->cn_thread); + else + error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_thread); + if (error) { + vput(tdp); + return (error); + } +#endif + + *vpp = tdp; + cnp->cn_flags |= SAVENAME; + return (0); + } + if (dd_ino != NULL) + return (0); + + /* + * Step through the translation in the name. We do not `vput' the + * directory because we may need it again if a symbolic link + * is relative to the current directory. Instead we save it + * unlocked as "pdp". We must get the target inode before unlocking + * the directory to insure that the inode will not be removed + * before we get it. We prevent deadlock by always fetching + * inodes from the root, moving down the directory tree. Thus + * when following backward pointers ".." we must unlock the + * parent directory before getting the requested directory. + * There is a potential race condition here if both the current + * and parent directories are removed before the VFS_VGET for the + * inode associated with ".." returns. We hope that this occurs + * infrequently since we cannot avoid this race condition without + * implementing a sophisticated deadlock detection algorithm. + * Note also that this simple deadlock detection scheme will not + * work if the filesystem has any hard links other than ".." + * that point backwards in the directory structure. + */ + pdp = vdp; + if (flags & ISDOTDOT) { + error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp); + if (error) + return (error); + + /* + * Recheck that ".." entry in the vdp directory points + * to the inode we looked up before vdp lock was + * dropped. + */ + error = ufs_lookup_ino(pdp, NULL, cnp, &ino1); + if (error) { + vput(tdp); + return (error); + } + if (ino1 != ino) { + vput(tdp); + goto restart; + } + + *vpp = tdp; + } else if (dp->i_number == ino) { + VREF(vdp); /* we want ourself, ie "." */ + /* + * When we lookup "." we still can be asked to lock it + * differently. + */ + ltype = cnp->cn_lkflags & LK_TYPE_MASK; + if (ltype != VOP_ISLOCKED(vdp)) { + if (ltype == LK_EXCLUSIVE) + vn_lock(vdp, LK_UPGRADE | LK_RETRY); + else /* if (ltype == LK_SHARED) */ + vn_lock(vdp, LK_DOWNGRADE | LK_RETRY); + /* + * Relock for the "." case may left us with + * reclaimed vnode. + */ + if (vdp->v_iflag & VI_DOOMED) { + vrele(vdp); + return (ENOENT); + } + } + *vpp = vdp; + } else { + error = VFS_VGET(pdp->v_mount, ino, cnp->cn_lkflags, &tdp); + if (error) + return (error); + *vpp = tdp; + } + + /* + * Insert name into cache if appropriate. + */ + if (cnp->cn_flags & MAKEENTRY) + cache_enter(vdp, *vpp, cnp); + return (0); +} + +void +ufs_dirbad(ip, offset, how) + struct inode *ip; + doff_t offset; + char *how; +{ + struct mount *mp; + + mp = ITOV(ip)->v_mount; + if ((mp->mnt_flag & MNT_RDONLY) == 0) + panic("ufs_dirbad: %s: bad dir ino %ju at offset %ld: %s", + mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number, + (long)offset, how); + else + (void)printf("%s: bad dir ino %ju at offset %ld: %s\n", + mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number, + (long)offset, how); +} + +/* + * Do consistency checking on a directory entry: + * record length must be multiple of 4 + * entry must fit in rest of its DIRBLKSIZ block + * record must be large enough to contain entry + * name is not longer than MAXNAMLEN + * name must be as long as advertised, and null terminated + */ +int +ufs_dirbadentry(dp, ep, entryoffsetinblock) + struct vnode *dp; + struct direct *ep; + int entryoffsetinblock; +{ + int i, namlen; + +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (OFSFMT(dp)) + namlen = ep->d_type; + else + namlen = ep->d_namlen; +# else + namlen = ep->d_namlen; +# endif + if ((ep->d_reclen & 0x3) != 0 || + ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || + ep->d_reclen < DIRSIZ(OFSFMT(dp), ep) || namlen > MAXNAMLEN) { + /*return (1); */ + printf("First bad\n"); + goto bad; + } + if (ep->d_ino == 0) + return (0); + for (i = 0; i < namlen; i++) + if (ep->d_name[i] == '\0') { + /*return (1); */ + printf("Second bad\n"); + goto bad; + } + if (ep->d_name[i]) + goto bad; + return (0); +bad: + return (1); +} + +/* + * Construct a new directory entry after a call to namei, using the + * parameters that it left in the componentname argument cnp. The + * argument ip is the inode to which the new directory entry will refer. + */ +void +ufs_makedirentry(ip, cnp, newdirp) + struct inode *ip; + struct componentname *cnp; + struct direct *newdirp; +{ + +#ifdef INVARIANTS + if ((cnp->cn_flags & SAVENAME) == 0) + panic("ufs_makedirentry: missing name"); +#endif + newdirp->d_ino = ip->i_number; + newdirp->d_namlen = cnp->cn_namelen; + bcopy(cnp->cn_nameptr, newdirp->d_name, (unsigned)cnp->cn_namelen + 1); + if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0) + newdirp->d_type = IFTODT(ip->i_mode); + else { + newdirp->d_type = 0; +# if (BYTE_ORDER == LITTLE_ENDIAN) + { u_char tmp = newdirp->d_namlen; + newdirp->d_namlen = newdirp->d_type; + newdirp->d_type = tmp; } +# endif + } +} + +/* + * Write a directory entry after a call to namei, using the parameters + * that it left in nameidata. The argument dirp is the new directory + * entry contents. Dvp is a pointer to the directory to be written, + * which was left locked by namei. Remaining parameters (dp->i_offset, + * dp->i_count) indicate how the space for the new entry is to be obtained. + * Non-null bp indicates that a directory is being created (for the + * soft dependency code). + */ +int +ufs_direnter(dvp, tvp, dirp, cnp, newdirbp, isrename) + struct vnode *dvp; + struct vnode *tvp; + struct direct *dirp; + struct componentname *cnp; + struct buf *newdirbp; + int isrename; +{ + struct ucred *cr; + struct thread *td; + int newentrysize; + struct inode *dp; + struct buf *bp; + u_int dsize; + struct direct *ep, *nep; + u_int64_t old_isize; + int error, ret, blkoff, loc, spacefree, flags, namlen; + char *dirbuf; + + td = curthread; /* XXX */ + cr = td->td_ucred; + + dp = VTOI(dvp); + newentrysize = DIRSIZ(OFSFMT(dvp), dirp); + + if (dp->i_count == 0) { + /* + * If dp->i_count is 0, then namei could find no + * space in the directory. Here, dp->i_offset will + * be on a directory block boundary and we will write the + * new entry into a fresh block. + */ + if (dp->i_offset & (DIRBLKSIZ - 1)) + panic("ufs_direnter: newblk"); + flags = BA_CLRBUF; + if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp)) + flags |= IO_SYNC; +#ifdef QUOTA + if ((error = getinoquota(dp)) != 0) { + if (DOINGSOFTDEP(dvp) && newdirbp != NULL) + bdwrite(newdirbp); + return (error); + } +#endif + old_isize = dp->i_size; + vnode_pager_setsize(dvp, (u_long)dp->i_offset + DIRBLKSIZ); + if ((error = UFS_BALLOC(dvp, (off_t)dp->i_offset, DIRBLKSIZ, + cr, flags, &bp)) != 0) { + if (DOINGSOFTDEP(dvp) && newdirbp != NULL) + bdwrite(newdirbp); + vnode_pager_setsize(dvp, (u_long)old_isize); + return (error); + } + dp->i_size = dp->i_offset + DIRBLKSIZ; + DIP_SET(dp, i_size, dp->i_size); + dp->i_endoff = dp->i_size; + dp->i_flag |= IN_CHANGE | IN_UPDATE; + dirp->d_reclen = DIRBLKSIZ; + blkoff = dp->i_offset & + (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1); + bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize); +#ifdef UFS_DIRHASH + if (dp->i_dirhash != NULL) { + ufsdirhash_newblk(dp, dp->i_offset); + ufsdirhash_add(dp, dirp, dp->i_offset); + ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff, + dp->i_offset); + } +#endif + if (DOINGSOFTDEP(dvp)) { + /* + * Ensure that the entire newly allocated block is a + * valid directory so that future growth within the + * block does not have to ensure that the block is + * written before the inode. + */ + blkoff += DIRBLKSIZ; + while (blkoff < bp->b_bcount) { + ((struct direct *) + (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; + blkoff += DIRBLKSIZ; + } + if (softdep_setup_directory_add(bp, dp, dp->i_offset, + dirp->d_ino, newdirbp, 1)) + dp->i_flag |= IN_NEEDSYNC; + if (newdirbp) + bdwrite(newdirbp); + bdwrite(bp); + if ((dp->i_flag & IN_NEEDSYNC) == 0) + return (UFS_UPDATE(dvp, 0)); + /* + * We have just allocated a directory block in an + * indirect block. We must prevent holes in the + * directory created if directory entries are + * written out of order. To accomplish this we + * fsync when we extend a directory into indirects. + * During rename it's not safe to drop the tvp lock + * so sync must be delayed until it is. + * + * This synchronous step could be removed if fsck and + * the kernel were taught to fill in sparse + * directories rather than panic. + */ + if (isrename) + return (0); + if (tvp != NULL) + VOP_UNLOCK(tvp, 0); + (void) VOP_FSYNC(dvp, MNT_WAIT, td); + if (tvp != NULL) + vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); + return (error); + } + if (DOINGASYNC(dvp)) { + bdwrite(bp); + return (UFS_UPDATE(dvp, 0)); + } + error = bwrite(bp); + ret = UFS_UPDATE(dvp, 1); + if (error == 0) + return (ret); + return (error); + } + + /* + * If dp->i_count is non-zero, then namei found space for the new + * entry in the range dp->i_offset to dp->i_offset + dp->i_count + * in the directory. To use this space, we may have to compact + * the entries located there, by copying them together towards the + * beginning of the block, leaving the free space in one usable + * chunk at the end. + */ + + /* + * Increase size of directory if entry eats into new space. + * This should never push the size past a new multiple of + * DIRBLKSIZE. + * + * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. + */ + if (dp->i_offset + dp->i_count > dp->i_size) { + dp->i_size = dp->i_offset + dp->i_count; + DIP_SET(dp, i_size, dp->i_size); + } + /* + * Get the block containing the space for the new directory entry. + */ + error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp); + if (error) { + if (DOINGSOFTDEP(dvp) && newdirbp != NULL) + bdwrite(newdirbp); + return (error); + } + /* + * Find space for the new entry. In the simple case, the entry at + * offset base will have the space. If it does not, then namei + * arranged that compacting the region dp->i_offset to + * dp->i_offset + dp->i_count would yield the space. + */ + ep = (struct direct *)dirbuf; + dsize = ep->d_ino ? DIRSIZ(OFSFMT(dvp), ep) : 0; + spacefree = ep->d_reclen - dsize; + for (loc = ep->d_reclen; loc < dp->i_count; ) { + nep = (struct direct *)(dirbuf + loc); + + /* Trim the existing slot (NB: dsize may be zero). */ + ep->d_reclen = dsize; + ep = (struct direct *)((char *)ep + dsize); + + /* Read nep->d_reclen now as the bcopy() may clobber it. */ + loc += nep->d_reclen; + if (nep->d_ino == 0) { + /* + * A mid-block unused entry. Such entries are + * never created by the kernel, but fsck_ffs + * can create them (and it doesn't fix them). + * + * Add up the free space, and initialise the + * relocated entry since we don't bcopy it. + */ + spacefree += nep->d_reclen; + ep->d_ino = 0; + dsize = 0; + continue; + } + dsize = DIRSIZ(OFSFMT(dvp), nep); + spacefree += nep->d_reclen - dsize; +#ifdef UFS_DIRHASH + if (dp->i_dirhash != NULL) + ufsdirhash_move(dp, nep, + dp->i_offset + ((char *)nep - dirbuf), + dp->i_offset + ((char *)ep - dirbuf)); +#endif + if (DOINGSOFTDEP(dvp)) + softdep_change_directoryentry_offset(bp, dp, dirbuf, + (caddr_t)nep, (caddr_t)ep, dsize); + else + bcopy((caddr_t)nep, (caddr_t)ep, dsize); + } + /* + * Here, `ep' points to a directory entry containing `dsize' in-use + * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0, + * then the entry is completely unused (dsize == 0). The value + * of ep->d_reclen is always indeterminate. + * + * Update the pointer fields in the previous entry (if any), + * copy in the new entry, and write out the block. + */ +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (OFSFMT(dvp)) + namlen = ep->d_type; + else + namlen = ep->d_namlen; +# else + namlen = ep->d_namlen; +# endif + if (ep->d_ino == 0 || + (ep->d_ino == WINO && namlen == dirp->d_namlen && + bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { + if (spacefree + dsize < newentrysize) + panic("ufs_direnter: compact1"); + dirp->d_reclen = spacefree + dsize; + } else { + if (spacefree < newentrysize) + panic("ufs_direnter: compact2"); + dirp->d_reclen = spacefree; + ep->d_reclen = dsize; + ep = (struct direct *)((char *)ep + dsize); + } +#ifdef UFS_DIRHASH + if (dp->i_dirhash != NULL && (ep->d_ino == 0 || + dirp->d_reclen == spacefree)) + ufsdirhash_add(dp, dirp, dp->i_offset + ((char *)ep - dirbuf)); +#endif + bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize); +#ifdef UFS_DIRHASH + if (dp->i_dirhash != NULL) + ufsdirhash_checkblock(dp, dirbuf - + (dp->i_offset & (DIRBLKSIZ - 1)), + rounddown2(dp->i_offset, DIRBLKSIZ)); +#endif + + if (DOINGSOFTDEP(dvp)) { + (void) softdep_setup_directory_add(bp, dp, + dp->i_offset + (caddr_t)ep - dirbuf, + dirp->d_ino, newdirbp, 0); + if (newdirbp != NULL) + bdwrite(newdirbp); + bdwrite(bp); + } else { + if (DOINGASYNC(dvp)) { + bdwrite(bp); + error = 0; + } else { + error = bwrite(bp); + } + } + dp->i_flag |= IN_CHANGE | IN_UPDATE; + /* + * If all went well, and the directory can be shortened, proceed + * with the truncation. Note that we have to unlock the inode for + * the entry that we just entered, as the truncation may need to + * lock other inodes which can lead to deadlock if we also hold a + * lock on the newly entered node. + */ + if (isrename == 0 && error == 0 && + dp->i_endoff && dp->i_endoff < dp->i_size) { + if (tvp != NULL) + VOP_UNLOCK(tvp, 0); + error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, + IO_NORMAL | (DOINGASYNC(dvp) ? 0 : IO_SYNC), cr); + if (error != 0) + vn_printf(dvp, + "ufs_direnter: failed to truncate, error %d\n", + error); +#ifdef UFS_DIRHASH + if (error == 0 && dp->i_dirhash != NULL) + ufsdirhash_dirtrunc(dp, dp->i_endoff); +#endif + error = 0; + if (tvp != NULL) + vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY); + } + return (error); +} + +/* + * Remove a directory entry after a call to namei, using + * the parameters which it left in nameidata. The entry + * dp->i_offset contains the offset into the directory of the + * entry to be eliminated. The dp->i_count field contains the + * size of the previous record in the directory. If this + * is 0, the first entry is being deleted, so we need only + * zero the inode number to mark the entry as free. If the + * entry is not the first in the directory, we must reclaim + * the space of the now empty record by adding the record size + * to the size of the previous entry. + */ +int +ufs_dirremove(dvp, ip, flags, isrmdir) + struct vnode *dvp; + struct inode *ip; + int flags; + int isrmdir; +{ + struct inode *dp; + struct direct *ep, *rep; + struct buf *bp; + int error; + + dp = VTOI(dvp); + + /* + * Adjust the link count early so softdep can block if necessary. + */ + if (ip) { + ip->i_effnlink--; + if (DOINGSOFTDEP(dvp)) { + softdep_setup_unlink(dp, ip); + } else { + ip->i_nlink--; + DIP_SET(ip, i_nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + } + } + if (flags & DOWHITEOUT) { + /* + * Whiteout entry: set d_ino to WINO. + */ + if ((error = + UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) + return (error); + ep->d_ino = WINO; + ep->d_type = DT_WHT; + goto out; + } + + if ((error = UFS_BLKATOFF(dvp, + (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0) + return (error); + + /* Set 'rep' to the entry being removed. */ + if (dp->i_count == 0) + rep = ep; + else + rep = (struct direct *)((char *)ep + ep->d_reclen); +#ifdef UFS_DIRHASH + /* + * Remove the dirhash entry. This is complicated by the fact + * that `ep' is the previous entry when dp->i_count != 0. + */ + if (dp->i_dirhash != NULL) + ufsdirhash_remove(dp, rep, dp->i_offset); +#endif + if (ip && rep->d_ino != ip->i_number) + panic("ufs_dirremove: ip %ju does not match dirent ino %ju\n", + (uintmax_t)ip->i_number, (uintmax_t)rep->d_ino); + if (dp->i_count == 0) { + /* + * First entry in block: set d_ino to zero. + */ + ep->d_ino = 0; + } else { + /* + * Collapse new free space into previous entry. + */ + ep->d_reclen += rep->d_reclen; + } +#ifdef UFS_DIRHASH + if (dp->i_dirhash != NULL) + ufsdirhash_checkblock(dp, (char *)ep - + ((dp->i_offset - dp->i_count) & (DIRBLKSIZ - 1)), + rounddown2(dp->i_offset, DIRBLKSIZ)); +#endif +out: + error = 0; + if (DOINGSOFTDEP(dvp)) { + if (ip) + softdep_setup_remove(bp, dp, ip, isrmdir); + if (softdep_slowdown(dvp)) + error = bwrite(bp); + else + bdwrite(bp); + } else { + if (flags & DOWHITEOUT) + error = bwrite(bp); + else if (DOINGASYNC(dvp) && dp->i_count != 0) + bdwrite(bp); + else + error = bwrite(bp); + } + dp->i_flag |= IN_CHANGE | IN_UPDATE; + /* + * If the last named reference to a snapshot goes away, + * drop its snapshot reference so that it will be reclaimed + * when last open reference goes away. + */ + if (ip != NULL && (ip->i_flags & SF_SNAPSHOT) != 0 && + ip->i_effnlink == 0) + UFS_SNAPGONE(ip); + return (error); +} + +/* + * Rewrite an existing directory entry to point at the inode + * supplied. The parameters describing the directory entry are + * set up by a call to namei. + */ +int +ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir) + struct inode *dp, *oip; + ino_t newinum; + int newtype; + int isrmdir; +{ + struct buf *bp; + struct direct *ep; + struct vnode *vdp = ITOV(dp); + int error; + + /* + * Drop the link before we lock the buf so softdep can block if + * necessary. + */ + oip->i_effnlink--; + if (DOINGSOFTDEP(vdp)) { + softdep_setup_unlink(dp, oip); + } else { + oip->i_nlink--; + DIP_SET(oip, i_nlink, oip->i_nlink); + oip->i_flag |= IN_CHANGE; + } + + error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp); + if (error) + return (error); + if (ep->d_namlen == 2 && ep->d_name[1] == '.' && ep->d_name[0] == '.' && + ep->d_ino != oip->i_number) { + brelse(bp); + return (EIDRM); + } + ep->d_ino = newinum; + if (!OFSFMT(vdp)) + ep->d_type = newtype; + if (DOINGSOFTDEP(vdp)) { + softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir); + bdwrite(bp); + } else { + if (DOINGASYNC(vdp)) { + bdwrite(bp); + error = 0; + } else { + error = bwrite(bp); + } + } + dp->i_flag |= IN_CHANGE | IN_UPDATE; + /* + * If the last named reference to a snapshot goes away, + * drop its snapshot reference so that it will be reclaimed + * when last open reference goes away. + */ + if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_effnlink == 0) + UFS_SNAPGONE(oip); + return (error); +} + +/* + * Check if a directory is empty or not. + * Inode supplied must be locked. + * + * Using a struct dirtemplate here is not precisely + * what we want, but better than using a struct direct. + * + * NB: does not handle corrupted directories. + */ +int +ufs_dirempty(ip, parentino, cred) + struct inode *ip; + ino_t parentino; + struct ucred *cred; +{ + doff_t off; + struct dirtemplate dbuf; + struct direct *dp = (struct direct *)&dbuf; + int error, namlen; + ssize_t count; +#define MINDIRSIZ (sizeof (struct dirtemplate) / 2) + + for (off = 0; off < ip->i_size; off += dp->d_reclen) { + error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, + off, UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, cred, + NOCRED, &count, (struct thread *)0); + /* + * Since we read MINDIRSIZ, residual must + * be 0 unless we're at end of file. + */ + if (error || count != 0) + return (0); + /* avoid infinite loops */ + if (dp->d_reclen == 0) + return (0); + /* skip empty entries */ + if (dp->d_ino == 0 || dp->d_ino == WINO) + continue; + /* accept only "." and ".." */ +# if (BYTE_ORDER == LITTLE_ENDIAN) + if (OFSFMT(ITOV(ip))) + namlen = dp->d_type; + else + namlen = dp->d_namlen; +# else + namlen = dp->d_namlen; +# endif + if (namlen > 2) + return (0); + if (dp->d_name[0] != '.') + return (0); + /* + * At this point namlen must be 1 or 2. + * 1 implies ".", 2 implies ".." if second + * char is also "." + */ + if (namlen == 1 && dp->d_ino == ip->i_number) + continue; + if (dp->d_name[1] == '.' && dp->d_ino == parentino) + continue; + return (0); + } + return (1); +} + +static int +ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino, + struct vnode **dd_vp) +{ + struct dirtemplate dirbuf; + struct vnode *ddvp; + int error, namlen; + + ASSERT_VOP_LOCKED(vp, "ufs_dir_dd_ino"); + if (vp->v_type != VDIR) + return (ENOTDIR); + /* + * First check to see if we have it in the name cache. + */ + if ((ddvp = vn_dir_dd_ino(vp)) != NULL) { + KASSERT(ddvp->v_mount == vp->v_mount, + ("ufs_dir_dd_ino: Unexpected mount point crossing")); + *dd_ino = VTOI(ddvp)->i_number; + *dd_vp = ddvp; + return (0); + } + /* + * Have to read the directory. + */ + error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, + sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, + IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, NULL, NULL); + if (error != 0) + return (error); +#if (BYTE_ORDER == LITTLE_ENDIAN) + if (OFSFMT(vp)) + namlen = dirbuf.dotdot_type; + else + namlen = dirbuf.dotdot_namlen; +#else + namlen = dirbuf.dotdot_namlen; +#endif + if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || + dirbuf.dotdot_name[1] != '.') + return (ENOTDIR); + *dd_ino = dirbuf.dotdot_ino; + *dd_vp = NULL; + return (0); +} + +/* + * Check if source directory is in the path of the target directory. + */ +int +ufs_checkpath(ino_t source_ino, ino_t parent_ino, struct inode *target, struct ucred *cred, ino_t *wait_ino) +{ + struct mount *mp; + struct vnode *tvp, *vp, *vp1; + int error; + ino_t dd_ino; + + vp = tvp = ITOV(target); + mp = vp->v_mount; + *wait_ino = 0; + if (target->i_number == source_ino) + return (EEXIST); + if (target->i_number == parent_ino) + return (0); + if (target->i_number == ROOTINO) + return (0); + for (;;) { + error = ufs_dir_dd_ino(vp, cred, &dd_ino, &vp1); + if (error != 0) + break; + if (dd_ino == source_ino) { + error = EINVAL; + break; + } + if (dd_ino == ROOTINO) + break; + if (dd_ino == parent_ino) + break; + if (vp1 == NULL) { + error = VFS_VGET(mp, dd_ino, LK_SHARED | LK_NOWAIT, + &vp1); + if (error != 0) { + *wait_ino = dd_ino; + break; + } + } + KASSERT(dd_ino == VTOI(vp1)->i_number, + ("directory %ju reparented\n", + (uintmax_t)VTOI(vp1)->i_number)); + if (vp != tvp) + vput(vp); + vp = vp1; + } + + if (error == ENOTDIR) + panic("checkpath: .. not a directory\n"); + if (vp1 != NULL) + vput(vp1); + if (vp != tvp) + vput(vp); + return (error); +} diff --git a/Dump/ufs/ufs/ufs_quota.c b/Dump/ufs/ufs/ufs_quota.c new file mode 100644 index 0000000..550bb9c --- /dev/null +++ b/Dump/ufs/ufs/ufs_quota.c @@ -0,0 +1,1855 @@ +/*- + * Copyright (c) 1982, 1986, 1990, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_quota.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include "opt_ffs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +CTASSERT(sizeof(struct dqblk64) == sizeof(struct dqhdr64)); + +static int unprivileged_get_quota = 0; +SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_get_quota, CTLFLAG_RW, + &unprivileged_get_quota, 0, + "Unprivileged processes may retrieve quotas for other uids and gids"); + +static MALLOC_DEFINE(M_DQUOT, "ufs_quota", "UFS quota entries"); + +/* + * Quota name to error message mapping. + */ +static char *quotatypes[] = INITQFNAMES; + +static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int, int *); +static int chkiqchg(struct inode *, int, struct ucred *, int, int *); +static int dqopen(struct vnode *, struct ufsmount *, int); +static int dqget(struct vnode *, + u_long, struct ufsmount *, int, struct dquot **); +static int dqsync(struct vnode *, struct dquot *); +static int dqflush(struct vnode *); +static int quotaoff1(struct thread *td, struct mount *mp, int type); +static int quotaoff_inchange(struct thread *td, struct mount *mp, int type); + +/* conversion functions - from_to() */ +static void dqb32_dq(const struct dqblk32 *, struct dquot *); +static void dqb64_dq(const struct dqblk64 *, struct dquot *); +static void dq_dqb32(const struct dquot *, struct dqblk32 *); +static void dq_dqb64(const struct dquot *, struct dqblk64 *); +static void dqb32_dqb64(const struct dqblk32 *, struct dqblk64 *); +static void dqb64_dqb32(const struct dqblk64 *, struct dqblk32 *); + +#ifdef DIAGNOSTIC +static void dqref(struct dquot *); +static void chkdquot(struct inode *); +#endif + +/* + * Set up the quotas for an inode. + * + * This routine completely defines the semantics of quotas. + * If other criterion want to be used to establish quotas, the + * MAXQUOTAS value in quota.h should be increased, and the + * additional dquots set up here. + */ +int +getinoquota(struct inode *ip) +{ + struct ufsmount *ump; + struct vnode *vp; + int error; + + vp = ITOV(ip); + + /* + * Disk quotas must be turned off for system files. Currently + * snapshot and quota files. + */ + if ((vp->v_vflag & VV_SYSTEM) != 0) + return (0); + /* + * XXX: Turn off quotas for files with a negative UID or GID. + * This prevents the creation of 100GB+ quota files. + */ + if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) + return (0); + ump = VFSTOUFS(vp->v_mount); + /* + * Set up the user quota based on file uid. + * EINVAL means that quotas are not enabled. + */ + if ((error = + dqget(vp, ip->i_uid, ump, USRQUOTA, &ip->i_dquot[USRQUOTA])) && + error != EINVAL) + return (error); + /* + * Set up the group quota based on file gid. + * EINVAL means that quotas are not enabled. + */ + if ((error = + dqget(vp, ip->i_gid, ump, GRPQUOTA, &ip->i_dquot[GRPQUOTA])) && + error != EINVAL) + return (error); + return (0); +} + +/* + * Update disk usage, and take corrective action. + */ +int +chkdq(struct inode *ip, ufs2_daddr_t change, struct ucred *cred, int flags) +{ + struct dquot *dq; + ufs2_daddr_t ncurblocks; + struct vnode *vp = ITOV(ip); + int i, error, warn, do_check; + + /* + * Disk quotas must be turned off for system files. Currently + * snapshot and quota files. + */ + if ((vp->v_vflag & VV_SYSTEM) != 0) + return (0); + /* + * XXX: Turn off quotas for files with a negative UID or GID. + * This prevents the creation of 100GB+ quota files. + */ + if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) + return (0); +#ifdef DIAGNOSTIC + if ((flags & CHOWN) == 0) + chkdquot(ip); +#endif + if (change == 0) + return (0); + if (change < 0) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "chkdq1"); + ncurblocks = dq->dq_curblocks + change; + if (ncurblocks >= 0) + dq->dq_curblocks = ncurblocks; + else + dq->dq_curblocks = 0; + dq->dq_flags &= ~DQ_BLKS; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + } + return (0); + } + if ((flags & FORCE) == 0 && + priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) + do_check = 1; + else + do_check = 0; + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + warn = 0; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "chkdq2"); + if (do_check) { + error = chkdqchg(ip, change, cred, i, &warn); + if (error) { + /* + * Roll back user quota changes when + * group quota failed. + */ + while (i > 0) { + --i; + dq = ip->i_dquot[i]; + if (dq == NODQUOT) + continue; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "chkdq3"); + ncurblocks = dq->dq_curblocks - change; + if (ncurblocks >= 0) + dq->dq_curblocks = ncurblocks; + else + dq->dq_curblocks = 0; + dq->dq_flags &= ~DQ_BLKS; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + } + return (error); + } + } + /* Reset timer when crossing soft limit */ + if (dq->dq_curblocks + change >= dq->dq_bsoftlimit && + dq->dq_curblocks < dq->dq_bsoftlimit) + dq->dq_btime = time_second + ITOUMP(ip)->um_btime[i]; + dq->dq_curblocks += change; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + if (warn) + uprintf("\n%s: warning, %s disk quota exceeded\n", + ITOVFS(ip)->mnt_stat.f_mntonname, + quotatypes[i]); + } + return (0); +} + +/* + * Check for a valid change to a users allocation. + * Issue an error message if appropriate. + */ +static int +chkdqchg(struct inode *ip, ufs2_daddr_t change, struct ucred *cred, + int type, int *warn) +{ + struct dquot *dq = ip->i_dquot[type]; + ufs2_daddr_t ncurblocks = dq->dq_curblocks + change; + + /* + * If user would exceed their hard limit, disallow space allocation. + */ + if (ncurblocks >= dq->dq_bhardlimit && dq->dq_bhardlimit) { + if ((dq->dq_flags & DQ_BLKS) == 0 && + ip->i_uid == cred->cr_uid) { + dq->dq_flags |= DQ_BLKS; + DQI_UNLOCK(dq); + uprintf("\n%s: write failed, %s disk limit reached\n", + ITOVFS(ip)->mnt_stat.f_mntonname, + quotatypes[type]); + return (EDQUOT); + } + DQI_UNLOCK(dq); + return (EDQUOT); + } + /* + * If user is over their soft limit for too long, disallow space + * allocation. Reset time limit as they cross their soft limit. + */ + if (ncurblocks >= dq->dq_bsoftlimit && dq->dq_bsoftlimit) { + if (dq->dq_curblocks < dq->dq_bsoftlimit) { + dq->dq_btime = time_second + ITOUMP(ip)->um_btime[type]; + if (ip->i_uid == cred->cr_uid) + *warn = 1; + return (0); + } + if (time_second > dq->dq_btime) { + if ((dq->dq_flags & DQ_BLKS) == 0 && + ip->i_uid == cred->cr_uid) { + dq->dq_flags |= DQ_BLKS; + DQI_UNLOCK(dq); + uprintf("\n%s: write failed, %s " + "disk quota exceeded for too long\n", + ITOVFS(ip)->mnt_stat.f_mntonname, + quotatypes[type]); + return (EDQUOT); + } + DQI_UNLOCK(dq); + return (EDQUOT); + } + } + return (0); +} + +/* + * Check the inode limit, applying corrective action. + */ +int +chkiq(struct inode *ip, int change, struct ucred *cred, int flags) +{ + struct dquot *dq; + int i, error, warn, do_check; + +#ifdef DIAGNOSTIC + if ((flags & CHOWN) == 0) + chkdquot(ip); +#endif + if (change == 0) + return (0); + if (change < 0) { + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "chkiq1"); + if (dq->dq_curinodes >= -change) + dq->dq_curinodes += change; + else + dq->dq_curinodes = 0; + dq->dq_flags &= ~DQ_INODS; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + } + return (0); + } + if ((flags & FORCE) == 0 && + priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) + do_check = 1; + else + do_check = 0; + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + warn = 0; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "chkiq2"); + if (do_check) { + error = chkiqchg(ip, change, cred, i, &warn); + if (error) { + /* + * Roll back user quota changes when + * group quota failed. + */ + while (i > 0) { + --i; + dq = ip->i_dquot[i]; + if (dq == NODQUOT) + continue; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "chkiq3"); + if (dq->dq_curinodes >= change) + dq->dq_curinodes -= change; + else + dq->dq_curinodes = 0; + dq->dq_flags &= ~DQ_INODS; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + } + return (error); + } + } + /* Reset timer when crossing soft limit */ + if (dq->dq_curinodes + change >= dq->dq_isoftlimit && + dq->dq_curinodes < dq->dq_isoftlimit) + dq->dq_itime = time_second + ITOUMP(ip)->um_itime[i]; + dq->dq_curinodes += change; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + if (warn) + uprintf("\n%s: warning, %s inode quota exceeded\n", + ITOVFS(ip)->mnt_stat.f_mntonname, + quotatypes[i]); + } + return (0); +} + +/* + * Check for a valid change to a users allocation. + * Issue an error message if appropriate. + */ +static int +chkiqchg(struct inode *ip, int change, struct ucred *cred, int type, int *warn) +{ + struct dquot *dq = ip->i_dquot[type]; + ino_t ncurinodes = dq->dq_curinodes + change; + + /* + * If user would exceed their hard limit, disallow inode allocation. + */ + if (ncurinodes >= dq->dq_ihardlimit && dq->dq_ihardlimit) { + if ((dq->dq_flags & DQ_INODS) == 0 && + ip->i_uid == cred->cr_uid) { + dq->dq_flags |= DQ_INODS; + DQI_UNLOCK(dq); + uprintf("\n%s: write failed, %s inode limit reached\n", + ITOVFS(ip)->mnt_stat.f_mntonname, + quotatypes[type]); + return (EDQUOT); + } + DQI_UNLOCK(dq); + return (EDQUOT); + } + /* + * If user is over their soft limit for too long, disallow inode + * allocation. Reset time limit as they cross their soft limit. + */ + if (ncurinodes >= dq->dq_isoftlimit && dq->dq_isoftlimit) { + if (dq->dq_curinodes < dq->dq_isoftlimit) { + dq->dq_itime = time_second + ITOUMP(ip)->um_itime[type]; + if (ip->i_uid == cred->cr_uid) + *warn = 1; + return (0); + } + if (time_second > dq->dq_itime) { + if ((dq->dq_flags & DQ_INODS) == 0 && + ip->i_uid == cred->cr_uid) { + dq->dq_flags |= DQ_INODS; + DQI_UNLOCK(dq); + uprintf("\n%s: write failed, %s " + "inode quota exceeded for too long\n", + ITOVFS(ip)->mnt_stat.f_mntonname, + quotatypes[type]); + return (EDQUOT); + } + DQI_UNLOCK(dq); + return (EDQUOT); + } + } + return (0); +} + +#ifdef DIAGNOSTIC +/* + * On filesystems with quotas enabled, it is an error for a file to change + * size and not to have a dquot structure associated with it. + */ +static void +chkdquot(struct inode *ip) +{ + struct ufsmount *ump; + struct vnode *vp; + int i; + + ump = ITOUMP(ip); + vp = ITOV(ip); + + /* + * Disk quotas must be turned off for system files. Currently + * these are snapshots and quota files. + */ + if ((vp->v_vflag & VV_SYSTEM) != 0) + return; + /* + * XXX: Turn off quotas for files with a negative UID or GID. + * This prevents the creation of 100GB+ quota files. + */ + if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0) + return; + + UFS_LOCK(ump); + for (i = 0; i < MAXQUOTAS; i++) { + if (ump->um_quotas[i] == NULLVP || + (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING))) + continue; + if (ip->i_dquot[i] == NODQUOT) { + UFS_UNLOCK(ump); + vn_printf(ITOV(ip), "chkdquot: missing dquot "); + panic("chkdquot: missing dquot"); + } + } + UFS_UNLOCK(ump); +} +#endif + +/* + * Code to process quotactl commands. + */ + +/* + * Q_QUOTAON - set up a quota file for a particular filesystem. + */ +int +quotaon(struct thread *td, struct mount *mp, int type, void *fname) +{ + struct ufsmount *ump; + struct vnode *vp, **vpp; + struct vnode *mvp; + struct dquot *dq; + int error, flags; + struct nameidata nd; + + error = priv_check(td, PRIV_UFS_QUOTAON); + if (error != 0) { + vfs_unbusy(mp); + return (error); + } + + if ((mp->mnt_flag & MNT_RDONLY) != 0) { + vfs_unbusy(mp); + return (EROFS); + } + + ump = VFSTOUFS(mp); + dq = NODQUOT; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname, td); + flags = FREAD | FWRITE; + vfs_ref(mp); + vfs_unbusy(mp); + error = vn_open(&nd, &flags, 0, NULL); + if (error != 0) { + vfs_rel(mp); + return (error); + } + NDFREE(&nd, NDF_ONLY_PNBUF); + vp = nd.ni_vp; + error = vfs_busy(mp, MBF_NOWAIT); + vfs_rel(mp); + if (error == 0) { + if (vp->v_type != VREG) { + error = EACCES; + vfs_unbusy(mp); + } + } + if (error != 0) { + VOP_UNLOCK(vp, 0); + (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); + return (error); + } + + UFS_LOCK(ump); + if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) { + UFS_UNLOCK(ump); + VOP_UNLOCK(vp, 0); + (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); + vfs_unbusy(mp); + return (EALREADY); + } + ump->um_qflags[type] |= QTF_OPENING|QTF_CLOSING; + UFS_UNLOCK(ump); + if ((error = dqopen(vp, ump, type)) != 0) { + VOP_UNLOCK(vp, 0); + UFS_LOCK(ump); + ump->um_qflags[type] &= ~(QTF_OPENING|QTF_CLOSING); + UFS_UNLOCK(ump); + (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); + vfs_unbusy(mp); + return (error); + } + VOP_UNLOCK(vp, 0); + MNT_ILOCK(mp); + mp->mnt_flag |= MNT_QUOTA; + MNT_IUNLOCK(mp); + + vpp = &ump->um_quotas[type]; + if (*vpp != vp) + quotaoff1(td, mp, type); + + /* + * When the directory vnode containing the quota file is + * inactivated, due to the shared lookup of the quota file + * vput()ing the dvp, the qsyncvp() call for the containing + * directory would try to acquire the quota lock exclusive. + * At the same time, lookup already locked the quota vnode + * shared. Mark the quota vnode lock as allowing recursion + * and automatically converting shared locks to exclusive. + * + * Also mark quota vnode as system. + */ + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + vp->v_vflag |= VV_SYSTEM; + VN_LOCK_AREC(vp); + VN_LOCK_DSHARE(vp); + VOP_UNLOCK(vp, 0); + *vpp = vp; + /* + * Save the credential of the process that turned on quotas. + * Set up the time limits for this quota. + */ + ump->um_cred[type] = crhold(td->td_ucred); + ump->um_btime[type] = MAX_DQ_TIME; + ump->um_itime[type] = MAX_IQ_TIME; + if (dqget(NULLVP, 0, ump, type, &dq) == 0) { + if (dq->dq_btime > 0) + ump->um_btime[type] = dq->dq_btime; + if (dq->dq_itime > 0) + ump->um_itime[type] = dq->dq_itime; + dqrele(NULLVP, dq); + } + /* + * Allow the getdq from getinoquota below to read the quota + * from file. + */ + UFS_LOCK(ump); + ump->um_qflags[type] &= ~QTF_CLOSING; + UFS_UNLOCK(ump); + /* + * Search vnodes associated with this mount point, + * adding references to quota file being opened. + * NB: only need to add dquot's for inodes being modified. + */ +again: + MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + goto again; + } + if (vp->v_type == VNON || vp->v_writecount == 0) { + VOP_UNLOCK(vp, 0); + vrele(vp); + continue; + } + error = getinoquota(VTOI(vp)); + VOP_UNLOCK(vp, 0); + vrele(vp); + if (error) { + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + break; + } + } + + if (error) + quotaoff_inchange(td, mp, type); + UFS_LOCK(ump); + ump->um_qflags[type] &= ~QTF_OPENING; + KASSERT((ump->um_qflags[type] & QTF_CLOSING) == 0, + ("quotaon: leaking flags")); + UFS_UNLOCK(ump); + + vfs_unbusy(mp); + return (error); +} + +/* + * Main code to turn off disk quotas for a filesystem. Does not change + * flags. + */ +static int +quotaoff1(struct thread *td, struct mount *mp, int type) +{ + struct vnode *vp; + struct vnode *qvp, *mvp; + struct ufsmount *ump; + struct dquot *dq; + struct inode *ip; + struct ucred *cr; + int error; + + ump = VFSTOUFS(mp); + + UFS_LOCK(ump); + KASSERT((ump->um_qflags[type] & QTF_CLOSING) != 0, + ("quotaoff1: flags are invalid")); + if ((qvp = ump->um_quotas[type]) == NULLVP) { + UFS_UNLOCK(ump); + return (0); + } + cr = ump->um_cred[type]; + UFS_UNLOCK(ump); + + /* + * Search vnodes associated with this mount point, + * deleting any references to quota file being closed. + */ +again: + MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { + if (vp->v_type == VNON) { + VI_UNLOCK(vp); + continue; + } + if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { + MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); + goto again; + } + ip = VTOI(vp); + dq = ip->i_dquot[type]; + ip->i_dquot[type] = NODQUOT; + dqrele(vp, dq); + VOP_UNLOCK(vp, 0); + vrele(vp); + } + + error = dqflush(qvp); + if (error != 0) + return (error); + + /* + * Clear um_quotas before closing the quota vnode to prevent + * access to the closed vnode from dqget/dqsync + */ + UFS_LOCK(ump); + ump->um_quotas[type] = NULLVP; + ump->um_cred[type] = NOCRED; + UFS_UNLOCK(ump); + + vn_lock(qvp, LK_EXCLUSIVE | LK_RETRY); + qvp->v_vflag &= ~VV_SYSTEM; + VOP_UNLOCK(qvp, 0); + error = vn_close(qvp, FREAD|FWRITE, td->td_ucred, td); + crfree(cr); + + return (error); +} + +/* + * Turns off quotas, assumes that ump->um_qflags are already checked + * and QTF_CLOSING is set to indicate operation in progress. Fixes + * ump->um_qflags and mp->mnt_flag after. + */ +int +quotaoff_inchange(struct thread *td, struct mount *mp, int type) +{ + struct ufsmount *ump; + int i; + int error; + + error = quotaoff1(td, mp, type); + + ump = VFSTOUFS(mp); + UFS_LOCK(ump); + ump->um_qflags[type] &= ~QTF_CLOSING; + for (i = 0; i < MAXQUOTAS; i++) + if (ump->um_quotas[i] != NULLVP) + break; + if (i == MAXQUOTAS) { + MNT_ILOCK(mp); + mp->mnt_flag &= ~MNT_QUOTA; + MNT_IUNLOCK(mp); + } + UFS_UNLOCK(ump); + return (error); +} + +/* + * Q_QUOTAOFF - turn off disk quotas for a filesystem. + */ +int +quotaoff(struct thread *td, struct mount *mp, int type) +{ + struct ufsmount *ump; + int error; + + error = priv_check(td, PRIV_UFS_QUOTAOFF); + if (error) + return (error); + + ump = VFSTOUFS(mp); + UFS_LOCK(ump); + if ((ump->um_qflags[type] & (QTF_OPENING|QTF_CLOSING)) != 0) { + UFS_UNLOCK(ump); + return (EALREADY); + } + ump->um_qflags[type] |= QTF_CLOSING; + UFS_UNLOCK(ump); + + return (quotaoff_inchange(td, mp, type)); +} + +/* + * Q_GETQUOTA - return current values in a dqblk structure. + */ +static int +_getquota(struct thread *td, struct mount *mp, u_long id, int type, + struct dqblk64 *dqb) +{ + struct dquot *dq; + int error; + + switch (type) { + case USRQUOTA: + if ((td->td_ucred->cr_uid != id) && !unprivileged_get_quota) { + error = priv_check(td, PRIV_VFS_GETQUOTA); + if (error) + return (error); + } + break; + + case GRPQUOTA: + if (!groupmember(id, td->td_ucred) && + !unprivileged_get_quota) { + error = priv_check(td, PRIV_VFS_GETQUOTA); + if (error) + return (error); + } + break; + + default: + return (EINVAL); + } + + dq = NODQUOT; + error = dqget(NULLVP, id, VFSTOUFS(mp), type, &dq); + if (error) + return (error); + *dqb = dq->dq_dqb; + dqrele(NULLVP, dq); + return (error); +} + +/* + * Q_SETQUOTA - assign an entire dqblk structure. + */ +static int +_setquota(struct thread *td, struct mount *mp, u_long id, int type, + struct dqblk64 *dqb) +{ + struct dquot *dq; + struct dquot *ndq; + struct ufsmount *ump; + struct dqblk64 newlim; + int error; + + error = priv_check(td, PRIV_VFS_SETQUOTA); + if (error) + return (error); + + newlim = *dqb; + + ndq = NODQUOT; + ump = VFSTOUFS(mp); + + error = dqget(NULLVP, id, ump, type, &ndq); + if (error) + return (error); + dq = ndq; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "setqta"); + /* + * Copy all but the current values. + * Reset time limit if previously had no soft limit or were + * under it, but now have a soft limit and are over it. + */ + newlim.dqb_curblocks = dq->dq_curblocks; + newlim.dqb_curinodes = dq->dq_curinodes; + if (dq->dq_id != 0) { + newlim.dqb_btime = dq->dq_btime; + newlim.dqb_itime = dq->dq_itime; + } + if (newlim.dqb_bsoftlimit && + dq->dq_curblocks >= newlim.dqb_bsoftlimit && + (dq->dq_bsoftlimit == 0 || dq->dq_curblocks < dq->dq_bsoftlimit)) + newlim.dqb_btime = time_second + ump->um_btime[type]; + if (newlim.dqb_isoftlimit && + dq->dq_curinodes >= newlim.dqb_isoftlimit && + (dq->dq_isoftlimit == 0 || dq->dq_curinodes < dq->dq_isoftlimit)) + newlim.dqb_itime = time_second + ump->um_itime[type]; + dq->dq_dqb = newlim; + if (dq->dq_curblocks < dq->dq_bsoftlimit) + dq->dq_flags &= ~DQ_BLKS; + if (dq->dq_curinodes < dq->dq_isoftlimit) + dq->dq_flags &= ~DQ_INODS; + if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && + dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) + dq->dq_flags |= DQ_FAKE; + else + dq->dq_flags &= ~DQ_FAKE; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + dqrele(NULLVP, dq); + return (0); +} + +/* + * Q_SETUSE - set current inode and block usage. + */ +static int +_setuse(struct thread *td, struct mount *mp, u_long id, int type, + struct dqblk64 *dqb) +{ + struct dquot *dq; + struct ufsmount *ump; + struct dquot *ndq; + struct dqblk64 usage; + int error; + + error = priv_check(td, PRIV_UFS_SETUSE); + if (error) + return (error); + + usage = *dqb; + + ump = VFSTOUFS(mp); + ndq = NODQUOT; + + error = dqget(NULLVP, id, ump, type, &ndq); + if (error) + return (error); + dq = ndq; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "setuse"); + /* + * Reset time limit if have a soft limit and were + * previously under it, but are now over it. + */ + if (dq->dq_bsoftlimit && dq->dq_curblocks < dq->dq_bsoftlimit && + usage.dqb_curblocks >= dq->dq_bsoftlimit) + dq->dq_btime = time_second + ump->um_btime[type]; + if (dq->dq_isoftlimit && dq->dq_curinodes < dq->dq_isoftlimit && + usage.dqb_curinodes >= dq->dq_isoftlimit) + dq->dq_itime = time_second + ump->um_itime[type]; + dq->dq_curblocks = usage.dqb_curblocks; + dq->dq_curinodes = usage.dqb_curinodes; + if (dq->dq_curblocks < dq->dq_bsoftlimit) + dq->dq_flags &= ~DQ_BLKS; + if (dq->dq_curinodes < dq->dq_isoftlimit) + dq->dq_flags &= ~DQ_INODS; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + dqrele(NULLVP, dq); + return (0); +} + +int +getquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) +{ + struct dqblk32 dqb32; + struct dqblk64 dqb64; + int error; + + error = _getquota(td, mp, id, type, &dqb64); + if (error) + return (error); + dqb64_dqb32(&dqb64, &dqb32); + error = copyout(&dqb32, addr, sizeof(dqb32)); + return (error); +} + +int +setquota32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) +{ + struct dqblk32 dqb32; + struct dqblk64 dqb64; + int error; + + error = copyin(addr, &dqb32, sizeof(dqb32)); + if (error) + return (error); + dqb32_dqb64(&dqb32, &dqb64); + error = _setquota(td, mp, id, type, &dqb64); + return (error); +} + +int +setuse32(struct thread *td, struct mount *mp, u_long id, int type, void *addr) +{ + struct dqblk32 dqb32; + struct dqblk64 dqb64; + int error; + + error = copyin(addr, &dqb32, sizeof(dqb32)); + if (error) + return (error); + dqb32_dqb64(&dqb32, &dqb64); + error = _setuse(td, mp, id, type, &dqb64); + return (error); +} + +int +getquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr) +{ + struct dqblk64 dqb64; + int error; + + error = _getquota(td, mp, id, type, &dqb64); + if (error) + return (error); + error = copyout(&dqb64, addr, sizeof(dqb64)); + return (error); +} + +int +setquota(struct thread *td, struct mount *mp, u_long id, int type, void *addr) +{ + struct dqblk64 dqb64; + int error; + + error = copyin(addr, &dqb64, sizeof(dqb64)); + if (error) + return (error); + error = _setquota(td, mp, id, type, &dqb64); + return (error); +} + +int +setuse(struct thread *td, struct mount *mp, u_long id, int type, void *addr) +{ + struct dqblk64 dqb64; + int error; + + error = copyin(addr, &dqb64, sizeof(dqb64)); + if (error) + return (error); + error = _setuse(td, mp, id, type, &dqb64); + return (error); +} + +/* + * Q_GETQUOTASIZE - get bit-size of quota file fields + */ +int +getquotasize(struct thread *td, struct mount *mp, u_long id, int type, + void *sizep) +{ + struct ufsmount *ump = VFSTOUFS(mp); + int bitsize; + + UFS_LOCK(ump); + if (ump->um_quotas[type] == NULLVP || + (ump->um_qflags[type] & QTF_CLOSING)) { + UFS_UNLOCK(ump); + return (EINVAL); + } + if ((ump->um_qflags[type] & QTF_64BIT) != 0) + bitsize = 64; + else + bitsize = 32; + UFS_UNLOCK(ump); + return (copyout(&bitsize, sizep, sizeof(int))); +} + +/* + * Q_SYNC - sync quota files to disk. + */ +int +qsync(struct mount *mp) +{ + struct ufsmount *ump = VFSTOUFS(mp); + struct thread *td = curthread; /* XXX */ + struct vnode *vp, *mvp; + struct dquot *dq; + int i, error; + + /* + * Check if the mount point has any quotas. + * If not, simply return. + */ + for (i = 0; i < MAXQUOTAS; i++) + if (ump->um_quotas[i] != NULLVP) + break; + if (i == MAXQUOTAS) + return (0); + /* + * Search vnodes associated with this mount point, + * synchronizing any modified dquot structures. + */ +again: + MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) { + if (vp->v_type == VNON) { + VI_UNLOCK(vp); + continue; + } + error = vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td); + if (error) { + if (error == ENOENT) { + MNT_VNODE_FOREACH_ACTIVE_ABORT(mp, mvp); + goto again; + } + continue; + } + for (i = 0; i < MAXQUOTAS; i++) { + dq = VTOI(vp)->i_dquot[i]; + if (dq != NODQUOT) + dqsync(vp, dq); + } + vput(vp); + } + return (0); +} + +/* + * Sync quota file for given vnode to disk. + */ +int +qsyncvp(struct vnode *vp) +{ + struct ufsmount *ump = VFSTOUFS(vp->v_mount); + struct dquot *dq; + int i; + + /* + * Check if the mount point has any quotas. + * If not, simply return. + */ + for (i = 0; i < MAXQUOTAS; i++) + if (ump->um_quotas[i] != NULLVP) + break; + if (i == MAXQUOTAS) + return (0); + /* + * Search quotas associated with this vnode + * synchronizing any modified dquot structures. + */ + for (i = 0; i < MAXQUOTAS; i++) { + dq = VTOI(vp)->i_dquot[i]; + if (dq != NODQUOT) + dqsync(vp, dq); + } + return (0); +} + +/* + * Code pertaining to management of the in-core dquot data structures. + */ +#define DQHASH(dqvp, id) \ + (&dqhashtbl[((((intptr_t)(dqvp)) >> 8) + id) & dqhash]) +static LIST_HEAD(dqhash, dquot) *dqhashtbl; +static u_long dqhash; + +/* + * Dquot free list. + */ +#define DQUOTINC 5 /* minimum free dquots desired */ +static TAILQ_HEAD(dqfreelist, dquot) dqfreelist; +static long numdquot, desireddquot = DQUOTINC; + +/* + * Lock to protect quota hash, dq free list and dq_cnt ref counters of + * _all_ dqs. + */ +struct mtx dqhlock; + +#define DQH_LOCK() mtx_lock(&dqhlock) +#define DQH_UNLOCK() mtx_unlock(&dqhlock) + +static struct dquot *dqhashfind(struct dqhash *dqh, u_long id, + struct vnode *dqvp); + +/* + * Initialize the quota system. + */ +void +dqinit(void) +{ + + mtx_init(&dqhlock, "dqhlock", NULL, MTX_DEF); + dqhashtbl = hashinit(desiredvnodes, M_DQUOT, &dqhash); + TAILQ_INIT(&dqfreelist); +} + +/* + * Shut down the quota system. + */ +void +dquninit(void) +{ + struct dquot *dq; + + hashdestroy(dqhashtbl, M_DQUOT, dqhash); + while ((dq = TAILQ_FIRST(&dqfreelist)) != NULL) { + TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); + mtx_destroy(&dq->dq_lock); + free(dq, M_DQUOT); + } + mtx_destroy(&dqhlock); +} + +static struct dquot * +dqhashfind(struct dqhash *dqh, u_long id, struct vnode *dqvp) +{ + struct dquot *dq; + + mtx_assert(&dqhlock, MA_OWNED); + LIST_FOREACH(dq, dqh, dq_hash) { + if (dq->dq_id != id || + dq->dq_ump->um_quotas[dq->dq_type] != dqvp) + continue; + /* + * Cache hit with no references. Take + * the structure off the free list. + */ + if (dq->dq_cnt == 0) + TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); + DQREF(dq); + return (dq); + } + return (NODQUOT); +} + +/* + * Determine the quota file type. + * + * A 32-bit quota file is simply an array of struct dqblk32. + * + * A 64-bit quota file is a struct dqhdr64 followed by an array of struct + * dqblk64. The header contains various magic bits which allow us to be + * reasonably confident that it is indeeda 64-bit quota file and not just + * a 32-bit quota file that just happens to "look right". + * + */ +static int +dqopen(struct vnode *vp, struct ufsmount *ump, int type) +{ + struct dqhdr64 dqh; + struct iovec aiov; + struct uio auio; + int error; + + ASSERT_VOP_LOCKED(vp, "dqopen"); + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = &dqh; + aiov.iov_len = sizeof(dqh); + auio.uio_resid = sizeof(dqh); + auio.uio_offset = 0; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_READ; + auio.uio_td = (struct thread *)0; + error = VOP_READ(vp, &auio, 0, ump->um_cred[type]); + + if (error != 0) + return (error); + if (auio.uio_resid > 0) { + /* assume 32 bits */ + return (0); + } + + UFS_LOCK(ump); + if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) == 0 && + be32toh(dqh.dqh_version) == Q_DQHDR64_VERSION && + be32toh(dqh.dqh_hdrlen) == (uint32_t)sizeof(struct dqhdr64) && + be32toh(dqh.dqh_reclen) == (uint32_t)sizeof(struct dqblk64)) { + /* XXX: what if the magic matches, but the sizes are wrong? */ + ump->um_qflags[type] |= QTF_64BIT; + } else { + ump->um_qflags[type] &= ~QTF_64BIT; + } + UFS_UNLOCK(ump); + + return (0); +} + +/* + * Obtain a dquot structure for the specified identifier and quota file + * reading the information from the file if necessary. + */ +static int +dqget(struct vnode *vp, u_long id, struct ufsmount *ump, int type, + struct dquot **dqp) +{ + uint8_t buf[sizeof(struct dqblk64)]; + off_t base, recsize; + struct dquot *dq, *dq1; + struct dqhash *dqh; + struct vnode *dqvp; + struct iovec aiov; + struct uio auio; + int dqvplocked, error; + +#ifdef DEBUG_VFS_LOCKS + if (vp != NULLVP) + ASSERT_VOP_ELOCKED(vp, "dqget"); +#endif + + if (vp != NULLVP && *dqp != NODQUOT) { + return (0); + } + + /* XXX: Disallow negative id values to prevent the + * creation of 100GB+ quota data files. + */ + if ((int)id < 0) + return (EINVAL); + + UFS_LOCK(ump); + dqvp = ump->um_quotas[type]; + if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) { + *dqp = NODQUOT; + UFS_UNLOCK(ump); + return (EINVAL); + } + vref(dqvp); + UFS_UNLOCK(ump); + error = 0; + dqvplocked = 0; + + /* + * Check the cache first. + */ + dqh = DQHASH(dqvp, id); + DQH_LOCK(); + dq = dqhashfind(dqh, id, dqvp); + if (dq != NULL) { + DQH_UNLOCK(); +hfound: DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "dqget"); + DQI_UNLOCK(dq); + if (dq->dq_ump == NULL) { + dqrele(vp, dq); + dq = NODQUOT; + error = EIO; + } + *dqp = dq; + if (dqvplocked) + vput(dqvp); + else + vrele(dqvp); + return (error); + } + + /* + * Quota vnode lock is before DQ_LOCK. Acquire dqvp lock there + * since new dq will appear on the hash chain DQ_LOCKed. + */ + if (vp != dqvp) { + DQH_UNLOCK(); + vn_lock(dqvp, LK_SHARED | LK_RETRY); + dqvplocked = 1; + DQH_LOCK(); + /* + * Recheck the cache after sleep for quota vnode lock. + */ + dq = dqhashfind(dqh, id, dqvp); + if (dq != NULL) { + DQH_UNLOCK(); + goto hfound; + } + } + + /* + * Not in cache, allocate a new one or take it from the + * free list. + */ + if (TAILQ_FIRST(&dqfreelist) == NODQUOT && + numdquot < MAXQUOTAS * desiredvnodes) + desireddquot += DQUOTINC; + if (numdquot < desireddquot) { + numdquot++; + DQH_UNLOCK(); + dq1 = malloc(sizeof *dq1, M_DQUOT, M_WAITOK | M_ZERO); + mtx_init(&dq1->dq_lock, "dqlock", NULL, MTX_DEF); + DQH_LOCK(); + /* + * Recheck the cache after sleep for memory. + */ + dq = dqhashfind(dqh, id, dqvp); + if (dq != NULL) { + numdquot--; + DQH_UNLOCK(); + mtx_destroy(&dq1->dq_lock); + free(dq1, M_DQUOT); + goto hfound; + } + dq = dq1; + } else { + if ((dq = TAILQ_FIRST(&dqfreelist)) == NULL) { + DQH_UNLOCK(); + tablefull("dquot"); + *dqp = NODQUOT; + if (dqvplocked) + vput(dqvp); + else + vrele(dqvp); + return (EUSERS); + } + if (dq->dq_cnt || (dq->dq_flags & DQ_MOD)) + panic("dqget: free dquot isn't %p", dq); + TAILQ_REMOVE(&dqfreelist, dq, dq_freelist); + if (dq->dq_ump != NULL) + LIST_REMOVE(dq, dq_hash); + } + + /* + * Dq is put into hash already locked to prevent parallel + * usage while it is being read from file. + */ + dq->dq_flags = DQ_LOCK; + dq->dq_id = id; + dq->dq_type = type; + dq->dq_ump = ump; + LIST_INSERT_HEAD(dqh, dq, dq_hash); + DQREF(dq); + DQH_UNLOCK(); + + /* + * Read the requested quota record from the quota file, performing + * any necessary conversions. + */ + if (ump->um_qflags[type] & QTF_64BIT) { + recsize = sizeof(struct dqblk64); + base = sizeof(struct dqhdr64); + } else { + recsize = sizeof(struct dqblk32); + base = 0; + } + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = buf; + aiov.iov_len = recsize; + auio.uio_resid = recsize; + auio.uio_offset = base + id * recsize; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_READ; + auio.uio_td = (struct thread *)0; + + error = VOP_READ(dqvp, &auio, 0, ump->um_cred[type]); + if (auio.uio_resid == recsize && error == 0) { + bzero(&dq->dq_dqb, sizeof(dq->dq_dqb)); + } else { + if (ump->um_qflags[type] & QTF_64BIT) + dqb64_dq((struct dqblk64 *)buf, dq); + else + dqb32_dq((struct dqblk32 *)buf, dq); + } + if (dqvplocked) + vput(dqvp); + else + vrele(dqvp); + /* + * I/O error in reading quota file, release + * quota structure and reflect problem to caller. + */ + if (error) { + DQH_LOCK(); + dq->dq_ump = NULL; + LIST_REMOVE(dq, dq_hash); + DQH_UNLOCK(); + DQI_LOCK(dq); + if (dq->dq_flags & DQ_WANT) + wakeup(dq); + dq->dq_flags = 0; + DQI_UNLOCK(dq); + dqrele(vp, dq); + *dqp = NODQUOT; + return (error); + } + DQI_LOCK(dq); + /* + * Check for no limit to enforce. + * Initialize time values if necessary. + */ + if (dq->dq_isoftlimit == 0 && dq->dq_bsoftlimit == 0 && + dq->dq_ihardlimit == 0 && dq->dq_bhardlimit == 0) + dq->dq_flags |= DQ_FAKE; + if (dq->dq_id != 0) { + if (dq->dq_btime == 0) { + dq->dq_btime = time_second + ump->um_btime[type]; + if (dq->dq_bsoftlimit && + dq->dq_curblocks >= dq->dq_bsoftlimit) + dq->dq_flags |= DQ_MOD; + } + if (dq->dq_itime == 0) { + dq->dq_itime = time_second + ump->um_itime[type]; + if (dq->dq_isoftlimit && + dq->dq_curinodes >= dq->dq_isoftlimit) + dq->dq_flags |= DQ_MOD; + } + } + DQI_WAKEUP(dq); + DQI_UNLOCK(dq); + *dqp = dq; + return (0); +} + +#ifdef DIAGNOSTIC +/* + * Obtain a reference to a dquot. + */ +static void +dqref(struct dquot *dq) +{ + + dq->dq_cnt++; +} +#endif + +/* + * Release a reference to a dquot. + */ +void +dqrele(struct vnode *vp, struct dquot *dq) +{ + + if (dq == NODQUOT) + return; + DQH_LOCK(); + KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 1", dq)); + if (dq->dq_cnt > 1) { + dq->dq_cnt--; + DQH_UNLOCK(); + return; + } + DQH_UNLOCK(); +sync: + (void) dqsync(vp, dq); + + DQH_LOCK(); + KASSERT(dq->dq_cnt > 0, ("Lost dq %p reference 2", dq)); + if (--dq->dq_cnt > 0) + { + DQH_UNLOCK(); + return; + } + + /* + * The dq may become dirty after it is synced but before it is + * put to the free list. Checking the DQ_MOD there without + * locking dq should be safe since no other references to the + * dq exist. + */ + if ((dq->dq_flags & DQ_MOD) != 0) { + dq->dq_cnt++; + DQH_UNLOCK(); + goto sync; + } + TAILQ_INSERT_TAIL(&dqfreelist, dq, dq_freelist); + DQH_UNLOCK(); +} + +/* + * Update the disk quota in the quota file. + */ +static int +dqsync(struct vnode *vp, struct dquot *dq) +{ + uint8_t buf[sizeof(struct dqblk64)]; + off_t base, recsize; + struct vnode *dqvp; + struct iovec aiov; + struct uio auio; + int error; + struct mount *mp; + struct ufsmount *ump; + +#ifdef DEBUG_VFS_LOCKS + if (vp != NULL) + ASSERT_VOP_ELOCKED(vp, "dqsync"); +#endif + + mp = NULL; + error = 0; + if (dq == NODQUOT) + panic("dqsync: dquot"); + if ((ump = dq->dq_ump) == NULL) + return (0); + UFS_LOCK(ump); + if ((dqvp = ump->um_quotas[dq->dq_type]) == NULLVP) { + if (vp == NULL) { + UFS_UNLOCK(ump); + return (0); + } else + panic("dqsync: file"); + } + vref(dqvp); + UFS_UNLOCK(ump); + + DQI_LOCK(dq); + if ((dq->dq_flags & DQ_MOD) == 0) { + DQI_UNLOCK(dq); + vrele(dqvp); + return (0); + } + DQI_UNLOCK(dq); + + (void) vn_start_secondary_write(dqvp, &mp, V_WAIT); + if (vp != dqvp) + vn_lock(dqvp, LK_EXCLUSIVE | LK_RETRY); + + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+2, "dqsync"); + if ((dq->dq_flags & DQ_MOD) == 0) + goto out; + dq->dq_flags |= DQ_LOCK; + DQI_UNLOCK(dq); + + /* + * Write the quota record to the quota file, performing any + * necessary conversions. See dqget() for additional details. + */ + if (ump->um_qflags[dq->dq_type] & QTF_64BIT) { + dq_dqb64(dq, (struct dqblk64 *)buf); + recsize = sizeof(struct dqblk64); + base = sizeof(struct dqhdr64); + } else { + dq_dqb32(dq, (struct dqblk32 *)buf); + recsize = sizeof(struct dqblk32); + base = 0; + } + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + aiov.iov_base = buf; + aiov.iov_len = recsize; + auio.uio_resid = recsize; + auio.uio_offset = base + dq->dq_id * recsize; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_td = (struct thread *)0; + error = VOP_WRITE(dqvp, &auio, 0, dq->dq_ump->um_cred[dq->dq_type]); + if (auio.uio_resid && error == 0) + error = EIO; + + DQI_LOCK(dq); + DQI_WAKEUP(dq); + dq->dq_flags &= ~DQ_MOD; +out: + DQI_UNLOCK(dq); + if (vp != dqvp) + vput(dqvp); + else + vrele(dqvp); + vn_finished_secondary_write(mp); + return (error); +} + +/* + * Flush all entries from the cache for a particular vnode. + */ +static int +dqflush(struct vnode *vp) +{ + struct dquot *dq, *nextdq; + struct dqhash *dqh; + int error; + + /* + * Move all dquot's that used to refer to this quota + * file off their hash chains (they will eventually + * fall off the head of the free list and be re-used). + */ + error = 0; + DQH_LOCK(); + for (dqh = &dqhashtbl[dqhash]; dqh >= dqhashtbl; dqh--) { + for (dq = LIST_FIRST(dqh); dq; dq = nextdq) { + nextdq = LIST_NEXT(dq, dq_hash); + if (dq->dq_ump->um_quotas[dq->dq_type] != vp) + continue; + if (dq->dq_cnt) + error = EBUSY; + else { + LIST_REMOVE(dq, dq_hash); + dq->dq_ump = NULL; + } + } + } + DQH_UNLOCK(); + return (error); +} + +/* + * The following three functions are provided for the adjustment of + * quotas by the soft updates code. + */ +#ifdef SOFTUPDATES +/* + * Acquire a reference to the quota structures associated with a vnode. + * Return count of number of quota structures found. + */ +int +quotaref(vp, qrp) + struct vnode *vp; + struct dquot **qrp; +{ + struct inode *ip; + struct dquot *dq; + int i, found; + + for (i = 0; i < MAXQUOTAS; i++) + qrp[i] = NODQUOT; + /* + * Disk quotas must be turned off for system files. Currently + * snapshot and quota files. + */ + if ((vp->v_vflag & VV_SYSTEM) != 0) + return (0); + /* + * Iterate through and copy active quotas. + */ + found = 0; + ip = VTOI(vp); + mtx_lock(&dqhlock); + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = ip->i_dquot[i]) == NODQUOT) + continue; + DQREF(dq); + qrp[i] = dq; + found++; + } + mtx_unlock(&dqhlock); + return (found); +} + +/* + * Release a set of quota structures obtained from a vnode. + */ +void +quotarele(qrp) + struct dquot **qrp; +{ + struct dquot *dq; + int i; + + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = qrp[i]) == NODQUOT) + continue; + dqrele(NULL, dq); + } +} + +/* + * Adjust the number of blocks associated with a quota. + * Positive numbers when adding blocks; negative numbers when freeing blocks. + */ +void +quotaadj(qrp, ump, blkcount) + struct dquot **qrp; + struct ufsmount *ump; + int64_t blkcount; +{ + struct dquot *dq; + ufs2_daddr_t ncurblocks; + int i; + + if (blkcount == 0) + return; + for (i = 0; i < MAXQUOTAS; i++) { + if ((dq = qrp[i]) == NODQUOT) + continue; + DQI_LOCK(dq); + DQI_WAIT(dq, PINOD+1, "adjqta"); + ncurblocks = dq->dq_curblocks + blkcount; + if (ncurblocks >= 0) + dq->dq_curblocks = ncurblocks; + else + dq->dq_curblocks = 0; + if (blkcount < 0) + dq->dq_flags &= ~DQ_BLKS; + else if (dq->dq_curblocks + blkcount >= dq->dq_bsoftlimit && + dq->dq_curblocks < dq->dq_bsoftlimit) + dq->dq_btime = time_second + ump->um_btime[i]; + dq->dq_flags |= DQ_MOD; + DQI_UNLOCK(dq); + } +} +#endif /* SOFTUPDATES */ + +/* + * 32-bit / 64-bit conversion functions. + * + * 32-bit quota records are stored in native byte order. Attention must + * be paid to overflow issues. + * + * 64-bit quota records are stored in network byte order. + */ + +#define CLIP32(u64) (u64 > UINT32_MAX ? UINT32_MAX : (uint32_t)u64) + +/* + * Convert 32-bit host-order structure to dquot. + */ +static void +dqb32_dq(const struct dqblk32 *dqb32, struct dquot *dq) +{ + + dq->dq_bhardlimit = dqb32->dqb_bhardlimit; + dq->dq_bsoftlimit = dqb32->dqb_bsoftlimit; + dq->dq_curblocks = dqb32->dqb_curblocks; + dq->dq_ihardlimit = dqb32->dqb_ihardlimit; + dq->dq_isoftlimit = dqb32->dqb_isoftlimit; + dq->dq_curinodes = dqb32->dqb_curinodes; + dq->dq_btime = dqb32->dqb_btime; + dq->dq_itime = dqb32->dqb_itime; +} + +/* + * Convert 64-bit network-order structure to dquot. + */ +static void +dqb64_dq(const struct dqblk64 *dqb64, struct dquot *dq) +{ + + dq->dq_bhardlimit = be64toh(dqb64->dqb_bhardlimit); + dq->dq_bsoftlimit = be64toh(dqb64->dqb_bsoftlimit); + dq->dq_curblocks = be64toh(dqb64->dqb_curblocks); + dq->dq_ihardlimit = be64toh(dqb64->dqb_ihardlimit); + dq->dq_isoftlimit = be64toh(dqb64->dqb_isoftlimit); + dq->dq_curinodes = be64toh(dqb64->dqb_curinodes); + dq->dq_btime = be64toh(dqb64->dqb_btime); + dq->dq_itime = be64toh(dqb64->dqb_itime); +} + +/* + * Convert dquot to 32-bit host-order structure. + */ +static void +dq_dqb32(const struct dquot *dq, struct dqblk32 *dqb32) +{ + + dqb32->dqb_bhardlimit = CLIP32(dq->dq_bhardlimit); + dqb32->dqb_bsoftlimit = CLIP32(dq->dq_bsoftlimit); + dqb32->dqb_curblocks = CLIP32(dq->dq_curblocks); + dqb32->dqb_ihardlimit = CLIP32(dq->dq_ihardlimit); + dqb32->dqb_isoftlimit = CLIP32(dq->dq_isoftlimit); + dqb32->dqb_curinodes = CLIP32(dq->dq_curinodes); + dqb32->dqb_btime = CLIP32(dq->dq_btime); + dqb32->dqb_itime = CLIP32(dq->dq_itime); +} + +/* + * Convert dquot to 64-bit network-order structure. + */ +static void +dq_dqb64(const struct dquot *dq, struct dqblk64 *dqb64) +{ + + dqb64->dqb_bhardlimit = htobe64(dq->dq_bhardlimit); + dqb64->dqb_bsoftlimit = htobe64(dq->dq_bsoftlimit); + dqb64->dqb_curblocks = htobe64(dq->dq_curblocks); + dqb64->dqb_ihardlimit = htobe64(dq->dq_ihardlimit); + dqb64->dqb_isoftlimit = htobe64(dq->dq_isoftlimit); + dqb64->dqb_curinodes = htobe64(dq->dq_curinodes); + dqb64->dqb_btime = htobe64(dq->dq_btime); + dqb64->dqb_itime = htobe64(dq->dq_itime); +} + +/* + * Convert 64-bit host-order structure to 32-bit host-order structure. + */ +static void +dqb64_dqb32(const struct dqblk64 *dqb64, struct dqblk32 *dqb32) +{ + + dqb32->dqb_bhardlimit = CLIP32(dqb64->dqb_bhardlimit); + dqb32->dqb_bsoftlimit = CLIP32(dqb64->dqb_bsoftlimit); + dqb32->dqb_curblocks = CLIP32(dqb64->dqb_curblocks); + dqb32->dqb_ihardlimit = CLIP32(dqb64->dqb_ihardlimit); + dqb32->dqb_isoftlimit = CLIP32(dqb64->dqb_isoftlimit); + dqb32->dqb_curinodes = CLIP32(dqb64->dqb_curinodes); + dqb32->dqb_btime = CLIP32(dqb64->dqb_btime); + dqb32->dqb_itime = CLIP32(dqb64->dqb_itime); +} + +/* + * Convert 32-bit host-order structure to 64-bit host-order structure. + */ +static void +dqb32_dqb64(const struct dqblk32 *dqb32, struct dqblk64 *dqb64) +{ + + dqb64->dqb_bhardlimit = dqb32->dqb_bhardlimit; + dqb64->dqb_bsoftlimit = dqb32->dqb_bsoftlimit; + dqb64->dqb_curblocks = dqb32->dqb_curblocks; + dqb64->dqb_ihardlimit = dqb32->dqb_ihardlimit; + dqb64->dqb_isoftlimit = dqb32->dqb_isoftlimit; + dqb64->dqb_curinodes = dqb32->dqb_curinodes; + dqb64->dqb_btime = dqb32->dqb_btime; + dqb64->dqb_itime = dqb32->dqb_itime; +} diff --git a/Dump/ufs/ufs/ufs_vfsops.c b/Dump/ufs/ufs/ufs_vfsops.c new file mode 100644 index 0000000..461cd73 --- /dev/null +++ b/Dump/ufs/ufs/ufs_vfsops.c @@ -0,0 +1,244 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_vfsops.c 8.8 (Berkeley) 5/20/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_vfsops.c 331722 2018-03-29 02:50:57Z eadler $"); + +#include "opt_quota.h" +#include "opt_ufs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef UFS_DIRHASH +#include +#include +#endif + +MALLOC_DEFINE(M_UFSMNT, "ufs_mount", "UFS mount structure"); + +/* + * Return the root of a filesystem. + */ +int +ufs_root(mp, flags, vpp) + struct mount *mp; + int flags; + struct vnode **vpp; +{ + struct vnode *nvp; + int error; + + error = VFS_VGET(mp, (ino_t)ROOTINO, flags, &nvp); + if (error) + return (error); + *vpp = nvp; + return (0); +} + +/* + * Do operations associated with quotas + */ +int +ufs_quotactl(mp, cmds, id, arg) + struct mount *mp; + int cmds; + uid_t id; + void *arg; +{ +#ifndef QUOTA + if ((cmds >> SUBCMDSHIFT) == Q_QUOTAON) + vfs_unbusy(mp); + + return (EOPNOTSUPP); +#else + struct thread *td; + int cmd, type, error; + + td = curthread; + cmd = cmds >> SUBCMDSHIFT; + type = cmds & SUBCMDMASK; + if (id == -1) { + switch (type) { + + case USRQUOTA: + id = td->td_ucred->cr_ruid; + break; + + case GRPQUOTA: + id = td->td_ucred->cr_rgid; + break; + + default: + if (cmd == Q_QUOTAON) + vfs_unbusy(mp); + return (EINVAL); + } + } + if ((u_int)type >= MAXQUOTAS) { + if (cmd == Q_QUOTAON) + vfs_unbusy(mp); + return (EINVAL); + } + + switch (cmd) { + case Q_QUOTAON: + error = quotaon(td, mp, type, arg); + break; + + case Q_QUOTAOFF: + error = quotaoff(td, mp, type); + break; + + case Q_SETQUOTA32: + error = setquota32(td, mp, id, type, arg); + break; + + case Q_SETUSE32: + error = setuse32(td, mp, id, type, arg); + break; + + case Q_GETQUOTA32: + error = getquota32(td, mp, id, type, arg); + break; + + case Q_SETQUOTA: + error = setquota(td, mp, id, type, arg); + break; + + case Q_SETUSE: + error = setuse(td, mp, id, type, arg); + break; + + case Q_GETQUOTA: + error = getquota(td, mp, id, type, arg); + break; + + case Q_GETQUOTASIZE: + error = getquotasize(td, mp, id, type, arg); + break; + + case Q_SYNC: + error = qsync(mp); + break; + + default: + error = EINVAL; + break; + } + return (error); +#endif +} + +/* + * Initial UFS filesystems, done only once. + */ +int +ufs_init(vfsp) + struct vfsconf *vfsp; +{ + +#ifdef QUOTA + dqinit(); +#endif +#ifdef UFS_DIRHASH + ufsdirhash_init(); +#endif + return (0); +} + +/* + * Uninitialise UFS filesystems, done before module unload. + */ +int +ufs_uninit(vfsp) + struct vfsconf *vfsp; +{ + +#ifdef QUOTA + dquninit(); +#endif +#ifdef UFS_DIRHASH + ufsdirhash_uninit(); +#endif + return (0); +} + +/* + * This is the generic part of fhtovp called after the underlying + * filesystem has validated the file handle. + * + * Call the VFS_CHECKEXP beforehand to verify access. + */ +int +ufs_fhtovp(mp, ufhp, flags, vpp) + struct mount *mp; + struct ufid *ufhp; + int flags; + struct vnode **vpp; +{ + struct inode *ip; + struct vnode *nvp; + int error; + + error = VFS_VGET(mp, ufhp->ufid_ino, flags, &nvp); + if (error) { + *vpp = NULLVP; + return (error); + } + ip = VTOI(nvp); + if (ip->i_mode == 0 || ip->i_gen != ufhp->ufid_gen || + ip->i_effnlink <= 0) { + vput(nvp); + *vpp = NULLVP; + return (ESTALE); + } + *vpp = nvp; + vnode_create_vobject(*vpp, DIP(ip, i_size), curthread); + return (0); +} diff --git a/Dump/ufs/ufs/ufs_vnops.c b/Dump/ufs/ufs/ufs_vnops.c new file mode 100644 index 0000000..66662a6 --- /dev/null +++ b/Dump/ufs/ufs/ufs_vnops.c @@ -0,0 +1,2805 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95 + */ + +#include +__FBSDID("$FreeBSD: releng/11.2/sys/ufs/ufs/ufs_vnops.c 332749 2018-04-19 02:47:21Z pfg $"); + +#include "opt_quota.h" +#include "opt_suiddir.h" +#include "opt_ufs.h" +#include "opt_ffs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include /* XXX */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef UFS_DIRHASH +#include +#endif +#ifdef UFS_GJOURNAL +#include +FEATURE(ufs_gjournal, "Journaling support through GEOM for UFS"); +#endif + +#ifdef QUOTA +FEATURE(ufs_quota, "UFS disk quotas support"); +FEATURE(ufs_quota64, "64bit UFS disk quotas support"); +#endif + +#ifdef SUIDDIR +FEATURE(suiddir, + "Give all new files in directory the same ownership as the directory"); +#endif + + +#include + +static vop_accessx_t ufs_accessx; +static int ufs_chmod(struct vnode *, int, struct ucred *, struct thread *); +static int ufs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct thread *); +static vop_close_t ufs_close; +static vop_create_t ufs_create; +static vop_getattr_t ufs_getattr; +static vop_ioctl_t ufs_ioctl; +static vop_link_t ufs_link; +static int ufs_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *, const char *); +static vop_markatime_t ufs_markatime; +static vop_mkdir_t ufs_mkdir; +static vop_mknod_t ufs_mknod; +static vop_open_t ufs_open; +static vop_pathconf_t ufs_pathconf; +static vop_print_t ufs_print; +static vop_readlink_t ufs_readlink; +static vop_remove_t ufs_remove; +static vop_rename_t ufs_rename; +static vop_rmdir_t ufs_rmdir; +static vop_setattr_t ufs_setattr; +static vop_strategy_t ufs_strategy; +static vop_symlink_t ufs_symlink; +static vop_whiteout_t ufs_whiteout; +static vop_close_t ufsfifo_close; +static vop_kqfilter_t ufsfifo_kqfilter; + +SYSCTL_NODE(_vfs, OID_AUTO, ufs, CTLFLAG_RD, 0, "UFS filesystem"); + +/* + * A virgin directory (no blushing please). + */ +static struct dirtemplate mastertemplate = { + 0, 12, DT_DIR, 1, ".", + 0, DIRBLKSIZ - 12, DT_DIR, 2, ".." +}; +static struct odirtemplate omastertemplate = { + 0, 12, 1, ".", + 0, DIRBLKSIZ - 12, 2, ".." +}; + +static void +ufs_itimes_locked(struct vnode *vp) +{ + struct inode *ip; + struct timespec ts; + + ASSERT_VI_LOCKED(vp, __func__); + + ip = VTOI(vp); + if (UFS_RDONLY(ip)) + goto out; + if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) + return; + + if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp)) + ip->i_flag |= IN_LAZYMOD; + else if (((vp->v_mount->mnt_kern_flag & + (MNTK_SUSPENDED | MNTK_SUSPEND)) == 0) || + (ip->i_flag & (IN_CHANGE | IN_UPDATE))) + ip->i_flag |= IN_MODIFIED; + else if (ip->i_flag & IN_ACCESS) + ip->i_flag |= IN_LAZYACCESS; + vfs_timestamp(&ts); + if (ip->i_flag & IN_ACCESS) { + DIP_SET(ip, i_atime, ts.tv_sec); + DIP_SET(ip, i_atimensec, ts.tv_nsec); + } + if (ip->i_flag & IN_UPDATE) { + DIP_SET(ip, i_mtime, ts.tv_sec); + DIP_SET(ip, i_mtimensec, ts.tv_nsec); + } + if (ip->i_flag & IN_CHANGE) { + DIP_SET(ip, i_ctime, ts.tv_sec); + DIP_SET(ip, i_ctimensec, ts.tv_nsec); + DIP_SET(ip, i_modrev, DIP(ip, i_modrev) + 1); + } + + out: + ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); +} + +void +ufs_itimes(struct vnode *vp) +{ + + VI_LOCK(vp); + ufs_itimes_locked(vp); + VI_UNLOCK(vp); +} + +/* + * Create a regular file + */ +static int +ufs_create(ap) + struct vop_create_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap; +{ + int error; + + error = + ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode), + ap->a_dvp, ap->a_vpp, ap->a_cnp, "ufs_create"); + if (error != 0) + return (error); + if ((ap->a_cnp->cn_flags & MAKEENTRY) != 0) + cache_enter(ap->a_dvp, *ap->a_vpp, ap->a_cnp); + return (0); +} + +/* + * Mknod vnode call + */ +/* ARGSUSED */ +static int +ufs_mknod(ap) + struct vop_mknod_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap; +{ + struct vattr *vap = ap->a_vap; + struct vnode **vpp = ap->a_vpp; + struct inode *ip; + ino_t ino; + int error; + + error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), + ap->a_dvp, vpp, ap->a_cnp, "ufs_mknod"); + if (error) + return (error); + ip = VTOI(*vpp); + ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; + if (vap->va_rdev != VNOVAL) { + /* + * Want to be able to use this to make badblock + * inodes, so don't truncate the dev number. + */ + DIP_SET(ip, i_rdev, vap->va_rdev); + } + /* + * Remove inode, then reload it through VFS_VGET so it is + * checked to see if it is an alias of an existing entry in + * the inode cache. XXX I don't believe this is necessary now. + */ + (*vpp)->v_type = VNON; + ino = ip->i_number; /* Save this before vgone() invalidates ip. */ + vgone(*vpp); + vput(*vpp); + error = VFS_VGET(ap->a_dvp->v_mount, ino, LK_EXCLUSIVE, vpp); + if (error) { + *vpp = NULL; + return (error); + } + return (0); +} + +/* + * Open called. + */ +/* ARGSUSED */ +static int +ufs_open(struct vop_open_args *ap) +{ + struct vnode *vp = ap->a_vp; + struct inode *ip; + + if (vp->v_type == VCHR || vp->v_type == VBLK) + return (EOPNOTSUPP); + + ip = VTOI(vp); + /* + * Files marked append-only must be opened for appending. + */ + if ((ip->i_flags & APPEND) && + (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) + return (EPERM); + vnode_create_vobject(vp, DIP(ip, i_size), ap->a_td); + return (0); +} + +/* + * Close called. + * + * Update the times on the inode. + */ +/* ARGSUSED */ +static int +ufs_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + int usecount; + + VI_LOCK(vp); + usecount = vp->v_usecount; + if (usecount > 1) + ufs_itimes_locked(vp); + VI_UNLOCK(vp); + return (0); +} + +static int +ufs_accessx(ap) + struct vop_accessx_args /* { + struct vnode *a_vp; + accmode_t a_accmode; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + accmode_t accmode = ap->a_accmode; + int error; +#ifdef QUOTA + int relocked; +#endif +#ifdef UFS_ACL + struct acl *acl; + acl_type_t type; +#endif + + /* + * Disallow write attempts on read-only filesystems; + * unless the file is a socket, fifo, or a block or + * character device resident on the filesystem. + */ + if (accmode & VMODIFY_PERMS) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); +#ifdef QUOTA + /* + * Inode is accounted in the quotas only if struct + * dquot is attached to it. VOP_ACCESS() is called + * from vn_open_cred() and provides a convenient + * point to call getinoquota(). + */ + if (VOP_ISLOCKED(vp) != LK_EXCLUSIVE) { + + /* + * Upgrade vnode lock, since getinoquota() + * requires exclusive lock to modify inode. + */ + relocked = 1; + vhold(vp); + vn_lock(vp, LK_UPGRADE | LK_RETRY); + VI_LOCK(vp); + if (vp->v_iflag & VI_DOOMED) { + vdropl(vp); + error = ENOENT; + goto relock; + } + vdropl(vp); + } else + relocked = 0; + error = getinoquota(ip); +relock: + if (relocked) + vn_lock(vp, LK_DOWNGRADE | LK_RETRY); + if (error != 0) + return (error); +#endif + break; + default: + break; + } + } + + /* + * If immutable bit set, nobody gets to write it. "& ~VADMIN_PERMS" + * permits the owner of the file to remove the IMMUTABLE flag. + */ + if ((accmode & (VMODIFY_PERMS & ~VADMIN_PERMS)) && + (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) + return (EPERM); + +#ifdef UFS_ACL + if ((vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) != 0) { + if (vp->v_mount->mnt_flag & MNT_NFS4ACLS) + type = ACL_TYPE_NFS4; + else + type = ACL_TYPE_ACCESS; + + acl = acl_alloc(M_WAITOK); + if (type == ACL_TYPE_NFS4) + error = ufs_getacl_nfs4_internal(vp, acl, ap->a_td); + else + error = VOP_GETACL(vp, type, acl, ap->a_cred, ap->a_td); + switch (error) { + case 0: + if (type == ACL_TYPE_NFS4) { + error = vaccess_acl_nfs4(vp->v_type, ip->i_uid, + ip->i_gid, acl, accmode, ap->a_cred, NULL); + } else { + error = vfs_unixify_accmode(&accmode); + if (error == 0) + error = vaccess_acl_posix1e(vp->v_type, ip->i_uid, + ip->i_gid, acl, accmode, ap->a_cred, NULL); + } + break; + default: + if (error != EOPNOTSUPP) + printf( +"ufs_accessx(): Error retrieving ACL on object (%d).\n", + error); + /* + * XXX: Fall back until debugged. Should + * eventually possibly log an error, and return + * EPERM for safety. + */ + error = vfs_unixify_accmode(&accmode); + if (error == 0) + error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, + ip->i_gid, accmode, ap->a_cred, NULL); + } + acl_free(acl); + + return (error); + } +#endif /* !UFS_ACL */ + error = vfs_unixify_accmode(&accmode); + if (error == 0) + error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, + accmode, ap->a_cred, NULL); + return (error); +} + +/* ARGSUSED */ +static int +ufs_getattr(ap) + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct vattr *vap = ap->a_vap; + + VI_LOCK(vp); + ufs_itimes_locked(vp); + if (I_IS_UFS1(ip)) { + vap->va_atime.tv_sec = ip->i_din1->di_atime; + vap->va_atime.tv_nsec = ip->i_din1->di_atimensec; + } else { + vap->va_atime.tv_sec = ip->i_din2->di_atime; + vap->va_atime.tv_nsec = ip->i_din2->di_atimensec; + } + VI_UNLOCK(vp); + /* + * Copy from inode table + */ + vap->va_fsid = dev2udev(ITOUMP(ip)->um_dev); + vap->va_fileid = ip->i_number; + vap->va_mode = ip->i_mode & ~IFMT; + vap->va_nlink = ip->i_effnlink; + vap->va_uid = ip->i_uid; + vap->va_gid = ip->i_gid; + if (I_IS_UFS1(ip)) { + vap->va_rdev = ip->i_din1->di_rdev; + vap->va_size = ip->i_din1->di_size; + vap->va_mtime.tv_sec = ip->i_din1->di_mtime; + vap->va_mtime.tv_nsec = ip->i_din1->di_mtimensec; + vap->va_ctime.tv_sec = ip->i_din1->di_ctime; + vap->va_ctime.tv_nsec = ip->i_din1->di_ctimensec; + vap->va_bytes = dbtob((u_quad_t)ip->i_din1->di_blocks); + vap->va_filerev = ip->i_din1->di_modrev; + } else { + vap->va_rdev = ip->i_din2->di_rdev; + vap->va_size = ip->i_din2->di_size; + vap->va_mtime.tv_sec = ip->i_din2->di_mtime; + vap->va_mtime.tv_nsec = ip->i_din2->di_mtimensec; + vap->va_ctime.tv_sec = ip->i_din2->di_ctime; + vap->va_ctime.tv_nsec = ip->i_din2->di_ctimensec; + vap->va_birthtime.tv_sec = ip->i_din2->di_birthtime; + vap->va_birthtime.tv_nsec = ip->i_din2->di_birthnsec; + vap->va_bytes = dbtob((u_quad_t)ip->i_din2->di_blocks); + vap->va_filerev = ip->i_din2->di_modrev; + } + vap->va_flags = ip->i_flags; + vap->va_gen = ip->i_gen; + vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; + vap->va_type = IFTOVT(ip->i_mode); + return (0); +} + +/* + * Set attribute vnode op. called from several syscalls + */ +static int +ufs_setattr(ap) + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + } */ *ap; +{ + struct vattr *vap = ap->a_vap; + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct ucred *cred = ap->a_cred; + struct thread *td = curthread; + int error; + + /* + * Check for unsettable attributes. + */ + if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || + (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || + (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || + ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { + return (EINVAL); + } + if (vap->va_flags != VNOVAL) { + if ((vap->va_flags & ~(SF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | + SF_NOUNLINK | SF_SNAPSHOT | UF_APPEND | UF_ARCHIVE | + UF_HIDDEN | UF_IMMUTABLE | UF_NODUMP | UF_NOUNLINK | + UF_OFFLINE | UF_OPAQUE | UF_READONLY | UF_REPARSE | + UF_SPARSE | UF_SYSTEM)) != 0) + return (EOPNOTSUPP); + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + /* + * Callers may only modify the file flags on objects they + * have VADMIN rights for. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + return (error); + /* + * Unprivileged processes are not permitted to unset system + * flags, or modify flags if any system flags are set. + * Privileged non-jail processes may not modify system flags + * if securelevel > 0 and any existing system flags are set. + * Privileged jail processes behave like privileged non-jail + * processes if the security.jail.chflags_allowed sysctl is + * is non-zero; otherwise, they behave like unprivileged + * processes. + */ + if (!priv_check_cred(cred, PRIV_VFS_SYSFLAGS, 0)) { + if (ip->i_flags & + (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { + error = securelevel_gt(cred, 0); + if (error) + return (error); + } + /* The snapshot flag cannot be toggled. */ + if ((vap->va_flags ^ ip->i_flags) & SF_SNAPSHOT) + return (EPERM); + } else { + if (ip->i_flags & + (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || + ((vap->va_flags ^ ip->i_flags) & SF_SETTABLE)) + return (EPERM); + } + ip->i_flags = vap->va_flags; + DIP_SET(ip, i_flags, vap->va_flags); + ip->i_flag |= IN_CHANGE; + error = UFS_UPDATE(vp, 0); + if (ip->i_flags & (IMMUTABLE | APPEND)) + return (error); + } + /* + * If immutable or append, no one can change any of its attributes + * except the ones already handled (in some cases, file flags + * including the immutability flags themselves for the superuser). + */ + if (ip->i_flags & (IMMUTABLE | APPEND)) + return (EPERM); + /* + * Go through the fields and update iff not VNOVAL. + */ + if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, + td)) != 0) + return (error); + } + if (vap->va_size != VNOVAL) { + /* + * XXX most of the following special cases should be in + * callers instead of in N filesystems. The VDIR check + * mostly already is. + */ + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VLNK: + case VREG: + /* + * Truncation should have an effect in these cases. + * Disallow it if the filesystem is read-only or + * the file is being snapshotted. + */ + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((ip->i_flags & SF_SNAPSHOT) != 0) + return (EPERM); + break; + default: + /* + * According to POSIX, the result is unspecified + * for file types other than regular files, + * directories and shared memory objects. We + * don't support shared memory objects in the file + * system, and have dubious support for truncating + * symlinks. Just ignore the request in other cases. + */ + return (0); + } + if ((error = UFS_TRUNCATE(vp, vap->va_size, IO_NORMAL | + ((vap->va_vaflags & VA_SYNC) != 0 ? IO_SYNC : 0), + cred)) != 0) + return (error); + } + if (vap->va_atime.tv_sec != VNOVAL || + vap->va_mtime.tv_sec != VNOVAL || + vap->va_birthtime.tv_sec != VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((ip->i_flags & SF_SNAPSHOT) != 0) + return (EPERM); + error = vn_utimes_perm(vp, vap, cred, td); + if (error != 0) + return (error); + ip->i_flag |= IN_CHANGE | IN_MODIFIED; + if (vap->va_atime.tv_sec != VNOVAL) { + ip->i_flag &= ~IN_ACCESS; + DIP_SET(ip, i_atime, vap->va_atime.tv_sec); + DIP_SET(ip, i_atimensec, vap->va_atime.tv_nsec); + } + if (vap->va_mtime.tv_sec != VNOVAL) { + ip->i_flag &= ~IN_UPDATE; + DIP_SET(ip, i_mtime, vap->va_mtime.tv_sec); + DIP_SET(ip, i_mtimensec, vap->va_mtime.tv_nsec); + } + if (vap->va_birthtime.tv_sec != VNOVAL && I_IS_UFS2(ip)) { + ip->i_din2->di_birthtime = vap->va_birthtime.tv_sec; + ip->i_din2->di_birthnsec = vap->va_birthtime.tv_nsec; + } + error = UFS_UPDATE(vp, 0); + if (error) + return (error); + } + error = 0; + if (vap->va_mode != (mode_t)VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((ip->i_flags & SF_SNAPSHOT) != 0 && (vap->va_mode & + (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP | S_IXOTH | S_IWOTH))) + return (EPERM); + error = ufs_chmod(vp, (int)vap->va_mode, cred, td); + } + return (error); +} + +#ifdef UFS_ACL +static int +ufs_update_nfs4_acl_after_mode_change(struct vnode *vp, int mode, + int file_owner_id, struct ucred *cred, struct thread *td) +{ + int error; + struct acl *aclp; + + aclp = acl_alloc(M_WAITOK); + error = ufs_getacl_nfs4_internal(vp, aclp, td); + /* + * We don't have to handle EOPNOTSUPP here, as the filesystem claims + * it supports ACLs. + */ + if (error) + goto out; + + acl_nfs4_sync_acl_from_mode(aclp, mode, file_owner_id); + error = ufs_setacl_nfs4_internal(vp, aclp, td); + +out: + acl_free(aclp); + return (error); +} +#endif /* UFS_ACL */ + +/* + * Mark this file's access time for update for vfs_mark_atime(). This + * is called from execve() and mmap(). + */ +static int +ufs_markatime(ap) + struct vop_markatime_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + + VI_LOCK(vp); + ip->i_flag |= IN_ACCESS; + VI_UNLOCK(vp); + /* + * XXXKIB No UFS_UPDATE(ap->a_vp, 0) there. + */ + return (0); +} + +/* + * Change the mode on a file. + * Inode must be locked before calling. + */ +static int +ufs_chmod(vp, mode, cred, td) + struct vnode *vp; + int mode; + struct ucred *cred; + struct thread *td; +{ + struct inode *ip = VTOI(vp); + int error; + + /* + * To modify the permissions on a file, must possess VADMIN + * for that file. + */ + if ((error = VOP_ACCESSX(vp, VWRITE_ACL, cred, td))) + return (error); + /* + * Privileged processes may set the sticky bit on non-directories, + * as well as set the setgid bit on a file with a group that the + * process is not a member of. Both of these are allowed in + * jail(8). + */ + if (vp->v_type != VDIR && (mode & S_ISTXT)) { + if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0)) + return (EFTYPE); + } + if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) { + error = priv_check_cred(cred, PRIV_VFS_SETGID, 0); + if (error) + return (error); + } + + /* + * Deny setting setuid if we are not the file owner. + */ + if ((mode & ISUID) && ip->i_uid != cred->cr_uid) { + error = priv_check_cred(cred, PRIV_VFS_ADMIN, 0); + if (error) + return (error); + } + + ip->i_mode &= ~ALLPERMS; + ip->i_mode |= (mode & ALLPERMS); + DIP_SET(ip, i_mode, ip->i_mode); + ip->i_flag |= IN_CHANGE; +#ifdef UFS_ACL + if ((vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) + error = ufs_update_nfs4_acl_after_mode_change(vp, mode, ip->i_uid, cred, td); +#endif + if (error == 0 && (ip->i_flag & IN_CHANGE) != 0) + error = UFS_UPDATE(vp, 0); + + return (error); +} + +/* + * Perform chown operation on inode ip; + * inode must be locked prior to call. + */ +static int +ufs_chown(vp, uid, gid, cred, td) + struct vnode *vp; + uid_t uid; + gid_t gid; + struct ucred *cred; + struct thread *td; +{ + struct inode *ip = VTOI(vp); + uid_t ouid; + gid_t ogid; + int error = 0; +#ifdef QUOTA + int i; + ufs2_daddr_t change; +#endif + + if (uid == (uid_t)VNOVAL) + uid = ip->i_uid; + if (gid == (gid_t)VNOVAL) + gid = ip->i_gid; + /* + * To modify the ownership of a file, must possess VADMIN for that + * file. + */ + if ((error = VOP_ACCESSX(vp, VWRITE_OWNER, cred, td))) + return (error); + /* + * To change the owner of a file, or change the group of a file to a + * group of which we are not a member, the caller must have + * privilege. + */ + if (((uid != ip->i_uid && uid != cred->cr_uid) || + (gid != ip->i_gid && !groupmember(gid, cred))) && + (error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0))) + return (error); + ogid = ip->i_gid; + ouid = ip->i_uid; +#ifdef QUOTA + if ((error = getinoquota(ip)) != 0) + return (error); + if (ouid == uid) { + dqrele(vp, ip->i_dquot[USRQUOTA]); + ip->i_dquot[USRQUOTA] = NODQUOT; + } + if (ogid == gid) { + dqrele(vp, ip->i_dquot[GRPQUOTA]); + ip->i_dquot[GRPQUOTA] = NODQUOT; + } + change = DIP(ip, i_blocks); + (void) chkdq(ip, -change, cred, CHOWN); + (void) chkiq(ip, -1, cred, CHOWN); + for (i = 0; i < MAXQUOTAS; i++) { + dqrele(vp, ip->i_dquot[i]); + ip->i_dquot[i] = NODQUOT; + } +#endif + ip->i_gid = gid; + DIP_SET(ip, i_gid, gid); + ip->i_uid = uid; + DIP_SET(ip, i_uid, uid); +#ifdef QUOTA + if ((error = getinoquota(ip)) == 0) { + if (ouid == uid) { + dqrele(vp, ip->i_dquot[USRQUOTA]); + ip->i_dquot[USRQUOTA] = NODQUOT; + } + if (ogid == gid) { + dqrele(vp, ip->i_dquot[GRPQUOTA]); + ip->i_dquot[GRPQUOTA] = NODQUOT; + } + if ((error = chkdq(ip, change, cred, CHOWN)) == 0) { + if ((error = chkiq(ip, 1, cred, CHOWN)) == 0) + goto good; + else + (void) chkdq(ip, -change, cred, CHOWN|FORCE); + } + for (i = 0; i < MAXQUOTAS; i++) { + dqrele(vp, ip->i_dquot[i]); + ip->i_dquot[i] = NODQUOT; + } + } + ip->i_gid = ogid; + DIP_SET(ip, i_gid, ogid); + ip->i_uid = ouid; + DIP_SET(ip, i_uid, ouid); + if (getinoquota(ip) == 0) { + if (ouid == uid) { + dqrele(vp, ip->i_dquot[USRQUOTA]); + ip->i_dquot[USRQUOTA] = NODQUOT; + } + if (ogid == gid) { + dqrele(vp, ip->i_dquot[GRPQUOTA]); + ip->i_dquot[GRPQUOTA] = NODQUOT; + } + (void) chkdq(ip, change, cred, FORCE|CHOWN); + (void) chkiq(ip, 1, cred, FORCE|CHOWN); + (void) getinoquota(ip); + } + return (error); +good: + if (getinoquota(ip)) + panic("ufs_chown: lost quota"); +#endif /* QUOTA */ + ip->i_flag |= IN_CHANGE; + if ((ip->i_mode & (ISUID | ISGID)) && (ouid != uid || ogid != gid)) { + if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) { + ip->i_mode &= ~(ISUID | ISGID); + DIP_SET(ip, i_mode, ip->i_mode); + } + } + error = UFS_UPDATE(vp, 0); + return (error); +} + +static int +ufs_remove(ap) + struct vop_remove_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *ap; +{ + struct inode *ip; + struct vnode *vp = ap->a_vp; + struct vnode *dvp = ap->a_dvp; + int error; + struct thread *td; + + td = curthread; + ip = VTOI(vp); + if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || + (VTOI(dvp)->i_flags & APPEND)) { + error = EPERM; + goto out; + } +#ifdef UFS_GJOURNAL + ufs_gjournal_orphan(vp); +#endif + error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0); + if (ip->i_nlink <= 0) + vp->v_vflag |= VV_NOSYNC; + if ((ip->i_flags & SF_SNAPSHOT) != 0) { + /* + * Avoid deadlock where another thread is trying to + * update the inodeblock for dvp and is waiting on + * snaplk. Temporary unlock the vnode lock for the + * unlinked file and sync the directory. This should + * allow vput() of the directory to not block later on + * while holding the snapshot vnode locked, assuming + * that the directory hasn't been unlinked too. + */ + VOP_UNLOCK(vp, 0); + (void) VOP_FSYNC(dvp, MNT_WAIT, td); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + } +out: + return (error); +} + +static void +print_bad_link_count(const char *funcname, struct vnode *dvp) +{ + struct inode *dip; + + dip = VTOI(dvp); + uprintf("%s: Bad link count %d on parent inode %jd in file system %s\n", + funcname, dip->i_effnlink, (intmax_t)dip->i_number, + dvp->v_mount->mnt_stat.f_mntonname); +} + +/* + * link vnode call + */ +static int +ufs_link(ap) + struct vop_link_args /* { + struct vnode *a_tdvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct vnode *tdvp = ap->a_tdvp; + struct componentname *cnp = ap->a_cnp; + struct inode *ip; + struct direct newdir; + int error; + +#ifdef INVARIANTS + if ((cnp->cn_flags & HASBUF) == 0) + panic("ufs_link: no name"); +#endif + if (VTOI(tdvp)->i_effnlink < 2) { + print_bad_link_count("ufs_link", tdvp); + error = EINVAL; + goto out; + } + ip = VTOI(vp); + if ((nlink_t)ip->i_nlink >= LINK_MAX) { + error = EMLINK; + goto out; + } + /* + * The file may have been removed after namei droped the original + * lock. + */ + if (ip->i_effnlink == 0) { + error = ENOENT; + goto out; + } + if (ip->i_flags & (IMMUTABLE | APPEND)) { + error = EPERM; + goto out; + } + ip->i_effnlink++; + ip->i_nlink++; + DIP_SET(ip, i_nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(vp)) + softdep_setup_link(VTOI(tdvp), ip); + error = UFS_UPDATE(vp, !(DOINGSOFTDEP(vp) | DOINGASYNC(vp))); + if (!error) { + ufs_makedirentry(ip, cnp, &newdir); + error = ufs_direnter(tdvp, vp, &newdir, cnp, NULL, 0); + } + + if (error) { + ip->i_effnlink--; + ip->i_nlink--; + DIP_SET(ip, i_nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(vp)) + softdep_revert_link(VTOI(tdvp), ip); + } +out: + return (error); +} + +/* + * whiteout vnode call + */ +static int +ufs_whiteout(ap) + struct vop_whiteout_args /* { + struct vnode *a_dvp; + struct componentname *a_cnp; + int a_flags; + } */ *ap; +{ + struct vnode *dvp = ap->a_dvp; + struct componentname *cnp = ap->a_cnp; + struct direct newdir; + int error = 0; + + switch (ap->a_flags) { + case LOOKUP: + /* 4.4 format directories support whiteout operations */ + if (dvp->v_mount->mnt_maxsymlinklen > 0) + return (0); + return (EOPNOTSUPP); + + case CREATE: + /* create a new directory whiteout */ +#ifdef INVARIANTS + if ((cnp->cn_flags & SAVENAME) == 0) + panic("ufs_whiteout: missing name"); + if (dvp->v_mount->mnt_maxsymlinklen <= 0) + panic("ufs_whiteout: old format filesystem"); +#endif + + newdir.d_ino = WINO; + newdir.d_namlen = cnp->cn_namelen; + bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); + newdir.d_type = DT_WHT; + error = ufs_direnter(dvp, NULL, &newdir, cnp, NULL, 0); + break; + + case DELETE: + /* remove an existing directory whiteout */ +#ifdef INVARIANTS + if (dvp->v_mount->mnt_maxsymlinklen <= 0) + panic("ufs_whiteout: old format filesystem"); +#endif + + cnp->cn_flags &= ~DOWHITEOUT; + error = ufs_dirremove(dvp, NULL, cnp->cn_flags, 0); + break; + default: + panic("ufs_whiteout: unknown op"); + } + return (error); +} + +static volatile int rename_restarts; +SYSCTL_INT(_vfs_ufs, OID_AUTO, rename_restarts, CTLFLAG_RD, + __DEVOLATILE(int *, &rename_restarts), 0, + "Times rename had to restart due to lock contention"); + +/* + * Rename system call. + * rename("foo", "bar"); + * is essentially + * unlink("bar"); + * link("foo", "bar"); + * unlink("foo"); + * but ``atomically''. Can't do full commit without saving state in the + * inode on disk which isn't feasible at this time. Best we can do is + * always guarantee the target exists. + * + * Basic algorithm is: + * + * 1) Bump link count on source while we're linking it to the + * target. This also ensure the inode won't be deleted out + * from underneath us while we work (it may be truncated by + * a concurrent `trunc' or `open' for creation). + * 2) Link source to destination. If destination already exists, + * delete it first. + * 3) Unlink source reference to inode if still around. If a + * directory was moved and the parent of the destination + * is different from the source, patch the ".." entry in the + * directory. + */ +static int +ufs_rename(ap) + struct vop_rename_args /* { + struct vnode *a_fdvp; + struct vnode *a_fvp; + struct componentname *a_fcnp; + struct vnode *a_tdvp; + struct vnode *a_tvp; + struct componentname *a_tcnp; + } */ *ap; +{ + struct vnode *tvp = ap->a_tvp; + struct vnode *tdvp = ap->a_tdvp; + struct vnode *fvp = ap->a_fvp; + struct vnode *fdvp = ap->a_fdvp; + struct vnode *nvp; + struct componentname *tcnp = ap->a_tcnp; + struct componentname *fcnp = ap->a_fcnp; + struct thread *td = fcnp->cn_thread; + struct inode *fip, *tip, *tdp, *fdp; + struct direct newdir; + off_t endoff; + int doingdirectory, newparent; + int error = 0; + struct mount *mp; + ino_t ino; + +#ifdef INVARIANTS + if ((tcnp->cn_flags & HASBUF) == 0 || + (fcnp->cn_flags & HASBUF) == 0) + panic("ufs_rename: no name"); +#endif + endoff = 0; + mp = tdvp->v_mount; + VOP_UNLOCK(tdvp, 0); + if (tvp && tvp != tdvp) + VOP_UNLOCK(tvp, 0); + /* + * Check for cross-device rename. + */ + if ((fvp->v_mount != tdvp->v_mount) || + (tvp && (fvp->v_mount != tvp->v_mount))) { + error = EXDEV; + mp = NULL; + goto releout; + } +relock: + /* + * We need to acquire 2 to 4 locks depending on whether tvp is NULL + * and fdvp and tdvp are the same directory. Subsequently we need + * to double-check all paths and in the directory rename case we + * need to verify that we are not creating a directory loop. To + * handle this we acquire all but fdvp using non-blocking + * acquisitions. If we fail to acquire any lock in the path we will + * drop all held locks, acquire the new lock in a blocking fashion, + * and then release it and restart the rename. This acquire/release + * step ensures that we do not spin on a lock waiting for release. + */ + error = vn_lock(fdvp, LK_EXCLUSIVE); + if (error) + goto releout; + if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { + VOP_UNLOCK(fdvp, 0); + error = vn_lock(tdvp, LK_EXCLUSIVE); + if (error) + goto releout; + VOP_UNLOCK(tdvp, 0); + atomic_add_int(&rename_restarts, 1); + goto relock; + } + /* + * Re-resolve fvp to be certain it still exists and fetch the + * correct vnode. + */ + error = ufs_lookup_ino(fdvp, NULL, fcnp, &ino); + if (error) { + VOP_UNLOCK(fdvp, 0); + VOP_UNLOCK(tdvp, 0); + goto releout; + } + error = VFS_VGET(mp, ino, LK_EXCLUSIVE | LK_NOWAIT, &nvp); + if (error) { + VOP_UNLOCK(fdvp, 0); + VOP_UNLOCK(tdvp, 0); + if (error != EBUSY) + goto releout; + error = VFS_VGET(mp, ino, LK_EXCLUSIVE, &nvp); + if (error != 0) + goto releout; + VOP_UNLOCK(nvp, 0); + vrele(fvp); + fvp = nvp; + atomic_add_int(&rename_restarts, 1); + goto relock; + } + vrele(fvp); + fvp = nvp; + /* + * Re-resolve tvp and acquire the vnode lock if present. + */ + error = ufs_lookup_ino(tdvp, NULL, tcnp, &ino); + if (error != 0 && error != EJUSTRETURN) { + VOP_UNLOCK(fdvp, 0); + VOP_UNLOCK(tdvp, 0); + VOP_UNLOCK(fvp, 0); + goto releout; + } + /* + * If tvp disappeared we just carry on. + */ + if (error == EJUSTRETURN && tvp != NULL) { + vrele(tvp); + tvp = NULL; + } + /* + * Get the tvp ino if the lookup succeeded. We may have to restart + * if the non-blocking acquire fails. + */ + if (error == 0) { + nvp = NULL; + error = VFS_VGET(mp, ino, LK_EXCLUSIVE | LK_NOWAIT, &nvp); + if (tvp) + vrele(tvp); + tvp = nvp; + if (error) { + VOP_UNLOCK(fdvp, 0); + VOP_UNLOCK(tdvp, 0); + VOP_UNLOCK(fvp, 0); + if (error != EBUSY) + goto releout; + error = VFS_VGET(mp, ino, LK_EXCLUSIVE, &nvp); + if (error != 0) + goto releout; + vput(nvp); + atomic_add_int(&rename_restarts, 1); + goto relock; + } + } + fdp = VTOI(fdvp); + fip = VTOI(fvp); + tdp = VTOI(tdvp); + tip = NULL; + if (tvp) + tip = VTOI(tvp); + if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) || + (VTOI(tdvp)->i_flags & APPEND))) { + error = EPERM; + goto unlockout; + } + /* + * Renaming a file to itself has no effect. The upper layers should + * not call us in that case. However, things could change after + * we drop the locks above. + */ + if (fvp == tvp) { + error = 0; + goto unlockout; + } + doingdirectory = 0; + newparent = 0; + ino = fip->i_number; + if (fip->i_nlink >= LINK_MAX) { + error = EMLINK; + goto unlockout; + } + if ((fip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) + || (fdp->i_flags & APPEND)) { + error = EPERM; + goto unlockout; + } + if ((fip->i_mode & IFMT) == IFDIR) { + /* + * Avoid ".", "..", and aliases of "." for obvious reasons. + */ + if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || + fdp == fip || + (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) { + error = EINVAL; + goto unlockout; + } + if (fdp->i_number != tdp->i_number) + newparent = tdp->i_number; + doingdirectory = 1; + } + if ((fvp->v_type == VDIR && fvp->v_mountedhere != NULL) || + (tvp != NULL && tvp->v_type == VDIR && + tvp->v_mountedhere != NULL)) { + error = EXDEV; + goto unlockout; + } + + /* + * If ".." must be changed (ie the directory gets a new + * parent) then the source directory must not be in the + * directory hierarchy above the target, as this would + * orphan everything below the source directory. Also + * the user must have write permission in the source so + * as to be able to change "..". + */ + if (doingdirectory && newparent) { + error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread); + if (error) + goto unlockout; + error = ufs_checkpath(ino, fdp->i_number, tdp, tcnp->cn_cred, + &ino); + /* + * We encountered a lock that we have to wait for. Unlock + * everything else and VGET before restarting. + */ + if (ino) { + VOP_UNLOCK(fdvp, 0); + VOP_UNLOCK(fvp, 0); + VOP_UNLOCK(tdvp, 0); + if (tvp) + VOP_UNLOCK(tvp, 0); + error = VFS_VGET(mp, ino, LK_SHARED, &nvp); + if (error == 0) + vput(nvp); + atomic_add_int(&rename_restarts, 1); + goto relock; + } + if (error) + goto unlockout; + if ((tcnp->cn_flags & SAVESTART) == 0) + panic("ufs_rename: lost to startdir"); + } + if (fip->i_effnlink == 0 || fdp->i_effnlink == 0 || + tdp->i_effnlink == 0) + panic("Bad effnlink fip %p, fdp %p, tdp %p", fip, fdp, tdp); + + /* + * 1) Bump link count while we're moving stuff + * around. If we crash somewhere before + * completing our work, the link count + * may be wrong, but correctable. + */ + fip->i_effnlink++; + fip->i_nlink++; + DIP_SET(fip, i_nlink, fip->i_nlink); + fip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(fvp)) + softdep_setup_link(tdp, fip); + error = UFS_UPDATE(fvp, !(DOINGSOFTDEP(fvp) | DOINGASYNC(fvp))); + if (error) + goto bad; + + /* + * 2) If target doesn't exist, link the target + * to the source and unlink the source. + * Otherwise, rewrite the target directory + * entry to reference the source inode and + * expunge the original entry's existence. + */ + if (tip == NULL) { + if (ITODEV(tdp) != ITODEV(fip)) + panic("ufs_rename: EXDEV"); + if (doingdirectory && newparent) { + /* + * Account for ".." in new directory. + * When source and destination have the same + * parent we don't adjust the link count. The + * actual link modification is completed when + * .. is rewritten below. + */ + if ((nlink_t)tdp->i_nlink >= LINK_MAX) { + error = EMLINK; + goto bad; + } + } + ufs_makedirentry(fip, tcnp, &newdir); + error = ufs_direnter(tdvp, NULL, &newdir, tcnp, NULL, 1); + if (error) + goto bad; + /* Setup tdvp for directory compaction if needed. */ + if (tdp->i_count && tdp->i_endoff && + tdp->i_endoff < tdp->i_size) + endoff = tdp->i_endoff; + } else { + if (ITODEV(tip) != ITODEV(tdp) || ITODEV(tip) != ITODEV(fip)) + panic("ufs_rename: EXDEV"); + /* + * Short circuit rename(foo, foo). + */ + if (tip->i_number == fip->i_number) + panic("ufs_rename: same file"); + /* + * If the parent directory is "sticky", then the caller + * must possess VADMIN for the parent directory, or the + * destination of the rename. This implements append-only + * directories. + */ + if ((tdp->i_mode & S_ISTXT) && + VOP_ACCESS(tdvp, VADMIN, tcnp->cn_cred, td) && + VOP_ACCESS(tvp, VADMIN, tcnp->cn_cred, td)) { + error = EPERM; + goto bad; + } + /* + * Target must be empty if a directory and have no links + * to it. Also, ensure source and target are compatible + * (both directories, or both not directories). + */ + if ((tip->i_mode & IFMT) == IFDIR) { + if ((tip->i_effnlink > 2) || + !ufs_dirempty(tip, tdp->i_number, tcnp->cn_cred)) { + error = ENOTEMPTY; + goto bad; + } + if (!doingdirectory) { + error = ENOTDIR; + goto bad; + } + cache_purge(tdvp); + } else if (doingdirectory) { + error = EISDIR; + goto bad; + } + if (doingdirectory) { + if (!newparent) { + tdp->i_effnlink--; + if (DOINGSOFTDEP(tdvp)) + softdep_change_linkcnt(tdp); + } + tip->i_effnlink--; + if (DOINGSOFTDEP(tvp)) + softdep_change_linkcnt(tip); + } + error = ufs_dirrewrite(tdp, tip, fip->i_number, + IFTODT(fip->i_mode), + (doingdirectory && newparent) ? newparent : doingdirectory); + if (error) { + if (doingdirectory) { + if (!newparent) { + tdp->i_effnlink++; + if (DOINGSOFTDEP(tdvp)) + softdep_change_linkcnt(tdp); + } + tip->i_effnlink++; + if (DOINGSOFTDEP(tvp)) + softdep_change_linkcnt(tip); + } + } + if (doingdirectory && !DOINGSOFTDEP(tvp)) { + /* + * The only stuff left in the directory is "." + * and "..". The "." reference is inconsequential + * since we are quashing it. We have removed the "." + * reference and the reference in the parent directory, + * but there may be other hard links. The soft + * dependency code will arrange to do these operations + * after the parent directory entry has been deleted on + * disk, so when running with that code we avoid doing + * them now. + */ + if (!newparent) { + tdp->i_nlink--; + DIP_SET(tdp, i_nlink, tdp->i_nlink); + tdp->i_flag |= IN_CHANGE; + } + tip->i_nlink--; + DIP_SET(tip, i_nlink, tip->i_nlink); + tip->i_flag |= IN_CHANGE; + } + } + + /* + * 3) Unlink the source. We have to resolve the path again to + * fixup the directory offset and count for ufs_dirremove. + */ + if (fdvp == tdvp) { + error = ufs_lookup_ino(fdvp, NULL, fcnp, &ino); + if (error) + panic("ufs_rename: from entry went away!"); + if (ino != fip->i_number) + panic("ufs_rename: ino mismatch %ju != %ju\n", + (uintmax_t)ino, (uintmax_t)fip->i_number); + } + /* + * If the source is a directory with a + * new parent, the link count of the old + * parent directory must be decremented + * and ".." set to point to the new parent. + */ + if (doingdirectory && newparent) { + /* + * If tip exists we simply use its link, otherwise we must + * add a new one. + */ + if (tip == NULL) { + tdp->i_effnlink++; + tdp->i_nlink++; + DIP_SET(tdp, i_nlink, tdp->i_nlink); + tdp->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(tdvp)) + softdep_setup_dotdot_link(tdp, fip); + error = UFS_UPDATE(tdvp, !(DOINGSOFTDEP(tdvp) | + DOINGASYNC(tdvp))); + /* Don't go to bad here as the new link exists. */ + if (error) + goto unlockout; + } else if (DOINGSUJ(tdvp)) + /* Journal must account for each new link. */ + softdep_setup_dotdot_link(tdp, fip); + fip->i_offset = mastertemplate.dot_reclen; + ufs_dirrewrite(fip, fdp, newparent, DT_DIR, 0); + cache_purge(fdvp); + } + error = ufs_dirremove(fdvp, fip, fcnp->cn_flags, 0); + /* + * The kern_renameat() looks up the fvp using the DELETE flag, which + * causes the removal of the name cache entry for fvp. + * As the relookup of the fvp is done in two steps: + * ufs_lookup_ino() and then VFS_VGET(), another thread might do a + * normal lookup of the from name just before the VFS_VGET() call, + * causing the cache entry to be re-instantiated. + * + * The same issue also applies to tvp if it exists as + * otherwise we may have a stale name cache entry for the new + * name that references the old i-node if it has other links + * or open file descriptors. + */ + cache_purge(fvp); + if (tvp) + cache_purge(tvp); + cache_purge_negative(tdvp); + +unlockout: + vput(fdvp); + vput(fvp); + if (tvp) + vput(tvp); + /* + * If compaction or fsync was requested do it now that other locks + * are no longer needed. + */ + if (error == 0 && endoff != 0) { + error = UFS_TRUNCATE(tdvp, endoff, IO_NORMAL | IO_SYNC, + tcnp->cn_cred); + if (error != 0) + vn_printf(tdvp, + "ufs_rename: failed to truncate, error %d\n", + error); +#ifdef UFS_DIRHASH + else if (tdp->i_dirhash != NULL) + ufsdirhash_dirtrunc(tdp, endoff); +#endif + /* + * Even if the directory compaction failed, rename was + * succesful. Do not propagate a UFS_TRUNCATE() error + * to the caller. + */ + error = 0; + } + if (error == 0 && tdp->i_flag & IN_NEEDSYNC) + error = VOP_FSYNC(tdvp, MNT_WAIT, td); + vput(tdvp); + return (error); + +bad: + fip->i_effnlink--; + fip->i_nlink--; + DIP_SET(fip, i_nlink, fip->i_nlink); + fip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(fvp)) + softdep_revert_link(tdp, fip); + goto unlockout; + +releout: + vrele(fdvp); + vrele(fvp); + vrele(tdvp); + if (tvp) + vrele(tvp); + + return (error); +} + +#ifdef UFS_ACL +static int +ufs_do_posix1e_acl_inheritance_dir(struct vnode *dvp, struct vnode *tvp, + mode_t dmode, struct ucred *cred, struct thread *td) +{ + int error; + struct inode *ip = VTOI(tvp); + struct acl *dacl, *acl; + + acl = acl_alloc(M_WAITOK); + dacl = acl_alloc(M_WAITOK); + + /* + * Retrieve default ACL from parent, if any. + */ + error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred, td); + switch (error) { + case 0: + /* + * Retrieved a default ACL, so merge mode and ACL if + * necessary. If the ACL is empty, fall through to + * the "not defined or available" case. + */ + if (acl->acl_cnt != 0) { + dmode = acl_posix1e_newfilemode(dmode, acl); + ip->i_mode = dmode; + DIP_SET(ip, i_mode, dmode); + *dacl = *acl; + ufs_sync_acl_from_inode(ip, acl); + break; + } + /* FALLTHROUGH */ + + case EOPNOTSUPP: + /* + * Just use the mode as-is. + */ + ip->i_mode = dmode; + DIP_SET(ip, i_mode, dmode); + error = 0; + goto out; + + default: + goto out; + } + + /* + * XXX: If we abort now, will Soft Updates notify the extattr + * code that the EAs for the file need to be released? + */ + error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred, td); + if (error == 0) + error = VOP_SETACL(tvp, ACL_TYPE_DEFAULT, dacl, cred, td); + switch (error) { + case 0: + break; + + case EOPNOTSUPP: + /* + * XXX: This should not happen, as EOPNOTSUPP above + * was supposed to free acl. + */ + printf("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()\n"); + /* + panic("ufs_mkdir: VOP_GETACL() but no VOP_SETACL()"); + */ + break; + + default: + goto out; + } + +out: + acl_free(acl); + acl_free(dacl); + + return (error); +} + +static int +ufs_do_posix1e_acl_inheritance_file(struct vnode *dvp, struct vnode *tvp, + mode_t mode, struct ucred *cred, struct thread *td) +{ + int error; + struct inode *ip = VTOI(tvp); + struct acl *acl; + + acl = acl_alloc(M_WAITOK); + + /* + * Retrieve default ACL for parent, if any. + */ + error = VOP_GETACL(dvp, ACL_TYPE_DEFAULT, acl, cred, td); + switch (error) { + case 0: + /* + * Retrieved a default ACL, so merge mode and ACL if + * necessary. + */ + if (acl->acl_cnt != 0) { + /* + * Two possible ways for default ACL to not + * be present. First, the EA can be + * undefined, or second, the default ACL can + * be blank. If it's blank, fall through to + * the it's not defined case. + */ + mode = acl_posix1e_newfilemode(mode, acl); + ip->i_mode = mode; + DIP_SET(ip, i_mode, mode); + ufs_sync_acl_from_inode(ip, acl); + break; + } + /* FALLTHROUGH */ + + case EOPNOTSUPP: + /* + * Just use the mode as-is. + */ + ip->i_mode = mode; + DIP_SET(ip, i_mode, mode); + error = 0; + goto out; + + default: + goto out; + } + + /* + * XXX: If we abort now, will Soft Updates notify the extattr + * code that the EAs for the file need to be released? + */ + error = VOP_SETACL(tvp, ACL_TYPE_ACCESS, acl, cred, td); + switch (error) { + case 0: + break; + + case EOPNOTSUPP: + /* + * XXX: This should not happen, as EOPNOTSUPP above was + * supposed to free acl. + */ + printf("ufs_do_posix1e_acl_inheritance_file: VOP_GETACL() " + "but no VOP_SETACL()\n"); + /* panic("ufs_do_posix1e_acl_inheritance_file: VOP_GETACL() " + "but no VOP_SETACL()"); */ + break; + + default: + goto out; + } + +out: + acl_free(acl); + + return (error); +} + +static int +ufs_do_nfs4_acl_inheritance(struct vnode *dvp, struct vnode *tvp, + mode_t child_mode, struct ucred *cred, struct thread *td) +{ + int error; + struct acl *parent_aclp, *child_aclp; + + parent_aclp = acl_alloc(M_WAITOK); + child_aclp = acl_alloc(M_WAITOK | M_ZERO); + + error = ufs_getacl_nfs4_internal(dvp, parent_aclp, td); + if (error) + goto out; + acl_nfs4_compute_inherited_acl(parent_aclp, child_aclp, + child_mode, VTOI(tvp)->i_uid, tvp->v_type == VDIR); + error = ufs_setacl_nfs4_internal(tvp, child_aclp, td); + if (error) + goto out; +out: + acl_free(parent_aclp); + acl_free(child_aclp); + + return (error); +} +#endif + +/* + * Mkdir system call + */ +static int +ufs_mkdir(ap) + struct vop_mkdir_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + } */ *ap; +{ + struct vnode *dvp = ap->a_dvp; + struct vattr *vap = ap->a_vap; + struct componentname *cnp = ap->a_cnp; + struct inode *ip, *dp; + struct vnode *tvp; + struct buf *bp; + struct dirtemplate dirtemplate, *dtp; + struct direct newdir; + int error, dmode; + long blkoff; + +#ifdef INVARIANTS + if ((cnp->cn_flags & HASBUF) == 0) + panic("ufs_mkdir: no name"); +#endif + dp = VTOI(dvp); + if ((nlink_t)dp->i_nlink >= LINK_MAX) { + error = EMLINK; + goto out; + } + dmode = vap->va_mode & 0777; + dmode |= IFDIR; + /* + * Must simulate part of ufs_makeinode here to acquire the inode, + * but not have it entered in the parent directory. The entry is + * made later after writing "." and ".." entries. + */ + if (dp->i_effnlink < 2) { + print_bad_link_count("ufs_mkdir", dvp); + error = EINVAL; + goto out; + } + error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp); + if (error) + goto out; + ip = VTOI(tvp); + ip->i_gid = dp->i_gid; + DIP_SET(ip, i_gid, dp->i_gid); +#ifdef SUIDDIR + { +#ifdef QUOTA + struct ucred ucred, *ucp; + gid_t ucred_group; + ucp = cnp->cn_cred; +#endif + /* + * If we are hacking owners here, (only do this where told to) + * and we are not giving it TO root, (would subvert quotas) + * then go ahead and give it to the other user. + * The new directory also inherits the SUID bit. + * If user's UID and dir UID are the same, + * 'give it away' so that the SUID is still forced on. + */ + if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) && + (dp->i_mode & ISUID) && dp->i_uid) { + dmode |= ISUID; + ip->i_uid = dp->i_uid; + DIP_SET(ip, i_uid, dp->i_uid); +#ifdef QUOTA + if (dp->i_uid != cnp->cn_cred->cr_uid) { + /* + * Make sure the correct user gets charged + * for the space. + * Make a dummy credential for the victim. + * XXX This seems to never be accessed out of + * our context so a stack variable is ok. + */ + refcount_init(&ucred.cr_ref, 1); + ucred.cr_uid = ip->i_uid; + ucred.cr_ngroups = 1; + ucred.cr_groups = &ucred_group; + ucred.cr_groups[0] = dp->i_gid; + ucp = &ucred; + } +#endif + } else { + ip->i_uid = cnp->cn_cred->cr_uid; + DIP_SET(ip, i_uid, ip->i_uid); + } +#ifdef QUOTA + if ((error = getinoquota(ip)) || + (error = chkiq(ip, 1, ucp, 0))) { + if (DOINGSOFTDEP(tvp)) + softdep_revert_link(dp, ip); + UFS_VFREE(tvp, ip->i_number, dmode); + vput(tvp); + return (error); + } +#endif + } +#else /* !SUIDDIR */ + ip->i_uid = cnp->cn_cred->cr_uid; + DIP_SET(ip, i_uid, ip->i_uid); +#ifdef QUOTA + if ((error = getinoquota(ip)) || + (error = chkiq(ip, 1, cnp->cn_cred, 0))) { + if (DOINGSOFTDEP(tvp)) + softdep_revert_link(dp, ip); + UFS_VFREE(tvp, ip->i_number, dmode); + vput(tvp); + return (error); + } +#endif +#endif /* !SUIDDIR */ + ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; + ip->i_mode = dmode; + DIP_SET(ip, i_mode, dmode); + tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */ + ip->i_effnlink = 2; + ip->i_nlink = 2; + DIP_SET(ip, i_nlink, 2); + + if (cnp->cn_flags & ISWHITEOUT) { + ip->i_flags |= UF_OPAQUE; + DIP_SET(ip, i_flags, ip->i_flags); + } + + /* + * Bump link count in parent directory to reflect work done below. + * Should be done before reference is created so cleanup is + * possible if we crash. + */ + dp->i_effnlink++; + dp->i_nlink++; + DIP_SET(dp, i_nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(dvp)) + softdep_setup_mkdir(dp, ip); + error = UFS_UPDATE(dvp, !(DOINGSOFTDEP(dvp) | DOINGASYNC(dvp))); + if (error) + goto bad; +#ifdef MAC + if (dvp->v_mount->mnt_flag & MNT_MULTILABEL) { + error = mac_vnode_create_extattr(cnp->cn_cred, dvp->v_mount, + dvp, tvp, cnp); + if (error) + goto bad; + } +#endif +#ifdef UFS_ACL + if (dvp->v_mount->mnt_flag & MNT_ACLS) { + error = ufs_do_posix1e_acl_inheritance_dir(dvp, tvp, dmode, + cnp->cn_cred, cnp->cn_thread); + if (error) + goto bad; + } else if (dvp->v_mount->mnt_flag & MNT_NFS4ACLS) { + error = ufs_do_nfs4_acl_inheritance(dvp, tvp, dmode, + cnp->cn_cred, cnp->cn_thread); + if (error) + goto bad; + } +#endif /* !UFS_ACL */ + + /* + * Initialize directory with "." and ".." from static template. + */ + if (dvp->v_mount->mnt_maxsymlinklen > 0) + dtp = &mastertemplate; + else + dtp = (struct dirtemplate *)&omastertemplate; + dirtemplate = *dtp; + dirtemplate.dot_ino = ip->i_number; + dirtemplate.dotdot_ino = dp->i_number; + vnode_pager_setsize(tvp, DIRBLKSIZ); + if ((error = UFS_BALLOC(tvp, (off_t)0, DIRBLKSIZ, cnp->cn_cred, + BA_CLRBUF, &bp)) != 0) + goto bad; + ip->i_size = DIRBLKSIZ; + DIP_SET(ip, i_size, DIRBLKSIZ); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + bcopy((caddr_t)&dirtemplate, (caddr_t)bp->b_data, sizeof dirtemplate); + if (DOINGSOFTDEP(tvp)) { + /* + * Ensure that the entire newly allocated block is a + * valid directory so that future growth within the + * block does not have to ensure that the block is + * written before the inode. + */ + blkoff = DIRBLKSIZ; + while (blkoff < bp->b_bcount) { + ((struct direct *) + (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ; + blkoff += DIRBLKSIZ; + } + } + if ((error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(tvp) | + DOINGASYNC(tvp)))) != 0) { + (void)bwrite(bp); + goto bad; + } + /* + * Directory set up, now install its entry in the parent directory. + * + * If we are not doing soft dependencies, then we must write out the + * buffer containing the new directory body before entering the new + * name in the parent. If we are doing soft dependencies, then the + * buffer containing the new directory body will be passed to and + * released in the soft dependency code after the code has attached + * an appropriate ordering dependency to the buffer which ensures that + * the buffer is written before the new name is written in the parent. + */ + if (DOINGASYNC(dvp)) + bdwrite(bp); + else if (!DOINGSOFTDEP(dvp) && ((error = bwrite(bp)))) + goto bad; + ufs_makedirentry(ip, cnp, &newdir); + error = ufs_direnter(dvp, tvp, &newdir, cnp, bp, 0); + +bad: + if (error == 0) { + *ap->a_vpp = tvp; + } else { + dp->i_effnlink--; + dp->i_nlink--; + DIP_SET(dp, i_nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + /* + * No need to do an explicit VOP_TRUNCATE here, vrele will + * do this for us because we set the link count to 0. + */ + ip->i_effnlink = 0; + ip->i_nlink = 0; + DIP_SET(ip, i_nlink, 0); + ip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(tvp)) + softdep_revert_mkdir(dp, ip); + + vput(tvp); + } +out: + return (error); +} + +/* + * Rmdir system call. + */ +static int +ufs_rmdir(ap) + struct vop_rmdir_args /* { + struct vnode *a_dvp; + struct vnode *a_vp; + struct componentname *a_cnp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct vnode *dvp = ap->a_dvp; + struct componentname *cnp = ap->a_cnp; + struct inode *ip, *dp; + int error; + + ip = VTOI(vp); + dp = VTOI(dvp); + + /* + * Do not remove a directory that is in the process of being renamed. + * Verify the directory is empty (and valid). Rmdir ".." will not be + * valid since ".." will contain a reference to the current directory + * and thus be non-empty. Do not allow the removal of mounted on + * directories (this can happen when an NFS exported filesystem + * tries to remove a locally mounted on directory). + */ + error = 0; + if (dp->i_effnlink <= 2) { + if (dp->i_effnlink == 2) + print_bad_link_count("ufs_rmdir", dvp); + error = EINVAL; + goto out; + } + if (!ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) { + error = ENOTEMPTY; + goto out; + } + if ((dp->i_flags & APPEND) + || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) { + error = EPERM; + goto out; + } + if (vp->v_mountedhere != 0) { + error = EINVAL; + goto out; + } +#ifdef UFS_GJOURNAL + ufs_gjournal_orphan(vp); +#endif + /* + * Delete reference to directory before purging + * inode. If we crash in between, the directory + * will be reattached to lost+found, + */ + dp->i_effnlink--; + ip->i_effnlink--; + if (DOINGSOFTDEP(vp)) + softdep_setup_rmdir(dp, ip); + error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1); + if (error) { + dp->i_effnlink++; + ip->i_effnlink++; + if (DOINGSOFTDEP(vp)) + softdep_revert_rmdir(dp, ip); + goto out; + } + cache_purge(dvp); + /* + * The only stuff left in the directory is "." and "..". The "." + * reference is inconsequential since we are quashing it. The soft + * dependency code will arrange to do these operations after + * the parent directory entry has been deleted on disk, so + * when running with that code we avoid doing them now. + */ + if (!DOINGSOFTDEP(vp)) { + dp->i_nlink--; + DIP_SET(dp, i_nlink, dp->i_nlink); + dp->i_flag |= IN_CHANGE; + error = UFS_UPDATE(dvp, 0); + ip->i_nlink--; + DIP_SET(ip, i_nlink, ip->i_nlink); + ip->i_flag |= IN_CHANGE; + } + cache_purge(vp); +#ifdef UFS_DIRHASH + /* Kill any active hash; i_effnlink == 0, so it will not come back. */ + if (ip->i_dirhash != NULL) + ufsdirhash_free(ip); +#endif +out: + return (error); +} + +/* + * symlink -- make a symbolic link + */ +static int +ufs_symlink(ap) + struct vop_symlink_args /* { + struct vnode *a_dvp; + struct vnode **a_vpp; + struct componentname *a_cnp; + struct vattr *a_vap; + char *a_target; + } */ *ap; +{ + struct vnode *vp, **vpp = ap->a_vpp; + struct inode *ip; + int len, error; + + error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, + vpp, ap->a_cnp, "ufs_symlink"); + if (error) + return (error); + vp = *vpp; + len = strlen(ap->a_target); + if (len < vp->v_mount->mnt_maxsymlinklen) { + ip = VTOI(vp); + bcopy(ap->a_target, SHORTLINK(ip), len); + ip->i_size = len; + DIP_SET(ip, i_size, len); + ip->i_flag |= IN_CHANGE | IN_UPDATE; + error = UFS_UPDATE(vp, 0); + } else + error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, + UIO_SYSSPACE, IO_NODELOCKED | IO_NOMACCHECK, + ap->a_cnp->cn_cred, NOCRED, NULL, NULL); + if (error) + vput(vp); + return (error); +} + +/* + * Vnode op for reading directories. + */ +int +ufs_readdir(ap) + struct vop_readdir_args /* { + struct vnode *a_vp; + struct uio *a_uio; + struct ucred *a_cred; + int *a_eofflag; + int *a_ncookies; + u_long **a_cookies; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct uio *uio = ap->a_uio; + struct buf *bp; + struct inode *ip; + struct direct *dp, *edp; + u_long *cookies; + struct dirent dstdp; + off_t offset, startoffset; + size_t readcnt, skipcnt; + ssize_t startresid; + int ncookies; + int error; + + if (uio->uio_offset < 0) + return (EINVAL); + ip = VTOI(vp); + if (ip->i_effnlink == 0) + return (0); + if (ap->a_ncookies != NULL) { + if (uio->uio_resid < 0) + ncookies = 0; + else + ncookies = uio->uio_resid; + if (uio->uio_offset >= ip->i_size) + ncookies = 0; + else if (ip->i_size - uio->uio_offset < ncookies) + ncookies = ip->i_size - uio->uio_offset; + ncookies = ncookies / (offsetof(struct direct, d_name) + 4) + 1; + cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK); + *ap->a_ncookies = ncookies; + *ap->a_cookies = cookies; + } else { + ncookies = 0; + cookies = NULL; + } + offset = startoffset = uio->uio_offset; + startresid = uio->uio_resid; + error = 0; + while (error == 0 && uio->uio_resid > 0 && + uio->uio_offset < ip->i_size) { + error = ffs_blkatoff(vp, uio->uio_offset, NULL, &bp); + if (error) + break; + if (bp->b_offset + bp->b_bcount > ip->i_size) + readcnt = ip->i_size - bp->b_offset; + else + readcnt = bp->b_bcount; + skipcnt = (size_t)(uio->uio_offset - bp->b_offset) & + ~(size_t)(DIRBLKSIZ - 1); + offset = bp->b_offset + skipcnt; + dp = (struct direct *)&bp->b_data[skipcnt]; + edp = (struct direct *)&bp->b_data[readcnt]; + while (error == 0 && uio->uio_resid > 0 && dp < edp) { + if (dp->d_reclen <= offsetof(struct direct, d_name) || + (caddr_t)dp + dp->d_reclen > (caddr_t)edp) { + error = EIO; + break; + } +#if BYTE_ORDER == LITTLE_ENDIAN + /* Old filesystem format. */ + if (vp->v_mount->mnt_maxsymlinklen <= 0) { + dstdp.d_namlen = dp->d_type; + dstdp.d_type = dp->d_namlen; + } else +#endif + { + dstdp.d_namlen = dp->d_namlen; + dstdp.d_type = dp->d_type; + } + if (offsetof(struct direct, d_name) + dstdp.d_namlen > + dp->d_reclen) { + error = EIO; + break; + } + if (offset < startoffset || dp->d_ino == 0) + goto nextentry; + dstdp.d_fileno = dp->d_ino; + dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp); + bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen); + dstdp.d_name[dstdp.d_namlen] = '\0'; + if (dstdp.d_reclen > uio->uio_resid) { + if (uio->uio_resid == startresid) + error = EINVAL; + else + error = EJUSTRETURN; + break; + } + /* Advance dp. */ + error = uiomove((caddr_t)&dstdp, dstdp.d_reclen, uio); + if (error) + break; + if (cookies != NULL) { + KASSERT(ncookies > 0, + ("ufs_readdir: cookies buffer too small")); + *cookies = offset + dp->d_reclen; + cookies++; + ncookies--; + } +nextentry: + offset += dp->d_reclen; + dp = (struct direct *)((caddr_t)dp + dp->d_reclen); + } + bqrelse(bp); + uio->uio_offset = offset; + } + /* We need to correct uio_offset. */ + uio->uio_offset = offset; + if (error == EJUSTRETURN) + error = 0; + if (ap->a_ncookies != NULL) { + if (error == 0) { + ap->a_ncookies -= ncookies; + } else { + free(*ap->a_cookies, M_TEMP); + *ap->a_ncookies = 0; + *ap->a_cookies = NULL; + } + } + if (error == 0 && ap->a_eofflag) + *ap->a_eofflag = ip->i_size <= uio->uio_offset; + return (error); +} + +/* + * Return target name of a symbolic link + */ +static int +ufs_readlink(ap) + struct vop_readlink_args /* { + struct vnode *a_vp; + struct uio *a_uio; + struct ucred *a_cred; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + doff_t isize; + + isize = ip->i_size; + if ((isize < vp->v_mount->mnt_maxsymlinklen) || + DIP(ip, i_blocks) == 0) { /* XXX - for old fastlink support */ + return (uiomove(SHORTLINK(ip), isize, ap->a_uio)); + } + return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); +} + +/* + * Calculate the logical to physical mapping if not done already, + * then call the device strategy routine. + * + * In order to be able to swap to a file, the ufs_bmaparray() operation may not + * deadlock on memory. See ufs_bmap() for details. + */ +static int +ufs_strategy(ap) + struct vop_strategy_args /* { + struct vnode *a_vp; + struct buf *a_bp; + } */ *ap; +{ + struct buf *bp = ap->a_bp; + struct vnode *vp = ap->a_vp; + ufs2_daddr_t blkno; + int error; + + if (bp->b_blkno == bp->b_lblkno) { + error = ufs_bmaparray(vp, bp->b_lblkno, &blkno, bp, NULL, NULL); + bp->b_blkno = blkno; + if (error) { + bp->b_error = error; + bp->b_ioflags |= BIO_ERROR; + bufdone(bp); + return (0); + } + if ((long)bp->b_blkno == -1) + vfs_bio_clrbuf(bp); + } + if ((long)bp->b_blkno == -1) { + bufdone(bp); + return (0); + } + bp->b_iooffset = dbtob(bp->b_blkno); + BO_STRATEGY(VFSTOUFS(vp->v_mount)->um_bo, bp); + return (0); +} + +/* + * Print out the contents of an inode. + */ +static int +ufs_print(ap) + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + + printf("\tino %lu, on dev %s", (u_long)ip->i_number, + devtoname(ITODEV(ip))); + if (vp->v_type == VFIFO) + fifo_printinfo(vp); + printf("\n"); + return (0); +} + +/* + * Close wrapper for fifos. + * + * Update the times on the inode then do device close. + */ +static int +ufsfifo_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + int usecount; + + VI_LOCK(vp); + usecount = vp->v_usecount; + if (usecount > 1) + ufs_itimes_locked(vp); + VI_UNLOCK(vp); + return (fifo_specops.vop_close(ap)); +} + +/* + * Kqfilter wrapper for fifos. + * + * Fall through to ufs kqfilter routines if needed + */ +static int +ufsfifo_kqfilter(ap) + struct vop_kqfilter_args *ap; +{ + int error; + + error = fifo_specops.vop_kqfilter(ap); + if (error) + error = vfs_kqfilter(ap); + return (error); +} + +/* + * Return POSIX pathconf information applicable to ufs filesystems. + */ +static int +ufs_pathconf(ap) + struct vop_pathconf_args /* { + struct vnode *a_vp; + int a_name; + int *a_retval; + } */ *ap; +{ + int error; + + error = 0; + switch (ap->a_name) { + case _PC_NAME_MAX: + *ap->a_retval = NAME_MAX; + break; + case _PC_PIPE_BUF: + if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) + *ap->a_retval = PIPE_BUF; + else + error = EINVAL; + break; + case _PC_CHOWN_RESTRICTED: + *ap->a_retval = 1; + break; + case _PC_NO_TRUNC: + *ap->a_retval = 1; + break; + case _PC_ACL_EXTENDED: +#ifdef UFS_ACL + if (ap->a_vp->v_mount->mnt_flag & MNT_ACLS) + *ap->a_retval = 1; + else + *ap->a_retval = 0; +#else + *ap->a_retval = 0; +#endif + break; + + case _PC_ACL_NFS4: +#ifdef UFS_ACL + if (ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) + *ap->a_retval = 1; + else + *ap->a_retval = 0; +#else + *ap->a_retval = 0; +#endif + break; + + case _PC_ACL_PATH_MAX: +#ifdef UFS_ACL + if (ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) + *ap->a_retval = ACL_MAX_ENTRIES; + else + *ap->a_retval = 3; +#else + *ap->a_retval = 3; +#endif + break; + case _PC_MAC_PRESENT: +#ifdef MAC + if (ap->a_vp->v_mount->mnt_flag & MNT_MULTILABEL) + *ap->a_retval = 1; + else + *ap->a_retval = 0; +#else + *ap->a_retval = 0; +#endif + break; + case _PC_MIN_HOLE_SIZE: + *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; + break; + case _PC_PRIO_IO: + *ap->a_retval = 0; + break; + case _PC_SYNC_IO: + *ap->a_retval = 0; + break; + case _PC_ALLOC_SIZE_MIN: + *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize; + break; + case _PC_FILESIZEBITS: + *ap->a_retval = 64; + break; + case _PC_REC_INCR_XFER_SIZE: + *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; + break; + case _PC_REC_MAX_XFER_SIZE: + *ap->a_retval = -1; /* means ``unlimited'' */ + break; + case _PC_REC_MIN_XFER_SIZE: + *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize; + break; + case _PC_REC_XFER_ALIGN: + *ap->a_retval = PAGE_SIZE; + break; + case _PC_SYMLINK_MAX: + *ap->a_retval = MAXPATHLEN; + break; + + default: + error = vop_stdpathconf(ap); + break; + } + return (error); +} + +/* + * Initialize the vnode associated with a new inode, handle aliased + * vnodes. + */ +int +ufs_vinit(mntp, fifoops, vpp) + struct mount *mntp; + struct vop_vector *fifoops; + struct vnode **vpp; +{ + struct inode *ip; + struct vnode *vp; + + vp = *vpp; + ip = VTOI(vp); + vp->v_type = IFTOVT(ip->i_mode); + if (vp->v_type == VFIFO) + vp->v_op = fifoops; + ASSERT_VOP_LOCKED(vp, "ufs_vinit"); + if (ip->i_number == ROOTINO) + vp->v_vflag |= VV_ROOT; + *vpp = vp; + return (0); +} + +/* + * Allocate a new inode. + * Vnode dvp must be locked. + */ +static int +ufs_makeinode(mode, dvp, vpp, cnp, callfunc) + int mode; + struct vnode *dvp; + struct vnode **vpp; + struct componentname *cnp; + const char *callfunc; +{ + struct inode *ip, *pdir; + struct direct newdir; + struct vnode *tvp; + int error; + + pdir = VTOI(dvp); +#ifdef INVARIANTS + if ((cnp->cn_flags & HASBUF) == 0) + panic("%s: no name", callfunc); +#endif + *vpp = NULL; + if ((mode & IFMT) == 0) + mode |= IFREG; + + if (pdir->i_effnlink < 2) { + print_bad_link_count(callfunc, dvp); + return (EINVAL); + } + error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp); + if (error) + return (error); + ip = VTOI(tvp); + ip->i_gid = pdir->i_gid; + DIP_SET(ip, i_gid, pdir->i_gid); +#ifdef SUIDDIR + { +#ifdef QUOTA + struct ucred ucred, *ucp; + gid_t ucred_group; + ucp = cnp->cn_cred; +#endif + /* + * If we are not the owner of the directory, + * and we are hacking owners here, (only do this where told to) + * and we are not giving it TO root, (would subvert quotas) + * then go ahead and give it to the other user. + * Note that this drops off the execute bits for security. + */ + if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) && + (pdir->i_mode & ISUID) && + (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) { + ip->i_uid = pdir->i_uid; + DIP_SET(ip, i_uid, ip->i_uid); + mode &= ~07111; +#ifdef QUOTA + /* + * Make sure the correct user gets charged + * for the space. + * Quickly knock up a dummy credential for the victim. + * XXX This seems to never be accessed out of our + * context so a stack variable is ok. + */ + refcount_init(&ucred.cr_ref, 1); + ucred.cr_uid = ip->i_uid; + ucred.cr_ngroups = 1; + ucred.cr_groups = &ucred_group; + ucred.cr_groups[0] = pdir->i_gid; + ucp = &ucred; +#endif + } else { + ip->i_uid = cnp->cn_cred->cr_uid; + DIP_SET(ip, i_uid, ip->i_uid); + } + +#ifdef QUOTA + if ((error = getinoquota(ip)) || + (error = chkiq(ip, 1, ucp, 0))) { + if (DOINGSOFTDEP(tvp)) + softdep_revert_link(pdir, ip); + UFS_VFREE(tvp, ip->i_number, mode); + vput(tvp); + return (error); + } +#endif + } +#else /* !SUIDDIR */ + ip->i_uid = cnp->cn_cred->cr_uid; + DIP_SET(ip, i_uid, ip->i_uid); +#ifdef QUOTA + if ((error = getinoquota(ip)) || + (error = chkiq(ip, 1, cnp->cn_cred, 0))) { + if (DOINGSOFTDEP(tvp)) + softdep_revert_link(pdir, ip); + UFS_VFREE(tvp, ip->i_number, mode); + vput(tvp); + return (error); + } +#endif +#endif /* !SUIDDIR */ + ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; + ip->i_mode = mode; + DIP_SET(ip, i_mode, mode); + tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */ + ip->i_effnlink = 1; + ip->i_nlink = 1; + DIP_SET(ip, i_nlink, 1); + if (DOINGSOFTDEP(tvp)) + softdep_setup_create(VTOI(dvp), ip); + if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && + priv_check_cred(cnp->cn_cred, PRIV_VFS_SETGID, 0)) { + ip->i_mode &= ~ISGID; + DIP_SET(ip, i_mode, ip->i_mode); + } + + if (cnp->cn_flags & ISWHITEOUT) { + ip->i_flags |= UF_OPAQUE; + DIP_SET(ip, i_flags, ip->i_flags); + } + + /* + * Make sure inode goes to disk before directory entry. + */ + error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(tvp) | DOINGASYNC(tvp))); + if (error) + goto bad; +#ifdef MAC + if (dvp->v_mount->mnt_flag & MNT_MULTILABEL) { + error = mac_vnode_create_extattr(cnp->cn_cred, dvp->v_mount, + dvp, tvp, cnp); + if (error) + goto bad; + } +#endif +#ifdef UFS_ACL + if (dvp->v_mount->mnt_flag & MNT_ACLS) { + error = ufs_do_posix1e_acl_inheritance_file(dvp, tvp, mode, + cnp->cn_cred, cnp->cn_thread); + if (error) + goto bad; + } else if (dvp->v_mount->mnt_flag & MNT_NFS4ACLS) { + error = ufs_do_nfs4_acl_inheritance(dvp, tvp, mode, + cnp->cn_cred, cnp->cn_thread); + if (error) + goto bad; + } +#endif /* !UFS_ACL */ + ufs_makedirentry(ip, cnp, &newdir); + error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL, 0); + if (error) + goto bad; + *vpp = tvp; + return (0); + +bad: + /* + * Write error occurred trying to update the inode + * or the directory so must deallocate the inode. + */ + ip->i_effnlink = 0; + ip->i_nlink = 0; + DIP_SET(ip, i_nlink, 0); + ip->i_flag |= IN_CHANGE; + if (DOINGSOFTDEP(tvp)) + softdep_revert_create(VTOI(dvp), ip); + vput(tvp); + return (error); +} + +static int +ufs_ioctl(struct vop_ioctl_args *ap) +{ + + switch (ap->a_command) { + case FIOSEEKDATA: + case FIOSEEKHOLE: + return (vn_bmap_seekhole(ap->a_vp, ap->a_command, + (off_t *)ap->a_data, ap->a_cred)); + default: + return (ENOTTY); + } +} + +/* Global vfs data structures for ufs. */ +struct vop_vector ufs_vnodeops = { + .vop_default = &default_vnodeops, + .vop_fsync = VOP_PANIC, + .vop_read = VOP_PANIC, + .vop_reallocblks = VOP_PANIC, + .vop_write = VOP_PANIC, + .vop_accessx = ufs_accessx, + .vop_bmap = ufs_bmap, + .vop_cachedlookup = ufs_lookup, + .vop_close = ufs_close, + .vop_create = ufs_create, + .vop_getattr = ufs_getattr, + .vop_inactive = ufs_inactive, + .vop_ioctl = ufs_ioctl, + .vop_link = ufs_link, + .vop_lookup = vfs_cache_lookup, + .vop_markatime = ufs_markatime, + .vop_mkdir = ufs_mkdir, + .vop_mknod = ufs_mknod, + .vop_open = ufs_open, + .vop_pathconf = ufs_pathconf, + .vop_poll = vop_stdpoll, + .vop_print = ufs_print, + .vop_readdir = ufs_readdir, + .vop_readlink = ufs_readlink, + .vop_reclaim = ufs_reclaim, + .vop_remove = ufs_remove, + .vop_rename = ufs_rename, + .vop_rmdir = ufs_rmdir, + .vop_setattr = ufs_setattr, +#ifdef MAC + .vop_setlabel = vop_stdsetlabel_ea, +#endif + .vop_strategy = ufs_strategy, + .vop_symlink = ufs_symlink, + .vop_whiteout = ufs_whiteout, +#ifdef UFS_EXTATTR + .vop_getextattr = ufs_getextattr, + .vop_deleteextattr = ufs_deleteextattr, + .vop_setextattr = ufs_setextattr, +#endif +#ifdef UFS_ACL + .vop_getacl = ufs_getacl, + .vop_setacl = ufs_setacl, + .vop_aclcheck = ufs_aclcheck, +#endif +}; + +struct vop_vector ufs_fifoops = { + .vop_default = &fifo_specops, + .vop_fsync = VOP_PANIC, + .vop_accessx = ufs_accessx, + .vop_close = ufsfifo_close, + .vop_getattr = ufs_getattr, + .vop_inactive = ufs_inactive, + .vop_kqfilter = ufsfifo_kqfilter, + .vop_markatime = ufs_markatime, + .vop_pathconf = ufs_pathconf, + .vop_print = ufs_print, + .vop_read = VOP_PANIC, + .vop_reclaim = ufs_reclaim, + .vop_setattr = ufs_setattr, +#ifdef MAC + .vop_setlabel = vop_stdsetlabel_ea, +#endif + .vop_write = VOP_PANIC, +#ifdef UFS_EXTATTR + .vop_getextattr = ufs_getextattr, + .vop_deleteextattr = ufs_deleteextattr, + .vop_setextattr = ufs_setextattr, +#endif +#ifdef UFS_ACL + .vop_getacl = ufs_getacl, + .vop_setacl = ufs_setacl, + .vop_aclcheck = ufs_aclcheck, +#endif +}; diff --git a/Dump/ufs/ufs/ufsmount.h b/Dump/ufs/ufs/ufsmount.h new file mode 100644 index 0000000..88ecf09 --- /dev/null +++ b/Dump/ufs/ufs/ufsmount.h @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ufsmount.h 8.6 (Berkeley) 3/30/95 + * $FreeBSD: releng/11.2/sys/ufs/ufs/ufsmount.h 331722 2018-03-29 02:50:57Z eadler $ + */ + +#ifndef _UFS_UFS_UFSMOUNT_H_ +#define _UFS_UFS_UFSMOUNT_H_ + +/* + * Arguments to mount UFS-based filesystems + */ +struct ufs_args { + char *fspec; /* block special device to mount */ + struct oexport_args export; /* network export information */ +}; + +#ifdef _KERNEL + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_UFSMNT); +#endif + +struct buf; +struct inode; +struct nameidata; +struct taskqueue; +struct timeval; +struct ucred; +struct uio; +struct vnode; +struct ufs_extattr_per_mount; +struct jblocks; +struct inodedep; + +TAILQ_HEAD(inodedeplst, inodedep); +LIST_HEAD(bmsafemaphd, bmsafemap); + +/* This structure describes the UFS specific mount structure data. */ +struct ufsmount { + struct mount *um_mountp; /* filesystem vfs structure */ + struct cdev *um_dev; /* device mounted */ + struct g_consumer *um_cp; + struct bufobj *um_bo; /* Buffer cache object */ + struct vnode *um_devvp; /* block device mounted vnode */ + u_long um_fstype; /* type of filesystem */ + struct fs *um_fs; /* pointer to superblock */ + struct ufs_extattr_per_mount um_extattr; /* extended attrs */ + u_long um_nindir; /* indirect ptrs per block */ + u_long um_bptrtodb; /* indir ptr to disk block */ + u_long um_seqinc; /* inc between seq blocks */ + struct mtx um_lock; /* Protects ufsmount & fs */ + pid_t um_fsckpid; /* PID permitted fsck sysctls */ + struct mount_softdeps *um_softdep; /* softdep mgmt structure */ + struct vnode *um_quotas[MAXQUOTAS]; /* pointer to quota files */ + struct ucred *um_cred[MAXQUOTAS]; /* quota file access cred */ + time_t um_btime[MAXQUOTAS]; /* block quota time limit */ + time_t um_itime[MAXQUOTAS]; /* inode quota time limit */ + char um_qflags[MAXQUOTAS]; /* quota specific flags */ + int64_t um_savedmaxfilesize; /* XXX - limit maxfilesize */ + int um_candelete; /* devvp supports TRIM */ + int um_writesuspended; /* suspension in progress */ + u_int um_trim_inflight; + struct taskqueue *um_trim_tq; + int (*um_balloc)(struct vnode *, off_t, int, struct ucred *, + int, struct buf **); + int (*um_blkatoff)(struct vnode *, off_t, char **, struct buf **); + int (*um_truncate)(struct vnode *, off_t, int, struct ucred *); + int (*um_update)(struct vnode *, int); + int (*um_valloc)(struct vnode *, int, struct ucred *, + struct vnode **); + int (*um_vfree)(struct vnode *, ino_t, int); + void (*um_ifree)(struct ufsmount *, struct inode *); + int (*um_rdonly)(struct inode *); + void (*um_snapgone)(struct inode *); +}; + +#define UFS_BALLOC(aa, bb, cc, dd, ee, ff) VFSTOUFS((aa)->v_mount)->um_balloc(aa, bb, cc, dd, ee, ff) +#define UFS_BLKATOFF(aa, bb, cc, dd) VFSTOUFS((aa)->v_mount)->um_blkatoff(aa, bb, cc, dd) +#define UFS_TRUNCATE(aa, bb, cc, dd) VFSTOUFS((aa)->v_mount)->um_truncate(aa, bb, cc, dd) +#define UFS_UPDATE(aa, bb) VFSTOUFS((aa)->v_mount)->um_update(aa, bb) +#define UFS_VALLOC(aa, bb, cc, dd) VFSTOUFS((aa)->v_mount)->um_valloc(aa, bb, cc, dd) +#define UFS_VFREE(aa, bb, cc) VFSTOUFS((aa)->v_mount)->um_vfree(aa, bb, cc) +#define UFS_IFREE(aa, bb) ((aa)->um_ifree(aa, bb)) +#define UFS_RDONLY(aa) (ITOUMP(aa)->um_rdonly(aa)) +#define UFS_SNAPGONE(aa) (ITOUMP(aa)->um_snapgone(aa)) + +#define UFS_LOCK(aa) mtx_lock(&(aa)->um_lock) +#define UFS_UNLOCK(aa) mtx_unlock(&(aa)->um_lock) +#define UFS_MTX(aa) (&(aa)->um_lock) + +/* + * Filesystem types + */ +#define UFS1 1 +#define UFS2 2 + +/* + * Flags describing the state of quotas. + */ +#define QTF_OPENING 0x01 /* Q_QUOTAON in progress */ +#define QTF_CLOSING 0x02 /* Q_QUOTAOFF in progress */ +#define QTF_64BIT 0x04 /* 64-bit quota file */ + +/* Convert mount ptr to ufsmount ptr. */ +#define VFSTOUFS(mp) ((struct ufsmount *)((mp)->mnt_data)) +#define UFSTOVFS(ump) (ump)->um_mountp + +/* + * Macros to access filesystem parameters in the ufsmount structure. + * Used by ufs_bmap. + */ +#define MNINDIR(ump) ((ump)->um_nindir) +#define blkptrtodb(ump, b) ((b) << (ump)->um_bptrtodb) +#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc) +#endif /* _KERNEL */ + +#endif diff --git a/Makefile b/Makefile index 2c0089b..c87d58e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CURDIR=${.CURDIR} -OBJ_DIR?= ${CURDIR}/obj +OBJ_DIR?= ${CURDIR}/build CLEANDIR=clean @@ -13,14 +13,12 @@ WORLD_INC="-I${CURDIR}/include_old -I${CURDIR}/lib/objgfx40/ -I${CURDIR}/lib/libcpp/include" WORLD_FLAGS=_ARCH=${_ARCH} CC="cc" CXX="c++" AS="as" AR="ar" LD="ld" NM=nm OBJDUMP= OBJCOPY="objcopy" RANLIB=ranlib -WMAKE= ${MAKE} ${WORLD_FLAGS} INCLUDE=${WORLD_INC} BUILD_DIR=${CURDIR}/build +WMAKE=${MAKE} ${WORLD_FLAGS} INCLUDE=${WORLD_INC} BUILD_DIR=${CURDIR}/build TMP_PATH=${PATH} ROOT=/ubixos all: kernel world install-kernel install-world -# csu ubix_api libc_old libc ubix libcpp bin tools -# depend kernel tools kernel: @cd sys;make diff --git a/Makefile.incl b/Makefile.incl index 30939ec..cd34834 100644 --- a/Makefile.incl +++ b/Makefile.incl @@ -1,4 +1,4 @@ -# $Id: Makefile.inc 89 2016-01-12 00:20:40Z reddawg $ +# The System Makefile (C) 2002, 2017 The UbixOS Project # Global 'Source' Options # allow you to change your default compiler without affecting your other work diff --git a/README.md b/README.md index 28e4972..b1ef0dd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ UbixOS =============== -Build Information: +Build Information: 1.1-CURRENT make - Builds Kernel And World make kernel - Build Kernel Only diff --git a/bin/Makefile b/bin/Makefile index 7a2f8e9..e84eb72 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -1,8 +1,6 @@ -# $Id: Makefile 121 2016-01-14 03:18:20Z reddawg $ -# The System Makefile (C) 2002 The UbixOS Project +# System Makefile (C) 2002 The UbixOS Project all: init-bin login-bin shell-bin clock-bin cp-bin fdisk-bin format-bin disklabel-bin ubistry-bin ttyd-bin stat-bin muffin-bin -# cat-bin # MrOlsen (2016-01-11) ERROR: weird it didnt like -elf rtld-elf-bin # MrOlsen (2016-01-11) NOTE: edit-bin # test-bin pwd-bin de-bin ls-bin goofball-bin mount-bin diff --git a/bin/login/main.c b/bin/login/main.c index 576dc01..b18fdd5 100644 --- a/bin/login/main.c +++ b/bin/login/main.c @@ -63,6 +63,20 @@ static char *argv_shell[2] = { "shell", NULL, }; // ARGV For Initial Proccess static char *envp_shell[6] = { "HOME=/", "PWD=/", "PATH=/bin:/sbin:/usr/bin:/usr/sbin", "USER=root", "GROUP=admin", NULL, }; //ENVP For Initial Proccess + +static char *envp_init[11] = { + "HOST=Dev.uBixOS.com", + "TERM=xterm", + "SHELL=/bin/sh", + "HOME=/", + "PWD=/", + "PATH=/bin:/sbin:/usr/bin:/usr/sbin", + "USER=root", + "LOGNAME=root", + "GROUP=admin", + "LD_LIBRARY_PATH=/lib:/usr/lib", + NULL, }; //ENVP For Initial Proccess + int main(int argc, char **argv, char **env) { FILE *fd; @@ -140,7 +154,7 @@ fclose(fd); //chdir(data[i].path); chdir("sys:/bin/"); - execve(data[i].shell,argv_shell,envp_shell); + execve(data[i].shell,argv_shell,envp_init); printf("Error: Problem Starting Shell\n"); exit(-1); } diff --git a/bin/sh/mkbuiltins b/bin/sh/mkbuiltins old mode 100755 new mode 100644 diff --git a/bin/sh/tests/functional_test.sh b/bin/sh/tests/functional_test.sh old mode 100755 new mode 100644 diff --git a/bin/shell/exec.c b/bin/shell/exec.c index 859daf8..4470e2d 100644 --- a/bin/shell/exec.c +++ b/bin/shell/exec.c @@ -32,10 +32,36 @@ #include #include "shell.h" -static char *argv_init[2] = { "/bin/sh", NULL, }; // ARGV For Initial Proccess -//static char *envp_init[12] = { "HOST=MrOlsen.uBixOS.com", "TERM=xterm", "SHELL=/bin/sh", "HOME=/", "PWD=/", "PATH=/bin:/sbin:/usr/bin:/usr/sbin", "USER=root", "LOGNAME=root", "GROUP=admin", "LD_DEBUG=all", "LD_LIBRARY_PATH=/lib:/usr/lib", NULL, }; //ENVP For Initial Proccess -static char *envp_init[11] = { "HOST=MrOlsen.uBixOS.com", "TERM=xterm", "SHELL=/bin/sh", "HOME=/", "PWD=/", "PATH=/bin:/sbin:/usr/bin:/usr/sbin", "USER=root", "LOGNAME=root", "GROUP=admin", "LD_LIBRARY_PATH=/lib:/usr/lib", NULL, }; //ENVP For Initial Proccess +static char *argv_init[2] = { + "/bin/sh", + NULL, }; // ARGV For Initial Proccess +static char *envp_init_old[12] = { + "HOST=MrOlsen.uBixOS.com", + "TERM=xterm", + "SHELL=/bin/sh", + "HOME=/", + "PWD=/", + "PATH=/bin:/sbin:/usr/bin:/usr/sbin", + "USER=root", + "LOGNAME=root", + "GROUP=admin", + "LD_DEBUG=all", + "LD_LIBRARY_PATH=/lib:/usr/lib", + NULL, }; //ENVP For Initial Proccess + +static char *envp_init[11] = { + "HOST=MrOlsen.uBixOS.com", + "TERM=xterm", + "SHELL=/bin/sh", + "HOME=/", + "PWD=/", + "PATH=/bin:/sbin:/usr/bin:/usr/sbin", + "USER=root", + "LOGNAME=root", + "GROUP=admin", + "LD_LIBRARY_PATH=/lib:/usr/lib", + NULL, }; //ENVP For Initial Proccess void execProgram(inputBuffer *data) { char file[1024]; @@ -46,13 +72,13 @@ if (!cPid) { sprintf(file, "%s%s", cwd, data->argv[1]); execve(file, argv_init, envp_init); - printf("%s: Command Not Found.\n",data->argv[1]); + printf("%s: Command Not Found.\n", data->argv[1]); exit(-1); - } + } else { if (data->bg == 0x0) { while (pidStatus(cPid) > 0) sched_yield(); - } - } + } } +} diff --git a/contrib/jemalloc/FREEBSD-upgrade b/contrib/jemalloc/FREEBSD-upgrade old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/cat/t_cat.sh b/contrib/netbsd-tests/bin/cat/t_cat.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/cp/t_cp.sh b/contrib/netbsd-tests/bin/cp/t_cp.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/dd/t_dd.sh b/contrib/netbsd-tests/bin/dd/t_dd.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/df/t_df.sh b/contrib/netbsd-tests/bin/df/t_df.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/expr/t_expr.sh b/contrib/netbsd-tests/bin/expr/t_expr.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/pax/t_pax.sh b/contrib/netbsd-tests/bin/pax/t_pax.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/ps/t_ps.sh b/contrib/netbsd-tests/bin/ps/t_ps.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/dotcmd/scoped_command b/contrib/netbsd-tests/bin/sh/dotcmd/scoped_command old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/dotcmd/t_dotcmd.sh b/contrib/netbsd-tests/bin/sh/dotcmd/t_dotcmd.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_arith.sh b/contrib/netbsd-tests/bin/sh/t_arith.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_cmdsub.sh b/contrib/netbsd-tests/bin/sh/t_cmdsub.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_evaltested.sh b/contrib/netbsd-tests/bin/sh/t_evaltested.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_exit.sh b/contrib/netbsd-tests/bin/sh/t_exit.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_expand.sh b/contrib/netbsd-tests/bin/sh/t_expand.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_fsplit.sh b/contrib/netbsd-tests/bin/sh/t_fsplit.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_here.sh b/contrib/netbsd-tests/bin/sh/t_here.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_option.sh b/contrib/netbsd-tests/bin/sh/t_option.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_redir.sh b/contrib/netbsd-tests/bin/sh/t_redir.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_redircloexec.sh b/contrib/netbsd-tests/bin/sh/t_redircloexec.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_set_e.sh b/contrib/netbsd-tests/bin/sh/t_set_e.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_shift.sh b/contrib/netbsd-tests/bin/sh/t_shift.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_ulimit.sh b/contrib/netbsd-tests/bin/sh/t_ulimit.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_varquote.sh b/contrib/netbsd-tests/bin/sh/t_varquote.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_varval.sh b/contrib/netbsd-tests/bin/sh/t_varval.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sh/t_wait.sh b/contrib/netbsd-tests/bin/sh/t_wait.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/sleep/t_sleep.sh b/contrib/netbsd-tests/bin/sleep/t_sleep.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/bin/tar/t_tar.sh b/contrib/netbsd-tests/bin/tar/t_tar.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/crypto/libcrypto/t_certs.sh b/contrib/netbsd-tests/crypto/libcrypto/t_certs.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/crypto/libcrypto/t_ciphers.sh b/contrib/netbsd-tests/crypto/libcrypto/t_ciphers.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/crypto/libcrypto/t_hashes.sh b/contrib/netbsd-tests/crypto/libcrypto/t_hashes.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/crypto/libcrypto/t_libcrypto.sh b/contrib/netbsd-tests/crypto/libcrypto/t_libcrypto.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/crypto/libcrypto/t_pubkey.sh b/contrib/netbsd-tests/crypto/libcrypto/t_pubkey.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/crypto/opencrypto/t_opencrypto.sh b/contrib/netbsd-tests/crypto/opencrypto/t_opencrypto.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/dev/audio/t_pad.sh b/contrib/netbsd-tests/dev/audio/t_pad.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/dev/cgd/t_cgd.sh b/contrib/netbsd-tests/dev/cgd/t_cgd.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/dev/clock_subr/clock_subr_test_data_gen.sh b/contrib/netbsd-tests/dev/clock_subr/clock_subr_test_data_gen.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/dev/dm/t_dm.sh b/contrib/netbsd-tests/dev/dm/t_dm.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/dev/fss/t_fss.sh b/contrib/netbsd-tests/dev/fss/t_fss.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/dev/md/t_md.sh b/contrib/netbsd-tests/dev/md/t_md.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/dev/raidframe/t_raid.sh b/contrib/netbsd-tests/dev/raidframe/t_raid.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/dev/sysmon/t_swsensor.sh b/contrib/netbsd-tests/dev/sysmon/t_swsensor.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/cd9660/t_high_ino_big_file.sh b/contrib/netbsd-tests/fs/cd9660/t_high_ino_big_file.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/ffs/ffs_common.sh b/contrib/netbsd-tests/fs/ffs/ffs_common.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/ffs/quotas_common.sh b/contrib/netbsd-tests/fs/ffs/quotas_common.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/ffs/t_clearquota.sh b/contrib/netbsd-tests/fs/ffs/t_clearquota.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/ffs/t_getquota.sh b/contrib/netbsd-tests/fs/ffs/t_getquota.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/ffs/t_miscquota.sh b/contrib/netbsd-tests/fs/ffs/t_miscquota.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/ffs/t_quotalimit.sh b/contrib/netbsd-tests/fs/ffs/t_quotalimit.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/ffs/t_setquota.sh b/contrib/netbsd-tests/fs/ffs/t_setquota.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/nfs/t_rquotad.sh b/contrib/netbsd-tests/fs/nfs/t_rquotad.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/psshfs/t_psshfs.sh b/contrib/netbsd-tests/fs/psshfs/t_psshfs.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_create.sh b/contrib/netbsd-tests/fs/tmpfs/t_create.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_devices.sh b/contrib/netbsd-tests/fs/tmpfs/t_devices.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_dots.sh b/contrib/netbsd-tests/fs/tmpfs/t_dots.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_exec.sh b/contrib/netbsd-tests/fs/tmpfs/t_exec.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_link.sh b/contrib/netbsd-tests/fs/tmpfs/t_link.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_mkdir.sh b/contrib/netbsd-tests/fs/tmpfs/t_mkdir.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_mknod.sh b/contrib/netbsd-tests/fs/tmpfs/t_mknod.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_mount.sh b/contrib/netbsd-tests/fs/tmpfs/t_mount.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_pipes.sh b/contrib/netbsd-tests/fs/tmpfs/t_pipes.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_read_write.sh b/contrib/netbsd-tests/fs/tmpfs/t_read_write.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_readdir.sh b/contrib/netbsd-tests/fs/tmpfs/t_readdir.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_remove.sh b/contrib/netbsd-tests/fs/tmpfs/t_remove.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_rename.sh b/contrib/netbsd-tests/fs/tmpfs/t_rename.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_rmdir.sh b/contrib/netbsd-tests/fs/tmpfs/t_rmdir.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_setattr.sh b/contrib/netbsd-tests/fs/tmpfs/t_setattr.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_sizes.sh b/contrib/netbsd-tests/fs/tmpfs/t_sizes.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_sockets.sh b/contrib/netbsd-tests/fs/tmpfs/t_sockets.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_statvfs.sh b/contrib/netbsd-tests/fs/tmpfs/t_statvfs.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_symlink.sh b/contrib/netbsd-tests/fs/tmpfs/t_symlink.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_times.sh b/contrib/netbsd-tests/fs/tmpfs/t_times.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_trail_slash.sh b/contrib/netbsd-tests/fs/tmpfs/t_trail_slash.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_truncate.sh b/contrib/netbsd-tests/fs/tmpfs/t_truncate.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_vnd.sh b/contrib/netbsd-tests/fs/tmpfs/t_vnd.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/tmpfs/t_vnode_leak.sh b/contrib/netbsd-tests/fs/tmpfs/t_vnode_leak.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/fs/zfs/t_zpool.sh b/contrib/netbsd-tests/fs/zfs/t_zpool.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/games/t_factor.sh b/contrib/netbsd-tests/games/t_factor.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/h_common.sh b/contrib/netbsd-tests/ipf/h_common.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/t_bpf.sh b/contrib/netbsd-tests/ipf/t_bpf.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/t_filter_exec.sh b/contrib/netbsd-tests/ipf/t_filter_exec.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/t_filter_parse.sh b/contrib/netbsd-tests/ipf/t_filter_parse.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/t_logging.sh b/contrib/netbsd-tests/ipf/t_logging.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/t_nat_exec.sh b/contrib/netbsd-tests/ipf/t_nat_exec.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/t_nat_ipf_exec.sh b/contrib/netbsd-tests/ipf/t_nat_ipf_exec.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/t_nat_parse.sh b/contrib/netbsd-tests/ipf/t_nat_parse.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/ipf/t_pools.sh b/contrib/netbsd-tests/ipf/t_pools.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/kernel/gen_t_subr_prf b/contrib/netbsd-tests/kernel/gen_t_subr_prf old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/kernel/t_ps_strings.sh b/contrib/netbsd-tests/kernel/t_ps_strings.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/kernel/t_umount.sh b/contrib/netbsd-tests/kernel/t_umount.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/kernel/t_umountstress.sh b/contrib/netbsd-tests/kernel/t_umountstress.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/csu/t_crt0.sh b/contrib/netbsd-tests/lib/csu/t_crt0.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/db/t_db.sh b/contrib/netbsd-tests/lib/libc/db/t_db.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/gen/posix_spawn/h_nonexec.sh b/contrib/netbsd-tests/lib/libc/gen/posix_spawn/h_nonexec.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/hash/t_hash.sh b/contrib/netbsd-tests/lib/libc/hash/t_hash.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/net/gen_ether_subr b/contrib/netbsd-tests/lib/libc/net/gen_ether_subr old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/net/getaddrinfo/t_getaddrinfo.sh b/contrib/netbsd-tests/lib/libc/net/getaddrinfo/t_getaddrinfo.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/net/t_hostent.sh b/contrib/netbsd-tests/lib/libc/net/t_hostent.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/net/t_nsdispatch.sh b/contrib/netbsd-tests/lib/libc/net/t_nsdispatch.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/net/t_protoent.sh b/contrib/netbsd-tests/lib/libc/net/t_protoent.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/net/t_servent.sh b/contrib/netbsd-tests/lib/libc/net/t_servent.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/regex/t_regex.sh b/contrib/netbsd-tests/lib/libc/regex/t_regex.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh b/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/stdlib/t_atexit.sh b/contrib/netbsd-tests/lib/libc/stdlib/t_atexit.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libc/stdlib/t_getopt.sh b/contrib/netbsd-tests/lib/libc/stdlib/t_getopt.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libcurses/t_curses.sh b/contrib/netbsd-tests/lib/libcurses/t_curses.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libevent/t_event.sh b/contrib/netbsd-tests/lib/libevent/t_event.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libppath/plist_to_c b/contrib/netbsd-tests/lib/libppath/plist_to_c old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libpthread/t_atexit.sh b/contrib/netbsd-tests/lib/libpthread/t_atexit.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libpthread/t_cancel.sh b/contrib/netbsd-tests/lib/libpthread/t_cancel.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libpthread/t_exit.sh b/contrib/netbsd-tests/lib/libpthread/t_exit.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libpthread/t_resolv.sh b/contrib/netbsd-tests/lib/libpthread/t_resolv.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/librumpclient/t_exec.sh b/contrib/netbsd-tests/lib/librumpclient/t_exec.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/librumphijack/t_asyncio.sh b/contrib/netbsd-tests/lib/librumphijack/t_asyncio.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/librumphijack/t_config.sh b/contrib/netbsd-tests/lib/librumphijack/t_config.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/librumphijack/t_cwd.sh b/contrib/netbsd-tests/lib/librumphijack/t_cwd.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/librumphijack/t_sh.sh b/contrib/netbsd-tests/lib/librumphijack/t_sh.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/librumphijack/t_tcpip.sh b/contrib/netbsd-tests/lib/librumphijack/t_tcpip.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/librumphijack/t_vfs.sh b/contrib/netbsd-tests/lib/librumphijack/t_vfs.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/lib/libsljit/t_sljit.sh b/contrib/netbsd-tests/lib/libsljit/t_sljit.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/libexec/ld.elf_so/t_df_1_noopen.sh b/contrib/netbsd-tests/libexec/ld.elf_so/t_df_1_noopen.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/libexec/ld.elf_so/t_dl_symver.sh b/contrib/netbsd-tests/libexec/ld.elf_so/t_dl_symver.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/modules/t_abi_uvm.sh b/contrib/netbsd-tests/modules/t_abi_uvm.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/modules/t_modload.sh b/contrib/netbsd-tests/modules/t_modload.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/arp/t_arp.sh b/contrib/netbsd-tests/net/arp/t_arp.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/arp/t_dad.sh b/contrib/netbsd-tests/net/arp/t_dad.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/carp/t_basic.sh b/contrib/netbsd-tests/net/carp/t_basic.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/fdpass/t_fdpass.sh b/contrib/netbsd-tests/net/fdpass/t_fdpass.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/icmp/t_icmp6_redirect.sh b/contrib/netbsd-tests/net/icmp/t_icmp6_redirect.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/icmp/t_icmp_redirect.sh b/contrib/netbsd-tests/net/icmp/t_icmp_redirect.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/icmp/t_ping2.sh b/contrib/netbsd-tests/net/icmp/t_ping2.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/if/t_ifconf.sh b/contrib/netbsd-tests/net/if/t_ifconf.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/if/t_ifconfig.sh b/contrib/netbsd-tests/net/if/t_ifconfig.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/if_bridge/t_bridge.sh b/contrib/netbsd-tests/net/if_bridge/t_bridge.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/if_gif/t_gif.sh b/contrib/netbsd-tests/net/if_gif/t_gif.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/if_pppoe/t_pppoe.sh b/contrib/netbsd-tests/net/if_pppoe/t_pppoe.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/if_tap/t_tap.sh b/contrib/netbsd-tests/net/if_tap/t_tap.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/if_tun/t_tun.sh b/contrib/netbsd-tests/net/if_tun/t_tun.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/if_vlan/t_vlan.sh b/contrib/netbsd-tests/net/if_vlan/t_vlan.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/in_cksum/t_in_cksum.sh b/contrib/netbsd-tests/net/in_cksum/t_in_cksum.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/mcast/t_mcast.sh b/contrib/netbsd-tests/net/mcast/t_mcast.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/mpls/t_ldp_regen.sh b/contrib/netbsd-tests/net/mpls/t_ldp_regen.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/mpls/t_mpls_fw.sh b/contrib/netbsd-tests/net/mpls/t_mpls_fw.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/mpls/t_mpls_fw6.sh b/contrib/netbsd-tests/net/mpls/t_mpls_fw6.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/mpls/t_mpls_fw64.sh b/contrib/netbsd-tests/net/mpls/t_mpls_fw64.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/mpls/t_rfc4182.sh b/contrib/netbsd-tests/net/mpls/t_rfc4182.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/ndp/t_dad.sh b/contrib/netbsd-tests/net/ndp/t_dad.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/ndp/t_ndp.sh b/contrib/netbsd-tests/net/ndp/t_ndp.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/ndp/t_ra.sh b/contrib/netbsd-tests/net/ndp/t_ra.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/net/t_forwarding.sh b/contrib/netbsd-tests/net/net/t_forwarding.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/net/t_ipaddress.sh b/contrib/netbsd-tests/net/net/t_ipaddress.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/net/t_ipv6_lifetime.sh b/contrib/netbsd-tests/net/net/t_ipv6_lifetime.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/net/t_ipv6address.sh b/contrib/netbsd-tests/net/net/t_ipv6address.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/net/t_mtudisc.sh b/contrib/netbsd-tests/net/net/t_mtudisc.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/net/t_mtudisc6.sh b/contrib/netbsd-tests/net/net/t_mtudisc6.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/net/t_ping6_opts.sh b/contrib/netbsd-tests/net/net/t_ping6_opts.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/net_common.sh b/contrib/netbsd-tests/net/net_common.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/npf/t_npf.sh b/contrib/netbsd-tests/net/npf/t_npf.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/route/t_change.sh b/contrib/netbsd-tests/net/route/t_change.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/route/t_flags.sh b/contrib/netbsd-tests/net/route/t_flags.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/route/t_flags6.sh b/contrib/netbsd-tests/net/route/t_flags6.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/net/route/t_route.sh b/contrib/netbsd-tests/net/route/t_route.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/rump/rumpkern/t_sp.sh b/contrib/netbsd-tests/rump/rumpkern/t_sp.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/rump/rumpnet/t_shmif.sh b/contrib/netbsd-tests/rump/rumpnet/t_shmif.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/fsck_ffs/quotas_common.sh b/contrib/netbsd-tests/sbin/fsck_ffs/quotas_common.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/fsck_ffs/t_check_quotas.sh b/contrib/netbsd-tests/sbin/fsck_ffs/t_check_quotas.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/fsck_ffs/t_enable_quotas.sh b/contrib/netbsd-tests/sbin/fsck_ffs/t_enable_quotas.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/gpt/t_gpt.sh b/contrib/netbsd-tests/sbin/gpt/t_gpt.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/ifconfig/t_nonexistent.sh b/contrib/netbsd-tests/sbin/ifconfig/t_nonexistent.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/newfs/quotas_common.sh b/contrib/netbsd-tests/sbin/newfs/quotas_common.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/newfs/t_enable_quotas.sh b/contrib/netbsd-tests/sbin/newfs/t_enable_quotas.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/newfs_msdos/t_create.sh b/contrib/netbsd-tests/sbin/newfs_msdos/t_create.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/resize_ffs/common.sh b/contrib/netbsd-tests/sbin/resize_ffs/common.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/resize_ffs/t_check.sh b/contrib/netbsd-tests/sbin/resize_ffs/t_check.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/resize_ffs/t_grow.sh b/contrib/netbsd-tests/sbin/resize_ffs/t_grow.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/resize_ffs/t_grow_swapped.sh b/contrib/netbsd-tests/sbin/resize_ffs/t_grow_swapped.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/resize_ffs/t_shrink.sh b/contrib/netbsd-tests/sbin/resize_ffs/t_shrink.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/resize_ffs/t_shrink_swapped.sh b/contrib/netbsd-tests/sbin/resize_ffs/t_shrink_swapped.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/route/t_missing.sh b/contrib/netbsd-tests/sbin/route/t_missing.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/sysctl/t_perm.sh b/contrib/netbsd-tests/sbin/sysctl/t_perm.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sbin/sysctl/t_sysctl.sh b/contrib/netbsd-tests/sbin/sysctl/t_sysctl.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/share/examples/t_asm.sh b/contrib/netbsd-tests/share/examples/t_asm.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/share/mk/t_lib.sh b/contrib/netbsd-tests/share/mk/t_lib.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/share/mk/t_own.sh b/contrib/netbsd-tests/share/mk/t_own.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/share/mk/t_prog.sh b/contrib/netbsd-tests/share/mk/t_prog.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/share/mk/t_test.sh b/contrib/netbsd-tests/share/mk/t_test.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sys/rc/h_args.sh b/contrib/netbsd-tests/sys/rc/h_args.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sys/rc/h_simple.sh b/contrib/netbsd-tests/sys/rc/h_simple.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/sys/rc/t_rc_d_cli.sh b/contrib/netbsd-tests/sys/rc/t_rc_d_cli.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/awk/t_awk.sh b/contrib/netbsd-tests/usr.bin/awk/t_awk.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/basename/t_basename.sh b/contrib/netbsd-tests/usr.bin/basename/t_basename.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/bzip2/t_bzip2.sh b/contrib/netbsd-tests/usr.bin/bzip2/t_bzip2.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/cc/t_hello.sh b/contrib/netbsd-tests/usr.bin/cc/t_hello.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/cmp/t_cmp.sh b/contrib/netbsd-tests/usr.bin/cmp/t_cmp.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/config/t_config.sh b/contrib/netbsd-tests/usr.bin/config/t_config.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/cut/t_cut.sh b/contrib/netbsd-tests/usr.bin/cut/t_cut.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/diff/t_diff.sh b/contrib/netbsd-tests/usr.bin/diff/t_diff.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/dirname/t_dirname.sh b/contrib/netbsd-tests/usr.bin/dirname/t_dirname.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/find/t_find.sh b/contrib/netbsd-tests/usr.bin/find/t_find.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/gdb/t_regress.sh b/contrib/netbsd-tests/usr.bin/gdb/t_regress.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/gzip/t_gzip.sh b/contrib/netbsd-tests/usr.bin/gzip/t_gzip.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/id/t_groups.sh b/contrib/netbsd-tests/usr.bin/id/t_groups.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/id/t_id.sh b/contrib/netbsd-tests/usr.bin/id/t_id.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/id/t_whoami.sh b/contrib/netbsd-tests/usr.bin/id/t_whoami.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/infocmp/t_terminfo.sh b/contrib/netbsd-tests/usr.bin/infocmp/t_terminfo.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/jot/t_jot.sh b/contrib/netbsd-tests/usr.bin/jot/t_jot.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/ld/t_script.sh b/contrib/netbsd-tests/usr.bin/ld/t_script.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/ld/t_section.sh b/contrib/netbsd-tests/usr.bin/ld/t_section.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/m4/t_m4.sh b/contrib/netbsd-tests/usr.bin/m4/t_m4.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/make/t_make.sh b/contrib/netbsd-tests/usr.bin/make/t_make.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/mixerctl/t_mixerctl.sh b/contrib/netbsd-tests/usr.bin/mixerctl/t_mixerctl.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/mkdep/t_mkdep.sh b/contrib/netbsd-tests/usr.bin/mkdep/t_mkdep.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/nbperf/h_nbperf.sh b/contrib/netbsd-tests/usr.bin/nbperf/h_nbperf.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/nbperf/t_nbperf.sh b/contrib/netbsd-tests/usr.bin/nbperf/t_nbperf.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/netpgpverify/t_netpgpverify.sh b/contrib/netbsd-tests/usr.bin/netpgpverify/t_netpgpverify.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/pr/t_basic.sh b/contrib/netbsd-tests/usr.bin/pr/t_basic.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/rump_server/t_disk.sh b/contrib/netbsd-tests/usr.bin/rump_server/t_disk.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/sdiff/t_sdiff.sh b/contrib/netbsd-tests/usr.bin/sdiff/t_sdiff.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/sed/t_sed.sh b/contrib/netbsd-tests/usr.bin/sed/t_sed.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/shmif_dumpbus/t_basic.sh b/contrib/netbsd-tests/usr.bin/shmif_dumpbus/t_basic.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/sort/t_sort.sh b/contrib/netbsd-tests/usr.bin/sort/t_sort.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/tmux/t_tmux.sh b/contrib/netbsd-tests/usr.bin/tmux/t_tmux.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/tr/t_basic.sh b/contrib/netbsd-tests/usr.bin/tr/t_basic.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/unifdef/t_basic.sh b/contrib/netbsd-tests/usr.bin/unifdef/t_basic.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/uniq/t_uniq.sh b/contrib/netbsd-tests/usr.bin/uniq/t_uniq.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/vmstat/t_vmstat.sh b/contrib/netbsd-tests/usr.bin/vmstat/t_vmstat.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.bin/xlint/lint1/t_integration.sh b/contrib/netbsd-tests/usr.bin/xlint/lint1/t_integration.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.sbin/mtree/t_mtree.sh b/contrib/netbsd-tests/usr.sbin/mtree/t_mtree.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.sbin/tcpdump/t_tcpdump.sh b/contrib/netbsd-tests/usr.sbin/tcpdump/t_tcpdump.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.sbin/traceroute/t_traceroute.sh b/contrib/netbsd-tests/usr.sbin/traceroute/t_traceroute.sh old mode 100755 new mode 100644 diff --git a/contrib/netbsd-tests/usr.sbin/useradd/t_useradd.sh b/contrib/netbsd-tests/usr.sbin/useradd/t_useradd.sh old mode 100755 new mode 100644 diff --git a/debug/getrlimit.c b/debug/getrlimit.c new file mode 100644 index 0000000..620975e --- /dev/null +++ b/debug/getrlimit.c @@ -0,0 +1,13 @@ +#include +#include +#include + + + +int main(int argc, char **argv) { + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) != -1) + printf("cur: %i, max: %i\n", rl.rlim_cur, rl.rlim_max); + + return(0); +} diff --git a/debug/pipe2.c b/debug/pipe2.c new file mode 100644 index 0000000..845487c --- /dev/null +++ b/debug/pipe2.c @@ -0,0 +1,61 @@ +#include +#include +#include + +#define MSGSIZE 32 + + +int main(int argc, char **argv) { + int p[2]; + int pid; + int j; + + char inbuf[MSGSIZE]; + + if (pipe(p) == -1) { + printf("pipe call error"); + exit(1); + } + + for (j = 0; j < 2; j++) + printf("p[%i]: %i\n", j, p[j]); + + write(p[1], "TEST 1", MSGSIZE); + printf("r: %i\n", read(p[0], inbuf, MSGSIZE)); + printf("Parent: %s\n", inbuf); + write(p[1], "TEST 2", MSGSIZE); + printf("r: %i\n", read(p[0], inbuf, MSGSIZE)); + printf("Parent: %s\n", inbuf); + printf("r: %i\n", read(p[0], inbuf, MSGSIZE)); + printf("Parent: %s\n", inbuf); + write(p[1], "TEST 3", MSGSIZE); + read(p[0], inbuf, MSGSIZE); + printf("Parent: %s\n", inbuf); +printf("lseek: %i\n", lseek(p[0], 128, SEEK_SET)); + write(p[1], "TEST 4", MSGSIZE); + write(p[1], "TEST 5", MSGSIZE); + read(p[0], inbuf, MSGSIZE); + printf("Parent: %s\n", inbuf); + read(p[0], inbuf, MSGSIZE); + printf("Parent: %s\n", inbuf); + printf("r: %i\n", read(p[0], inbuf, MSGSIZE)); + printf("Parent: %s\n", inbuf); +/* + switch (pid = fork()) { + case 0: + close(p[0]); + write(p[1], "TEST 1", MSGSIZE); + write(p[1], "TEST 2", MSGSIZE); + write(p[1], "TEST 3", MSGSIZE); + break; + default: + close(p[1]); + for (j=0;j<3;j++) { + read(p[0], inbuf, MSGSIZE); + printf("Parent: %s\n", inbuf); + } + } +*/ + + return(0); +} diff --git a/debug/readlink.c b/debug/readlink.c new file mode 100644 index 0000000..b76dba8 --- /dev/null +++ b/debug/readlink.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) { + char *buf = (char *)malloc(1024); + + printf("__error: 0x%X\n", (u_int32_t)__error()); + printf("readlink: %i\n", readlink("/etc/malloc.conf", buf, 1024)); + printf("buf: [%s]\n", buf); + printf("__error: 0x%X\n", (u_int32_t)__error()); + printf("errno: %i\n", errno); + + return(0); +} diff --git a/debug/sysctl.c b/debug/sysctl.c new file mode 100644 index 0000000..b4c45b9 --- /dev/null +++ b/debug/sysctl.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +int mib[CTL_MAXNAME]; +size_t len; +char *p; + +static int name2oid(const char *name, int *oidp); + +int main() { + printf("SYSCTL\n"); + + int i; + u_int32_t *tI; + int *sI; + + + mib[0] = 1; + mib[1] = 18; + + sysctl(mib, 2, NULL, &len, NULL, 0); + p = malloc(len); + sysctl(mib, 2, p, &len, NULL, 0); + + printf("[len: %i]\n", len); + if (len == 4) { + sI = p; + printf("[%i]\n", sI[0]); + } + else + printf("[%s]\n", p); + + size_t j; + + j = name2oid("kern.ngroups", mib); + //j = name2oid("hw.pagesizes", mib); + + printf("j:[%i]\n", j); + + for (int i = 0; i < j; i++) + printf("[%i]", mib[i]); + + printf("\n"); +} + +static int name2oid(const char *name, int *oidp) +{ + int oid[2]; + int i; + size_t j; + + oid[0] = 0; + oid[1] = 3; + + j = CTL_MAXNAME * sizeof(int); + i = sysctl(oid, 2, oidp, &j, name, strlen(name)); + if (i < 0) + return (i); + j /= sizeof(int); + return (j); +} + diff --git a/etc/userdb b/etc/userdb index ed464e7..def853f 100644 --- a/etc/userdb +++ b/etc/userdb Binary files differ diff --git a/include/mk-osreldate.sh b/include/mk-osreldate.sh old mode 100755 new mode 100644 diff --git a/include/sys/socket.h b/include/sys/socket.h new file mode 100644 index 0000000..718cd0f --- /dev/null +++ b/include/sys/socket.h @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_SOCKET_HH_ +#define _SYS_SOCKET_H_ + +#endif /* !_SYS_SOCKET_H_ */ diff --git a/lib/Makefile b/lib/Makefile index 8127688..0f32f5a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,5 +1,4 @@ -# $Id: Makefile 121 2016-01-14 03:18:20Z reddawg $ -# The System Makefile (C) 2002 The UbixOS Project +# Makefile (C) 2002 The UbixOS Project all: csu-code ubix_api-code libc_old-code ubix-code libcpp-code objgfx-code #libc-code# libcpp-code # bin tools diff --git a/lib/libc/regex/grot/mkh b/lib/libc/regex/grot/mkh old mode 100755 new mode 100644 diff --git a/lib/libc_old/sys/setgid.c b/lib/libc_old/sys/setgid.c index b38299d..7352ca8 100644 --- a/lib/libc_old/sys/setgid.c +++ b/lib/libc_old/sys/setgid.c @@ -33,7 +33,7 @@ volatile int status = 0x0; asm volatile( "int %0\n" - : : "i" (0x80),"a" (34),"b" (gid),"c" (&status) + : : "i" (0x80),"a" (181),"b" (gid),"c" (&status) ); return(status); } diff --git a/lib/objgfx/objgfx40.so b/lib/objgfx/objgfx40.so deleted file mode 100755 index 963e03b..0000000 --- a/lib/objgfx/objgfx40.so +++ /dev/null Binary files differ diff --git a/lib/objgfx40/ROMAN1.DPF b/lib/objgfx40/ROMAN1.DPF old mode 100755 new mode 100644 Binary files differ diff --git a/lib/objgfx40/SCRIPT.DPF b/lib/objgfx40/SCRIPT.DPF old mode 100755 new mode 100644 Binary files differ diff --git a/lib/objgfx40/ogDisplay_UbixOS.cc b/lib/objgfx40/ogDisplay_UbixOS.cc old mode 100755 new mode 100644 diff --git a/libexec/Makefile b/libexec/Makefile index 96e6538..1a9cdaa 100644 --- a/libexec/Makefile +++ b/libexec/Makefile @@ -1,4 +1,4 @@ -# The System Makefile (C) 2017 The UbixOS Project +# Makefile (C) 2017 The UbixOS Project all: ld-bin #rtld-elf-bin diff --git a/sys/Makefile b/sys/Makefile index 929246e..549a24b 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -1,5 +1,4 @@ -# $Id: Makefile 134 2016-01-15 14:50:24Z reddawg $ -# Kernel Makefile (C) 2002 The UbixOS Project +# Makefile (C) 2002 The UbixOS Project include ../Makefile.incl include Makefile.incl @@ -37,8 +36,8 @@ init-code: init (cd init;make) -arch-code: ${_ARCH} - (cd ${_ARCH};make) +arch-code: arch/${_ARCH} + (cd arch/${_ARCH};make) kernel-code: kernel (cd kernel;make) @@ -110,7 +109,7 @@ clean: (cd init;make clean) - (cd ${_ARCH};make clean) + (cd arch/${_ARCH};make clean) (cd sys;make clean) (cd kernel;make clean) (cd vmm;make clean) @@ -121,10 +120,10 @@ (cd pci;make clean) (cd net;make clean) (cd compile;make clean) - #(cd vfs;make clean) - #(cd sde;make clean) - #(cd devfs;make clean) - #(cd net;make clean) - #(cd kmods;make clean) - #(cd ufs;make clean) + (cd fs/vfs;make clean) + (cd sde;make clean) + (cd fs/devfs;make clean) + (cd net;make clean) + (cd kmods;make clean) + (cd fs/ufs;make clean) #(cd ../tools/;make clean) diff --git a/sys/Makefile.incl b/sys/Makefile.incl index c3eb38f..71ba64b 100644 --- a/sys/Makefile.incl +++ b/sys/Makefile.incl @@ -9,6 +9,6 @@ INCLUDES = -I${INCLUDE} -CFLAGS = ${KFLAGS} -O -Wall -nostdlib -nostdinc -fno-builtin -fno-exceptions -ffreestanding +CFLAGS = ${KFLAGS} -DDEBUG_SYSCTL -O -Wall -nostdlib -nostdinc -fno-builtin -fno-exceptions -ffreestanding ROOT=/ubixos diff --git a/sys/arch/armv6/Makefile b/sys/arch/armv6/Makefile new file mode 100644 index 0000000..de38484 --- /dev/null +++ b/sys/arch/armv6/Makefile @@ -0,0 +1,28 @@ +# (C) 2002 The UbixOS Project +# $Id: Makefile 134 2016-01-15 14:50:24Z reddawg $ + +# Include Global 'Source' Options +include ../../Makefile.incl +include ../Makefile.incl + +# Objects +OBJS = schedyield.o kpanic.o timer.o spinlock.o i386_exec.o sys_call_new.o sys_call.o bioscall.o fork.o syscall.o systemtask.o sched.o cpu.o +# ap-boot.o smp.o vitals.o(obsolete) + +all: $(OBJS) + +# Compile Types +.cc.o: + $(CXX) -DNOBOOL $(CFLAGS) $(INCLUDES) -c -o $@ $< +.cc.s: + $(CXX) -DNOBOOL $(CFLAGS) $(INCLUDES) -S -o $@ $< +.c.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< +.c.s: + $(CC) $(CFLAGS) $(INCLUDES) -S -o $@ $< +.S.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< + +# Clean up the junk +clean: + $(REMOVE) $(OBJS) diff --git a/sys/arch/armv6/ap-boot.S b/sys/arch/armv6/ap-boot.S new file mode 100644 index 0000000..c08bd1e --- /dev/null +++ b/sys/arch/armv6/ap-boot.S @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Okay, this file contains the code that's going to bootstrap the AP cpus + */ + + + .globl ap_trampoline_start,ap_trampoline_end + .text + .code16 +ap_trampoline_start: + cli + cld + + movw %cs,%ax // The CPU knows its CS already, so lets use it for the other segments + movw %ax,%ds + movw %ax,%es + movw %ax,%ss + + // Do some bochs-specific bullshit + mov $0x31,%al // '1' + mov $0xe9,%dx + outb %al,%dx + //lgdt ap_gdt; + lgdt ap_trampoline_gdt_limit - ap_trampoline_start + movl %cr0,%eax + orl $0x1,%eax + movl %eax,%cr0 // PMODE! + +.code32 + .byte 0x66 + ljmp $0x08,$(ap_trampoline_32 - ap_trampoline_start) // 0x08 == KERNEL_CS + +ap_trampoline_32: + mov $0x32,%al // '2' + mov $0xe9,%dx + outb %al,%dx + + mov $0x10,%ax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + mov %ax,%ss + + // Spinlock + mov ap_trampoline_spl - ap_trampoline_start,%edi +ap_spl: + //cmp $1,(%edi) + //je ap_spl + + mov $1,%eax // Value to be set + xchgl (%edi),%eax + cmp $0,%eax + je ap_spl + // /Spinlock + + mov $0x30,%al // '0' + mov $0xe9,%dx + outb %al,%dx + + mov ap_trampoline_stackptr - ap_trampoline_start,%ebx + mov %ebx,%esp + add $0x1000,%ebx + mov %ebx,ap_trampoline_stackptr - ap_trampoline_start + + mov $0x31,%al // '1' + mov $0xe9,%dx + outb %al,%dx + + // spinunlock + mov $0,%eax + mov ap_trampoline_spl - ap_trampoline_start,%edi + xchgl (%edi),%eax + // /spinunlock + + mov $0x33,%al // '3' + mov $0xe9,%dx + outb %al,%dx + + mov ap_trampoline_epoint,%eax + call *%eax +1: + hlt + jmp 1b // Halt if we ever get here somehow + + // Stack.. This sucks, since CPU initialization isn't serialized +ap_trampoline_stackptr: + .long 0x10000 // 256KB +ap_trampoline_epoint: + .long c_ap_boot + +ap_trampoline_spl: + .long 0 +ap_gdt: + .long ubixGDT + + // GDT +ap_trampoline_gdt: + .word 0 +ap_trampoline_gdt_limit: + .word 128 // Room for 32 descriptors +ap_trampoline_gdt_base: + .long 0x20000 // 128KB (move this later) + + +ap_trampoline_end: diff --git a/sys/arch/armv6/bioscall.c b/sys/arch/armv6/bioscall.c new file mode 100644 index 0000000..c27a8db --- /dev/null +++ b/sys/arch/armv6/bioscall.c @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +asm( + ".globl bios16Code\n" + ".code16 \n" + "bios16Code: \n" + "int $0x10 \n" + "int $0x69 \n" + ".code32 \n" + ); + + +void biosCall(int biosInt,int eax,int ebx,int ecx,int edx,int esi,int edi,int es,int ds) { + short segment = 0x0,offset = 0x0; + uInt32 tmpAddr = (uInt32)&bios16Code; + kTask_t *newProcess = 0x0; + + offset = tmpAddr & 0xF; // lower 4 bits + segment = tmpAddr >> 4; + + newProcess = schedNewTask(); + assert(newProcess); + + + newProcess->tss.back_link = 0x0; + newProcess->tss.esp0 = (uInt32)kmalloc(0x2000)+0x2000; + newProcess->tss.ss0 = 0x10; + newProcess->tss.esp1 = 0x0; + newProcess->tss.ss1 = 0x0; + newProcess->tss.esp2 = 0x0; + newProcess->tss.ss2 = 0x0; + newProcess->tss.cr3 = (uInt32)_current->tss.cr3;//(uInt32)vmmCreateVirtualSpace(newProcess->id); + newProcess->tss.eip = offset & 0xFFFF; + newProcess->tss.eflags = 2 | EFLAG_IF | EFLAG_VM; + newProcess->tss.eax = eax & 0xFFFF; + newProcess->tss.ebx = ebx & 0xFFFF; + newProcess->tss.ecx = ecx & 0xFFFF; + newProcess->tss.edx = edx & 0xFFFF; + newProcess->tss.esp = 0x1000 & 0xFFFF; + newProcess->tss.ebp = 0x1000 & 0xFFFF; + newProcess->tss.esi = esi & 0xFFFF; + newProcess->tss.edi = edi & 0xFFFF; + newProcess->tss.es = es & 0xFFFF; + newProcess->tss.cs = segment & 0xFFFF; + newProcess->tss.ss = 0x1000 & 0xFFFF; + newProcess->tss.ds = ds & 0xFFFF; + newProcess->tss.fs = 0x0 & 0xFFFF; + newProcess->tss.gs = 0x0 & 0xFFFF; + newProcess->tss.ldt = 0x0 & 0xFFFF; + newProcess->tss.trace_bitmap = 0x0 & 0xFFFF; + newProcess->tss.io_map = 0x0 & 0xFFFF; + newProcess->tss.io_map = sizeof(struct tssStruct)-8192; + newProcess->oInfo.v86Task = 0x1; + + newProcess->state = READY; + + while (newProcess->state > 0); + + return; + } + +/*** + END + ***/ + diff --git a/sys/arch/armv6/exec.c b/sys/arch/armv6/exec.c new file mode 100644 index 0000000..3af2f28 --- /dev/null +++ b/sys/arch/armv6/exec.c @@ -0,0 +1,750 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STACK_ADDR 0xC800000 + +#define AT_NULL 0 /* Terminates the vector. */ +#define AT_IGNORE 1 /* Ignored entry. */ +#define AT_EXECFD 2 /* File descriptor of program to load. */ +#define AT_PHDR 3 /* Program header of program already loaded. */ +#define AT_PHENT 4 /* Size of each program header entry. */ +#define AT_PHNUM 5 /* Number of program header entries. */ +#define AT_PAGESZ 6 /* Page size in bytes. */ +#define AT_BASE 7 /* Interpreter's base address. */ +#define AT_FLAGS 8 /* Flags (unused for i386). */ +#define AT_ENTRY 9 /* Where interpreter should transfer control. */ + +//#define AUXARGS_ENTRY(pos, id, val) {memcpy((void *)pos++,(void *)id,sizeof(long)); memcpy((void *)pos++,(void *)val,sizeof(long));} +#define AUXARGS_ENTRY(pos, id, val) {*pos = id;pos++; *pos = val;pos++;} + +/***************************************************************************************** + + Function: execThread(void (*)(void),int,char *); + Description: This function will create a thread from code in the current memory space + + Notes: + + 05/19/04 - This does not work the way I want it to it still makes a copy of kernel space + so do not use out side of kernel space + + *****************************************************************************************/ +uInt32 execThread(void (*tproc)(void), uInt32 stack, char *arg) { + kTask_t * newProcess = 0x0; + /* Find A New Thread */ + newProcess = schedNewTask(); + assert(newProcess); + if (stack < 0x100000) + kpanic("exec: stack not in valid area: [0x%X]\n", stack); + + /* Set All The Correct Thread Attributes */ + newProcess->tss.back_link = 0x0; + newProcess->tss.esp0 = 0x0; + newProcess->tss.ss0 = 0x0; + newProcess->tss.esp1 = 0x0; + newProcess->tss.ss1 = 0x0; + newProcess->tss.esp2 = 0x0; + newProcess->tss.ss2 = 0x0; + newProcess->tss.cr3 = (unsigned int) kernelPageDirectory; + newProcess->tss.eip = (unsigned int) tproc; + newProcess->tss.eflags = 0x206; + newProcess->tss.esp = stack; + newProcess->tss.ebp = stack; + newProcess->tss.esi = 0x0; + newProcess->tss.edi = 0x0; + + /* Set these up to be ring 3 tasks */ + /* + newProcess->tss.es = 0x30+3; + newProcess->tss.cs = 0x28+3; + newProcess->tss.ss = 0x30+3; + newProcess->tss.ds = 0x30+3; + newProcess->tss.fs = 0x30+3; + newProcess->tss.gs = 0x30+3; + */ + + newProcess->tss.es = 0x10; + newProcess->tss.cs = 0x08; + newProcess->tss.ss = 0x10; + newProcess->tss.ds = 0x10; + newProcess->tss.fs = 0x10; + newProcess->tss.gs = 0x10; + + newProcess->tss.ldt = 0x18; + newProcess->tss.trace_bitmap = 0x0000; + newProcess->tss.io_map = 0x8000; + newProcess->oInfo.vmStart = 0x6400000; + + //newProcess->imageFd = 0x0; + + /* Set up default stack for thread here filled with arg list 3 times */ + asm volatile( + "pusha \n" + "movl %%esp,%%ecx \n" + "movl %1,%%eax \n" + "movl %%eax,%%esp \n" + "pushl %%ebx \n" + "pushl %%ebx \n" + "pushl %%ebx \n" + "movl %%esp,%%eax \n" + "movl %%eax,%1 \n" + "movl %%ecx,%%esp \n" + "popa \n" + : + : "b" (arg),"m" (newProcess->tss.esp) + ); + + /* Put new thread into the READY state */ + sched_setStatus(newProcess->id, READY); + + /* Return with the new process ID */ + return ((uInt32) newProcess); +} + +/***************************************************************************************** + + Function: void execFile(char *file); + Description: This Function Executes A Kile Into A New VM Space With Out + Having To Fork + Notes: + + 07/30/02 - I Have Made Some Heavy Changes To This As Well As Fixed A Few + Memory Leaks The Memory Allocated To Load The Binary Into Is + Now Unmapped So It Can Be Used Again And Not Held Onto Until + The Program Exits + + 07/30/02 - Now I Have To Make A Better Memory Allocator So We Can Set Up + The Freshly Allocated Pages With The Correct Permissions + + *****************************************************************************************/ +void execFile(char *file, int argc, char **argv, int console) { + + int i = 0x0; + int x = 0x0; + uint32_t *tmp = 0x0; + + fileDescriptor *tmpFd = 0x0; + elfHeader *binaryHeader = 0x0; + elfProgramHeader *programHeader = 0x0; + + /* Get A New Task For This Proccess */ + _current = schedNewTask(); + assert(_current); + _current->gid = 0x0; + _current->uid = 0x0; + _current->term = tty_find(console); + if (_current->term == 0x0) + kprintf("Error: invalid console\n"); + + /* Set tty ownership */ + _current->term->owner = _current->id; + + /* Now We Must Create A Virtual Space For This Proccess To Run In */ + _current->tss.cr3 = (uInt32) vmmCreateVirtualSpace(_current->id); + + /* To Better Load This Application We Will Switch Over To Its VM Space */ + asm volatile( + "movl %0,%%eax \n" + "movl %%eax,%%cr3 \n" + : : "d" ((uInt32 *)(_current->tss.cr3)) + ); + + /* Lets Find The File */ + tmpFd = fopen(file, "r"); + + /* If We Dont Find the File Return */ + if (tmpFd == 0x0) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + fclose(tmpFd); + return; + } + if (tmpFd->perms == 0x0) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + fclose(tmpFd); + return; + } + + /* Load ELF Header */ + binaryHeader = (elfHeader *) kmalloc(sizeof(elfHeader)); + + //kprintf(">a:%i:0x%X:0x%X<",sizeof(elfHeader),binaryHeader,tmpFd); + fread(binaryHeader, sizeof(elfHeader), 1, tmpFd); + + /* Check If App Is A Real Application */ + if ((binaryHeader->eIdent[1] != 'E') && (binaryHeader->eIdent[2] != 'L') && (binaryHeader->eIdent[3] != 'F')) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(tmpFd); + return; + } + else if (binaryHeader->eType != 2) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(tmpFd); + return; + } + else if (binaryHeader->eEntry == 0x300000) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(tmpFd); + return; + } + + /* Load The Program Header(s) */ + programHeader = (elfProgramHeader *) kmalloc(sizeof(elfProgramHeader) * binaryHeader->ePhnum); + fseek(tmpFd, binaryHeader->ePhoff, 0); + + //kprintf(">c:%i:0x%X:0x%X<",sizeof(elfProgramHeader)*binaryHeader->ePhnum,programHeader,tmpFd); + fread(programHeader, (sizeof(elfProgramHeader) * binaryHeader->ePhnum), 1, tmpFd); + //kprintf(">d<"); + + /* Loop Through The Header And Load Sections Which Need To Be Loaded */ + for (i = 0; i < binaryHeader->ePhnum; i++) { + if (programHeader[i].phType == 1) { + /* + Allocate Memory Im Going To Have To Make This Load Memory With Correct + Settings so it helps us in the future + */ + for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { + /* Make readonly and read/write !!! */ + if (vmm_remapPage(vmm_findFreePage(_current->id), ((programHeader[i].phVaddr & 0xFFFFF000) + x), PAGE_DEFAULT) == 0x0) + K_PANIC("Remap Page Failed"); + + memset((void *) ((programHeader[i].phVaddr & 0xFFFFF000) + x), 0x0, 0x1000); + } + _current->oInfo.vmStart = 0x80000000; + _current->td.vm_daddr = (char *) (programHeader[i].phVaddr & 0xFFFFF000); + /* Now Load Section To Memory */ + fseek(tmpFd, programHeader[i].phOffset, 0); + fread((void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, tmpFd); + if ((programHeader[i].phFlags & 0x2) != 0x2) { + kprintf("pH: [0x%X]\n", programHeader[i].phMemsz); + for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { + if ((vmm_setPageAttributes((programHeader[i].phVaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) + kpanic("Error: vmm_setPageAttributes failed, File: %s, Line: %i\n", __FILE__, __LINE__); + } + } + } + } + + /* Set Virtual Memory Start */ + _current->oInfo.vmStart = 0x80000000; + _current->td.vm_daddr = (char *) (programHeader[i].phVaddr & 0xFFFFF000); + + /* Set Up Stack Space */ + for (x = 1; x < 100; x++) { + vmm_remapPage(vmm_findFreePage(_current->id), STACK_ADDR - (x * 0x1000), PAGE_DEFAULT | PAGE_STACK); + } + + /* Kernel Stack 0x2000 bytes long */ + vmm_remapPage(vmm_findFreePage(_current->id), 0x5BC000, KERNEL_PAGE_DEFAULT | PAGE_STACK); + vmm_remapPage(vmm_findFreePage(_current->id), 0x5BB000, KERNEL_PAGE_DEFAULT | PAGE_STACK); + + /* Set All The Proper Information For The Task */ + _current->tss.back_link = 0x0; + _current->tss.esp0 = 0x5BC000; + _current->tss.ss0 = 0x10; + _current->tss.esp1 = 0x0; + _current->tss.ss1 = 0x0; + _current->tss.esp2 = 0x0; + _current->tss.ss2 = 0x0; + _current->tss.eip = (long) binaryHeader->eEntry; + _current->tss.eflags = 0x206; + _current->tss.esp = STACK_ADDR - 12; + _current->tss.ebp = STACK_ADDR; + _current->tss.esi = 0x0; + _current->tss.edi = 0x0; + + /* Set these up to be ring 3 tasks */ + _current->tss.es = 0x30 + 3; + _current->tss.cs = 0x28 + 3; + _current->tss.ss = 0x30 + 3; + _current->tss.ds = 0x30 + 3; + _current->tss.fs = 0x30 + 3; + _current->tss.gs = 0x30 + 3; + + _current->tss.ldt = 0x18; + _current->tss.trace_bitmap = 0x0000; + _current->tss.io_map = 0x8000; + + sched_setStatus(_current->id, READY); + + kfree(binaryHeader); + kfree(programHeader); + fclose(tmpFd); + + tmp = (uInt32 *) _current->tss.esp0 - 5; + tmp[0] = binaryHeader->eEntry; + tmp[3] = STACK_ADDR - 12; + + tmp = (uInt32 *) STACK_ADDR - 2; + + if (_current->id > 4) + kprintf("argv[0]: [%s]\n", argv[0]); + kprintf("argv: [0x%X]\n", argv); + tmp[0] = (uint32_t) argv; + tmp[1] = (uint32_t) argv; + + /* Switch Back To The Kernels VM Space */ + asm volatile( + "movl %0,%%eax \n" + "movl %%eax,%%cr3 \n" + : : "d" ((uInt32 *)(kernelPageDirectory)) + ); + + /* Finally Return */ + return; +} + +/***************************************************************************************** + + Function: void sysExec(); + Description: This Is The System Call To Execute A New Task + + Notes: + 04-22-03 - It Now Loads Sections Not The Full File + + *****************************************************************************************/ +void sysExec(char *file, char *ap) { + int i = 0x0; + int x = 0x0; + int argc = 0x0; + unsigned int *tmp = 0x0; + uInt32 ldAddr = 0x0; + uInt32 seg_size = 0x0; + uInt32 seg_addr = 0x0; + char *interp = 0x0; + char **argv = 0x0; + char **argvNew = 0x0; + char *args = 0x0; + + fileDescriptor *tmpFd = 0x0; + elfHeader *binaryHeader = 0x0; + elfProgramHeader *programHeader = 0x0; + elfSectionHeader *sectionHeader = 0x0; + elfDynamic *elfDynamicS = 0x0; + struct i386_frame *iFrame = 0x0; + + tmpFd = fopen(file, "r"); + _current->files[0] = tmpFd; + /* If We Dont Find the File Return */ + if (tmpFd == 0x0) { + return; + } + if (tmpFd->perms == 0) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + fclose(tmpFd); + return; + } + + /* Load ELF Header */ + + if ((binaryHeader = (elfHeader *) kmalloc(sizeof(elfHeader))) == 0x0) + endTask(_current->id); + fread(binaryHeader, sizeof(elfHeader), 1, tmpFd); + /* Set sectionHeader To Point To Loaded Binary To We Can Gather Info */ + + /* Check If App Is A Real Application */ + if ((binaryHeader->eIdent[1] != 'E') && (binaryHeader->eIdent[2] != 'L') && (binaryHeader->eIdent[3] != 'F')) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(tmpFd); + + return; + } + else if (binaryHeader->eType != 2) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(tmpFd); + return; + } + else if (binaryHeader->eEntry == 0x300000) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(tmpFd); + return; + } + + /* Load The Program Header(s) */ + if ((programHeader = (elfProgramHeader *) kmalloc(sizeof(elfProgramHeader) * binaryHeader->ePhnum)) == 0x0) + endTask(_current->id); + + assert(programHeader); + fseek(tmpFd, binaryHeader->ePhoff, 0); + fread(programHeader, (sizeof(elfProgramHeader) * binaryHeader->ePhnum), 1, tmpFd); + + if ((sectionHeader = (elfSectionHeader *) kmalloc(sizeof(elfSectionHeader) * binaryHeader->eShnum)) == 0x0) + endTask(_current->id); + + assert(sectionHeader); + fseek(tmpFd, binaryHeader->eShoff, 0); + fread(sectionHeader, sizeof(elfSectionHeader) * binaryHeader->eShnum, 1, tmpFd); + + /* Loop Through The Header And Load Sections Which Need To Be Loaded */ + for (i = 0; i < binaryHeader->ePhnum; i++) { + switch (programHeader[i].phType) { + case PT_LOAD: + seg_addr = trunc_page(programHeader[i].phVaddr); + seg_size = round_page(programHeader[i].phMemsz + programHeader[i].phVaddr - seg_addr); + + /* + Allocate Memory Im Going To Have To Make This Load Memory With Correct + Settings so it helps us in the future + */ + for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { + /* Make readonly and read/write !!! */ + if (vmm_remapPage(vmm_findFreePage(_current->id), ((programHeader[i].phVaddr & 0xFFFFF000) + x), PAGE_DEFAULT) == 0x0) + K_PANIC("Error: Remap Page Failed"); + memset((void *) ((programHeader[i].phVaddr & 0xFFFFF000) + x), 0x0, 0x1000); + } + + /* Now Load Section To Memory */ + fseek(tmpFd, programHeader[i].phOffset, 0); + fread((void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, tmpFd); + if ((programHeader[i].phFlags & 0x2) != 0x2) { + for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { + if ((vmm_setPageAttributes((programHeader[i].phVaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) + kpanic("Error: vmm_setPageAttributes failed, File: %s,Line: %i\n", __FILE__, __LINE__); + } + } + kprintf("setting daddr\n"); + if (binaryHeader->eEntry >= programHeader[i].phVaddr && binaryHeader->eEntry < (programHeader[i].phVaddr + programHeader[i].phMemsz)) { + /* We're suposed to do something here? */ + } + else { + _current->td.vm_dsize = seg_size >> PAGE_SHIFT; + _current->td.vm_daddr = (char *) seg_addr; + } + + _current->oInfo.vmStart = ((programHeader[i].phVaddr & 0xFFFFF000) + 0xA900000); + break; + case PT_DYNAMIC: + //newLoc = (char *)programHeader[i].phVaddr; + elfDynamicS = (elfDynamic *) programHeader[i].phVaddr; + fseek(tmpFd, programHeader[i].phOffset, 0); + fread((void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, tmpFd); + break; + case PT_INTERP: + interp = (char *) kmalloc(programHeader[i].phFilesz); + fseek(tmpFd, programHeader[i].phOffset, 0); + fread((void *) interp, programHeader[i].phFilesz, 1, tmpFd); + kprintf("Interp: [%s]\n", interp); + ldAddr = ldEnable(); + break; + default: + break; + } + } + + /* What is this doing? 11/23/06 */ + if (elfDynamicS != 0x0) { + for (i = 0; i < 12; i++) { + if (elfDynamicS[i].dynVal == 0x3) { + tmp = (void *) elfDynamicS[i].dynPtr; + if (tmp == 0x0) + kpanic("tmp: NULL\n"); + tmp[2] = (uInt32) ldAddr; + tmp[1] = (uInt32) tmpFd; + break; + } + /* + else { + kprintf("dyn_val: %i",elfDynamicS[i].dynVal); + } + */ + } + } + + _current->td.vm_dsize = seg_size >> PAGE_SHIFT; + _current->td.vm_daddr = (char *) seg_addr; + + argv = ≈ + + if (argv[1] != 0x0) { + argc = (int) argv[0]; + args = (char *) vmmGetFreeVirtualPage(_current->id, 1, VM_TASK); + memset(args, 0x0, 0x1000); + x = 0x0; + argvNew = (char **) kmalloc(sizeof(char *) * argc); + for (i = 0x0; i < argc; i++) { + strcpy(args + x, argv[i + 1]); + argvNew[i] = args + x; + x += strlen(argv[i + 1]) + 1; + //args[x] = '\0'; + //x++; + } + argv = argvNew; + } + + //! Clean the virtual of COW pages left over from the fork + vmm_cleanVirtualSpace(_current->td.vm_daddr + (_current->td.vm_dsize << PAGE_SIZE)); + + //! Adjust iframe + iFrame = (struct i386_frame *) _current->tss.esp0 - sizeof(struct i386_frame); + iFrame->ebp = STACK_ADDR; + iFrame->eip = binaryHeader->eEntry; + iFrame->user_esp = STACK_ADDR - 12; + + //if (_current->id > 3) { + + iFrame->user_esp = ((uint32_t) STACK_ADDR) - (sizeof(uint32_t) * (argc + 3)); + tmp = (void *) iFrame->user_esp; + + //! build argc and argv[] + tmp[0] = argc; + for (i = 0; i < argc; i++) { + tmp[i + 1] = (u_int) argv[i]; + } + tmp[argc + 1] = 0x0; + tmp[argc + 2] = 0x1; + //} + //else { + //tmp = (uint32_t *)STACK_ADDR - 2; + //tmp[0] = 0x1; + //tmp[1] = 0x0; + //tmp[1] = (uint32_t)argv; + //} + kfree(argvNew); + /* Now That We Relocated The Binary We Can Unmap And Free Header Info */ + kfree(binaryHeader); + kfree(programHeader); + + return; +} + +/*! + * \brief New exec... + * + */ +void sys_exec(char *file, char *ap) { + int error = 0x0; + int i = 0x0; + int x = 0x0; + int argc = 0x0; + uint32_t *tmp = 0x0; + uint32_t seg_size = 0x0; + uint32_t seg_addr = 0x0; + uint32_t addr = 0x0; + uint32_t eip = 0x0; + uint32_t proghdr = 0x0; + char *args = 0x0; + char *interp = 0x0; + char **argv = 0x0; + char **argvNew = 0x0; + elfHeader *binaryHeader = 0x0; + elfProgramHeader *programHeader = 0x0; + struct i386_frame *iFrame = 0x0; + //Elf_Auxargs *auxargs = 0x0; + + _current->files[0] = fopen(file, "r"); + if (_current->files[0] == 0x0) + return; //We Need To Set errno + + /* Load the ELF header */ + if ((binaryHeader = (elfHeader *) kmalloc(sizeof(elfHeader))) == 0x0) + K_PANIC("malloc failed!"); + fread(binaryHeader, sizeof(elfHeader), 1, _current->files[0]); + + /* Check If App Is A Real Application */ + if (((binaryHeader->eIdent[1] != 'E') && (binaryHeader->eIdent[2] != 'L') && (binaryHeader->eIdent[3] != 'F')) || (binaryHeader->eType != ET_EXEC)) { + kfree(binaryHeader); + fclose(_current->files[0]); + return; //We Need To Set errno + } + + /* Load The Program Header(s) */ + if ((programHeader = (elfProgramHeader *) kmalloc(sizeof(elfProgramHeader) * binaryHeader->ePhnum)) == 0x0) + K_PANIC("malloc failed!"); + fseek(_current->files[0], binaryHeader->ePhoff, 0); + fread(programHeader, (sizeof(elfProgramHeader) * binaryHeader->ePhnum), 1, _current->files[0]); + + /* Loop Through The Header And Load Sections Which Need To Be Loaded */ + for (i = 0x0; i < binaryHeader->ePhnum; i++) { + switch (programHeader[i].phType) { + case PT_LOAD: + seg_addr = trunc_page(programHeader[i].phVaddr); + seg_size = round_page(programHeader[i].phMemsz + programHeader[i].phVaddr - seg_addr); + + /* + Allocate Memory Im Going To Have To Make This Load Memory With Correct + Settings so it helps us in the future + */ + for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { + /* Make readonly and read/write !!! */ + if (vmm_remapPage(vmm_findFreePage(_current->id), ((programHeader[i].phVaddr & 0xFFFFF000) + x), PAGE_DEFAULT) == 0x0) + K_PANIC("Error: Remap Page Failed"); + memset((void *) ((programHeader[i].phVaddr & 0xFFFFF000) + x), 0x0, 0x1000); + } + + /* Now Load Section To Memory */ + fseek(_current->files[0], programHeader[i].phOffset, 0); + fread((void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, _current->files[0]); + if ((programHeader[i].phFlags & 0x2) != 0x2) { + for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { + if ((vmm_setPageAttributes((programHeader[i].phVaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) + K_PANIC("vmm_setPageAttributes failed"); + } + } + if (binaryHeader->eEntry >= programHeader[i].phVaddr && binaryHeader->eEntry < (programHeader[i].phVaddr + programHeader[i].phMemsz)) { + /* We're suposed to do something here? */ + } + else { + _current->td.vm_dsize = seg_size >> PAGE_SHIFT; + _current->td.vm_daddr = (char *) seg_addr; + } + + _current->oInfo.vmStart = ((programHeader[i].phVaddr & 0xFFFFF000) + 0xA900000); + break; + case PT_INTERP: + interp = (char *) kmalloc(programHeader[i].phFilesz); + if (interp == 0x0) + K_PANIC("malloc failed") + ; + + fseek(_current->files[0], programHeader[i].phOffset, 0); + fread((void *) interp, programHeader[i].phFilesz, 1, _current->files[0]); + kprintf("Interp: [%s]\n", interp); + //ldAddr = ldEnable(); + break; + case PT_PHDR: + proghdr = programHeader[i].phVaddr; + break; + default: + break; + } + } + + addr = LD_START; + + if (interp != 0x0) { + //kprintf("TEST"); + elf_loadfile(_current, interp, &addr, &eip); + } + //kprintf("[0x%X][0x%X]\n",eip,addr); + + _current->td.vm_dsize = seg_size >> PAGE_SHIFT; + _current->td.vm_daddr = (char *) seg_addr; + + //! copy in arg strings + argv = ap; + + if (argv[1] != 0x0) { + argc = argv[0]; + args = (char *) vmmGetFreeVirtualPage(_current->id, 1, VM_TASK); + memset(args, 0x0, 0x1000); + x = 0x0; + argvNew = (char **) kmalloc(sizeof(char *) * argc); + for (i = 0x0; i < argc; i++) { + strcpy(args + x, argv[i + 1]); + argvNew[i] = args + x; + x += strlen(argv[i + 1]) + 1; + } + argv = argvNew; + } + + //! Clean the virtual of COW pages left over from the fork + vmm_cleanVirtualSpace(_current->td.vm_daddr + (_current->td.vm_dsize << PAGE_SIZE)); + + //! Adjust iframe + iFrame = _current->tss.esp0 - sizeof(struct i386_frame); + iFrame->ebp = STACK_ADDR; + iFrame->eip = eip; + + //if (_current->id > 3) { + + iFrame->user_esp = ((uint32_t) STACK_ADDR) - (sizeof(uint32_t) * (argc + 4)); // + (sizeof(Elf_Auxargs) * 2))); + kprintf("\n\n\nuser_esp: [0x%X]\n", iFrame->user_esp); + tmp = iFrame->user_esp; + + //! build argc and argv[] + tmp[0] = argc; + for (i = 0; i < argc; i++) { + tmp[i + 1] = argv[i]; + } + //! Build ENV + args = (char *) vmmGetFreeVirtualPage(_current->id, 1, VM_TASK); + memset(args, 0x0, 0x1000); + strcpy(args, "LIBRARY_PATH=/lib"); + tmp[argc + 2] = args; + kprintf("env: [0x%X][0x%X]\n", (uInt32) tmp + argc + 2, tmp[argc + 2]); + tmp[argc + 3] = 0x0; + kprintf("env: [0x%X][0x%X]\n", (uInt32) tmp + argc + 2, tmp[argc + 2]); + //auxargs = iFrame->user_esp + argc + 3; + tmp = iFrame->user_esp; + tmp += argc + 4; + + /* + auxargs->execfd = -1; + auxargs->phdr = proghdr; + auxargs->phent = binaryHeader->ePhentsize; + auxargs->phnum = binaryHeader->ePhnum; + auxargs->pagesz = PAGE_SIZE; + auxargs->base = addr; + auxargs->flags = 0x0; + auxargs->entry = binaryHeader->eEntry; + auxargs->trace = 0x0; + + AUXARGS_ENTRY(tmp, AT_PHDR, auxargs->phdr); + AUXARGS_ENTRY(tmp, AT_PHENT, auxargs->phent); + AUXARGS_ENTRY(tmp, AT_PHNUM, auxargs->phnum); + AUXARGS_ENTRY(tmp, AT_PAGESZ, auxargs->pagesz); + AUXARGS_ENTRY(tmp, AT_FLAGS, auxargs->flags); + AUXARGS_ENTRY(tmp, AT_ENTRY, auxargs->entry); + AUXARGS_ENTRY(tmp, AT_BASE, auxargs->base); + AUXARGS_ENTRY(tmp, AT_NULL, 0); + + kprintf("AT_BASE: [0x%X]\n",auxargs->base); + */ + + //iFrame->ebx = 0x0; + //iFrame->ebx = 0x0; + //iFrame->eip = binaryHeader->eEntry; + //kprintf("\n\nDOH: [0x%X]\n\n",iFrame->eip); +//while (1); + //while (1); + /* + error = elf_loadfile(_current,file,0x0,0x0); + if (error) + K_PANIC("elf_loadfile failed"); + */ + return; +} + +/*** + END + ***/ diff --git a/sys/arch/armv6/fork.c b/sys/arch/armv6/fork.c new file mode 100644 index 0000000..20fcde6 --- /dev/null +++ b/sys/arch/armv6/fork.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************************** + Functoin: static int fork_copyProcess(struct taskStruct *newProcess,long ebp,long edi, + long esi, long none,long ebx,long ecx,long edx,long eip,long cs,long eflags, + long esp,long ss) + + Desc: This function will copy a process + + Notes: + + *****************************************************************************************/ +/* Had to remove static though tihs function is only used in this file */ +int fork_copyProcess(struct taskStruct *newProcess, long ebp, long edi, long esi, long none, long ebx, long ecx, long edx, long eip, long cs, long eflags, long esp, long ss) { + volatile struct taskStruct * tmpProcPtr = newProcess; + assert(newProcess); + assert(_current); + + /* Set Up New Tasks Information */ + memcpy(newProcess->oInfo.cwd, _current->oInfo.cwd, 1024); + + newProcess->tss.eip = eip; + newProcess->oInfo.vmStart = _current->oInfo.vmStart; + newProcess->term = _current->term; + newProcess->term->owner = newProcess->id; + newProcess->uid = _current->uid; + newProcess->gid = _current->gid; + newProcess->tss.back_link = 0x0; + newProcess->tss.esp0 = _current->tss.esp0; + newProcess->tss.ss0 = 0x10; + newProcess->tss.esp1 = 0x0; + newProcess->tss.ss1 = 0x0; + newProcess->tss.esp2 = 0x0; + newProcess->tss.ss2 = 0x0; + newProcess->tss.eflags = eflags; + newProcess->tss.eax = 0x0; + newProcess->tss.ebx = ebx; + newProcess->tss.ecx = ecx; + newProcess->tss.edx = edx; + newProcess->tss.esi = esi; + newProcess->tss.edi = edi; + newProcess->tss.ebp = ebp; + newProcess->tss.esp = esp; + newProcess->tss.cs = cs & 0xFF; + newProcess->tss.ss = ss & 0xFF; + newProcess->tss.ds = _current->tss.ds & 0xFF; + newProcess->tss.fs = _current->tss.fs & 0xFF; + newProcess->tss.gs = _current->tss.gs & 0xFF; + newProcess->tss.es = _current->tss.es & 0xFF; + newProcess->tss.ldt = 0x18; + newProcess->tss.trace_bitmap = 0x0000; + newProcess->tss.io_map = 0x8000; + /* Create A Copy Of The VM Space For New Task */ + newProcess->tss.cr3 = (uInt32) vmmCopyVirtualSpace(newProcess->id); + newProcess->state = FORK; + + /* Fix gcc optimization problems */ + while (tmpProcPtr->state == FORK) + sched_yield(); + + /* Return Id of Proccess */ + return (newProcess->id); +} + +/***************************************************************************************** + Functoin: void sysFork(); + + Desc: This function will fork a new task + + Notes: + + 08/01/02 - This Seems To Be Working Fine However I'm Not Sure If I + Chose The Best Path To Impliment It I Guess We Will See + What The Future May Bring + + *****************************************************************************************/ +asm( + ".globl sysFork \n" + "sysFork: \n" + " xor %eax,%eax \n" + " call schedNewTask \n" + " testl %eax,%eax \n" + " je fork_ret \n" + " pushl %esi \n" + " pushl %edi \n" + " pushl %ebp \n" + " pushl %eax \n" + " call fork_copyProcess \n" + " movl %eax,(%ebx) \n" + " addl $16,%esp \n" + "fork_ret: \n" + " ret \n" +); diff --git a/sys/arch/armv6/kpanic.c b/sys/arch/armv6/kpanic.c new file mode 100644 index 0000000..e4b43c7 --- /dev/null +++ b/sys/arch/armv6/kpanic.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +/*! + * \brief print panic message and halt system + * + * \param fmt panic message + * + */ +void kpanic(const char *fmt, ...) { + char buf[512]; + va_list args; + + vaStart(args, fmt); + vsprintf(buf, fmt, args); + vaEnd(args); + + /* It's important that we print on the current terminal so let's reset foreground */ + tty_foreground = NULL; + kprintf("kPanic: %s", buf); + + /* Halt The System */ + //asm("cli"); + irqDisable(0x0); + + while (1) { + asm("hlt"); + } + +} + +/*** + END + ***/ + diff --git a/sys/arch/armv6/sched.c b/sys/arch/armv6/sched.c new file mode 100644 index 0000000..5f6ffc6 --- /dev/null +++ b/sys/arch/armv6/sched.c @@ -0,0 +1,279 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static kTask_t *taskList = 0x0; +static kTask_t *delList = 0x0; +static uInt32 nextID = -1; + +kTask_t *_current = 0x0; +kTask_t *_usedMath = 0x0; + +static struct spinLock schedulerSpinLock = SPIN_LOCK_INITIALIZER; + +/************************************************************************ + + Function: int sched_init() + + Description: This function is used to enable the kernel scheduler + + Notes: + + 02/20/2004 - Approved for quality + + ************************************************************************/ + +int sched_init() { + taskList = (kTask_t *) kmalloc(sizeof(kTask_t)); + if (taskList == 0x0) + kpanic("Unable to create task list"); + + taskList->id = nextID++; + + /* Print out information on scheduler */ + kprintf("sched0 - Address: [0x%X]\n", taskList); + + /* Return so we know everything went well */ + return (0x0); +} + +void sched() { + uInt32 memAddr = 0x0; + kTask_t *tmpTask = 0x0; + kTask_t *delTask = 0x0; + + if (!spinTryLock(&schedulerSpinLock)) + return; + + tmpTask = _current->next; + //outportByte(0xE9,_current->id + '0'); + schedStart: + + /* Yield the next task from the current prio queue */ + for (; tmpTask != 0x0; tmpTask = tmpTask->next) { + if (tmpTask->state > 0x0) { + _current = tmpTask; + if (_current->state == FORK) + _current->state = READY; + break; + } + else if (tmpTask->state == DEAD) { + delTask = tmpTask; + tmpTask = tmpTask->next; + sched_deleteTask(delTask->id); + sched_addDelTask(delTask); + goto schedStart; + } + } + + /* Finished all the tasks, restarting the list */ + if (0x0 == tmpTask) { + tmpTask = taskList; + goto schedStart; + } + + if (_current->state > 0x0) { + if (_current->oInfo.v86Task == 0x1) + irqDisable(0x0); + asm("cli"); + memAddr = (uInt32) &(_current->tss); + ubixGDT[4].descriptor.baseLow = (memAddr & 0xFFFF); + ubixGDT[4].descriptor.baseMed = ((memAddr >> 16) & 0xFF); + ubixGDT[4].descriptor.baseHigh = (memAddr >> 24); + ubixGDT[4].descriptor.access = '\x89'; + spinUnlock(&schedulerSpinLock); + asm("sti"); + asm("ljmp $0x20,$0\n"); + } + else { + spinUnlock(&schedulerSpinLock); + } + + return; +} + +kTask_t *schedNewTask() { + int i = 0; + kTask_t *tmpTask = (kTask_t *) kmalloc(sizeof(kTask_t)); + struct file *fp = 0x0; + if (tmpTask == 0x0) + kpanic("Error: schedNewTask() - kmalloc failed trying to initialize a new task struct\n"); + + memset(tmpTask, 0x0, sizeof(kTask_t)); + /* Filling in tasks attrs */ + tmpTask->usedMath = 0x0; + tmpTask->state = NEW; + + /* HACK */ + for (i = 0; i < 3; i++) { + fp = (void *) kmalloc(sizeof(struct file)); + tmpTask->td.o_files[i] = (uint32_t) fp; + fp->f_flag = 0x4; + } + + spinLock(&schedulerSpinLock); + tmpTask->id = nextID++; + tmpTask->next = taskList; + tmpTask->prev = 0x0; + taskList->prev = tmpTask; + taskList = tmpTask; + + spinUnlock(&schedulerSpinLock); + + return (tmpTask); +} + +int sched_deleteTask(pidType id) { + kTask_t *tmpTask = 0x0; + + /* Checking each task from the prio queue */ + for (tmpTask = taskList; tmpTask != 0x0; tmpTask = tmpTask->next) { + if (tmpTask->id == id) { + if (tmpTask->prev != 0x0) + tmpTask->prev->next = tmpTask->next; + if (tmpTask->next != 0x0) + tmpTask->next->prev = tmpTask->prev; + if (taskList == tmpTask) + taskList = tmpTask->next; + + return (0x0); + } + } + return (0x1); +} + +int sched_addDelTask(kTask_t *tmpTask) { + tmpTask->next = delList; + tmpTask->prev = 0x0; + if (delList != 0x0) + delList->prev = tmpTask; + delList = tmpTask; + return (0x0); +} + +kTask_t *sched_getDelTask() { + kTask_t *tmpTask = 0x0; + + if (delList == 0x0) + return (0x0); + + tmpTask = delList; + delList = delList->next; + return (tmpTask); +} + +kTask_t * +schedFindTask(uInt32 id) { + kTask_t *tmpTask = 0x0; + + for (tmpTask = taskList; tmpTask; tmpTask = tmpTask->next) { + if (tmpTask->id == id) + return (tmpTask); + } + + return (0x0); +} + +/************************************************************************ + + Function: void schedEndTask() + + Description: This function will end a task + + Notes: + + 02/20/2004 - Approved for quality + + ************************************************************************/ +void schedEndTask(pidType pid) { + endTask(_current->id); + sched_yield(); +} + +/************************************************************************ + + Function: int schedEndTask() + + Description: This function will yield a task + + Notes: + + 02/20/2004 - Approved for quality + + ************************************************************************/ + +void sched_yield() { + sched(); +} + +/* + asm( + ".globl sched_yield \n" + "sched_yield: \n" + " cli \n" + " call sched \n" + ); + */ + +/************************************************************************ + + Function: int sched_setStatus(pidType pid,tState state) + + Description: Change the tasks status + + Notes: + + ************************************************************************/ +int sched_setStatus(pidType pid, tState state) { + kTask_t *tmpTask = schedFindTask(pid); + if (tmpTask == 0x0) + return (0x1); + tmpTask->state = state; + return (0x0); +} + +/*** + END + ***/ + diff --git a/sys/arch/armv6/schedyield.S b/sys/arch/armv6/schedyield.S new file mode 100644 index 0000000..1072793 --- /dev/null +++ b/sys/arch/armv6/schedyield.S @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.globl sched_yield_new +.text +.code32 +sched_yield_new: + pusha /* Save all of the registers */ + push %ss + push %ds + push %es + push %fs + push %gs + call sched + mov %eax,%esp + pop %gs + pop %fs + pop %es + pop %ds + pop %ss + popa /* Restore Registers */ + iret + +/*** + END + ***/ diff --git a/sys/arch/armv6/spinlock.c b/sys/arch/armv6/spinlock.c new file mode 100644 index 0000000..790d1fb --- /dev/null +++ b/sys/arch/armv6/spinlock.c @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +void spinLockInit(spinLock_t *lock) { + *lock = SPIN_LOCK_INITIALIZER; + } + +void spinUnlock(spinLock_t *lock) { + *lock = 0x0; + /* + register int unlocked; + asm volatile( + "xchgl %0, %1" + : "=&r" (unlocked), "=m" (*lock) : "0" (0) + ); + */ + } + +int spinTryLock(spinLock_t *lock) { + register int locked; + asm volatile("xchgl %0, %1" + : "=&r" (locked), "=m" (*lock) : "0" (1) + ); + return(!locked); + } + +void spinLock(spinLock_t *lock) { + while (!spinTryLock(lock)) + { + while (*lock == 1) + sched_yield(); + } +} + +void spinLock_scheduler(spinLock_t *lock) { + while (!spinTryLock(lock)) + while (*lock == 1); + } + + +int spinLockLocked(spinLock_t *lock) { + return(*lock != 0); + } + + +/*** + END + ***/ + diff --git a/sys/arch/armv6/sys_call.S b/sys/arch/armv6/sys_call.S new file mode 100644 index 0000000..b4a557e --- /dev/null +++ b/sys/arch/armv6/sys_call.S @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.globl _sysCall +.text +.code32 +_sysCall: + cmpl totalCalls,%eax + jae invalidSysCall + + cld + pushl %edx + pushl %ecx + pushl %ebx + call *systemCalls(,%eax,4) + popl %ebx + popl %ecx + popl %edx /* Restore Registers */ + + iret + +invalidSysCall: + movl $-1,%eax + iret + +/*** + END + ***/ + diff --git a/sys/arch/armv6/sys_call_new.S b/sys/arch/armv6/sys_call_new.S new file mode 100644 index 0000000..2f73600 --- /dev/null +++ b/sys/arch/armv6/sys_call_new.S @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define FAKE_MCOUNT(caller) pushl caller ; call __mcount ; popl %ecx + +.globl _sysCall_new +.text +.code32 +_sysCall_new: + pushl $2 /* sizeof "int 0x80" */ + subl $4,%esp /* skip over tf_trapno */ + pushal + pushl %ds + pushl %es + pushl %fs + /* switch to kernel segments */ + movl $0x10,%eax + movl %eax,%ds + movl %eax,%es + movl %eax,%fs + //FAKE_MCOUNT(TF_EIP(%esp)) + call syscall + //MEXITCOUNT + //jmp doreti + popl %fs + popl %es + popl %ds + popal + addl $8,%esp + iret + +invalidSysCall: + push %eax + call invalidCall + pop %eax + movl $-1,%eax + iret + +/*** + END + ***/ + diff --git a/sys/arch/armv6/syscall.c b/sys/arch/armv6/syscall.c new file mode 100644 index 0000000..36a81d8 --- /dev/null +++ b/sys/arch/armv6/syscall.c @@ -0,0 +1,247 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ +#include +#include + +//long fuword(const void *base); + +//void sdeTestThread(); + +asm( + ".globl _sysCallNew \n" + "_sysCallNew: \n" + " pusha \n" + " push %ss \n" + " push %ds \n" + " push %es \n" + " push %fs \n" + " push %gs \n" + " cmpl totalCalls,%eax \n" + " jae invalidSysCallNew \n" + " mov %esp,%ebx \n" + " add $12,%ebx \n" + " push (%ebx) \n" + " call *systemCalls(,%eax,4) \n" + " add $4,%esp \n" + " jmp doneNew \n" + "invalidSysCallNew: \n" + " call InvalidSystemCall \n" + "doneNew: \n" + " pop %gs \n" + " pop %fs \n" + " pop %es \n" + " pop %ds \n" + " pop %ss \n" + " popa \n" + " iret \n" +); + +void InvalidSystemCall() { + kprintf("attempt was made to an invalid system call\n"); + return; +} + +typedef struct _UbixUser UbixUser; +struct _UbixUser { + char *username; + char *password; + int uid; + int gid; + char *home; + char *shell; +}; + +void sysAuth(UbixUser *uu) { + kprintf("authenticating user %s\n", uu->username); + + /* MrOlsen 2016-01-01 uh? + if(uu->username == "root" && uu->password == "user") + { + uu->uid = 0; + uu->gid = 0; + } + */ + uu->uid = -1; + uu->gid = -1; + return; +} + +void sysPasswd(char *passwd) { + kprintf("changing user password for user %d\n", _current->uid); + return; +} + +void sysAddModule() { + return; +} + +void sysRmModule() { + return; +} + +void sysGetpid(int *pid) { + if (pid) + *pid = _current->id; + return; +} + +void sysGetUid(int *uid) { + if (uid) + *uid = _current->uid; + return; +} + +void sysGetGid(int *gid) { + if (gid) + *gid = _current->gid; + return; +} + +void sysSetUid(int uid, int *status) { + if (_current->uid == 0x0) { + _current->uid = uid; + if (status) + *status = 0x0; + } + else { + if (status) + *status = 1; + } + return; +} + +void sysSetGid(int gid, int *status) { + if (_current->gid == 0x0) { + _current->gid = gid; + if (status) + *status = 0x0; + } + else { + if (status) + *status = 1; + } + return; +} + +void sysExit(int status) { + endTask(_current->id); +} + +void sysCheckPid(int pid, int *ptr) { + kTask_t *tmpTask = schedFindTask(pid); + if ((tmpTask != 0x0) && (ptr != 0x0)) + *ptr = tmpTask->state; + else + *ptr = 0x0; + return; +} + +/************************************************************************ + + Function: void sysGetFreePage(); + Description: Allocs A Page To The Users VM Space + Notes: + + ************************************************************************/ +void sysGetFreePage(long *ptr, int count, int type) { + if (ptr) { + if (type == 2) + *ptr = (long) vmmGetFreeVirtualPage(_current->id, count, VM_THRD); + else + *ptr = (long) vmmGetFreeVirtualPage(_current->id, count, VM_TASK); + } + return; +} + +void sysGetDrives(uInt32 *ptr) { + if (ptr) + *ptr = 0x0; //(uInt32)devices; + return; +} + +void sysGetUptime(uInt32 *ptr) { + if (ptr) + *ptr = systemVitals->sysTicks; + return; +} + +void sysGetTime(uInt32 *ptr) { + if (ptr) + *ptr = systemVitals->sysUptime + systemVitals->timeStart; + return; +} + +void sysGetCwd(char *data, int len) { + if (data) + sprintf(data, "%s", _current->oInfo.cwd); + return; +} + +void sysSchedYield() { + sched_yield(); +} + +void sysStartSDE() { + int i = 0x0; + for (i = 0; i < 1400; i++) { + asm("hlt"); + } + //execThread(sdeThread,(uInt32)(kmalloc(0x2000)+0x2000),0x0); + for (i = 0; i < 1400; i++) { + asm("hlt"); + } + return; +} + +void invalidCall(int sys_call) { + kprintf("Invalid System Call #[%i]\n", sys_call); + return; +} + +/*** + END + ***/ + diff --git a/sys/arch/armv6/systemtask.c b/sys/arch/armv6/systemtask.c new file mode 100644 index 0000000..c0a999e --- /dev/null +++ b/sys/arch/armv6/systemtask.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *videoBuffer = (char *)0xB8000; + + +void systemTask() { + mpi_message_t myMsg; + uInt32 counter = 0x0; + int i = 0x0; + int *x = 0x0; + kTask_t *tmpTask = 0x0; + + if (mpi_createMbox("system") != 0x0) { + kpanic("Error: Error creating mailbox: system\n"); + } + + while(1) { + if (mpi_fetchMessage("system",&myMsg) == 0x0) { + kprintf("A"); + switch(myMsg.header) { + case 0x69: + x = (int *)&myMsg.data; + kprintf("Switching to term: [%i][%i]\n",*x,myMsg.pid); + schedFindTask(myMsg.pid)->term = tty_find(*x); + break; + case 1000: + kprintf("Restarting the system in 5 seconds\n"); + counter = systemVitals->sysUptime + 5; + while (systemVitals->sysUptime < counter) { + sched_yield(); + } + kprintf("Rebooting NOW!!!\n"); + while(inportByte(0x64) & 0x02); + outportByte(0x64, 0xFE); + break; + case 31337: + kprintf("system: backdoor opened\n"); + break; + case 0x80: + if (!strcmp(myMsg.data,"sdeStart")) { + kprintf("Starting SDE\n"); + //execThread(sdeThread,(uInt32)(kmalloc(0x2000)+0x2000),0x0); + } + else if (!strcmp(myMsg.data,"freePage")) { + kprintf("kkk Free Pages"); + } + else if (!strcmp(myMsg.data,"sdeStop")) { + printOff = 0x0; + biosCall(0x10,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0); + for (i=0x0;i<100;i++) asm("hlt"); + } + break; + default: + kprintf("system: Received message %i:%s\n",myMsg.header,myMsg.data); + break; + } + } + + /* + Here we get the next task from the delete task queue + we first check to see if it has an fd attached for the binary and after that + we free the pages for the process and then free the task + */ + tmpTask = sched_getDelTask(); + if (tmpTask != 0x0) { + if (tmpTask->files[0] != 0x0) + fclose(tmpTask->files[0]); + vmmFreeProcessPages(tmpTask->id); + kfree(tmpTask); + } + videoBuffer[0] = systemVitals->sysTicks; + sched_yield(); + } + + return; + } + +/*** + END + ***/ + diff --git a/sys/arch/armv6/timer.S b/sys/arch/armv6/timer.S new file mode 100644 index 0000000..c7aa642 --- /dev/null +++ b/sys/arch/armv6/timer.S @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.globl timerInt +.text +.code32 +timerInt: + pusha /* Save all of the registers */ + mov $0x20,%dx /* The Following Sends Our EOI To The MPIC */ + mov $0x20,%ax + outb %al,%dx + movl systemVitals,%ecx /* Put Location Of System Vitals Into ECX */ + incl 4(%ecx) /* Increment sysTicks our 1000ms counter */ + movl 4(%ecx),%eax /* Increment our sysUptime by 1S if 1000MS */ + movl $200,%ebx /* Have Passed */ + xor %edx,%edx + div %ebx + test %edx,%edx + jnz next + incl 8(%ecx) +next: + movl 4(%ecx),%eax /* Test If quantum Has Passed If So Then */ + movl 12(%ecx),%ebx /* We Can CALL sched */ + xor %edx,%edx + div %ebx + test %edx,%edx + jnz done + call sched +done: + popa /* Restore Registers */ + iret + +/*** + END + ***/ + diff --git a/sys/arch/i386/Makefile b/sys/arch/i386/Makefile new file mode 100644 index 0000000..97a86c3 --- /dev/null +++ b/sys/arch/i386/Makefile @@ -0,0 +1,28 @@ +# (C) 2002 The UbixOS Project +# $Id: Makefile 202 2016-01-23 15:21:35Z reddawg $ + +# Include Global 'Source' Options +include ../../../Makefile.incl +include ../../Makefile.incl + +# Objects +OBJS = support.o strcpy.o strcmp.o strncmp.o memset.o memcmp.o schedyield.o kpanic.o timer.o spinlock.o i386_exec.o sys_call_posix.o sys_call.o bioscall.o fork.o systemtask.o sched.o cpu.o trap.o bios16code.o +# ap-boot.o smp.o vitals.o(obsolete) + +all: $(OBJS) + +# Compile Types +.cc.o: + $(CXX) -DNOBOOL $(CFLAGS) $(INCLUDES) -c -o $@ $< +.cc.s: + $(CXX) -DNOBOOL $(CFLAGS) $(INCLUDES) -S -o $@ $< +.c.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< +.c.s: + $(CC) $(CFLAGS) $(INCLUDES) -S -o $@ $< +.S.o: + $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< + +# Clean up the junk +clean: + $(REMOVE) $(OBJS) diff --git a/sys/arch/i386/ap-boot.S b/sys/arch/i386/ap-boot.S new file mode 100644 index 0000000..c08bd1e --- /dev/null +++ b/sys/arch/i386/ap-boot.S @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Okay, this file contains the code that's going to bootstrap the AP cpus + */ + + + .globl ap_trampoline_start,ap_trampoline_end + .text + .code16 +ap_trampoline_start: + cli + cld + + movw %cs,%ax // The CPU knows its CS already, so lets use it for the other segments + movw %ax,%ds + movw %ax,%es + movw %ax,%ss + + // Do some bochs-specific bullshit + mov $0x31,%al // '1' + mov $0xe9,%dx + outb %al,%dx + //lgdt ap_gdt; + lgdt ap_trampoline_gdt_limit - ap_trampoline_start + movl %cr0,%eax + orl $0x1,%eax + movl %eax,%cr0 // PMODE! + +.code32 + .byte 0x66 + ljmp $0x08,$(ap_trampoline_32 - ap_trampoline_start) // 0x08 == KERNEL_CS + +ap_trampoline_32: + mov $0x32,%al // '2' + mov $0xe9,%dx + outb %al,%dx + + mov $0x10,%ax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + mov %ax,%ss + + // Spinlock + mov ap_trampoline_spl - ap_trampoline_start,%edi +ap_spl: + //cmp $1,(%edi) + //je ap_spl + + mov $1,%eax // Value to be set + xchgl (%edi),%eax + cmp $0,%eax + je ap_spl + // /Spinlock + + mov $0x30,%al // '0' + mov $0xe9,%dx + outb %al,%dx + + mov ap_trampoline_stackptr - ap_trampoline_start,%ebx + mov %ebx,%esp + add $0x1000,%ebx + mov %ebx,ap_trampoline_stackptr - ap_trampoline_start + + mov $0x31,%al // '1' + mov $0xe9,%dx + outb %al,%dx + + // spinunlock + mov $0,%eax + mov ap_trampoline_spl - ap_trampoline_start,%edi + xchgl (%edi),%eax + // /spinunlock + + mov $0x33,%al // '3' + mov $0xe9,%dx + outb %al,%dx + + mov ap_trampoline_epoint,%eax + call *%eax +1: + hlt + jmp 1b // Halt if we ever get here somehow + + // Stack.. This sucks, since CPU initialization isn't serialized +ap_trampoline_stackptr: + .long 0x10000 // 256KB +ap_trampoline_epoint: + .long c_ap_boot + +ap_trampoline_spl: + .long 0 +ap_gdt: + .long ubixGDT + + // GDT +ap_trampoline_gdt: + .word 0 +ap_trampoline_gdt_limit: + .word 128 // Room for 32 descriptors +ap_trampoline_gdt_base: + .long 0x20000 // 128KB (move this later) + + +ap_trampoline_end: diff --git a/sys/arch/i386/bios16code.S b/sys/arch/i386/bios16code.S new file mode 100644 index 0000000..b86ee01 --- /dev/null +++ b/sys/arch/i386/bios16code.S @@ -0,0 +1,5 @@ +.globl bios16Code +bios16Code: +.code16 +int $0x10 +int $0x69 diff --git a/sys/arch/i386/bioscall.c b/sys/arch/i386/bioscall.c new file mode 100644 index 0000000..2c6d0a4 --- /dev/null +++ b/sys/arch/i386/bioscall.c @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void biosCall(int biosInt, int eax, int ebx, int ecx, int edx, int esi, int edi, int es, int ds) { + short segment = 0x0, offset = 0x0; + uint32_t tmpAddr = (uint32_t) &bios16Code; + kTask_t *newProcess = 0x0; + + offset = tmpAddr & 0xF; // lower 4 bits + segment = tmpAddr >> 4; + + newProcess = schedNewTask(); + assert(newProcess); + + newProcess->tss.back_link = 0x0; + newProcess->tss.esp0 = (uint32_t) vmm_getFreeKernelPage(newProcess->id, 2) + (0x2000 - 0x4); // XXX I had 0xDEADBEEF I'm not sure why + newProcess->tss.ss0 = 0x10; + newProcess->tss.esp1 = 0x0; + newProcess->tss.ss1 = 0x0; + newProcess->tss.esp2 = 0x0; + newProcess->tss.ss2 = 0x0; + newProcess->tss.cr3 = kernelPageDirectory; //vmm_createVirtualSpace(newProcess->id); //(uint32_t)_current->tss.cr3; + newProcess->tss.eip = offset & 0xFFFF; + newProcess->tss.eflags = 2 | EFLAG_IF | EFLAG_VM; + newProcess->tss.eax = eax & 0xFFFF; + newProcess->tss.ebx = ebx & 0xFFFF; + newProcess->tss.ecx = ecx & 0xFFFF; + newProcess->tss.edx = edx & 0xFFFF; + newProcess->tss.esp = 0x1000 & 0xFFFF; + newProcess->tss.ebp = 0x1000 & 0xFFFF; + newProcess->tss.esi = esi & 0xFFFF; + newProcess->tss.edi = edi & 0xFFFF; + newProcess->tss.es = es & 0xFFFF; + newProcess->tss.cs = segment & 0xFFFF; + newProcess->tss.ss = 0x1000 & 0xFFFF; + newProcess->tss.ds = ds & 0xFFFF; + newProcess->tss.fs = 0x0 & 0xFFFF; + newProcess->tss.gs = 0x0 & 0xFFFF; + newProcess->tss.ldt = 0x0 & 0xFFFF; + newProcess->tss.trace_bitmap = 0x0 & 0xFFFF; + newProcess->tss.io_map = 0x0 & 0xFFFF; + newProcess->tss.io_map = sizeof(struct tssStruct) - 8192; + newProcess->oInfo.v86Task = 0x1; + + kprintf("EIP: [0x%X] 0x%X:0x%X", tmpAddr, newProcess->tss.eip, newProcess->tss.cs); + + newProcess->state = READY; + while (newProcess->state > 0) + sched_yield(); + + kprintf("EIP: [0x%X] 0x%X:0x%X!", tmpAddr, newProcess->tss.eip, newProcess->tss.cs); + kprintf("CALL DONE: %i 0x%X 0x%X!", newProcess->state, newProcess->tss.esp, newProcess->tss.ss); + + return; +} diff --git a/sys/arch/i386/cpu.c b/sys/arch/i386/cpu.c new file mode 100644 index 0000000..ef9e0c0 --- /dev/null +++ b/sys/arch/i386/cpu.c @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include diff --git a/sys/arch/i386/fork.c b/sys/arch/i386/fork.c new file mode 100644 index 0000000..a61ff8e --- /dev/null +++ b/sys/arch/i386/fork.c @@ -0,0 +1,245 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int sys_fork(struct thread *td, struct sys_fork_args *args) { + struct taskStruct *newProcess; + + newProcess = schedNewTask(); + + /* + * + * Initalize New Task Information From Parrent + * + */ + + /* Set CWD */ + memcpy(newProcess->oInfo.cwd, _current->oInfo.cwd, 1024); + + /* Set PPID */ + newProcess->ppid = _current->id; + + /* Set PGRP */ + newProcess->pgrp = _current->pgrp; + + /* Copy File Descriptor Table */ + //memcpy(newProcess->files, _current->files, sizeof(fileDescriptor_t *) * MAX_OFILES); + for (int i = 3; i < 64; i++) + if (td->o_files[i]) { + newProcess->td.o_files[i] = (struct file *)kmalloc(sizeof(struct file)); + memcpy(newProcess->td.o_files[i], td->o_files[i], sizeof(struct file)); + if (((struct file *)td->o_files[i])->fd) { + ((struct file *)newProcess->td.o_files[i])->fd = kmalloc(sizeof(fileDescriptor_t)); + memcpy( ((struct file *)newProcess->td.o_files[i])->fd, ((struct file *)td->o_files[i])->fd, sizeof(fileDescriptor_t)); + if (((struct file *)td->o_files[i])->fd->buffer) { + ((struct file *)newProcess->td.o_files[i])->fd->buffer = kmalloc(4096); + memcpy(((struct file *)newProcess->td.o_files[i])->fd->buffer, ((struct file *)td->o_files[i])->fd->buffer, 4096); + } + } + } + + /* Set Up Task State */ + newProcess->tss.eip = td->frame->tf_eip; + newProcess->oInfo.vmStart = _current->oInfo.vmStart; + newProcess->term = _current->term; + newProcess->term->owner = newProcess->id; + newProcess->uid = _current->uid; + newProcess->gid = _current->gid; + newProcess->tss.back_link = 0x0; + newProcess->tss.esp0 = _current->tss.esp0; + newProcess->tss.ss0 = 0x10; + newProcess->tss.esp1 = 0x0; + newProcess->tss.ss1 = 0x0; + newProcess->tss.esp2 = 0x0; + newProcess->tss.ss2 = 0x0; + newProcess->tss.eflags = td->frame->tf_eflags; + newProcess->tss.eax = 0x0; + newProcess->tss.ebx = td->frame->tf_ebx; + newProcess->tss.ecx = td->frame->tf_ecx; + newProcess->tss.edx = td->frame->tf_edx; + newProcess->tss.esi = td->frame->tf_esi; + newProcess->tss.edi = td->frame->tf_edi; + newProcess->tss.ebp = td->frame->tf_ebp; + newProcess->tss.esp = td->frame->tf_esp; + newProcess->tss.cs = td->frame->tf_cs; // & 0xFF; + newProcess->tss.ss = td->frame->tf_ss; // & 0xFF; + newProcess->tss.ds = td->frame->tf_ds; //_current->tss.ds & 0xFF; + newProcess->tss.fs = td->frame->tf_fs; //_current->tss.fs & 0xFF; + newProcess->tss.gs = _current->tss.gs & 0xFF; + newProcess->tss.es = td->frame->tf_es; //_current->tss.es & 0xFF; + newProcess->tss.ldt = 0x18; + newProcess->tss.trace_bitmap = 0x0000; + newProcess->tss.io_map = 0x8000; + + newProcess->td.vm_tsize = _current->td.vm_tsize; + newProcess->td.vm_taddr = _current->td.vm_taddr; + newProcess->td.vm_dsize = _current->td.vm_dsize; + newProcess->td.vm_daddr = _current->td.vm_daddr; + + //kprintf("Copying Mem Space! [0x%X:0x%X:0x%X:0x%X:0x%X:%i:%i]\n", newProcess->tss.esp0, newProcess->tss.esp, newProcess->tss.ebp, td->frame->tf_esi, td->frame->tf_eip, newProcess->id, _current->id); + + newProcess->tss.cr3 = (uInt32) vmm_copyVirtualSpace(newProcess->id); + //kprintf( "Copied Mem Space! [0x%X]\n", newProcess->tss.cr3 ); + + newProcess->state = FORK; + /* Fix gcc optimization problems */ + while (newProcess->state == FORK) + sched_yield(); + + newProcess->parent = _current; + _current->children++; + + /* Return Id of Proccess */ + td->td_retval[0] = newProcess->id; + return (0); + +} + +/***************************************************************************************** + Functoin: static int fork_copyProcess(struct taskStruct *newProcess,long ebp,long edi, + long esi, long none,long ebx,long ecx,long edx,long eip,long cs,long eflags, + long esp,long ss) + + Desc: This function will copy a process + + Notes: + + *****************************************************************************************/ + +/* Had to remove static though tihs function is only used in this file */ +int fork_copyProcess(struct taskStruct *newProcess, long ebp, long edi, long esi, long none, long ebx, long ecx, long edx, long eip, long cs, long eflags, long esp, long ss) { + volatile struct taskStruct * tmpProcPtr = newProcess; + assert(newProcess); + assert(_current); + + /* Set Up New Tasks Information */ + memcpy(newProcess->oInfo.cwd, _current->oInfo.cwd, 1024); + //kprintf( "Initializing New CWD!\n" ); + + newProcess->tss.eip = eip; + newProcess->oInfo.vmStart = _current->oInfo.vmStart; + newProcess->term = _current->term; + newProcess->term->owner = newProcess->id; + newProcess->uid = _current->uid; + newProcess->gid = _current->gid; + newProcess->tss.back_link = 0x0; + newProcess->tss.esp0 = _current->tss.esp0; + newProcess->tss.ss0 = 0x10; + newProcess->tss.esp1 = 0x0; + newProcess->tss.ss1 = 0x0; + newProcess->tss.esp2 = 0x0; + newProcess->tss.ss2 = 0x0; + newProcess->tss.eflags = eflags; + newProcess->tss.eax = 0x0; + newProcess->tss.ebx = ebx; + newProcess->tss.ecx = ecx; + newProcess->tss.edx = edx; + newProcess->tss.esi = esi; + newProcess->tss.edi = edi; + newProcess->tss.ebp = ebp; + newProcess->tss.esp = esp; + newProcess->tss.cs = cs & 0xFF; + newProcess->tss.ss = ss & 0xFF; + newProcess->tss.ds = _current->tss.ds & 0xFF; + newProcess->tss.fs = _current->tss.fs & 0xFF; + newProcess->tss.gs = _current->tss.gs & 0xFF; + newProcess->tss.es = _current->tss.es & 0xFF; + newProcess->tss.ldt = 0x18; + newProcess->tss.trace_bitmap = 0x0000; + newProcess->tss.io_map = 0x8000; + + newProcess->td.vm_tsize = _current->td.vm_tsize; + newProcess->td.vm_taddr = _current->td.vm_taddr; + newProcess->td.vm_dsize = _current->td.vm_dsize; + newProcess->td.vm_daddr = _current->td.vm_daddr; + + /* Create A Copy Of The VM Space For New Task */ + //MrOlsen 2018kprintf("Copying Mem Space! [0x%X:0x%X:0x%X:0x%X:0x%X:%i:%i:0x%X]\n", newProcess->tss.esp0, newProcess->tss.esp, newProcess->tss.ebp, esi, eip, newProcess->id, _current->id, newProcess->td.vm_daddr); + newProcess->tss.cr3 = (uInt32) vmm_copyVirtualSpace(newProcess->id); + //kprintf( "Copied Mem Space!\n" ); + + newProcess->state = FORK; + + /* Fix gcc optimization problems */ + while (tmpProcPtr->state == FORK) + sched_yield(); + /* Return Id of Proccess */ + kprintf("Returning! [%i]", _current->id); + + return (newProcess->id); +} + +void qT() { + kprintf("qT\n"); +} + +/***************************************************************************************** + Functoin: void sysFork(); + + Desc: This function will fork a new task + + Notes: + + 08/01/02 - This Seems To Be Working Fine However I'm Not Sure If I + Chose The Best Path To Impliment It I Guess We Will See + What The Future May Bring + + *****************************************************************************************/ +//asm volatile( +__asm( + ".globl sysFork_old \n" + "sysFork_old: \n" + " xor %eax,%eax \n" + " call schedNewTask \n" + " testl %eax,%eax \n" + " je fork_ret \n" + " pushl %esi \n" + " pushl %edi \n" + " pushl %ebp \n" + " pushl %eax \n" + " call fork_copyProcess \n" + " movl %eax,(%ebx) \n" + " addl $16,%esp \n" + "fork_ret: \n" + " ret \n" +); + +/*** + END + ***/ + diff --git a/sys/arch/i386/i386_exec.c b/sys/arch/i386/i386_exec.c new file mode 100644 index 0000000..6f904e9 --- /dev/null +++ b/sys/arch/i386/i386_exec.c @@ -0,0 +1,997 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENVP_PAGE 0x100 +#define ARGV_PAGE 0x100 +#define ELF_AUX 0x100 +#define STACK_PAD 0x1000 + +#define ENOEXEC -1 + +#define AT_NULL 0 /* Terminates the vector. */ +#define AT_IGNORE 1 /* Ignored entry. */ +#define AT_EXECFD 2 /* File descriptor of program to load. */ +#define AT_PHDR 3 /* Program header of program already loaded. */ +#define AT_PHENT 4 /* Size of each program header entry. */ +#define AT_PHNUM 5 /* Number of program header entries. */ +#define AT_PAGESZ 6 /* Page size in bytes. */ +#define AT_BASE 7 /* Interpreter's base address. */ +#define AT_FLAGS 8 /* Flags (unused for i386). */ +#define AT_ENTRY 9 /* Where interpreter should transfer control. */ + +#define AUXARGS_ENTRY(pos, id, val) {*pos = id;pos++; *pos = val;pos++;} + +static int argv_count(char **argv) { + int i = 0; + + while (*argv++ != 0x0) + i++; + + return (i); +} + +static int envp_count(char **envp) { + int i = 0; + + while (*envp++ != 0x0) + i++; + + return (i); +} + +static int args_copyin(char **argv_in, char **argv_out, char **args_out) { + + int argc = argv_count(argv_in); + + uint32_t *argv_tmp = (uint32_t *) kmalloc(sizeof(char *) * (argc + 2)); // + 1 For ARGC + 1 For NULL TERM + + char *args_tmp = (char *) kmalloc(ARGV_PAGE); + + argv_tmp[0] = argc; + + uint32_t sp = 0x0; + + int i = 0x0; + + for (i = 1; i <= argc; i++) { + argv_tmp[i] = (uint32_t)(args_tmp + sp); + strcpy((char *)argv_tmp[i], argv_in[i - 1]); + sp += strlen(argv_in[i - 1]) + 1; + } + + argv_tmp[i++] = 0x0; + + *argv_out = (char *)argv_tmp; + *args_out = args_tmp; + + return (0); + +} + +static int envs_copyin(char **envp_in, char **envp_out, char **envs_out) { + + int envc = envp_count(envp_in); + + uint32_t *envp_tmp = (uint32_t *) kmalloc(sizeof(char *) * (envc + 1)); // + 1 For NULL TERM + + char *envs_tmp = (char *) kmalloc(ENVP_PAGE); + + uint32_t sp = 0x0; + + int i = 0x0; + + for (i = 0; i < envc; i++) { + envp_tmp[i] = (uint32_t)(envs_tmp + sp); + strcpy((char *)envp_tmp[i], envp_in[i]); + sp += strlen(envp_in[i]) + 1; + } + envp_tmp[i++] = 0x0; + + *envp_out = (char *)envp_tmp; + *envs_out = envs_tmp; + return (0); +} + +static int elf_parse_dynamic(elf_file_t ef); + +/***************************************************************************************** + + Function: execThread(void (*)(void),int,char *); + Description: This function will create a thread from code in the current memory space + + Notes: + + 05/19/04 - This does not work the way I want it to it still makes a copy of kernel space + so do not use out side of kernel space + + *****************************************************************************************/ +uint32_t execThread(void (*tproc)(void), uint32_t stack, char *arg) { + + kTask_t * newProcess = 0x0; + uint32_t stackAddr = 0x0; + + /* Find A New Thread */ + newProcess = schedNewTask(); + assert(newProcess); + + stackAddr = vmm_getFreeKernelPage(newProcess->id, stack / PAGE_SIZE); + + /* Set All The Correct Thread Attributes */ + newProcess->tss.back_link = 0x0; + newProcess->tss.esp0 = 0x0; + newProcess->tss.ss0 = 0x0; + newProcess->tss.esp1 = 0x0; + newProcess->tss.ss1 = 0x0; + newProcess->tss.esp2 = 0x0; + newProcess->tss.ss2 = 0x0; + newProcess->tss.cr3 = (unsigned int) kernelPageDirectory; + newProcess->tss.eip = (unsigned int) tproc; + newProcess->tss.eflags = 0x206; + newProcess->tss.esp = stackAddr + (stack - 0x4); //stack; + newProcess->tss.ebp = 0x0;//stack; + newProcess->tss.esi = 0x0; + newProcess->tss.edi = 0x0; + + /* Ring 3 Selectors */ + /* + newProcess->tss.es = 0x30+3; + newProcess->tss.cs = 0x28+3; + newProcess->tss.ss = 0x30+3; + newProcess->tss.ds = 0x30+3; + newProcess->tss.fs = 0x30+3; + newProcess->tss.gs = 0x30+3; + */ + + /* Ring 0 Selectors */ + newProcess->tss.es = 0x10; + newProcess->tss.cs = 0x08; + newProcess->tss.ss = 0x10; + newProcess->tss.ds = 0x10; + newProcess->tss.fs = 0x10; + newProcess->tss.gs = 0x10; + + newProcess->tss.ldt = 0x18; + newProcess->tss.trace_bitmap = 0x0000; + newProcess->tss.io_map = 0x8000; + newProcess->oInfo.vmStart = 0x6400000; + + if (newProcess->files[0] != 0x0) + kpanic("Problem With File Descriptors"); + + newProcess->files[0] = 0x0; + + //kprintf("EIP: 0x%X(%i)", tproc, newProcess->id); + + /* Set up default stack for thread here filled with arg list 3 times */ + asm volatile( + "pusha \n" + "movl %%esp,%%ecx \n" + "movl %1,%%eax \n" + "movl %%eax,%%esp \n" + "pushl %%ebx \n" + "pushl %%ebx \n" + "pushl %%ebx \n" + "movl %%esp,%%eax \n" + "movl %%eax,%1 \n" + "movl %%ecx,%%esp \n" + "popa \n" + : + : "b" (arg),"m" (newProcess->tss.esp) + ); + + /* Put new thread into the READY state */ + sched_setStatus(newProcess->id, READY); + + /* Return with the new process ID */ + return ((uint32_t) newProcess); +} + +/***************************************************************************************** + + Function: void execFile(char *file); + Description: This Function Executes A Kile Into A New VM Space With Out + Having To Fork + Notes: + + 07/30/02 - I Have Made Some Heavy Changes To This As Well As Fixed A Few + Memory Leaks The Memory Allocated To Load The Binary Into Is + Now Unmapped So It Can Be Used Again And Not Held Onto Until + The Program Exits + + 07/30/02 - Now I Have To Make A Better Memory Allocator So We Can Set Up + The Freshly Allocated Pages With The Correct Permissions + + *****************************************************************************************/ +void execFile(char *file, char **argv, char **envp, int console) { + + kTask_t *newProcess = 0x0; + + int i = 0x0; + int x = 0x0; + + uint32_t *tmp = 0x0; + + Elf_Ehdr *binaryHeader = 0x0; + + Elf_Phdr *programHeader = 0x0; + + int argc = argv_count(argv); + int envc = envp_count(envp); + + /* Get A New Task For This Proccess */ + newProcess = schedNewTask(); + assert(newProcess); + + newProcess->gid = 0x0; + newProcess->uid = 0x0; + newProcess->pgrp = newProcess->id; + newProcess->term = tty_find(console); + + if (newProcess->term == 0x0) + kprintf("Error: invalid console\n"); + + /* Set tty ownership */ + newProcess->term->owner = newProcess->id; + + /* Now We Must Create A Virtual Space For This Proccess To Run In */ + newProcess->tss.cr3 = (uint32_t) vmm_createVirtualSpace(newProcess->id); + + /* To Better Load This Application We Will Switch Over To Its VM Space */ + asm volatile( + "movl %0,%%eax \n" + "movl %%eax,%%cr3 \n" + : : "d" ((uint32_t *)(newProcess->tss.cr3)) + ); + + /* Lets Find The File */ + if (newProcess->files[0] != 0x0) + kpanic("Problem With File Descriptors"); + newProcess->files[0] = fopen(file, "r"); + + /* If We Dont Find the File Return */ + if (newProcess->files[0] == 0x0) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + fclose(newProcess->files[0]); + return; + } + + if (newProcess->files[0]->perms == 0x0) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + fclose(newProcess->files[0]); + return; + } + + /* Load ELF Header */ + binaryHeader = (Elf_Ehdr *) kmalloc(sizeof(Elf_Ehdr)); + + fread(binaryHeader, sizeof(Elf_Ehdr), 1, newProcess->files[0]); + + /* Check If App Is A Real Application */ + if ((binaryHeader->e_ident[1] != 'E') && (binaryHeader->e_ident[2] != 'L') && (binaryHeader->e_ident[3] != 'F')) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(newProcess->files[0]); + return; + } + else if (binaryHeader->e_type != 2) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(newProcess->files[0]); + return; + } + else if (binaryHeader->e_entry == 0x300000) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(newProcess->files[0]); + return; + } + + newProcess->td.abi = binaryHeader->e_ident[EI_OSABI]; + + /* Load The Program Header(s) */ + programHeader = (Elf_Phdr *) kmalloc(sizeof(Elf_Phdr) * binaryHeader->e_phnum); + fseek(newProcess->files[0], binaryHeader->e_phoff, 0); + + fread(programHeader, (sizeof(Elf_Phdr) * binaryHeader->e_phnum), 1, newProcess->files[0]); + + /* Loop Through The Header And Load Sections Which Need To Be Loaded */ + for (i = 0; i < binaryHeader->e_phnum; i++) { + if (programHeader[i].p_type == 1) { + /* + Allocate Memory Im Going To Have To Make This Load Memory With Correct + Settings so it helps us in the future + */ + for (x = 0x0; x < (programHeader[i].p_memsz); x += 0x1000) { + /* Make readonly and read/write !!! */ + if (vmm_remapPage(vmm_findFreePage(newProcess->id), ((programHeader[i].p_vaddr & 0xFFFFF000) + x), PAGE_DEFAULT, newProcess->id, 0) == 0x0) + K_PANIC("Remap Page Failed"); + + memset((void *) ((programHeader[i].p_vaddr & 0xFFFFF000) + x), 0x0, 0x1000); + + } + + /* Now Load Section To Memory */ + fseek(newProcess->files[0], programHeader[i].p_offset, 0); + + fread((void *) programHeader[i].p_vaddr, programHeader[i].p_filesz, 1, newProcess->files[0]); + + if ((programHeader[i].p_flags & 0x2) != 0x2) { + for (x = 0x0; x < (programHeader[i].p_memsz); x += 0x1000) { + if ((vmm_setPageAttributes((programHeader[i].p_vaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) + kpanic("Error: vmm_setPageAttributes failed, File: %s, Line: %i\n", __FILE__, __LINE__); + } + } + } + } + + /* Set Virtual Memory Start */ + newProcess->oInfo.vmStart = 0x80000000; + newProcess->td.vm_daddr = (u_long) (programHeader[i].p_vaddr & 0xFFFFF000); + + /* Set Up Stack Space */ + //MrOlsen (2016-01-14) FIX: is the stack start supposed to be addressable xhcnage x= 1 to x=0 + //x = 0 because GS= stack address not address -1 fix! + for (x = 1; x <= 100; x++) { + vmm_remapPage(vmm_findFreePage(newProcess->id), (STACK_ADDR+1) - (x * PAGE_SIZE), PAGE_DEFAULT | PAGE_STACK, newProcess->id, 0); + bzero((void *)((STACK_ADDR+1) - (x * PAGE_SIZE)), PAGE_SIZE); + } + + /* Kernel Stack 0x2000 bytes long */ + + //vmm_remapPage(vmm_findFreePage(newProcess->id), 0x5BC000, KERNEL_PAGE_DEFAULT | PAGE_STACK, newProcess->id); + //vmm_remapPage(vmm_findFreePage(newProcess->id), 0x5BB000, KERNEL_PAGE_DEFAULT | PAGE_STACK, newProcess->id); + /* + for (x = 0; x < 2; x++) + vmm_remapPage(vmm_findFreePage(newProcess->id), 0xFFFFF000 - (PAGE_SIZE * x), KERNEL_PAGE_DEFAULT | PAGE_STACK, newProcess->id, 0); + */ + + /* Set All The Proper Information For The Task */ + newProcess->tss.back_link = 0x0; + newProcess->tss.esp0 = 0xFFFFFFFF; //0x5BC000; + newProcess->tss.ss0 = 0x10; + newProcess->tss.esp1 = 0x0; + newProcess->tss.ss1 = 0x0; + newProcess->tss.esp2 = 0x0; + newProcess->tss.ss2 = 0x0; + newProcess->tss.eip = (long) binaryHeader->e_entry; + newProcess->tss.eflags = 0x206; + newProcess->tss.esp = STACK_ADDR; + newProcess->tss.ebp = 0x0;//STACK_ADDR; + newProcess->tss.esi = 0x0; + newProcess->tss.edi = 0x0; + + /* Set these up to be ring 3 tasks */ + newProcess->tss.es = 0x30 + 3; + newProcess->tss.cs = 0x28 + 3; + newProcess->tss.ss = 0x30 + 3; + newProcess->tss.ds = 0x30 + 3; + newProcess->tss.fs = 0x30 + 3; + newProcess->tss.gs = 0x8 + 3 + 4;//0x50 + 3; //0x30 + 3; + + newProcess->tss.ldt = 0x18; + newProcess->tss.trace_bitmap = 0x0000; + newProcess->tss.io_map = 0x8000; + + //sched_setStatus(newProcess->id, READY); + + kfree(binaryHeader); + kfree(programHeader); + fclose(newProcess->files[0]); + newProcess->files[0] = 0x0; + + tmp = (uint32_t *) newProcess->tss.esp0 - 5; + + tmp[0] = binaryHeader->e_entry; + tmp[3] = STACK_ADDR - 12; + + newProcess->tss.esp = STACK_ADDR - ARGV_PAGE - ENVP_PAGE - ELF_AUX - (argc + 1) - (envc + 1) - STACK_PAD; + + tmp = (uint32_t *) newProcess->tss.esp; + + tmp[0] = argc; + + uint32_t sp = 0x0; + + for (i = 1; i <= argc; i++) { + tmp[i] = STACK_ADDR - ARGV_PAGE + sp; + strcpy((char *) tmp[i], argv[i - 1]); + sp += strlen(argv[i - 1]) + 1; + } + tmp[i++] = 0x0; + + sp = 0; + + for (int x = 0; x < envc; x++) { + tmp[x + i] = STACK_ADDR - ARGV_PAGE - ENVP_PAGE + sp; + strcpy((char *) tmp[x + i], envp[x]); + sp += strlen(envp[x]) + 1; + } + tmp[i + x] = 0x0; + + /* Build LDT For GS and FS */ + vmm_unmapPage(VMM_USER_LDT, 1); + + if (vmm_remapPage(vmm_findFreePage(newProcess->id), VMM_USER_LDT, PAGE_DEFAULT, newProcess->id, 0) == 0x0) { + K_PANIC("Error: Remap Page Failed"); + } + + struct gdtDescriptor *taskLDT = 0x0; + + taskLDT = (struct gdtDescriptor *)(VMM_USER_LDT + sizeof(struct gdtDescriptor)); + uint32_t data_addr = 0x0; + + taskLDT->limitLow = (0xFFFFF & 0xFFFF); + taskLDT->baseLow = (data_addr & 0xFFFF); + taskLDT->baseMed = ((data_addr >> 16) & 0xFF); + taskLDT->access = ((dData + dWrite + dBig + dBiglim + dDpl3) + dPresent) >> 8; + taskLDT->limitHigh = (0xFFFFF >> 16); + taskLDT->granularity = ((dData + dWrite + dBig + dBiglim + dDpl3) & 0xFF) >> 4; + taskLDT->baseHigh = data_addr >> 24; + + + /* Switch Back To The Kernels VM Space */ + asm volatile( + "movl %0,%%eax \n" + "movl %%eax,%%cr3 \n" + : : "d" ((uint32_t *)(kernelPageDirectory)) + ); + + sprintf(newProcess->oInfo.cwd, "/"); + + //MrOlsen 2018 kprintf("execFile Return: 0x%X - %i\n", newProcess->tss.eip, newProcess->id); + + /* Put new thread into the READY state */ + sched_setStatus(newProcess->id, READY); + + //_current = newProcess; + + /* Finally Return */ + return; +} + +int sys_exec(struct thread *td, char *file, char **argv, char **envp) { + + int i = 0x0; + int x = 0x0; + + int argc = argv_count(argv); + int envc = envp_count(envp); + + uint32_t cr3 = 0x0; + + uint32_t *tmp = 0x0; + + uInt32 seg_size = 0x0; + uInt32 seg_addr = 0x0; + + char *interp = 0x0; + uint32_t ldAddr = 0x0; + + fileDescriptor_t *fd = 0x0; + + Elf_Ehdr *binaryHeader = 0x0; + Elf_Phdr *programHeader = 0x0; + Elf_Shdr *sectionHeader = 0x0; + + elf_file_t ef = 0x0; + + u_long text_addr = 0, text_size = 0; + u_long data_addr = 0, data_size = 0; + + struct i386_frame *iFrame = 0x0; + + asm("movl %%cr3, %0;" : "=r" (cr3)); + + fd = fopen(file, "r"); + + if (fd == 0x0) { + td->td_retval[0] = 2; + return (-1); + } + + /* Test If Executable */ + if (fd->perms == 0) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + fclose(fd); + return (-1); + } + + /* Set Threads FD to open FD */ + _current->files[0] = fd; + + /* Copy In ARGS & ENVS Before Cleaning Virtual Space */ + uint32_t *argv_out = 0x0; + char *args_out = 0x0; + + args_copyin(argv, (char **)&argv_out, &args_out); + + uint32_t *envp_out = 0x0; + char *envs_out = 0x0; + + envs_copyin(envp, (char **)&envp_out, &envs_out); + + //! Clean the virtual of COW pages left over from the fork + //vmm_cleanVirtualSpace( (uint32_t) _current->td.vm_daddr + (_current->td.vm_dsize << PAGE_SHIFT) ); + //MrOlsen 2017-12-15 - FIX! - This should be done before it was causing a lot of problems why did I free space after loading binary???? + //vmm_cleanVirtualSpace((uint32_t) 0x8048000); + vmm_cleanVirtualSpace((uint32_t) VMM_USER_START); + + /* Clear Stack */ + //bzero(STACK_ADDR - (100 * PAGE_SIZE), (PAGE_SIZE * 100)); + for (x = 1; x <= 100; x++) { + vmm_remapPage(vmm_findFreePage(_current->id), (STACK_ADDR+1) - (x * 0x1000), PAGE_DEFAULT | PAGE_STACK, _current->id, 0); + bzero((void *)((STACK_ADDR+1) - (x * 0x1000)), 0x1000); + } + + /* Load ELF Header */ + if ((binaryHeader = (Elf_Ehdr *) kmalloc(sizeof(Elf_Ehdr))) == 0x0) + K_PANIC("MALLOC FAILED"); + + fread(binaryHeader, sizeof(Elf_Ehdr), 1, fd); + /* Done Loading ELF Header */ + + /* Check If App Is A Real Application */ + if ((binaryHeader->e_ident[1] != 'E') && (binaryHeader->e_ident[2] != 'L') && (binaryHeader->e_ident[3] != 'F')) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(fd); + return (-1); + } + else if (binaryHeader->e_type != ET_EXEC) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(fd); + return (-1); + } + else if (binaryHeader->e_entry == 0x300000) { + kprintf("Exec Format Error: Binary File Not Executable.\n"); + kfree(binaryHeader); + fclose(fd); + return (-1); + } + + /* Set Thread ABI */ + td->abi = binaryHeader->e_ident[EI_OSABI]; + + /* Load The Program Header(s) */ + if ((programHeader = (Elf_Phdr *) kmalloc(sizeof(Elf_Phdr) * binaryHeader->e_phnum)) == 0x0) + K_PANIC("MALLOC FAILED"); + + assert(programHeader); + + fseek(fd, binaryHeader->e_phoff, 0); + fread(programHeader, (sizeof(Elf_Phdr) * binaryHeader->e_phnum), 1, fd); + /* Done Loading Program Header(s) */ + + /* Load The Section Header(s) */ + if ((sectionHeader = (Elf_Shdr *) kmalloc(sizeof(Elf_Shdr) * binaryHeader->e_shnum)) == 0x0) + K_PANIC("MALLOC FAILED"); + + assert(sectionHeader); + fseek(fd, binaryHeader->e_shoff, 0); + fread(sectionHeader, sizeof(Elf_Shdr) * binaryHeader->e_shnum, 1, fd); + /* Done Loading Section Header(s) */ + + ef = kmalloc(sizeof(struct elf_file)); + memset(ef, 0x0, sizeof(struct elf_file)); + + /* Loop Through The Header And Load Sections Which Need To Be Loaded */ + for (i = 0; i < binaryHeader->e_phnum; i++) { + switch (programHeader[i].p_type) { + case PT_LOAD: + if (programHeader[i].p_memsz == 0x0) + break; + + seg_addr = trunc_page(programHeader[i].p_vaddr); + seg_size = round_page(programHeader[i].p_memsz + programHeader[i].p_vaddr - seg_addr); + + /* + Allocate Memory Im Going To Have To Make This Load Memory With Correct + Settings so it helps us in the future + */ + for (x = 0x0; x < (round_page(programHeader[i].p_memsz)); x += 0x1000) { + /* Make readonly and read/write !!! */ + if (vmm_remapPage(vmm_findFreePage(_current->id), ((programHeader[i].p_vaddr & 0xFFFFF000) + x), PAGE_DEFAULT, _current->id, 0) == 0x0) { + K_PANIC("Error: Remap Page Failed"); + } + else { + //MrOlsen 2018-01-15 kprintf("rP[0x%X]", (programHeader[i].p_vaddr & 0xFFFFF000) + x); + } + + memset((void *) ((programHeader[i].p_vaddr & 0xFFFFF000) + x), 0x0, 0x1000); + + } + + /* Now Load Section To Memory */ + fseek(fd, programHeader[i].p_offset, 0); + fread((void *) programHeader[i].p_vaddr, programHeader[i].p_filesz, 1, fd); + + if ((programHeader[i].p_flags & 0x2) != 0x2) { + for (x = 0x0; x < (round_page(programHeader[i].p_memsz)); x += 0x1000) { + if ((vmm_setPageAttributes((programHeader[i].p_vaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) + kpanic("Error: vmm_setPageAttributes failed, File: %s,Line: %i\n", __FILE__, __LINE__); + } + } + + if ((programHeader[i].p_flags & PF_X) && text_size < seg_size) { + //MrOlsen 2018kprintf("setting text: 0x%X - 0x%X\n", seg_addr, seg_size); + text_size = seg_size; + text_addr = seg_addr; + } + else { + //MrOlsen 2018kprintf("setting data: 0x%X - 0x%X\n", seg_addr, seg_size); + data_size = seg_size; + data_addr = seg_addr; + /* + _current->td.vm_dsize = seg_size >> PAGE_SHIFT; + _current->td.vm_daddr = (char *) seg_addr; + kprintf( "setting daddr: 0x%X, dsiize: 0x%X\n", _current->td.vm_daddr, _current->td.vm_dsize ); + */ + } + + /* + * MrOlsen (2016-01-19) NOTE: Note Sure, I should Do This Later + * Thjis is for stack space + */ + _current->oInfo.vmStart = ((programHeader[i].p_vaddr & 0xFFFFF000) + 0xA900000); + break; + case PT_DYNAMIC: + //newLoc = (char *)programHeader[i].phVaddr; + //elfDynamicS = (elfDynamic *) programHeader[i].p_vaddr; + ef->dynamic = (Elf_Dyn *) programHeader[i].p_vaddr; + //fseek( fd, programHeader[i].phOffset, 0 ); + //fread( (void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, fd ); + break; + case PT_INTERP: + #ifdef DEBUG_EXEC + kprintf("%s:%i>Malloc: %i\n", _FILE_,_LINE_,programHeader[i].p_filesz); + #endif + interp = (char *) kmalloc(programHeader[i].p_filesz); + fseek(fd, programHeader[i].p_offset, 0); + fread((void *) interp, programHeader[i].p_filesz, 1, fd); + #ifdef DEBUG_EXEC + kprintf("Interp: [%s]\n", interp); + #endif + ldAddr = ldEnable(interp); + //ef->ld_addr = ldEnable(); + break; + case PT_GNU_STACK: + asm("nop"); + break; + default: + break; + } + } + + _current->td.vm_tsize = text_size >> PAGE_SHIFT; + _current->td.vm_taddr = text_addr; + _current->td.vm_dsize = data_size >> PAGE_SHIFT; + _current->td.vm_daddr = data_addr; + + //MrOlsen 2018kprintf("Done Looping\n"); + + ef->preloaded = 1; + ef->address = 0x0; + elf_parse_dynamic(ef); + + //asm("cld"); + //irqDisable(0); + iFrame = (struct i386_frame *) (_current->tss.esp0 - sizeof(struct i386_frame)); + + //iFrame->ebp = 0x0; + + if (ldAddr != 0x0) { + iFrame->eip = ldAddr; + } + else { + iFrame->eip = binaryHeader->e_entry; + } + + //iFrame->edx = 0x0; + + iFrame->user_esp = (uint32_t) (STACK_ADDR - ARGV_PAGE - ENVP_PAGE - ELF_AUX - (argc + 1) - (envc + 1) - STACK_PAD) & 0xFFFFF000; + + tmp = (uint32_t *) iFrame->user_esp; + +// memset((char *) tmp, 0x0, ARGV_PAGE + ENVP_PAGE + ELF_AUX + (argc + 1) + (envc + 1) + STACK_PAD); + + tmp[0] = argc; + + uint32_t sp = 0x0; + + char *EXECP = 0x0; + + for (i = 1; i <= argc; i++) { + tmp[i] = (uint32_t) STACK_ADDR - ARGV_PAGE + sp; + if (i == 1) { + EXECP = (char *)tmp[i]; + } + strcpy((char *)tmp[i], (const char *)argv_out[i]); + #ifdef EXEC_DEBUG + kprintf("argv[%i]:%s",i, (const char *)argv_out[i]); + #endif + sp += strlen((const char *)argv_out[i]) + 1; + } + + tmp[i++] = 0x0; + + kfree(argv_out); + kfree(args_out); + + sp = 0; + + x = 0; + + for (x = 0; x < envc; x++) { + tmp[x + i] = (uint32_t) STACK_ADDR - ARGV_PAGE - ENVP_PAGE + sp; + strcpy((char *) tmp[x + i], (const char *)envp_out[x]); + sp += strlen((const char *)envp_out[x]) + 1; + } + + tmp[i + x] = 0x0; + + kfree(envp_out); + kfree(envs_out); + + i = i + x + 1; + + struct file *tFP = 0x0; + int tFD = 0x0; + + fseek(_current->files[0], 0x0, 0x0); // Reset File Position + falloc(&_current->td, &tFP, &tFD); + + tFP->fd = _current->files[0]; + + + tmp[i++] = 2; + tmp[i++] = -1;// tFD; // _current->imageFd; + _current->td.o_files[4] = tFP; // XXX - I had this -> _current->files[0]; not sure why changed to tFP on 2018-11-09 + //MrOlsen 2018kprintf("AT_EXECFD: [%i:%i]", tmp[i - 1], tFD); + + tmp[i++] = 3; + tmp[i++] = binaryHeader->e_phoff + 0x08048000; + //MrOlsen 2018kprintf("AT_PHDR: [0x%X]", tmp[i - 1]); + + tmp[i++] = 4; + tmp[i++] = binaryHeader->e_phentsize; + //MrOlsen 2018kprintf("AT_PHENT: [0x%X]", tmp[i - 1]); + + tmp[i++] = 5; + tmp[i++] = binaryHeader->e_phnum; + //MrOlsen 2018kprintf("AT_PHNUM: [0x%X]", tmp[i - 1]); + + tmp[i++] = 6; + tmp[i++] = 0x1000; + + tmp[i++] = 7; + tmp[i++] = LD_START; + //MrOlsen 2018kprintf("AT_BASE: [0x%X]", tmp[i - 1]); + + tmp[i++] = 8; + tmp[i++] = 0x0; + + tmp[i++] = 9; + tmp[i++] = binaryHeader->e_entry; + + tmp[i++] = 11; + tmp[i++] = 0x0; + + tmp[i++] = 12; + tmp[i++] = 0x0; + + tmp[i++] = 13; + tmp[i++] = 0x0; + + tmp[i++] = 14; + tmp[i++] = 0x0; + + tmp[i++] = 15; //EXEC PATH + tmp[i++] = (uint32_t)EXECP; + + tmp[i++] = 19; //NCPUS + tmp[i++] = 0x1; + + tmp[i++] = 23; //STACKPROT + tmp[i++] = 0x3; + + tmp[i++] = 0; + tmp[i++] = 0; + + /* Now That We Relocated The Binary We Can Unmap And Free Header Info */ + kfree(binaryHeader); + kfree(programHeader); + //irqEnable(0); + //asm("sti"); + + /* + _current->tss.es = 0x30 + 3; + _current->tss.cs = 0x28 + 3; + _current->tss.ss = 0x30 + 3; + _current->tss.ds = 0x30 + 3; + _current->tss.fs = 0x30 + 3; + _current->tss.gs = 0x50 + 3; //0x30 + 3; + + _current->tss.ldt = 0x18; + _current->tss.trace_bitmap = 0x0000; + _current->tss.io_map = 0x8000; + */ + + /* + kfree (iFrameNew); + + memAddr = (uint32_t) & (_current->tss); + ubixGDT[4].descriptor.baseLow = (memAddr & 0xFFFF); + ubixGDT[4].descriptor.baseMed = ((memAddr >> 16) & 0xFF); + ubixGDT[4].descriptor.baseHigh = (memAddr >> 24); + ubixGDT[4].descriptor.access = '\x89'; + + ubixGDT[10].descriptor.baseLow = (STACK_ADDR & 0xFFFF); + ubixGDT[10].descriptor.baseMed = ((STACK_ADDR >> 16) & 0xFF); + ubixGDT[10].descriptor.baseHigh = (STACK_ADDR >> 24); + + */ + + /* Build LDT For GS and FS */ + vmm_unmapPage(VMM_USER_LDT, 1); // Can I Free This? + if (vmm_remapPage(vmm_findFreePage(_current->id), VMM_USER_LDT, PAGE_DEFAULT, _current->id, 0) == 0x0) { + K_PANIC("Error: Remap Page Failed"); + } + + struct gdtDescriptor *taskLDT = 0x0; + + taskLDT = (struct gdtDescriptor *)(VMM_USER_LDT + sizeof(struct gdtDescriptor)); + + //data_addr = 0x0; //TEMP + + taskLDT->limitLow = (0xFFFFF & 0xFFFF); + taskLDT->baseLow = (data_addr & 0xFFFF); + taskLDT->baseMed = ((data_addr >> 16) & 0xFF); + taskLDT->access = ((dData + dWrite + dBig + dBiglim + dDpl3) + dPresent) >> 8; + taskLDT->limitHigh = (0xFFFFF >> 16); + taskLDT->granularity = ((dData + dWrite + dBig + dBiglim + dDpl3) & 0xFF) >> 4; + taskLDT->baseHigh = data_addr >> 24; + + _current->tss.gs = 0xF; //Select 0x8 + Ring 3 + LDT + _current->pgrp = _current->id; + + return (0x0); +} + +static int elf_parse_dynamic(elf_file_t ef) { + Elf32_Dyn *dynp; + int plttype = DT_REL; + + for (dynp = ef->dynamic; dynp->d_tag != 0x0; dynp++) { + switch (dynp->d_tag) { + case DT_NEEDED: + asm("nop"); + break; + case DT_INIT: + asm("nop"); + break; + case DT_FINI: + asm("nop"); + break; + case DT_HASH: + asm("nop"); + /* From src/libexec/rtld-elf/rtld.c */ + const Elf_Hashelt *hashtab = (const Elf_Hashelt *) (ef->address + dynp->d_un.d_ptr); + ef->nbuckets = hashtab[0]; + ef->nchains = hashtab[1]; + ef->buckets = hashtab + 2; + ef->chains = ef->buckets + ef->nbuckets; + break; + case DT_STRTAB: + ef->strtab = (caddr_t) (ef->address + dynp->d_un.d_ptr); + break; + case DT_STRSZ: + ef->strsz = dynp->d_un.d_val; + break; + case DT_SYMTAB: + ef->symtab = (Elf_Sym *) (ef->address + dynp->d_un.d_ptr); + break; + case DT_SYMENT: + if (dynp->d_un.d_val != sizeof(Elf32_Sym)) + return (ENOEXEC); + break; + case DT_REL: + ef->rel = (const Elf_Rel *) (ef->address + dynp->d_un.d_ptr); + break; + case DT_RELSZ: + ef->relsize = dynp->d_un.d_val; + break; + case DT_RELENT: + if (dynp->d_un.d_val != sizeof(Elf_Rel)) + return (ENOEXEC); + break; + case DT_JMPREL: + ef->pltrel = (const Elf_Rel *) (ef->address + dynp->d_un.d_ptr); + break; + case DT_PLTRELSZ: + ef->pltrelsize = dynp->d_un.d_val; + break; + case DT_RELA: + ef->rela = (const Elf_Rela *) (ef->address + dynp->d_un.d_ptr); + break; + case DT_RELASZ: + ef->relasize = dynp->d_un.d_val; + break; + case DT_RELAENT: + if (dynp->d_un.d_val != sizeof(Elf_Rela)) + return (ENOEXEC); + break; + case DT_PLTREL: + plttype = dynp->d_un.d_val; + if (plttype != DT_REL && plttype != DT_RELA) + return (ENOEXEC); + break; + case DT_PLTGOT: + ef->got = (Elf_Addr *) (ef->address + dynp->d_un.d_ptr); + /* + tmp = (void *) dynp->d_un.d_ptr; //elfDynamicS[i].dynPtr; + tmp[2] = (uInt32) ef->ld_addr; + tmp[1] = (uInt32) ef; //0x0;//0xBEEFEAD;//STACK_ADDR - 128;//_current->imageFd;//0xBEEFDEAD;//ef; + */ + break; + default: + asm("nop"); + //kprintf("t_tag: 0x%X>", dynp->d_tag); + break; + } + } + + if (plttype == DT_RELA) { + ef->pltrela = (const Elf_Rela *) ef->pltrel; + ef->pltrel = NULL; + ef->pltrelasize = ef->pltrelsize; + ef->pltrelsize = 0; + } + + ef->ddbsymtab = ef->symtab; + ef->ddbsymcnt = ef->nchains; + ef->ddbstrtab = ef->strtab; + ef->ddbstrcnt = ef->strsz; + return (0); +} diff --git a/sys/arch/i386/kpanic.c b/sys/arch/i386/kpanic.c new file mode 100644 index 0000000..b0824b4 --- /dev/null +++ b/sys/arch/i386/kpanic.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +/*! + * \brief print panic message and halt system + * + * \param fmt panic message + * + */ +void kpanic(const char *fmt, ...) { + char buf[512]; + va_list args; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + /* It's important that we print on the current terminal so let's reset foreground */ + tty_foreground = NULL; + kprintf("kPanic: %s", buf); + + /* Halt The System */ + //asm("cli"); + irqDisable(0x0); + + while (1) { + asm("hlt"); + } + +} + +/*** + END + ***/ + diff --git a/sys/arch/i386/memcmp.S b/sys/arch/i386/memcmp.S new file mode 100644 index 0000000..c8e68c2 --- /dev/null +++ b/sys/arch/i386/memcmp.S @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include + +ENTRY(memcmp) + pushl %edi + pushl %esi + movl 12(%esp),%edi + movl 16(%esp),%esi + cld /* set compare direction forward */ + + movl 20(%esp),%ecx /* compare by words */ + shrl $2,%ecx + repe + cmpsl + jne L5 /* do we match so far? */ + + movl 20(%esp),%ecx /* compare remainder by bytes */ + andl $3,%ecx + repe + cmpsb + jne L6 /* do we match? */ + + xorl %eax,%eax /* we match, return zero */ + popl %esi + popl %edi + ret + +L5: movl $4,%ecx /* We know that one of the next */ + subl %ecx,%edi /* four pairs of bytes do not */ + subl %ecx,%esi /* match. */ + repe + cmpsb +L6: movzbl -1(%edi),%eax /* Perform unsigned comparison */ + movzbl -1(%esi),%edx + subl %edx,%eax + popl %esi + popl %edi + ret +END(memcmp) diff --git a/sys/arch/i386/memset.S b/sys/arch/i386/memset.S new file mode 100644 index 0000000..03bef8d --- /dev/null +++ b/sys/arch/i386/memset.S @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include + + +ENTRY(memset) + pushl %edi + pushl %ebx + movl 12(%esp),%edi + movzbl 16(%esp),%eax /* unsigned char, zero extend */ + movl 20(%esp),%ecx + pushl %edi /* push address of buffer */ + + cld /* set fill direction forward */ + + /* + * if the string is too short, it's really not worth the overhead + * of aligning to word boundries, etc. So we jump to a plain + * unaligned set. + */ + cmpl $0x0f,%ecx + jle L1 + + movb %al,%ah /* copy char to all bytes in word */ + movl %eax,%edx + sall $16,%eax + orl %edx,%eax + + movl %edi,%edx /* compute misalignment */ + negl %edx + andl $3,%edx + movl %ecx,%ebx + subl %edx,%ebx + + movl %edx,%ecx /* set until word aligned */ + rep + stosb + + movl %ebx,%ecx + shrl $2,%ecx /* set by words */ + rep + stosl + + movl %ebx,%ecx /* set remainder by bytes */ + andl $3,%ecx +L1: rep + stosb + + popl %eax /* pop address of buffer */ + popl %ebx + popl %edi + ret +END(memset) diff --git a/sys/arch/i386/sched.c b/sys/arch/i386/sched.c new file mode 100644 index 0000000..a8328c6 --- /dev/null +++ b/sys/arch/i386/sched.c @@ -0,0 +1,388 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static kTask_t *taskList = 0x0; +static kTask_t *delList = 0x0; +static uint32_t nextID = 1; + +kTask_t *_current = 0x0; +kTask_t *_usedMath = 0x0; + +static struct spinLock schedulerSpinLock = SPIN_LOCK_INITIALIZER; + +int need_resched = 0; + +/************************************************************************ + + Function: int sched_init() + + Description: This function is used to enable the kernel scheduler + + Notes: + + 02/20/2004 - Approved for quality + + ************************************************************************/ + +int sched_init() { + taskList = (kTask_t *) kmalloc(sizeof(kTask_t)); + if (taskList == 0x0) + kpanic("Unable to create task list"); + + taskList->id = nextID++; + + /* Print out information on scheduler */ + kprintf("sched0 - Address: [0x%X]\n", taskList); + + /* Return so we know everything went well */ + return (0x0); +} + +void sched() { + uint32_t memAddr = 0x0; + kTask_t *tmpTask = 0x0; + kTask_t *delTask = 0x0; + + if (spinTryLock(&schedulerSpinLock)) + return; + + tmpTask = ((_current == 0) ? 0 : _current->next); + schedStart: + + /* Yield the next task from the current prio queue */ + for (; tmpTask != 0x0; tmpTask = tmpTask->next) { + if (tmpTask->state == FORK) + tmpTask->state = READY; + + if (tmpTask->state == READY) { + _current->state = (_current->state == DEAD) ? DEAD : READY; + _current = tmpTask; + break; + } + else if (tmpTask->state == DEAD) { + delTask = tmpTask; + if (delTask->parent != 0x0) { + delTask->parent->children -= 1; + delTask->parent->last_exit = delTask->id; + delTask->parent->state = READY; + } + + tmpTask = tmpTask->next; + sched_deleteTask(delTask->id); + sched_addDelTask(delTask); + goto schedStart; + } + } + + /* Finished all the tasks, restarting the list */ + if (0x0 == tmpTask) { + tmpTask = taskList; + goto schedStart; + } + + if (_current->state == READY || _current->state == RUNNING) { + + if (_current->oInfo.v86Task == 0x1) { + irqDisable(0x0); + kprintf("IRQD(%i): 0x%X*0x%X:0x%X@, esp: 0x%X:0x%X, ebp: 0x%X:0x%X ds: 0x%X", _current->id, _current->tss.eflags, _current->tss.cs, _current->tss.eip, _current->tss.ss, _current->tss.esp, _current->tss.ss, _current->tss.ebp,_current->tss.ds); + kprintf("ss0: 0x%X, esp0: 0x%X", _current->tss.ss0, _current->tss.esp0); + } + + asm("cli"); + + memAddr = (uint32_t) &(_current->tss); + ubixGDT[4].descriptor.baseLow = (memAddr & 0xFFFF); + ubixGDT[4].descriptor.baseMed = ((memAddr >> 16) & 0xFF); + ubixGDT[4].descriptor.baseHigh = (memAddr >> 24); + ubixGDT[4].descriptor.access = '\x89'; + + _current->state = RUNNING; + + spinUnlock(&schedulerSpinLock); + + asm("sti"); + asm("ljmp $0x20,$0"); + } + else { + spinUnlock(&schedulerSpinLock); + } + + return; +} + +kTask_t *schedNewTask() { + int i = 0; + + kTask_t *tmpTask = (kTask_t *) kmalloc(sizeof(kTask_t)); + + struct file *fp = 0x0; + + if (tmpTask == 0x0) + kpanic("Error: schedNewTask() - kmalloc failed trying to initialize a new task struct\n"); + + memset(tmpTask, 0x0, sizeof(kTask_t)); + + /* Filling in tasks attrs */ + tmpTask->usedMath = 0x0; + tmpTask->state = NEW; + + memcpy(tmpTask->username, "UbixOS", 6); + + /* HACK */ + + for (i = 0; i < 3; i++) { + fp = (void *) kmalloc(sizeof(struct file)); + //kprintf("DB: [0x%X]\n", (uint32_t) fp); + tmpTask->td.o_files[i] = (void *) fp; + fp->f_flag = 0x4; + } + + spinLock(&schedulerSpinLock); + tmpTask->id = nextID++; + tmpTask->next = taskList; + tmpTask->prev = 0x0; + taskList->prev = tmpTask; + taskList = tmpTask; + + spinUnlock(&schedulerSpinLock); + + return (tmpTask); +} + +int sched_deleteTask(pidType id) { + kTask_t *tmpTask = 0x0; + + /* Checking each task from the prio queue */ + for (tmpTask = taskList; tmpTask != 0x0; tmpTask = tmpTask->next) { + if (tmpTask->id == id) { + if (tmpTask->prev != 0x0) + tmpTask->prev->next = tmpTask->next; + if (tmpTask->next != 0x0) + tmpTask->next->prev = tmpTask->prev; + if (taskList == tmpTask) + taskList = tmpTask->next; + + return (0x0); + } + } + return (0x1); +} + +int sched_addDelTask(kTask_t *tmpTask) { + tmpTask->next = delList; + tmpTask->prev = 0x0; + if (delList != 0x0) + delList->prev = tmpTask; + delList = tmpTask; + return (0x0); +} + +kTask_t *sched_getDelTask() { + kTask_t *tmpTask = 0x0; + + if (delList == 0x0) + return (0x0); + + tmpTask = delList; + delList = delList->next; + return (tmpTask); +} + +kTask_t *schedFindTask(uint32_t id) { + kTask_t *tmpTask = 0x0; + + for (tmpTask = taskList; tmpTask; tmpTask = tmpTask->next) { + if (tmpTask->id == id) + return (tmpTask); + } + + return (0x0); +} + +/************************************************************************ + + Function: void schedEndTask() + + Description: This function will end a task + + Notes: + + 02/20/2004 - Approved for quality + + ************************************************************************/ +void schedEndTask(pidType pid) { + endTask(_current->id); + sched_yield(); +} + +/************************************************************************ + + Function: int schedEndTask() + + Description: This function will yield a task + + Notes: + + 02/20/2004 - Approved for quality + + ************************************************************************/ + +void sched_yield() { + sched(); +} + +/* + asm( + ".globl sched_yield \n" + "sched_yield: \n" + " cli \n" + " call sched \n" + ); + */ + +/************************************************************************ + + Function: int sched_setStatus(pidType pid,tState state) + + Description: Change the tasks status + + Notes: + + ************************************************************************/ +int sched_setStatus(pidType pid, tState state) { + kTask_t *tmpTask = schedFindTask(pid); + if (tmpTask == 0x0) + return (0x1); + tmpTask->state = state; + return (0x0); +} + +void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait) { + unsigned long flags; + + save_flags(flags); + cli(); + if (!*p) { + wait->next = wait; + *p = wait; + } + else { + wait->next = (*p)->next; + (*p)->next = wait; + } + restore_flags(flags); +} + +void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait) { + unsigned long flags; + struct wait_queue * tmp; + + save_flags(flags); + cli(); + if ((*p == wait) && ((*p = wait->next) == wait)) { + *p = NULL; + } + else { + tmp = wait; + while (tmp->next != wait) { + tmp = tmp->next; + } + tmp->next = wait->next; + } + wait->next = NULL; + restore_flags(flags); +} + +void wake_up_interruptible(struct wait_queue **q) { + struct wait_queue *tmp; + kTask_t *p; + + if (!q || !(tmp = *q)) + return; + do { + if ((p = tmp->task) != NULL) { + if (p->state == INTERRUPTIBLE) { + p->state = RUNNING; + if (p->counter > _current->counter) + need_resched = 1; + } + } + if (!tmp->next) { + kprintf("wait_queue is bad (eip = %08lx)\n", ((unsigned long *) q)[-1]); + kprintf(" q = %p\n", q); + kprintf(" *q = %p\n", *q); + kprintf(" tmp = %p\n", tmp); + break; + } + tmp = tmp->next; + } while (tmp != *q); +} + +void wake_up(struct wait_queue **q) { + struct wait_queue *tmp; + kTask_t * p; + + if (!q || !(tmp = *q)) + return; + do { + if ((p = tmp->task) != NULL) { + if ((p->state == UNINTERRUPTIBLE) || (p->state == INTERRUPTIBLE)) { + p->state = RUNNING; + if (p->counter > _current->counter) + need_resched = 1; + } + } + if (!tmp->next) { + kprintf("wait_queue is bad (eip = %08lx)\n", ((unsigned long *) q)[-1]); + kprintf(" q = %p\n", q); + kprintf(" *q = %p\n", *q); + kprintf(" tmp = %p\n", tmp); + break; + } + tmp = tmp->next; + } while (tmp != *q); +} diff --git a/sys/arch/i386/schedyield.S b/sys/arch/i386/schedyield.S new file mode 100644 index 0000000..1072793 --- /dev/null +++ b/sys/arch/i386/schedyield.S @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.globl sched_yield_new +.text +.code32 +sched_yield_new: + pusha /* Save all of the registers */ + push %ss + push %ds + push %es + push %fs + push %gs + call sched + mov %eax,%esp + pop %gs + pop %fs + pop %es + pop %ds + pop %ss + popa /* Restore Registers */ + iret + +/*** + END + ***/ diff --git a/sys/arch/i386/spinlock.c b/sys/arch/i386/spinlock.c new file mode 100644 index 0000000..d713cb9 --- /dev/null +++ b/sys/arch/i386/spinlock.c @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#define atomic_xadd(P, V) __sync_fetch_and_add((P), (V)) +#define cmpxchg(P, O, N) __sync_val_compare_and_swap((P), (O), (N)) +#define atomic_inc(P) __sync_add_and_fetch((P), 1) +#define atomic_dec(P) __sync_add_and_fetch((P), -1) +#define atomic_add(P, V) __sync_add_and_fetch((P), (V)) +#define atomic_set_bit(P, V) __sync_or_and_fetch((P), 1<<(V)) +#define atomic_clear_bit(P, V) __sync_and_and_fetch((P), ~(1<<(V))) + +#define barrier() asm volatile("": : :"memory") + +/* Pause instruction to prevent excess processor bus usage */ +#define cpu_relax() asm volatile("pause\n": : :"memory") + +void spinLockInit(spinLock_t lock) { + memset(lock, 0x0, sizeof(struct spinLock)); +} + +int spinTryLock(spinLock_t lock) { + if (!cmpxchg(&lock->locked, NULL, LLOCK_FLAG)) + return 0; + + /* Failure! */ + return LOCKED; +} + +void spinUnlock(spinLock_t lock) { + barrier(); + lock->locked = 0x0; +} + +void spinLock(spinLock_t lock) { + while (1) { + if (!xchg_32(&lock->locked, LOCKED)) + return; + while (lock->locked == 1) + sched_yield(); + } +} + diff --git a/sys/arch/i386/strcmp.S b/sys/arch/i386/strcmp.S new file mode 100644 index 0000000..19bb2ff --- /dev/null +++ b/sys/arch/i386/strcmp.S @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include + +ENTRY(strcmp) + movl 0x04(%esp),%eax + movl 0x08(%esp),%edx + jmp L2 /* Jump into the loop! */ + + .align 2,0x90 +L1: incl %eax + incl %edx +L2: movb (%eax),%cl + testb %cl,%cl + je L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + je L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + je L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + je L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + je L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + je L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + je L3 + cmpb %cl,(%edx) + jne L3 + incl %eax + incl %edx + movb (%eax),%cl + testb %cl,%cl + je L3 + cmpb %cl,(%edx) + je L1 + .align 2, 0x90 +L3: movzbl (%eax),%eax /* unsigned comparison */ + movzbl (%edx),%edx + subl %edx,%eax + ret +END(strcmp) diff --git a/sys/arch/i386/strcpy.S b/sys/arch/i386/strcpy.S new file mode 100644 index 0000000..e6f6a0c --- /dev/null +++ b/sys/arch/i386/strcpy.S @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include + + ENTRY(strcpy) + movl 4(%esp),%ecx /* dst address */ + movl 8(%esp),%edx /* src address */ + pushl %ecx /* push dst address */ + + .align 2,0x90 +L1: movb (%edx),%al /* unroll loop, but not too much */ + movb %al,(%ecx) + testb %al,%al + je L2 + movb 1(%edx),%al + movb %al,1(%ecx) + testb %al,%al + je L2 + movb 2(%edx),%al + movb %al,2(%ecx) + testb %al,%al + je L2 + movb 3(%edx),%al + movb %al,3(%ecx) + testb %al,%al + je L2 + movb 4(%edx),%al + movb %al,4(%ecx) + testb %al,%al + je L2 + movb 5(%edx),%al + movb %al,5(%ecx) + testb %al,%al + je L2 + movb 6(%edx),%al + movb %al,6(%ecx) + testb %al,%al + je L2 + movb 7(%edx),%al + movb %al,7(%ecx) + addl $8,%edx + addl $8,%ecx + testb %al,%al + jne L1 +L2: popl %eax /* pop dst address */ + ret +END(strcpy) diff --git a/sys/arch/i386/strncmp.S b/sys/arch/i386/strncmp.S new file mode 100644 index 0000000..9696281 --- /dev/null +++ b/sys/arch/i386/strncmp.S @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include + +ENTRY(strncmp) + pushl %ebx + movl 8(%esp),%eax + movl 12(%esp),%ecx + movl 16(%esp),%edx + testl %edx,%edx + jmp L2 /* Jump into the loop! */ + + .align 2,0x90 +L1: incl %eax + incl %ecx + decl %edx +L2: jz L4 /* strings are equal */ + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + jne L3 + + incl %eax + incl %ecx + decl %edx + jz L4 + movb (%eax),%bl + testb %bl,%bl + jz L3 + cmpb %bl,(%ecx) + je L1 + + .align 2,0x90 +L3: movzbl (%eax),%eax /* unsigned comparison */ + movzbl (%ecx),%ecx + subl %ecx,%eax + popl %ebx + ret + .align 2,0x90 +L4: xorl %eax,%eax + popl %ebx + ret +END(strncmp) diff --git a/sys/arch/i386/support.S b/sys/arch/i386/support.S new file mode 100644 index 0000000..347cdf8 --- /dev/null +++ b/sys/arch/i386/support.S @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include +.text + +// void bzero(void *buf, u_int len) +ENTRY(bzero) + pushl %edi + movl 8(%esp),%edi + movl 12(%esp),%ecx + xorl %eax,%eax + shrl $2,%ecx + cld + rep + stosl + movl 12(%esp),%ecx + andl $3,%ecx + rep + stosb + popl %edi + ret +END(bzero) + +// bcopy(src, dst, cnt) +ENTRY(bcopy) + pushl %ebp + movl %esp,%ebp + pushl %esi + pushl %edi + movl 8(%ebp),%esi + movl 12(%ebp),%edi + movl 16(%ebp),%ecx + + movl %edi,%eax + subl %esi,%eax + cmpl %ecx,%eax /* overlapping && src < dst? */ + jb 1f + + shrl $2,%ecx /* copy by 32-bit words */ + cld /* nope, copy forwards */ + rep + movsl + movl 16(%ebp),%ecx + andl $3,%ecx /* any bytes left? */ + rep + movsb + popl %edi + popl %esi + popl %ebp + ret + + ALIGN_TEXT +1: + addl %ecx,%edi /* copy backwards */ + addl %ecx,%esi + decl %edi + decl %esi + andl $3,%ecx /* any fractional bytes? */ + std + rep + movsb + movl 16(%ebp),%ecx /* copy remainder by 32-bit words */ + shrl $2,%ecx + subl $3,%esi + subl $3,%edi + rep + movsl + popl %edi + popl %esi + cld + popl %ebp + ret +END(bcopy) + +// void *memcpy(const void *dst, const void * src, size_t length) +ENTRY(memcpy) + pushl %edi + pushl %esi + movl 12(%esp),%edi + movl 16(%esp),%esi + movl 20(%esp),%ecx + movl %edi,%eax + shrl $2,%ecx /* copy by 32-bit words */ + cld /* nope, copy forwards */ + rep + movsl + movl 20(%esp),%ecx + andl $3,%ecx /* any bytes left? */ + rep + movsb + popl %esi + popl %edi + ret +END(memcpy) diff --git a/sys/arch/i386/sys_call.S b/sys/arch/i386/sys_call.S new file mode 100644 index 0000000..7844128 --- /dev/null +++ b/sys/arch/i386/sys_call.S @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.globl _sys_call +.text +.code32 + +_B4: +_B3: +nop + +_ast: + +_astRet: + +_sysCall_MrOlsen: +//MrOlsen 2018-01-14 push $0x2 +//MrOlsen 2018-01-14 sub $0x4,%esp +pusha +push %ds +push %es +push %fs +push %gs +mov $0x10,%eax +mov %eax,%ds +mov %eax,%es +mov %eax,%fs +cld +push %esp +call sys_call +add $0x4,%esp +cmpb $0x13,0x38(%esp) +je _B4 +testl $0x2000,0x3c(%esp) /* Test If VM */ +jz _notVM +jmp _isVM +_notVM: +testb $0x3,0x38(%esp) /* See If We're In User CS (GDT Entry 5) */ +jz _popFS +jmp _popFS /* TMP BECAUSE ABOVE ISN'T RIGHT */ +cli +mov %fs:0x0,%eax +testl $0x10800,0x80(%eax) /* Document This */ +je _popFS +sti +push %esp +call _ast +add $0x4,%esp +jmp _astRet +_isVM: +hlt + +_popFS: +pop %gs +pop %fs +pop %es +pop %ds +popa +//MrOlsen 2018-01-14 add $0x8,%esp +iret + +_sys_call: +push $0x0 +push $0x80 +pusha +push %ds +push %es +push %fs +push %gs +mov $0x10,%eax +mov %eax, %ds +mov %eax, %es +mov %eax, %fs +cld +push %esp +call sys_call +add $0x4,%esp /* Remove Stack Pointer From Stack */ +pop %gs +pop %fs +pop %es +pop %ds +popa +add $0x8,%esp //Back Out Error Code & trap_no +iret diff --git a/sys/arch/i386/sys_call_posix.S b/sys/arch/i386/sys_call_posix.S new file mode 100644 index 0000000..d9b082f --- /dev/null +++ b/sys/arch/i386/sys_call_posix.S @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define FAKE_MCOUNT(caller) pushl caller ; call __mcount ; popl %ecx + +.globl _sys_call_posix +.text +.code32 + +_sys_call_posix: +push $0x0 +push $0x80 +pusha +push %ds +push %es +push %fs +push %gs +mov $0x10,%eax +mov %eax, %ds +mov %eax, %es +mov %eax, %fs +cld +push %esp +call sys_call_posix +add $0x4,%esp /* Remove Stack Pointer From Stack */ +pop %gs +pop %fs +pop %es +pop %ds +popa +add $0x8,%esp //Back Out Error Code & trap_no +iret diff --git a/sys/arch/i386/systemtask.c b/sys/arch/i386/systemtask.c new file mode 100644 index 0000000..952fc06 --- /dev/null +++ b/sys/arch/i386/systemtask.c @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned char *videoBuffer = (unsigned char *) 0xB8000; + +void systemTask() { + + mpi_message_t myMsg; + uint32_t counter = 0x0; + int i = 0x0; + int *x = 0x0; + kTask_t *tmpTask = 0x0; + + char buf[16] = { "a\n" }; + + if (mpi_createMbox("system") != 0x0) { + kpanic("Error: Error creating mailbox: system\n"); + } + + while (1) { + if (mpi_fetchMessage("system", &myMsg) == 0x0) { + switch (myMsg.header) { + case 0x69: + x = (int *) &myMsg.data; + kprintf("Switching to term: [%i][%i]\n", *x, myMsg.pid); + schedFindTask(myMsg.pid)->term = tty_find(*x); + break; + case 1000: + kprintf("Restarting the system in 5 seconds\n"); + counter = systemVitals->sysUptime + 5; + while (systemVitals->sysUptime < counter) { + sched_yield(); + } + kprintf("Rebooting NOW!!!\n"); + while (inportByte(0x64) & 0x02) + ; + outportByte(0x64, 0xFE); + break; + case 31337: + kprintf("system: backdoor opened\n"); + break; + case 0x80: + if (!strcmp(myMsg.data, "sdeStart")) { + kprintf("Starting SDE\n"); + execThread(sdeThread,0x2000,0x0); + } + else if (!strcmp(myMsg.data, "freePage")) { + kprintf("kkk Free Pages"); + } + else if (!strcmp(myMsg.data, "sdeStop")) { + printOff = 0x0; + biosCall(0x10, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0); + for (i = 0x0; i < 100; i++) + asm("hlt"); + } + break; + default: + kprintf("system: Received message %i:%s\n", myMsg.header, myMsg.data); + break; + } + } + + /* + Here we get the next task from the delete task queue + we first check to see if it has an fd attached for the binary and after that + we free the pages for the process and then free the task + */ + tmpTask = sched_getDelTask(); + + if (tmpTask != 0x0) { + if (tmpTask->files[0] != 0x0) + fclose(tmpTask->files[0]); + vmm_freeProcessPages(tmpTask->id); + kfree(tmpTask); + + } + + if (ogprintOff == 1) { + videoBuffer[0] = systemVitals->sysTicks; + videoBuffer[1] = 'c'; + } + /* + else + ogPrintf(buf); + */ + + sched_yield(); + } + + return; +} diff --git a/sys/arch/i386/timer.S b/sys/arch/i386/timer.S new file mode 100644 index 0000000..1ddfcc1 --- /dev/null +++ b/sys/arch/i386/timer.S @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +.globl timerInt +.text +.code32 +timerInt: + pusha /* Save all of the registers */ + mov $0x20,%dx /* The Following Sends Our EOI To The MPIC */ + mov $0x20,%ax + outb %al,%dx + movl systemVitals,%ecx /* Put Location Of System Vitals Into ECX */ + incl (%ecx) /* Increment sysTicks our 1000ms counter */ + movl (%ecx),%eax /* Increment our sysUptime by 1S if 1000MS */ + movl $200,%ebx /* Have Passed */ + xor %edx,%edx + div %ebx + test %edx,%edx + jnz next + incl 4(%ecx) +next: + movl (%ecx),%eax /* Test If quantum Has Passed If So Then */ + movl 8(%ecx),%ebx /* We Can CALL sched */ + xor %edx,%edx + div %ebx + test %edx,%edx + jnz done +/* +push %ds +push %es +push %fs +push %gs +mov $0x10,%eax +mov %eax, %ds +mov %eax, %es +mov %eax, %fs +cld +*/ +/* push %esp */ + call sched +/* add $0x4,%esp */ /* Remove Stack Pointer From Stack */ +/* +pop %gs +pop %fs +pop %es +pop %ds +*/ +done: + popa /* Restore Registers */ + iret diff --git a/sys/arch/i386/trap.c b/sys/arch/i386/trap.c new file mode 100644 index 0000000..de1a2c4 --- /dev/null +++ b/sys/arch/i386/trap.c @@ -0,0 +1,134 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define FIRST_TSS_ENTRY 6 +#define VM_MASK 0x00020000 + +#define store_TR(n) \ + __asm__("str %%ax\n\t" \ + "subl %2,%%eax\n\t" \ + "shrl $4,%%eax" \ + :"=a" (n) \ + :"0" (0),"i" (FIRST_TSS_ENTRY<<3)) + +#define get_seg_long(seg,addr) ({ \ + register unsigned long __res; \ + __asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ + __res;}) + +#define get_seg_byte(seg,addr) ({ \ +register char __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +void die_if_kernel(char *str, struct trapframe *regs, long err) { + int i; + unsigned long esp; + unsigned short ss; + unsigned long *stack; + + esp = (unsigned long) ®s->tf_esp; + + ss = 0x10; //KERNEL_DS + + //if ((regs->tf_eflags & VM_MASK) || (3 & regs->tf_cs) == 3) + // return; + + if ((regs->tf_cs & 3) == 3) { + esp = regs->tf_esp; + ss = regs->tf_ss; + kprintf("USER TASK!"); + } + else { + ss = 0x10; + } + + kprintf("\n%s: 0x%X:%i, CPU %d, EIP: 0x%X, EFLAGS: 0x%X\n", str, regs->tf_err, regs->tf_trapno, 0x0, regs->tf_eip, regs->tf_eflags); + kprintf("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->tf_eax, regs->tf_ebx, regs->tf_ecx, regs->tf_edx); + kprintf("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", regs->tf_esi, regs->tf_edi, regs->tf_ebp, esp); + kprintf("cs: 0x%X ds: 0x%X es: 0x%X fs: 0x%X gs: 0x%X ss: 0x%X\n", regs->tf_cs, regs->tf_ds, regs->tf_es, regs->tf_fs, regs->tf_gs, ss); + kprintf("cr0: 0x%X, cr2: 0x%X, cr3: 0x%X, cr4: 0x%X\n", rcr0(), rcr2(), rcr3(), rcr4()); + + store_TR(i); + kprintf("Process %s (pid: %i, process nr: %d, stackpage=%08lx)\nStack:", _current->name, _current->id, 0xffff & i, esp); + + stack = (unsigned long *) esp; + + for (i = 0; i < 16; i++) { + if (i && ((i % 8) == 0)) + kprintf("\n "); + kprintf("%08lx ", get_seg_long(ss, stack++)); + } + + endTask(_current->id); +} + +void trap(struct trapframe *frame) { + u_int trap_code; + u_int cr2 = 0; + + trap_code = frame->tf_trapno; + + cr2 = rcr2(); + kprintf("CR2: 0x%X(0x%X)[0x%X]", cr2, _current->tss.eip, _current->tss.ldt); + if (_current->id == 7) + while (1) + asm("nop"); + + if ((frame->tf_eflags & PSL_I) == 0) { + if (SEL_GET_PL(frame->tf_cs) == SEL_PL_USER || (frame->tf_eflags & PSL_VM)) { + kpanic("INT OFF! USER"); + die_if_kernel("TEST", frame, 0x100); + } + else { + kpanic("INT OFF! KERN[0x%X]", trap_code); + die_if_kernel("TEST", frame, 0x200); + } + } + + kprintf("trap_code: %i(0x%X), EIP: 0x%X, CR2: 0x%X\n", frame->tf_trapno, frame->tf_trapno, frame->tf_eip, cr2); + if (frame->tf_trapno == 0xc) { + vmm_pageFault(frame, cr2); + } + else { + kpanic("TRAPCODE"); + die_if_kernel("trapCode", frame, frame->tf_trapno); + endTask(_current->id); + sched_yield(); + } +} diff --git a/sys/armv6/Makefile b/sys/armv6/Makefile deleted file mode 100644 index de38484..0000000 --- a/sys/armv6/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# (C) 2002 The UbixOS Project -# $Id: Makefile 134 2016-01-15 14:50:24Z reddawg $ - -# Include Global 'Source' Options -include ../../Makefile.incl -include ../Makefile.incl - -# Objects -OBJS = schedyield.o kpanic.o timer.o spinlock.o i386_exec.o sys_call_new.o sys_call.o bioscall.o fork.o syscall.o systemtask.o sched.o cpu.o -# ap-boot.o smp.o vitals.o(obsolete) - -all: $(OBJS) - -# Compile Types -.cc.o: - $(CXX) -DNOBOOL $(CFLAGS) $(INCLUDES) -c -o $@ $< -.cc.s: - $(CXX) -DNOBOOL $(CFLAGS) $(INCLUDES) -S -o $@ $< -.c.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< -.c.s: - $(CC) $(CFLAGS) $(INCLUDES) -S -o $@ $< -.S.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< - -# Clean up the junk -clean: - $(REMOVE) $(OBJS) diff --git a/sys/armv6/ap-boot.S b/sys/armv6/ap-boot.S deleted file mode 100644 index c08bd1e..0000000 --- a/sys/armv6/ap-boot.S +++ /dev/null @@ -1,133 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Okay, this file contains the code that's going to bootstrap the AP cpus - */ - - - .globl ap_trampoline_start,ap_trampoline_end - .text - .code16 -ap_trampoline_start: - cli - cld - - movw %cs,%ax // The CPU knows its CS already, so lets use it for the other segments - movw %ax,%ds - movw %ax,%es - movw %ax,%ss - - // Do some bochs-specific bullshit - mov $0x31,%al // '1' - mov $0xe9,%dx - outb %al,%dx - //lgdt ap_gdt; - lgdt ap_trampoline_gdt_limit - ap_trampoline_start - movl %cr0,%eax - orl $0x1,%eax - movl %eax,%cr0 // PMODE! - -.code32 - .byte 0x66 - ljmp $0x08,$(ap_trampoline_32 - ap_trampoline_start) // 0x08 == KERNEL_CS - -ap_trampoline_32: - mov $0x32,%al // '2' - mov $0xe9,%dx - outb %al,%dx - - mov $0x10,%ax - mov %ax,%ds - mov %ax,%es - mov %ax,%fs - mov %ax,%gs - mov %ax,%ss - - // Spinlock - mov ap_trampoline_spl - ap_trampoline_start,%edi -ap_spl: - //cmp $1,(%edi) - //je ap_spl - - mov $1,%eax // Value to be set - xchgl (%edi),%eax - cmp $0,%eax - je ap_spl - // /Spinlock - - mov $0x30,%al // '0' - mov $0xe9,%dx - outb %al,%dx - - mov ap_trampoline_stackptr - ap_trampoline_start,%ebx - mov %ebx,%esp - add $0x1000,%ebx - mov %ebx,ap_trampoline_stackptr - ap_trampoline_start - - mov $0x31,%al // '1' - mov $0xe9,%dx - outb %al,%dx - - // spinunlock - mov $0,%eax - mov ap_trampoline_spl - ap_trampoline_start,%edi - xchgl (%edi),%eax - // /spinunlock - - mov $0x33,%al // '3' - mov $0xe9,%dx - outb %al,%dx - - mov ap_trampoline_epoint,%eax - call *%eax -1: - hlt - jmp 1b // Halt if we ever get here somehow - - // Stack.. This sucks, since CPU initialization isn't serialized -ap_trampoline_stackptr: - .long 0x10000 // 256KB -ap_trampoline_epoint: - .long c_ap_boot - -ap_trampoline_spl: - .long 0 -ap_gdt: - .long ubixGDT - - // GDT -ap_trampoline_gdt: - .word 0 -ap_trampoline_gdt_limit: - .word 128 // Room for 32 descriptors -ap_trampoline_gdt_base: - .long 0x20000 // 128KB (move this later) - - -ap_trampoline_end: diff --git a/sys/armv6/bioscall.c b/sys/armv6/bioscall.c deleted file mode 100644 index c27a8db..0000000 --- a/sys/armv6/bioscall.c +++ /dev/null @@ -1,101 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -asm( - ".globl bios16Code\n" - ".code16 \n" - "bios16Code: \n" - "int $0x10 \n" - "int $0x69 \n" - ".code32 \n" - ); - - -void biosCall(int biosInt,int eax,int ebx,int ecx,int edx,int esi,int edi,int es,int ds) { - short segment = 0x0,offset = 0x0; - uInt32 tmpAddr = (uInt32)&bios16Code; - kTask_t *newProcess = 0x0; - - offset = tmpAddr & 0xF; // lower 4 bits - segment = tmpAddr >> 4; - - newProcess = schedNewTask(); - assert(newProcess); - - - newProcess->tss.back_link = 0x0; - newProcess->tss.esp0 = (uInt32)kmalloc(0x2000)+0x2000; - newProcess->tss.ss0 = 0x10; - newProcess->tss.esp1 = 0x0; - newProcess->tss.ss1 = 0x0; - newProcess->tss.esp2 = 0x0; - newProcess->tss.ss2 = 0x0; - newProcess->tss.cr3 = (uInt32)_current->tss.cr3;//(uInt32)vmmCreateVirtualSpace(newProcess->id); - newProcess->tss.eip = offset & 0xFFFF; - newProcess->tss.eflags = 2 | EFLAG_IF | EFLAG_VM; - newProcess->tss.eax = eax & 0xFFFF; - newProcess->tss.ebx = ebx & 0xFFFF; - newProcess->tss.ecx = ecx & 0xFFFF; - newProcess->tss.edx = edx & 0xFFFF; - newProcess->tss.esp = 0x1000 & 0xFFFF; - newProcess->tss.ebp = 0x1000 & 0xFFFF; - newProcess->tss.esi = esi & 0xFFFF; - newProcess->tss.edi = edi & 0xFFFF; - newProcess->tss.es = es & 0xFFFF; - newProcess->tss.cs = segment & 0xFFFF; - newProcess->tss.ss = 0x1000 & 0xFFFF; - newProcess->tss.ds = ds & 0xFFFF; - newProcess->tss.fs = 0x0 & 0xFFFF; - newProcess->tss.gs = 0x0 & 0xFFFF; - newProcess->tss.ldt = 0x0 & 0xFFFF; - newProcess->tss.trace_bitmap = 0x0 & 0xFFFF; - newProcess->tss.io_map = 0x0 & 0xFFFF; - newProcess->tss.io_map = sizeof(struct tssStruct)-8192; - newProcess->oInfo.v86Task = 0x1; - - newProcess->state = READY; - - while (newProcess->state > 0); - - return; - } - -/*** - END - ***/ - diff --git a/sys/armv6/exec.c b/sys/armv6/exec.c deleted file mode 100644 index 3af2f28..0000000 --- a/sys/armv6/exec.c +++ /dev/null @@ -1,750 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define STACK_ADDR 0xC800000 - -#define AT_NULL 0 /* Terminates the vector. */ -#define AT_IGNORE 1 /* Ignored entry. */ -#define AT_EXECFD 2 /* File descriptor of program to load. */ -#define AT_PHDR 3 /* Program header of program already loaded. */ -#define AT_PHENT 4 /* Size of each program header entry. */ -#define AT_PHNUM 5 /* Number of program header entries. */ -#define AT_PAGESZ 6 /* Page size in bytes. */ -#define AT_BASE 7 /* Interpreter's base address. */ -#define AT_FLAGS 8 /* Flags (unused for i386). */ -#define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -//#define AUXARGS_ENTRY(pos, id, val) {memcpy((void *)pos++,(void *)id,sizeof(long)); memcpy((void *)pos++,(void *)val,sizeof(long));} -#define AUXARGS_ENTRY(pos, id, val) {*pos = id;pos++; *pos = val;pos++;} - -/***************************************************************************************** - - Function: execThread(void (*)(void),int,char *); - Description: This function will create a thread from code in the current memory space - - Notes: - - 05/19/04 - This does not work the way I want it to it still makes a copy of kernel space - so do not use out side of kernel space - - *****************************************************************************************/ -uInt32 execThread(void (*tproc)(void), uInt32 stack, char *arg) { - kTask_t * newProcess = 0x0; - /* Find A New Thread */ - newProcess = schedNewTask(); - assert(newProcess); - if (stack < 0x100000) - kpanic("exec: stack not in valid area: [0x%X]\n", stack); - - /* Set All The Correct Thread Attributes */ - newProcess->tss.back_link = 0x0; - newProcess->tss.esp0 = 0x0; - newProcess->tss.ss0 = 0x0; - newProcess->tss.esp1 = 0x0; - newProcess->tss.ss1 = 0x0; - newProcess->tss.esp2 = 0x0; - newProcess->tss.ss2 = 0x0; - newProcess->tss.cr3 = (unsigned int) kernelPageDirectory; - newProcess->tss.eip = (unsigned int) tproc; - newProcess->tss.eflags = 0x206; - newProcess->tss.esp = stack; - newProcess->tss.ebp = stack; - newProcess->tss.esi = 0x0; - newProcess->tss.edi = 0x0; - - /* Set these up to be ring 3 tasks */ - /* - newProcess->tss.es = 0x30+3; - newProcess->tss.cs = 0x28+3; - newProcess->tss.ss = 0x30+3; - newProcess->tss.ds = 0x30+3; - newProcess->tss.fs = 0x30+3; - newProcess->tss.gs = 0x30+3; - */ - - newProcess->tss.es = 0x10; - newProcess->tss.cs = 0x08; - newProcess->tss.ss = 0x10; - newProcess->tss.ds = 0x10; - newProcess->tss.fs = 0x10; - newProcess->tss.gs = 0x10; - - newProcess->tss.ldt = 0x18; - newProcess->tss.trace_bitmap = 0x0000; - newProcess->tss.io_map = 0x8000; - newProcess->oInfo.vmStart = 0x6400000; - - //newProcess->imageFd = 0x0; - - /* Set up default stack for thread here filled with arg list 3 times */ - asm volatile( - "pusha \n" - "movl %%esp,%%ecx \n" - "movl %1,%%eax \n" - "movl %%eax,%%esp \n" - "pushl %%ebx \n" - "pushl %%ebx \n" - "pushl %%ebx \n" - "movl %%esp,%%eax \n" - "movl %%eax,%1 \n" - "movl %%ecx,%%esp \n" - "popa \n" - : - : "b" (arg),"m" (newProcess->tss.esp) - ); - - /* Put new thread into the READY state */ - sched_setStatus(newProcess->id, READY); - - /* Return with the new process ID */ - return ((uInt32) newProcess); -} - -/***************************************************************************************** - - Function: void execFile(char *file); - Description: This Function Executes A Kile Into A New VM Space With Out - Having To Fork - Notes: - - 07/30/02 - I Have Made Some Heavy Changes To This As Well As Fixed A Few - Memory Leaks The Memory Allocated To Load The Binary Into Is - Now Unmapped So It Can Be Used Again And Not Held Onto Until - The Program Exits - - 07/30/02 - Now I Have To Make A Better Memory Allocator So We Can Set Up - The Freshly Allocated Pages With The Correct Permissions - - *****************************************************************************************/ -void execFile(char *file, int argc, char **argv, int console) { - - int i = 0x0; - int x = 0x0; - uint32_t *tmp = 0x0; - - fileDescriptor *tmpFd = 0x0; - elfHeader *binaryHeader = 0x0; - elfProgramHeader *programHeader = 0x0; - - /* Get A New Task For This Proccess */ - _current = schedNewTask(); - assert(_current); - _current->gid = 0x0; - _current->uid = 0x0; - _current->term = tty_find(console); - if (_current->term == 0x0) - kprintf("Error: invalid console\n"); - - /* Set tty ownership */ - _current->term->owner = _current->id; - - /* Now We Must Create A Virtual Space For This Proccess To Run In */ - _current->tss.cr3 = (uInt32) vmmCreateVirtualSpace(_current->id); - - /* To Better Load This Application We Will Switch Over To Its VM Space */ - asm volatile( - "movl %0,%%eax \n" - "movl %%eax,%%cr3 \n" - : : "d" ((uInt32 *)(_current->tss.cr3)) - ); - - /* Lets Find The File */ - tmpFd = fopen(file, "r"); - - /* If We Dont Find the File Return */ - if (tmpFd == 0x0) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - fclose(tmpFd); - return; - } - if (tmpFd->perms == 0x0) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - fclose(tmpFd); - return; - } - - /* Load ELF Header */ - binaryHeader = (elfHeader *) kmalloc(sizeof(elfHeader)); - - //kprintf(">a:%i:0x%X:0x%X<",sizeof(elfHeader),binaryHeader,tmpFd); - fread(binaryHeader, sizeof(elfHeader), 1, tmpFd); - - /* Check If App Is A Real Application */ - if ((binaryHeader->eIdent[1] != 'E') && (binaryHeader->eIdent[2] != 'L') && (binaryHeader->eIdent[3] != 'F')) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(tmpFd); - return; - } - else if (binaryHeader->eType != 2) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(tmpFd); - return; - } - else if (binaryHeader->eEntry == 0x300000) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(tmpFd); - return; - } - - /* Load The Program Header(s) */ - programHeader = (elfProgramHeader *) kmalloc(sizeof(elfProgramHeader) * binaryHeader->ePhnum); - fseek(tmpFd, binaryHeader->ePhoff, 0); - - //kprintf(">c:%i:0x%X:0x%X<",sizeof(elfProgramHeader)*binaryHeader->ePhnum,programHeader,tmpFd); - fread(programHeader, (sizeof(elfProgramHeader) * binaryHeader->ePhnum), 1, tmpFd); - //kprintf(">d<"); - - /* Loop Through The Header And Load Sections Which Need To Be Loaded */ - for (i = 0; i < binaryHeader->ePhnum; i++) { - if (programHeader[i].phType == 1) { - /* - Allocate Memory Im Going To Have To Make This Load Memory With Correct - Settings so it helps us in the future - */ - for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { - /* Make readonly and read/write !!! */ - if (vmm_remapPage(vmm_findFreePage(_current->id), ((programHeader[i].phVaddr & 0xFFFFF000) + x), PAGE_DEFAULT) == 0x0) - K_PANIC("Remap Page Failed"); - - memset((void *) ((programHeader[i].phVaddr & 0xFFFFF000) + x), 0x0, 0x1000); - } - _current->oInfo.vmStart = 0x80000000; - _current->td.vm_daddr = (char *) (programHeader[i].phVaddr & 0xFFFFF000); - /* Now Load Section To Memory */ - fseek(tmpFd, programHeader[i].phOffset, 0); - fread((void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, tmpFd); - if ((programHeader[i].phFlags & 0x2) != 0x2) { - kprintf("pH: [0x%X]\n", programHeader[i].phMemsz); - for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { - if ((vmm_setPageAttributes((programHeader[i].phVaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) - kpanic("Error: vmm_setPageAttributes failed, File: %s, Line: %i\n", __FILE__, __LINE__); - } - } - } - } - - /* Set Virtual Memory Start */ - _current->oInfo.vmStart = 0x80000000; - _current->td.vm_daddr = (char *) (programHeader[i].phVaddr & 0xFFFFF000); - - /* Set Up Stack Space */ - for (x = 1; x < 100; x++) { - vmm_remapPage(vmm_findFreePage(_current->id), STACK_ADDR - (x * 0x1000), PAGE_DEFAULT | PAGE_STACK); - } - - /* Kernel Stack 0x2000 bytes long */ - vmm_remapPage(vmm_findFreePage(_current->id), 0x5BC000, KERNEL_PAGE_DEFAULT | PAGE_STACK); - vmm_remapPage(vmm_findFreePage(_current->id), 0x5BB000, KERNEL_PAGE_DEFAULT | PAGE_STACK); - - /* Set All The Proper Information For The Task */ - _current->tss.back_link = 0x0; - _current->tss.esp0 = 0x5BC000; - _current->tss.ss0 = 0x10; - _current->tss.esp1 = 0x0; - _current->tss.ss1 = 0x0; - _current->tss.esp2 = 0x0; - _current->tss.ss2 = 0x0; - _current->tss.eip = (long) binaryHeader->eEntry; - _current->tss.eflags = 0x206; - _current->tss.esp = STACK_ADDR - 12; - _current->tss.ebp = STACK_ADDR; - _current->tss.esi = 0x0; - _current->tss.edi = 0x0; - - /* Set these up to be ring 3 tasks */ - _current->tss.es = 0x30 + 3; - _current->tss.cs = 0x28 + 3; - _current->tss.ss = 0x30 + 3; - _current->tss.ds = 0x30 + 3; - _current->tss.fs = 0x30 + 3; - _current->tss.gs = 0x30 + 3; - - _current->tss.ldt = 0x18; - _current->tss.trace_bitmap = 0x0000; - _current->tss.io_map = 0x8000; - - sched_setStatus(_current->id, READY); - - kfree(binaryHeader); - kfree(programHeader); - fclose(tmpFd); - - tmp = (uInt32 *) _current->tss.esp0 - 5; - tmp[0] = binaryHeader->eEntry; - tmp[3] = STACK_ADDR - 12; - - tmp = (uInt32 *) STACK_ADDR - 2; - - if (_current->id > 4) - kprintf("argv[0]: [%s]\n", argv[0]); - kprintf("argv: [0x%X]\n", argv); - tmp[0] = (uint32_t) argv; - tmp[1] = (uint32_t) argv; - - /* Switch Back To The Kernels VM Space */ - asm volatile( - "movl %0,%%eax \n" - "movl %%eax,%%cr3 \n" - : : "d" ((uInt32 *)(kernelPageDirectory)) - ); - - /* Finally Return */ - return; -} - -/***************************************************************************************** - - Function: void sysExec(); - Description: This Is The System Call To Execute A New Task - - Notes: - 04-22-03 - It Now Loads Sections Not The Full File - - *****************************************************************************************/ -void sysExec(char *file, char *ap) { - int i = 0x0; - int x = 0x0; - int argc = 0x0; - unsigned int *tmp = 0x0; - uInt32 ldAddr = 0x0; - uInt32 seg_size = 0x0; - uInt32 seg_addr = 0x0; - char *interp = 0x0; - char **argv = 0x0; - char **argvNew = 0x0; - char *args = 0x0; - - fileDescriptor *tmpFd = 0x0; - elfHeader *binaryHeader = 0x0; - elfProgramHeader *programHeader = 0x0; - elfSectionHeader *sectionHeader = 0x0; - elfDynamic *elfDynamicS = 0x0; - struct i386_frame *iFrame = 0x0; - - tmpFd = fopen(file, "r"); - _current->files[0] = tmpFd; - /* If We Dont Find the File Return */ - if (tmpFd == 0x0) { - return; - } - if (tmpFd->perms == 0) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - fclose(tmpFd); - return; - } - - /* Load ELF Header */ - - if ((binaryHeader = (elfHeader *) kmalloc(sizeof(elfHeader))) == 0x0) - endTask(_current->id); - fread(binaryHeader, sizeof(elfHeader), 1, tmpFd); - /* Set sectionHeader To Point To Loaded Binary To We Can Gather Info */ - - /* Check If App Is A Real Application */ - if ((binaryHeader->eIdent[1] != 'E') && (binaryHeader->eIdent[2] != 'L') && (binaryHeader->eIdent[3] != 'F')) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(tmpFd); - - return; - } - else if (binaryHeader->eType != 2) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(tmpFd); - return; - } - else if (binaryHeader->eEntry == 0x300000) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(tmpFd); - return; - } - - /* Load The Program Header(s) */ - if ((programHeader = (elfProgramHeader *) kmalloc(sizeof(elfProgramHeader) * binaryHeader->ePhnum)) == 0x0) - endTask(_current->id); - - assert(programHeader); - fseek(tmpFd, binaryHeader->ePhoff, 0); - fread(programHeader, (sizeof(elfProgramHeader) * binaryHeader->ePhnum), 1, tmpFd); - - if ((sectionHeader = (elfSectionHeader *) kmalloc(sizeof(elfSectionHeader) * binaryHeader->eShnum)) == 0x0) - endTask(_current->id); - - assert(sectionHeader); - fseek(tmpFd, binaryHeader->eShoff, 0); - fread(sectionHeader, sizeof(elfSectionHeader) * binaryHeader->eShnum, 1, tmpFd); - - /* Loop Through The Header And Load Sections Which Need To Be Loaded */ - for (i = 0; i < binaryHeader->ePhnum; i++) { - switch (programHeader[i].phType) { - case PT_LOAD: - seg_addr = trunc_page(programHeader[i].phVaddr); - seg_size = round_page(programHeader[i].phMemsz + programHeader[i].phVaddr - seg_addr); - - /* - Allocate Memory Im Going To Have To Make This Load Memory With Correct - Settings so it helps us in the future - */ - for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { - /* Make readonly and read/write !!! */ - if (vmm_remapPage(vmm_findFreePage(_current->id), ((programHeader[i].phVaddr & 0xFFFFF000) + x), PAGE_DEFAULT) == 0x0) - K_PANIC("Error: Remap Page Failed"); - memset((void *) ((programHeader[i].phVaddr & 0xFFFFF000) + x), 0x0, 0x1000); - } - - /* Now Load Section To Memory */ - fseek(tmpFd, programHeader[i].phOffset, 0); - fread((void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, tmpFd); - if ((programHeader[i].phFlags & 0x2) != 0x2) { - for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { - if ((vmm_setPageAttributes((programHeader[i].phVaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) - kpanic("Error: vmm_setPageAttributes failed, File: %s,Line: %i\n", __FILE__, __LINE__); - } - } - kprintf("setting daddr\n"); - if (binaryHeader->eEntry >= programHeader[i].phVaddr && binaryHeader->eEntry < (programHeader[i].phVaddr + programHeader[i].phMemsz)) { - /* We're suposed to do something here? */ - } - else { - _current->td.vm_dsize = seg_size >> PAGE_SHIFT; - _current->td.vm_daddr = (char *) seg_addr; - } - - _current->oInfo.vmStart = ((programHeader[i].phVaddr & 0xFFFFF000) + 0xA900000); - break; - case PT_DYNAMIC: - //newLoc = (char *)programHeader[i].phVaddr; - elfDynamicS = (elfDynamic *) programHeader[i].phVaddr; - fseek(tmpFd, programHeader[i].phOffset, 0); - fread((void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, tmpFd); - break; - case PT_INTERP: - interp = (char *) kmalloc(programHeader[i].phFilesz); - fseek(tmpFd, programHeader[i].phOffset, 0); - fread((void *) interp, programHeader[i].phFilesz, 1, tmpFd); - kprintf("Interp: [%s]\n", interp); - ldAddr = ldEnable(); - break; - default: - break; - } - } - - /* What is this doing? 11/23/06 */ - if (elfDynamicS != 0x0) { - for (i = 0; i < 12; i++) { - if (elfDynamicS[i].dynVal == 0x3) { - tmp = (void *) elfDynamicS[i].dynPtr; - if (tmp == 0x0) - kpanic("tmp: NULL\n"); - tmp[2] = (uInt32) ldAddr; - tmp[1] = (uInt32) tmpFd; - break; - } - /* - else { - kprintf("dyn_val: %i",elfDynamicS[i].dynVal); - } - */ - } - } - - _current->td.vm_dsize = seg_size >> PAGE_SHIFT; - _current->td.vm_daddr = (char *) seg_addr; - - argv = ≈ - - if (argv[1] != 0x0) { - argc = (int) argv[0]; - args = (char *) vmmGetFreeVirtualPage(_current->id, 1, VM_TASK); - memset(args, 0x0, 0x1000); - x = 0x0; - argvNew = (char **) kmalloc(sizeof(char *) * argc); - for (i = 0x0; i < argc; i++) { - strcpy(args + x, argv[i + 1]); - argvNew[i] = args + x; - x += strlen(argv[i + 1]) + 1; - //args[x] = '\0'; - //x++; - } - argv = argvNew; - } - - //! Clean the virtual of COW pages left over from the fork - vmm_cleanVirtualSpace(_current->td.vm_daddr + (_current->td.vm_dsize << PAGE_SIZE)); - - //! Adjust iframe - iFrame = (struct i386_frame *) _current->tss.esp0 - sizeof(struct i386_frame); - iFrame->ebp = STACK_ADDR; - iFrame->eip = binaryHeader->eEntry; - iFrame->user_esp = STACK_ADDR - 12; - - //if (_current->id > 3) { - - iFrame->user_esp = ((uint32_t) STACK_ADDR) - (sizeof(uint32_t) * (argc + 3)); - tmp = (void *) iFrame->user_esp; - - //! build argc and argv[] - tmp[0] = argc; - for (i = 0; i < argc; i++) { - tmp[i + 1] = (u_int) argv[i]; - } - tmp[argc + 1] = 0x0; - tmp[argc + 2] = 0x1; - //} - //else { - //tmp = (uint32_t *)STACK_ADDR - 2; - //tmp[0] = 0x1; - //tmp[1] = 0x0; - //tmp[1] = (uint32_t)argv; - //} - kfree(argvNew); - /* Now That We Relocated The Binary We Can Unmap And Free Header Info */ - kfree(binaryHeader); - kfree(programHeader); - - return; -} - -/*! - * \brief New exec... - * - */ -void sys_exec(char *file, char *ap) { - int error = 0x0; - int i = 0x0; - int x = 0x0; - int argc = 0x0; - uint32_t *tmp = 0x0; - uint32_t seg_size = 0x0; - uint32_t seg_addr = 0x0; - uint32_t addr = 0x0; - uint32_t eip = 0x0; - uint32_t proghdr = 0x0; - char *args = 0x0; - char *interp = 0x0; - char **argv = 0x0; - char **argvNew = 0x0; - elfHeader *binaryHeader = 0x0; - elfProgramHeader *programHeader = 0x0; - struct i386_frame *iFrame = 0x0; - //Elf_Auxargs *auxargs = 0x0; - - _current->files[0] = fopen(file, "r"); - if (_current->files[0] == 0x0) - return; //We Need To Set errno - - /* Load the ELF header */ - if ((binaryHeader = (elfHeader *) kmalloc(sizeof(elfHeader))) == 0x0) - K_PANIC("malloc failed!"); - fread(binaryHeader, sizeof(elfHeader), 1, _current->files[0]); - - /* Check If App Is A Real Application */ - if (((binaryHeader->eIdent[1] != 'E') && (binaryHeader->eIdent[2] != 'L') && (binaryHeader->eIdent[3] != 'F')) || (binaryHeader->eType != ET_EXEC)) { - kfree(binaryHeader); - fclose(_current->files[0]); - return; //We Need To Set errno - } - - /* Load The Program Header(s) */ - if ((programHeader = (elfProgramHeader *) kmalloc(sizeof(elfProgramHeader) * binaryHeader->ePhnum)) == 0x0) - K_PANIC("malloc failed!"); - fseek(_current->files[0], binaryHeader->ePhoff, 0); - fread(programHeader, (sizeof(elfProgramHeader) * binaryHeader->ePhnum), 1, _current->files[0]); - - /* Loop Through The Header And Load Sections Which Need To Be Loaded */ - for (i = 0x0; i < binaryHeader->ePhnum; i++) { - switch (programHeader[i].phType) { - case PT_LOAD: - seg_addr = trunc_page(programHeader[i].phVaddr); - seg_size = round_page(programHeader[i].phMemsz + programHeader[i].phVaddr - seg_addr); - - /* - Allocate Memory Im Going To Have To Make This Load Memory With Correct - Settings so it helps us in the future - */ - for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { - /* Make readonly and read/write !!! */ - if (vmm_remapPage(vmm_findFreePage(_current->id), ((programHeader[i].phVaddr & 0xFFFFF000) + x), PAGE_DEFAULT) == 0x0) - K_PANIC("Error: Remap Page Failed"); - memset((void *) ((programHeader[i].phVaddr & 0xFFFFF000) + x), 0x0, 0x1000); - } - - /* Now Load Section To Memory */ - fseek(_current->files[0], programHeader[i].phOffset, 0); - fread((void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, _current->files[0]); - if ((programHeader[i].phFlags & 0x2) != 0x2) { - for (x = 0x0; x < (programHeader[i].phMemsz); x += 0x1000) { - if ((vmm_setPageAttributes((programHeader[i].phVaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) - K_PANIC("vmm_setPageAttributes failed"); - } - } - if (binaryHeader->eEntry >= programHeader[i].phVaddr && binaryHeader->eEntry < (programHeader[i].phVaddr + programHeader[i].phMemsz)) { - /* We're suposed to do something here? */ - } - else { - _current->td.vm_dsize = seg_size >> PAGE_SHIFT; - _current->td.vm_daddr = (char *) seg_addr; - } - - _current->oInfo.vmStart = ((programHeader[i].phVaddr & 0xFFFFF000) + 0xA900000); - break; - case PT_INTERP: - interp = (char *) kmalloc(programHeader[i].phFilesz); - if (interp == 0x0) - K_PANIC("malloc failed") - ; - - fseek(_current->files[0], programHeader[i].phOffset, 0); - fread((void *) interp, programHeader[i].phFilesz, 1, _current->files[0]); - kprintf("Interp: [%s]\n", interp); - //ldAddr = ldEnable(); - break; - case PT_PHDR: - proghdr = programHeader[i].phVaddr; - break; - default: - break; - } - } - - addr = LD_START; - - if (interp != 0x0) { - //kprintf("TEST"); - elf_loadfile(_current, interp, &addr, &eip); - } - //kprintf("[0x%X][0x%X]\n",eip,addr); - - _current->td.vm_dsize = seg_size >> PAGE_SHIFT; - _current->td.vm_daddr = (char *) seg_addr; - - //! copy in arg strings - argv = ap; - - if (argv[1] != 0x0) { - argc = argv[0]; - args = (char *) vmmGetFreeVirtualPage(_current->id, 1, VM_TASK); - memset(args, 0x0, 0x1000); - x = 0x0; - argvNew = (char **) kmalloc(sizeof(char *) * argc); - for (i = 0x0; i < argc; i++) { - strcpy(args + x, argv[i + 1]); - argvNew[i] = args + x; - x += strlen(argv[i + 1]) + 1; - } - argv = argvNew; - } - - //! Clean the virtual of COW pages left over from the fork - vmm_cleanVirtualSpace(_current->td.vm_daddr + (_current->td.vm_dsize << PAGE_SIZE)); - - //! Adjust iframe - iFrame = _current->tss.esp0 - sizeof(struct i386_frame); - iFrame->ebp = STACK_ADDR; - iFrame->eip = eip; - - //if (_current->id > 3) { - - iFrame->user_esp = ((uint32_t) STACK_ADDR) - (sizeof(uint32_t) * (argc + 4)); // + (sizeof(Elf_Auxargs) * 2))); - kprintf("\n\n\nuser_esp: [0x%X]\n", iFrame->user_esp); - tmp = iFrame->user_esp; - - //! build argc and argv[] - tmp[0] = argc; - for (i = 0; i < argc; i++) { - tmp[i + 1] = argv[i]; - } - //! Build ENV - args = (char *) vmmGetFreeVirtualPage(_current->id, 1, VM_TASK); - memset(args, 0x0, 0x1000); - strcpy(args, "LIBRARY_PATH=/lib"); - tmp[argc + 2] = args; - kprintf("env: [0x%X][0x%X]\n", (uInt32) tmp + argc + 2, tmp[argc + 2]); - tmp[argc + 3] = 0x0; - kprintf("env: [0x%X][0x%X]\n", (uInt32) tmp + argc + 2, tmp[argc + 2]); - //auxargs = iFrame->user_esp + argc + 3; - tmp = iFrame->user_esp; - tmp += argc + 4; - - /* - auxargs->execfd = -1; - auxargs->phdr = proghdr; - auxargs->phent = binaryHeader->ePhentsize; - auxargs->phnum = binaryHeader->ePhnum; - auxargs->pagesz = PAGE_SIZE; - auxargs->base = addr; - auxargs->flags = 0x0; - auxargs->entry = binaryHeader->eEntry; - auxargs->trace = 0x0; - - AUXARGS_ENTRY(tmp, AT_PHDR, auxargs->phdr); - AUXARGS_ENTRY(tmp, AT_PHENT, auxargs->phent); - AUXARGS_ENTRY(tmp, AT_PHNUM, auxargs->phnum); - AUXARGS_ENTRY(tmp, AT_PAGESZ, auxargs->pagesz); - AUXARGS_ENTRY(tmp, AT_FLAGS, auxargs->flags); - AUXARGS_ENTRY(tmp, AT_ENTRY, auxargs->entry); - AUXARGS_ENTRY(tmp, AT_BASE, auxargs->base); - AUXARGS_ENTRY(tmp, AT_NULL, 0); - - kprintf("AT_BASE: [0x%X]\n",auxargs->base); - */ - - //iFrame->ebx = 0x0; - //iFrame->ebx = 0x0; - //iFrame->eip = binaryHeader->eEntry; - //kprintf("\n\nDOH: [0x%X]\n\n",iFrame->eip); -//while (1); - //while (1); - /* - error = elf_loadfile(_current,file,0x0,0x0); - if (error) - K_PANIC("elf_loadfile failed"); - */ - return; -} - -/*** - END - ***/ diff --git a/sys/armv6/fork.c b/sys/armv6/fork.c deleted file mode 100644 index 20fcde6..0000000 --- a/sys/armv6/fork.c +++ /dev/null @@ -1,128 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/***************************************************************************************** - Functoin: static int fork_copyProcess(struct taskStruct *newProcess,long ebp,long edi, - long esi, long none,long ebx,long ecx,long edx,long eip,long cs,long eflags, - long esp,long ss) - - Desc: This function will copy a process - - Notes: - - *****************************************************************************************/ -/* Had to remove static though tihs function is only used in this file */ -int fork_copyProcess(struct taskStruct *newProcess, long ebp, long edi, long esi, long none, long ebx, long ecx, long edx, long eip, long cs, long eflags, long esp, long ss) { - volatile struct taskStruct * tmpProcPtr = newProcess; - assert(newProcess); - assert(_current); - - /* Set Up New Tasks Information */ - memcpy(newProcess->oInfo.cwd, _current->oInfo.cwd, 1024); - - newProcess->tss.eip = eip; - newProcess->oInfo.vmStart = _current->oInfo.vmStart; - newProcess->term = _current->term; - newProcess->term->owner = newProcess->id; - newProcess->uid = _current->uid; - newProcess->gid = _current->gid; - newProcess->tss.back_link = 0x0; - newProcess->tss.esp0 = _current->tss.esp0; - newProcess->tss.ss0 = 0x10; - newProcess->tss.esp1 = 0x0; - newProcess->tss.ss1 = 0x0; - newProcess->tss.esp2 = 0x0; - newProcess->tss.ss2 = 0x0; - newProcess->tss.eflags = eflags; - newProcess->tss.eax = 0x0; - newProcess->tss.ebx = ebx; - newProcess->tss.ecx = ecx; - newProcess->tss.edx = edx; - newProcess->tss.esi = esi; - newProcess->tss.edi = edi; - newProcess->tss.ebp = ebp; - newProcess->tss.esp = esp; - newProcess->tss.cs = cs & 0xFF; - newProcess->tss.ss = ss & 0xFF; - newProcess->tss.ds = _current->tss.ds & 0xFF; - newProcess->tss.fs = _current->tss.fs & 0xFF; - newProcess->tss.gs = _current->tss.gs & 0xFF; - newProcess->tss.es = _current->tss.es & 0xFF; - newProcess->tss.ldt = 0x18; - newProcess->tss.trace_bitmap = 0x0000; - newProcess->tss.io_map = 0x8000; - /* Create A Copy Of The VM Space For New Task */ - newProcess->tss.cr3 = (uInt32) vmmCopyVirtualSpace(newProcess->id); - newProcess->state = FORK; - - /* Fix gcc optimization problems */ - while (tmpProcPtr->state == FORK) - sched_yield(); - - /* Return Id of Proccess */ - return (newProcess->id); -} - -/***************************************************************************************** - Functoin: void sysFork(); - - Desc: This function will fork a new task - - Notes: - - 08/01/02 - This Seems To Be Working Fine However I'm Not Sure If I - Chose The Best Path To Impliment It I Guess We Will See - What The Future May Bring - - *****************************************************************************************/ -asm( - ".globl sysFork \n" - "sysFork: \n" - " xor %eax,%eax \n" - " call schedNewTask \n" - " testl %eax,%eax \n" - " je fork_ret \n" - " pushl %esi \n" - " pushl %edi \n" - " pushl %ebp \n" - " pushl %eax \n" - " call fork_copyProcess \n" - " movl %eax,(%ebx) \n" - " addl $16,%esp \n" - "fork_ret: \n" - " ret \n" -); diff --git a/sys/armv6/kpanic.c b/sys/armv6/kpanic.c deleted file mode 100644 index e4b43c7..0000000 --- a/sys/armv6/kpanic.c +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -/*! - * \brief print panic message and halt system - * - * \param fmt panic message - * - */ -void kpanic(const char *fmt, ...) { - char buf[512]; - va_list args; - - vaStart(args, fmt); - vsprintf(buf, fmt, args); - vaEnd(args); - - /* It's important that we print on the current terminal so let's reset foreground */ - tty_foreground = NULL; - kprintf("kPanic: %s", buf); - - /* Halt The System */ - //asm("cli"); - irqDisable(0x0); - - while (1) { - asm("hlt"); - } - -} - -/*** - END - ***/ - diff --git a/sys/armv6/sched.c b/sys/armv6/sched.c deleted file mode 100644 index 5f6ffc6..0000000 --- a/sys/armv6/sched.c +++ /dev/null @@ -1,279 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static kTask_t *taskList = 0x0; -static kTask_t *delList = 0x0; -static uInt32 nextID = -1; - -kTask_t *_current = 0x0; -kTask_t *_usedMath = 0x0; - -static struct spinLock schedulerSpinLock = SPIN_LOCK_INITIALIZER; - -/************************************************************************ - - Function: int sched_init() - - Description: This function is used to enable the kernel scheduler - - Notes: - - 02/20/2004 - Approved for quality - - ************************************************************************/ - -int sched_init() { - taskList = (kTask_t *) kmalloc(sizeof(kTask_t)); - if (taskList == 0x0) - kpanic("Unable to create task list"); - - taskList->id = nextID++; - - /* Print out information on scheduler */ - kprintf("sched0 - Address: [0x%X]\n", taskList); - - /* Return so we know everything went well */ - return (0x0); -} - -void sched() { - uInt32 memAddr = 0x0; - kTask_t *tmpTask = 0x0; - kTask_t *delTask = 0x0; - - if (!spinTryLock(&schedulerSpinLock)) - return; - - tmpTask = _current->next; - //outportByte(0xE9,_current->id + '0'); - schedStart: - - /* Yield the next task from the current prio queue */ - for (; tmpTask != 0x0; tmpTask = tmpTask->next) { - if (tmpTask->state > 0x0) { - _current = tmpTask; - if (_current->state == FORK) - _current->state = READY; - break; - } - else if (tmpTask->state == DEAD) { - delTask = tmpTask; - tmpTask = tmpTask->next; - sched_deleteTask(delTask->id); - sched_addDelTask(delTask); - goto schedStart; - } - } - - /* Finished all the tasks, restarting the list */ - if (0x0 == tmpTask) { - tmpTask = taskList; - goto schedStart; - } - - if (_current->state > 0x0) { - if (_current->oInfo.v86Task == 0x1) - irqDisable(0x0); - asm("cli"); - memAddr = (uInt32) &(_current->tss); - ubixGDT[4].descriptor.baseLow = (memAddr & 0xFFFF); - ubixGDT[4].descriptor.baseMed = ((memAddr >> 16) & 0xFF); - ubixGDT[4].descriptor.baseHigh = (memAddr >> 24); - ubixGDT[4].descriptor.access = '\x89'; - spinUnlock(&schedulerSpinLock); - asm("sti"); - asm("ljmp $0x20,$0\n"); - } - else { - spinUnlock(&schedulerSpinLock); - } - - return; -} - -kTask_t *schedNewTask() { - int i = 0; - kTask_t *tmpTask = (kTask_t *) kmalloc(sizeof(kTask_t)); - struct file *fp = 0x0; - if (tmpTask == 0x0) - kpanic("Error: schedNewTask() - kmalloc failed trying to initialize a new task struct\n"); - - memset(tmpTask, 0x0, sizeof(kTask_t)); - /* Filling in tasks attrs */ - tmpTask->usedMath = 0x0; - tmpTask->state = NEW; - - /* HACK */ - for (i = 0; i < 3; i++) { - fp = (void *) kmalloc(sizeof(struct file)); - tmpTask->td.o_files[i] = (uint32_t) fp; - fp->f_flag = 0x4; - } - - spinLock(&schedulerSpinLock); - tmpTask->id = nextID++; - tmpTask->next = taskList; - tmpTask->prev = 0x0; - taskList->prev = tmpTask; - taskList = tmpTask; - - spinUnlock(&schedulerSpinLock); - - return (tmpTask); -} - -int sched_deleteTask(pidType id) { - kTask_t *tmpTask = 0x0; - - /* Checking each task from the prio queue */ - for (tmpTask = taskList; tmpTask != 0x0; tmpTask = tmpTask->next) { - if (tmpTask->id == id) { - if (tmpTask->prev != 0x0) - tmpTask->prev->next = tmpTask->next; - if (tmpTask->next != 0x0) - tmpTask->next->prev = tmpTask->prev; - if (taskList == tmpTask) - taskList = tmpTask->next; - - return (0x0); - } - } - return (0x1); -} - -int sched_addDelTask(kTask_t *tmpTask) { - tmpTask->next = delList; - tmpTask->prev = 0x0; - if (delList != 0x0) - delList->prev = tmpTask; - delList = tmpTask; - return (0x0); -} - -kTask_t *sched_getDelTask() { - kTask_t *tmpTask = 0x0; - - if (delList == 0x0) - return (0x0); - - tmpTask = delList; - delList = delList->next; - return (tmpTask); -} - -kTask_t * -schedFindTask(uInt32 id) { - kTask_t *tmpTask = 0x0; - - for (tmpTask = taskList; tmpTask; tmpTask = tmpTask->next) { - if (tmpTask->id == id) - return (tmpTask); - } - - return (0x0); -} - -/************************************************************************ - - Function: void schedEndTask() - - Description: This function will end a task - - Notes: - - 02/20/2004 - Approved for quality - - ************************************************************************/ -void schedEndTask(pidType pid) { - endTask(_current->id); - sched_yield(); -} - -/************************************************************************ - - Function: int schedEndTask() - - Description: This function will yield a task - - Notes: - - 02/20/2004 - Approved for quality - - ************************************************************************/ - -void sched_yield() { - sched(); -} - -/* - asm( - ".globl sched_yield \n" - "sched_yield: \n" - " cli \n" - " call sched \n" - ); - */ - -/************************************************************************ - - Function: int sched_setStatus(pidType pid,tState state) - - Description: Change the tasks status - - Notes: - - ************************************************************************/ -int sched_setStatus(pidType pid, tState state) { - kTask_t *tmpTask = schedFindTask(pid); - if (tmpTask == 0x0) - return (0x1); - tmpTask->state = state; - return (0x0); -} - -/*** - END - ***/ - diff --git a/sys/armv6/schedyield.S b/sys/armv6/schedyield.S deleted file mode 100644 index 1072793..0000000 --- a/sys/armv6/schedyield.S +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -.globl sched_yield_new -.text -.code32 -sched_yield_new: - pusha /* Save all of the registers */ - push %ss - push %ds - push %es - push %fs - push %gs - call sched - mov %eax,%esp - pop %gs - pop %fs - pop %es - pop %ds - pop %ss - popa /* Restore Registers */ - iret - -/*** - END - ***/ diff --git a/sys/armv6/spinlock.c b/sys/armv6/spinlock.c deleted file mode 100644 index 790d1fb..0000000 --- a/sys/armv6/spinlock.c +++ /dev/null @@ -1,77 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -void spinLockInit(spinLock_t *lock) { - *lock = SPIN_LOCK_INITIALIZER; - } - -void spinUnlock(spinLock_t *lock) { - *lock = 0x0; - /* - register int unlocked; - asm volatile( - "xchgl %0, %1" - : "=&r" (unlocked), "=m" (*lock) : "0" (0) - ); - */ - } - -int spinTryLock(spinLock_t *lock) { - register int locked; - asm volatile("xchgl %0, %1" - : "=&r" (locked), "=m" (*lock) : "0" (1) - ); - return(!locked); - } - -void spinLock(spinLock_t *lock) { - while (!spinTryLock(lock)) - { - while (*lock == 1) - sched_yield(); - } -} - -void spinLock_scheduler(spinLock_t *lock) { - while (!spinTryLock(lock)) - while (*lock == 1); - } - - -int spinLockLocked(spinLock_t *lock) { - return(*lock != 0); - } - - -/*** - END - ***/ - diff --git a/sys/armv6/sys_call.S b/sys/armv6/sys_call.S deleted file mode 100644 index b4a557e..0000000 --- a/sys/armv6/sys_call.S +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -.globl _sysCall -.text -.code32 -_sysCall: - cmpl totalCalls,%eax - jae invalidSysCall - - cld - pushl %edx - pushl %ecx - pushl %ebx - call *systemCalls(,%eax,4) - popl %ebx - popl %ecx - popl %edx /* Restore Registers */ - - iret - -invalidSysCall: - movl $-1,%eax - iret - -/*** - END - ***/ - diff --git a/sys/armv6/sys_call_new.S b/sys/armv6/sys_call_new.S deleted file mode 100644 index 2f73600..0000000 --- a/sys/armv6/sys_call_new.S +++ /dev/null @@ -1,67 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define FAKE_MCOUNT(caller) pushl caller ; call __mcount ; popl %ecx - -.globl _sysCall_new -.text -.code32 -_sysCall_new: - pushl $2 /* sizeof "int 0x80" */ - subl $4,%esp /* skip over tf_trapno */ - pushal - pushl %ds - pushl %es - pushl %fs - /* switch to kernel segments */ - movl $0x10,%eax - movl %eax,%ds - movl %eax,%es - movl %eax,%fs - //FAKE_MCOUNT(TF_EIP(%esp)) - call syscall - //MEXITCOUNT - //jmp doreti - popl %fs - popl %es - popl %ds - popal - addl $8,%esp - iret - -invalidSysCall: - push %eax - call invalidCall - pop %eax - movl $-1,%eax - iret - -/*** - END - ***/ - diff --git a/sys/armv6/syscall.c b/sys/armv6/syscall.c deleted file mode 100644 index 36a81d8..0000000 --- a/sys/armv6/syscall.c +++ /dev/null @@ -1,247 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* #include */ -#include -#include - -//long fuword(const void *base); - -//void sdeTestThread(); - -asm( - ".globl _sysCallNew \n" - "_sysCallNew: \n" - " pusha \n" - " push %ss \n" - " push %ds \n" - " push %es \n" - " push %fs \n" - " push %gs \n" - " cmpl totalCalls,%eax \n" - " jae invalidSysCallNew \n" - " mov %esp,%ebx \n" - " add $12,%ebx \n" - " push (%ebx) \n" - " call *systemCalls(,%eax,4) \n" - " add $4,%esp \n" - " jmp doneNew \n" - "invalidSysCallNew: \n" - " call InvalidSystemCall \n" - "doneNew: \n" - " pop %gs \n" - " pop %fs \n" - " pop %es \n" - " pop %ds \n" - " pop %ss \n" - " popa \n" - " iret \n" -); - -void InvalidSystemCall() { - kprintf("attempt was made to an invalid system call\n"); - return; -} - -typedef struct _UbixUser UbixUser; -struct _UbixUser { - char *username; - char *password; - int uid; - int gid; - char *home; - char *shell; -}; - -void sysAuth(UbixUser *uu) { - kprintf("authenticating user %s\n", uu->username); - - /* MrOlsen 2016-01-01 uh? - if(uu->username == "root" && uu->password == "user") - { - uu->uid = 0; - uu->gid = 0; - } - */ - uu->uid = -1; - uu->gid = -1; - return; -} - -void sysPasswd(char *passwd) { - kprintf("changing user password for user %d\n", _current->uid); - return; -} - -void sysAddModule() { - return; -} - -void sysRmModule() { - return; -} - -void sysGetpid(int *pid) { - if (pid) - *pid = _current->id; - return; -} - -void sysGetUid(int *uid) { - if (uid) - *uid = _current->uid; - return; -} - -void sysGetGid(int *gid) { - if (gid) - *gid = _current->gid; - return; -} - -void sysSetUid(int uid, int *status) { - if (_current->uid == 0x0) { - _current->uid = uid; - if (status) - *status = 0x0; - } - else { - if (status) - *status = 1; - } - return; -} - -void sysSetGid(int gid, int *status) { - if (_current->gid == 0x0) { - _current->gid = gid; - if (status) - *status = 0x0; - } - else { - if (status) - *status = 1; - } - return; -} - -void sysExit(int status) { - endTask(_current->id); -} - -void sysCheckPid(int pid, int *ptr) { - kTask_t *tmpTask = schedFindTask(pid); - if ((tmpTask != 0x0) && (ptr != 0x0)) - *ptr = tmpTask->state; - else - *ptr = 0x0; - return; -} - -/************************************************************************ - - Function: void sysGetFreePage(); - Description: Allocs A Page To The Users VM Space - Notes: - - ************************************************************************/ -void sysGetFreePage(long *ptr, int count, int type) { - if (ptr) { - if (type == 2) - *ptr = (long) vmmGetFreeVirtualPage(_current->id, count, VM_THRD); - else - *ptr = (long) vmmGetFreeVirtualPage(_current->id, count, VM_TASK); - } - return; -} - -void sysGetDrives(uInt32 *ptr) { - if (ptr) - *ptr = 0x0; //(uInt32)devices; - return; -} - -void sysGetUptime(uInt32 *ptr) { - if (ptr) - *ptr = systemVitals->sysTicks; - return; -} - -void sysGetTime(uInt32 *ptr) { - if (ptr) - *ptr = systemVitals->sysUptime + systemVitals->timeStart; - return; -} - -void sysGetCwd(char *data, int len) { - if (data) - sprintf(data, "%s", _current->oInfo.cwd); - return; -} - -void sysSchedYield() { - sched_yield(); -} - -void sysStartSDE() { - int i = 0x0; - for (i = 0; i < 1400; i++) { - asm("hlt"); - } - //execThread(sdeThread,(uInt32)(kmalloc(0x2000)+0x2000),0x0); - for (i = 0; i < 1400; i++) { - asm("hlt"); - } - return; -} - -void invalidCall(int sys_call) { - kprintf("Invalid System Call #[%i]\n", sys_call); - return; -} - -/*** - END - ***/ - diff --git a/sys/armv6/systemtask.c b/sys/armv6/systemtask.c deleted file mode 100644 index c0a999e..0000000 --- a/sys/armv6/systemtask.c +++ /dev/null @@ -1,122 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned char *videoBuffer = (char *)0xB8000; - - -void systemTask() { - mpi_message_t myMsg; - uInt32 counter = 0x0; - int i = 0x0; - int *x = 0x0; - kTask_t *tmpTask = 0x0; - - if (mpi_createMbox("system") != 0x0) { - kpanic("Error: Error creating mailbox: system\n"); - } - - while(1) { - if (mpi_fetchMessage("system",&myMsg) == 0x0) { - kprintf("A"); - switch(myMsg.header) { - case 0x69: - x = (int *)&myMsg.data; - kprintf("Switching to term: [%i][%i]\n",*x,myMsg.pid); - schedFindTask(myMsg.pid)->term = tty_find(*x); - break; - case 1000: - kprintf("Restarting the system in 5 seconds\n"); - counter = systemVitals->sysUptime + 5; - while (systemVitals->sysUptime < counter) { - sched_yield(); - } - kprintf("Rebooting NOW!!!\n"); - while(inportByte(0x64) & 0x02); - outportByte(0x64, 0xFE); - break; - case 31337: - kprintf("system: backdoor opened\n"); - break; - case 0x80: - if (!strcmp(myMsg.data,"sdeStart")) { - kprintf("Starting SDE\n"); - //execThread(sdeThread,(uInt32)(kmalloc(0x2000)+0x2000),0x0); - } - else if (!strcmp(myMsg.data,"freePage")) { - kprintf("kkk Free Pages"); - } - else if (!strcmp(myMsg.data,"sdeStop")) { - printOff = 0x0; - biosCall(0x10,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0); - for (i=0x0;i<100;i++) asm("hlt"); - } - break; - default: - kprintf("system: Received message %i:%s\n",myMsg.header,myMsg.data); - break; - } - } - - /* - Here we get the next task from the delete task queue - we first check to see if it has an fd attached for the binary and after that - we free the pages for the process and then free the task - */ - tmpTask = sched_getDelTask(); - if (tmpTask != 0x0) { - if (tmpTask->files[0] != 0x0) - fclose(tmpTask->files[0]); - vmmFreeProcessPages(tmpTask->id); - kfree(tmpTask); - } - videoBuffer[0] = systemVitals->sysTicks; - sched_yield(); - } - - return; - } - -/*** - END - ***/ - diff --git a/sys/armv6/timer.S b/sys/armv6/timer.S deleted file mode 100644 index c7aa642..0000000 --- a/sys/armv6/timer.S +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -.globl timerInt -.text -.code32 -timerInt: - pusha /* Save all of the registers */ - mov $0x20,%dx /* The Following Sends Our EOI To The MPIC */ - mov $0x20,%ax - outb %al,%dx - movl systemVitals,%ecx /* Put Location Of System Vitals Into ECX */ - incl 4(%ecx) /* Increment sysTicks our 1000ms counter */ - movl 4(%ecx),%eax /* Increment our sysUptime by 1S if 1000MS */ - movl $200,%ebx /* Have Passed */ - xor %edx,%edx - div %ebx - test %edx,%edx - jnz next - incl 8(%ecx) -next: - movl 4(%ecx),%eax /* Test If quantum Has Passed If So Then */ - movl 12(%ecx),%ebx /* We Can CALL sched */ - xor %edx,%edx - div %ebx - test %edx,%edx - jnz done - call sched -done: - popa /* Restore Registers */ - iret - -/*** - END - ***/ - diff --git a/sys/compile/Makefile b/sys/compile/Makefile index 341c4c1..4f28ac4 100644 --- a/sys/compile/Makefile +++ b/sys/compile/Makefile @@ -9,7 +9,7 @@ OBJS = null.o #Kernel Parts -KPARTS = ../${_ARCH}/*.o ../init/*.o ../sys/*.o ../vmm/*.o ../lib/*.o ../kernel/*.o ../isa/*.o ../fs/vfs/*.o ../pci/*.o ../fs/devfs/*.o ../mpi/*.o ../fs/ufs/*.o ../fs/common/*.o ../net/net/*.o ../net/netif/*.o ../net/api/*.o ../net/core/*.o ../net/core/ipv4/*.o ../sde/*.o +KPARTS = ../arch/${_ARCH}/*.o ../init/*.o ../sys/*.o ../vmm/*.o ../lib/*.o ../kernel/*.o ../isa/*.o ../fs/vfs/*.o ../pci/*.o ../fs/devfs/*.o ../mpi/*.o ../fs/ufs/*.o ../fs/common/*.o ../net/net/*.o ../net/netif/*.o ../net/api/*.o ../net/core/*.o ../net/core/ipv4/*.o ../sde/*.o # ../net/core/ipv6/*.o # ../fs/ubixfs/*.o # ../sde/*.o ../graphics/*.o ../ld/*.o -Ttext 0x30000 -Tdata 0x34000 ../ubixfs/*.o diff --git a/sys/fs/ubixfs/thread.c b/sys/fs/ubixfs/thread.c old mode 100755 new mode 100644 diff --git a/sys/fs/ufs/ufs.c b/sys/fs/ufs/ufs.c index 9ecb3ce..0e4d9bd 100644 --- a/sys/fs/ufs/ufs.c +++ b/sys/fs/ufs/ufs.c @@ -267,10 +267,14 @@ static int ufs_openFile(const char *file, fileDescriptor_t *fd) { char tmp[2]; int ino = 0; + fd->dmadat = (struct dmadat *) kmalloc(sizeof(struct dmadat)); + ino = lookup(file, fd); + fd->offset = 0x0; fd->ino = ino; + if (ino == 0x0) { kfree(fd->dmadat); return (-1); @@ -279,6 +283,7 @@ /* Quick Hack for file size */ fsread(fd->ino, &tmp, 1, fd); fd->offset = 0; + /* Return */ fd->perms = 0x1; return (0x1); diff --git a/sys/fs/vfs/file.c b/sys/fs/vfs/file.c index eb86f6b..4001910 100644 --- a/sys/fs/vfs/file.c +++ b/sys/fs/vfs/file.c @@ -38,20 +38,23 @@ #include #include -static struct spinLock fdTable_lock = SPIN_LOCK_INITIALIZER; +static struct spinLock fdTable_lock = SPIN_LOCK_INITIALIZER +; fileDescriptor_t *fdTable = 0x0; fileDescriptor_t *vfs_fileTable = 0x0; -int sys_fwrite( struct thread *td, struct sys_fwrite_args *uap ) { +int sys_fwrite(struct thread *td, struct sys_fwrite_args *uap) { char *t = uap->buf; - if ( uap->fd == 0x0 ) - tty_print( (char *) uap->buf, _current->term ); + if (uap->fd == 0x0) + tty_print((char *) uap->buf, _current->term); else { - kprintf( "uap->size: %i, FD: [0x%X], BUF: [0x%X][%c]\n", uap->nbytes, uap->fd, uap->buf, t[0] ); - fwrite( uap->buf, uap->nbytes, 1, uap->fd->fd ); +#ifdef DEBUG_VFS + kprintf("uap->size: %i, FD: [0x%X], BUF: [0x%X][%c]\n", uap->nbytes, uap->fd, uap->buf, t[0]); +#endif + fwrite(uap->buf, uap->nbytes, 1, uap->fd->fd); } td->td_retval[0] = 0x0; @@ -61,27 +64,27 @@ /* USER */ -void sysFwrite( char *ptr, int size, userFileDescriptor *userFd ) { - if ( userFd == 0x0 ) { - tty_print( ptr, _current->term ); +void sysFwrite(char *ptr, int size, userFileDescriptor *userFd) { + if (userFd == 0x0) { + tty_print(ptr, _current->term); } else { - fwrite( ptr, size, 1, userFd->fd ); + fwrite(ptr, size, 1, userFd->fd); } return; } -int sys_fgetc( struct thread *td, struct sys_fgetc_args *args ) { +int sys_fgetc(struct thread *td, struct sys_fgetc_args *args) { char c; - if ( args->FILE->fd == 0x0 ) { + if (args->FILE->fd == 0x0) { - while ( 1 ) { + while (1) { - if ( _current->term == tty_foreground ) { + if (_current->term == tty_foreground) { c = getchar(); - if ( c != 0x0 ) { + if (c != 0x0) { td->td_retval[0] = c; return (0); } @@ -104,7 +107,7 @@ } } else { - c = fgetc( args->FILE->fd ); + c = fgetc(args->FILE->fd); td->td_retval[0] = c; return (0); } @@ -114,38 +117,37 @@ return; } -int sys_fseek( struct thread *td, struct sys_fseek_args *args ) { +int sys_fseek(struct thread *td, struct sys_fseek_args *args) { kprintf("offset: %ld, whence: 0x%X", args->offset, args->whence); // TODO : coredump? - if ( args->FILE == NULL ) { + if (args->FILE == NULL) { td->td_retval[0] = -1; return (-1); } - if ( args->FILE->fd == NULL ) { + if (args->FILE->fd == NULL) { td->td_retval[0] = -1; return (-1); } - switch (args->whence) { - case 0: - args->FILE->fd->offset = args->offset + args->whence; + case 0: + args->FILE->fd->offset = args->offset + args->whence; break; - case 1: - args->FILE->fd->offset += args->offset; + case 1: + args->FILE->fd->offset += args->offset; break; - default: - kprintf ("seek-whence: %i", args->whence); + default: + kprintf("seek-whence: %i", args->whence); break; } - td->td_retval[0] = args->FILE->fd->offset & 0xFFFFFFFF; + td->td_retval[0] = args->FILE->fd->offset & 0xFFFFFFFF; return (0); } -int sys_lseek( struct thread *td, struct sys_lseek_args *args ) { +int sys_lseek(struct thread *td, struct sys_lseek_args *args) { int error = 0; struct file *fdd = 0x0; fileDescriptor_t *fd = 0x0; @@ -162,18 +164,18 @@ kprintf("loffset(%i): %i:%i, whence: 0x%X", sizeof(off_t), args->offset >> 32, args->offset & 0xFFFFFF, args->whence); switch (args->whence) { - case SEEK_SET: - fd->offset = args->offset; - td->td_retval[0] = fd->offset & 0xFFFFFFFF; - td->td_retval[1] = fd->offset >> 32; + case SEEK_SET: + fd->offset = args->offset; + td->td_retval[0] = fd->offset & 0xFFFFFFFF; + td->td_retval[1] = fd->offset >> 32; break; - case SEEK_CUR: - fd->offset += args->offset; - td->td_retval[0] = fd->offset & 0xFFFFFFFF; - td->td_retval[1] = fd->offset >> 32; + case SEEK_CUR: + fd->offset += args->offset; + td->td_retval[0] = fd->offset & 0xFFFFFFFF; + td->td_retval[1] = fd->offset >> 32; break; - default: - kprintf ("seek-whence: %i", args->whence); + default: + kprintf("seek-whence: %i", args->whence); break; } @@ -182,19 +184,18 @@ return (error); } - -int sys_chdir( struct thread *td, struct sys_chdir_args *args ) { - if ( strstr( args->path, ":" ) == 0x0 ) { - sprintf( _current->oInfo.cwd, "%s%s", _current->oInfo.cwd, args->path ); +int sys_chdir(struct thread *td, struct sys_chdir_args *args) { + if (strstr(args->path, ":") == 0x0) { + sprintf(_current->oInfo.cwd, "%s%s", _current->oInfo.cwd, args->path); } else { - sprintf( _current->oInfo.cwd, args->path ); + sprintf(_current->oInfo.cwd, args->path); } td->td_retval[0] = 0; return (0); } -int sys_fchdir( struct thread *td, struct sys_fchdir_args *args ) { +int sys_fchdir(struct thread *td, struct sys_fchdir_args *args) { int error = 0; struct file *fdd = 0x0; fileDescriptor_t *fd = 0x0; @@ -206,25 +207,25 @@ if (fdd == 0 || fdd->fd == 0x0) { error = -1; } -else { - if ( strstr( fd->fileName, ":" ) == 0x0 ) { - sprintf( _current->oInfo.cwd, "%s%s", _current->oInfo.cwd, fd->fileName ); - } else { - sprintf( _current->oInfo.cwd, fd->fileName ); + if (strstr(fd->fileName, ":") == 0x0) { + sprintf(_current->oInfo.cwd, "%s%s", _current->oInfo.cwd, fd->fileName); + } + else { + sprintf(_current->oInfo.cwd, fd->fileName); + } } -} return (error); } -int sys_rename( struct thread *td, struct sys_rename_args *args ) { +int sys_rename(struct thread *td, struct sys_rename_args *args) { td->td_retval[0] = 0; return (0); } -int sysUnlink( const char *path, int *retVal ) { +int sysUnlink(const char *path, int *retVal) { *retVal = 0; - return(*retVal); + return (*retVal); } /************************************************************************ @@ -235,15 +236,15 @@ ************************************************************************/ //void sysFopen(const char *file,char *flags,userFileDescriptor *userFd) { -int sys_fopen( struct thread *td, struct sys_fopen_args *args ) { - kprintf("fopen really?"); - if ( args->FILE == NULL ) { - kprintf( "Error: userFd == NULL, File: %s, Line: %i\n", __FILE__, __LINE__ ); +int sys_fopen(struct thread *td, struct sys_fopen_args *args) { + + if (args->FILE == NULL) { + kprintf("Error: userFd == NULL, File: %s, Line: %i\n", __FILE__, __LINE__); return (-1); } - args->FILE->fd = fopen( args->path, args->mode ); - if ( args->FILE->fd != 0x0 ) { + args->FILE->fd = fopen(args->path, args->mode); + if (args->FILE->fd != 0x0) { args->FILE->fdSize = args->FILE->fd->size; } /* Return */ @@ -257,17 +258,17 @@ Notes: ************************************************************************/ -int sys_fread( struct thread *td, struct sys_fread_args *args ) { +int sys_fread(struct thread *td, struct sys_fread_args *args) { /* TODO : coredump? */ - if ( args->FILE == NULL ) + if (args->FILE == NULL) return (-1); - if ( args->FILE->fd == NULL ) + if (args->FILE->fd == NULL) return (-1); - td->td_retval[0] = fread( args->ptr, args->size, args->nmemb, args->FILE->fd ); - return(0); + td->td_retval[0] = fread(args->ptr, args->size, args->nmemb, args->FILE->fd); + return (0); } /************************************************************************ @@ -277,50 +278,49 @@ Notes: ************************************************************************/ -int sys_fclose( struct thread *td, struct sys_fclose_args *args ) { - if ( args->FILE == NULL ) { +int sys_fclose(struct thread *td, struct sys_fclose_args *args) { + if (args->FILE == NULL) { return (-1); } - if ( args->FILE == NULL ) { + if (args->FILE == NULL) { return (-1); } /* Return */ - return (fclose( args->FILE->fd )); + return (fclose(args->FILE->fd)); } /* KERNEL */ -size_t fread( void *ptr, size_t size, size_t nmemb, fileDescriptor_t *fd ) { +size_t fread(void *ptr, size_t size, size_t nmemb, fileDescriptor_t *fd) { size_t i = 0x0; - - if ( fd == 0x0 ) + if (fd == 0x0) return (0x0); - if ( nmemb == 0x0 ) + if (nmemb == 0x0) nmemb = 1; //Temp Fix - assert( fd ); - assert( fd->mp ); - assert( fd->mp->fs ); + assert(fd); + assert(fd->mp); + assert(fd->mp->fs); - i = fd->mp->fs->vfsRead( fd, ptr, fd->offset, size * nmemb ); + i = fd->mp->fs->vfsRead(fd, ptr, fd->offset, size * nmemb); //fd->offset += size * nmemb; return (i); } -size_t fwrite( void *ptr, int size, int nmemb, fileDescriptor_t *fd ) { - if ( fd != 0x0 ) { - fd->mp->fs->vfsWrite( fd, ptr, fd->offset, size * nmemb ); +size_t fwrite(void *ptr, int size, int nmemb, fileDescriptor_t *fd) { + if (fd != 0x0) { + fd->mp->fs->vfsWrite(fd, ptr, fd->offset, size * nmemb); fd->offset += size * nmemb; } return (0x0); } -int fseek( fileDescriptor_t *tmpFd, long offset, int whence ) { +int fseek(fileDescriptor_t *tmpFd, long offset, int whence) { tmpFd->offset = offset + whence; return (tmpFd->offset); } @@ -332,8 +332,8 @@ Notes: ************************************************************************/ -int feof( fileDescriptor_t *fd ) { - if ( fd->status == fdEof ) { +int feof(fileDescriptor_t *fd) { + if (fd->status == fdEof) { return (-1); } return (0); @@ -346,9 +346,9 @@ Notes: ************************************************************************/ -int fputc( int ch, fileDescriptor_t *fd ) { - if ( fd != 0x0 ) { - ch = fd->mp->fs->vfsWrite( fd, (char *) ch, fd->offset, 1 ); +int fputc(int ch, fileDescriptor_t *fd) { + if (fd != 0x0) { + ch = fd->mp->fs->vfsWrite(fd, (char *) ch, fd->offset, 1); fd->offset++; return (ch); } @@ -363,11 +363,11 @@ Notes: ************************************************************************/ -int fgetc( fileDescriptor_t *fd ) { +int fgetc(fileDescriptor_t *fd) { int ch = 0x0; /* If Found Return Next Char */ - if ( fd != 0x0 ) { - fd->mp->fs->vfsRead( fd, (char *) &ch, fd->offset, 1 ); + if (fd != 0x0) { + fd->mp->fs->vfsRead(fd, (char *) &ch, fd->offset, 1); fd->offset++; return (ch); } @@ -386,7 +386,8 @@ ************************************************************************/ -fileDescriptor_t *fopen( const char *file, const char *flags ) { +fileDescriptor_t *fopen(const char *file, const char *flags) { + int i = 0x0; char *path = 0x0; char *mountPoint = 0x0; @@ -394,86 +395,91 @@ fileDescriptor_t *tmpFd = 0x0; /* Allocate Memory For File Descriptor */ - if ( (tmpFd = (fileDescriptor_t *) kmalloc( sizeof(fileDescriptor_t) )) == 0x0 ) { - kprintf( "Error: tmpFd == NULL, File: %s, Line: %i\n", __FILE__, __LINE__ ); + if ((tmpFd = (fileDescriptor_t *) kmalloc(sizeof(fileDescriptor_t))) == 0x0) { + kprintf("Error: tmpFd == NULL, File: %s, Line: %i\n", __FILE__, __LINE__); return (NULL); } + memset(tmpFd, 0x0, sizeof(fileDescriptor_t)); + path = file; + /* Determine if path is relative or absolute */ if (path[0] == "." && path[1] == '\0') strcpy(fileName, _current->oInfo.cwd); else - strcpy( fileName, file ); + strcpy(fileName, file); path = 0x0; - if ( strstr( fileName, ":" ) ) { - mountPoint = (char *) strtok( (char *) &fileName, ":" ); - path = strtok( NULL, "\n" ); + if (strstr(fileName, ":")) { + mountPoint = (char *) strtok((char *) &fileName, ":"); + path = strtok( NULL, "\n"); } else { path = fileName; } - if ( path[0] == '/' ) - strcpy( tmpFd->fileName, path ); + if (path[0] == '/') + strcpy(tmpFd->fileName, path); else - sprintf( tmpFd->fileName, "/%s", path ); + sprintf(tmpFd->fileName, "/%s", path); /* Find our mount point or set default to sys */ - if ( mountPoint == 0x0 ) { - tmpFd->mp = vfs_findMount( "sys" ); + if (mountPoint == 0x0) { + tmpFd->mp = vfs_findMount("sys"); } else { - tmpFd->mp = vfs_findMount( mountPoint ); + tmpFd->mp = vfs_findMount(mountPoint); } - if ( tmpFd->mp == 0x0 ) { - kprintf( "Mount Point Bad\n" ); + if (tmpFd->mp == 0x0) { + kprintf("Mount Point Bad\n"); return (0x0); } - //kprintf("[fO: %s]", file); /* This Will Set Up The Descriptor Modes */ tmpFd->mode = 0; - for ( i = 0; '\0' != flags[i]; i++ ) { - switch ( flags[i] ) { - case 'w': - case 'W': - tmpFd->mode |= fileWrite; - break; - case 'r': - case 'R': - tmpFd->mode |= fileRead; - break; - case 'b': - case 'B': - tmpFd->mode |= fileBinary; - break; - case 'a': - case 'A': - tmpFd->mode |= fileAppend; - break; - default: - kprintf( "Invalid mode '%c' for fopen\n", flags[i] ); - break; + for (i = 0; '\0' != flags[i]; i++) { + switch (flags[i]) { + case 'w': + case 'W': + tmpFd->mode |= fileWrite; + break; + case 'r': + case 'R': + tmpFd->mode |= fileRead; + break; + case 'b': + case 'B': + tmpFd->mode |= fileBinary; + break; + case 'a': + case 'A': + tmpFd->mode |= fileAppend; + break; + default: + kprintf("Invalid mode '%c' for fopen\n", flags[i]); + break; } } + /* Search For The File */ - if ( tmpFd->mp->fs->vfsOpenFile( tmpFd->fileName, tmpFd ) == 0x1 ) { + if (tmpFd->mp->fs->vfsOpenFile(tmpFd->fileName, tmpFd) == 0x1) { /* If The File Is Found Then Set Up The Descriptor */ /* in order to save resources we will allocate the buffer later when it is needed */ - tmpFd->buffer = (char *) kmalloc( 4096 ); - if ( tmpFd->buffer == 0x0 ) { - kfree( tmpFd ); - kprintf( "Error: tmpFd->buffer == NULL, File: %s, Line: %i\n", __FILE__, __LINE__ ); - spinUnlock( &fdTable_lock ); - return(0x0); + tmpFd->buffer = (char *) kmalloc(4096); + + if (tmpFd->buffer == 0x0) { + kfree(tmpFd); + kprintf("Error: tmpFd->buffer == NULL, File: %s, Line: %i\n", __FILE__, __LINE__); + spinUnlock(&fdTable_lock); + return (0x0); } + /* Set Its Status To Open */ tmpFd->status = fdOpen; @@ -483,28 +489,28 @@ /* we do not want to be in a spinlock longer than we need to, so it has been moved to here. */ - spinLock( &fdTable_lock ); + spinLock(&fdTable_lock); /* Increment Number Of Open Files */ systemVitals->openFiles++; tmpFd->next = fdTable; - if ( fdTable != 0x0 ) + if (fdTable != 0x0) fdTable->prev = tmpFd; fdTable = tmpFd; - spinUnlock( &fdTable_lock ); + spinUnlock(&fdTable_lock); /* Return The FD */ return (tmpFd); } else { //kprintf("Freeing"); - kfree( tmpFd->buffer ); - kfree( tmpFd ); - spinUnlock( &fdTable_lock ); + kfree(tmpFd->buffer); + kfree(tmpFd); + spinUnlock(&fdTable_lock); //MrOlsen (2016-01-13) NOTE: We don't need this right now kprintf("File Not Found? %s\n",file); return (NULL); } @@ -520,7 +526,7 @@ Notes: ************************************************************************/ -int fclose( fileDescriptor_t *fd ) { +int fclose(fileDescriptor_t *fd) { fileDescriptor_t *tmpFd = 0x0; // XXX Can't do this @@ -528,28 +534,28 @@ if (fd == 0) return (0x0); - spinLock( &fdTable_lock ); + spinLock(&fdTable_lock); - for ( tmpFd = fdTable; tmpFd != 0x0; tmpFd = tmpFd->next ) { - if ( tmpFd == fd ) { - if ( tmpFd->prev ) + for (tmpFd = fdTable; tmpFd != 0x0; tmpFd = tmpFd->next) { + if (tmpFd == fd) { + if (tmpFd->prev) tmpFd->prev->next = tmpFd->next; - if ( tmpFd->next ) + if (tmpFd->next) tmpFd->next->prev = tmpFd->prev; - if ( tmpFd == fdTable ) + if (tmpFd == fdTable) fdTable = tmpFd->next; systemVitals->openFiles--; - spinUnlock( &fdTable_lock ); - if ( tmpFd->buffer != NULL ) - kfree( tmpFd->buffer ); - kfree( tmpFd ); + spinUnlock(&fdTable_lock); + if (tmpFd->buffer != NULL) + kfree(tmpFd->buffer); + kfree(tmpFd); return (0x0); } } - spinUnlock( &fdTable_lock ); + spinUnlock(&fdTable_lock); return (0x1); } @@ -562,7 +568,7 @@ Notes: ************************************************************************/ -void sysMkDir( const char *path ) { +void sysMkDir(const char *path) { fileDescriptor_t *tmpFD = 0x0; char tmpDir[1024]; char rootPath[256]; @@ -571,28 +577,28 @@ rootPath[0] = '\0'; dir = (char *) path; - if ( strstr( path, ":" ) == 0x0 ) { - sprintf( tmpDir, "%s%s", _current->oInfo.cwd, path ); + if (strstr(path, ":") == 0x0) { + sprintf(tmpDir, "%s%s", _current->oInfo.cwd, path); dir = (char *) &tmpDir; } - while ( strstr( dir, "/" ) ) { - if ( rootPath[0] == 0x0 ) - sprintf( rootPath, "%s/", strtok( dir, "/" ) ); + while (strstr(dir, "/")) { + if (rootPath[0] == 0x0) + sprintf(rootPath, "%s/", strtok(dir, "/")); else - sprintf( rootPath, "%s%s/", rootPath, strtok( dir, "/" ) ); - tmp = strtok( NULL, "\n" ); + sprintf(rootPath, "%s%s/", rootPath, strtok(dir, "/")); + tmp = strtok( NULL, "\n"); dir = tmp; } //kprintf("rootPath: [%s]\n",rootPath); - tmpFD = fopen( rootPath, "rb" ); + tmpFD = fopen(rootPath, "rb"); - if ( tmpFD->mp == 0x0 ) { - kprintf( "Invalid Mount Point\n" ); + if (tmpFD->mp == 0x0) { + kprintf("Invalid Mount Point\n"); } - tmpFD->mp->fs->vfsMakeDir( dir, tmpFD ); + tmpFD->mp->fs->vfsMakeDir(dir, tmpFD); - fclose( tmpFD ); + fclose(tmpFD); return; } @@ -605,22 +611,22 @@ ************************************************************************/ -int unlink( const char *node ) { +int unlink(const char *node) { char *path = 0x0, *mountPoint = 0x0; struct vfs_mountPoint *mp = 0x0; - path = (char *) strtok( (char *) node, "@" ); - mountPoint = strtok( NULL, "\n" ); - if ( mountPoint == 0x0 ) { - mp = vfs_findMount( "sys" ); /* _current->oInfo.container; */ + path = (char *) strtok((char *) node, "@"); + mountPoint = strtok( NULL, "\n"); + if (mountPoint == 0x0) { + mp = vfs_findMount("sys"); /* _current->oInfo.container; */ } else { - mp = vfs_findMount( mountPoint ); + mp = vfs_findMount(mountPoint); } - if ( mp == 0x0 ) { + if (mp == 0x0) { //kpanic("Mount Point Bad"); return (0x0); } - mp->fs->vfsUnlink( path, mp ); + mp->fs->vfsUnlink(path, mp); return (0x0); } diff --git a/sys/i386/Makefile b/sys/i386/Makefile deleted file mode 100644 index 0ce7291..0000000 --- a/sys/i386/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# (C) 2002 The UbixOS Project -# $Id: Makefile 202 2016-01-23 15:21:35Z reddawg $ - -# Include Global 'Source' Options -include ../../Makefile.incl -include ../Makefile.incl - -# Objects -OBJS = support.o strcpy.o strcmp.o strncmp.o memset.o memcmp.o schedyield.o kpanic.o timer.o spinlock.o i386_exec.o sys_call_posix.o sys_call.o bioscall.o fork.o systemtask.o sched.o cpu.o trap.o bios16code.o -# ap-boot.o smp.o vitals.o(obsolete) - -all: $(OBJS) - -# Compile Types -.cc.o: - $(CXX) -DNOBOOL $(CFLAGS) $(INCLUDES) -c -o $@ $< -.cc.s: - $(CXX) -DNOBOOL $(CFLAGS) $(INCLUDES) -S -o $@ $< -.c.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< -.c.s: - $(CC) $(CFLAGS) $(INCLUDES) -S -o $@ $< -.S.o: - $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $< - -# Clean up the junk -clean: - $(REMOVE) $(OBJS) diff --git a/sys/i386/ap-boot.S b/sys/i386/ap-boot.S deleted file mode 100644 index c08bd1e..0000000 --- a/sys/i386/ap-boot.S +++ /dev/null @@ -1,133 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Okay, this file contains the code that's going to bootstrap the AP cpus - */ - - - .globl ap_trampoline_start,ap_trampoline_end - .text - .code16 -ap_trampoline_start: - cli - cld - - movw %cs,%ax // The CPU knows its CS already, so lets use it for the other segments - movw %ax,%ds - movw %ax,%es - movw %ax,%ss - - // Do some bochs-specific bullshit - mov $0x31,%al // '1' - mov $0xe9,%dx - outb %al,%dx - //lgdt ap_gdt; - lgdt ap_trampoline_gdt_limit - ap_trampoline_start - movl %cr0,%eax - orl $0x1,%eax - movl %eax,%cr0 // PMODE! - -.code32 - .byte 0x66 - ljmp $0x08,$(ap_trampoline_32 - ap_trampoline_start) // 0x08 == KERNEL_CS - -ap_trampoline_32: - mov $0x32,%al // '2' - mov $0xe9,%dx - outb %al,%dx - - mov $0x10,%ax - mov %ax,%ds - mov %ax,%es - mov %ax,%fs - mov %ax,%gs - mov %ax,%ss - - // Spinlock - mov ap_trampoline_spl - ap_trampoline_start,%edi -ap_spl: - //cmp $1,(%edi) - //je ap_spl - - mov $1,%eax // Value to be set - xchgl (%edi),%eax - cmp $0,%eax - je ap_spl - // /Spinlock - - mov $0x30,%al // '0' - mov $0xe9,%dx - outb %al,%dx - - mov ap_trampoline_stackptr - ap_trampoline_start,%ebx - mov %ebx,%esp - add $0x1000,%ebx - mov %ebx,ap_trampoline_stackptr - ap_trampoline_start - - mov $0x31,%al // '1' - mov $0xe9,%dx - outb %al,%dx - - // spinunlock - mov $0,%eax - mov ap_trampoline_spl - ap_trampoline_start,%edi - xchgl (%edi),%eax - // /spinunlock - - mov $0x33,%al // '3' - mov $0xe9,%dx - outb %al,%dx - - mov ap_trampoline_epoint,%eax - call *%eax -1: - hlt - jmp 1b // Halt if we ever get here somehow - - // Stack.. This sucks, since CPU initialization isn't serialized -ap_trampoline_stackptr: - .long 0x10000 // 256KB -ap_trampoline_epoint: - .long c_ap_boot - -ap_trampoline_spl: - .long 0 -ap_gdt: - .long ubixGDT - - // GDT -ap_trampoline_gdt: - .word 0 -ap_trampoline_gdt_limit: - .word 128 // Room for 32 descriptors -ap_trampoline_gdt_base: - .long 0x20000 // 128KB (move this later) - - -ap_trampoline_end: diff --git a/sys/i386/bios16code.S b/sys/i386/bios16code.S deleted file mode 100644 index b86ee01..0000000 --- a/sys/i386/bios16code.S +++ /dev/null @@ -1,5 +0,0 @@ -.globl bios16Code -bios16Code: -.code16 -int $0x10 -int $0x69 diff --git a/sys/i386/bioscall.c b/sys/i386/bioscall.c deleted file mode 100644 index e3d3094..0000000 --- a/sys/i386/bioscall.c +++ /dev/null @@ -1,90 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void biosCall(int biosInt, int eax, int ebx, int ecx, int edx, int esi, int edi, int es, int ds) { - short segment = 0x0, offset = 0x0; - uint32_t tmpAddr = (uint32_t) &bios16Code; - kTask_t *newProcess = 0x0; - - offset = tmpAddr & 0xF; // lower 4 bits - segment = tmpAddr >> 4; - - newProcess = schedNewTask(); - assert(newProcess); - - newProcess->tss.back_link = 0x0; - newProcess->tss.esp0 = (uint32_t) vmm_getFreeKernelPage(newProcess->id, 2) + (0x2000 - 0x4); // XXX I had 0xDEADBEEF I'm not sure why - newProcess->tss.ss0 = 0x10; - newProcess->tss.esp1 = 0x0; - newProcess->tss.ss1 = 0x0; - newProcess->tss.esp2 = 0x0; - newProcess->tss.ss2 = 0x0; - newProcess->tss.cr3 = kernelPageDirectory; //vmm_createVirtualSpace(newProcess->id); //(uint32_t)_current->tss.cr3; - newProcess->tss.eip = offset & 0xFFFF; - newProcess->tss.eflags = 2 | EFLAG_IF | EFLAG_VM; - newProcess->tss.eax = eax & 0xFFFF; - newProcess->tss.ebx = ebx & 0xFFFF; - newProcess->tss.ecx = ecx & 0xFFFF; - newProcess->tss.edx = edx & 0xFFFF; - newProcess->tss.esp = 0x1000 & 0xFFFF; - newProcess->tss.ebp = 0x1000 & 0xFFFF; - newProcess->tss.esi = esi & 0xFFFF; - newProcess->tss.edi = edi & 0xFFFF; - newProcess->tss.es = es & 0xFFFF; - newProcess->tss.cs = segment & 0xFFFF; - newProcess->tss.ss = 0x1000 & 0xFFFF; - newProcess->tss.ds = ds & 0xFFFF; - newProcess->tss.fs = 0x0 & 0xFFFF; - newProcess->tss.gs = 0x0 & 0xFFFF; - newProcess->tss.ldt = 0x0 & 0xFFFF; - newProcess->tss.trace_bitmap = 0x0 & 0xFFFF; - newProcess->tss.io_map = 0x0 & 0xFFFF; - newProcess->tss.io_map = sizeof(struct tssStruct) - 8192; - newProcess->oInfo.v86Task = 0x1; - - kprintf("EIP: [0x%X] 0x%X:0x%X", tmpAddr, newProcess->tss.eip, newProcess->tss.cs); - - newProcess->state = READY; - while (newProcess->state > 0) - sched_yield(); - - kprintf("EIP: [0x%X] 0x%X:0x%X!", tmpAddr, newProcess->tss.eip, newProcess->tss.cs); - kprintf("CALL DONE: %i 0x%X 0x%X!", newProcess->state, newProcess->tss.esp, newProcess->tss.ss); - - return; -} diff --git a/sys/i386/cpu.c b/sys/i386/cpu.c deleted file mode 100644 index ef9e0c0..0000000 --- a/sys/i386/cpu.c +++ /dev/null @@ -1,29 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include diff --git a/sys/i386/fork.c b/sys/i386/fork.c deleted file mode 100644 index 3e222f8..0000000 --- a/sys/i386/fork.c +++ /dev/null @@ -1,228 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int sys_fork(struct thread *td, struct sys_fork_args *args) { - struct taskStruct *newProcess; - - newProcess = schedNewTask(); - - /* - * - * Initalize New Task Information From Parrent - * - */ - - /* Set CWD */ - memcpy(newProcess->oInfo.cwd, _current->oInfo.cwd, 1024); - - /* Set PPID */ - newProcess->ppid = _current->id; - - /* Set PGRP */ - newProcess->pgrp = _current->pgrp; - - /* Set Up Task State */ - newProcess->tss.eip = td->frame->tf_eip; - newProcess->oInfo.vmStart = _current->oInfo.vmStart; - newProcess->term = _current->term; - newProcess->term->owner = newProcess->id; - newProcess->uid = _current->uid; - newProcess->gid = _current->gid; - newProcess->tss.back_link = 0x0; - newProcess->tss.esp0 = _current->tss.esp0; - newProcess->tss.ss0 = 0x10; - newProcess->tss.esp1 = 0x0; - newProcess->tss.ss1 = 0x0; - newProcess->tss.esp2 = 0x0; - newProcess->tss.ss2 = 0x0; - newProcess->tss.eflags = td->frame->tf_eflags; - newProcess->tss.eax = 0x0; - newProcess->tss.ebx = td->frame->tf_ebx; - newProcess->tss.ecx = td->frame->tf_ecx; - newProcess->tss.edx = td->frame->tf_edx; - newProcess->tss.esi = td->frame->tf_esi; - newProcess->tss.edi = td->frame->tf_edi; - newProcess->tss.ebp = td->frame->tf_ebp; - newProcess->tss.esp = td->frame->tf_esp; - newProcess->tss.cs = td->frame->tf_cs; // & 0xFF; - newProcess->tss.ss = td->frame->tf_ss; // & 0xFF; - newProcess->tss.ds = td->frame->tf_ds; //_current->tss.ds & 0xFF; - newProcess->tss.fs = td->frame->tf_fs; //_current->tss.fs & 0xFF; - newProcess->tss.gs = _current->tss.gs & 0xFF; - newProcess->tss.es = td->frame->tf_es; //_current->tss.es & 0xFF; - newProcess->tss.ldt = 0x18; - newProcess->tss.trace_bitmap = 0x0000; - newProcess->tss.io_map = 0x8000; - - newProcess->td.vm_tsize = _current->td.vm_tsize; - newProcess->td.vm_taddr = _current->td.vm_taddr; - newProcess->td.vm_dsize = _current->td.vm_dsize; - newProcess->td.vm_daddr = _current->td.vm_daddr; - - //kprintf("Copying Mem Space! [0x%X:0x%X:0x%X:0x%X:0x%X:%i:%i]\n", newProcess->tss.esp0, newProcess->tss.esp, newProcess->tss.ebp, td->frame->tf_esi, td->frame->tf_eip, newProcess->id, _current->id); - - newProcess->tss.cr3 = (uInt32) vmm_copyVirtualSpace(newProcess->id); - //kprintf( "Copied Mem Space! [0x%X]\n", newProcess->tss.cr3 ); - - newProcess->state = FORK; - /* Fix gcc optimization problems */ - while (newProcess->state == FORK) - sched_yield(); - - newProcess->parent = _current; - _current->children++; - - /* Return Id of Proccess */ - td->td_retval[0] = newProcess->id; - return (0); - -} - -/***************************************************************************************** - Functoin: static int fork_copyProcess(struct taskStruct *newProcess,long ebp,long edi, - long esi, long none,long ebx,long ecx,long edx,long eip,long cs,long eflags, - long esp,long ss) - - Desc: This function will copy a process - - Notes: - - *****************************************************************************************/ - -/* Had to remove static though tihs function is only used in this file */ -int fork_copyProcess(struct taskStruct *newProcess, long ebp, long edi, long esi, long none, long ebx, long ecx, long edx, long eip, long cs, long eflags, long esp, long ss) { - volatile struct taskStruct * tmpProcPtr = newProcess; - assert(newProcess); - assert(_current); - - /* Set Up New Tasks Information */ - memcpy(newProcess->oInfo.cwd, _current->oInfo.cwd, 1024); - //kprintf( "Initializing New CWD!\n" ); - - newProcess->tss.eip = eip; - newProcess->oInfo.vmStart = _current->oInfo.vmStart; - newProcess->term = _current->term; - newProcess->term->owner = newProcess->id; - newProcess->uid = _current->uid; - newProcess->gid = _current->gid; - newProcess->tss.back_link = 0x0; - newProcess->tss.esp0 = _current->tss.esp0; - newProcess->tss.ss0 = 0x10; - newProcess->tss.esp1 = 0x0; - newProcess->tss.ss1 = 0x0; - newProcess->tss.esp2 = 0x0; - newProcess->tss.ss2 = 0x0; - newProcess->tss.eflags = eflags; - newProcess->tss.eax = 0x0; - newProcess->tss.ebx = ebx; - newProcess->tss.ecx = ecx; - newProcess->tss.edx = edx; - newProcess->tss.esi = esi; - newProcess->tss.edi = edi; - newProcess->tss.ebp = ebp; - newProcess->tss.esp = esp; - newProcess->tss.cs = cs & 0xFF; - newProcess->tss.ss = ss & 0xFF; - newProcess->tss.ds = _current->tss.ds & 0xFF; - newProcess->tss.fs = _current->tss.fs & 0xFF; - newProcess->tss.gs = _current->tss.gs & 0xFF; - newProcess->tss.es = _current->tss.es & 0xFF; - newProcess->tss.ldt = 0x18; - newProcess->tss.trace_bitmap = 0x0000; - newProcess->tss.io_map = 0x8000; - - newProcess->td.vm_tsize = _current->td.vm_tsize; - newProcess->td.vm_taddr = _current->td.vm_taddr; - newProcess->td.vm_dsize = _current->td.vm_dsize; - newProcess->td.vm_daddr = _current->td.vm_daddr; - - /* Create A Copy Of The VM Space For New Task */ - //MrOlsen 2018kprintf("Copying Mem Space! [0x%X:0x%X:0x%X:0x%X:0x%X:%i:%i:0x%X]\n", newProcess->tss.esp0, newProcess->tss.esp, newProcess->tss.ebp, esi, eip, newProcess->id, _current->id, newProcess->td.vm_daddr); - newProcess->tss.cr3 = (uInt32) vmm_copyVirtualSpace(newProcess->id); - //kprintf( "Copied Mem Space!\n" ); - - newProcess->state = FORK; - - /* Fix gcc optimization problems */ - while (tmpProcPtr->state == FORK) - sched_yield(); - /* Return Id of Proccess */ - kprintf("Returning! [%i]", _current->id); - - return (newProcess->id); -} - -void qT() { - kprintf("qT\n"); -} - -/***************************************************************************************** - Functoin: void sysFork(); - - Desc: This function will fork a new task - - Notes: - - 08/01/02 - This Seems To Be Working Fine However I'm Not Sure If I - Chose The Best Path To Impliment It I Guess We Will See - What The Future May Bring - - *****************************************************************************************/ -//asm volatile( -__asm( - ".globl sysFork_old \n" - "sysFork_old: \n" - " xor %eax,%eax \n" - " call schedNewTask \n" - " testl %eax,%eax \n" - " je fork_ret \n" - " pushl %esi \n" - " pushl %edi \n" - " pushl %ebp \n" - " pushl %eax \n" - " call fork_copyProcess \n" - " movl %eax,(%ebx) \n" - " addl $16,%esp \n" - "fork_ret: \n" - " ret \n" -); - -/*** - END - ***/ - diff --git a/sys/i386/i386_exec.c b/sys/i386/i386_exec.c deleted file mode 100644 index 733d2a2..0000000 --- a/sys/i386/i386_exec.c +++ /dev/null @@ -1,990 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ENVP_PAGE 0x100 -#define ARGV_PAGE 0x100 -#define ELF_AUX 0x100 -#define STACK_PAD 0x1000 - -#define ENOEXEC -1 - -#define AT_NULL 0 /* Terminates the vector. */ -#define AT_IGNORE 1 /* Ignored entry. */ -#define AT_EXECFD 2 /* File descriptor of program to load. */ -#define AT_PHDR 3 /* Program header of program already loaded. */ -#define AT_PHENT 4 /* Size of each program header entry. */ -#define AT_PHNUM 5 /* Number of program header entries. */ -#define AT_PAGESZ 6 /* Page size in bytes. */ -#define AT_BASE 7 /* Interpreter's base address. */ -#define AT_FLAGS 8 /* Flags (unused for i386). */ -#define AT_ENTRY 9 /* Where interpreter should transfer control. */ - -#define AUXARGS_ENTRY(pos, id, val) {*pos = id;pos++; *pos = val;pos++;} - -static int argv_count(char **argv) { - int i = 0; - - while (*argv++ != 0x0) - i++; - - return (i); -} - -static int envp_count(char **envp) { - int i = 0; - - while (*envp++ != 0x0) - i++; - - return (i); -} - -static int args_copyin(char **argv_in, char **argv_out, char **args_out) { - - int argc = argv_count(argv_in); - - uint32_t *argv_tmp = (uint32_t *) kmalloc(sizeof(char *) * (argc + 2)); // + 1 For ARGC + 1 For NULL TERM - - char *args_tmp = (char *) kmalloc(ARGV_PAGE); - - argv_tmp[0] = argc; - - uint32_t sp = 0x0; - - int i = 0x0; - - for (i = 1; i <= argc; i++) { - argv_tmp[i] = (uint32_t)(args_tmp + sp); - strcpy((char *)argv_tmp[i], argv_in[i - 1]); - sp += strlen(argv_in[i - 1]) + 1; - } - - argv_tmp[i++] = 0x0; - - *argv_out = (char *)argv_tmp; - *args_out = args_tmp; - - return (0); - -} - -static int envs_copyin(char **envp_in, char **envp_out, char **envs_out) { - - int envc = envp_count(envp_in); - - uint32_t *envp_tmp = (uint32_t *) kmalloc(sizeof(char *) * (envc + 1)); // + 1 For NULL TERM - - char *envs_tmp = (char *) kmalloc(ENVP_PAGE); - - uint32_t sp = 0x0; - - int i = 0x0; - - for (i = 0; i < envc; i++) { - envp_tmp[i] = (uint32_t)(envs_tmp + sp); - strcpy((char *)envp_tmp[i], envp_in[i]); - sp += strlen(envp_in[i]) + 1; - } - envp_tmp[i++] = 0x0; - - *envp_out = (char *)envp_tmp; - *envs_out = envs_tmp; - return (0); -} - -static int elf_parse_dynamic(elf_file_t ef); - -/***************************************************************************************** - - Function: execThread(void (*)(void),int,char *); - Description: This function will create a thread from code in the current memory space - - Notes: - - 05/19/04 - This does not work the way I want it to it still makes a copy of kernel space - so do not use out side of kernel space - - *****************************************************************************************/ -uint32_t execThread(void (*tproc)(void), uint32_t stack, char *arg) { - - kTask_t * newProcess = 0x0; - uint32_t stackAddr = 0x0; - - /* Find A New Thread */ - newProcess = schedNewTask(); - assert(newProcess); - - stackAddr = vmm_getFreeKernelPage(newProcess->id, stack / PAGE_SIZE); - - /* Set All The Correct Thread Attributes */ - newProcess->tss.back_link = 0x0; - newProcess->tss.esp0 = 0x0; - newProcess->tss.ss0 = 0x0; - newProcess->tss.esp1 = 0x0; - newProcess->tss.ss1 = 0x0; - newProcess->tss.esp2 = 0x0; - newProcess->tss.ss2 = 0x0; - newProcess->tss.cr3 = (unsigned int) kernelPageDirectory; - newProcess->tss.eip = (unsigned int) tproc; - newProcess->tss.eflags = 0x206; - newProcess->tss.esp = stackAddr + (stack - 0x4); //stack; - newProcess->tss.ebp = 0x0;//stack; - newProcess->tss.esi = 0x0; - newProcess->tss.edi = 0x0; - - /* Ring 3 Selectors */ - /* - newProcess->tss.es = 0x30+3; - newProcess->tss.cs = 0x28+3; - newProcess->tss.ss = 0x30+3; - newProcess->tss.ds = 0x30+3; - newProcess->tss.fs = 0x30+3; - newProcess->tss.gs = 0x30+3; - */ - - /* Ring 0 Selectors */ - newProcess->tss.es = 0x10; - newProcess->tss.cs = 0x08; - newProcess->tss.ss = 0x10; - newProcess->tss.ds = 0x10; - newProcess->tss.fs = 0x10; - newProcess->tss.gs = 0x10; - - newProcess->tss.ldt = 0x18; - newProcess->tss.trace_bitmap = 0x0000; - newProcess->tss.io_map = 0x8000; - newProcess->oInfo.vmStart = 0x6400000; - - if (newProcess->files[0] != 0x0) - kpanic("Problem With File Descriptors"); - - newProcess->files[0] = 0x0; - - //kprintf("EIP: 0x%X(%i)", tproc, newProcess->id); - - /* Set up default stack for thread here filled with arg list 3 times */ - asm volatile( - "pusha \n" - "movl %%esp,%%ecx \n" - "movl %1,%%eax \n" - "movl %%eax,%%esp \n" - "pushl %%ebx \n" - "pushl %%ebx \n" - "pushl %%ebx \n" - "movl %%esp,%%eax \n" - "movl %%eax,%1 \n" - "movl %%ecx,%%esp \n" - "popa \n" - : - : "b" (arg),"m" (newProcess->tss.esp) - ); - - /* Put new thread into the READY state */ - sched_setStatus(newProcess->id, READY); - - /* Return with the new process ID */ - return ((uint32_t) newProcess); -} - -/***************************************************************************************** - - Function: void execFile(char *file); - Description: This Function Executes A Kile Into A New VM Space With Out - Having To Fork - Notes: - - 07/30/02 - I Have Made Some Heavy Changes To This As Well As Fixed A Few - Memory Leaks The Memory Allocated To Load The Binary Into Is - Now Unmapped So It Can Be Used Again And Not Held Onto Until - The Program Exits - - 07/30/02 - Now I Have To Make A Better Memory Allocator So We Can Set Up - The Freshly Allocated Pages With The Correct Permissions - - *****************************************************************************************/ -void execFile(char *file, char **argv, char **envp, int console) { - - kTask_t *newProcess = 0x0; - - int i = 0x0; - int x = 0x0; - - uint32_t *tmp = 0x0; - - Elf_Ehdr *binaryHeader = 0x0; - - Elf_Phdr *programHeader = 0x0; - - int argc = argv_count(argv); - int envc = envp_count(envp); - - /* Get A New Task For This Proccess */ - newProcess = schedNewTask(); - assert(newProcess); - - newProcess->gid = 0x0; - newProcess->uid = 0x0; - newProcess->pgrp = newProcess->id; - newProcess->term = tty_find(console); - - if (newProcess->term == 0x0) - kprintf("Error: invalid console\n"); - - /* Set tty ownership */ - newProcess->term->owner = newProcess->id; - - /* Now We Must Create A Virtual Space For This Proccess To Run In */ - newProcess->tss.cr3 = (uint32_t) vmm_createVirtualSpace(newProcess->id); - - /* To Better Load This Application We Will Switch Over To Its VM Space */ - asm volatile( - "movl %0,%%eax \n" - "movl %%eax,%%cr3 \n" - : : "d" ((uint32_t *)(newProcess->tss.cr3)) - ); - - /* Lets Find The File */ - if (newProcess->files[0] != 0x0) - kpanic("Problem With File Descriptors"); - newProcess->files[0] = fopen(file, "r"); - - /* If We Dont Find the File Return */ - if (newProcess->files[0] == 0x0) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - fclose(newProcess->files[0]); - return; - } - - if (newProcess->files[0]->perms == 0x0) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - fclose(newProcess->files[0]); - return; - } - - /* Load ELF Header */ - binaryHeader = (Elf_Ehdr *) kmalloc(sizeof(Elf_Ehdr)); - - fread(binaryHeader, sizeof(Elf_Ehdr), 1, newProcess->files[0]); - - /* Check If App Is A Real Application */ - if ((binaryHeader->e_ident[1] != 'E') && (binaryHeader->e_ident[2] != 'L') && (binaryHeader->e_ident[3] != 'F')) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(newProcess->files[0]); - return; - } - else if (binaryHeader->e_type != 2) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(newProcess->files[0]); - return; - } - else if (binaryHeader->e_entry == 0x300000) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(newProcess->files[0]); - return; - } - - newProcess->td.abi = binaryHeader->e_ident[EI_OSABI]; - - /* Load The Program Header(s) */ - programHeader = (Elf_Phdr *) kmalloc(sizeof(Elf_Phdr) * binaryHeader->e_phnum); - fseek(newProcess->files[0], binaryHeader->e_phoff, 0); - - fread(programHeader, (sizeof(Elf_Phdr) * binaryHeader->e_phnum), 1, newProcess->files[0]); - - /* Loop Through The Header And Load Sections Which Need To Be Loaded */ - for (i = 0; i < binaryHeader->e_phnum; i++) { - if (programHeader[i].p_type == 1) { - /* - Allocate Memory Im Going To Have To Make This Load Memory With Correct - Settings so it helps us in the future - */ - for (x = 0x0; x < (programHeader[i].p_memsz); x += 0x1000) { - /* Make readonly and read/write !!! */ - if (vmm_remapPage(vmm_findFreePage(newProcess->id), ((programHeader[i].p_vaddr & 0xFFFFF000) + x), PAGE_DEFAULT, newProcess->id, 0) == 0x0) - K_PANIC("Remap Page Failed"); - - memset((void *) ((programHeader[i].p_vaddr & 0xFFFFF000) + x), 0x0, 0x1000); - - } - - /* Now Load Section To Memory */ - fseek(newProcess->files[0], programHeader[i].p_offset, 0); - - fread((void *) programHeader[i].p_vaddr, programHeader[i].p_filesz, 1, newProcess->files[0]); - - if ((programHeader[i].p_flags & 0x2) != 0x2) { - for (x = 0x0; x < (programHeader[i].p_memsz); x += 0x1000) { - if ((vmm_setPageAttributes((programHeader[i].p_vaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) - kpanic("Error: vmm_setPageAttributes failed, File: %s, Line: %i\n", __FILE__, __LINE__); - } - } - } - } - - /* Set Virtual Memory Start */ - newProcess->oInfo.vmStart = 0x80000000; - newProcess->td.vm_daddr = (u_long) (programHeader[i].p_vaddr & 0xFFFFF000); - - /* Set Up Stack Space */ - //MrOlsen (2016-01-14) FIX: is the stack start supposed to be addressable xhcnage x= 1 to x=0 - //x = 0 because GS= stack address not address -1 fix! - for (x = 1; x <= 100; x++) { - vmm_remapPage(vmm_findFreePage(newProcess->id), (STACK_ADDR+1) - (x * PAGE_SIZE), PAGE_DEFAULT | PAGE_STACK, newProcess->id, 0); - bzero((void *)((STACK_ADDR+1) - (x * PAGE_SIZE)), PAGE_SIZE); - } - - /* Kernel Stack 0x2000 bytes long */ - - //vmm_remapPage(vmm_findFreePage(newProcess->id), 0x5BC000, KERNEL_PAGE_DEFAULT | PAGE_STACK, newProcess->id); - //vmm_remapPage(vmm_findFreePage(newProcess->id), 0x5BB000, KERNEL_PAGE_DEFAULT | PAGE_STACK, newProcess->id); - /* - for (x = 0; x < 2; x++) - vmm_remapPage(vmm_findFreePage(newProcess->id), 0xFFFFF000 - (PAGE_SIZE * x), KERNEL_PAGE_DEFAULT | PAGE_STACK, newProcess->id, 0); - */ - - /* Set All The Proper Information For The Task */ - newProcess->tss.back_link = 0x0; - newProcess->tss.esp0 = 0xFFFFFFFF; //0x5BC000; - newProcess->tss.ss0 = 0x10; - newProcess->tss.esp1 = 0x0; - newProcess->tss.ss1 = 0x0; - newProcess->tss.esp2 = 0x0; - newProcess->tss.ss2 = 0x0; - newProcess->tss.eip = (long) binaryHeader->e_entry; - newProcess->tss.eflags = 0x206; - newProcess->tss.esp = STACK_ADDR; - newProcess->tss.ebp = 0x0;//STACK_ADDR; - newProcess->tss.esi = 0x0; - newProcess->tss.edi = 0x0; - - /* Set these up to be ring 3 tasks */ - newProcess->tss.es = 0x30 + 3; - newProcess->tss.cs = 0x28 + 3; - newProcess->tss.ss = 0x30 + 3; - newProcess->tss.ds = 0x30 + 3; - newProcess->tss.fs = 0x30 + 3; - newProcess->tss.gs = 0x8 + 3 + 4;//0x50 + 3; //0x30 + 3; - - newProcess->tss.ldt = 0x18; - newProcess->tss.trace_bitmap = 0x0000; - newProcess->tss.io_map = 0x8000; - - //sched_setStatus(newProcess->id, READY); - - kfree(binaryHeader); - kfree(programHeader); - fclose(newProcess->files[0]); - newProcess->files[0] = 0x0; - - tmp = (uint32_t *) newProcess->tss.esp0 - 5; - - tmp[0] = binaryHeader->e_entry; - tmp[3] = STACK_ADDR - 12; - - newProcess->tss.esp = STACK_ADDR - ARGV_PAGE - ENVP_PAGE - ELF_AUX - (argc + 1) - (envc + 1) - STACK_PAD; - - tmp = (uint32_t *) newProcess->tss.esp; - - tmp[0] = argc; - - uint32_t sp = 0x0; - - for (i = 1; i <= argc; i++) { - tmp[i] = STACK_ADDR - ARGV_PAGE + sp; - strcpy((char *) tmp[i], argv[i - 1]); - sp += strlen(argv[i - 1]) + 1; - } - tmp[i++] = 0x0; - - sp = 0; - - for (int x = 0; x < envc; x++) { - tmp[x + i] = STACK_ADDR - ARGV_PAGE - ENVP_PAGE + sp; - strcpy((char *) tmp[x + i], envp[x]); - sp += strlen(envp[x]) + 1; - } - tmp[i + x] = 0x0; - - /* Build LDT For GS and FS */ - vmm_unmapPage(VMM_USER_LDT, 1); - - if (vmm_remapPage(vmm_findFreePage(newProcess->id), VMM_USER_LDT, PAGE_DEFAULT, newProcess->id, 0) == 0x0) { - K_PANIC("Error: Remap Page Failed"); - } - - struct gdtDescriptor *taskLDT = 0x0; - - taskLDT = (struct gdtDescriptor *)(VMM_USER_LDT + sizeof(struct gdtDescriptor)); - uint32_t data_addr = 0x0; - - taskLDT->limitLow = (0xFFFFF & 0xFFFF); - taskLDT->baseLow = (data_addr & 0xFFFF); - taskLDT->baseMed = ((data_addr >> 16) & 0xFF); - taskLDT->access = ((dData + dWrite + dBig + dBiglim + dDpl3) + dPresent) >> 8; - taskLDT->limitHigh = (0xFFFFF >> 16); - taskLDT->granularity = ((dData + dWrite + dBig + dBiglim + dDpl3) & 0xFF) >> 4; - taskLDT->baseHigh = data_addr >> 24; - - - /* Switch Back To The Kernels VM Space */ - asm volatile( - "movl %0,%%eax \n" - "movl %%eax,%%cr3 \n" - : : "d" ((uint32_t *)(kernelPageDirectory)) - ); - - sprintf(newProcess->oInfo.cwd, "/"); - - //MrOlsen 2018 kprintf("execFile Return: 0x%X - %i\n", newProcess->tss.eip, newProcess->id); - - /* Put new thread into the READY state */ - sched_setStatus(newProcess->id, READY); - - //_current = newProcess; - - /* Finally Return */ - return; -} - -int sys_exec(struct thread *td, char *file, char **argv, char **envp) { - - int i = 0x0; - int x = 0x0; - - int argc = argv_count(argv); - int envc = envp_count(envp); - - uint32_t cr3 = 0x0; - - uint32_t *tmp = 0x0; - - uInt32 seg_size = 0x0; - uInt32 seg_addr = 0x0; - - char *interp = 0x0; - uint32_t ldAddr = 0x0; - - fileDescriptor_t *fd = 0x0; - - Elf_Ehdr *binaryHeader = 0x0; - Elf_Phdr *programHeader = 0x0; - Elf_Shdr *sectionHeader = 0x0; - - elf_file_t ef = 0x0; - - u_long text_addr = 0, text_size = 0; - u_long data_addr = 0, data_size = 0; - - struct i386_frame *iFrame = 0x0; - - asm("movl %%cr3, %0;" : "=r" (cr3)); - - fd = fopen(file, "r"); - - if (fd == 0x0) { - td->td_retval[0] = 2; - return (-1); - } - - /* Test If Executable */ - if (fd->perms == 0) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - fclose(fd); - return (-1); - } - - /* Set Threads FD to open FD */ - _current->files[0] = fd; - - /* Copy In ARGS & ENVS Before Cleaning Virtual Space */ - uint32_t *argv_out = 0x0; - char *args_out = 0x0; - - args_copyin(argv, (char **)&argv_out, &args_out); - - uint32_t *envp_out = 0x0; - char *envs_out = 0x0; - - envs_copyin(envp, (char **)&envp_out, &envs_out); - - //! Clean the virtual of COW pages left over from the fork - //vmm_cleanVirtualSpace( (uint32_t) _current->td.vm_daddr + (_current->td.vm_dsize << PAGE_SHIFT) ); - //MrOlsen 2017-12-15 - FIX! - This should be done before it was causing a lot of problems why did I free space after loading binary???? - //vmm_cleanVirtualSpace((uint32_t) 0x8048000); - vmm_cleanVirtualSpace((uint32_t) VMM_USER_START); - - /* Clear Stack */ - //bzero(STACK_ADDR - (100 * PAGE_SIZE), (PAGE_SIZE * 100)); - for (x = 1; x <= 100; x++) { - vmm_remapPage(vmm_findFreePage(_current->id), (STACK_ADDR+1) - (x * 0x1000), PAGE_DEFAULT | PAGE_STACK, _current->id, 0); - bzero((void *)((STACK_ADDR+1) - (x * 0x1000)), 0x1000); - } - - /* Load ELF Header */ - if ((binaryHeader = (Elf_Ehdr *) kmalloc(sizeof(Elf_Ehdr))) == 0x0) - K_PANIC("MALLOC FAILED"); - - fread(binaryHeader, sizeof(Elf_Ehdr), 1, fd); - /* Done Loading ELF Header */ - - /* Check If App Is A Real Application */ - if ((binaryHeader->e_ident[1] != 'E') && (binaryHeader->e_ident[2] != 'L') && (binaryHeader->e_ident[3] != 'F')) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(fd); - return (-1); - } - else if (binaryHeader->e_type != ET_EXEC) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(fd); - return (-1); - } - else if (binaryHeader->e_entry == 0x300000) { - kprintf("Exec Format Error: Binary File Not Executable.\n"); - kfree(binaryHeader); - fclose(fd); - return (-1); - } - - /* Set Thread ABI */ - td->abi = binaryHeader->e_ident[EI_OSABI]; - - /* Load The Program Header(s) */ - if ((programHeader = (Elf_Phdr *) kmalloc(sizeof(Elf_Phdr) * binaryHeader->e_phnum)) == 0x0) - K_PANIC("MALLOC FAILED"); - - assert(programHeader); - - fseek(fd, binaryHeader->e_phoff, 0); - fread(programHeader, (sizeof(Elf_Phdr) * binaryHeader->e_phnum), 1, fd); - /* Done Loading Program Header(s) */ - - /* Load The Section Header(s) */ - if ((sectionHeader = (Elf_Shdr *) kmalloc(sizeof(Elf_Shdr) * binaryHeader->e_shnum)) == 0x0) - K_PANIC("MALLOC FAILED"); - - assert(sectionHeader); - fseek(fd, binaryHeader->e_shoff, 0); - fread(sectionHeader, sizeof(Elf_Shdr) * binaryHeader->e_shnum, 1, fd); - /* Done Loading Section Header(s) */ - - ef = kmalloc(sizeof(struct elf_file)); - memset(ef, 0x0, sizeof(struct elf_file)); - - /* Loop Through The Header And Load Sections Which Need To Be Loaded */ - for (i = 0; i < binaryHeader->e_phnum; i++) { - switch (programHeader[i].p_type) { - case PT_LOAD: - if (programHeader[i].p_memsz == 0x0) - break; - - seg_addr = trunc_page(programHeader[i].p_vaddr); - seg_size = round_page(programHeader[i].p_memsz + programHeader[i].p_vaddr - seg_addr); - - /* - Allocate Memory Im Going To Have To Make This Load Memory With Correct - Settings so it helps us in the future - */ - for (x = 0x0; x < (round_page(programHeader[i].p_memsz)); x += 0x1000) { - /* Make readonly and read/write !!! */ - if (vmm_remapPage(vmm_findFreePage(_current->id), ((programHeader[i].p_vaddr & 0xFFFFF000) + x), PAGE_DEFAULT, _current->id, 0) == 0x0) { - K_PANIC("Error: Remap Page Failed"); - } - else { - //MrOlsen 2018-01-15 kprintf("rP[0x%X]", (programHeader[i].p_vaddr & 0xFFFFF000) + x); - } - - memset((void *) ((programHeader[i].p_vaddr & 0xFFFFF000) + x), 0x0, 0x1000); - - } - - /* Now Load Section To Memory */ - fseek(fd, programHeader[i].p_offset, 0); - fread((void *) programHeader[i].p_vaddr, programHeader[i].p_filesz, 1, fd); - - if ((programHeader[i].p_flags & 0x2) != 0x2) { - for (x = 0x0; x < (round_page(programHeader[i].p_memsz)); x += 0x1000) { - if ((vmm_setPageAttributes((programHeader[i].p_vaddr & 0xFFFFF000) + x, PAGE_PRESENT | PAGE_USER)) != 0x0) - kpanic("Error: vmm_setPageAttributes failed, File: %s,Line: %i\n", __FILE__, __LINE__); - } - } - - if ((programHeader[i].p_flags & PF_X) && text_size < seg_size) { - //MrOlsen 2018kprintf("setting text: 0x%X - 0x%X\n", seg_addr, seg_size); - text_size = seg_size; - text_addr = seg_addr; - } - else { - //MrOlsen 2018kprintf("setting data: 0x%X - 0x%X\n", seg_addr, seg_size); - data_size = seg_size; - data_addr = seg_addr; - /* - _current->td.vm_dsize = seg_size >> PAGE_SHIFT; - _current->td.vm_daddr = (char *) seg_addr; - kprintf( "setting daddr: 0x%X, dsiize: 0x%X\n", _current->td.vm_daddr, _current->td.vm_dsize ); - */ - } - - /* - * MrOlsen (2016-01-19) NOTE: Note Sure, I should Do This Later - * Thjis is for stack space - */ - _current->oInfo.vmStart = ((programHeader[i].p_vaddr & 0xFFFFF000) + 0xA900000); - break; - case PT_DYNAMIC: - //newLoc = (char *)programHeader[i].phVaddr; - //elfDynamicS = (elfDynamic *) programHeader[i].p_vaddr; - ef->dynamic = (Elf_Dyn *) programHeader[i].p_vaddr; - //fseek( fd, programHeader[i].phOffset, 0 ); - //fread( (void *) programHeader[i].phVaddr, programHeader[i].phFilesz, 1, fd ); - break; - case PT_INTERP: - kprintf("Malloc: %i\n", programHeader[i].p_filesz); - interp = (char *) kmalloc(programHeader[i].p_filesz); - fseek(fd, programHeader[i].p_offset, 0); - fread((void *) interp, programHeader[i].p_filesz, 1, fd); - kprintf("Interp: [%s]\n", interp); - ldAddr = ldEnable(interp); - //ef->ld_addr = ldEnable(); - break; - case PT_GNU_STACK: - asm("nop"); - break; - default: - break; - } - } - - _current->td.vm_tsize = text_size >> PAGE_SHIFT; - _current->td.vm_taddr = text_addr; - _current->td.vm_dsize = data_size >> PAGE_SHIFT; - _current->td.vm_daddr = data_addr; - - //MrOlsen 2018kprintf("Done Looping\n"); - - ef->preloaded = 1; - ef->address = 0x0; - elf_parse_dynamic(ef); - - //asm("cld"); - //irqDisable(0); - iFrame = (struct i386_frame *) (_current->tss.esp0 - sizeof(struct i386_frame)); - - //iFrame->ebp = 0x0; - - if (ldAddr != 0x0) { - iFrame->eip = ldAddr; - } - else { - iFrame->eip = binaryHeader->e_entry; - } - - //iFrame->edx = 0x0; - - iFrame->user_esp = (uint32_t) (STACK_ADDR - ARGV_PAGE - ENVP_PAGE - ELF_AUX - (argc + 1) - (envc + 1) - STACK_PAD) & 0xFFFFF000; - - tmp = (uint32_t *) iFrame->user_esp; - -// memset((char *) tmp, 0x0, ARGV_PAGE + ENVP_PAGE + ELF_AUX + (argc + 1) + (envc + 1) + STACK_PAD); - - tmp[0] = argc; - - uint32_t sp = 0x0; - - char *EXECP = 0x0; - - for (i = 1; i <= argc; i++) { - tmp[i] = (uint32_t) STACK_ADDR - ARGV_PAGE + sp; - if (i == 1) { - EXECP = (char *)tmp[i]; - } - strcpy((char *)tmp[i], (const char *)argv_out[i]); - kprintf("argv[%i]:%s",i, (const char *)argv_out[i]); - sp += strlen((const char *)argv_out[i]) + 1; - } - - tmp[i++] = 0x0; - - kfree(argv_out); - kfree(args_out); - - sp = 0; - - x = 0; - - for (x = 0; x < envc; x++) { - tmp[x + i] = (uint32_t) STACK_ADDR - ARGV_PAGE - ENVP_PAGE + sp; - strcpy((char *) tmp[x + i], (const char *)envp_out[x]); - sp += strlen((const char *)envp_out[x]) + 1; - } - - tmp[i + x] = 0x0; - - kfree(envp_out); - kfree(envs_out); - - i = i + x + 1; - - struct file *tFP = 0x0; - int tFD = 0x0; - - fseek(_current->files[0], 0x0, 0x0); // Reset File Position - falloc(&_current->td, &tFP, &tFD); - - tFP->fd = _current->files[0]; - - - tmp[i++] = 2; - tmp[i++] = -1;// tFD; // _current->imageFd; - _current->td.o_files[4] = _current->files[0]; - //MrOlsen 2018kprintf("AT_EXECFD: [%i:%i]", tmp[i - 1], tFD); - - tmp[i++] = 3; - tmp[i++] = binaryHeader->e_phoff + 0x08048000; - //MrOlsen 2018kprintf("AT_PHDR: [0x%X]", tmp[i - 1]); - - tmp[i++] = 4; - tmp[i++] = binaryHeader->e_phentsize; - //MrOlsen 2018kprintf("AT_PHENT: [0x%X]", tmp[i - 1]); - - tmp[i++] = 5; - tmp[i++] = binaryHeader->e_phnum; - //MrOlsen 2018kprintf("AT_PHNUM: [0x%X]", tmp[i - 1]); - - tmp[i++] = 6; - tmp[i++] = 0x1000; - - tmp[i++] = 7; - tmp[i++] = LD_START; - //MrOlsen 2018kprintf("AT_BASE: [0x%X]", tmp[i - 1]); - - tmp[i++] = 8; - tmp[i++] = 0x0; - - tmp[i++] = 9; - tmp[i++] = binaryHeader->e_entry; - - tmp[i++] = 11; - tmp[i++] = 0x0; - - tmp[i++] = 12; - tmp[i++] = 0x0; - - tmp[i++] = 13; - tmp[i++] = 0x0; - - tmp[i++] = 14; - tmp[i++] = 0x0; - - tmp[i++] = 15; //EXEC PATH - tmp[i++] = (uint32_t)EXECP; - - tmp[i++] = 19; //NCPUS - tmp[i++] = 0x1; - - tmp[i++] = 23; //STACKPROT - tmp[i++] = 0x3; - - tmp[i++] = 0; - tmp[i++] = 0; - - /* Now That We Relocated The Binary We Can Unmap And Free Header Info */ - kfree(binaryHeader); - kfree(programHeader); - //irqEnable(0); - //asm("sti"); - - /* - _current->tss.es = 0x30 + 3; - _current->tss.cs = 0x28 + 3; - _current->tss.ss = 0x30 + 3; - _current->tss.ds = 0x30 + 3; - _current->tss.fs = 0x30 + 3; - _current->tss.gs = 0x50 + 3; //0x30 + 3; - - _current->tss.ldt = 0x18; - _current->tss.trace_bitmap = 0x0000; - _current->tss.io_map = 0x8000; - */ - - /* - kfree (iFrameNew); - - memAddr = (uint32_t) & (_current->tss); - ubixGDT[4].descriptor.baseLow = (memAddr & 0xFFFF); - ubixGDT[4].descriptor.baseMed = ((memAddr >> 16) & 0xFF); - ubixGDT[4].descriptor.baseHigh = (memAddr >> 24); - ubixGDT[4].descriptor.access = '\x89'; - - ubixGDT[10].descriptor.baseLow = (STACK_ADDR & 0xFFFF); - ubixGDT[10].descriptor.baseMed = ((STACK_ADDR >> 16) & 0xFF); - ubixGDT[10].descriptor.baseHigh = (STACK_ADDR >> 24); - - */ - - /* Build LDT For GS and FS */ - vmm_unmapPage(VMM_USER_LDT, 1); // Can I Free This? - if (vmm_remapPage(vmm_findFreePage(_current->id), VMM_USER_LDT, PAGE_DEFAULT, _current->id, 0) == 0x0) { - K_PANIC("Error: Remap Page Failed"); - } - - struct gdtDescriptor *taskLDT = 0x0; - - taskLDT = (struct gdtDescriptor *)(VMM_USER_LDT + sizeof(struct gdtDescriptor)); - - //data_addr = 0x0; //TEMP - - taskLDT->limitLow = (0xFFFFF & 0xFFFF); - taskLDT->baseLow = (data_addr & 0xFFFF); - taskLDT->baseMed = ((data_addr >> 16) & 0xFF); - taskLDT->access = ((dData + dWrite + dBig + dBiglim + dDpl3) + dPresent) >> 8; - taskLDT->limitHigh = (0xFFFFF >> 16); - taskLDT->granularity = ((dData + dWrite + dBig + dBiglim + dDpl3) & 0xFF) >> 4; - taskLDT->baseHigh = data_addr >> 24; - - _current->tss.gs = 0xF; //Select 0x8 + Ring 3 + LDT - _current->pgrp = _current->id; - - return (0x0); -} - -static int elf_parse_dynamic(elf_file_t ef) { - Elf32_Dyn *dynp; - int plttype = DT_REL; - - for (dynp = ef->dynamic; dynp->d_tag != 0x0; dynp++) { - switch (dynp->d_tag) { - case DT_NEEDED: - asm("nop"); - break; - case DT_INIT: - asm("nop"); - break; - case DT_FINI: - asm("nop"); - break; - case DT_HASH: - asm("nop"); - /* From src/libexec/rtld-elf/rtld.c */ - const Elf_Hashelt *hashtab = (const Elf_Hashelt *) (ef->address + dynp->d_un.d_ptr); - ef->nbuckets = hashtab[0]; - ef->nchains = hashtab[1]; - ef->buckets = hashtab + 2; - ef->chains = ef->buckets + ef->nbuckets; - break; - case DT_STRTAB: - ef->strtab = (caddr_t) (ef->address + dynp->d_un.d_ptr); - break; - case DT_STRSZ: - ef->strsz = dynp->d_un.d_val; - break; - case DT_SYMTAB: - ef->symtab = (Elf_Sym *) (ef->address + dynp->d_un.d_ptr); - break; - case DT_SYMENT: - if (dynp->d_un.d_val != sizeof(Elf32_Sym)) - return (ENOEXEC); - break; - case DT_REL: - ef->rel = (const Elf_Rel *) (ef->address + dynp->d_un.d_ptr); - break; - case DT_RELSZ: - ef->relsize = dynp->d_un.d_val; - break; - case DT_RELENT: - if (dynp->d_un.d_val != sizeof(Elf_Rel)) - return (ENOEXEC); - break; - case DT_JMPREL: - ef->pltrel = (const Elf_Rel *) (ef->address + dynp->d_un.d_ptr); - break; - case DT_PLTRELSZ: - ef->pltrelsize = dynp->d_un.d_val; - break; - case DT_RELA: - ef->rela = (const Elf_Rela *) (ef->address + dynp->d_un.d_ptr); - break; - case DT_RELASZ: - ef->relasize = dynp->d_un.d_val; - break; - case DT_RELAENT: - if (dynp->d_un.d_val != sizeof(Elf_Rela)) - return (ENOEXEC); - break; - case DT_PLTREL: - plttype = dynp->d_un.d_val; - if (plttype != DT_REL && plttype != DT_RELA) - return (ENOEXEC); - break; - case DT_PLTGOT: - ef->got = (Elf_Addr *) (ef->address + dynp->d_un.d_ptr); - /* - tmp = (void *) dynp->d_un.d_ptr; //elfDynamicS[i].dynPtr; - tmp[2] = (uInt32) ef->ld_addr; - tmp[1] = (uInt32) ef; //0x0;//0xBEEFEAD;//STACK_ADDR - 128;//_current->imageFd;//0xBEEFDEAD;//ef; - */ - break; - default: - asm("nop"); - //kprintf("t_tag: 0x%X>", dynp->d_tag); - break; - } - } - - if (plttype == DT_RELA) { - ef->pltrela = (const Elf_Rela *) ef->pltrel; - ef->pltrel = NULL; - ef->pltrelasize = ef->pltrelsize; - ef->pltrelsize = 0; - } - - ef->ddbsymtab = ef->symtab; - ef->ddbsymcnt = ef->nchains; - ef->ddbstrtab = ef->strtab; - ef->ddbstrcnt = ef->strsz; - return (0); -} diff --git a/sys/i386/kpanic.c b/sys/i386/kpanic.c deleted file mode 100644 index 4b6ce22..0000000 --- a/sys/i386/kpanic.c +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -/*! - * \brief print panic message and halt system - * - * \param fmt panic message - * - */ -void kpanic(const char *fmt, ...) { - char buf[512]; - va_list args; - - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); - - /* It's important that we print on the current terminal so let's reset foreground */ - tty_foreground = NULL; - kprintf("kPanic: %s", buf); - - /* Halt The System */ - //asm("cli"); - irqDisable(0x0); - - while (1) { - asm("hlt"); - } - -} - -/*** - END - ***/ - diff --git a/sys/i386/memcmp.S b/sys/i386/memcmp.S deleted file mode 100644 index c8e68c2..0000000 --- a/sys/i386/memcmp.S +++ /dev/null @@ -1,66 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - #include - -ENTRY(memcmp) - pushl %edi - pushl %esi - movl 12(%esp),%edi - movl 16(%esp),%esi - cld /* set compare direction forward */ - - movl 20(%esp),%ecx /* compare by words */ - shrl $2,%ecx - repe - cmpsl - jne L5 /* do we match so far? */ - - movl 20(%esp),%ecx /* compare remainder by bytes */ - andl $3,%ecx - repe - cmpsb - jne L6 /* do we match? */ - - xorl %eax,%eax /* we match, return zero */ - popl %esi - popl %edi - ret - -L5: movl $4,%ecx /* We know that one of the next */ - subl %ecx,%edi /* four pairs of bytes do not */ - subl %ecx,%esi /* match. */ - repe - cmpsb -L6: movzbl -1(%edi),%eax /* Perform unsigned comparison */ - movzbl -1(%esi),%edx - subl %edx,%eax - popl %esi - popl %edi - ret -END(memcmp) diff --git a/sys/i386/memset.S b/sys/i386/memset.S deleted file mode 100644 index 03bef8d..0000000 --- a/sys/i386/memset.S +++ /dev/null @@ -1,79 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - #include - - -ENTRY(memset) - pushl %edi - pushl %ebx - movl 12(%esp),%edi - movzbl 16(%esp),%eax /* unsigned char, zero extend */ - movl 20(%esp),%ecx - pushl %edi /* push address of buffer */ - - cld /* set fill direction forward */ - - /* - * if the string is too short, it's really not worth the overhead - * of aligning to word boundries, etc. So we jump to a plain - * unaligned set. - */ - cmpl $0x0f,%ecx - jle L1 - - movb %al,%ah /* copy char to all bytes in word */ - movl %eax,%edx - sall $16,%eax - orl %edx,%eax - - movl %edi,%edx /* compute misalignment */ - negl %edx - andl $3,%edx - movl %ecx,%ebx - subl %edx,%ebx - - movl %edx,%ecx /* set until word aligned */ - rep - stosb - - movl %ebx,%ecx - shrl $2,%ecx /* set by words */ - rep - stosl - - movl %ebx,%ecx /* set remainder by bytes */ - andl $3,%ecx -L1: rep - stosb - - popl %eax /* pop address of buffer */ - popl %ebx - popl %edi - ret -END(memset) diff --git a/sys/i386/sched.c b/sys/i386/sched.c deleted file mode 100644 index 069868d..0000000 --- a/sys/i386/sched.c +++ /dev/null @@ -1,385 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static kTask_t *taskList = 0x0; -static kTask_t *delList = 0x0; -static uint32_t nextID = 1; - -kTask_t *_current = 0x0; -kTask_t *_usedMath = 0x0; - -static struct spinLock schedulerSpinLock = SPIN_LOCK_INITIALIZER; - -int need_resched = 0; - -/************************************************************************ - - Function: int sched_init() - - Description: This function is used to enable the kernel scheduler - - Notes: - - 02/20/2004 - Approved for quality - - ************************************************************************/ - -int sched_init() { - taskList = (kTask_t *) kmalloc(sizeof(kTask_t)); - if (taskList == 0x0) - kpanic("Unable to create task list"); - - taskList->id = nextID++; - - /* Print out information on scheduler */ - kprintf("sched0 - Address: [0x%X]\n", taskList); - - /* Return so we know everything went well */ - return (0x0); -} - -void sched() { - uint32_t memAddr = 0x0; - kTask_t *tmpTask = 0x0; - kTask_t *delTask = 0x0; - - if (spinTryLock(&schedulerSpinLock)) - return; - - tmpTask = ((_current == 0) ? 0 : _current->next); - schedStart: - - /* Yield the next task from the current prio queue */ - for (; tmpTask != 0x0; tmpTask = tmpTask->next) { - if (tmpTask->state == FORK) - tmpTask->state = READY; - - if (tmpTask->state == READY) { - _current->state = (_current->state == DEAD) ? DEAD : READY; - _current = tmpTask; - break; - } - else if (tmpTask->state == DEAD) { - delTask = tmpTask; - if (delTask->parent != 0x0) { - delTask->parent->children -= 1; - delTask->parent->last_exit = delTask->id; - delTask->parent->state = READY; - } - - tmpTask = tmpTask->next; - sched_deleteTask(delTask->id); - sched_addDelTask(delTask); - goto schedStart; - } - } - - /* Finished all the tasks, restarting the list */ - if (0x0 == tmpTask) { - tmpTask = taskList; - goto schedStart; - } - - if (_current->state == READY || _current->state == RUNNING) { - - if (_current->oInfo.v86Task == 0x1) { - irqDisable(0x0); - kprintf("IRQD(%i): 0x%X*0x%X:0x%X@, esp: 0x%X:0x%X, ebp: 0x%X:0x%X ds: 0x%X", _current->id, _current->tss.eflags, _current->tss.cs, _current->tss.eip, _current->tss.ss, _current->tss.esp, _current->tss.ss, _current->tss.ebp,_current->tss.ds); - kprintf("ss0: 0x%X, esp0: 0x%X", _current->tss.ss0, _current->tss.esp0); - } - - asm("cli"); - - memAddr = (uint32_t) &(_current->tss); - ubixGDT[4].descriptor.baseLow = (memAddr & 0xFFFF); - ubixGDT[4].descriptor.baseMed = ((memAddr >> 16) & 0xFF); - ubixGDT[4].descriptor.baseHigh = (memAddr >> 24); - ubixGDT[4].descriptor.access = '\x89'; - - _current->state = RUNNING; - - spinUnlock(&schedulerSpinLock); - - asm("sti"); - asm("ljmp $0x20,$0"); - } - else { - spinUnlock(&schedulerSpinLock); - } - - return; -} - -kTask_t *schedNewTask() { - int i = 0; - - kTask_t *tmpTask = (kTask_t *) kmalloc(sizeof(kTask_t)); - - struct file *fp = 0x0; - - if (tmpTask == 0x0) - kpanic("Error: schedNewTask() - kmalloc failed trying to initialize a new task struct\n"); - - memset(tmpTask, 0x0, sizeof(kTask_t)); - - /* Filling in tasks attrs */ - tmpTask->usedMath = 0x0; - tmpTask->state = NEW; - - /* HACK */ - - for (i = 0; i < 3; i++) { - fp = (void *) kmalloc(sizeof(struct file)); - //kprintf("DB: [0x%X]\n", (uint32_t) fp); - tmpTask->td.o_files[i] = (void *) fp; - fp->f_flag = 0x4; - } - - spinLock(&schedulerSpinLock); - tmpTask->id = nextID++; - tmpTask->next = taskList; - tmpTask->prev = 0x0; - taskList->prev = tmpTask; - taskList = tmpTask; - - spinUnlock(&schedulerSpinLock); - - return (tmpTask); -} - -int sched_deleteTask(pidType id) { - kTask_t *tmpTask = 0x0; - - /* Checking each task from the prio queue */ - for (tmpTask = taskList; tmpTask != 0x0; tmpTask = tmpTask->next) { - if (tmpTask->id == id) { - if (tmpTask->prev != 0x0) - tmpTask->prev->next = tmpTask->next; - if (tmpTask->next != 0x0) - tmpTask->next->prev = tmpTask->prev; - if (taskList == tmpTask) - taskList = tmpTask->next; - - return (0x0); - } - } - return (0x1); -} - -int sched_addDelTask(kTask_t *tmpTask) { - tmpTask->next = delList; - tmpTask->prev = 0x0; - if (delList != 0x0) - delList->prev = tmpTask; - delList = tmpTask; - return (0x0); -} - -kTask_t *sched_getDelTask() { - kTask_t *tmpTask = 0x0; - - if (delList == 0x0) - return (0x0); - - tmpTask = delList; - delList = delList->next; - return (tmpTask); -} - -kTask_t *schedFindTask(uint32_t id) { - kTask_t *tmpTask = 0x0; - - for (tmpTask = taskList; tmpTask; tmpTask = tmpTask->next) { - if (tmpTask->id == id) - return (tmpTask); - } - - return (0x0); -} - -/************************************************************************ - - Function: void schedEndTask() - - Description: This function will end a task - - Notes: - - 02/20/2004 - Approved for quality - - ************************************************************************/ -void schedEndTask(pidType pid) { - endTask(_current->id); - sched_yield(); -} - -/************************************************************************ - - Function: int schedEndTask() - - Description: This function will yield a task - - Notes: - - 02/20/2004 - Approved for quality - - ************************************************************************/ - -void sched_yield() { - sched(); -} - -/* - asm( - ".globl sched_yield \n" - "sched_yield: \n" - " cli \n" - " call sched \n" - ); - */ - -/************************************************************************ - - Function: int sched_setStatus(pidType pid,tState state) - - Description: Change the tasks status - - Notes: - - ************************************************************************/ -int sched_setStatus(pidType pid, tState state) { - kTask_t *tmpTask = schedFindTask(pid); - if (tmpTask == 0x0) - return (0x1); - tmpTask->state = state; - return (0x0); -} - -void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait) { - unsigned long flags; - - save_flags(flags); - cli(); - if (!*p) { - wait->next = wait; - *p = wait; - } - else { - wait->next = (*p)->next; - (*p)->next = wait; - } - restore_flags(flags); -} - -void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait) { - unsigned long flags; - struct wait_queue * tmp; - - save_flags(flags); - cli(); - if ((*p == wait) && ((*p = wait->next) == wait)) { - *p = NULL; - } - else { - tmp = wait; - while (tmp->next != wait) { - tmp = tmp->next; - } - tmp->next = wait->next; - } - wait->next = NULL; - restore_flags(flags); -} - -void wake_up_interruptible(struct wait_queue **q) { - struct wait_queue *tmp; - kTask_t *p; - - if (!q || !(tmp = *q)) - return; - do { - if ((p = tmp->task) != NULL) { - if (p->state == INTERRUPTIBLE) { - p->state = RUNNING; - if (p->counter > _current->counter) - need_resched = 1; - } - } - if (!tmp->next) { - kprintf("wait_queue is bad (eip = %08lx)\n", ((unsigned long *) q)[-1]); - kprintf(" q = %p\n", q); - kprintf(" *q = %p\n", *q); - kprintf(" tmp = %p\n", tmp); - break; - } - tmp = tmp->next; - } while (tmp != *q); -} - -void wake_up(struct wait_queue **q) { - struct wait_queue *tmp; - kTask_t * p; - - if (!q || !(tmp = *q)) - return; - do { - if ((p = tmp->task) != NULL) { - if ((p->state == UNINTERRUPTIBLE) || (p->state == INTERRUPTIBLE)) { - p->state = RUNNING; - if (p->counter > _current->counter) - need_resched = 1; - } - } - if (!tmp->next) { - kprintf("wait_queue is bad (eip = %08lx)\n", ((unsigned long *) q)[-1]); - kprintf(" q = %p\n", q); - kprintf(" *q = %p\n", *q); - kprintf(" tmp = %p\n", tmp); - break; - } - tmp = tmp->next; - } while (tmp != *q); -} diff --git a/sys/i386/schedyield.S b/sys/i386/schedyield.S deleted file mode 100644 index 1072793..0000000 --- a/sys/i386/schedyield.S +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -.globl sched_yield_new -.text -.code32 -sched_yield_new: - pusha /* Save all of the registers */ - push %ss - push %ds - push %es - push %fs - push %gs - call sched - mov %eax,%esp - pop %gs - pop %fs - pop %es - pop %ds - pop %ss - popa /* Restore Registers */ - iret - -/*** - END - ***/ diff --git a/sys/i386/spinlock.c b/sys/i386/spinlock.c deleted file mode 100644 index db6653d..0000000 --- a/sys/i386/spinlock.c +++ /dev/null @@ -1,71 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -#define atomic_xadd(P, V) __sync_fetch_and_add((P), (V)) -#define cmpxchg(P, O, N) __sync_val_compare_and_swap((P), (O), (N)) -#define atomic_inc(P) __sync_add_and_fetch((P), 1) -#define atomic_dec(P) __sync_add_and_fetch((P), -1) -#define atomic_add(P, V) __sync_add_and_fetch((P), (V)) -#define atomic_set_bit(P, V) __sync_or_and_fetch((P), 1<<(V)) -#define atomic_clear_bit(P, V) __sync_and_and_fetch((P), ~(1<<(V))) - -#define barrier() asm volatile("": : :"memory") - -/* Pause instruction to prevent excess processor bus usage */ -#define cpu_relax() asm volatile("pause\n": : :"memory") - -void spinLockInit(spinLock_t lock) { - memset(lock, 0x0, sizeof(struct spinLock)); -} - -int spinTryLock(spinLock_t lock) { - if (!cmpxchg(&lock->locked, NULL, LLOCK_FLAG)) - return 0; - - /* Failure! */ - return LOCKED; -} - -void spinUnlock(spinLock_t lock) { - barrier(); - lock->locked = 0x0; -} - -void spinLock(spinLock_t lock) { - while (1) { - if (!xchg_32(&lock->locked, LOCKED)) - return; - while (lock->locked == 1) - sched_yield(); - } -} - diff --git a/sys/i386/strcmp.S b/sys/i386/strcmp.S deleted file mode 100644 index 19bb2ff..0000000 --- a/sys/i386/strcmp.S +++ /dev/null @@ -1,98 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - #include - -ENTRY(strcmp) - movl 0x04(%esp),%eax - movl 0x08(%esp),%edx - jmp L2 /* Jump into the loop! */ - - .align 2,0x90 -L1: incl %eax - incl %edx -L2: movb (%eax),%cl - testb %cl,%cl - je L3 - cmpb %cl,(%edx) - jne L3 - incl %eax - incl %edx - movb (%eax),%cl - testb %cl,%cl - je L3 - cmpb %cl,(%edx) - jne L3 - incl %eax - incl %edx - movb (%eax),%cl - testb %cl,%cl - je L3 - cmpb %cl,(%edx) - jne L3 - incl %eax - incl %edx - movb (%eax),%cl - testb %cl,%cl - je L3 - cmpb %cl,(%edx) - jne L3 - incl %eax - incl %edx - movb (%eax),%cl - testb %cl,%cl - je L3 - cmpb %cl,(%edx) - jne L3 - incl %eax - incl %edx - movb (%eax),%cl - testb %cl,%cl - je L3 - cmpb %cl,(%edx) - jne L3 - incl %eax - incl %edx - movb (%eax),%cl - testb %cl,%cl - je L3 - cmpb %cl,(%edx) - jne L3 - incl %eax - incl %edx - movb (%eax),%cl - testb %cl,%cl - je L3 - cmpb %cl,(%edx) - je L1 - .align 2, 0x90 -L3: movzbl (%eax),%eax /* unsigned comparison */ - movzbl (%edx),%edx - subl %edx,%eax - ret -END(strcmp) diff --git a/sys/i386/strcpy.S b/sys/i386/strcpy.S deleted file mode 100644 index e6f6a0c..0000000 --- a/sys/i386/strcpy.S +++ /dev/null @@ -1,73 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - #include - - ENTRY(strcpy) - movl 4(%esp),%ecx /* dst address */ - movl 8(%esp),%edx /* src address */ - pushl %ecx /* push dst address */ - - .align 2,0x90 -L1: movb (%edx),%al /* unroll loop, but not too much */ - movb %al,(%ecx) - testb %al,%al - je L2 - movb 1(%edx),%al - movb %al,1(%ecx) - testb %al,%al - je L2 - movb 2(%edx),%al - movb %al,2(%ecx) - testb %al,%al - je L2 - movb 3(%edx),%al - movb %al,3(%ecx) - testb %al,%al - je L2 - movb 4(%edx),%al - movb %al,4(%ecx) - testb %al,%al - je L2 - movb 5(%edx),%al - movb %al,5(%ecx) - testb %al,%al - je L2 - movb 6(%edx),%al - movb %al,6(%ecx) - testb %al,%al - je L2 - movb 7(%edx),%al - movb %al,7(%ecx) - addl $8,%edx - addl $8,%ecx - testb %al,%al - jne L1 -L2: popl %eax /* pop dst address */ - ret -END(strcpy) diff --git a/sys/i386/strncmp.S b/sys/i386/strncmp.S deleted file mode 100644 index 9696281..0000000 --- a/sys/i386/strncmp.S +++ /dev/null @@ -1,129 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - #include - -ENTRY(strncmp) - pushl %ebx - movl 8(%esp),%eax - movl 12(%esp),%ecx - movl 16(%esp),%edx - testl %edx,%edx - jmp L2 /* Jump into the loop! */ - - .align 2,0x90 -L1: incl %eax - incl %ecx - decl %edx -L2: jz L4 /* strings are equal */ - movb (%eax),%bl - testb %bl,%bl - jz L3 - cmpb %bl,(%ecx) - jne L3 - incl %eax - incl %ecx - decl %edx - jz L4 - movb (%eax),%bl - testb %bl,%bl - jz L3 - cmpb %bl,(%ecx) - jne L3 - - incl %eax - incl %ecx - decl %edx - jz L4 - movb (%eax),%bl - testb %bl,%bl - jz L3 - cmpb %bl,(%ecx) - jne L3 - - incl %eax - incl %ecx - decl %edx - jz L4 - movb (%eax),%bl - testb %bl,%bl - jz L3 - cmpb %bl,(%ecx) - jne L3 - - incl %eax - incl %ecx - decl %edx - jz L4 - movb (%eax),%bl - testb %bl,%bl - jz L3 - cmpb %bl,(%ecx) - jne L3 - - incl %eax - incl %ecx - decl %edx - jz L4 - movb (%eax),%bl - testb %bl,%bl - jz L3 - cmpb %bl,(%ecx) - jne L3 - - incl %eax - incl %ecx - decl %edx - jz L4 - movb (%eax),%bl - testb %bl,%bl - jz L3 - cmpb %bl,(%ecx) - jne L3 - - incl %eax - incl %ecx - decl %edx - jz L4 - movb (%eax),%bl - testb %bl,%bl - jz L3 - cmpb %bl,(%ecx) - je L1 - - .align 2,0x90 -L3: movzbl (%eax),%eax /* unsigned comparison */ - movzbl (%ecx),%ecx - subl %ecx,%eax - popl %ebx - ret - .align 2,0x90 -L4: xorl %eax,%eax - popl %ebx - ret -END(strncmp) diff --git a/sys/i386/support.S b/sys/i386/support.S deleted file mode 100644 index 347cdf8..0000000 --- a/sys/i386/support.S +++ /dev/null @@ -1,120 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - #include -.text - -// void bzero(void *buf, u_int len) -ENTRY(bzero) - pushl %edi - movl 8(%esp),%edi - movl 12(%esp),%ecx - xorl %eax,%eax - shrl $2,%ecx - cld - rep - stosl - movl 12(%esp),%ecx - andl $3,%ecx - rep - stosb - popl %edi - ret -END(bzero) - -// bcopy(src, dst, cnt) -ENTRY(bcopy) - pushl %ebp - movl %esp,%ebp - pushl %esi - pushl %edi - movl 8(%ebp),%esi - movl 12(%ebp),%edi - movl 16(%ebp),%ecx - - movl %edi,%eax - subl %esi,%eax - cmpl %ecx,%eax /* overlapping && src < dst? */ - jb 1f - - shrl $2,%ecx /* copy by 32-bit words */ - cld /* nope, copy forwards */ - rep - movsl - movl 16(%ebp),%ecx - andl $3,%ecx /* any bytes left? */ - rep - movsb - popl %edi - popl %esi - popl %ebp - ret - - ALIGN_TEXT -1: - addl %ecx,%edi /* copy backwards */ - addl %ecx,%esi - decl %edi - decl %esi - andl $3,%ecx /* any fractional bytes? */ - std - rep - movsb - movl 16(%ebp),%ecx /* copy remainder by 32-bit words */ - shrl $2,%ecx - subl $3,%esi - subl $3,%edi - rep - movsl - popl %edi - popl %esi - cld - popl %ebp - ret -END(bcopy) - -// void *memcpy(const void *dst, const void * src, size_t length) -ENTRY(memcpy) - pushl %edi - pushl %esi - movl 12(%esp),%edi - movl 16(%esp),%esi - movl 20(%esp),%ecx - movl %edi,%eax - shrl $2,%ecx /* copy by 32-bit words */ - cld /* nope, copy forwards */ - rep - movsl - movl 20(%esp),%ecx - andl $3,%ecx /* any bytes left? */ - rep - movsb - popl %esi - popl %edi - ret -END(memcpy) diff --git a/sys/i386/sys_call.S b/sys/i386/sys_call.S deleted file mode 100644 index 7844128..0000000 --- a/sys/i386/sys_call.S +++ /dev/null @@ -1,109 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -.globl _sys_call -.text -.code32 - -_B4: -_B3: -nop - -_ast: - -_astRet: - -_sysCall_MrOlsen: -//MrOlsen 2018-01-14 push $0x2 -//MrOlsen 2018-01-14 sub $0x4,%esp -pusha -push %ds -push %es -push %fs -push %gs -mov $0x10,%eax -mov %eax,%ds -mov %eax,%es -mov %eax,%fs -cld -push %esp -call sys_call -add $0x4,%esp -cmpb $0x13,0x38(%esp) -je _B4 -testl $0x2000,0x3c(%esp) /* Test If VM */ -jz _notVM -jmp _isVM -_notVM: -testb $0x3,0x38(%esp) /* See If We're In User CS (GDT Entry 5) */ -jz _popFS -jmp _popFS /* TMP BECAUSE ABOVE ISN'T RIGHT */ -cli -mov %fs:0x0,%eax -testl $0x10800,0x80(%eax) /* Document This */ -je _popFS -sti -push %esp -call _ast -add $0x4,%esp -jmp _astRet -_isVM: -hlt - -_popFS: -pop %gs -pop %fs -pop %es -pop %ds -popa -//MrOlsen 2018-01-14 add $0x8,%esp -iret - -_sys_call: -push $0x0 -push $0x80 -pusha -push %ds -push %es -push %fs -push %gs -mov $0x10,%eax -mov %eax, %ds -mov %eax, %es -mov %eax, %fs -cld -push %esp -call sys_call -add $0x4,%esp /* Remove Stack Pointer From Stack */ -pop %gs -pop %fs -pop %es -pop %ds -popa -add $0x8,%esp //Back Out Error Code & trap_no -iret diff --git a/sys/i386/sys_call_posix.S b/sys/i386/sys_call_posix.S deleted file mode 100644 index d9b082f..0000000 --- a/sys/i386/sys_call_posix.S +++ /dev/null @@ -1,57 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define FAKE_MCOUNT(caller) pushl caller ; call __mcount ; popl %ecx - -.globl _sys_call_posix -.text -.code32 - -_sys_call_posix: -push $0x0 -push $0x80 -pusha -push %ds -push %es -push %fs -push %gs -mov $0x10,%eax -mov %eax, %ds -mov %eax, %es -mov %eax, %fs -cld -push %esp -call sys_call_posix -add $0x4,%esp /* Remove Stack Pointer From Stack */ -pop %gs -pop %fs -pop %es -pop %ds -popa -add $0x8,%esp //Back Out Error Code & trap_no -iret diff --git a/sys/i386/systemtask.c b/sys/i386/systemtask.c deleted file mode 100644 index 952fc06..0000000 --- a/sys/i386/systemtask.c +++ /dev/null @@ -1,131 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned char *videoBuffer = (unsigned char *) 0xB8000; - -void systemTask() { - - mpi_message_t myMsg; - uint32_t counter = 0x0; - int i = 0x0; - int *x = 0x0; - kTask_t *tmpTask = 0x0; - - char buf[16] = { "a\n" }; - - if (mpi_createMbox("system") != 0x0) { - kpanic("Error: Error creating mailbox: system\n"); - } - - while (1) { - if (mpi_fetchMessage("system", &myMsg) == 0x0) { - switch (myMsg.header) { - case 0x69: - x = (int *) &myMsg.data; - kprintf("Switching to term: [%i][%i]\n", *x, myMsg.pid); - schedFindTask(myMsg.pid)->term = tty_find(*x); - break; - case 1000: - kprintf("Restarting the system in 5 seconds\n"); - counter = systemVitals->sysUptime + 5; - while (systemVitals->sysUptime < counter) { - sched_yield(); - } - kprintf("Rebooting NOW!!!\n"); - while (inportByte(0x64) & 0x02) - ; - outportByte(0x64, 0xFE); - break; - case 31337: - kprintf("system: backdoor opened\n"); - break; - case 0x80: - if (!strcmp(myMsg.data, "sdeStart")) { - kprintf("Starting SDE\n"); - execThread(sdeThread,0x2000,0x0); - } - else if (!strcmp(myMsg.data, "freePage")) { - kprintf("kkk Free Pages"); - } - else if (!strcmp(myMsg.data, "sdeStop")) { - printOff = 0x0; - biosCall(0x10, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0); - for (i = 0x0; i < 100; i++) - asm("hlt"); - } - break; - default: - kprintf("system: Received message %i:%s\n", myMsg.header, myMsg.data); - break; - } - } - - /* - Here we get the next task from the delete task queue - we first check to see if it has an fd attached for the binary and after that - we free the pages for the process and then free the task - */ - tmpTask = sched_getDelTask(); - - if (tmpTask != 0x0) { - if (tmpTask->files[0] != 0x0) - fclose(tmpTask->files[0]); - vmm_freeProcessPages(tmpTask->id); - kfree(tmpTask); - - } - - if (ogprintOff == 1) { - videoBuffer[0] = systemVitals->sysTicks; - videoBuffer[1] = 'c'; - } - /* - else - ogPrintf(buf); - */ - - sched_yield(); - } - - return; -} diff --git a/sys/i386/timer.S b/sys/i386/timer.S deleted file mode 100644 index 1ddfcc1..0000000 --- a/sys/i386/timer.S +++ /dev/null @@ -1,75 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -.globl timerInt -.text -.code32 -timerInt: - pusha /* Save all of the registers */ - mov $0x20,%dx /* The Following Sends Our EOI To The MPIC */ - mov $0x20,%ax - outb %al,%dx - movl systemVitals,%ecx /* Put Location Of System Vitals Into ECX */ - incl (%ecx) /* Increment sysTicks our 1000ms counter */ - movl (%ecx),%eax /* Increment our sysUptime by 1S if 1000MS */ - movl $200,%ebx /* Have Passed */ - xor %edx,%edx - div %ebx - test %edx,%edx - jnz next - incl 4(%ecx) -next: - movl (%ecx),%eax /* Test If quantum Has Passed If So Then */ - movl 8(%ecx),%ebx /* We Can CALL sched */ - xor %edx,%edx - div %ebx - test %edx,%edx - jnz done -/* -push %ds -push %es -push %fs -push %gs -mov $0x10,%eax -mov %eax, %ds -mov %eax, %es -mov %eax, %fs -cld -*/ -/* push %esp */ - call sched -/* add $0x4,%esp */ /* Remove Stack Pointer From Stack */ -/* -pop %gs -pop %fs -pop %es -pop %ds -*/ -done: - popa /* Restore Registers */ - iret diff --git a/sys/i386/trap.c b/sys/i386/trap.c deleted file mode 100644 index de1a2c4..0000000 --- a/sys/i386/trap.c +++ /dev/null @@ -1,134 +0,0 @@ -/*- - * Copyright (c) 2002-2018 The UbixOS Project. - * All rights reserved. - * - * This was developed by Christopher W. Olsen for the UbixOS Project. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1) Redistributions of source code must retain the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors. - * 2) Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions, the following disclaimer and the list of authors in the documentation and/or - * other materials provided with the distribution. - * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define FIRST_TSS_ENTRY 6 -#define VM_MASK 0x00020000 - -#define store_TR(n) \ - __asm__("str %%ax\n\t" \ - "subl %2,%%eax\n\t" \ - "shrl $4,%%eax" \ - :"=a" (n) \ - :"0" (0),"i" (FIRST_TSS_ENTRY<<3)) - -#define get_seg_long(seg,addr) ({ \ - register unsigned long __res; \ - __asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ - :"=a" (__res):"0" (seg),"m" (*(addr))); \ - __res;}) - -#define get_seg_byte(seg,addr) ({ \ -register char __res; \ -__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ - :"=a" (__res):"0" (seg),"m" (*(addr))); \ -__res;}) - -void die_if_kernel(char *str, struct trapframe *regs, long err) { - int i; - unsigned long esp; - unsigned short ss; - unsigned long *stack; - - esp = (unsigned long) ®s->tf_esp; - - ss = 0x10; //KERNEL_DS - - //if ((regs->tf_eflags & VM_MASK) || (3 & regs->tf_cs) == 3) - // return; - - if ((regs->tf_cs & 3) == 3) { - esp = regs->tf_esp; - ss = regs->tf_ss; - kprintf("USER TASK!"); - } - else { - ss = 0x10; - } - - kprintf("\n%s: 0x%X:%i, CPU %d, EIP: 0x%X, EFLAGS: 0x%X\n", str, regs->tf_err, regs->tf_trapno, 0x0, regs->tf_eip, regs->tf_eflags); - kprintf("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->tf_eax, regs->tf_ebx, regs->tf_ecx, regs->tf_edx); - kprintf("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", regs->tf_esi, regs->tf_edi, regs->tf_ebp, esp); - kprintf("cs: 0x%X ds: 0x%X es: 0x%X fs: 0x%X gs: 0x%X ss: 0x%X\n", regs->tf_cs, regs->tf_ds, regs->tf_es, regs->tf_fs, regs->tf_gs, ss); - kprintf("cr0: 0x%X, cr2: 0x%X, cr3: 0x%X, cr4: 0x%X\n", rcr0(), rcr2(), rcr3(), rcr4()); - - store_TR(i); - kprintf("Process %s (pid: %i, process nr: %d, stackpage=%08lx)\nStack:", _current->name, _current->id, 0xffff & i, esp); - - stack = (unsigned long *) esp; - - for (i = 0; i < 16; i++) { - if (i && ((i % 8) == 0)) - kprintf("\n "); - kprintf("%08lx ", get_seg_long(ss, stack++)); - } - - endTask(_current->id); -} - -void trap(struct trapframe *frame) { - u_int trap_code; - u_int cr2 = 0; - - trap_code = frame->tf_trapno; - - cr2 = rcr2(); - kprintf("CR2: 0x%X(0x%X)[0x%X]", cr2, _current->tss.eip, _current->tss.ldt); - if (_current->id == 7) - while (1) - asm("nop"); - - if ((frame->tf_eflags & PSL_I) == 0) { - if (SEL_GET_PL(frame->tf_cs) == SEL_PL_USER || (frame->tf_eflags & PSL_VM)) { - kpanic("INT OFF! USER"); - die_if_kernel("TEST", frame, 0x100); - } - else { - kpanic("INT OFF! KERN[0x%X]", trap_code); - die_if_kernel("TEST", frame, 0x200); - } - } - - kprintf("trap_code: %i(0x%X), EIP: 0x%X, CR2: 0x%X\n", frame->tf_trapno, frame->tf_trapno, frame->tf_eip, cr2); - if (frame->tf_trapno == 0xc) { - vmm_pageFault(frame, cr2); - } - else { - kpanic("TRAPCODE"); - die_if_kernel("trapCode", frame, frame->tf_trapno); - endTask(_current->id); - sched_yield(); - } -} diff --git a/sys/include/lib/kern_trie.h b/sys/include/lib/kern_trie.h new file mode 100644 index 0000000..07e8171 --- /dev/null +++ b/sys/include/lib/kern_trie.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LIB_KERN_TRIE_H_ +#define _LIB_KERN_TRIE_H_ + +#include + +#define CHAR_SIZE 26 + +struct Trie { + u_int8_t isLeaf; + struct Trie *character[CHAR_SIZE]; + void *e; +}; + + +struct Trie *new_trieNode(); + +void insert_trieNode(struct Trie **, char *, void *); + +struct Trie *search_trieNode(struct Trie *, char *); + +int delete_trieNode(struct Trie **, char *); + +#endif _LIB_LKERN_TRIE_H_ diff --git a/sys/include/objgfx/ogDisplay_VESA.h b/sys/include/objgfx/ogDisplay_VESA.h old mode 100755 new mode 100644 diff --git a/sys/include/sde/ogDisplay_UbixOS.h b/sys/include/sde/ogDisplay_UbixOS.h old mode 100755 new mode 100644 diff --git a/sys/include/sys/_null.h b/sys/include/sys/_null.h new file mode 100644 index 0000000..b290b3f --- /dev/null +++ b/sys/include/sys/_null.h @@ -0,0 +1,19 @@ +#ifndef NULL + +#if !defined(__cplusplus) +#define NULL ((void *)0) +#else +#if __cplusplus >= 201103L +#define NULL nullptr +#elif defined(__GNUG__) && defined(__GNUC__) && __GNUC__ >= 4 +#define NULL __null +#else +#if defined(__LP64__) +#define NULL (0L) +#else +#define NULL 0 +#endif /* __LP64__ */ +#endif /* __GNUG__ */ +#endif /* !__cplusplus */ + +#endif diff --git a/sys/include/sys/_types.h b/sys/include/sys/_types.h index c998ff6..2cfb128 100644 --- a/sys/include/sys/_types.h +++ b/sys/include/sys/_types.h @@ -29,6 +29,7 @@ #ifndef _SYS__TYPES_H_ #define _SYS__TYPES_H_ + typedef char __int8_t; typedef unsigned char __uint8_t; typedef short __int16_t; @@ -38,6 +39,10 @@ typedef long long __int64_t; typedef unsigned long long __uint64_t; +typedef __int64_t __rlim_t; /* resource limit - intentionally */ + /* signed, because of legacy code */ + /* that uses -1 for RLIM_INFINITY */ + typedef unsigned long __clock_t; typedef __uint32_t __ino_t; typedef __int32_t __ssize_t;/* stat types */ typedef __uint32_t __dev_t;/* device number */ diff --git a/sys/include/sys/descrip.h b/sys/include/sys/descrip.h index 9953efd..af2d2e5 100644 --- a/sys/include/sys/descrip.h +++ b/sys/include/sys/descrip.h @@ -35,64 +35,20 @@ #include #include +#include + /* Limits */ #define MAX_FILES 256 typedef __mode_t mode_t; typedef __nlink_t nlink_t; -/* command values */ -#define F_DUPFD 0 /* duplicate file descriptor */ -#define F_GETFD 1 /* get file descriptor flags */ -#define F_SETFD 2 /* set file descriptor flags */ -#define F_GETFL 3 /* get file status flags */ -#define F_SETFL 4 /* set file status flags */ -#define F_GETOWN 5 /* get SIGIO/SIGURG proc/pgrp */ -#define F_SETOWN 6 /* set SIGIO/SIGURG proc/pgrp */ -#define F_GETLK 7 /* get record locking information */ -#define F_SETLK 8 /* set record locking information */ -#define F_SETLKW 9 /* F_SETLK; wait if blocked */ - -/* Flag Values */ -#define FREAD 0x0001 -#define FWRITE 0x0002 -#define O_NONBLOCK 0x0004 /* no delay */ -#define O_APPEND 0x0008 /* set append mode */ -#define O_SHLOCK 0x0010 /* open with shared file lock */ -#define O_EXLOCK 0x0020 /* open with exclusive file lock */ -#define O_ASYNC 0x0040 /* signal pgrp when data ready */ -#define O_FSYNC 0x0080 /* synchronous writes */ -#define O_SYNC 0x0080 /* POSIX synonym for O_FSYNC */ -#define O_NOFOLLOW 0x0100 /* don't follow symlinks */ -#define O_CREAT 0x0200 /* create if nonexistent */ -#define O_TRUNC 0x0400 /* truncate to zero length */ -#define O_EXCL 0x0800 /* error if already exists */ -#define O_DIRECT 0x00010000 -#define O_RDONLY 0x0000 /* open for reading only */ -#define O_WRONLY 0x0001 /* open for writing only */ -#define O_RDWR 0x0002 /* open for reading and writing */ -#define O_ACCMODE 0x0003 /* mask for above modes */ - -#define FHASLOCK 0x4000 /* descriptor holds advisory lock */ - -/* F MAPPERS */ -#define FAPPEND O_APPEND /* kernel/compat */ -#define FASYNC O_ASYNC /* kernel/compat */ -#define FFSYNC O_FSYNC /* kernel */ -#define FNONBLOCK O_NONBLOCK /* kernel */ -#define FNDELAY O_NONBLOCK /* compat */ -#define O_NDELAY O_NONBLOCK /* compat */ -#define FPOSIXSHM O_NOFOLLOW - -#define FCNTLFLAGS (FAPPEND|FASYNC|FFSYNC|FNONBLOCK|FPOSIXSHM|O_DIRECT) - -#define FFLAGS(oflags) ((oflags) + 1) -#define OFLAGS(fflags) ((fflags) - 1) - struct fileOps; struct file; -struct uio; //TMP -struct ucred; //TMP +struct uio; +//TMP +struct ucred; +//TMP /* Function Protos */ typedef int fo_rdwr_t(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags, struct thread *td); @@ -100,11 +56,11 @@ typedef int fo_close_t(struct file *fp, struct thread *td); struct ucred { - char pad; + char pad; }; struct uio { - char pad; + char pad; }; struct file { @@ -114,6 +70,7 @@ fileDescriptor_t *fd; int fd_type; int socket; + void *data; }; struct fileOps { @@ -179,6 +136,8 @@ int ioctl(struct thread *, struct ioctl_args *); int getfd(struct thread *td, struct file **fp, int fd); +int_kern_openat(struct thread *, int, char *, int); + #endif /*** diff --git a/sys/include/sys/errno.h b/sys/include/sys/errno.h new file mode 100644 index 0000000..87c1218 --- /dev/null +++ b/sys/include/sys/errno.h @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_ERRNO_H_ +#define _SYS_ERRNO_H_ + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* Input/output error */ +#define ENXIO 6 /* Device not configured */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EDEADLK 11 /* Resource deadlock avoided */ +/* 11 was EAGAIN */ +#define ENOMEM 12 /* Cannot allocate memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ + +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* Operation not supported by device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ +#define ETXTBSY 26 /* Text file busy */ + +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only filesystem */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ + +/* math software */ +#define EDOM 33 /* Numerical argument out of domain */ +#define ERANGE 34 /* Result too large */ + +/* non-blocking and interrupt i/o */ +#define EAGAIN 35 /* Resource temporarily unavailable */ + +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported */ +#define ENOTSUP EOPNOTSUPP /* Operation not supported */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Operation timed out */ +#define ECONNREFUSED 61 /* Connection refused */ + +#define ELOOP 62 /* Too many levels of symbolic links */ + +#define ENAMETOOLONG 63 + +/* should be rearranged */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ + +/* quotas & mush */ +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ + +/* Network File System */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ + +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ + +#define EFTYPE 79 /* Inappropriate file type or format */ +#define EAUTH 80 /* Authentication error */ +#define ENEEDAUTH 81 /* Need authenticator */ +#define EIDRM 82 /* Identifier removed */ +#define ENOMSG 83 /* No message of desired type */ +#define EOVERFLOW 84 /* Value too large to be stored in data type */ +#define ECANCELED 85 /* Operation canceled */ +#define EILSEQ 86 /* Illegal byte sequence */ +#define ENOATTR 87 /* Attribute not found */ + +#define EDOOFUS 88 /* Programming error */ + +#define EBADMSG 89 /* Bad message */ +#define EMULTIHOP 90 /* Multihop attempted */ +#define ENOLINK 91 /* Link has been severed */ +#define EPROTO 92 /* Protocol error */ + +#define ENOTCAPABLE 93 /* Capabilities insufficient */ +#define ECAPMODE 94 /* Not permitted in capability mode */ +#define ENOTRECOVERABLE 95 /* State not recoverable */ +#define EOWNERDEAD 96 /* Previous owner died */ + +#define ELAST 96 /* Must be equal largest errno */ + +#endif /* !_SYS_ERNRO_H_ */ diff --git a/sys/include/sys/fcntl.h b/sys/include/sys/fcntl.h new file mode 100644 index 0000000..985cc79 --- /dev/null +++ b/sys/include/sys/fcntl.h @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_FCNTL_H_ +#define _SYS_FCNTL_H_ + +#define AT_FDCWD -100 + +/* command values */ +#define F_DUPFD 0 /* duplicate file descriptor */ +#define F_GETFD 1 /* get file descriptor flags */ +#define F_SETFD 2 /* set file descriptor flags */ +#define F_GETFL 3 /* get file status flags */ +#define F_SETFL 4 /* set file status flags */ +#define F_GETOWN 5 /* get SIGIO/SIGURG proc/pgrp */ +#define F_SETOWN 6 /* set SIGIO/SIGURG proc/pgrp */ +#define F_GETLK 7 /* get record locking information */ +#define F_SETLK 8 /* set record locking information */ +#define F_SETLKW 9 /* F_SETLK; wait if blocked */ + +/* Flag Values */ +#define FREAD 0x0001 +#define FWRITE 0x0002 +#define O_NONBLOCK 0x0004 /* no delay */ +#define O_APPEND 0x0008 /* set append mode */ +#define O_SHLOCK 0x0010 /* open with shared file lock */ +#define O_EXLOCK 0x0020 /* open with exclusive file lock */ +#define O_ASYNC 0x0040 /* signal pgrp when data ready */ +#define O_FSYNC 0x0080 /* synchronous writes */ +#define O_SYNC 0x0080 /* POSIX synonym for O_FSYNC */ +#define O_NOFOLLOW 0x0100 /* don't follow symlinks */ +#define O_CREAT 0x0200 /* create if nonexistent */ +#define O_TRUNC 0x0400 /* truncate to zero length */ +#define O_EXCL 0x0800 /* error if already exists */ +#define O_DIRECT 0x00010000 +#define O_RDONLY 0x0000 /* open for reading only */ +#define O_WRONLY 0x0001 /* open for writing only */ +#define O_RDWR 0x0002 /* open for reading and writing */ +#define O_ACCMODE 0x0003 /* mask for above modes */ + +#define FHASLOCK 0x4000 /* descriptor holds advisory lock */ + +/* F MAPPERS */ +#define FAPPEND O_APPEND /* kernel/compat */ +#define FASYNC O_ASYNC /* kernel/compat */ +#define FFSYNC O_FSYNC /* kernel */ +#define FNONBLOCK O_NONBLOCK /* kernel */ +#define FNDELAY O_NONBLOCK /* compat */ +#define O_NDELAY O_NONBLOCK /* compat */ +#define FPOSIXSHM O_NOFOLLOW + +#define O_DIRECTORY 0x00020000 /* Fail if not directory */ +#define O_EXEC 0x00040000 /* Open for execute only */ + +#define FCNTLFLAGS (FAPPEND|FASYNC|FFSYNC|FNONBLOCK|FPOSIXSHM|O_DIRECT) + +/* + #define FFLAGS(oflags) ((oflags) + 1) + #define OFLAGS(fflags) ((fflags) - 1) + */ + +/* convert from open() flags to/from fflags; convert O_RD/WR to FREAD/FWRITE */ +#define FFLAGS(oflags) ((oflags) & O_EXEC ? (oflags) : (oflags) + 1) +#define OFLAGS(fflags) ((fflags) & O_EXEC ? (fflags) : (fflags) - 1) + +#define FMASK (FREAD|FWRITE|FAPPEND|FASYNC|FFSYNC|FNONBLOCK|O_DIRECT|FEXEC) + +#endif /* !_SYS_FCNTL_H_ */ diff --git a/sys/include/sys/kern_sysctl.h b/sys/include/sys/kern_sysctl.h index 9aeb258..2820992 100644 --- a/sys/include/sys/kern_sysctl.h +++ b/sys/include/sys/kern_sysctl.h @@ -61,6 +61,8 @@ int id; void *value; int val_len; + int full_name[CTL_MAXNAME]; + int namelen; }; int kern_sysctl(int *name,u_int namelen,void *old,size_t *oldlenp,void *new,size_t newlen,size_t *retval,int flags); diff --git a/sys/include/sys/pipe.h b/sys/include/sys/pipe.h index dff67de..4de1505 100644 --- a/sys/include/sys/pipe.h +++ b/sys/include/sys/pipe.h @@ -34,4 +34,22 @@ int pipe(struct thread *, struct pipe_args *); +struct pipeBuf { + struct pipeBuf *next; + char *buffer; + size_t nbytes; + off_t offset; + +}; + +struct pipeInfo { + int rFD; + int rfdCNT; + int wFD; + int wfdCNT; + int bCNT; + struct pipeBuf *headPB; + struct pipeBuf *tailPB; +}; + #endif /* END _SYS_PIPE_H */ diff --git a/sys/include/sys/resource.h b/sys/include/sys/resource.h new file mode 100644 index 0000000..d8dc18f --- /dev/null +++ b/sys/include/sys/resource.h @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_RESOURCE_H_ +#define _SYS_RESOURCE_H_ + +#include + +#ifndef _RLIM_T_DECLARED +typedef __rlim_t rlim_t; +#define _RLIM_T_DECLARED +#endif + + +/* + * Resource limits + */ +#define RLIMIT_CPU 0 /* maximum cpu time in seconds */ +#define RLIMIT_FSIZE 1 /* maximum file size */ +#define RLIMIT_DATA 2 /* data size */ +#define RLIMIT_STACK 3 /* stack size */ +#define RLIMIT_CORE 4 /* core file size */ +#define RLIMIT_RSS 5 /* resident set size */ +#define RLIMIT_MEMLOCK 6 /* locked-in-memory address space */ +#define RLIMIT_NPROC 7 /* number of processes */ +#define RLIMIT_NOFILE 8 /* number of open files */ +#define RLIMIT_SBSIZE 9 /* maximum size of all socket buffers */ +#define RLIMIT_VMEM 10 /* virtual process size (incl. mmap) */ +#define RLIMIT_AS RLIMIT_VMEM /* standard name for RLIMIT_VMEM */ +#define RLIMIT_NPTS 11 /* pseudo-terminals */ +#define RLIMIT_SWAP 12 /* swap used */ +#define RLIMIT_KQUEUES 13 /* kqueues allocated */ +#define RLIMIT_UMTXP 14 /* process-shared umtx */ + +#define RLIM_NLIMITS 15 /* number of resource limits */ + + +/* + * Resource limit string identifiers + */ + +static const char *rlimit_ident[RLIM_NLIMITS] = { + "cpu", + "fsize", + "data", + "stack", + "core", + "rss", + "memlock", + "nproc", + "nofile", + "sbsize", + "vmem", + "npts", + "swap", + "kqueues", + "umtx", +}; + + +struct rlimit { + rlim_t rlim_cur; /* current (soft) limit */ + rlim_t rlim_max; /* maximum value for rlim_cur */ +}; + +#endif /* !_SYS_RESOURCE_H_ */ diff --git a/sys/include/sys/sysproto_posix.h b/sys/include/sys/sysproto_posix.h index f8a0143..e14e374 100644 --- a/sys/include/sys/sysproto_posix.h +++ b/sys/include/sys/sysproto_posix.h @@ -26,13 +26,12 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _SYS_SYSPROTO_POSIX_H -#define _SYS_SYSPROTO_POSIX_H +#ifndef _SYS_SYSPROTO_POSIX_H_ +#define _SYS_SYSPROTO_POSIX_H_ #include #include - /* TEMP */ #include @@ -48,7 +47,6 @@ #define PADR_(t) 0 #endif -//Protos struct sys_exit_args { char status_l_[PADL_(int)]; int status; @@ -217,9 +215,15 @@ }; struct sys_lseek_args { - char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; - char offset_l_[PADL_(off_t)]; off_t offset; char offset_r_[PADR_(off_t)]; - char whence_l_[PADL_(int)]; int whence; char whence_r_[PADR_(int)]; + char fd_l_[PADL_(int)]; + int fd; + char fd_r_[PADR_(int)]; + char offset_l_[PADL_(off_t)]; + off_t offset; + char offset_r_[PADR_(off_t)]; + char whence_l_[PADL_(int)]; + int whence; + char whence_r_[PADR_(int)]; }; struct sys_sysctl_args { @@ -257,7 +261,6 @@ char arg_r_[PADR_(long)]; }; - /* OLD */ struct setitimer_args { @@ -684,25 +687,126 @@ }; struct sys_gettimeofday_args { - char tp_l_[PADL_(struct timeval *)]; struct timeval * tp; char tp_r_[PADR_(struct timeval *)]; - char tzp_l_[PADL_(struct timezone *)]; struct timezone * tzp; char tzp_r_[PADR_(struct timezone *)]; + char tp_l_[PADL_(struct timeval *)]; + struct timeval * tp; + char tp_r_[PADR_(struct timeval *)]; + char tzp_l_[PADL_(struct timezone *)]; + struct timezone * tzp; + char tzp_r_[PADR_(struct timezone *)]; }; - struct sys_sendto_args { - char s_l_[PADL_(int)]; int s; char s_r_[PADR_(int)]; - char buf_l_[PADL_(caddr_t)]; caddr_t buf; char buf_r_[PADR_(caddr_t)]; - char len_l_[PADL_(size_t)]; size_t len; char len_r_[PADR_(size_t)]; - char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)]; - char to_l_[PADL_(caddr_t)]; caddr_t to; char to_r_[PADR_(caddr_t)]; - char tolen_l_[PADL_(int)]; int tolen; char tolen_r_[PADR_(int)]; + char s_l_[PADL_(int)]; + int s; + char s_r_[PADR_(int)]; + char buf_l_[PADL_(caddr_t)]; + caddr_t buf; + char buf_r_[PADR_(caddr_t)]; + char len_l_[PADL_(size_t)]; + size_t len; + char len_r_[PADR_(size_t)]; + char flags_l_[PADL_(int)]; + int flags; + char flags_r_[PADR_(int)]; + char to_l_[PADL_(caddr_t)]; + caddr_t to; + char to_r_[PADR_(caddr_t)]; + char tolen_l_[PADL_(int)]; + int tolen; + char tolen_r_[PADR_(int)]; }; struct sys_rename_args { - char from_l_[PADL_(char *)]; char * from; char from_r_[PADR_(char *)]; - char to_l_[PADL_(char *)]; char * to; char to_r_[PADR_(char *)]; + char from_l_[PADL_(char *)]; + char * from; + char from_r_[PADR_(char *)]; + char to_l_[PADL_(char *)]; + char * to; + char to_r_[PADR_(char *)]; }; +struct sys_pread_args { + char fd_l_[PADL_(int)]; + int fd; + char fd_r_[PADR_(int)]; + char buf_l_[PADL_(void *)]; + void * buf; + char buf_r_[PADR_(void *)]; + char nbyte_l_[PADL_(size_t)]; + size_t nbyte; + char nbyte_r_[PADR_(size_t)]; + char offset_l_[PADL_(off_t)]; + off_t offset; + char offset_r_[PADR_(off_t)]; +}; + +struct sys_readlink_args { + char path_l_[PADL_(char *)]; + char * path; + char path_r_[PADR_(char *)]; + char buf_l_[PADL_(char *)]; + char * buf; + char buf_r_[PADR_(char *)]; + char count_l_[PADL_(size_t)]; + size_t count; + char count_r_[PADR_(size_t)]; +}; + +int sys_readlink(struct thread *, struct sys_readlink_args *); + +struct sys_pipe2_args { + char fildes_l_[PADL_(int *)]; + int * fildes; + char fildes_r_[PADR_(int *)]; + char flags_l_[PADL_(int)]; + int flags; + char flags_r_[PADR_(int)]; +}; + +int sys_pipe2(struct thread *, struct sys_pipe2_args *); + +struct sys_getlogin_args { + char namebuf_l_[PADL_(char *)]; + char * namebuf; + char namebuf_r_[PADR_(char *)]; + char namelen_l_[PADL_(u_int)]; + u_int namelen; + char namelen_r_[PADR_(u_int)]; +}; + +int sys_getlogin(struct thread *, struct sys_getlogin_args *); + +struct sys_setlogin_args { + char namebuf_l_[PADL_(char *)]; + char * namebuf; + char namebuf_r_[PADR_(char *)]; +}; + +int sys_setlogin(struct thread *, struct sys_setlogin_args *); + + +struct sys_getrlimit_args { + char which_l_[PADL_(u_int)]; + u_int which; + char which_r_[PADR_(u_int)]; + char rlp_l_[PADL_(struct rlimit *)]; + struct rlimit * rlp; + char rlp_r_[PADR_(struct rlimit *)]; +}; + +int sys_getrlimit(struct thread *, struct sys_getrlimit_args *); + +struct sys_setrlimit_args { + char which_l_[PADL_(u_int)]; + u_int which; + char which_r_[PADR_(u_int)]; + char rlp_l_[PADL_(struct rlimit *)]; + struct rlimit * rlp; + char rlp_r_[PADR_(struct rlimit *)]; +}; + +int sys_setrlimit(struct thread *, struct sys_setrlimit_args *); + //Func Defs int sys_invalid(struct thread *, void *); int sys_exit(struct thread *, struct sys_exit_args *); @@ -785,4 +889,7 @@ int sys_gettimeofday(struct thread *td, struct sys_gettimeofday_args *); int sys_sendto(struct thread *td, struct sys_sendto_args *); -#endif /* END _SYS_SYSPROTO_POSIX_H */ + +int sys_pread(struct thread *td, struct sys_pread_args *); + +#endif /* END _SYS_SYSPROTO_POSIX_H_ */ diff --git a/sys/include/sys/thread.h b/sys/include/sys/thread.h index 23b5d1f..13d720d 100644 --- a/sys/include/sys/thread.h +++ b/sys/include/sys/thread.h @@ -32,6 +32,7 @@ #include #include #include +#include #define O_FILES 64 @@ -46,6 +47,7 @@ int abi; sigset_t sigmask; struct sigaction sigact[128]; + struct rlimit rlim[RLIM_NLIMITS]; }; #endif /* END _SYS_THREAD_H */ diff --git a/sys/include/ubixos/sched.h b/sys/include/ubixos/sched.h index 3388bec..411821e 100644 --- a/sys/include/ubixos/sched.h +++ b/sys/include/ubixos/sched.h @@ -88,6 +88,7 @@ uint32_t children; // Hack for WAIT uint32_t last_exit; // Hack For WAIT struct taskStruct *parent; + char username[256]; } kTask_t; int sched_init(); diff --git a/sys/include/ubixos/syscalls.h b/sys/include/ubixos/syscalls.h index bae41f1..1336ac6 100644 --- a/sys/include/ubixos/syscalls.h +++ b/sys/include/ubixos/syscalls.h @@ -44,6 +44,7 @@ #define SYSCALL_INVALID 0 #define SYSCALL_VALID 1 #define SYSCALL_DUMMY 2 +#define SYSCALL_NOTIMP 3 typedef int sys_call_t(struct thread *, void *); diff --git a/sys/init/main.c b/sys/init/main.c index 8b4ebbe..46c78f5 100644 --- a/sys/init/main.c +++ b/sys/init/main.c @@ -109,8 +109,17 @@ union descriptorTableUnion *gdt __attribute__ ((packed)); } loadGDT = { (11 * sizeof(union descriptorTableUnion) - 1), ubixGDT }; -static char *argv_init[2] = { "init", NULL, }; // ARGV For Initial Proccess -static char *envp_init[6] = { "HOME=/", "PWD=/", "PATH=/bin:/sbin:/usr/bin:/usr/sbin", "USER=root", "GROUP=admin", NULL, }; //ENVP For Initial Proccess +static char *argv_init[2] = { + "init", + NULL, }; /* ARGV For Initial Process */ + +static char *envp_init[6] = { + "HOME=/", + "PWD=/", + "PATH=/bin:/sbin:/usr/bin:/usr/sbin", + "USER=root", + "GROUP=admin", + NULL, }; /* ENVP For Initial Process */ struct bootinfo _bootinfo; char _kernelname[512]; @@ -136,9 +145,9 @@ } /* New Root Mount Point */ - //Old 2 new 10 + /* Old 2 new 10 */ kprintf("[0x%X][0x%X:0x%X:0x%X:0x%X:0x%X:0x%X]\n", B_ADAPTOR(rootdev), B_CONTROLLER(rootdev), B_SLICE(rootdev), B_UNIT(rootdev), B_PARTITION(rootdev), B_TYPE(rootdev)); - //if ( vfs_mount( B_UNIT(_bootdev), B_PARTITION(_bootdev), 0x0, 0xAA, "sys", "rw" ) != 0x0 ) { + /* if ( vfs_mount( B_UNIT(_bootdev), B_PARTITION(_bootdev), 0x0, 0xAA, "sys", "rw" ) != 0x0 ) { */ if (vfs_mount(0x1, 0x2, 0x0, 0xAA, "sys", "rw") != 0x0) { kprintf("Problem Mounting sys Mount Point\n"); } @@ -162,8 +171,8 @@ - //kprintf("SDE Thread Start! [0x%X]\n", &sdeThread); - //execThread(&sdeThread, 0x2000,0x0); + /* kprintf("SDE Thread Start! [0x%X]\n", &sdeThread); */ + /* execThread(&sdeThread, 0x2000,0x0); */ kprintf("Kernel Name: [%s], Boot How To [0x%X], Boot Dev: [0x%X]\n", _kernelname, _boothowto, _bootdev); kprintf("B_TYPE(0x%X), B_SLICE(0x%X), B_UNIT(0x%X), B_PARTITION(0x%X)\n", B_TYPE(_bootdev), B_SLICE(_bootdev), B_UNIT(_bootdev), B_PARTITION(_bootdev)); diff --git a/sys/kernel/Makefile b/sys/kernel/Makefile index 50d81ae..6d6e4e6 100644 --- a/sys/kernel/Makefile +++ b/sys/kernel/Makefile @@ -6,7 +6,7 @@ include ../Makefile.incl # Objects -OBJS = sem.o vfs_calls.o tty.o kern_sig.o pipe.o descrip.o kern_sysctl.o gen_calls.o endtask.o ld.o time.o elf.o ubthread.o vitals.o access.o syscall.o syscall_posix.o syscalls.o syscalls_posix.o execve.o +OBJS = sem.o vfs_calls.o tty.o kern_sig.o pipe.o descrip.o kern_sysctl.o gen_calls.o endtask.o ld.o time.o elf.o ubthread.o vitals.o access.o syscall.o syscall_posix.o syscalls.o syscalls_posix.o execve.o kern_pipe.o #OBJS += ../${_ARCH}/schedyield.o ../${_ARCH}/kpanic.o ../${_ARCH}/timer.o ../${_ARCH}/spinlock.o ../${_ARCH}/exec.o ../${_ARCH}/sys_call_new.o ../${_ARCH}/sys_call.o ../${_ARCH}/bioscall.o ../${_ARCH}/fork.o ../${_ARCH}/syscall.o ../${_ARCH}/systemtask.o ../${_ARCH}/sched.o ../${_ARCH}/cpu.o # ap-boot.o smp.o vitals.o(obsolete) diff --git a/sys/kernel/access.c b/sys/kernel/access.c index 8d36fd3..2e5df39 100644 --- a/sys/kernel/access.c +++ b/sys/kernel/access.c @@ -42,7 +42,6 @@ ************************************************************************/ int sys_setUID(struct thread *td, struct sys_setUID_args *args) { - kprintf("Here?\n"); if (_current->uid == 0x0) { _current->uid = args->uid; return (0); diff --git a/sys/kernel/gen_calls.c b/sys/kernel/gen_calls.c index 5a7fb22..098025d 100644 --- a/sys/kernel/gen_calls.c +++ b/sys/kernel/gen_calls.c @@ -187,9 +187,9 @@ void **segbase = 0x0; uint32_t base_addr = 0x0; if (args->op == 10) { - kprintf("SETGSBASE: 0x%X:0x%X", args->parms, args->parms[0]); + //kprintf("SETGSBASE: 0x%X:0x%X", args->parms, args->parms[0]); segbase = args->parms; - kprintf("SGS: [0x%X:0x%X]", segbase[0], segbase[1]); + //kprintf("SGS: [0x%X:0x%X]", segbase[0], segbase[1]); base_addr = (uint32_t) segbase[0]; struct gdtDescriptor *tmpDesc = 0x0; @@ -202,15 +202,16 @@ tmpDesc->limitHigh = (0xFFFFF >> 16); tmpDesc->granularity = ((dData + dWrite + dBig + dBiglim + dDpl3) & 0xFF) >> 4; tmpDesc->baseHigh = base_addr >> 24; - /* - asm( - "push %eax\n" - "lgdtl (loadGDT)\n" - "mov $0xF,%eax\n" - "mov %eax,%gs\n" - "pop %eax\n" - ); - */ + + asm( + "push %eax\n" + "mov $0x18,%ax\n" + "lldt %ax\n" /* "lgdtl (loadGDT)\n" */ + "mov $0xF,%eax\n" + "mov %eax,%gs\n" + "pop %eax\n" + ); + td->td_retval[0] = 0; } else { @@ -355,3 +356,165 @@ td->td_retval[0] = 0; return (0); } + +int sys_getlogin(struct thread *thr, struct sys_getlogin_args *args) { + int error = 0; + + memcpy(args->namebuf, _current->username, args->namelen); + + return (error); +} + +int sys_setlogin(struct thread *thr, struct sys_setlogin_args *args) { + int error = 0; + + memcpy(_current->username, args->namebuf, 256); + + return (error); +} + +int sys_getrlimit(struct thread *thr, struct sys_getrlimit_args *args) { + int error = 0; + + struct rlimit *rlim = 0x0; + + switch (args->which) { + case 0: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 1: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 2: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 3: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 4: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 5: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 6: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 7: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 8: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 9: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 10: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 11: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 12: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 13: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + case 14: + args->rlp->rlim_cur = thr->rlim[args->which].rlim_cur; + args->rlp->rlim_max = thr->rlim[args->which].rlim_max; + break; + default: + error = -1; + kprintf("[getrlimit: %i]", args->which); + } + + return (error); +} + +int sys_setrlimit(struct thread *thr, struct sys_setrlimit_args *args) { + int error = 0; + + switch (args->which) { + case 0: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 1: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 2: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 3: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 4: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 5: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 6: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 7: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 8: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 9: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 10: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 11: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 12: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 13: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + case 14: + thr->rlim[args->which].rlim_cur = args->rlp->rlim_cur; + thr->rlim[args->which].rlim_max = args->rlp->rlim_max; + break; + default: + error = -1; + kprintf("[setrlimit: %i]", args->which); + } + + return (error); +} diff --git a/sys/kernel/kern_pipe.c b/sys/kernel/kern_pipe.c new file mode 100644 index 0000000..58c645d --- /dev/null +++ b/sys/kernel/kern_pipe.c @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2002-2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +int sys_pipe2(struct thread *thr, struct sys_pipe2_args *args) { + int error = 0x0; + + int fd1 = 0x0; + int fd2 = 0x0; + + struct file *nfp1 = 0x0; + struct file *nfp2 = 0x0; + + struct pipeInfo *pipeDesc = kmalloc(sizeof(struct pipeInfo)); + + memset(pipeDesc, 0x0, sizeof(struct pipeInfo)); + + error = falloc(thr, &nfp1, &fd1); + error = falloc(thr, &nfp2, &fd2); + + nfp1->data = pipeDesc; + nfp2->data = pipeDesc; + + nfp1->fd_type = 3; + nfp2->fd_type = 3; + + pipeDesc->rFD = fd1; + pipeDesc->rfdCNT = 2; + pipeDesc->wFD = fd2; + pipeDesc->wfdCNT = 2; + + args->fildes[0] = fd1; + args->fildes[1] = fd2; + + thr->td_retval[0] = 0; + + return (0x0); +} diff --git a/sys/kernel/kern_sysctl.c b/sys/kernel/kern_sysctl.c index f263417..b475ab8 100644 --- a/sys/kernel/kern_sysctl.c +++ b/sys/kernel/kern_sysctl.c @@ -36,16 +36,20 @@ #include #include #include +#include static struct sysctl_entry *ctls = 0x0; static struct sysctl_entry *sysctl_find(int *, int); static struct sysctl_entry *sysctl_findMib(char *name, int namelen); +struct Trie *sysctl_headTrie = 0x0; + /* This is a cheat for now */ static void def_ctls() { int name[CTL_MAXNAME], name_len; uint32_t page_val = 0x1000; + int32_t usPage_val = 0x0; name[0] = 6; name[1] = 7; name_len = 2; @@ -116,21 +120,43 @@ char s61[4] = "i386"; sysctl_add(name, name_len, "kern.hostname", &s61, 4); + /* XXX 6, 2147482988 */ + name[0] = 6; + name[1] = 2147482988; + page_val = 4096; + sysctl_add(name, name_len, "hw.pagesizes", &page_val, sizeof(u_int32_t)); + + name[0] = 2; + name[1] = 12; + page_val = 0; + sysctl_add(name, name_len, "vm.overcommit", &page_val, sizeof(u_int32_t)); + + name[0] = 1; + name[1] = 18; + usPage_val = 1023; + sysctl_add(name, name_len, "kern.ngroups", &page_val, sizeof(int32_t)); + } int sysctl_init() { + struct sysctl_entry *tmpCtl = 0x0; + if (ctls != 0x0) { kprintf("sysctl already Initialized\n"); while (1) ; } + /* Initialize Head Trie */ + sysctl_headTrie = (struct Trie *) kmalloc(sizeof(struct Trie)); + ctls = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); ctls->prev = 0x0; ctls->id = CTL_UNSPEC; ctls->children = 0x0; sprintf(ctls->name, "unspec"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->prev = ctls; @@ -138,6 +164,7 @@ tmpCtl->children = 0x0; sprintf(tmpCtl->name, "kern"); ctls->next = tmpCtl; + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -145,6 +172,7 @@ tmpCtl->id = CTL_VM; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "vm"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -152,6 +180,7 @@ tmpCtl->id = CTL_VFS; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "vfs"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -159,6 +188,7 @@ tmpCtl->id = CTL_NET; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "net"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -166,6 +196,7 @@ tmpCtl->id = CTL_DEBUG; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "debug"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -173,6 +204,7 @@ tmpCtl->id = CTL_HW; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "hw"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -180,6 +212,7 @@ tmpCtl->id = CTL_MACHDEP; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "machdep"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -187,6 +220,7 @@ tmpCtl->id = CTL_USER; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "user"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -194,6 +228,7 @@ tmpCtl->id = CTL_P1003_1B; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "p1003_1b"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); tmpCtl->next = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); tmpCtl->next->prev = tmpCtl; @@ -201,6 +236,7 @@ tmpCtl->id = CTL_UBIX; tmpCtl->children = 0x0; sprintf(tmpCtl->name, "ubix"); + insert_trieNode(&sysctl_headTrie, &ctls->name, ctls); def_ctls(); @@ -240,6 +276,7 @@ int sys_sysctl(struct thread *td, struct sys_sysctl_args *args) { struct sysctl_entry *tmpCtl = 0x0; + struct Trie *tmpTrie = 0x0; int i = 0; if (ctls == 0x0) @@ -250,24 +287,60 @@ endTask(_current->id); } + /* XXX - Handle search by name */ if (args->namelen == 2 && args->name[0] == 0 && args->name[1] == 3) { - kprintf("name_to_mib: %s", args->newp); - // tmpCtl = sysctl_findMib(args->newp, args->namelen); -td->td_retval[0] = ENOENT; -return(-1); + + tmpTrie = search_trieNode(sysctl_headTrie, args->newp); + + if (tmpTrie != 0x0) { + tmpCtl = (struct sysctl_entry *)tmpTrie->e; + + //kprintf("\n", tmpCtl->name,tmpCtl->namelen); + + // tmpCtl = sysctl_findMib(args->newp, args->namelen); + *args->oldlenp = tmpCtl->namelen *4; + u_int32_t *oldp = args->oldp; + + for (i=0;inamelen;i++) + oldp[i] = tmpCtl->full_name[i]; + + td->td_retval[0] = 0; /* XXX - Very Bad need to store namelen in the struct */ + + return(0x0); + } + else { + + #ifdef DEBUG_SYSCTL + kprintf("%s:%i>name_to_mib: %s\n", __FILE__,__LINE__,args->newp); + #endif + + td->td_retval[0] = ENOENT; + return(-1); + } } else { - tmpCtl = sysctl_find(args->name, args->namelen); + tmpCtl = sysctl_find(args->name, args->namelen); } if (tmpCtl == 0x0) { - kprintf("Invalid CTL: "); + kprintf("Invalid CTL(%i): ", args->namelen); for (i = 0x0; i < args->namelen; i++) kprintf("(%i)", (int) args->name[i]); kprintf("\n"); td->td_retval[0] = -1; return (-1); } + /* + else { + kprintf("Valid CTL(%i): ", args->namelen); + for (i = 0x0; i < args->namelen; i++) + kprintf("(%i)", (int) args->name[i]); + kprintf("\n"); + } + + kprintf("{%i:%i}\n",args->oldlenp, tmpCtl->val_len); + +*/ if ((uint32_t) args->oldlenp < tmpCtl->val_len) memcpy(args->oldp, tmpCtl->value, (uInt32) args->oldlenp); @@ -310,6 +383,10 @@ kprintf("FMIB: %s", mib); + + lCtl = (struct sysctl_entry *) search_trieNode(sysctl_headTrie, mib)->e; + kprintf("FT: %s", lCtl->name); + /* Loop Name Len */ for (i = 0x0; i < namelen; i++) { for (tmpCtl = lCtl; tmpCtl != 0x0; tmpCtl = tmpCtl->next) { @@ -332,6 +409,7 @@ int sysctl_add(int *name, int namelen, char *str_name, void *buf, int buf_size) { struct sysctl_entry *tmpCtl = 0x0; struct sysctl_entry *newCtl = 0x0; + int i = 0; /* Check if it exists */ tmpCtl = sysctl_find(name, namelen); @@ -349,22 +427,38 @@ } if (tmpCtl->children == 0x0) { tmpCtl->children = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); + memset(tmpCtl->children, 0x0, sizeof(struct sysctl_entry)); tmpCtl->children->children = 0x0; tmpCtl->children->prev = 0x0; tmpCtl->children->next = 0x0; tmpCtl->children->id = name[namelen - 1]; + for (i = 0; i < namelen;i++) + tmpCtl->children->full_name[i] = name[i]; + + tmpCtl->children->namelen = namelen; + sprintf(tmpCtl->children->name, str_name); + + insert_trieNode(&sysctl_headTrie, &tmpCtl->children->name, tmpCtl->children); tmpCtl->children->value = (void *) kmalloc(buf_size); memcpy(tmpCtl->children->value, buf, buf_size); tmpCtl->children->val_len = buf_size; } else { newCtl = (struct sysctl_entry *) kmalloc(sizeof(struct sysctl_entry)); + memset(newCtl, 0x0, sizeof(struct sysctl_entry)); newCtl->prev = 0x0; newCtl->next = tmpCtl->children; newCtl->children = 0x0; newCtl->id = name[namelen - 1]; + + for (i = 0; ifull_name[i] = name[i]; + + newCtl->namelen = namelen; + sprintf(newCtl->name, str_name); + insert_trieNode(&sysctl_headTrie, &newCtl->name, newCtl); newCtl->value = (void *) kmalloc(buf_size); memcpy(newCtl->value, buf, buf_size); newCtl->val_len = buf_size; diff --git a/sys/kernel/syscall_posix.c b/sys/kernel/syscall_posix.c index 9c71601..f7d8e0e 100644 --- a/sys/kernel/syscall_posix.c +++ b/sys/kernel/syscall_posix.c @@ -69,10 +69,17 @@ die_if_kernel("Invalid System pCall", frame, frame->tf_eax); kpanic("PID: %i", _current->id); } - else if ((uint32_t) systemCalls_posix[code].sc_status == SYSCALL_INVALID) { - kprintf("Invalid Call: [%i][0x%X]\n", code, (uint32_t) systemCalls[code].sc_name); + else if ((int) systemCalls_posix[code].sc_status == SYSCALL_INVALID) { + kprintf("Invalid Call: [%i][%s]\n", code, systemCalls_posix[code].sc_name); frame->tf_eax = -1; frame->tf_edx = 0x0; + frame->tf_eflags |= PSL_C; + } + else if ((int) systemCalls_posix[code].sc_status == SYSCALL_NOTIMP) { + kprintf("Not Implemented Call: [%i][%s]\n", code, systemCalls_posix[code].sc_name); + frame->tf_eax = 22;//-1; + frame->tf_edx = 0x0; + frame->tf_eflags |= PSL_C; } else { td->td_retval[0] = 0; @@ -108,6 +115,7 @@ frame->tf_eax = td->td_retval[0]; frame->tf_edx = td->td_retval[1]; frame->tf_eflags |= PSL_C; + kprintf("SC[%i][%s][%i][%i]\n", code, systemCalls_posix[code].sc_name, frame->tf_eax, frame->tf_edx); break; } } diff --git a/sys/kernel/syscalls_posix.c b/sys/kernel/syscalls_posix.c index 1f50add..b48b452 100644 --- a/sys/kernel/syscalls_posix.c +++ b/sys/kernel/syscalls_posix.c @@ -31,516 +31,2761 @@ /* System Calls List */ struct syscall_entry systemCalls_posix[] = { - { 0, "No Call", sys_invalid, SYSCALL_VALID }, // 0 - syscall - { ARG_COUNT(sys_exit_args), "exit", (sys_call_t *) sys_exit, SYSCALL_VALID }, // 1 - exit - { ARG_COUNT(sys_fork_args), "fork", (sys_call_t *) sys_fork, SYSCALL_VALID }, // 2 - fork - { ARG_COUNT(sys_read_args), "read", (sys_call_t *) sys_read, SYSCALL_VALID }, // 3 - read - { ARG_COUNT(sys_write_args), "write", (sys_call_t *) sys_write, SYSCALL_VALID }, // 4 - write - { ARG_COUNT(sys_open_args), "open", (sys_call_t *) sys_open, SYSCALL_VALID }, // 5 - open - { ARG_COUNT(sys_close_args), "close", (sys_call_t *) sys_close, SYSCALL_VALID }, // 6 - close - { ARG_COUNT(sys_wait4_args), "wiat4", (sys_call_t *) sys_wait4, SYSCALL_VALID }, // 7 - wait4 - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { ARG_COUNT(sys_chdir_args), "Change Dir", (sys_call_t *) sys_chdir, SYSCALL_VALID }, // 12 - chdir - { ARG_COUNT(sys_fchdir_args), "fchdir", sys_fchdir, SYSCALL_VALID }, // 13 - fchdir - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { ARG_COUNT(sys_getpid_args), "getpid", sys_getpid, SYSCALL_VALID }, // 20 - getpid - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { ARG_COUNT(sys_setUID_args), "Set UID", (sys_call_t *) sys_setUID, SYSCALL_VALID }, // 23 - setUID - { 0, "Get UID", sys_getUID, SYSCALL_VALID }, - { ARG_COUNT(sys_geteuid_args), "geteuid", sys_geteuid, SYSCALL_VALID }, // 25 - getuid - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, // 31 - { 0, "No Call", sys_invalid, SYSCALL_VALID }, // 32 - { ARG_COUNT(sys_access_args), "access", sys_access, SYSCALL_VALID }, // 33 - access - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { ARG_COUNT(sys_getppid_args), "getpid", sys_getpid, SYSCALL_VALID }, // 39 - getppid - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { ARG_COUNT(sys_getegid_args), "getegid", sys_getegid, SYSCALL_VALID }, // 43 - getegid - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "getuid", sys_getGID, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { ARG_COUNT(sys_ioctl_args), "ioctl", sys_ioctl, SYSCALL_VALID }, // 54 - ioctl - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, - { ARG_COUNT(sys_execve_args), "execve", (sys_call_t *) sys_execve, SYSCALL_VALID }, - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 60 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 61 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 62 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 63 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 64 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 65 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 66 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 67 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 68 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 69 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 70 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 71 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 72 - Invalid */ - { ARG_COUNT(sys_munmap_args), "MUNMAP", sys_munmap, SYSCALL_VALID }, /* 73 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 74 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 75 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 76 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 77 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 78 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 79 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 80 - Invalid */ - { ARG_COUNT(sys_getpgrp_args), "getpgrp", sys_getpgrp, SYSCALL_VALID }, // 81 - getpgrp - { ARG_COUNT(sys_setpgid_args), "setpgid", sys_setpgid, SYSCALL_VALID }, // 82 - setpgid - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 83 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 84 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 85 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 86 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 87 - Invalid */ - { 0, "Get Free Page", (sys_call_t *) sysGetFreePage, SYSCALL_VALID }, /* 88 - getFreePage TEMP */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 89 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 90 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 91 - Invalid */ - { ARG_COUNT(sys_fcntl_args), "fcntl", sys_fcntl, SYSCALL_VALID }, // 92 - fcntl - { ARG_COUNT(sys_select_args), "select", sys_select, SYSCALL_VALID }, // 93 - select - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 94 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 95 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 96 - Invalid */ - { ARG_COUNT(sys_socket_args), "socket", sys_socket, SYSCALL_VALID }, // 97 - socket - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 98 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 99 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 100 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 101 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 102 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 103 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 104 - Invalid */ - { ARG_COUNT(sys_setsockopt_args), "setsockopt", sys_setsockopt, SYSCALL_VALID }, // 105 setsockopt - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 106 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 107 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 108 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 109 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 110 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 111 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 112 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 113 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 114 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 115 - Invalid */ - { ARG_COUNT(sys_gettimeofday_args), "gettimeofday", sys_gettimeofday, SYSCALL_VALID }, // 116 - gettimeofday - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 117 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 118 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 119 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 120 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 121 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 122 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 123 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 124 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 125 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 126 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 127 - Invalid */ - { ARG_COUNT(sys_rename_args), "rename", sys_rename, SYSCALL_VALID }, /* 128 - rename */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 129 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 130 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 131 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 132 - Invalid */ - { ARG_COUNT(sys_sendto_args), "sendto", sys_sendto, SYSCALL_VALID }, // 133 - sendto - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 134 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 135 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 136 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 137 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 138 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 139 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 140 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 141 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 142 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 143 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 144 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 145 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 146 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 147 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 148 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 149 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 150 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 151 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 152 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 153 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 154 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 155 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 156 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 157 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 158 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 159 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 160 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 161 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 162 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 163 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 164 - Invalid */ - { ARG_COUNT(sys_sysarch_args), "sysarch", sys_sysarch, SYSCALL_VALID }, // 165 - sysarch - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 166 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 167 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 168 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 169 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 170 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 171 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 172 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 173 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 174 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 175 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 176 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 177 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 178 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 179 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 180 - Invalid */ - { ARG_COUNT(sys_setGID_args), "Set GID", (sys_call_t *) sys_setGID, SYSCALL_VALID }, // 181 - getgid - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 182 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 183 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 184 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 185 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 186 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 187 - Invalid */ - { ARG_COUNT(sys_stat_args), "FSTAT", (sys_call_t *) sys_stat, SYSCALL_VALID }, /* 188 - sys_stat */ - { ARG_COUNT(sys_fstat_args), "FSTAT", (sys_call_t *) sys_fstat, SYSCALL_VALID }, /* 189 - sys_fstat */ - { ARG_COUNT(sys_lstat_args), "LSTAT", (sys_call_t *) sys_lstat, SYSCALL_VALID }, /* 190 - sys_lstat */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 191 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 192 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 193 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 194 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 195 - Invalid */ - { ARG_COUNT(sys_getdirentries_args), "getdirentries", sys_getdirentries, SYSCALL_VALID }, // 196 - getdirentries - { ARG_COUNT(sys_mmap_args), "MMAP", (sys_call_t *) sys_mmap, SYSCALL_VALID }, /* 197 - sys_mmap */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 198 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 199 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 200 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 201 - Invalid */ - { ARG_COUNT(sys_sysctl_args), "SYS CTL", (sys_call_t *) sys_sysctl, SYSCALL_VALID }, /* 202 - sys_sysctl */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 203 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 204 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 205 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 206 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 207 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 208 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 209 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 210 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 211 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 212 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 213 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 214 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 215 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 216 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 217 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 218 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 219 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 220 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 221 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 222 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 223 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 224 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 225 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 226 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 227 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 228 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 229 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 230 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 231 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 232 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 233 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 234 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 235 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 236 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 237 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 238 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 239 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 240 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 241 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 242 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 243 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 244 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 245 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 246 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 247 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 248 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 249 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 250 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 251 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 252 - Invalid */ - { ARG_COUNT(sys_issetugid_args), "ISSETUGID", (sys_call_t *) sys_issetugid, SYSCALL_VALID }, /* 253 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 254 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 255 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 256 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 257 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 258 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 259 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 260 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 261 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 262 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 263 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 264 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 265 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 266 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 267 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 268 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 269 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 270 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 271 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 272 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 273 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 274 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 275 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 276 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 277 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 278 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 279 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 280 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 281 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 282 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 283 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 284 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 285 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 286 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 287 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 288 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 289 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 290 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 291 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 292 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 293 - Invalid */ - { ARG_COUNT(sys_fseek_args), "FILE Seek", (sys_call_t *) sys_fseek, SYSCALL_VALID }, /* 294 - sys_fseek */ - { ARG_COUNT(sys_fgetc_args), "FILE Get Char", (sys_call_t *) sys_fgetc, SYSCALL_VALID }, /* 295 - sys_fread */ - { ARG_COUNT(sys_fclose_args), "FILE Close", (sys_call_t *) sys_fclose, SYSCALL_VALID }, /* 296 - sys_fread */ - { ARG_COUNT(sys_fread_args), "FILE Read", (sys_call_t *) sys_fread, SYSCALL_VALID }, /* 297 - sys_fread */ - { ARG_COUNT(sys_fopen_args), "FILE Open", (sys_call_t *) sys_fopen, SYSCALL_VALID }, /* 298 - sys_fopen */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 299 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 300 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 301 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 302 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 303 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 304 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 305 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 306 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 307 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 308 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 309 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 310 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 311 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 312 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 313 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 314 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 315 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 316 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 317 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 318 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 319 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 320 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 321 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 322 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 323 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 324 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 325 - Invalid */ - { ARG_COUNT(sys_getcwd_args), "Get CWD", (sys_call_t *) sys_getcwd, SYSCALL_VALID }, /* 326 - sys_getcwd */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 327 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 328 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 329 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 330 - Invalid */ - { 0, "Sched Yield", sys_sched_yield, SYSCALL_VALID }, /* 331 - sys_sched_yield */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 332 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 333 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 334 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 335 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 336 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 337 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 338 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 339 - Invalid */ - { ARG_COUNT(sys_sigprocmask_args), "sigprocmask", sys_sigprocmask, SYSCALL_VALID }, // 340 - sigprocmask - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 341 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 342 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 343 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 344 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 345 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 346 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 347 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 348 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 349 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 350 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 351 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 352 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 353 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 354 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 355 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 356 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 357 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 358 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 359 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 350 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 351 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 352 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 353 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 354 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 355 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 356 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 357 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 358 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 359 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 360 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 361 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 362 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 363 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 364 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 365 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 366 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 367 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 368 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 369 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 370 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 371 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 372 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 373 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 374 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 375 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 376 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 377 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 378 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 379 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 380 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 381 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 382 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 383 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 384 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 385 - Invalid */ - { ARG_COUNT(sys_statfs_args), "statfs", (sys_call_t *) sys_statfs, SYSCALL_VALID }, // 396 statfs - { ARG_COUNT(sys_fstatfs_args), "fstatfs", (sys_call_t *) sys_fstatfs, SYSCALL_VALID }, // 397 fstatfs - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 398 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 399 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 400 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 401 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 402 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 403 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 404 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 405 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 306 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 307 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 308 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 409 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 410 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 411 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 412 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 413 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 414 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 415 - Invalid */ - { ARG_COUNT(sys_sigaction_args), "sigaction", sys_sigaction, SYSCALL_VALID }, // 416 - sigaction - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 417 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 418 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 419 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 410 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 421 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 422 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 423 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 424 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 425 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 426 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 427 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 428 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 429 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 430 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 431 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 432 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 433 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 434 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 435 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 436 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 437 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 438 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 439 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 440 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 441 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 442 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 443 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 444 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 445 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 446 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 447 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 448 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 449 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 450 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 451 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 452 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 453 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 454 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 455 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 456 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 457 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 458 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 459 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 460 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 461 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 462 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 463 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 464 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 465 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 466 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 467 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 468 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 469 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 470 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 471 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 472 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 473 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 474 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 475 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 476 - Invalid */ - { ARG_COUNT(sys_mmap_args), "MMAP", (sys_call_t *) sys_mmap, SYSCALL_VALID }, /* 477 - sys_mmap */ - { ARG_COUNT(sys_lseek_args), "lseek", (sys_call_t *) sys_lseek, SYSCALL_VALID }, /* 478 - sys_lseek */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 359 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 350 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 351 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 352 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 353 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 354 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 355 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 356 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 357 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 358 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 359 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 350 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 351 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 352 - Invalid */ - { ARG_COUNT(sys_fstatat_args), "fstatat", sys_fstatat, SYSCALL_VALID }, // 493 - fstatat - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 354 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 355 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 356 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 357 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 358 - Invalid */ - { ARG_COUNT(sys_openat_args), "SYS_openat", sys_openat, SYSCALL_VALID }, /* 499 - sys_openat */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 350 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 351 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 352 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 353 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 354 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 355 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 356 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 357 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 358 - Invalid */ - { 0, "No Call", sys_invalid, SYSCALL_VALID }, /* 359 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_VALID }, /* 0 */ + { + ARG_COUNT(sys_exit_args), + "exit", + (sys_call_t *) sys_exit, + SYSCALL_VALID }, /* 1 */ + { + ARG_COUNT(sys_fork_args), + "fork", + (sys_call_t *) sys_fork, + SYSCALL_VALID }, /* 2 */ + { + ARG_COUNT(sys_read_args), + "read", + (sys_call_t *) sys_read, + SYSCALL_VALID }, /* 3 */ + { + ARG_COUNT(sys_write_args), + "write", + (sys_call_t *) sys_write, + SYSCALL_VALID }, /* 4 */ + { + ARG_COUNT(sys_open_args), + "open", + (sys_call_t *) sys_open, + SYSCALL_VALID }, /* 5 */ + { + ARG_COUNT(sys_close_args), + "close", + (sys_call_t *) sys_close, + SYSCALL_VALID }, /* 6 */ + { + ARG_COUNT(sys_wait4_args), + "wiat4", + (sys_call_t *) sys_wait4, + SYSCALL_VALID }, /* 7 */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 8 */ + { + 0, + "link", + sys_invalid, + SYSCALL_NOTIMP }, /* 9 */ + { + 0, + "unlink", + sys_invalid, + SYSCALL_NOTIMP }, /* 10 */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 11 */ + { + ARG_COUNT(sys_chdir_args), + "cgdur", + (sys_call_t *) sys_chdir, + SYSCALL_VALID }, /* 12 */ + { + ARG_COUNT(sys_fchdir_args), + "fchdir", + sys_fchdir, + SYSCALL_VALID }, /* 13 */ + { + 0, + "mknod", + sys_invalid, + SYSCALL_NOTIMP }, /* 14 */ + { + 0, + "chmod", + sys_invalid, + SYSCALL_NOTIMP }, /* 15 */ + { + 0, + "chown", + sys_invalid, + SYSCALL_NOTIMP }, /* 16 */ + { + 0, + "break", + sys_invalid, + SYSCALL_NOTIMP }, /* 17 */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 18 */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 19 */ + { + ARG_COUNT(sys_getpid_args), + "getpid", + sys_getpid, + SYSCALL_VALID }, // 20 - getpid + { + 0, + "mount", + sys_invalid, + SYSCALL_NOTIMP }, // 21 - mount + { + 0, + "unmount", + sys_invalid, + SYSCALL_NOTIMP }, // 22 - unmount + { + ARG_COUNT(sys_setUID_args), + "setuid", + (sys_call_t *) sys_setUID, + SYSCALL_VALID }, // 23 - setUID + { + 0, + "getuid", + sys_getUID, + SYSCALL_VALID }, // 24 - getuid + { + ARG_COUNT(sys_geteuid_args), + "geteuid", + sys_geteuid, + SYSCALL_VALID }, // 25 - geteuid + { + 0, + "ptrace", + sys_invalid, + SYSCALL_NOTIMP }, // 26 - ptrace + { + 0, + "recvmsg", + sys_invalid, + SYSCALL_NOTIMP }, // 27 - recvmsg + { + 0, + "sendmsg", + sys_invalid, + SYSCALL_NOTIMP }, // 28 - sendmsg + { + 0, + "recvfrom", + sys_invalid, + SYSCALL_NOTIMP }, // 29 - recvfrom + { + 0, + "accept", + sys_invalid, + SYSCALL_NOTIMP }, // 30 - accept + { + 0, + "getpeername", + sys_invalid, + SYSCALL_NOTIMP }, // 31 - getpeername + { + 0, + "getsockname", + sys_invalid, + SYSCALL_NOTIMP }, // 32 - getsockname + { + ARG_COUNT(sys_access_args), + "access", + sys_access, + SYSCALL_VALID }, /* 33 */ + { + 0, + "chflags", + sys_invalid, + SYSCALL_NOTIMP }, // 34 - chflags + { + 0, + "fchflags", + sys_invalid, + SYSCALL_NOTIMP }, // 35 - fchflags + { + 0, + "sync", + sys_invalid, + SYSCALL_NOTIMP }, // 36 - sync + { + 0, + "kill", + sys_invalid, + SYSCALL_NOTIMP }, // 37 - kill + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, // 38 + { + ARG_COUNT(sys_getppid_args), + "getpid", + sys_getpid, + SYSCALL_VALID }, // 39 - getppid + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, // 40 + { + 0, + "dup", + sys_invalid, + SYSCALL_NOTIMP }, // 41 - dup + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, // 42 + { + ARG_COUNT(sys_getegid_args), + "getegid", + sys_getegid, + SYSCALL_VALID }, // 43 - getegid + { + 0, + "profil", + sys_invalid, + SYSCALL_NOTIMP }, // 44 - profil + { + 0, + "No Call", + sys_invalid, + SYSCALL_NOTIMP }, // 45 - ktrace + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, // 46 + { + 0, + "getuid", + sys_getGID, + SYSCALL_VALID }, // 47 - getgid + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, // 48 + { + ARG_COUNT(sys_getlogin_args), + "getlogin", + sys_getlogin, + SYSCALL_VALID }, /* 49 */ + { + ARG_COUNT(sys_setlogin_args), + "setlogin", + sys_setlogin, + SYSCALL_NOTIMP }, /* 50 */ + { + 0, + "acct", + sys_invalid, + SYSCALL_NOTIMP }, /* 51 */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 52 */ + { + 0, + "sigaltstack", + sys_invalid, + SYSCALL_NOTIMP }, /* 53 */ + { + ARG_COUNT(sys_ioctl_args), + "ioctl", + sys_ioctl, + SYSCALL_VALID }, // 54 - ioctl + { + 0, + "reboot", + sys_invalid, + SYSCALL_NOTIMP }, // 55 - reboot + { + 0, + "revoke", + sys_invalid, + SYSCALL_NOTIMP }, // 56 - revoke + { + 0, + "symlink", + sys_invalid, + SYSCALL_NOTIMP }, /* 57 */ + { + 0, + "readlink", + sys_readlink, + SYSCALL_VALID }, /* 58 */ + { + ARG_COUNT(sys_execve_args), + "execve", + (sys_call_t *) sys_execve, + SYSCALL_VALID }, // 59 - execv + { + 0, + "umask", + sys_invalid, + SYSCALL_NOTIMP }, // 60 - umask + { + 0, + "chroot", + sys_invalid, + SYSCALL_NOTIMP }, // 61 - chroot + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, // 62 + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, // 63 + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, // 64 + { + 0, + "msync", + sys_invalid, + SYSCALL_NOTIMP }, // 65 - msync + { + 0, + "vfork", + sys_invalid, + SYSCALL_NOTIMP }, // 66 - vfork + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 67 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 68 - Invalid */ + { + 0, + "sbrk", + sys_invalid, + SYSCALL_NOTIMP }, /* 69 - sbrk */ + { + 0, + "sstk", + sys_invalid, + SYSCALL_NOTIMP }, /* 70 - sstk */ + { + 0, + "old mmap", + sys_invalid, + SYSCALL_INVALID }, // 71 + { + 0, + "vadvise", + sys_invalid, + SYSCALL_NOTIMP }, /* 72 */ + { + ARG_COUNT(sys_munmap_args), + "munmap", + sys_munmap, + SYSCALL_VALID }, /* 73 */ + { + 0, + "mprotect", + sys_invalid, + SYSCALL_NOTIMP }, /* 74 */ + { + 0, + "madvise", + sys_invalid, + SYSCALL_NOTIMP }, /* 75 */ + { + 0, + "Obsolete vhangup", + sys_invalid, + SYSCALL_INVALID }, /* 76 - Invalid */ + { + 0, + "Obsolete vlimit", + sys_invalid, + SYSCALL_INVALID }, /* 77 - Invalid */ + { + 0, + "mincore", + sys_invalid, + SYSCALL_NOTIMP }, /* 78 - minicore */ + { + 0, + "getgroups", + sys_invalid, + SYSCALL_NOTIMP }, /* 79 - getgroups */ + { + 0, + "setgroups", + sys_invalid, + SYSCALL_NOTIMP }, /* 80 - setgroups */ + { + ARG_COUNT(sys_getpgrp_args), + "getpgrp", + sys_getpgrp, + SYSCALL_VALID }, // 81 - getpgrp + { + ARG_COUNT(sys_setpgid_args), + "setpgid", + sys_setpgid, + SYSCALL_VALID }, // 82 - setpgid + { + 0, + "setitimer", + sys_invalid, + SYSCALL_NOTIMP }, /* 83 - setitimer */ + { + 0, + "old wait", + sys_invalid, + SYSCALL_INVALID }, /* 84 - Invalid */ + { + 0, + "swapon", + sys_invalid, + SYSCALL_NOTIMP }, /* 85 - swapon */ + { + 0, + "getitimer", + sys_invalid, + SYSCALL_NOTIMP }, /* 86 - getitimer */ + { + 0, + "old gethostname", + sys_invalid, + SYSCALL_INVALID }, /* 87 */ + { + 0, + "Get Free Page", + (sys_call_t *) sysGetFreePage, + SYSCALL_VALID }, /* 88 - getFreePage TEMP OLD sethostname */ + { + 0, + "getdtablesize", + sys_invalid, + SYSCALL_NOTIMP }, /* 89 - gettablesize */ + { + 0, + "dup2", + sys_invalid, + SYSCALL_NOTIMP }, /* 90 - dup2 */ + { + 0, + "getdopt", + sys_invalid, + SYSCALL_NOTIMP }, /* 91 - getdopt */ + { + ARG_COUNT(sys_fcntl_args), + "fcntl", + sys_fcntl, + SYSCALL_VALID }, // 92 - fcntl + { + ARG_COUNT(sys_select_args), + "select", + sys_select, + SYSCALL_VALID }, // 93 - select + { + 0, + "setdopt", + sys_invalid, + SYSCALL_NOTIMP }, /* 94 - setdopt */ + { + 0, + "fsync", + sys_invalid, + SYSCALL_NOTIMP }, /* 95 - fsync */ + { + 0, + "setpriority", + sys_invalid, + SYSCALL_NOTIMP }, /* 96 - setpriority */ + { + ARG_COUNT(sys_socket_args), + "socket", + sys_socket, + SYSCALL_VALID }, // 97 - socket + { + 0, + "connect", + sys_invalid, + SYSCALL_NOTIMP }, /* 98 - connect */ + { + 0, + "old accept", + sys_invalid, + SYSCALL_INVALID }, /* 99 */ + { + 0, + "getpriority", + sys_invalid, + SYSCALL_NOTIMP }, /* 100 - getpriority */ + { + 0, + "old send", + sys_invalid, + SYSCALL_INVALID }, /* 101 */ + { + 0, + "old recv", + sys_invalid, + SYSCALL_INVALID }, /* 102 */ + { + 0, + "old sigreturn", + sys_invalid, + SYSCALL_INVALID }, /* 103 */ + { + 0, + "bind", + sys_invalid, + SYSCALL_NOTIMP }, // 104 - bind + { + ARG_COUNT(sys_setsockopt_args), + "setsockopt", + sys_setsockopt, + SYSCALL_VALID }, // 105 setsockopt + { + 0, + "listen", + sys_invalid, + SYSCALL_NOTIMP }, /* 106 - listen */ + { + 0, + "obsolete vtimes", + sys_invalid, + SYSCALL_INVALID }, /* 107 */ + { + 0, + "old sigvec", + sys_invalid, + SYSCALL_INVALID }, /* 108 - Invalid */ + { + 0, + "old sigblock", + sys_invalid, + SYSCALL_INVALID }, /* 109 - Invalid */ + { + 0, + "old sigsetmask", + sys_invalid, + SYSCALL_INVALID }, /* 110 - Invalid */ + { + 0, + "old sigsuspend", + sys_invalid, + SYSCALL_INVALID }, /* 111 - Invalid */ + { + 0, + "old sigstack", + sys_invalid, + SYSCALL_INVALID }, /* 112 - Invalid */ + { + 0, + "old recvmsg", + sys_invalid, + SYSCALL_INVALID }, /* 113 - Invalid */ + { + 0, + "old sendmsg", + sys_invalid, + SYSCALL_INVALID }, /* 114 - Invalid */ + { + 0, + "obsolete vtrace", + sys_invalid, + SYSCALL_INVALID }, /* 115 - Invalid */ + { + ARG_COUNT(sys_gettimeofday_args), + "gettimeofday", + sys_gettimeofday, + SYSCALL_VALID }, // 116 - gettimeofday + { + 0, + "getrusage", + sys_invalid, + SYSCALL_NOTIMP }, /* 117 - getrusage */ + { + 0, + "getsockopt", + sys_invalid, + SYSCALL_NOTIMP }, /* 118 - getsockopt */ + { + 0, + "resuba", + sys_invalid, + SYSCALL_NOTIMP }, /* 119 - resuba */ + { + 0, + "readv", + sys_invalid, + SYSCALL_NOTIMP }, /* 120 - readv */ + { + 0, + "writev", + sys_invalid, + SYSCALL_NOTIMP }, /* 121 - writev */ + { + 0, + "settimeofday", + sys_invalid, + SYSCALL_NOTIMP }, /* 122 - settimeofday */ + { + 0, + "fchown", + sys_invalid, + SYSCALL_NOTIMP }, /* 123 - fchown */ + { + 0, + "fchmod", + sys_invalid, + SYSCALL_NOTIMP }, /* 124 - fchmod */ + { + 0, + "old recvfrom", + sys_invalid, + SYSCALL_INVALID }, /* 125 - Invalid */ + { + 0, + "setreuid", + sys_invalid, + SYSCALL_NOTIMP }, /* 126 - setreuid */ + { + 0, + "setregid", + sys_invalid, + SYSCALL_NOTIMP }, /* 127 - setregid */ + { + ARG_COUNT(sys_rename_args), + "rename", + sys_rename, + SYSCALL_VALID }, /* 128 - rename */ + { + 0, + "old truncate", + sys_invalid, + SYSCALL_INVALID }, /* 129 - Invalid */ + { + 0, + "old fruncate", + sys_invalid, + SYSCALL_INVALID }, /* 130 - Invalid */ + { + 0, + "flock", + sys_invalid, + SYSCALL_NOTIMP }, /* 131 - flock */ + { + 0, + "mkfifo", + sys_invalid, + SYSCALL_NOTIMP }, /* 132 - mkfifo */ + { + ARG_COUNT(sys_sendto_args), + "sendto", + sys_sendto, + SYSCALL_VALID }, // 133 - sendto + { + 0, + "shutdown", + sys_invalid, + SYSCALL_NOTIMP }, /* 134 - shutdown */ + { + 0, + "socketpair", + sys_invalid, + SYSCALL_NOTIMP }, /* 135 - socketpair */ + { + 0, + "mkdir", + sys_invalid, + SYSCALL_NOTIMP }, /* 136 - mkdir */ + { + 0, + "rmdir", + sys_invalid, + SYSCALL_NOTIMP }, /* 137 - rmdir */ + { + 0, + "utimes", + sys_invalid, + SYSCALL_NOTIMP }, /* 138 - utimes */ + { + 0, + "obsolete sigreturn", + sys_invalid, + SYSCALL_INVALID }, /* 139 - Invalid */ + { + 0, + "adjtime", + sys_invalid, + SYSCALL_NOTIMP }, /* 140 - adjtime */ + { + 0, + "old getpeername", + sys_invalid, + SYSCALL_INVALID }, /* 141 - Invalid */ + { + 0, + "ikd gethostid", + sys_invalid, + SYSCALL_INVALID }, /* 142 - Invalid */ + { + 0, + "old sethostid", + sys_invalid, + SYSCALL_INVALID }, /* 143 - Invalid */ + { + 0, + "old getrlimit", + sys_invalid, + SYSCALL_INVALID }, /* 144 - Invalid */ + { + 0, + "old setrlimit", + sys_invalid, + SYSCALL_INVALID }, /* 145 - Invalid */ + { + 0, + "old killpg", + sys_invalid, + SYSCALL_INVALID }, /* 146 - Invalid */ + { + 0, + "setsid", + sys_invalid, + SYSCALL_NOTIMP }, /* 147 - setsid */ + { + 0, + "quotactl", + sys_invalid, + SYSCALL_NOTIMP }, /* 148 - quotactl */ + { + 0, + "old quota", + sys_invalid, + SYSCALL_INVALID }, /* 149 - Invalid */ + { + 0, + "old getsockname", + sys_invalid, + SYSCALL_INVALID }, /* 150 - Invalid */ + { + 0, + "sem_lock", + sys_invalid, + SYSCALL_NOTIMP }, /* 151 - sem_lock */ + { + 0, + "sem_wakeup", + sys_invalid, + SYSCALL_NOTIMP }, /* 152 - sem_Wakeup */ + { + 0, + "asyncdaemon", + sys_invalid, + SYSCALL_NOTIMP }, /* 153 - asyncdaemon */ + { + 0, + "nlm_syscall", + sys_invalid, + SYSCALL_NOTIMP }, /* 154 - nlm_syscall */ + { + 0, + "nfssvc", + sys_invalid, + SYSCALL_NOTIMP }, /* 155 - nfssvc */ + { + 0, + "old getdirentries", + sys_invalid, + SYSCALL_INVALID }, /* 156 - Invalid */ + { + 0, + "old statfs", + sys_invalid, + SYSCALL_INVALID }, /* 157 - Invalid */ + { + 0, + "old fstatfs", + sys_invalid, + SYSCALL_INVALID }, /* 158 - Invalid */ + { + 0, + "nosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 159 - nosys */ + { + 0, + "lgetfh", + sys_invalid, + SYSCALL_NOTIMP }, /* 160 - lgetfh */ + { + 0, + "getfh", + sys_invalid, + SYSCALL_NOTIMP }, /* 161 - Invalid */ + { + 0, + "old getdomainname", + sys_invalid, + SYSCALL_INVALID }, /* 162 - Invalid */ + { + 0, + "old setdomainname", + sys_invalid, + SYSCALL_INVALID }, /* 163 - Invalid */ + { + 0, + "old uname", + sys_invalid, + SYSCALL_INVALID }, /* 164 - Invalid */ + { + ARG_COUNT(sys_sysarch_args), + "sysarch", + sys_sysarch, + SYSCALL_VALID }, // 165 - sysarch + { + 0, + "rtprio", + sys_invalid, + SYSCALL_NOTIMP }, /* 166 - rtprio */ + { + 0, + "nosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 167 - nosys */ + { + 0, + "nosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 168 - nosys */ + { + 0, + "semsys", + sys_invalid, + SYSCALL_NOTIMP }, /* 169 - semsys */ + { + 0, + "msgsys", + sys_invalid, + SYSCALL_NOTIMP }, /* 170 - msgsys */ + { + 0, + "shmsys", + sys_invalid, + SYSCALL_NOTIMP }, /* 171 - shmsys */ + { + 0, + "nosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 172 - nosys */ + { + 0, + "old pread", + sys_invalid, + SYSCALL_INVALID }, /* 173 - Invalid */ + { + 0, + "old pwrite", + sys_invalid, + SYSCALL_INVALID }, /* 174 - Invalid */ + { + 0, + "setfib", + sys_invalid, + SYSCALL_NOTIMP }, /* 175 - setfib */ + { + 0, + "ntp_adjtime", + sys_invalid, + SYSCALL_NOTIMP }, /* 176 - ntp_adjtime */ + { + 0, + "sfork", + sys_invalid, + SYSCALL_NOTIMP }, /* 177 - sfork */ + { + 0, + "getdescriptor", + sys_invalid, + SYSCALL_NOTIMP }, /* 178 - getdescriptor */ + { + 0, + "setdescriptor", + sys_invalid, + SYSCALL_NOTIMP }, /* 179 - setdescriptor */ + { + 0, + "nosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 180 - Invalid */ + { + ARG_COUNT(sys_setGID_args), + "setgid", + (sys_call_t *) sys_setGID, + SYSCALL_VALID }, /* 181 - setgid */ + { + 0, + "setegid", + sys_invalid, + SYSCALL_NOTIMP }, // 182 - setegid + { + 0, + "seteuid", + sys_invalid, + SYSCALL_NOTIMP }, // 183 - seteuid + { + 0, + "lfs_bmapv", + sys_invalid, + SYSCALL_NOTIMP }, /* 184 - Invalid */ + { + 0, + "lfs_markv", + sys_invalid, + SYSCALL_NOTIMP }, /* 185 - Invalid */ + { + 0, + "lfs_segclean", + sys_invalid, + SYSCALL_NOTIMP }, /* 186 - Invalid */ + { + 0, + "lfs_segwait", + sys_invalid, + SYSCALL_NOTIMP }, /* 187 - Invalid */ + { + ARG_COUNT(sys_stat_args), + "stat", + (sys_call_t *) sys_stat, + SYSCALL_VALID }, /* 188 - sys_stat */ + { + ARG_COUNT(sys_fstat_args), + "fstat", + (sys_call_t *) sys_fstat, + SYSCALL_VALID }, /* 189 - sys_fstat */ + { + ARG_COUNT(sys_lstat_args), + "lstat", + (sys_call_t *) sys_lstat, + SYSCALL_VALID }, /* 190 - sys_lstat */ + { + 0, + "pathconf", + sys_invalid, + SYSCALL_NOTIMP }, /* 191 - Invalid */ + { + 0, + "fpathconf", + sys_invalid, + SYSCALL_NOTIMP }, /* 192 - Invalid */ + { + 0, + "nosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 193 - Invalid */ + { + ARG_COUNT(sys_getrlimit_args), + "getrlimit", + sys_getrlimit, + SYSCALL_VALID }, /* 194 - Invalid */ + { + ARG_COUNT(sys_setrlimit_args), + "setrlimit", + sys_setrlimit, + SYSCALL_VALID }, /* 195 - Invalid */ + { + ARG_COUNT(sys_getdirentries_args), + "getdirentries", + sys_getdirentries, + SYSCALL_VALID }, // 196 - getdirentries + { + ARG_COUNT(sys_mmap_args), + "old mmap", + (sys_call_t *) sys_mmap, + SYSCALL_INVALID }, /* 197 - sys_mmap */ + { + 0, + "__syscall", + sys_invalid, + SYSCALL_NOTIMP }, /* 198 - Invalid */ + { + 0, + "old lseek", + sys_invalid, + SYSCALL_INVALID }, /* 199 - Invalid */ + { + 0, + "old truncate", + sys_invalid, + SYSCALL_INVALID }, /* 200 - Invalid */ + { + 0, + "old fruncate", + sys_invalid, + SYSCALL_INVALID }, /* 201 - Invalid */ + { + ARG_COUNT(sys_sysctl_args), + "__sysctl", + (sys_call_t *) sys_sysctl, + SYSCALL_VALID }, /* 202 - sys_sysctl */ + { + 0, + "mlock", + sys_invalid, + SYSCALL_NOTIMP }, /* 203 - Invalid */ + { + 0, + "munlock", + sys_invalid, + SYSCALL_NOTIMP }, /* 204 - Invalid */ + { + 0, + "undelete", + sys_invalid, + SYSCALL_NOTIMP }, /* 205 - Invalid */ + { + 0, + "futimes", + sys_invalid, + SYSCALL_NOTIMP }, /* 206 - Invalid */ + { + 0, + "getpgid", + sys_invalid, + SYSCALL_NOTIMP }, /* 207 - Invalid */ + { + 0, + "reboot", + sys_invalid, + SYSCALL_NOTIMP }, /* 208 - Invalid */ + { + 0, + "poll", + sys_invalid, + SYSCALL_NOTIMP }, /* 209 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 210 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 211 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 212 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 213 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 214 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 215 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 216 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 217 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 218 - Invalid */ + { + 0, + "lkmnosys", + sys_invalid, + SYSCALL_NOTIMP }, /* 219 - Invalid */ + { + 0, + "old __semctl", + sys_invalid, + SYSCALL_INVALID }, /* 220 - Invalid */ + { + 0, + "semget", + sys_invalid, + SYSCALL_NOTIMP }, /* 221 - Invalid */ + { + 0, + "semop", + sys_invalid, + SYSCALL_NOTIMP }, /* 222 - Invalid */ + { + 0, + "semconfig", + sys_invalid, + SYSCALL_NOTIMP }, /* 223 - Invalid */ + { + 0, + "old msgctl", + sys_invalid, + SYSCALL_INVALID }, /* 224 - Invalid */ + { + 0, + "msgget", + sys_invalid, + SYSCALL_NOTIMP }, /* 225 - Invalid */ + { + 0, + "msgsnd", + sys_invalid, + SYSCALL_NOTIMP }, /* 226 - Invalid */ + { + 0, + "msgrcv", + sys_invalid, + SYSCALL_NOTIMP }, /* 227 - Invalid */ + { + 0, + "shmat", + sys_invalid, + SYSCALL_NOTIMP }, /* 228 - Invalid */ + { + 0, + "old shmctl", + sys_invalid, + SYSCALL_INVALID }, /* 229 - Invalid */ + { + 0, + "shmdt", + sys_invalid, + SYSCALL_NOTIMP }, /* 230 - Invalid */ + { + 0, + "shmget", + sys_invalid, + SYSCALL_NOTIMP }, /* 231 - Invalid */ + { + 0, + "clock_gettime", + sys_invalid, + SYSCALL_NOTIMP }, /* 232 - Invalid */ + { + 0, + "clock_settime", + sys_invalid, + SYSCALL_NOTIMP }, /* 233 - Invalid */ + { + 0, + "clock_getres", + sys_invalid, + SYSCALL_NOTIMP }, /* 234 - Invalid */ + { + 0, + "ktimer_create", + sys_invalid, + SYSCALL_NOTIMP }, /* 235 - Invalid */ + { + 0, + "ktimer_delete", + sys_invalid, + SYSCALL_NOTIMP }, /* 236 - Invalid */ + { + 0, + "ktimer_settime", + sys_invalid, + SYSCALL_NOTIMP }, /* 237 - Invalid */ + { + 0, + "ktimer_gettime", + sys_invalid, + SYSCALL_NOTIMP }, /* 238 - Invalid */ + { + 0, + "ktimer_getoverrun", + sys_invalid, + SYSCALL_NOTIMP }, /* 239 - Invalid */ + { + 0, + "nanosleep", + sys_invalid, + SYSCALL_NOTIMP }, /* 240 - Invalid */ + { + 0, + "ffclock_getcounter", + sys_invalid, + SYSCALL_NOTIMP }, /* 241 - Invalid */ + { + 0, + "ffclock_setestimate", + sys_invalid, + SYSCALL_NOTIMP }, /* 242 - Invalid */ + { + 0, + "fflock_getestimate", + sys_invalid, + SYSCALL_NOTIMP }, /* 243 - Invalid */ + { + 0, + "clock_nanosleep", + sys_invalid, + SYSCALL_NOTIMP }, /* 244 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 245 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 246 - Invalid */ + { + 0, + "clock_getcpuclockid2", + sys_invalid, + SYSCALL_NOTIMP }, /* 247 - Invalid */ + { + 0, + "ntp_gettime", + sys_invalid, + SYSCALL_NOTIMP }, /* 248 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 249 - Invalid */ + { + 0, + "minherit", + sys_invalid, + SYSCALL_NOTIMP }, /* 250 - Invalid */ + { + 0, + "rfork", + sys_invalid, + SYSCALL_NOTIMP }, /* 251 - Invalid */ + { + 0, + "openbsd_poll", + sys_invalid, + SYSCALL_NOTIMP }, /* 252 - Invalid */ + { + ARG_COUNT(sys_issetugid_args), + "issetugid", + (sys_call_t *) sys_issetugid, + SYSCALL_VALID }, /* 253 - Invalid */ + { + 0, + "lchown", + sys_invalid, + SYSCALL_NOTIMP }, /* 254 - Invalid */ + { + 0, + "aio_read", + sys_invalid, + SYSCALL_NOTIMP }, /* 255 - Invalid */ + { + 0, + "aio_write", + sys_invalid, + SYSCALL_NOTIMP }, /* 256 - Invalid */ + { + 0, + "lio_listio", + sys_invalid, + SYSCALL_NOTIMP }, /* 257 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 258 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 259 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 260 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 261 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 262 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 263 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 264 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 265 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 266 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 267 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 268 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 269 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 270 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 271 - Invalid */ + { + 0, + "getdents", + sys_invalid, + SYSCALL_NOTIMP }, /* 272 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 273 - Invalid */ + { + 0, + "lchmod", + sys_invalid, + SYSCALL_NOTIMP }, /* 274 - Invalid */ + { + 0, + "netbsd_lchown", + sys_invalid, + SYSCALL_NOTIMP }, /* 275 - Invalid */ + { + 0, + "lutimes", + sys_invalid, + SYSCALL_NOTIMP }, /* 276 - Invalid */ + { + 0, + "netbsd_msync", + sys_invalid, + SYSCALL_NOTIMP }, /* 277 - Invalid */ + { + 0, + "nstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 278 - Invalid */ + { + 0, + "nfstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 279 - Invalid */ + { + 0, + "nlstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 280 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 281 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 282 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 283 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 284 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 285 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 286 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 287 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 288 - Invalid */ + { + 0, + "preadv", + sys_invalid, + SYSCALL_NOTIMP }, /* 289 - Invalid */ + { + 0, + "pwritev", + sys_invalid, + SYSCALL_NOTIMP }, /* 290 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 291 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 292 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 293 - Invalid */ + { + ARG_COUNT(sys_fseek_args), + "feek", + (sys_call_t *) sys_fseek, + SYSCALL_VALID }, /* XXX - Wrong Spot 294 - fseek */ + { + ARG_COUNT(sys_fgetc_args), + "fgetc", + (sys_call_t *) sys_fgetc, + SYSCALL_VALID }, /* XXX - Wrong Spot 295 - fgetc */ + { + ARG_COUNT(sys_fclose_args), + "flose", + (sys_call_t *) sys_fclose, + SYSCALL_VALID }, /* XXX - Wrong Spot 296 - fclose */ + { + ARG_COUNT(sys_fread_args), + "fread", + (sys_call_t *) sys_fread, + SYSCALL_VALID }, /* XXX - Wrong Spot 297 - fread */ + { + ARG_COUNT(sys_fopen_args), + "fopen", + (sys_call_t *) sys_fopen, + SYSCALL_VALID }, /* XXX - Wrong Spot 298 - fopen */ + { + 0, + "fhstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 299 - Invalid */ + { + 0, + "modnext", + sys_invalid, + SYSCALL_NOTIMP }, /* 300 - Invalid */ + { + 0, + "modstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 301 - Invalid */ + { + 0, + "modfnext", + sys_invalid, + SYSCALL_NOTIMP }, /* 302 - Invalid */ + { + 0, + "modfind", + sys_invalid, + SYSCALL_NOTIMP }, /* 303 - Invalid */ + { + 0, + "kldload", + sys_invalid, + SYSCALL_NOTIMP }, /* 304 - Invalid */ + { + 0, + "kldunload", + sys_invalid, + SYSCALL_NOTIMP }, /* 305 - Invalid */ + { + 0, + "kldfind", + sys_invalid, + SYSCALL_NOTIMP }, /* 306 - Invalid */ + { + 0, + "kldnext", + sys_invalid, + SYSCALL_NOTIMP }, /* 307 - Invalid */ + { + 0, + "kldstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 308 - Invalid */ + { + 0, + "kldfirstmod", + sys_invalid, + SYSCALL_NOTIMP }, /* 309 - Invalid */ + { + 0, + "getsid", + sys_invalid, + SYSCALL_NOTIMP }, /* 310 - Invalid */ + { + 0, + "setresuid", + sys_invalid, + SYSCALL_NOTIMP }, /* 311 - Invalid */ + { + 0, + "setresgid", + sys_invalid, + SYSCALL_NOTIMP }, /* 312 - Invalid */ + { + 0, + "obsolete signanosleep", + sys_invalid, + SYSCALL_INVALID }, /* 313 - Invalid */ + { + 0, + "aio_return", + sys_invalid, + SYSCALL_NOTIMP }, /* 314 - Invalid */ + { + 0, + "aio_suspend", + sys_invalid, + SYSCALL_NOTIMP }, /* 315 - Invalid */ + { + 0, + "aio_cancel", + sys_invalid, + SYSCALL_NOTIMP }, /* 316 - Invalid */ + { + 0, + "aio_error", + sys_invalid, + SYSCALL_NOTIMP }, /* 317 - Invalid */ + { + 0, + "old aio_read", + sys_invalid, + SYSCALL_INVALID }, /* 318 - Invalid */ + { + 0, + "old aio_write", + sys_invalid, + SYSCALL_INVALID }, /* 319 - Invalid */ + { + 0, + "old lio_listio", + sys_invalid, + SYSCALL_INVALID }, /* 320 - Invalid */ + { + 0, + "yield", + sys_invalid, + SYSCALL_NOTIMP }, /* 321 - Invalid */ + { + 0, + "obsolete thr_sleep", + sys_invalid, + SYSCALL_INVALID }, /* 322 - Invalid */ + { + 0, + "obsolete thr_wakeup", + sys_invalid, + SYSCALL_INVALID }, /* 323 - Invalid */ + { + 0, + "mlockall", + sys_invalid, + SYSCALL_NOTIMP }, /* 324 - Invalid */ + { + 0, + "munlockall", + sys_invalid, + SYSCALL_NOTIMP }, /* 325 - Invalid */ + { + ARG_COUNT(sys_getcwd_args), + "__getcwd", + (sys_call_t *) sys_getcwd, + SYSCALL_VALID }, /* 326 - sys_getcwd */ + { + 0, + "sched_setparam", + sys_invalid, + SYSCALL_NOTIMP }, /* 327 - Invalid */ + { + 0, + "sched_getparam", + sys_invalid, + SYSCALL_NOTIMP }, /* 328 - Invalid */ + { + 0, + "sched_setscheduler", + sys_invalid, + SYSCALL_NOTIMP }, /* 329 - Invalid */ + { + 0, + "sched_getscheduler", + sys_invalid, + SYSCALL_NOTIMP }, /* 330 - Invalid */ + { + 0, + "sched_yield", + sys_sched_yield, + SYSCALL_VALID }, /* 331 - sys_sched_yield */ + { + 0, + "sched_get_priority_max", + sys_invalid, + SYSCALL_NOTIMP }, /* 332 - Invalid */ + { + 0, + "sched_get_priority_min", + sys_invalid, + SYSCALL_NOTIMP }, /* 333 - Invalid */ + { + 0, + "sched_rr_get_interval", + sys_invalid, + SYSCALL_NOTIMP }, /* 334 - Invalid */ + { + 0, + "utrace", + sys_invalid, + SYSCALL_NOTIMP }, /* 335 - Invalid */ + { + 0, + "old sendfile", + sys_invalid, + SYSCALL_INVALID }, /* 336 - Invalid */ + { + 0, + "kldsym", + sys_invalid, + SYSCALL_NOTIMP }, /* 337 - Invalid */ + { + 0, + "jail", + sys_invalid, + SYSCALL_NOTIMP }, /* 338 - Invalid */ + { + 0, + "nnpfs_syscall", + sys_invalid, + SYSCALL_NOTIMP }, /* 339 - Invalid */ + { + ARG_COUNT(sys_sigprocmask_args), + "sigprocmask", + sys_sigprocmask, + SYSCALL_VALID }, // 340 - sigprocmask + { + 0, + "sigsuspend", + sys_invalid, + SYSCALL_NOTIMP }, /* 341 - Invalid */ + { + 0, + "old sigaction", + sys_invalid, + SYSCALL_INVALID }, /* 342 - Invalid */ + { + 0, + "sigpending", + sys_invalid, + SYSCALL_NOTIMP }, /* 343 - Invalid */ + { + 0, + "old sigreturn", + sys_invalid, + SYSCALL_INVALID }, /* 344 - Invalid */ + { + 0, + "sigtimedwait", + sys_invalid, + SYSCALL_NOTIMP }, /* 345 - Invalid */ + { + 0, + "sigwaitinfo", + sys_invalid, + SYSCALL_NOTIMP }, /* 346 - Invalid */ + { + 0, + "__acl_get_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 347 - Invalid */ + { + 0, + "__acl_set_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 348 - Invalid */ + { + 0, + "__acl_get_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 349 - Invalid */ + { + 0, + "__acl_set_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 350 - Invalid */ + { + 0, + "__acl_delete_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 351 - Invalid */ + { + 0, + "__acl_delete_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 352 - Invalid */ + { + 0, + "__acl_aclcheck_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 353 - Invalid */ + { + 0, + "__acl_aclcheck_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 354 - Invalid */ + { + 0, + "extattrctl", + sys_invalid, + SYSCALL_NOTIMP }, /* 355 - Invalid */ + { + 0, + "extattr_set_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 356 - Invalid */ + { + 0, + "extattr_get_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 357 - Invalid */ + { + 0, + "extattr_delete_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 358 - Invalid */ + { + 0, + "aio_waitcomplete", + sys_invalid, + SYSCALL_NOTIMP }, /* 359 - Invalid */ + { + 0, + "getresuid", + sys_invalid, + SYSCALL_NOTIMP }, /* 360 - Invalid */ + { + 0, + "getresgid", + sys_invalid, + SYSCALL_NOTIMP }, /* 361 - Invalid */ + { + 0, + "kqueue", + sys_invalid, + SYSCALL_NOTIMP }, /* 362 - Invalid */ + { + 0, + "kevent", + sys_invalid, + SYSCALL_NOTIMP }, /* 363 - Invalid */ + { + 0, + "__cap_get_proc", + sys_invalid, + SYSCALL_NOTIMP }, /* 364 - Invalid */ + { + 0, + "__cap_set_proc", + sys_invalid, + SYSCALL_NOTIMP }, /* 365 - Invalid */ + { + 0, + "__cap_get_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 366 - Invalid */ + { + 0, + "__cap_get_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 367 - Invalid */ + { + 0, + "__cap_set_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 368 - Invalid */ + { + 0, + "__cap_set_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 369 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 370 - Invalid */ + { + 0, + "extattr_set_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 371 - Invalid */ + { + 0, + "extattr_get_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 372 - Invalid */ + { + 0, + "extattr_delete_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 373 - Invalid */ + { + 0, + "__setugid", + sys_invalid, + SYSCALL_NOTIMP }, /* 374 - Invalid */ + { + 0, + "nfsclnt", + sys_invalid, + SYSCALL_NOTIMP }, /* 375 - Invalid */ + { + 0, + "eaccess", + sys_invalid, + SYSCALL_NOTIMP }, /* 376 - Invalid */ + { + 0, + "afs2_syscall", + sys_invalid, + SYSCALL_NOTIMP }, /* 377 - Invalid */ + { + 0, + "nmount", + sys_invalid, + SYSCALL_NOTIMP }, /* 378 - Invalid */ + { + 0, + "kse_exit", + sys_invalid, + SYSCALL_NOTIMP }, /* 379 - Invalid */ + { + 0, + "kse_wakeup", + sys_invalid, + SYSCALL_NOTIMP }, /* 380 - Invalid */ + { + 0, + "kse_create", + sys_invalid, + SYSCALL_NOTIMP }, /* 381 - Invalid */ + { + 0, + "kse_thr_interrupt", + sys_invalid, + SYSCALL_NOTIMP }, /* 382 - Invalid */ + { + 0, + "kse_release", + sys_invalid, + SYSCALL_NOTIMP }, /* 383 - Invalid */ + { + 0, + "__mac_get_proc", + sys_invalid, + SYSCALL_NOTIMP }, /* 384 - Invalid */ + { + 0, + "__mac_set_proc", + sys_invalid, + SYSCALL_NOTIMP }, /* 385 - Invalid */ + { + 0, + "__mac_get_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 386 - Invalid */ + { + 0, + "__mac_get_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 387 - Invalid */ + { + 0, + "__mac_set_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 388 - Invalid */ + { + 0, + "__mac_set_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 389 - Invalid */ + { + 0, + "kenv", + sys_invalid, + SYSCALL_NOTIMP }, /* 390 - Invalid */ + { + 0, + "lchflags", + sys_invalid, + SYSCALL_NOTIMP }, /* 391 - Invalid */ + { + 0, + "uuidgen", + sys_invalid, + SYSCALL_NOTIMP }, /* 392 - Invalid */ + { + 0, + "sendfile", + sys_invalid, + SYSCALL_NOTIMP }, /* 393 - Invalid */ + { + 0, + "mac_syscall", + sys_invalid, + SYSCALL_NOTIMP }, /* 394 - Invalid */ + { + 0, + "getfsstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 395 - Invalid */ + { + ARG_COUNT(sys_statfs_args), + "statfs", + (sys_call_t *) sys_statfs, + SYSCALL_VALID }, // 396 statfs + { + ARG_COUNT(sys_fstatfs_args), + "fstatfs", + (sys_call_t *) sys_fstatfs, + SYSCALL_VALID }, // 397 fstatfs + { + 0, + "fhstatfs", + sys_invalid, + SYSCALL_NOTIMP }, /* 398 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 399 - Invalid */ + { + 0, + "ksem_close", + sys_invalid, + SYSCALL_NOTIMP }, /* 400 - Invalid */ + { + 0, + "ksem_post", + sys_invalid, + SYSCALL_NOTIMP }, /* 401 - Invalid */ + { + 0, + "ksem_wait", + sys_invalid, + SYSCALL_NOTIMP }, /* 402 - Invalid */ + { + 0, + "ksem_trywait", + sys_invalid, + SYSCALL_NOTIMP }, /* 403 - Invalid */ + { + 0, + "ksem_init", + sys_invalid, + SYSCALL_NOTIMP }, /* 404 - Invalid */ + { + 0, + "ksem_open", + sys_invalid, + SYSCALL_NOTIMP }, /* 405 - Invalid */ + { + 0, + "ksem_unlink", + sys_invalid, + SYSCALL_NOTIMP }, /* 406 - Invalid */ + { + 0, + "ksem_getvalue", + sys_invalid, + SYSCALL_NOTIMP }, /* 407 - Invalid */ + { + 0, + "ksem_destroy", + sys_invalid, + SYSCALL_NOTIMP }, /* 408 - Invalid */ + { + 0, + "__mac_get_pid", + sys_invalid, + SYSCALL_NOTIMP }, /* 409 - Invalid */ + { + 0, + "__mac_get_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 410 - Invalid */ + { + 0, + "__mac_set_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 411 - Invalid */ + { + 0, + "extattr_set_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 412 - Invalid */ + { + 0, + "extattr_get_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 413 - Invalid */ + { + 0, + "extattr_delete_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 414 - Invalid */ + { + 0, + "__mac_execve", + sys_invalid, + SYSCALL_NOTIMP }, /* 415 - Invalid */ + { + ARG_COUNT(sys_sigaction_args), + "sigaction", + sys_sigaction, + SYSCALL_VALID }, // 416 - sigaction + { + 0, + "sigreturn", + sys_invalid, + SYSCALL_NOTIMP }, /* 417 - Invalid */ + { + 0, + "__xstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 418 - Invalid */ + { + 0, + "__xfstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 419 - Invalid */ + { + 0, + "__xlstat", + sys_invalid, + SYSCALL_NOTIMP }, /* 420 - Invalid */ + { + 0, + "getcontext", + sys_invalid, + SYSCALL_NOTIMP }, /* 421 - Invalid */ + { + 0, + "setcontext", + sys_invalid, + SYSCALL_NOTIMP }, /* 422 - Invalid */ + { + 0, + "swapcontext", + sys_invalid, + SYSCALL_NOTIMP }, /* 423 - Invalid */ + { + 0, + "swapoff", + sys_invalid, + SYSCALL_NOTIMP }, /* 424 - Invalid */ + { + 0, + "__acl_get_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 425 - Invalid */ + { + 0, + "__acl_set_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 426 - Invalid */ + { + 0, + "__acl_delete_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 427 - Invalid */ + { + 0, + "__acl_aclcheck_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 428 - Invalid */ + { + 0, + "sigwait", + sys_invalid, + SYSCALL_NOTIMP }, /* 429 - Invalid */ + { + 0, + "thr_create", + sys_invalid, + SYSCALL_NOTIMP }, /* 430 - Invalid */ + { + 0, + "thr_exit", + sys_invalid, + SYSCALL_NOTIMP }, /* 431 - Invalid */ + { + 0, + "thr_self", + sys_invalid, + SYSCALL_NOTIMP }, /* 432 - Invalid */ + { + 0, + "thr_kill", + sys_invalid, + SYSCALL_NOTIMP }, /* 433 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 434 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 435 - Invalid */ + { + 0, + "jail_attach", + sys_invalid, + SYSCALL_NOTIMP }, /* 436 - Invalid */ + { + 0, + "extattr_list_fd", + sys_invalid, + SYSCALL_NOTIMP }, /* 437 - Invalid */ + { + 0, + "extattr_list_file", + sys_invalid, + SYSCALL_NOTIMP }, /* 438 - Invalid */ + { + 0, + "extattr_list_link", + sys_invalid, + SYSCALL_NOTIMP }, /* 439 - Invalid */ + { + 0, + "kse_switchin", + sys_invalid, + SYSCALL_NOTIMP }, /* 440 - Invalid */ + { + 0, + "ksem_timedwait", + sys_invalid, + SYSCALL_NOTIMP }, /* 441 - Invalid */ + { + 0, + "thr_suspend", + sys_invalid, + SYSCALL_NOTIMP }, /* 442 - Invalid */ + { + 0, + "thr_wake", + sys_invalid, + SYSCALL_NOTIMP }, /* 443 - Invalid */ + { + 0, + "kldunloadf", + sys_invalid, + SYSCALL_NOTIMP }, /* 444 - Invalid */ + { + 0, + "audit", + sys_invalid, + SYSCALL_NOTIMP }, /* 445 - Invalid */ + { + 0, + "auditon", + sys_invalid, + SYSCALL_NOTIMP }, /* 446 - Invalid */ + { + 0, + "getauid", + sys_invalid, + SYSCALL_NOTIMP }, /* 447 - Invalid */ + { + 0, + "setauid", + sys_invalid, + SYSCALL_NOTIMP }, /* 448 - Invalid */ + { + 0, + "getaudit", + sys_invalid, + SYSCALL_NOTIMP }, /* 449 - Invalid */ + { + 0, + "setauid", + sys_invalid, + SYSCALL_NOTIMP }, /* 450 - Invalid */ + { + 0, + "getaudit_addr", + sys_invalid, + SYSCALL_NOTIMP }, /* 451 - Invalid */ + { + 0, + "setaudit_addr", + sys_invalid, + SYSCALL_NOTIMP }, /* 452 - Invalid */ + { + 0, + "auditctl", + sys_invalid, + SYSCALL_NOTIMP }, /* 453 - Invalid */ + { + 0, + "_umtx_op", + sys_invalid, + SYSCALL_NOTIMP }, /* 454 - Invalid */ + { + 0, + "thr_new", + sys_invalid, + SYSCALL_NOTIMP }, /* 455 - Invalid */ + { + 0, + "sigqueue", + sys_invalid, + SYSCALL_NOTIMP }, /* 456 - Invalid */ + { + 0, + "kmq_open", + sys_invalid, + SYSCALL_NOTIMP }, /* 457 - Invalid */ + { + 0, + "kmq_setattr", + sys_invalid, + SYSCALL_NOTIMP }, /* 458 - Invalid */ + { + 0, + "kmq_timedreceive", + sys_invalid, + SYSCALL_NOTIMP }, /* 459 - Invalid */ + { + 0, + "kmq_timedsend", + sys_invalid, + SYSCALL_NOTIMP }, /* 460 - Invalid */ + { + 0, + "kmq_notify", + sys_invalid, + SYSCALL_NOTIMP }, /* 461 - Invalid */ + { + 0, + "kmq_unlink", + sys_invalid, + SYSCALL_NOTIMP }, /* 462 - Invalid */ + { + 0, + "abort2", + sys_invalid, + SYSCALL_NOTIMP }, /* 463 - Invalid */ + { + 0, + "thr_set_name", + sys_invalid, + SYSCALL_NOTIMP }, /* 464 - Invalid */ + { + 0, + "aio_fsync", + sys_invalid, + SYSCALL_NOTIMP }, /* 465 - Invalid */ + { + 0, + "rtprio_thread", + sys_invalid, + SYSCALL_NOTIMP }, /* 466 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 467 - Invalid */ + { + 0, + "No Call", + sys_invalid, + SYSCALL_INVALID }, /* 468 - Invalid */ + { + 0, + "__getpath_fromfd", + sys_invalid, + SYSCALL_NOTIMP }, /* 469 - Invalid */ + { + 0, + "__getpath_fromaddr", + sys_invalid, + SYSCALL_NOTIMP }, /* 470 - Invalid */ + { + 0, + "sctp_peeloff", + sys_invalid, + SYSCALL_NOTIMP }, /* 471 - Invalid */ + { + 0, + "sctp_generic_sendmsg", + sys_invalid, + SYSCALL_NOTIMP }, /* 472 - Invalid */ + { + 0, + "sctp_generic_sendmsg_iov", + sys_invalid, + SYSCALL_NOTIMP }, /* 473 - Invalid */ + { + 0, + "sctp_generic_recvmsg", + sys_invalid, + SYSCALL_NOTIMP }, /* 474 - Invalid */ + { + ARG_COUNT(sys_pread_args), + "pread", + sys_pread, + SYSCALL_VALID }, // 475 - pread + { + 0, + "pwrite", + sys_invalid, + SYSCALL_NOTIMP }, /* 476 - Invalid */ + { + ARG_COUNT(sys_mmap_args), + "mmap", + (sys_call_t *) sys_mmap, + SYSCALL_VALID }, /* 477 - sys_mmap */ + { + ARG_COUNT(sys_lseek_args), + "lseek", + (sys_call_t *) sys_lseek, + SYSCALL_VALID }, /* 478 - sys_lseek */ + { + 0, + "truncate", + sys_invalid, + SYSCALL_NOTIMP }, /* 479 - Invalid */ + { + 0, + "ftruncate", + sys_invalid, + SYSCALL_NOTIMP }, /* 480 - Invalid */ + { + 0, + "thr_kill2", + sys_invalid, + SYSCALL_NOTIMP }, /* 481 - Invalid */ + { + 0, + "shm_open", + sys_invalid, + SYSCALL_NOTIMP }, /* 482 - Invalid */ + { + 0, + "shm_unlink", + sys_invalid, + SYSCALL_NOTIMP }, /* 483 - Invalid */ + { + 0, + "cpuset", + sys_invalid, + SYSCALL_NOTIMP }, /* 484 - Invalid */ + { + 0, + "cpuset_setid", + sys_invalid, + SYSCALL_NOTIMP }, /* 485 - Invalid */ + { + 0, + "cpuset_getid", + sys_invalid, + SYSCALL_NOTIMP }, /* 486 - Invalid */ + { + 0, + "cpuset_getaffinity", + sys_invalid, + SYSCALL_NOTIMP }, /* 487 - Invalid */ + { + 0, + "cpuset_setaffinity", + sys_invalid, + SYSCALL_NOTIMP }, /* 488 - Invalid */ + { + 0, + "faccessat", + sys_invalid, + SYSCALL_NOTIMP }, /* 489 - Invalid */ + { + 0, + "fchmodat", + sys_invalid, + SYSCALL_NOTIMP }, /* 490 - Invalid */ + { + 0, + "fchownat", + sys_invalid, + SYSCALL_NOTIMP }, /* 491 - Invalid */ + { + 0, + "fexecve", + sys_invalid, + SYSCALL_NOTIMP }, /* 492 - Invalid */ + { + ARG_COUNT(sys_fstatat_args), + "fstatat", + sys_fstatat, + SYSCALL_VALID }, // 493 - fstatat + { + 0, + "futimesat", + sys_invalid, + SYSCALL_NOTIMP }, /* 494 - Invalid */ + { + 0, + "linkat", + sys_invalid, + SYSCALL_NOTIMP }, /* 495 - Invalid */ + { + 0, + "mkdirat", + sys_invalid, + SYSCALL_NOTIMP }, /* 496 - Invalid */ + { + 0, + "mkfifoat", + sys_invalid, + SYSCALL_NOTIMP }, /* 497 - Invalid */ + { + 0, + "mknodat", + sys_invalid, + SYSCALL_NOTIMP }, /* 498 - Invalid */ + { + ARG_COUNT(sys_openat_args), + "openat", + sys_openat, + SYSCALL_VALID }, /* 499 - sys_openat */ + { + 0, + "readlinkat", + sys_invalid, + SYSCALL_NOTIMP }, /* 500 - Invalid */ + { + 0, + "renameat", + sys_invalid, + SYSCALL_NOTIMP }, /* 501 - Invalid */ + { + 0, + "symlinkat", + sys_invalid, + SYSCALL_NOTIMP }, /* 502 - Invalid */ + { + 0, + "unlinkat", + sys_invalid, + SYSCALL_NOTIMP }, /* 503 - Invalid */ + { + 0, + "posix_openpt", + sys_invalid, + SYSCALL_NOTIMP }, /* 504 - Invalid */ + { + 0, + "gssd_syscall", + sys_invalid, + SYSCALL_NOTIMP }, /* 505 - Invalid */ + { + 0, + "jail_get", + sys_invalid, + SYSCALL_NOTIMP }, /* 506 - Invalid */ + { + 0, + "jail_set", + sys_invalid, + SYSCALL_NOTIMP }, /* 507 - Invalid */ + { + 0, + "jail_remove", + sys_invalid, + SYSCALL_NOTIMP }, /* 508 - Invalid */ + { + 0, + "closefrom", + sys_invalid, + SYSCALL_NOTIMP }, /* 509 - Invalid */ + { + 0, + "__semctl", + sys_invalid, + SYSCALL_NOTIMP }, /* 510 - Invalid */ + { + 0, + "msgctl", + sys_invalid, + SYSCALL_NOTIMP }, /* 511 - Invalid */ + { + 0, + "shmctl", + sys_invalid, + SYSCALL_NOTIMP }, /* 512 - Invalid */ + { + 0, + "lpathconf", + sys_invalid, + SYSCALL_NOTIMP }, /* 513 - Invalid */ + { + 0, + "obsolete cap_new", + sys_invalid, + SYSCALL_INVALID }, /* 514 - Invalid */ + { + 0, + "__cap_rights_get", + sys_invalid, + SYSCALL_NOTIMP }, /* 515 - Invalid */ + { + 0, + "cap_enter", + sys_invalid, + SYSCALL_NOTIMP }, /* 516 - Invalid */ + { + 0, + "cap_getmode", + sys_invalid, + SYSCALL_NOTIMP }, /* 517 - Invalid */ + { + 0, + "pdfork", + sys_invalid, + SYSCALL_NOTIMP }, /* 518 - Invalid */ + { + 0, + "pdkill", + sys_invalid, + SYSCALL_NOTIMP }, /* 519 - Invalid */ + { + 0, + "pdgetpid", + sys_invalid, + SYSCALL_NOTIMP }, /* 520 - Invalid */ + { + 0, + "pdwait4", + sys_invalid, + SYSCALL_NOTIMP }, /* 521 - Invalid */ + { + 0, + "pselect", + sys_invalid, + SYSCALL_NOTIMP }, /* 522 - Invalid */ + { + 0, + "getloginclass", + sys_invalid, + SYSCALL_NOTIMP }, /* 523 - Invalid */ + { + 0, + "setloginclass", + sys_invalid, + SYSCALL_NOTIMP }, /* 524 - Invalid */ + { + 0, + "rctl_get_racct", + sys_invalid, + SYSCALL_NOTIMP }, /* 525 - Invalid */ + { + 0, + "rctl_get_rules", + sys_invalid, + SYSCALL_NOTIMP }, /* 526 - Invalid */ + { + 0, + "rctl_get_limits", + sys_invalid, + SYSCALL_NOTIMP }, /* 527 - Invalid */ + { + 0, + "rctl_add_rule", + sys_invalid, + SYSCALL_NOTIMP }, /* 528 - Invalid */ + { + 0, + "rctl_remove_rule", + sys_invalid, + SYSCALL_NOTIMP }, /* 529 - Invalid */ + { + 0, + "posix_fallocate", + sys_invalid, + SYSCALL_NOTIMP }, /* 530 - Invalid */ + { + 0, + "posix_fadvise", + sys_invalid, + SYSCALL_NOTIMP }, /* 531 - Invalid */ + { + 0, + "wait6", + sys_invalid, + SYSCALL_NOTIMP }, /* 532 - Invalid */ + { + 0, + "cap_rights_limit", + sys_invalid, + SYSCALL_NOTIMP }, /* 533 - Invalid */ + { + 0, + "cap_ioctls_limit", + sys_invalid, + SYSCALL_NOTIMP }, /* 534 - Invalid */ + { + 0, + "cap_ioctls_get", + sys_invalid, + SYSCALL_NOTIMP }, /* 535 - Invalid */ + { + 0, + "cap_fcntls_limit", + sys_invalid, + SYSCALL_NOTIMP }, /* 536 - Invalid */ + { + 0, + "cap_fcntls_get", + sys_invalid, + SYSCALL_NOTIMP }, /* 537 - Invalid */ + { + 0, + "bindat", + sys_invalid, + SYSCALL_NOTIMP }, /* 538 - Invalid */ + { + 0, + "connectact", + sys_invalid, + SYSCALL_NOTIMP }, /* 539 - Invalid */ + { + 0, + "chflagsat", + sys_invalid, + SYSCALL_NOTIMP }, /* 540 - Invalid */ + { + 0, + "accept4", + sys_invalid, + SYSCALL_NOTIMP }, /* 541 - Invalid */ + { + 0, + "pipe2", + sys_pipe2, + SYSCALL_VALID }, /* 542 */ + { + 0, + "aio_mlock", + sys_invalid, + SYSCALL_NOTIMP }, /* 543 - Invalid */ + { + 0, + "procctl", + sys_invalid, + SYSCALL_NOTIMP }, /* 544 - Invalid */ + { + 0, + "ppoll", + sys_invalid, + SYSCALL_NOTIMP }, /* 545 - Invalid */ + { + 0, + "futimens", + sys_invalid, + SYSCALL_NOTIMP }, /* 546 - Invalid */ + { + 0, + "utimensat", + sys_invalid, + SYSCALL_NOTIMP }, /* 547 - Invalid */ + { + 0, + "numa_getaffinity", + sys_invalid, + SYSCALL_NOTIMP }, /* 548 - Invalid */ + { + 0, + "num_setaffinity", + sys_invalid, + SYSCALL_NOTIMP }, /* 549 - Invalid */ + { + 0, + "fdatasync", + sys_invalid, + SYSCALL_NOTIMP }, /* 550 - Invalid */ }; int totalCalls_posix = sizeof(systemCalls_posix) / sizeof(struct syscall_entry); diff --git a/sys/kernel/vfs_calls.c b/sys/kernel/vfs_calls.c index c90e49f..f669668 100644 --- a/sys/kernel/vfs_calls.c +++ b/sys/kernel/vfs_calls.c @@ -31,48 +31,33 @@ #include #include #include +#include +#include +#include #include #include int sys_open(struct thread *td, struct sys_open_args *args) { + + return (kern_openat(td, AT_FDCWD, args->path, args->flags, args->mode)); + +} + +int sys_openat(struct thread *td, struct sys_openat_args *args) { + int error = 0x0; int fd = 0x0; struct file *nfp = 0x0; +#ifdef DEBUG_OPENAT + kprintf("openat"); +#endif + error = falloc(td, &nfp, &fd); if (error) return (error); - kprintf("sO: 0x%X:%s", args->mode, args->path); - - nfp->fd = fopen(args->path, "rb"); - - if (nfp->fd == 0x0) { - fdestroy(td, nfp, fd); - - td->td_retval[0] = -1; - error = -1; - } - else { - td->td_retval[0] = fd; - } - - return (error); -} - -int sys_openat(struct thread *td, struct sys_openat_args *args) { - int error = 0x0; - int fd = 0x0; - struct file *nfp = 0x0; - - kprintf("openat"); - - error = falloc(td, &nfp, &fd); - - if (error) - return(error); - if ((args->flag & O_WRONLY) == O_WRONLY) nfp->fd = fopen(args->path, "w"); else if ((args->flag & O_RDWR) == O_RDWR) @@ -85,46 +70,76 @@ td->td_retval[0] = -1; error = -1; + /* - kprintf("[sOA: 0x%X:%s:%s:%i]", args->flag, args->mode, args->path, td->td_retval[0]); + kprintf("[sOA: 0x%X:%s:%s:]", args->flag, args->mode, args->path, td->td_retval[0]); - if ((args->flag & O_RDONLY) == O_RDONLY) - kprintf("O_RDONLY"); + if ((args->flag & O_RDONLY) == O_RDONLY) + kprintf("O_RDONLY"); - if ((args->flag & O_WRONLY) == O_WRONLY) - kprintf("O_WRONLY"); + if ((args->flag & O_WRONLY) == O_WRONLY) + kprintf("O_WRONLY"); - if ((args->flag & O_RDWR) == O_RDWR) - kprintf("O_RDWR"); + if ((args->flag & O_RDWR) == O_RDWR) + kprintf("O_RDWR"); - if ((args->flag & O_ACCMODE) == O_ACCMODE) - kprintf("O_ACCMODE"); + if ((args->flag & O_ACCMODE) == O_ACCMODE) + kprintf("O_ACCMODE"); + */ } else { td->td_retval[0] = fd; } + //kprintf("[sOA: 0x%X:%s:%s:]", args->flag, args->mode, args->path, td->td_retval[0]); return (error); - } - +} int sys_close(struct thread *td, struct sys_close_args *args) { struct file *fd = 0x0; + struct pipeInfo *pFD = 0x0; + getfd(td, &fd, args->fd); - kprintf("[sC:%i:0x%X:0x%X]", args->fd, fd, fd->fd); +#ifdef DEBUG_VFS_CALLS + kprintf("[sC::0x%X:0x%X]", args->fd, fd, fd->fd); +#endif if (fd == 0x0) { + kprintf("COULDN'T FIND FD: ", args->fd); td->td_retval[0] = -1; } else { - if (!fclose(fd->fd)) - td->td_retval[0] = -1; - else { - fdestroy(td, fd, args->fd); - td->td_retval[0] = 0; + switch (fd->fd_type) { + case 3: + pFD = fd->data; + if (args->fd == pFD->rFD) { + if (pFD->rfdCNT < 2) + fdestroy(td, fd, args->fd); + pFD->rfdCNT--; + } + + if (args->fd == pFD->wFD) { + if (pFD->wfdCNT < 2) + fdestroy(td, fd, args->fd); + pFD->wfdCNT--; + } + + break; + default: + if (args->fd < 3) + td->td_retval[0] = 0; + else { + if (!fclose(fd->fd)) + td->td_retval[0] = -1; + else { + kprintf("DESTROY: !!!!!!!!!!!!!!!!!!!!!!!!!!!!", args->fd); + fdestroy(td, fd, args->fd); + td->td_retval[0] = 0; + } + } } } return (0); @@ -138,26 +153,64 @@ struct file *fd = 0x0; + struct pipeInfo *pFD = 0x0; + struct pipeInfo *rpFD = 0x0; + + size_t nbytes; + + int rpCNT = 0; + getfd(td, &fd, args->fd); if (args->fd > 3) { - td->td_retval[0] = fread(args->buf, args->nbyte, 1, fd->fd); + switch (fd->fd_type) { + case 3: /* XXX - Pipe2 Handling */ + pFD = fd->data; + while (pFD->bCNT == 0 && rpCNT < 100) { + sched_yield(); + rpCNT++; + } + + if (rpCNT >= 100 && pFD->bCNT == 0) { + td->td_retval[0] = 0; + } + else { + nbytes = (args->nbyte - (pFD->headPB->nbytes - pFD->headPB->offset) <= 0) ? args->nbyte : (pFD->headPB->nbytes - pFD->headPB->offset); + //kprintf("[unb: , nbs: %i, bf: 0x%X]", args->nbyte, nbytes, fd->fd->buffer); + //kprintf("PR: []", nbytes); + memcpy(args->buf, pFD->headPB->buffer + pFD->headPB->offset, nbytes); + pFD->headPB->offset += nbytes; + + if (pFD->headPB->offset >= pFD->headPB->nbytes) { + rpFD = pFD->headPB; + pFD->headPB = pFD->headPB->next; + kfree(rpFD); + pFD->bCNT--; + } + + td->td_retval[0] = nbytes; + } + break; + default: + //kprintf("[r:0x%X::%i:%s]",fd->fd, args->fd, fd->fd_type, fd->fd->fileName); + td->td_retval[0] = fread(args->buf, args->nbyte, 1, fd->fd); + } } else { - bf[1] = '\0'; - if ( _current->term == tty_foreground ) - c = getchar(); + bf[1] = '\0'; + if (_current->term == tty_foreground) + c = getchar(); for (x = 0; x < args->nbyte && c != '\n';) { - if ( _current->term == tty_foreground ) { + if (_current->term == tty_foreground) { - if ( c != 0x0 ) { + if (c != 0x0) { buf[x++] = c; bf[0] = c; kprintf(bf); } - if ( c == '\n') { + if (c == '\n') { buf[x++] = c; break; } @@ -169,11 +222,65 @@ sched_yield(); } } - if ( c == '\n') + if (c == '\n') buf[x++] = '\n'; - bf[0] = '\n'; + bf[0] = '\n'; + kprintf(bf); + + td->td_retval[0] = x; + } + return (0); +} + +int sys_pread(struct thread *td, struct sys_pread_args *args) { + int offset = 0; + int x = 0; + char c = 0x0; + char bf[2]; + volatile char *buf = args->buf; + + struct file *fd = 0x0; + + getfd(td, &fd, args->fd); + + if (args->fd > 3) { + offset = fd->fd->offset; + fd->fd->offset = args->offset; + td->td_retval[0] = fread(args->buf, args->nbyte, 1, fd->fd); + fd->fd->offset = offset; + } + else { + bf[1] = '\0'; + if (_current->term == tty_foreground) + c = getchar(); + + for (x = 0; x < args->nbyte && c != '\n';) { + if (_current->term == tty_foreground) { + + if (c != 0x0) { + buf[x++] = c; + bf[0] = c; kprintf(bf); + } + + if (c == '\n') { + buf[x++] = c; + break; + } + + sched_yield(); + c = getchar(); + } + else { + sched_yield(); + } + } + if (c == '\n') + buf[x++] = '\n'; + + bf[0] = '\n'; + kprintf(bf); td->td_retval[0] = x; } @@ -182,6 +289,12 @@ int sys_write(struct thread *td, struct sys_write_args *uap) { char *buffer = 0x0; + struct file *fd = 0x0; + + struct pipeInfo *pFD = 0x0; + struct pipeBuf *pBuf = 0x0; + + size_t nbytes; if (uap->fd == 2) { buffer = kmalloc(1024); @@ -200,25 +313,58 @@ td->td_retval[0] = uap->nbyte; } else { - kprintf("[%i]", uap->nbyte); - buffer = kmalloc(uap->nbyte); - memcpy(buffer, uap->buf, uap->nbyte); - kprintf("(%i) %s", uap->fd, uap->buf); - kfree(buffer); - td->td_retval[0] = uap->nbyte; + getfd(td, &fd, uap->fd); + + kprintf("[fd: :0x%X, fd_type: %i]", uap->fd, fd, fd->fd_type); + + switch (fd->fd_type) { + case 3: /* XXX - Temp Pipe Stuff */ + + pFD = fd->data; + pBuf = (struct pipeBuf *) kmalloc(sizeof(struct pipeBuf)); + pBuf->buffer = kmalloc(uap->nbyte); + + memcpy(pBuf->buffer, uap->buf, uap->nbyte); + + pBuf->nbytes = uap->nbyte; + + if (pFD->tailPB) + pFD->tailPB->next = pBuf; + + pFD->tailPB = pBuf; + + if (!pFD->headPB) + pFD->headPB = pBuf; + + pFD->bCNT++; + + td->td_retval[0] = nbytes; + + break; + default: + kprintf("[]", uap->nbyte); + buffer = kmalloc(uap->nbyte); + memcpy(buffer, uap->buf, uap->nbyte); + kprintf("() %s", uap->fd, uap->buf); + kfree(buffer); + td->td_retval[0] = uap->nbyte; + } + } return (0x0); } int sys_access(struct thread *td, struct sys_access_args *args) { - kprintf("%s:%i", args->path, args->amode); + /* XXX - This is a temporary as it always returns true */ + td->td_retval[0] = 0; - return(0); + return (0); } int sys_getdirentries(struct thread *td, struct sys_getdirentries_args *args) { - //kprintf("GDE: [%i:%i:0x%X]", args->fd, args->count, args->basep); + struct file *fd = 0x0; + getfd(td, &fd, args->fd); char buf[DEV_BSIZE]; @@ -226,22 +372,68 @@ char *s; ssize_t n; - //fd->offset = 0; td->td_retval[0] = fread(args->buf, args->count, 1, fd->fd); - //n = fsread(fd->fd->ino, args->buf, DEV_BSIZE, fd->fd); - //td->td_retval[0] = n; + + return (0); +} + +int sys_readlink(struct thread *thr, struct sys_readlink_args *args) { + /* XXX - Need to implement readlink */ + + kprintf("RL: %s:\n", args->path, args->count); + + //Return Error + thr->td_retval[0] = 2; + return (-1); +} + +int kern_openat(struct thread *thr, int afd, char *path, int flags, int mode) { + int error = 0x0; + int fd = 0x0; + struct file *nfp = 0x0; /* - while ((n = fsread(*ino, buf, DEV_BSIZE, fd)) > 0) - for (s = buf; s < buf + DEV_BSIZE;) { - d = (void *) s; - if (!strcmp(name, d->d_name)) { - *ino = d->d_fileno; - return d->d_type; - } - s += d->d_reclen; - } -*/ + * Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags + * may be specified. + */ + if (flags & O_EXEC) { + if (flags & O_ACCMODE) + return (EINVAL); + } + else if ((flags & O_ACCMODE) == O_ACCMODE) { + return (EINVAL); + } + else { + flags = FFLAGS(flags); + } - return(0); + error = falloc(thr, &nfp, &fd); + + if (error) { + thr->td_retval[0] = -1; + return (error); + } + + if (flags | O_CREAT) + kprintf("O_CREAT\n"); + + nfp->f_flag = flags & FMASK; + + nfp->fd = fopen(path, "rwb"); + + if (nfp->fd == 0x0) { + fdestroy(thr, nfp, fd); + + thr->td_retval[0] = -1; + + error = -1; + } + else { + thr->td_retval[0] = fd; + } + + //kprintf("sO: 0x%X:%s:", args->mode, args->path, td->td_retval[0]); + + return (error); + } diff --git a/sys/lib/kern_trie.c b/sys/lib/kern_trie.c new file mode 100644 index 0000000..d07ec03 --- /dev/null +++ b/sys/lib/kern_trie.c @@ -0,0 +1,149 @@ +/*- + * Copyright (c) 2018 The UbixOS Project. + * All rights reserved. + * + * This was developed by Christopher W. Olsen for the UbixOS Project. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1) Redistributions of source code must retain the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors. + * 2) Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions, the following disclaimer and the list of authors in the documentation and/or + * other materials provided with the distribution. + * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +struct Trie *new_trieNode() { + + struct Trie *node = (struct Trie *) kmalloc(sizeof(struct Trie)); + + node->isLeaf = 0; + + for (int i = 0; i < CHAR_SIZE; i++) + node->character[i] = NULL; + + return (node); +} + +// Insert Trie +void insert_trieNode(struct Trie **head, char* str, void *e) { + + // start from root node + struct Trie* curr = *head; + + while (*str) { + + // create a new node if path doesn't exists + if (curr->character[*str - 'a'] == NULL) { + curr->character[*str - 'a'] = new_trieNode(); + } + + // go to next node + curr = curr->character[*str - 'a']; + // move to next character + str++; + } + + curr->e = e; + // mark current node as leaf + curr->isLeaf = 1; +} + + +struct Trie *search_trieNode(struct Trie *head, char *str) { + + // return 0 if Trie is empty + if (head == NULL || str == NULL) + return (0); + + struct Trie *curr = head; + + while (*str) { + + // go to next node + curr = curr->character[*str - 'a']; + + // if string is invalid (reached end of path in Trie) + if (curr == NULL) + return (0); + + // move to next character + str++; + } + + // if current node is a leaf and we have reached the + // end of the string, return 1 + return (curr); +} + + + +// Recursive function to delete a string in Trie +int delete_trieNode(struct Trie **curr, char *str) { + + // return if Trie is empty + if (*curr == NULL) + return (0); + + // if we have not reached the end of the string + if (*str) { + // recurse for the node corresponding to next character in + // the string and if it returns 1, delete current node + // (if it is non-leaf) + if (*curr != NULL && (*curr)->character[*str - 'a'] != NULL && deletion(&((*curr)->character[*str - 'a']), str + 1) && (*curr)->isLeaf == 0) { + if (!haveChildren(*curr)) { + free(*curr); + (*curr) = NULL; + return (1); + } + else { + return (0); + } + } + } + + // if we have reached the end of the string + if (*str == '\0' && (*curr)->isLeaf) { + // if current node is a leaf node and don't have any children + if (!haveChildren(*curr)) { + free(*curr); // delete current node + (*curr) = NULL; + return (1); // delete non-leaf parent nodes + } + + // if current node is a leaf node and have children + else { + // mark current node as non-leaf node (DON'T DELETE IT) + (*curr)->isLeaf = 0; + return (0); // don't delete its parent nodes + } + } + + return (0); +} + +// returns 1 if given node has any children +int haveChildren(struct Trie* curr) { + for (int i = 0; i < CHAR_SIZE; i++) + if (curr->character[i]) + return (1); // child found + + return (0); +} diff --git a/sys/lib/kprintf.c b/sys/lib/kprintf.c index 66d096a..6d0c8a4 100644 --- a/sys/lib/kprintf.c +++ b/sys/lib/kprintf.c @@ -279,7 +279,7 @@ va_list args; int i; va_start(args, fmt); -//i = vsprintf( buf, fmt, args ); + /* i = vsprintf( buf, fmt, args ); */ i = kvprintf(fmt, NULL, buf, 10, args); va_end(args); return (i); diff --git a/sys/net/core/def.c b/sys/net/core/def.c index bfa98af..3d5469f 100644 --- a/sys/net/core/def.c +++ b/sys/net/core/def.c @@ -11,7 +11,7 @@ * \#define lwip_htonl(x) your_htonl * * Note lwip_ntohs() and lwip_ntohl() are merely references to the htonx counterparts. - * + * * If you \#define them to htons() and htonl(), you should * \#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS to prevent lwIP from * defining htonx/ntohx compatibility macros. @@ -72,10 +72,8 @@ * @param n u16_t in host byte order * @return n in network byte order */ -u16_t -lwip_htons(u16_t n) -{ - return (u16_t)PP_HTONS(n); +u16_t lwip_htons(u16_t n) { + return ((u16_t) PP_HTONS(n)); } #endif /* lwip_htons */ @@ -89,7 +87,7 @@ u32_t lwip_htonl(u32_t n) { - return (u32_t)PP_HTONL(n); + return ((u32_t) PP_HTONL(n)); } #endif /* lwip_htonl */ @@ -114,7 +112,7 @@ return LWIP_CONST_CAST(char *, p); } } - return NULL; + return (NULL); } #endif @@ -141,15 +139,15 @@ if (c1_upc != c2_upc) { /* still not equal */ /* don't care for < or > */ - return 1; + return (1); } } else { /* characters are not equal but none is in the alphabet range */ - return 1; + return (1); } } } while (c1 != 0); - return 0; + return (0); } #endif @@ -176,15 +174,15 @@ if (c1_upc != c2_upc) { /* still not equal */ /* don't care for < or > */ - return 1; + return (1); } } else { /* characters are not equal but none is in the alphabet range */ - return 1; + return (1); } } } while (len-- && c1 != 0); - return 0; + return (0); } #endif diff --git a/sys/net/netif/Makefile b/sys/net/netif/Makefile old mode 100755 new mode 100644 diff --git a/sys/sde/ogDisplay_UbixOS.cc b/sys/sde/ogDisplay_UbixOS.cc old mode 100755 new mode 100644 diff --git a/sys/vmm/paging.c b/sys/vmm/paging.c index a12a629..44eb690 100644 --- a/sys/vmm/paging.c +++ b/sys/vmm/paging.c @@ -634,7 +634,10 @@ "movl %cr3,%eax\n" "movl %eax,%cr3\n" ); - kprintf("Here?"); + + #ifdef VMM_DEBUG + kprintf("Here!?"); + #endif return (0x0); } diff --git a/sys/vmm/vmm_memory.c b/sys/vmm/vmm_memory.c index 56e2ac8..6139d61 100644 --- a/sys/vmm/vmm_memory.c +++ b/sys/vmm/vmm_memory.c @@ -40,7 +40,7 @@ static uint32_t freePages = 0; static struct spinLock vmmSpinLock = SPIN_LOCK_INITIALIZER; -static struct spinLock vmmCowSpinLock = SPIN_LOCK_INITIALIZER; +//static struct spinLock vmmCowSpinLock = SPIN_LOCK_INITIALIZER; int numPages = 0x0; @@ -344,7 +344,7 @@ ************************************************************************/ -/* TODO: This can be greatly immproved for performance but it gets the job done */ +/* TODO: This can be greatly improved for performance but it gets the job done */ void vmm_freeProcessPages(pidType pid) { int i = 0, x = 0; uint32_t *tmpPageTable = 0x0; @@ -353,7 +353,7 @@ spinLock(&vmmSpinLock); /* Check Page Directory For An Avail Page Table */ - //NOTE: Thie cleans all memory space up to kernel space + //NOTE: This cleans all memory space up to kernel space #ifdef _IGNORE for (i = 0; i < (PAGE_SIZE - (PAGE_SIZE / 4)); i++) { diff --git a/tools/SCRIPT.DPF b/tools/SCRIPT.DPF old mode 100755 new mode 100644 Binary files differ diff --git a/tools/makeuser.c b/tools/makeuser.c index 5041dd7..d06d36f 100644 --- a/tools/makeuser.c +++ b/tools/makeuser.c @@ -61,11 +61,11 @@ password[1].gid = 1; sprintf(password[2].username, "reddawg"); sprintf(password[2].passwd, "temp123"); - sprintf(password[2].shell, "sys:/bin/shell"); - sprintf(password[2].realname, "Christopher"); + sprintf(password[2].shell, "sys:/bin/sh"); + sprintf(password[2].realname, "Christopher W. Olsen"); sprintf(password[2].path, "reddawg"); password[2].uid = 1000; - password[2].gid = 1000; + password[2].gid = 0; fwrite(password, 4096, 1, out); fclose(out); for (i = 0; i < 3; i++) { diff --git a/tools/mbr b/tools/mbr old mode 100755 new mode 100644 Binary files differ diff --git a/tools/stat b/tools/stat old mode 100755 new mode 100644 Binary files differ diff --git a/tools/userdb b/tools/userdb index ed464e7..def853f 100644 --- a/tools/userdb +++ b/tools/userdb Binary files differ