ARM64: dts: rockchip: add max-link-speed for rk3399
[firefly-linux-kernel-4.4.55.git] / fs / fat / dir.c
index 4b775e606fc8f3ee44157e8a0b5dec4be7141bb4..8b2127ffb226cca2ece880d41fd756624c5d3118 100644 (file)
  *  Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
  */
 
-#include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/buffer_head.h>
 #include <linux/compat.h>
 #include <linux/uaccess.h>
-#include <linux/kernel.h>
 #include "fat.h"
 
 /*
@@ -543,6 +539,7 @@ end_of_dir:
 EXPORT_SYMBOL_GPL(fat_search_long);
 
 struct fat_ioctl_filldir_callback {
+       struct dir_context ctx;
        void __user *dirent;
        int result;
        /* for dir ioctl */
@@ -552,8 +549,9 @@ struct fat_ioctl_filldir_callback {
        int short_len;
 };
 
-static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
-                        filldir_t filldir, int short_only, int both)
+static int __fat_readdir(struct inode *inode, struct file *file,
+                        struct dir_context *ctx, int short_only,
+                        struct fat_ioctl_filldir_callback *both)
 {
        struct super_block *sb = inode->i_sb;
        struct msdos_sb_info *sbi = MSDOS_SB(sb);
@@ -564,27 +562,20 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
        unsigned char bufname[FAT_MAX_SHORT_SIZE];
        int isvfat = sbi->options.isvfat;
        const char *fill_name = NULL;
-       unsigned long inum;
-       unsigned long lpos, dummy, *furrfu = &lpos;
+       int fake_offset = 0;
        loff_t cpos;
        int short_len = 0, fill_len = 0;
        int ret = 0;
 
        mutex_lock(&sbi->s_lock);
 
-       cpos = filp->f_pos;
+       cpos = ctx->pos;
        /* Fake . and .. for the root directory. */
        if (inode->i_ino == MSDOS_ROOT_INO) {
-               while (cpos < 2) {
-                       if (filldir(dirent, "..", cpos+1, cpos,
-                                   MSDOS_ROOT_INO, DT_DIR) < 0)
-                               goto out;
-                       cpos++;
-                       filp->f_pos++;
-               }
-               if (cpos == 2) {
-                       dummy = 2;
-                       furrfu = &dummy;
+               if (!dir_emit_dots(file, ctx))
+                       goto out;
+               if (ctx->pos == 2) {
+                       fake_offset = 1;
                        cpos = 0;
                }
        }
@@ -619,9 +610,9 @@ parse_record:
                int status = fat_parse_long(inode, &cpos, &bh, &de,
                                            &unicode, &nr_slots);
                if (status < 0) {
-                       filp->f_pos = cpos;
+                       bh = NULL;
                        ret = status;
-                       goto out;
+                       goto end_of_dir;
                } else if (status == PARSE_INVALID)
                        goto record_end;
                else if (status == PARSE_NOT_LONGNAME)
@@ -639,6 +630,19 @@ parse_record:
                        /* !both && !short_only, so we don't need shortname. */
                        if (!both)
                                goto start_filldir;
+
+                       short_len = fat_parse_short(sb, de, bufname,
+                                                   sbi->options.dotsOK);
+                       if (short_len == 0)
+                               goto record_end;
+                       /* hack for fat_ioctl_filldir() */
+                       both->longname = fill_name;
+                       both->long_len = fill_len;
+                       both->shortname = bufname;
+                       both->short_len = short_len;
+                       fill_name = NULL;
+                       fill_len = 0;
+                       goto start_filldir;
                }
        }
 
@@ -646,28 +650,22 @@ parse_record:
        if (short_len == 0)
                goto record_end;
 
-       if (nr_slots) {
-               /* hack for fat_ioctl_filldir() */
-               struct fat_ioctl_filldir_callback *p = dirent;
-
-               p->longname = fill_name;
-               p->long_len = fill_len;
-               p->shortname = bufname;
-               p->short_len = short_len;
-               fill_name = NULL;
-               fill_len = 0;
-       } else {
-               fill_name = bufname;
-               fill_len = short_len;
-       }
+       fill_name = bufname;
+       fill_len = short_len;
 
 start_filldir:
-       lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
-       if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME))
-               inum = inode->i_ino;
-       else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
-               inum = parent_ino(filp->f_path.dentry);
+       ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
+       if (fake_offset && ctx->pos < 2)
+               ctx->pos = 2;
+
+       if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
+               if (!dir_emit_dot(file, ctx))
+                       goto fill_failed;
+       } else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) {
+               if (!dir_emit_dotdot(file, ctx))
+                       goto fill_failed;
        } else {
+               unsigned long inum;
                loff_t i_pos = fat_make_i_pos(sb, bh, de);
                struct inode *tmp = fat_iget(sb, i_pos);
                if (tmp) {
@@ -675,38 +673,42 @@ start_filldir:
                        iput(tmp);
                } else
                        inum = iunique(sb, MSDOS_ROOT_INO);
+               if (!dir_emit(ctx, fill_name, fill_len, inum,
+                           (de->attr & ATTR_DIR) ? DT_DIR : DT_REG))
+                       goto fill_failed;
        }
 
-       if (filldir(dirent, fill_name, fill_len, *furrfu, inum,
-                   (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0)
-               goto fill_failed;
-
 record_end:
-       furrfu = &lpos;
-       filp->f_pos = cpos;
+       fake_offset = 0;
+       ctx->pos = cpos;
        goto get_new;
+
 end_of_dir:
-       filp->f_pos = cpos;
+       if (fake_offset && cpos < 2)
+               ctx->pos = 2;
+       else
+               ctx->pos = cpos;
 fill_failed:
        brelse(bh);
        if (unicode)
                __putname(unicode);
 out:
        mutex_unlock(&sbi->s_lock);
+
        return ret;
 }
 
-static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int fat_readdir(struct file *file, struct dir_context *ctx)
 {
-       struct inode *inode = file_inode(filp);
-       return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
+       return __fat_readdir(file_inode(file), file, ctx, 0, NULL);
 }
 
 #define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type)                         \
-static int func(void *__buf, const char *name, int name_len,              \
+static int func(struct dir_context *ctx, const char *name, int name_len,   \
                             loff_t offset, u64 ino, unsigned int d_type)  \
 {                                                                         \
-       struct fat_ioctl_filldir_callback *buf = __buf;                    \
+       struct fat_ioctl_filldir_callback *buf =                           \
+               container_of(ctx, struct fat_ioctl_filldir_callback, ctx); \
        struct dirent_type __user *d1 = buf->dirent;                       \
        struct dirent_type __user *d2 = d1 + 1;                            \
                                                                           \
@@ -755,20 +757,25 @@ efault:                                                                      \
 
 FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent)
 
-static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
+static int fat_ioctl_readdir(struct inode *inode, struct file *file,
                             void __user *dirent, filldir_t filldir,
                             int short_only, int both)
 {
-       struct fat_ioctl_filldir_callback buf;
+       struct fat_ioctl_filldir_callback buf = {
+               .ctx.actor = filldir,
+               .dirent = dirent
+       };
        int ret;
 
        buf.dirent = dirent;
        buf.result = 0;
        mutex_lock(&inode->i_mutex);
+       buf.ctx.pos = file->f_pos;
        ret = -ENOENT;
        if (!IS_DEADDIR(inode)) {
-               ret = __fat_readdir(inode, filp, &buf, filldir,
-                                   short_only, both);
+               ret = __fat_readdir(inode, file, &buf.ctx,
+                                   short_only, both ? &buf : NULL);
+               file->f_pos = buf.ctx.pos;
        }
        mutex_unlock(&inode->i_mutex);
        if (ret >= 0)
@@ -776,13 +783,6 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
        return ret;
 }
 
-static int fat_ioctl_volume_id(struct inode *dir)
-{
-       struct super_block *sb = dir->i_sb;
-       struct msdos_sb_info *sbi = MSDOS_SB(sb);
-       return sbi->vol_id;
-}
-
 static long fat_dir_ioctl(struct file *filp, unsigned int cmd,
                          unsigned long arg)
 {
@@ -799,8 +799,6 @@ static long fat_dir_ioctl(struct file *filp, unsigned int cmd,
                short_only = 0;
                both = 1;
                break;
-       case VFAT_IOCTL_GET_VOLUME_ID:
-               return fat_ioctl_volume_id(inode);
        default:
                return fat_generic_ioctl(filp, cmd, arg);
        }
@@ -841,8 +839,6 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
                short_only = 0;
                both = 1;
                break;
-       case VFAT_IOCTL_GET_VOLUME_ID:
-               return fat_ioctl_volume_id(inode);
        default:
                return fat_generic_ioctl(filp, cmd, (unsigned long)arg);
        }
@@ -865,7 +861,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
 const struct file_operations fat_dir_operations = {
        .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
-       .readdir        = fat_readdir,
+       .iterate        = fat_readdir,
        .unlocked_ioctl = fat_dir_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = fat_compat_dir_ioctl,