dax: fix device-dax region base
[cascardo/linux.git] / fs / freevxfs / vxfs_lookup.c
index 6d576b9..ce4785f 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2000-2001 Christoph Hellwig.
+ * Copyright (c) 2016 Krzysztof Blaszkowski
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,33 +62,6 @@ const struct file_operations vxfs_dir_operations = {
        .iterate_shared =       vxfs_readdir,
 };
 
-static inline u_long
-dir_blocks(struct inode *ip)
-{
-       u_long                  bsize = ip->i_sb->s_blocksize;
-       return (ip->i_size + bsize - 1) & ~(bsize - 1);
-}
-
-/*
- * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
- *
- * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
- */
-static inline int
-vxfs_match(int len, const char * const name, struct vxfs_direct *de)
-{
-       if (len != de->d_namelen)
-               return 0;
-       if (!de->d_ino)
-               return 0;
-       return !memcmp(name, de->d_name, len);
-}
-
-static inline struct vxfs_direct *
-vxfs_next_entry(struct vxfs_direct *de)
-{
-       return ((struct vxfs_direct *)((char*)de + de->d_reclen));
-}
 
 /**
  * vxfs_find_entry - find a mathing directory entry for a dentry
@@ -106,50 +80,64 @@ vxfs_next_entry(struct vxfs_direct *de)
 static struct vxfs_direct *
 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
 {
-       u_long                          npages, page, nblocks, pblocks, block;
-       u_long                          bsize = ip->i_sb->s_blocksize;
-       const char                      *name = dp->d_name.name;
-       int                             namelen = dp->d_name.len;
-
-       npages = dir_pages(ip);
-       nblocks = dir_blocks(ip);
-       pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
-       
-       for (page = 0; page < npages; page++) {
-               caddr_t                 kaddr;
-               struct page             *pp;
+       u_long bsize = ip->i_sb->s_blocksize;
+       const char *name = dp->d_name.name;
+       int namelen = dp->d_name.len;
+       loff_t limit = VXFS_DIRROUND(ip->i_size);
+       struct vxfs_direct *de_exit = NULL;
+       loff_t pos = 0;
+       struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
 
-               pp = vxfs_get_page(ip->i_mapping, page);
+       while (pos < limit) {
+               struct page *pp;
+               char *kaddr;
+               int pg_ofs = pos & ~PAGE_MASK;
+
+               pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
                if (IS_ERR(pp))
-                       continue;
-               kaddr = (caddr_t)page_address(pp);
-
-               for (block = 0; block <= nblocks && block <= pblocks; block++) {
-                       caddr_t                 baddr, limit;
-                       struct vxfs_dirblk      *dbp;
-                       struct vxfs_direct      *de;
-
-                       baddr = kaddr + (block * bsize);
-                       limit = baddr + bsize - VXFS_DIRLEN(1);
-                       
-                       dbp = (struct vxfs_dirblk *)baddr;
-                       de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
-
-                       for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
-                               if (!de->d_reclen)
-                                       break;
-                               if (!de->d_ino)
-                                       continue;
-                               if (vxfs_match(namelen, name, de)) {
-                                       *ppp = pp;
-                                       return (de);
-                               }
+                       return NULL;
+               kaddr = (char *)page_address(pp);
+
+               while (pg_ofs < PAGE_SIZE && pos < limit) {
+                       struct vxfs_direct *de;
+
+                       if ((pos & (bsize - 1)) < 4) {
+                               struct vxfs_dirblk *dbp =
+                                       (struct vxfs_dirblk *)
+                                        (kaddr + (pos & ~PAGE_MASK));
+                               int overhead = VXFS_DIRBLKOV(sbi, dbp);
+
+                               pos += overhead;
+                               pg_ofs += overhead;
+                       }
+                       de = (struct vxfs_direct *)(kaddr + pg_ofs);
+
+                       if (!de->d_reclen) {
+                               pos += bsize - 1;
+                               pos &= ~(bsize - 1);
+                               break;
+                       }
+
+                       pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
+                       pos += fs16_to_cpu(sbi, de->d_reclen);
+                       if (!de->d_ino)
+                               continue;
+
+                       if (namelen != fs16_to_cpu(sbi, de->d_namelen))
+                               continue;
+                       if (!memcmp(name, de->d_name, namelen)) {
+                               *ppp = pp;
+                               de_exit = de;
+                               break;
                        }
                }
-               vxfs_put_page(pp);
+               if (!de_exit)
+                       vxfs_put_page(pp);
+               else
+                       break;
        }
 
-       return NULL;
+       return de_exit;
 }
 
 /**
@@ -173,7 +161,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
 
        de = vxfs_find_entry(dip, dp, &pp);
        if (de) {
-               ino = de->d_ino;
+               ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
                kunmap(pp);
                put_page(pp);
        }
@@ -233,74 +221,80 @@ vxfs_readdir(struct file *fp, struct dir_context *ctx)
        struct inode            *ip = file_inode(fp);
        struct super_block      *sbp = ip->i_sb;
        u_long                  bsize = sbp->s_blocksize;
-       u_long                  page, npages, block, pblocks, nblocks, offset;
-       loff_t                  pos;
+       loff_t                  pos, limit;
+       struct vxfs_sb_info     *sbi = VXFS_SBI(sbp);
 
        if (ctx->pos == 0) {
                if (!dir_emit_dot(fp, ctx))
-                       return 0;
-               ctx->pos = 1;
+                       goto out;
+               ctx->pos++;
        }
        if (ctx->pos == 1) {
                if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
-                       return 0;
-               ctx->pos = 2;
+                       goto out;
+               ctx->pos++;
        }
-       pos = ctx->pos - 2;
-       
-       if (pos > VXFS_DIRROUND(ip->i_size))
-               return 0;
 
-       npages = dir_pages(ip);
-       nblocks = dir_blocks(ip);
-       pblocks = VXFS_BLOCK_PER_PAGE(sbp);
+       limit = VXFS_DIRROUND(ip->i_size);
+       if (ctx->pos > limit)
+               goto out;
 
-       page = pos >> PAGE_SHIFT;
-       offset = pos & ~PAGE_MASK;
-       block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
+       pos = ctx->pos & ~3L;
 
-       for (; page < npages; page++, block = 0) {
-               char                    *kaddr;
-               struct page             *pp;
+       while (pos < limit) {
+               struct page *pp;
+               char *kaddr;
+               int pg_ofs = pos & ~PAGE_MASK;
+               int rc = 0;
 
-               pp = vxfs_get_page(ip->i_mapping, page);
+               pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
                if (IS_ERR(pp))
-                       continue;
+                       return -ENOMEM;
+
                kaddr = (char *)page_address(pp);
 
-               for (; block <= nblocks && block <= pblocks; block++) {
-                       char                    *baddr, *limit;
-                       struct vxfs_dirblk      *dbp;
-                       struct vxfs_direct      *de;
+               while (pg_ofs < PAGE_SIZE && pos < limit) {
+                       struct vxfs_direct *de;
 
-                       baddr = kaddr + (block * bsize);
-                       limit = baddr + bsize - VXFS_DIRLEN(1);
-       
-                       dbp = (struct vxfs_dirblk *)baddr;
-                       de = (struct vxfs_direct *)
-                               (offset ?
-                                (kaddr + offset) :
-                                (baddr + VXFS_DIRBLKOV(dbp)));
-
-                       for (; (char *)de <= limit; de = vxfs_next_entry(de)) {
-                               if (!de->d_reclen)
-                                       break;
-                               if (!de->d_ino)
-                                       continue;
-
-                               offset = (char *)de - kaddr;
-                               ctx->pos = ((page << PAGE_SHIFT) | offset) + 2;
-                               if (!dir_emit(ctx, de->d_name, de->d_namelen,
-                                       de->d_ino, DT_UNKNOWN)) {
-                                       vxfs_put_page(pp);
-                                       return 0;
-                               }
+                       if ((pos & (bsize - 1)) < 4) {
+                               struct vxfs_dirblk *dbp =
+                                       (struct vxfs_dirblk *)
+                                        (kaddr + (pos & ~PAGE_MASK));
+                               int overhead = VXFS_DIRBLKOV(sbi, dbp);
+
+                               pos += overhead;
+                               pg_ofs += overhead;
+                       }
+                       de = (struct vxfs_direct *)(kaddr + pg_ofs);
+
+                       if (!de->d_reclen) {
+                               pos += bsize - 1;
+                               pos &= ~(bsize - 1);
+                               break;
+                       }
+
+                       pg_ofs += fs16_to_cpu(sbi, de->d_reclen);
+                       pos += fs16_to_cpu(sbi, de->d_reclen);
+                       if (!de->d_ino)
+                               continue;
+
+                       rc = dir_emit(ctx, de->d_name,
+                                       fs16_to_cpu(sbi, de->d_namelen),
+                                       fs32_to_cpu(sbi, de->d_ino),
+                                       DT_UNKNOWN);
+                       if (!rc) {
+                               /* the dir entry was not read, fix pos. */
+                               pos -= fs16_to_cpu(sbi, de->d_reclen);
+                               break;
                        }
-                       offset = 0;
                }
                vxfs_put_page(pp);
-               offset = 0;
+               if (!rc)
+                       break;
        }
-       ctx->pos = ((page << PAGE_SHIFT) | offset) + 2;
+
+       ctx->pos = pos | 2;
+
+out:
        return 0;
 }