Whamcloud - gitweb
Update smfs: 1)unlock cache inode after we call bottom fs methods 2)minor fix in...
[fs/lustre-release.git] / lustre / smfs / dir.c
index 378df89..d194bb8 100644 (file)
@@ -9,35 +9,15 @@
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/unistd.h>
+#include <linux/lustre_idl.h> 
+#include <linux/smp_lock.h>
 
 #include "smfs_internal.h" 
+#include "kml_idl.h" 
 
-static void d_unalloc(struct dentry *dentry)
-{
-        if (dentry) {                                                                                                                                                                                
-               list_del(&dentry->d_hash);
-               INIT_LIST_HEAD(&dentry->d_hash);
-               dput(dentry);   
-       }
-}
-static struct inode *sm_create_inode(struct super_block *sb,
-                                    struct inode *cache_inode) 
-{
-       struct inode *inode;
-
-       inode = new_inode(sb);
-       if (inode) {
-               /*FIXME there are still some 
-                * other attributes need to
-                * duplicated*/
-               inode->i_ino = cache_inode->i_ino;                      
-               inode->i_mode = cache_inode->i_mode;                    
-       }       
-       
-       return inode;
-}
-                                                                                                                                                                                                     
-static void prepare_parent_dentry(struct dentry *dentry, struct inode *inode)
+#define NAME_ALLOC_LEN(len)     ((len+16) & ~15)
+                                                                                                                                                                                        
+void prepare_parent_dentry(struct dentry *dentry, struct inode *inode)
 {
         atomic_set(&dentry->d_count, 1);
         dentry->d_vfs_flags = 0;
@@ -52,14 +32,22 @@ static void prepare_parent_dentry(struct dentry *dentry, struct inode *inode)
         INIT_LIST_HEAD(&dentry->d_alias);
 }
 
+void d_unalloc(struct dentry *dentry)
+{
+
+       list_del(&dentry->d_hash);
+       INIT_LIST_HEAD(&dentry->d_hash);
+       dput(dentry); /* this will free the dentry memory */
+}
+
 static int smfs_create(struct inode *dir, 
                       struct dentry *dentry, 
                       int mode)
 {
        struct  inode *cache_dir; 
-       struct  inode *cache_inode, *inode;
-       struct  dentry tmp
-       struct  dentry *cache_dentry;
+       struct  inode *cache_inode = NULL, *inode;
+       struct  dentry parent
+       struct  dentry *cache_dentry = NULL;
        int     rc;
        
        ENTRY;
@@ -68,35 +56,41 @@ static int smfs_create(struct inode *dir,
         if (!cache_dir)
                 RETURN(-ENOENT);
        
-       prepare_parent_dentry(&tmp, cache_dir);      
-       cache_dentry = d_alloc(&tmp, &dentry->d_name);
-        
-       if (!cache_dentry) 
-                RETURN(-ENOENT);
+       prepare_parent_dentry(&parent, cache_dir);      
+       cache_dentry = d_alloc(&parent, &dentry->d_name);
        
-       if(cache_dir && cache_dir->i_op->create)
+       if (!cache_dentry) {
+               RETURN(-ENOMEM);
+       }
+                
+       if (cache_dir && cache_dir->i_op->create)
                rc = cache_dir->i_op->create(cache_dir, cache_dentry, mode);
+       
        if (rc)
                GOTO(exit, rc);
-       cache_inode = cache_dentry->d_inode;
-       inode = sm_create_inode(dir->i_sb, cache_inode);        
+
+       cache_inode = igrab(cache_dentry->d_inode);
        
+       inode = iget(dir->i_sb, cache_inode->i_ino);    
+
        if (!inode) 
-               GOTO(exit, rc);         
+               GOTO(exit, rc = -ENOMEM);
+               
+       d_instantiate(dentry, inode);   
        
        sm_set_inode_ops(cache_inode, inode);
 exit:
-       d_unalloc(cache_dentry);        
+       d_unalloc(cache_dentry);
        RETURN(rc);
 }
+
 static struct dentry *smfs_lookup(struct inode *dir,
                                  struct dentry *dentry)
 {
        struct  inode *cache_dir; 
-       struct  inode *cache_inode, *inode;
-       struct  dentry tmp
-       struct  dentry *cache_dentry;
+       struct  inode *cache_inode = NULL, *inode;
+       struct  dentry parent
+       struct  dentry *cache_dentry = NULL;
        struct  dentry *rc = NULL;
        
        ENTRY;
@@ -104,12 +98,9 @@ static struct dentry *smfs_lookup(struct inode *dir,
        cache_dir = I2CI(dir);
         if (!cache_dir)
                 RETURN(ERR_PTR(-ENOENT));
-       prepare_parent_dentry(&tmp, cache_dir);      
-       cache_dentry = d_alloc(&tmp, &dentry->d_name);
+       prepare_parent_dentry(&parent, cache_dir);      
+       cache_dentry = d_alloc(&parent, &dentry->d_name);
       
-       if (!cache_dentry)
-               RETURN(ERR_PTR(-ENOENT));
-
        if(cache_dir && cache_dir->i_op->lookup)
                rc = cache_dir->i_op->lookup(cache_dir, cache_dentry);
 
@@ -119,19 +110,358 @@ static struct dentry *smfs_lookup(struct inode *dir,
                GOTO(exit, rc); 
        }
 
-       cache_inode = cache_dentry->d_inode;
+       cache_inode = igrab(cache_dentry->d_inode);
        
        inode = iget(dir->i_sb, cache_inode->i_ino);    
                
        d_add(dentry, inode);   
 exit:
-       d_unalloc(cache_dentry);        
+       d_unalloc(cache_dentry);
        RETURN(rc);
 }                     
+
+static int smfs_lookup_raw(struct inode *dir, const char *name,
+                           int len, ino_t *data)
+{
+       struct  inode *cache_dir; 
+       int     rc = 0;
+
+       cache_dir = I2CI(dir);
+
+       if (!cache_dir) 
+                RETURN(-ENOENT);
+       
+       if (cache_dir->i_op->lookup_raw)
+               rc = cache_dir->i_op->lookup_raw(cache_dir, name, len, data);           
+               
+       RETURN(rc);
+}
+
+static int smfs_link(struct dentry * old_dentry,
+                     struct inode * dir, struct dentry *dentry)
+{
+       struct  inode *cache_old_inode = NULL; 
+       struct  inode *cache_dir = I2CI(dir); 
+       struct  inode *inode = NULL; 
+       struct  dentry *cache_dentry;
+       struct  dentry *cache_old_dentry;
+       struct  dentry parent; 
+       struct  dentry parent_old; 
+       int     rc = 0;
+
+       inode = old_dentry->d_inode;
+       
+       cache_old_inode = I2CI(inode);
+       
+       if (!cache_old_inode || !cache_dir) 
+                RETURN(-ENOENT);
+       
+       prepare_parent_dentry(&parent, cache_dir);
+       cache_dentry = d_alloc(&parent, &dentry->d_name);
+       
+       prepare_parent_dentry(&parent_old, cache_dir);
+       cache_old_dentry = d_alloc(&parent_old, &dentry->d_name);
+       d_add(cache_old_dentry, cache_old_inode); 
+       
+       if (cache_dir->i_op->link)
+               rc = cache_dir->i_op->link(cache_old_dentry, cache_dir, cache_dentry);          
+       
+       if (rc)
+               GOTO(exit, rc); 
+       
+       atomic_inc(&inode->i_count);
+       post_smfs_inode(inode, cache_old_dentry->d_inode);
+       d_instantiate(dentry, inode);
+
+exit:
+       if (cache_dentry->d_inode)      
+               igrab(cache_dentry->d_inode);
+       if (cache_old_dentry->d_inode)
+               igrab(cache_old_dentry->d_inode);
+       
+       d_unalloc(cache_dentry);
+       d_unalloc(cache_old_dentry);
+
+       RETURN(rc);
+}
+
+static int smfs_unlink(struct inode * dir, 
+                      struct dentry *dentry)
+{
+       struct inode *cache_dir = I2CI(dir);
+       struct inode *cache_inode = I2CI(dentry->d_inode);
+       struct dentry *cache_dentry;
+       struct dentry parent; 
+       int    rc = 0;
+
+       if (!cache_dir || !cache_inode)
+               RETURN(-ENOENT);
+       
+       prepare_parent_dentry(&parent, cache_dir);
+       cache_dentry = d_alloc(&parent, &dentry->d_name);
+       d_add(cache_dentry, cache_inode);
+
+       if (cache_dir->i_op->unlink)
+               rc = cache_dir->i_op->unlink(cache_dir, cache_dentry);
+
+       
+       post_smfs_inode(dentry->d_inode, cache_dentry->d_inode);
+       post_smfs_inode(dir, cache_dir);
+       
+       igrab(cache_dentry->d_inode);
+
+       d_unalloc(cache_dentry);        
+       RETURN(rc);     
+}
+
+static int smfs_symlink (struct inode * dir,
+                        struct dentry *dentry, 
+                        const char * symname)
+{
+       struct inode *cache_dir = I2CI(dir);
+       struct inode *cache_inode = NULL;
+       struct inode *inode = NULL;
+       struct dentry *cache_dentry; 
+       struct dentry parent; 
+       int    rc = 0;
+
+       if (!cache_dir) 
+               RETURN(-ENOENT);
+       
+       prepare_parent_dentry(&parent, cache_dir);
+       cache_dentry = d_alloc(&parent, &dentry->d_name);
+
+       if (cache_dir->i_op->symlink)
+               rc = cache_dir->i_op->symlink(cache_dir, cache_dentry, symname);
+       
+       cache_inode = igrab(cache_dentry->d_inode);
+       
+       inode = iget(dir->i_sb, cache_inode->i_ino);
+
+       if (inode)
+               d_instantiate(dentry, inode);
+       else
+               rc = -ENOENT;
+       
+       d_unalloc(cache_dentry);        
+       
+       RETURN(rc);                     
+}
+
+static int smfs_mkdir(struct inode * dir, 
+                     struct dentry * dentry, 
+                     int mode)
+{
+       struct inode *cache_dir = I2CI(dir);
+       struct inode *cache_inode = NULL;
+       struct inode *inode = NULL;
+       struct dentry *cache_dentry;
+       struct dentry parent;
+       void   *handle;
+       int    rc = 0;
+
+       if (!cache_dir) 
+               RETURN(-ENOENT);
+
+       handle = smfs_trans_start(cache_dir, KML_OPCODE_MKDIR);
+       if (IS_ERR(handle) ) {
+                CERROR("smfs_do_mkdir: no space for transaction\n");
+               RETURN(-ENOSPC);
+       }
+       
+       prepare_parent_dentry(&parent, cache_dir);
+       cache_dentry = d_alloc(&parent, &dentry->d_name);
+
+       lock_kernel();  
+       if (cache_dir->i_op->mkdir)
+               rc = cache_dir->i_op->mkdir(cache_dir, cache_dentry, mode);
+
+       cache_inode = igrab(cache_dentry->d_inode);
+
+       inode = iget(dir->i_sb, cache_inode->i_ino);
+
+       if (!inode)
+               GOTO(exit, rc = -ENOENT);
+       d_instantiate(dentry, inode);   
+       /*Do KML post hook*/
+       if (smfs_do_kml(dir)) {
+               rc = post_kml_mkdir(dir, dentry);
+               GOTO(exit, rc);
+       }
+       post_smfs_inode(dir, cache_dir);
+exit:
+       unlock_kernel();        
+       smfs_trans_commit(handle);
+       d_unalloc(cache_dentry);
+       RETURN(rc);             
+}
+
+static int  smfs_rmdir(struct inode * dir, 
+                      struct dentry *dentry) 
+{
+       struct inode *cache_dir = I2CI(dir);
+       struct inode *cache_inode = I2CI(dentry->d_inode);
+       struct dentry *cache_dentry;
+       struct dentry parent;
+       int    rc = 0;
+
+       if (!cache_dir) 
+               RETURN(-ENOENT);
+       
+       prepare_parent_dentry(&parent, cache_dir);
+       cache_dentry = d_alloc(&parent, &dentry->d_name);
+       d_add(cache_dentry, cache_inode);
+       
+       igrab(cache_inode);
+       
+       if (cache_dir->i_op->rmdir)
+               rc = cache_dir->i_op->rmdir(cache_dir, cache_dentry);
+
+       post_smfs_inode(dir, cache_dir);
+       post_smfs_inode(dentry->d_inode, cache_dentry->d_inode);
+       d_unalloc(cache_dentry);
+       RETURN(rc);             
+}
+
+static int smfs_mknod(struct inode * dir, struct dentry *dentry,
+                      int mode, int rdev)
+{
+       struct inode *cache_dir = I2CI(dir);
+       struct inode *inode = NULL;
+       struct inode *cache_inode = NULL;
+       struct dentry *cache_dentry;
+       struct dentry parent;
+       int    rc = 0;
+
+       if (!cache_dir) 
+               RETURN(-ENOENT);
+
+       prepare_parent_dentry(&parent, cache_dir);
+       cache_dentry = d_alloc(&parent, &dentry->d_name);
+       
+       if (cache_dir->i_op->mknod)
+               rc = cache_dir->i_op->mknod(cache_dir, cache_dentry, mode, rdev);
+       
+       if (cache_dentry->d_inode)
+               cache_inode = igrab(cache_dentry->d_inode);
+       if (rc)
+               GOTO(exit, rc);
+       
+       inode = iget(dir->i_sb, cache_inode->i_ino);
+       d_instantiate(dentry, inode);
+       post_smfs_inode(dir, cache_dir);
+       post_smfs_inode(dentry->d_inode, cache_dentry->d_inode);
+exit:
+       d_unalloc(cache_dentry);
+       RETURN(rc);             
+}
+static int smfs_rename(struct inode * old_dir, struct dentry *old_dentry,
+                       struct inode * new_dir,struct dentry *new_dentry)
+{
+       struct inode *cache_old_dir = I2CI(old_dir);
+       struct inode *cache_new_dir = I2CI(new_dir);
+       struct inode *cache_old_inode = I2CI(old_dentry->d_inode);
+       struct dentry *cache_old_dentry;
+       struct dentry *cache_new_dentry;
+       struct dentry parent_new;
+       struct dentry parent_old;
+       int    rc = 0;
+
+       if (!cache_old_dir || !cache_new_dir || !cache_old_inode) 
+               RETURN(-ENOENT);
+       
+       prepare_parent_dentry(&parent_old, cache_old_dir);
+       cache_old_dentry = d_alloc(&parent_old, &old_dentry->d_name);
+       d_add(cache_old_dentry, cache_old_inode);
+       igrab(cache_old_inode); 
+
+       prepare_parent_dentry(&parent_new, cache_new_dir);
+       cache_new_dentry = d_alloc(&parent_new, &new_dentry->d_name);
+       
+       if (cache_old_dir->i_op->rename)
+               rc = cache_old_dir->i_op->rename(cache_old_dir, cache_old_dentry,
+                                                cache_new_dir, cache_new_dentry);
+
+       post_smfs_inode(old_dir, cache_old_dir) ;
+       post_smfs_inode(new_dir, cache_new_dir);
+       if (cache_new_dentry->d_inode) {
+               igrab(cache_new_dentry->d_inode);       
+       }
+       d_unalloc(cache_old_dentry);
+       d_unalloc(cache_new_dentry);
+       RETURN(rc);             
+}
+
 struct inode_operations smfs_dir_iops = {
-       create: smfs_create,
-       lookup: smfs_lookup,
+       create:         smfs_create,
+       lookup:         smfs_lookup,
+       lookup_raw:     smfs_lookup_raw,        /* BKL held */
+        link:           smfs_link,              /* BKL held */
+        unlink:         smfs_unlink,            /* BKL held */
+        symlink:        smfs_symlink,           /* BKL held */
+        mkdir:          smfs_mkdir,             /* BKL held */
+        rmdir:          smfs_rmdir,             /* BKL held */
+        mknod:          smfs_mknod,             /* BKL held */
+        rename:         smfs_rename,            /* BKL held */
+        setxattr:       smfs_setxattr,          /* BKL held */
+        getxattr:       smfs_getxattr,          /* BKL held */
+        listxattr:      smfs_listxattr,         /* BKL held */
+        removexattr:    smfs_removexattr,       /* BKL held */
 };
-struct file_operations smfs_dir_fops = {
+
+static ssize_t smfs_read_dir(struct file *filp, char *buf, 
+                            size_t size, loff_t *ppos)
+{
+       struct dentry *dentry = filp->f_dentry;
+       struct inode *cache_inode = NULL;
+        struct  file open_file;
+       struct  dentry open_dentry;
+       int    rc = 0;
+       
+       cache_inode = I2CI(dentry->d_inode);
+
+       if (!cache_inode) 
+               RETURN(-EINVAL);
+
+       smfs_prepare_cachefile(dentry->d_inode, filp, cache_inode, 
+                              &open_file, &open_dentry);
        
+       if (cache_inode->i_fop->read)
+               rc = cache_inode->i_fop->read(&open_file, buf, size, ppos);
+
+       smfs_update_file(filp, &open_file);     
+       RETURN(rc);     
+}
+
+static int smfs_readdir(struct file * filp,
+                        void * dirent, 
+                       filldir_t filldir)
+{
+       struct dentry *dentry = filp->f_dentry;
+       struct inode *cache_inode = NULL;
+        struct  file open_file;
+       struct  dentry open_dentry;
+       int    rc = 0;
+       
+       cache_inode = I2CI(dentry->d_inode);
+
+       if (!cache_inode) 
+               RETURN(-EINVAL);
+
+       smfs_prepare_cachefile(dentry->d_inode, filp, cache_inode, 
+                              &open_file, &open_dentry);
+       
+       if (cache_inode->i_fop->readdir)
+               rc = cache_inode->i_fop->readdir(&open_file, dirent, filldir);
+       
+       smfs_update_file(filp, &open_file);     
+       RETURN(rc);     
+}
+
+struct file_operations smfs_dir_fops = {
+       read:           smfs_read_dir,  
+        readdir:        smfs_readdir,           /* BKL held */
+        ioctl:          smfs_ioctl,             /* BKL held */
+        fsync:          smfs_fsync,         /* BKL held */
 };