64 bit file seeking (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 6 Mar 2013 02:27:58 +0000 (18:27 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 6 Mar 2013 20:52:28 +0000 (12:52 -0800)
The kernel now tracks all file offsets as 64 bit values, and the old
lseek syscall is now llseek.  This call can handle 64 bit or 32 bit
offsets on both 64 and 32 bit systems.  It compiles and works on a 32
bit system (I don't have a 64 bit Akaros system to test out the 64 bit
stuff).  The ghetto file_test was updated to do a very basic lseek64 as
well.

glibc's lseek64 now uses the new syscall as well.

Rebuild your cross compiler, and copy-over the lseek files from the -ros
directory (or do a complete make clean).

14 files changed:
kern/include/devfs.h
kern/include/kfs.h
kern/include/ros/bits/syscall.h
kern/include/sys/types.h
kern/include/vfs.h
kern/src/devfs.c
kern/src/elf.c
kern/src/ext2fs.c
kern/src/kfs.c
kern/src/syscall.c
kern/src/vfs.c
tests/file_test.c
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/lseek.c
tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/lseek64.c [new file with mode: 0644]

index cd9fae5..67ebc28 100644 (file)
@@ -19,7 +19,7 @@ struct file *make_device(char *path, int mode, int type,
 /* Generic device (block or char) file ops.  Both of these are dummies that say
  * the device can't support the operation. */
 int dev_mmap(struct file *file, struct vm_region *vmr);
-off_t dev_c_llseek(struct file *file, off_t offset, int whence);
+int dev_c_llseek(struct file *file, off64_t offset, off64_t *ret, int whence);
 
 /* Exporting these for convenience (process creation) */
 extern struct file *dev_stdin, *dev_stdout, *dev_stderr;
index 75bf3a0..0e5c1db 100644 (file)
@@ -69,7 +69,7 @@ int kfs_d_delete(struct dentry *dentry);
 int kfs_d_release(struct dentry *dentry);
 void kfs_d_iput(struct dentry *dentry, struct inode *inode);
 /* file_operations */
-off_t kfs_llseek(struct file *file, off_t offset, int whence);
+int kfs_llseek(struct file *file, off64_t offset, off64_t *ret, int whence);
 int kfs_readdir(struct file *dir, struct dirent *dirent);
 int kfs_mmap(struct file *file, struct vm_region *vmr);
 int kfs_open(struct inode *inode, struct file *file);
@@ -78,11 +78,11 @@ int kfs_release(struct inode *inode, struct file *file);
 int kfs_fsync(struct file *file, struct dentry *dentry, int datasync);
 unsigned int kfs_poll(struct file *file, struct poll_table_struct *poll_table);
 ssize_t kfs_readv(struct file *file, const struct iovec *vector,
-                  unsigned long count, off_t *offset);
+                  unsigned long count, off64_t *offset);
 ssize_t kfs_writev(struct file *file, const struct iovec *vector,
-                  unsigned long count, off_t *offset);
+                  unsigned long count, off64_t *offset);
 ssize_t kfs_sendpage(struct file *file, struct page *page, int offset,
-                     size_t size, off_t pos, int more);
+                     size_t size, off64_t pos, int more);
 int kfs_check_flags(int flags);
 
 #endif /* !ROS_KERN_KFS_H */
index 3e1dc04..f1b0777 100644 (file)
@@ -61,7 +61,7 @@
 #define SYS_access                             108
 #define SYS_umask                              109
 #define SYS_chmod                              110
-#define SYS_lseek                              111
+#define SYS_llseek                             111
 #define SYS_link                               112
 #define SYS_unlink                             113
 #define SYS_symlink                            114
index 5c6d19e..1b260fe 100644 (file)
@@ -14,6 +14,7 @@ typedef uint32_t __nlink_t;
 typedef uint32_t __uid_t;
 typedef uint32_t __gid_t;
 typedef int64_t __off64_t;
+typedef __off64_t off64_t;
 typedef int32_t __blksize_t;
 typedef int64_t __blkcnt64_t;
 
index 6acb17e..219ddbd 100644 (file)
@@ -276,7 +276,7 @@ struct file {
        struct kref                                     f_kref;
        unsigned int                            f_flags;                /* O_APPEND, etc */
        int                                                     f_mode;                 /* O_RDONLY, etc */
-       off_t                                           f_pos;                  /* offset / file pointer */
+       off64_t                                         f_pos;                  /* offset / file pointer */
        unsigned int                            f_uid;
        unsigned int                            f_gid;
        int                                                     f_error;
@@ -292,9 +292,9 @@ struct file {
 };
 
 struct file_operations {
-       off_t (*llseek) (struct file *, off_t, int);
-       ssize_t (*read) (struct file *, char *, size_t, off_t *);
-       ssize_t (*write) (struct file *, const char *, size_t, off_t *);
+       int (*llseek) (struct file *, off64_t, off64_t *, int);
+       ssize_t (*read) (struct file *, char *, size_t, off64_t *);
+       ssize_t (*write) (struct file *, const char *, size_t, off64_t *);
        int (*readdir) (struct file *, struct dirent *);
        int (*mmap) (struct file *, struct vm_region *);
        int (*open) (struct inode *, struct file *);
@@ -303,10 +303,11 @@ struct file_operations {
        int (*fsync) (struct file *, struct dentry *, int);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        ssize_t (*readv) (struct file *, const struct iovec *, unsigned long,
-                         off_t *);
+                         off64_t *);
        ssize_t (*writev) (struct file *, const struct iovec *, unsigned long,
-                         off_t *);
-       ssize_t (*sendpage) (struct file *, struct page *, int, size_t, off_t, int);
+                         off64_t *);
+       ssize_t (*sendpage) (struct file *, struct page *, int, size_t, off64_t,
+                            int);
        int (*check_flags) (int flags);                         /* most FS's ignore this */
 };
 
@@ -441,11 +442,11 @@ struct inode *icache_remove(struct super_block *sb, unsigned long ino);
 
 /* File-ish functions */
 ssize_t generic_file_read(struct file *file, char *buf, size_t count,
-                          off_t *offset);
+                          off64_t *offset);
 ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
-                           off_t *offset);
+                           off64_t *offset);
 ssize_t generic_dir_read(struct file *file, char *u_buf, size_t count,
-                         off_t *offset);
+                         off64_t *offset);
 struct file *do_file_open(char *path, int flags, int mode);
 int do_symlink(char *path, const char *symname, int mode);
 int do_link(char *old_path, char *new_path);
index 2ce45cb..a227d08 100644 (file)
@@ -62,8 +62,7 @@ struct file *make_device(char *path, int mode, int type,
 /* We provide a separate set of f_ops for devices (char and block), and the fops
  * is the only thing that differs from the regular KFS.  We need to do some
  * ghetto-overriding of these ops after we create them. */
-
-off_t dev_c_llseek(struct file *file, off_t offset, int whence)
+int dev_c_llseek(struct file *file, off64_t offset, off64_t *ret, int whence)
 {
        set_errno(EINVAL);
        return -1;
@@ -79,7 +78,7 @@ int dev_mmap(struct file *file, struct vm_region *vmr)
 /* this is really /dev/console, and will need some tty work.  for now, no matter
  * how much they ask for, we return one character at a time. */
 ssize_t dev_stdin_read(struct file *file, char *buf, size_t count,
-                       off_t *offset)
+                       off64_t *offset)
 {
        char c;
        extern struct kb_buffer cons_buf;
@@ -93,7 +92,7 @@ ssize_t dev_stdin_read(struct file *file, char *buf, size_t count,
 }
 
 ssize_t dev_stdout_write(struct file *file, const char *buf, size_t count,
-                         off_t *offset)
+                         off64_t *offset)
 {
        char *t_buf;
        struct proc *p = current;
@@ -150,7 +149,7 @@ struct file_operations dev_f_op_stdout = {
 
 /* /dev/null: just take whatever was given and pretend it was written */
 ssize_t dev_null_write(struct file *file, const char *buf, size_t count,
-                       off_t *offset)
+                       off64_t *offset)
 {
        return count;
 }
index 30eea88..c5e1322 100644 (file)
@@ -24,7 +24,7 @@ static int load_one_elf(struct proc *p, struct file *f, uintptr_t pgoffset,
        ei->phdr = -1;
        ei->dynamic = 0;
        ei->highest_addr = 0;
-       off_t f_off = 0;
+       off64_t f_off = 0;
        void* phdrs = 0;
        int mm_perms, mm_flags = MAP_FIXED;
        
index 33c0e3b..94e8467 100644 (file)
@@ -1308,9 +1308,9 @@ void ext2_d_iput(struct dentry *dentry, struct inode *inode)
 /* Updates the file pointer.  TODO: think about locking, and putting this in the
  * VFS. */
 #include <syscall.h>   /* just for set_errno, may go away later */
-off_t ext2_llseek(struct file *file, off_t offset, int whence)
+int ext2_llseek(struct file *file, off64_t offset, off64_t *ret, int whence)
 {
-       off_t temp_off = 0;
+       off64_t temp_off = 0;
        switch (whence) {
                case SEEK_SET:
                        temp_off = offset;
@@ -1327,7 +1327,8 @@ off_t ext2_llseek(struct file *file, off_t offset, int whence)
                        return -1;
        }
        file->f_pos = temp_off;
-       return temp_off;
+       *ret = temp_off;
+       return 0;
 }
 
 /* Fills in the next directory entry (dirent), starting with d_off.  Like with
@@ -1343,7 +1344,7 @@ int ext2_readdir(struct file *dir, struct dirent *dirent)
        int block = dirent->d_off / dir->f_dentry->d_sb->s_blocksize;
        blk_buf = ext2_get_ino_metablock(dir->f_dentry->d_inode, block);
        assert(blk_buf);
-       off_t f_off = dirent->d_off % dir->f_dentry->d_sb->s_blocksize;
+       off64_t f_off = dirent->d_off % dir->f_dentry->d_sb->s_blocksize;
        /* Copy out the dirent info */
        struct ext2_dirent *e2dir = (struct ext2_dirent*)(blk_buf + f_off);
        dirent->d_ino = le32_to_cpu(e2dir->dir_inode);
@@ -1418,7 +1419,7 @@ unsigned int ext2_poll(struct file *file, struct poll_table_struct *poll_table)
 /* Reads count bytes from a file, starting from (and modifiying) offset, and
  * putting the bytes into buffers described by vector */
 ssize_t ext2_readv(struct file *file, const struct iovec *vector,
-                  unsigned long count, off_t *offset)
+                  unsigned long count, off64_t *offset)
 {
        return -1;
 }
@@ -1426,14 +1427,14 @@ ssize_t ext2_readv(struct file *file, const struct iovec *vector,
 /* Writes count bytes to a file, starting from (and modifiying) offset, and
  * taking the bytes from buffers described by vector */
 ssize_t ext2_writev(struct file *file, const struct iovec *vector,
-                  unsigned long count, off_t *offset)
+                  unsigned long count, off64_t *offset)
 {
        return -1;
 }
 
 /* Write the contents of file to the page.  Will sort the params later */
 ssize_t ext2_sendpage(struct file *file, struct page *page, int offset,
-                     size_t size, off_t pos, int more)
+                     size_t size, off64_t pos, int more)
 {
        return -1;
 }
index c5e876c..2373d0a 100644 (file)
@@ -523,9 +523,9 @@ void kfs_d_iput(struct dentry *dentry, struct inode *inode)
 
 /* Updates the file pointer.  KFS doesn't let you go past the end of a file
  * yet, so it won't let you seek past either.  TODO: think about locking. */
-off_t kfs_llseek(struct file *file, off_t offset, int whence)
+int kfs_llseek(struct file *file, off64_t offset, off64_t *ret, int whence)
 {
-       off_t temp_off = 0;
+       off64_t temp_off = 0;
        switch (whence) {
                case SEEK_SET:
                        temp_off = offset;
@@ -545,7 +545,8 @@ off_t kfs_llseek(struct file *file, off_t offset, int whence)
         * techincally, if they go too far, we should return EINVAL */
        temp_off = MAX(MIN(temp_off, file->f_dentry->d_inode->i_size), 0);
        file->f_pos = temp_off;
-       return temp_off;
+       *ret = temp_off;
+       return 0;
 }
 
 /* Fills in the next directory entry (dirent), starting with d_off.  KFS treats
@@ -655,7 +656,7 @@ unsigned int kfs_poll(struct file *file, struct poll_table_struct *poll_table)
 /* Reads count bytes from a file, starting from (and modifiying) offset, and
  * putting the bytes into buffers described by vector */
 ssize_t kfs_readv(struct file *file, const struct iovec *vector,
-                  unsigned long count, off_t *offset)
+                  unsigned long count, off64_t *offset)
 {
        return -1;
 }
@@ -663,14 +664,14 @@ ssize_t kfs_readv(struct file *file, const struct iovec *vector,
 /* Writes count bytes to a file, starting from (and modifiying) offset, and
  * taking the bytes from buffers described by vector */
 ssize_t kfs_writev(struct file *file, const struct iovec *vector,
-                  unsigned long count, off_t *offset)
+                  unsigned long count, off64_t *offset)
 {
        return -1;
 }
 
 /* Write the contents of file to the page.  Will sort the params later */
 ssize_t kfs_sendpage(struct file *file, struct page *page, int offset,
-                     size_t size, off_t pos, int more)
+                     size_t size, off64_t pos, int more)
 {
        return -1;
 }
index 34ada5f..9beb176 100644 (file)
@@ -1276,17 +1276,30 @@ intreg_t sys_chmod(struct proc *p, const char *path, size_t path_l, int mode)
        return retval;
 }
 
-static intreg_t sys_lseek(struct proc *p, int fd, off_t offset, int whence)
-{
-       off_t ret;
+/* 64 bit seek, with the off64_t passed in via two (potentially 32 bit) off_ts.
+ * We're supporting both 32 and 64 bit kernels/userspaces, but both use the
+ * llseek syscall with 64 bit parameters. */
+static intreg_t sys_llseek(struct proc *p, int fd, off_t offset_hi,
+                           off_t offset_lo, off64_t *result, int whence)
+{
+       off64_t retoff = 0;
+       off64_t tempoff = 0;
+       int ret = 0;
        struct file *file = get_file_from_fd(&p->open_files, fd);
        if (!file) {
                set_errno(EBADF);
                return -1;
        }
-       ret = file->f_op->llseek(file, offset, whence);
+       tempoff = offset_hi;
+       tempoff <<= 32;
+       tempoff |= offset_lo;
+       ret = file->f_op->llseek(file, tempoff, &retoff, whence);
        kref_put(&file->f_kref);
-       return ret;
+       if (ret)
+               return -1;
+       if (memcpy_to_user_errno(p, result, &retoff, sizeof(off64_t)))
+               return -1;
+       return 0;
 }
 
 intreg_t sys_link(struct proc *p, char *old_path, size_t old_l,
@@ -1566,7 +1579,7 @@ const static struct sys_table_entry syscall_table[] = {
        [SYS_access] = {(syscall_t)sys_access, "access"},
        [SYS_umask] = {(syscall_t)sys_umask, "umask"},
        [SYS_chmod] = {(syscall_t)sys_chmod, "chmod"},
-       [SYS_lseek] = {(syscall_t)sys_lseek, "lseek"},
+       [SYS_llseek] = {(syscall_t)sys_llseek, "llseek"},
        [SYS_link] = {(syscall_t)sys_link, "link"},
        [SYS_unlink] = {(syscall_t)sys_unlink, "unlink"},
        [SYS_symlink] = {(syscall_t)sys_symlink, "symlink"},
index f50ce9e..ce365b7 100644 (file)
@@ -1111,16 +1111,16 @@ struct inode *icache_remove(struct super_block *sb, unsigned long ino)
 
 /* File functions */
 
-/* Read count bytes from the file into buf, starting at *offset, which is increased
- * accordingly, returning the number of bytes transfered.  Most filesystems will
- * use this function for their f_op->read.  Note, this uses the page cache.
- * Want to try out page remapping later on... */
+/* Read count bytes from the file into buf, starting at *offset, which is
+ * increased accordingly, returning the number of bytes transfered.  Most
+ * filesystems will use this function for their f_op->read.
+ * Note, this uses the page cache. */
 ssize_t generic_file_read(struct file *file, char *buf, size_t count,
-                          off_t *offset)
+                          off64_t *offset)
 {
        struct page *page;
        int error;
-       off_t page_off;
+       off64_t page_off;
        unsigned long first_idx, last_idx;
        size_t copy_amt;
        char *buf_end;
@@ -1163,17 +1163,19 @@ ssize_t generic_file_read(struct file *file, char *buf, size_t count,
        return count;
 }
 
-/* Write count bytes from buf to the file, starting at *offset, which is increased
- * accordingly, returning the number of bytes transfered.  Most filesystems will
- * use this function for their f_op->write.  Note, this uses the page cache.
+/* Write count bytes from buf to the file, starting at *offset, which is
+ * increased accordingly, returning the number of bytes transfered.  Most
+ * filesystems will use this function for their f_op->write.  Note, this uses
+ * the page cache.
+ *
  * Changes don't get flushed to disc til there is an fsync, page cache eviction,
  * or other means of trying to writeback the pages. */
 ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
-                           off_t *offset)
+                           off64_t *offset)
 {
        struct page *page;
        int error;
-       off_t page_off;
+       off64_t page_off;
        unsigned long first_idx, last_idx;
        size_t copy_amt;
        const char *buf_end;
@@ -1215,7 +1217,7 @@ ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
  * currently expects us to do a readdir (short of doing linux's getdents).  Will
  * probably need work, based on whatever real programs want. */
 ssize_t generic_dir_read(struct file *file, char *u_buf, size_t count,
-                         off_t *offset)
+                         off64_t *offset)
 {
        struct kdirent dir_r = {0}, *dirent = &dir_r;
        int retval = 1;
index dc7e91b..e6e111f 100644 (file)
@@ -1,3 +1,5 @@
+#define _LARGEFILE64_SOURCE /* needed to use lseek64 */
+
 #include <stdio.h> 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -9,6 +11,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#define DUMMY_STR "AAAaaaBBBbbb"
 int main() 
 { 
        FILE *file; 
@@ -23,13 +26,26 @@ int main()
        int retval;
        retval = read(fd, rbuf, 16);
        printf("Tried to read, got %d bytes of buf: %s\n", retval, rbuf);
-       strcpy(wbuf, "paul <3's the new 61c");
-       retval = write(fd, wbuf, 22);
+       strcpy(wbuf, DUMMY_STR);
+       retval = write(fd, wbuf, strlen(DUMMY_STR));
        printf("Tried to write, wrote %d bytes\n", retval);
+
        printf("Trying to seek to 0\n");
        lseek(fd, 0, SEEK_SET);
        retval = read(fd, rbuf, 64);
        printf("Tried to read again, got %d bytes of buf: %s\n", retval, rbuf);
+       if (strcmp(DUMMY_STR, rbuf)) {
+               printf("Failed to read back our dummy string!\n");
+               return -1;
+       }
+       printf("Trying to lseek64 to 0\n");
+       lseek64(fd, 0, SEEK_SET);
+       retval = read(fd, rbuf, 64);
+       printf("Tried to read again, got %d bytes of buf: %s\n", retval, rbuf);
+       if (strcmp(DUMMY_STR, rbuf)) {
+               printf("Failed to read back our dummy string!\n");
+               return -1;
+       }
 
        retval = access("/bin/laden", X_OK);
        if (errno != ENOENT)
index 92abade..c6f0091 100644 (file)
@@ -1,14 +1,42 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <errno.h>
+#include <assert.h>
 #include <ros/syscall.h>
 
-off_t
-__libc_lseek (int fd, off_t offset, int whence)
+/* potentially a 32 bit seek (off_t is a long) */
+off_t __libc_lseek (int fd, off_t offset, int whence)
 {
-  return ros_syscall(SYS_lseek, fd, offset, whence, 0, 0, 0);
+       loff_t retoff = 0;
+       off_t hi = 0;
+       off_t lo = 0;
+       off_t ret;
+       if (fd < 0) {
+               __set_errno (EBADF);
+               return -1;
+       }
+       switch (whence) {
+               case SEEK_SET:
+               case SEEK_CUR:
+               case SEEK_END:
+                       break;
+               default:
+                       __set_errno (EINVAL);
+                       return -1;
+       }
+       /* get the high and low part, regardless of whether offset was already 64
+        * bits or not (casting to avoid warnings) */
+       hi = (loff_t)offset >> 32;
+       lo = offset & 0xffffffff;
+       ret = ros_syscall(SYS_llseek, fd, hi, lo, &retoff, whence, 0);
+       if (ret) {
+               assert(ret == -1);      /* catch odd bugs */
+               return ret;
+       }
+       /* Get the lower 32 or 64 bits, depending on the length of long */
+       ret = retoff & (unsigned long)(-1);
+       return ret;
 }
-
 weak_alias (__libc_lseek, __lseek)
 libc_hidden_def (__lseek)
 weak_alias (__libc_lseek, lseek)
diff --git a/tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/lseek64.c b/tools/compilers/gcc-glibc/glibc-2.14.1-ros/sysdeps/ros/lseek64.c
new file mode 100644 (file)
index 0000000..c1286c4
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (C) 1991,95,96,97,98,2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <ros/syscall.h>
+#include <assert.h>
+
+/* Seek to OFFSET on FD, starting from WHENCE.  */
+off64_t
+__libc_lseek64 (int fd, off64_t offset, int whence)
+{
+       off64_t retoff = 0;
+       off_t hi = 0;
+       off_t lo = 0;
+       int ret;
+       if (fd < 0) {
+               __set_errno (EBADF);
+               return -1;
+       }
+       switch (whence) {
+               case SEEK_SET:
+               case SEEK_CUR:
+               case SEEK_END:
+                       break;
+               default:
+                       __set_errno (EINVAL);
+                       return -1;
+       }
+       hi = offset >> 32;
+       lo = offset & 0xffffffff;
+       ret = ros_syscall(SYS_llseek, fd, hi, lo, &retoff, whence, 0);
+       if (ret) {
+               assert(ret == -1);      /* catch odd bugs */
+               return ret;
+       }
+       return retoff;
+}
+weak_alias (__libc_lseek64, __lseek64)
+weak_alias (__libc_lseek64, lseek64)