UBIFS: fix compilation warning
[pandora-kernel.git] / fs / ubifs / dir.c
index 1f1028d..a36f821 100644 (file)
@@ -349,31 +349,50 @@ static unsigned int vfs_dent_type(uint8_t type)
 static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 {
        int err, over = 0;
+       loff_t pos = file->f_pos;
        struct qstr nm;
        union ubifs_key key;
        struct ubifs_dent_node *dent;
        struct inode *dir = file->f_path.dentry->d_inode;
        struct ubifs_info *c = dir->i_sb->s_fs_info;
 
-       dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
+       dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, pos);
 
-       if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
+       if (pos > UBIFS_S_KEY_HASH_MASK || pos == 2)
                /*
                 * The directory was seek'ed to a senseless position or there
                 * are no more entries.
                 */
                return 0;
 
+       if (file->f_version == 0) {
+               /*
+                * The file was seek'ed, which means that @file->private_data
+                * is now invalid. This may also be just the first
+                * 'ubifs_readdir()' invocation, in which case
+                * @file->private_data is NULL, and the below code is
+                * basically a no-op.
+                */
+               kfree(file->private_data);
+               file->private_data = NULL;
+       }
+
+       /*
+        * 'generic_file_llseek()' unconditionally sets @file->f_version to
+        * zero, and we use this for detecting whether the file was seek'ed.
+        */
+       file->f_version = 1;
+
        /* File positions 0 and 1 correspond to "." and ".." */
-       if (file->f_pos == 0) {
+       if (pos == 0) {
                ubifs_assert(!file->private_data);
                over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR);
                if (over)
                        return 0;
-               file->f_pos = 1;
+               file->f_pos = pos = 1;
        }
 
-       if (file->f_pos == 1) {
+       if (pos == 1) {
                ubifs_assert(!file->private_data);
                over = filldir(dirent, "..", 2, 1,
                               parent_ino(file->f_path.dentry), DT_DIR);
@@ -389,7 +408,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
                        goto out;
                }
 
-               file->f_pos = key_hash_flash(c, &dent->key);
+               file->f_pos = pos = key_hash_flash(c, &dent->key);
                file->private_data = dent;
        }
 
@@ -397,17 +416,16 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
        if (!dent) {
                /*
                 * The directory was seek'ed to and is now readdir'ed.
-                * Find the entry corresponding to @file->f_pos or the
-                * closest one.
+                * Find the entry corresponding to @pos or the closest one.
                 */
-               dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
+               dent_key_init_hash(c, &key, dir->i_ino, pos);
                nm.name = NULL;
                dent = ubifs_tnc_next_ent(c, &key, &nm);
                if (IS_ERR(dent)) {
                        err = PTR_ERR(dent);
                        goto out;
                }
-               file->f_pos = key_hash_flash(c, &dent->key);
+               file->f_pos = pos = key_hash_flash(c, &dent->key);
                file->private_data = dent;
        }
 
@@ -419,7 +437,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
                             ubifs_inode(dir)->creat_sqnum);
 
                nm.len = le16_to_cpu(dent->nlen);
-               over = filldir(dirent, dent->name, nm.len, file->f_pos,
+               over = filldir(dirent, dent->name, nm.len, pos,
                               le64_to_cpu(dent->inum),
                               vfs_dent_type(dent->type));
                if (over)
@@ -435,9 +453,17 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
                }
 
                kfree(file->private_data);
-               file->f_pos = key_hash_flash(c, &dent->key);
+               file->f_pos = pos = key_hash_flash(c, &dent->key);
                file->private_data = dent;
                cond_resched();
+
+               if (file->f_version == 0)
+                       /*
+                        * The file was seek'ed meanwhile, lets return and start
+                        * reading direntries from the new position on the next
+                        * invocation.
+                        */
+                       return 0;
        }
 
 out:
@@ -448,15 +474,13 @@ out:
 
        kfree(file->private_data);
        file->private_data = NULL;
+       /* 2 is a special value indicating that there are no more direntries */
        file->f_pos = 2;
        return 0;
 }
 
-/* If a directory is seeked, we have to free saved readdir() state */
 static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int origin)
 {
-       kfree(file->private_data);
-       file->private_data = NULL;
        return generic_file_llseek(file, offset, origin);
 }
 
@@ -969,7 +993,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
                        .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
        struct timespec time;
-       unsigned int saved_nlink;
+       unsigned int uninitialized_var(saved_nlink);
 
        /*
         * Budget request settings: deletion direntry, new direntry, removing