Whamcloud - gitweb
b=20668
[fs/lustre-release.git] / libsysio / drivers / incore / fs_incore.c
index b6eb1c0..c2ce433 100644 (file)
@@ -62,6 +62,7 @@
 #include <sys/queue.h>
 
 #include "sysio.h"
+#include "xtio.h"
 #include "fs.h"
 #include "mount.h"
 #include "inode.h"
@@ -84,7 +85,6 @@
  */
 struct incore_inode {
        LIST_ENTRY(incore_inode) ici_link;              /* i-nodes list link */
-       unsigned ici_revalidate                 : 1;    /* synch sys inode? */
        struct intnl_stat ici_st;                       /* attrs */
        struct file_identifier ici_fileid;              /* file ID */
        void    *ici_data;                              /* file data */
@@ -131,10 +131,10 @@ static int _sysio_incore_inop_setattr(struct pnode *pno,
                                      struct inode *ino,
                                      unsigned mask,
                                      struct intnl_stat *stbuf);
-static ssize_t _sysio_incore_dirop_getdirentries(struct inode *ino,
-                                          char *buf,
-                                          size_t nbytes,
-                                          _SYSIO_OFF_T *basep);
+static ssize_t _sysio_incore_dirop_filldirentries(struct inode *ino,
+                                                 _SYSIO_OFF_T *posp,
+                                                 char *buf,
+                                                 size_t nbytes);
 static int _sysio_incore_dirop_mkdir(struct pnode *pno, mode_t mode);
 static int _sysio_incore_dirop_rmdir(struct pnode *pno);
 static int _sysio_incore_inop_open(struct pnode *pno, int flags, mode_t mode);
@@ -147,7 +147,8 @@ static int _sysio_incore_filop_write(struct inode *ino, struct ioctx *ioctx);
 static _SYSIO_OFF_T _sysio_incore_filop_pos(struct inode *ino,
                                            _SYSIO_OFF_T off);
 static int _sysio_incore_filop_iodone(struct ioctx *ioctx);
-static int _sysio_incore_filop_fcntl(struct inode *ino, int cmd, va_list ap);
+static int _sysio_incore_filop_fcntl(struct inode *ino, 
+                                    int cmd, va_list ap, int *rtn);
 static int _sysio_incore_inop_sync(struct inode *ino);
 static int _sysio_incore_filop_ioctl(struct inode *ino,
                                    unsigned long int request,
@@ -163,7 +164,7 @@ static void _sysio_incore_inop_gone(struct inode *ino);
 #define _sysio_incore_dirop_symlink \
        (int (*)(struct pnode *, const char *))_sysio_do_enosys
 #define _sysio_incore_dirop_readlink \
-       (int (*)(struct pnode *, char *, size_t))_sysio_do_einval
+       (int (*)(struct pnode *, char *, size_t))_sysio_do_enosys
 #define _sysio_incore_dirop_read \
        (int (*)(struct inode *, \
                 struct ioctx *))_sysio_do_eisdir
@@ -176,7 +177,7 @@ static void _sysio_incore_inop_gone(struct inode *ino);
 #define _sysio_incore_dirop_iodone \
        (int (*)(struct ioctx *))_sysio_do_illop
 #define _sysio_incore_dirop_fcntl \
-       (int (*)(struct inode *, int, va_list))_sysio_do_eisdir
+       (int (*)(struct inode *, int, va_list, int *))_sysio_do_eisdir
 #define _sysio_incore_dirop_ioctl \
        (int (*)(struct inode *, \
                 unsigned long int, \
@@ -186,7 +187,7 @@ static struct inode_ops _sysio_incore_dir_ops = {
        _sysio_incore_dirop_lookup,
        _sysio_incore_inop_getattr,
        _sysio_incore_inop_setattr,
-       _sysio_incore_dirop_getdirentries,
+       _sysio_incore_dirop_filldirentries,
        _sysio_incore_dirop_mkdir,
        _sysio_incore_dirop_rmdir,
        _sysio_incore_dirop_symlink,
@@ -216,11 +217,11 @@ static struct inode_ops _sysio_incore_dir_ops = {
                 struct inode **, \
                 struct intent *, \
                 const char *))_sysio_do_illop
-#define _sysio_incore_filop_getdirentries \
+#define _sysio_incore_filop_filldirentries \
        (ssize_t (*)(struct inode *, \
-                char *, \
-                size_t, \
-                _SYSIO_OFF_T *))_sysio_do_illop
+                    _SYSIO_OFF_T *, \
+                    char *, \
+                    size_t))_sysio_do_illop
 #define _sysio_incore_filop_mkdir \
        (int (*)(struct pnode *, mode_t))_sysio_do_illop
 #define _sysio_incore_filop_rmdir \
@@ -242,7 +243,7 @@ static struct inode_ops _sysio_incore_file_ops = {
        _sysio_incore_filop_lookup,
        _sysio_incore_inop_getattr,
        _sysio_incore_inop_setattr,
-       _sysio_incore_filop_getdirentries,
+       _sysio_incore_filop_filldirentries,
        _sysio_incore_filop_mkdir,
        _sysio_incore_filop_rmdir,
        _sysio_incore_filop_symlink,
@@ -271,7 +272,7 @@ static struct inode_ops _sysio_incore_dev_ops = {
        _sysio_incore_filop_lookup,
        _sysio_incore_inop_getattr,
        _sysio_incore_inop_setattr,
-       _sysio_incore_filop_getdirentries,
+       _sysio_incore_filop_filldirentries,
        _sysio_incore_filop_mkdir,
        _sysio_incore_filop_rmdir,
        _sysio_incore_filop_symlink,
@@ -417,7 +418,6 @@ incore_i_alloc(struct incore_filesys *icfs, struct intnl_stat *st)
        icino = malloc(sizeof(struct incore_inode));
        if (!icino)
                return NULL;
-       icino->ici_revalidate = 0;
        icino->ici_st = *st;
        icino->ici_fileid.fid_data = &icino->ici_st.st_ino;
        icino->ici_fileid.fid_len = sizeof(icino->ici_st.st_ino);
@@ -546,29 +546,40 @@ _sysio_incore_fsswop_mount(const char *source,
         * Source is a specification for the root attributes of this
         * new file system in the format:
         *
-        * <permissions>+<owner>+<group>
+        * <permissions>[+<owner>][-<group>]
         */
        ul = strtoul(source, &cp, 0);
        mode = (mode_t )ul & 07777;
-       if (*cp != '+' ||
-           (ul == ULONG_MAX && errno == ERANGE) ||
-           (unsigned long)mode != ul ||
-           mode > 07777)
-               return -EINVAL;
-       source = cp;
-       l = strtol(source, &cp, 0);
-       uid = (uid_t )l;
-       if (*cp != '+' ||
-           ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
-           (long )uid != l)
-               return -EINVAL;
-       source = cp;
-       l = strtol(source, &cp, 0);
-       gid = (gid_t )l;
-       if (*cp ||
-           ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
-           (long )gid != l)
-               return -EINVAL;
+       uid = getuid();                                 /* default */
+       gid = getgid();                                 /* default */
+       if (*cp != '\0') {
+               /*
+                * Get user and/or group.
+                */
+               if (*cp != '+' ||
+                   (ul == ULONG_MAX && errno == ERANGE) ||
+                   (unsigned long)mode != ul ||
+                   mode > 07777)
+                       return -EINVAL;
+               source = cp;
+               l = strtol(source, &cp, 0);
+               uid = (uid_t )l;
+               if (((l == LONG_MIN || l == LONG_MAX) &&
+                    errno == ERANGE) ||
+                   (long )uid != l)
+                       return -EINVAL;
+               if (*cp != '+')
+                       return -EINVAL;
+               source = cp;
+               l = strtol(source, &cp, 0);
+               gid = (gid_t )l;
+               if (((l == LONG_MIN || l == LONG_MAX) &&
+                    errno == ERANGE) ||
+                   (long )gid != l)
+                       return -EINVAL;
+               if (*cp != '\0')
+                       return -EINVAL;
+       }
 
        err = 0;
 
@@ -632,8 +643,7 @@ _sysio_incore_fsswop_mount(const char *source,
        rooti =
            _sysio_i_new(fs,
                         &icino->ici_fileid,
-                        icino->ici_st.st_mode,
-                        0,
+                        &icino->ici_st,
                         1,
                         &_sysio_incore_dir_ops,
                         icino);
@@ -768,18 +778,29 @@ incore_directory_probe(void *data,
 
 static struct intnl_dirent *
 incore_directory_match(struct intnl_dirent *de,
-                      size_t reclen __IS_UNUSED,
+                      size_t reclen,
                       struct lookup_data *ld)
 {
+       size_t  len;
 
 #if defined(BSD) || defined(REDSTORM)
        if (IFTODT(de->d_type) == DT_WHT)
                return NULL;
 #endif
-       if (
 #ifdef _DIRENT_HAVE_D_NAMLEN
-           ld->name->len == de->d_namlen &&
+       len = de->d_namlen;
+#else
+       {
+               const char *cp, *end;
+
+               cp = de->d_name;
+               end = (const char *)de + reclen;
+               while (cp < end && *cp != '\0')
+                       cp++;
+               len = cp - de->d_name;
+       }
 #endif
+       if (ld->name->len == len &&
            strncmp(de->d_name, ld->name->name, ld->name->len) == 0)
                return de;
        ld->de = de;
@@ -807,10 +828,7 @@ _sysio_incore_dirop_lookup(struct pnode *pno,
        if (*inop) {
                icino = I2IC(*inop);
                assert(icino);
-               if (icino->ici_revalidate) {
-                       (*inop)->i_mode = icino->ici_st.st_mode;
-                       icino->ici_revalidate = 0;
-               }
+               (*inop)->i_stbuf = icino->ici_st;
                return 0;
        }
 
@@ -854,8 +872,7 @@ _sysio_incore_dirop_lookup(struct pnode *pno,
        ino =
            _sysio_i_new(ino->i_fs,
                         &icino->ici_fileid,
-                        icino->ici_st.st_mode,
-                        0,
+                        &icino->ici_st
                         1,
                         ops,
                         icino);
@@ -909,7 +926,6 @@ _sysio_incore_inop_setattr(struct pnode *pno,
        if (mask & SETATTR_MODE) {
                icino->ici_st.st_mode =
                    (icino->ici_st.st_mode & S_IFMT) | (stbuf->st_mode & 07777);
-               icino->ici_revalidate = 1;
        }
        if (mask & SETATTR_MTIME)
                icino->ici_st.st_mtime = stbuf->st_mtime;
@@ -921,6 +937,7 @@ _sysio_incore_inop_setattr(struct pnode *pno,
                icino->ici_st.st_gid = stbuf->st_gid;
        icino->ici_st.st_ctime = time(NULL);
 
+       ino->i_stbuf = icino->ici_st;
 out:
        return err;
 }
@@ -937,20 +954,29 @@ incore_directory_position(struct intnl_dirent *de,
 struct copy_info {
        void    *data;
        size_t  nbytes;
+       unsigned count;
 };
 
 /*
  * Eumeration callback.
  *
  * Note:
- * On those systems supporting white-out entries, they are returned. On
- * systems without, they are not.
+ * Whiteout entries are never returned.
  */
 static void *
 incore_directory_enumerate(struct intnl_dirent *de,
                           size_t reclen,
                           struct copy_info *cinfo) {
 
+#ifdef DT_WHT
+       if (de->d_type == DT_WHT) {
+               /*
+                * Keep going  but skip the copy.
+                */
+               return NULL;
+       }
+#endif
+       cinfo->count++;
        if (reclen > cinfo->nbytes)
                return de;
        (void *)memcpy(cinfo->data, de, reclen);
@@ -960,36 +986,36 @@ incore_directory_enumerate(struct intnl_dirent *de,
 }
 
 static ssize_t
-_sysio_incore_dirop_getdirentries(struct inode *ino,
-                                char *buf,
-                                size_t nbytes,
-                                _SYSIO_OFF_T *basep)
+_sysio_incore_dirop_filldirentries(struct inode *ino,
+                                  _SYSIO_OFF_T *posp,
+                                  char *buf,
+                                  size_t nbytes)
 {
        struct incore_inode *icino = I2IC(ino);
        off_t   off;
        struct intnl_dirent *de;
        struct copy_info copy_info;
 
-       if (*basep > icino->ici_st.st_size)
+       if (*posp >= icino->ici_st.st_size)
                return 0;
 
        de =
            incore_directory_probe(icino->ici_data,
                                   icino->ici_st.st_size,
-                                  *basep,
+                                  *posp,
                                   (probe_ty )incore_directory_position,
                                   NULL,
-                                  (char *)icino->ici_data + *basep);
+                                  (char *)icino->ici_data + *posp);
        if (!de) {
                /*
                 * Past EOF.
                 */
-               *basep = 0;
                return 0;
        }
 
        copy_info.data = buf;
        copy_info.nbytes = nbytes;
+       copy_info.count = 0;
        off = (char *)de - (char *)icino->ici_data;
        de =
            incore_directory_probe(de,
@@ -998,11 +1024,15 @@ _sysio_incore_dirop_getdirentries(struct inode *ino,
                                   (probe_ty )incore_directory_enumerate,
                                   NULL,
                                   &copy_info);
-       nbytes -= copy_info.nbytes;
        icino->ici_st.st_atime = time(NULL);
+       if (nbytes == copy_info.nbytes && copy_info.count)
+               return -EINVAL;
+       nbytes -= copy_info.nbytes;
+#if 0
        if (!nbytes)
                return -EOVERFLOW;
-       *basep = nbytes;
+#endif
+       *posp += nbytes;
        return (ssize_t )nbytes;
 }
 
@@ -1165,8 +1195,7 @@ _sysio_incore_dirop_mkdir(struct pnode *pno, mode_t mode)
        ino =
            _sysio_i_new(pno->p_parent->p_base->pb_ino->i_fs,
                         &icino->ici_fileid,
-                        stat.st_mode,
-                        0,
+                        &stat,
                         1,
                         &_sysio_incore_dir_ops,
                         icino);
@@ -1272,7 +1301,7 @@ _sysio_incore_dirop_rmdir(struct pnode *pno)
 }
 
 static int
-incore_create(struct pnode *pno, struct intnl_stat *st)
+incore_create(struct pnode *pno, struct intnl_stat *stat)
 {
        struct inode *dino, *ino;
        struct incore_inode *icino;
@@ -1281,7 +1310,7 @@ incore_create(struct pnode *pno, struct intnl_stat *st)
        dino = pno->p_parent->p_base->pb_ino;
        assert(dino);
 
-       icino = incore_i_alloc(FS2ICFS(dino->i_fs), st);
+       icino = incore_i_alloc(FS2ICFS(dino->i_fs), stat);
        if (!icino)
                return -ENOSPC;
 
@@ -1291,10 +1320,9 @@ incore_create(struct pnode *pno, struct intnl_stat *st)
        ino =
            _sysio_i_new(dino->i_fs,
                         &icino->ici_fileid,
-                        st->st_mode,
-                        st->st_rdev,
+                        stat,
                         1,
-                        S_ISREG(st->st_mode)
+                        S_ISREG(stat->st_mode)
                           ? &_sysio_incore_file_ops
                           : &_sysio_incore_dev_ops,
                         icino);
@@ -1309,7 +1337,7 @@ incore_create(struct pnode *pno, struct intnl_stat *st)
        err =
            incore_directory_insert(I2IC(dino),
                                    &pno->p_base->pb_name,
-                                   st->st_ino,
+                                   stat->st_ino,
                                    INCORE_D_TYPEOF(icino->ici_st.st_mode));
        if (err) {
                I_RELE(ino);
@@ -1370,7 +1398,7 @@ _sysio_incore_dirop_link(struct pnode *old, struct pnode *new)
        int     err;
 
        assert(!new->p_base->pb_ino);
-       assert(!S_ISDIR(old->p_base->pb_ino->i_mode));
+       assert(!S_ISDIR(old->p_base->pb_ino->i_stbuf.st_mode));
 
        /*
         * Can bump the link count?
@@ -1573,12 +1601,14 @@ _sysio_incore_filop_iodone(struct ioctx *iocp __IS_UNUSED)
 static int
 _sysio_incore_filop_fcntl(struct inode *ino __IS_UNUSED,
                          int cmd __IS_UNUSED,
-                         va_list ap __IS_UNUSED)
+                         va_list ap __IS_UNUSED,
+                         int *rtn)
 {
 
        /*
         * No fcntl's supported.
         */
+       *rtn = -1;
        return -ENOTTY;
 }