yaffs Fix readdir locking
[yaffs2.git] / yaffs_fs.c
index 6eb356c81e6e4276c0ca88813e7b83082b788bd9..031c390c11dc13b6fdcca92d54ea5c146ff5d38b 100644 (file)
@@ -202,8 +202,12 @@ static int yaffs_file_flush(struct file *file, fl_owner_t id);
 static int yaffs_file_flush(struct file *file);
 #endif
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+static int yaffs_sync_object(struct file *file, int datasync);
+#else
 static int yaffs_sync_object(struct file *file, struct dentry *dentry,
                                int datasync);
+#endif
 
 static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
 
@@ -264,6 +268,15 @@ static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
 static int yaffs_writepage(struct page *page);
 #endif
 
+#ifdef CONFIG_YAFFS_XATTR
+int yaffs_setxattr(struct dentry *dentry, const char *name,
+                       const void *value, size_t size, int flags);
+ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
+                       size_t size);
+int yaffs_removexattr(struct dentry *dentry, const char *name);
+ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
+#endif
+
 
 #if (YAFFS_USE_WRITE_BEGIN_END != 0)
 static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
@@ -355,12 +368,24 @@ static void zero_user_segment(struct page *page, unsigned start, unsigned end)
 
 static const struct inode_operations yaffs_file_inode_operations = {
        .setattr = yaffs_setattr,
+#ifdef CONFIG_YAFFS_XATTR
+       .setxattr = yaffs_setxattr,
+       .getxattr = yaffs_getxattr,
+       .listxattr = yaffs_listxattr,
+       .removexattr = yaffs_removexattr,
+#endif
 };
 
 static const struct inode_operations yaffs_symlink_inode_operations = {
        .readlink = yaffs_readlink,
        .follow_link = yaffs_follow_link,
        .setattr = yaffs_setattr,
+#ifdef CONFIG_YAFFS_XATTR
+       .setxattr = yaffs_setxattr,
+       .getxattr = yaffs_getxattr,
+       .listxattr = yaffs_listxattr,
+       .removexattr = yaffs_removexattr,
+#endif
 };
 
 static const struct inode_operations yaffs_dir_inode_operations = {
@@ -374,6 +399,12 @@ static const struct inode_operations yaffs_dir_inode_operations = {
        .mknod = yaffs_mknod,
        .rename = yaffs_rename,
        .setattr = yaffs_setattr,
+#ifdef CONFIG_YAFFS_XATTR
+       .setxattr = yaffs_setxattr,
+       .getxattr = yaffs_getxattr,
+       .listxattr = yaffs_listxattr,
+       .removexattr = yaffs_removexattr,
+#endif
 };
 
 static const struct file_operations yaffs_dir_operations = {
@@ -1411,7 +1442,7 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
         sc = yaffs_NewSearch(obj);
         if(!sc){
                 retVal = -ENOMEM;
-                goto unlock_out;
+                goto out;
         }
 
        T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
@@ -1421,8 +1452,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                        (TSTR("yaffs_readdir: entry . ino %d \n"),
                        (int)inode->i_ino));
                yaffs_GrossUnlock(dev);
-               if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
+               if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
+                       yaffs_GrossLock(dev);
                        goto out;
+               }
                yaffs_GrossLock(dev);
                offset++;
                f->f_pos++;
@@ -1433,8 +1466,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                        (int)f->f_dentry->d_parent->d_inode->i_ino));
                yaffs_GrossUnlock(dev);
                if (filldir(dirent, "..", 2, offset,
-                       f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
+                       f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
+                       yaffs_GrossLock(dev);
                        goto out;
+               }
                yaffs_GrossLock(dev);
                offset++;
                f->f_pos++;
@@ -1470,8 +1505,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                                        strlen(name),
                                        offset,
                                        this_inode,
-                                       this_type) < 0)
+                                       this_type) < 0){
+                               yaffs_GrossLock(dev);
                                goto out;
+                       }
 
                         yaffs_GrossLock(dev);
 
@@ -1481,12 +1518,10 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
                 yaffs_SearchAdvance(sc);
        }
 
-unlock_out:
+out:
+       yaffs_EndSearch(sc);
        yaffs_DeviceToContext(dev)->readdirProcess = NULL;
-
        yaffs_GrossUnlock(dev);
-out:
-        yaffs_EndSearch(sc);
 
        return retVal;
 }
@@ -1715,12 +1750,19 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
        return -ENOMEM;
 }
 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+static int yaffs_sync_object(struct file *file, int datasync)
+#else
 static int yaffs_sync_object(struct file *file, struct dentry *dentry,
                                int datasync)
+#endif
 {
 
        yaffs_Object *obj;
        yaffs_Device *dev;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
+       struct dentry *dentry = file->f_path.dentry;
+#endif
 
        obj = yaffs_DentryToObject(dentry);
 
@@ -1836,6 +1878,123 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
        return error;
 }
 
+#ifdef CONFIG_YAFFS_XATTR
+int yaffs_setxattr(struct dentry *dentry, const char *name,
+                       const void *value, size_t size, int flags)
+{
+       struct inode *inode = dentry->d_inode;
+       int error = 0;
+       yaffs_Device *dev;
+       yaffs_Object *obj = yaffs_InodeToObject(inode);
+
+       T(YAFFS_TRACE_OS,
+               (TSTR("yaffs_setxattr of object %d\n"),
+               obj->objectId));
+
+
+       if (error == 0) {
+               int result;
+               dev = obj->myDev;
+               yaffs_GrossLock(dev);
+               result = yaffs_SetXAttribute(obj, name, value, size, flags);
+               if(result == YAFFS_OK)
+                       error = 0;
+               else if(result < 0)
+                       error = result;
+               yaffs_GrossUnlock(dev);
+
+       }
+       T(YAFFS_TRACE_OS,
+               (TSTR("yaffs_setxattr done returning %d\n"),error));
+
+       return error;
+}
+
+
+ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
+                       size_t size)
+{
+       struct inode *inode = dentry->d_inode;
+       int error = 0;
+       yaffs_Device *dev;
+       yaffs_Object *obj = yaffs_InodeToObject(inode);
+
+       T(YAFFS_TRACE_OS,
+               (TSTR("yaffs_getxattr of object %d\n"),
+               obj->objectId));
+
+
+       if (error == 0) {
+               dev = obj->myDev;
+               yaffs_GrossLock(dev);
+               error = yaffs_GetXAttribute(obj, name, buff, size);
+               yaffs_GrossUnlock(dev);
+
+       }
+       T(YAFFS_TRACE_OS,
+               (TSTR("yaffs_getxattr done returning %d\n"),error));
+
+       return error;
+}
+
+int yaffs_removexattr(struct dentry *dentry, const char *name)
+{
+       struct inode *inode = dentry->d_inode;
+       int error = 0;
+       yaffs_Device *dev;
+       yaffs_Object *obj = yaffs_InodeToObject(inode);
+
+       T(YAFFS_TRACE_OS,
+               (TSTR("yaffs_removexattr of object %d\n"),
+               obj->objectId));
+
+
+       if (error == 0) {
+               int result;
+               dev = obj->myDev;
+               yaffs_GrossLock(dev);
+               result = yaffs_RemoveXAttribute(obj, name);
+               if(result == YAFFS_OK)
+                       error = 0;
+               else if(result < 0)
+                       error = result;
+               yaffs_GrossUnlock(dev);
+
+       }
+       T(YAFFS_TRACE_OS,
+               (TSTR("yaffs_removexattr done returning %d\n"),error));
+
+       return error;
+}
+
+ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
+{
+       struct inode *inode = dentry->d_inode;
+       int error = 0;
+       yaffs_Device *dev;
+       yaffs_Object *obj = yaffs_InodeToObject(inode);
+
+       T(YAFFS_TRACE_OS,
+               (TSTR("yaffs_listxattr of object %d\n"),
+               obj->objectId));
+
+
+       if (error == 0) {
+               dev = obj->myDev;
+               yaffs_GrossLock(dev);
+               error = yaffs_ListXAttributes(obj, buff, size);
+               yaffs_GrossUnlock(dev);
+
+       }
+       T(YAFFS_TRACE_OS,
+               (TSTR("yaffs_listxattr done returning %d\n"),error));
+
+       return error;
+}
+
+#endif
+
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
 static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
@@ -2072,7 +2231,7 @@ static int yaffs_BackgroundThread(void *data)
                if(time_before(expires,now))
                        expires = now + HZ;
 
-               init_timer(&timer);
+               init_timer_on_stack(&timer);
                timer.expires = expires+1;
                timer.data = (unsigned long) current;
                timer.function = yaffs_background_waker;
@@ -2097,7 +2256,7 @@ static int yaffs_BackgroundStart(yaffs_Device *dev)
        context->bgRunning = 1;
 
        context->bgThread = kthread_run(yaffs_BackgroundThread,
-                               (void *)dev,"yaffs-bg");
+                               (void *)dev,"yaffs-bg-%d",context->mount_id);
 
        if(IS_ERR(context->bgThread)){
                retval = PTR_ERR(context->bgThread);
@@ -2414,6 +2573,11 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        yaffs_DeviceParam *param;
 
        yaffs_options options;
+       
+       unsigned mount_id;
+       int found;
+       struct yaffs_LinuxContext *context_iterator;
+       struct ylist_head *l;
 
        sb->s_magic = YAFFS_MAGIC;
        sb->s_op = &yaffs_super_ops;
@@ -2625,6 +2789,9 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
 
 #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
        param->disableLazyLoad = 1;
+#endif
+#ifdef CONFIG_YAFFS_XATTR
+       param->enableXattr = 1;
 #endif
        if(options.lazy_loading_overridden)
                param->disableLazyLoad = !options.lazy_loading_enabled;
@@ -2713,8 +2880,19 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion,
        param->skipCheckpointRead = options.skip_checkpoint_read;
        param->skipCheckpointWrite = options.skip_checkpoint_write;
 
-       /* we assume this is protected by lock_kernel() in mount/umount */
        down(&yaffs_context_lock);
+       /* Get a mount id */
+       found = 0;
+       for(mount_id=0; ! found; mount_id++){
+               found = 1;
+               ylist_for_each(l,&yaffs_context_list){
+                       context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
+                       if(context_iterator->mount_id == mount_id)
+                               found = 0;
+               }
+       }
+       context->mount_id = mount_id;
+       
        ylist_add_tail(&(yaffs_DeviceToContext(dev)->contextList), &yaffs_context_list);
        up(&yaffs_context_lock);
 
@@ -2900,10 +3078,8 @@ static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
        buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
        buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
        buf += sprintf(buf, "\n");
-       buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
-       buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
-       buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
-       buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
+       buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes);
+       buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects);
        buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
        buf += sprintf(buf, "\n");
        buf += sprintf(buf, "nPageWrites........ %u\n", dev->nPageWrites);
@@ -2996,18 +3172,13 @@ static int yaffs_stats_proc_read(char *page,
                yaffs_Device *dev = dc->dev;
 
                int erasedChunks;
-               int nObjects;
-               int nTnodes;
 
                erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
-               nObjects = dev->nObjectsCreated -dev->nFreeObjects;
-               nTnodes = dev->nTnodesCreated - dev->nFreeTnodes;
-               
                
-               buf += sprintf(buf,"%d, %d, %d, %u, %u, %d, %d\n",
+               buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
                                n, dev->nFreeChunks, erasedChunks,
                                dev->backgroundGCs, dev->oldestDirtyGCs,
-                               nObjects, nTnodes);
+                               dev->nObjects, dev->nTnodes);
        }
        up(&yaffs_context_lock);