UBIFS: fix compilation warning
[pandora-kernel.git] / fs / ubifs / dir.c
index 6834920..a36f821 100644 (file)
@@ -170,8 +170,6 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
        return inode;
 }
 
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
 static int dbg_check_name(const struct ubifs_info *c,
                          const struct ubifs_dent_node *dent,
                          const struct qstr *nm)
@@ -185,12 +183,6 @@ static int dbg_check_name(const struct ubifs_info *c,
        return 0;
 }
 
-#else
-
-#define dbg_check_name(c, dent, nm) 0
-
-#endif
-
 static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
                                   struct nameidata *nd)
 {
@@ -357,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);
@@ -397,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;
        }
 
@@ -405,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;
        }
 
@@ -427,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)
@@ -443,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:
@@ -456,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);
 }
 
@@ -566,6 +582,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
        int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
        int err, budgeted = 1;
        struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
+       unsigned int saved_nlink = inode->i_nlink;
 
        /*
         * Budget request settings: deletion direntry, deletion inode (+1 for
@@ -613,7 +630,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
 out_cancel:
        dir->i_size += sz_change;
        dir_ui->ui_size = dir->i_size;
-       inc_nlink(inode);
+       set_nlink(inode, saved_nlink);
        unlock_2_inodes(dir, inode);
        if (budgeted)
                ubifs_release_budget(c, &req);
@@ -704,8 +721,7 @@ out_cancel:
        dir->i_size += sz_change;
        dir_ui->ui_size = dir->i_size;
        inc_nlink(dir);
-       inc_nlink(inode);
-       inc_nlink(inode);
+       set_nlink(inode, 2);
        unlock_2_inodes(dir, inode);
        if (budgeted)
                ubifs_release_budget(c, &req);
@@ -977,6 +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 uninitialized_var(saved_nlink);
 
        /*
         * Budget request settings: deletion direntry, new direntry, removing
@@ -987,8 +1004,8 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
         * separately.
         */
 
-       dbg_gen("dent '%.*s' ino %lu in dir ino %lu to dent '%.*s' in "
-               "dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name,
+       dbg_gen("dent '%.*s' ino %lu in dir ino %lu to dent '%.*s' in dir ino %lu",
+               old_dentry->d_name.len, old_dentry->d_name.name,
                old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len,
                new_dentry->d_name.name, new_dir->i_ino);
        ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
@@ -1059,13 +1076,14 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (unlink) {
                /*
                 * Directories cannot have hard-links, so if this is a
-                * directory, decrement its @i_nlink twice because an empty
-                * directory has @i_nlink 2.
+                * directory, just clear @i_nlink.
                 */
+               saved_nlink = new_inode->i_nlink;
                if (is_dir)
+                       clear_nlink(new_inode);
+               else
                        drop_nlink(new_inode);
                new_inode->i_ctime = time;
-               drop_nlink(new_inode);
        } else {
                new_dir->i_size += new_sz;
                ubifs_inode(new_dir)->ui_size = new_dir->i_size;
@@ -1102,9 +1120,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 out_cancel:
        if (unlink) {
-               if (is_dir)
-                       inc_nlink(new_inode);
-               inc_nlink(new_inode);
+               set_nlink(new_inode, saved_nlink);
        } else {
                new_dir->i_size -= new_sz;
                ubifs_inode(new_dir)->ui_size = new_dir->i_size;
@@ -1187,12 +1203,10 @@ const struct inode_operations ubifs_dir_inode_operations = {
        .rename      = ubifs_rename,
        .setattr     = ubifs_setattr,
        .getattr     = ubifs_getattr,
-#ifdef CONFIG_UBIFS_FS_XATTR
        .setxattr    = ubifs_setxattr,
        .getxattr    = ubifs_getxattr,
        .listxattr   = ubifs_listxattr,
        .removexattr = ubifs_removexattr,
-#endif
 };
 
 const struct file_operations ubifs_dir_operations = {