Whamcloud - gitweb
Update smfs: fix bugs of smfs_create
[fs/lustre-release.git] / lustre / smfs / dir.c
index 3835509..c5f0554 100644 (file)
 
 #include "smfs_internal.h" 
 
-static void d_unalloc(struct dentry *dentry)
+#define NAME_ALLOC_LEN(len)     ((len+16) & ~15)
+
+void smfs_clear_dentry(struct dentry *dentry)
 {
-        if (dentry) {                                                                                                                                                                                
-               list_del(&dentry->d_hash);
-               INIT_LIST_HEAD(&dentry->d_hash);
-               dput(dentry);   
+       struct qstr *name = NULL; 
+
+       if (dentry) {   
+               if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock))
+                       return;
+               list_del(&dentry->d_hash);
+                       INIT_LIST_HEAD(&dentry->d_hash);
+               list_del(&dentry->d_child);
+                if (dentry->d_inode) {
+                       dentry->d_inode = NULL;
+                       list_del_init(&dentry->d_alias);
+               }
+       
+               name = &(dentry->d_name);
+               if (name->len > DNAME_INLINE_LEN-1) {
+                       SM_FREE((char *)name->name, NAME_ALLOC_LEN(name->len));
+               }
        }
 }
-                                                                                                                                                                                                     
+
+int smfs_prepare_dentry(struct dentry *dentry, 
+                       struct dentry *parent,
+                       struct qstr *name)
+{
+       char *str = NULL;
+
+       if (name->len > DNAME_INLINE_LEN-1) {
+               SM_ALLOC(str, NAME_ALLOC_LEN(name->len));
+               if (!str) 
+                       return (-ENOMEM);
+       } else
+               str = dentry->d_iname; 
+
+       memcpy(str, name->name, name->len);
+       str[name->len] = 0;
+       
+       atomic_set(&dentry->d_count, 1);
+       dentry->d_vfs_flags = 0;
+       dentry->d_flags = 0;
+       dentry->d_inode = NULL;
+       dentry->d_parent = NULL;
+       dentry->d_sb = NULL;
+       dentry->d_name.name = str;
+       dentry->d_name.len = name->len;
+       dentry->d_name.hash = name->hash;
+       dentry->d_op = NULL;
+       dentry->d_fsdata = NULL;
+       dentry->d_mounted = 0;
+       INIT_LIST_HEAD(&dentry->d_hash);
+       INIT_LIST_HEAD(&dentry->d_lru);
+       INIT_LIST_HEAD(&dentry->d_subdirs);
+       INIT_LIST_HEAD(&dentry->d_alias);
+       
+       if (parent) {
+               dentry->d_parent = dget(parent);
+               dentry->d_sb = parent->d_sb;
+               list_add(&dentry->d_child, &parent->d_subdirs);
+       } else
+               INIT_LIST_HEAD(&dentry->d_child);
+
+       return 0;
+}                                                                                                                                                                                                     
 static void prepare_parent_dentry(struct dentry *dentry, struct inode *inode)
 {
         atomic_set(&dentry->d_count, 1);
@@ -41,9 +98,9 @@ static int smfs_create(struct inode *dir,
                       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;
        int     rc;
        
        ENTRY;
@@ -52,18 +109,15 @@ 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);
-       
-       if(cache_dir && cache_dir->i_op->create)
-               rc = cache_dir->i_op->create(cache_dir, cache_dentry, mode);
+       prepare_parent_dentry(&parent, cache_dir);      
+       smfs_prepare_dentry(&cache_dentry, &parent, &dentry->d_name);
+                
+       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;
+       cache_inode = cache_dentry.d_inode;
        
        inode = iget(dir->i_sb, cache_inode->i_ino);    
 
@@ -74,7 +128,7 @@ static int smfs_create(struct inode *dir,
        
        sm_set_inode_ops(cache_inode, inode);
 exit:
-       d_unalloc(cache_dentry);        
+       smfs_clear_dentry(&cache_dentry);       
        RETURN(rc);
 }
 
@@ -82,9 +136,9 @@ static struct dentry *smfs_lookup(struct inode *dir,
                                  struct dentry *dentry)
 {
        struct  inode *cache_dir; 
-       struct  inode *cache_inode, *inode;
+       struct  inode *cache_inode = NULL, *inode;
        struct  dentry tmp; 
-       struct  dentry *cache_dentry;
+       struct  dentry cache_dentry;
        struct  dentry *rc = NULL;
        
        ENTRY;
@@ -93,27 +147,24 @@ static struct dentry *smfs_lookup(struct inode *dir,
         if (!cache_dir)
                 RETURN(ERR_PTR(-ENOENT));
        prepare_parent_dentry(&tmp, cache_dir);      
-       cache_dentry = d_alloc(&tmp, &dentry->d_name);
+       smfs_prepare_dentry(&cache_dentry, &tmp, &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);
+               rc = cache_dir->i_op->lookup(cache_dir, &cache_dentry);
 
-       if (rc || !cache_dentry->d_inode || 
-            is_bad_inode(cache_dentry->d_inode) ||
-           IS_ERR(cache_dentry->d_inode)) {
+       if (rc || !cache_dentry.d_inode || 
+            is_bad_inode(cache_dentry.d_inode) ||
+           IS_ERR(cache_dentry.d_inode)) {
                GOTO(exit, rc); 
        }
 
-       cache_inode = cache_dentry->d_inode;
+       cache_inode = cache_dentry.d_inode;
        
        inode = iget(dir->i_sb, cache_inode->i_ino);    
                
        d_add(dentry, inode);   
 exit:
-       d_unalloc(cache_dentry);        
+       smfs_clear_dentry(&cache_dentry);       
        RETURN(rc);
 }                     
 
@@ -140,7 +191,8 @@ static int smfs_link(struct dentry * old_dentry,
        struct  inode *cache_old_inode = NULL; 
        struct  inode *cache_dir = I2CI(dir); 
        struct  inode *inode = NULL; 
-       struct  dentry *cache_dentry = NULL;
+       struct  dentry cache_dentry;
+       struct  dentry cache_old_dentry;
        struct  dentry tmp; 
        struct  dentry tmp_old; 
        int     rc = 0;
@@ -149,31 +201,34 @@ static int smfs_link(struct dentry * old_dentry,
        
        cache_old_inode = I2CI(inode);
        
-       if (!cache_old_inode || !dir) 
+       if (!cache_old_inode || !cache_dir) 
                 RETURN(-ENOENT);
-
-       prepare_parent_dentry(&tmp_old, cache_old_inode);
-
+       
        prepare_parent_dentry(&tmp, cache_dir);
-       cache_dentry = d_alloc(&tmp, &dentry->d_name); 
-       
+       smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name);
+       
+       prepare_parent_dentry(&tmp_old, cache_dir);
+       smfs_prepare_dentry(&cache_old_dentry, &tmp_old, &dentry->d_name);
+       d_add(&cache_old_dentry, cache_old_inode); 
+       
        if (cache_dir->i_op->link)
-               rc = cache_dir->i_op->link(&tmp, cache_dir, cache_dentry);              
+               rc = cache_dir->i_op->link(&cache_old_dentry, cache_dir, &cache_dentry);                
        
        if (rc == 0) {
                d_instantiate(dentry, inode);
        }       
        
-       d_unalloc(cache_dentry);
-       
+       smfs_clear_dentry(&cache_dentry);
+       smfs_clear_dentry(&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 = NULL;
+       struct dentry cache_dentry;
        struct dentry tmp; 
        int    rc = 0;
 
@@ -181,20 +236,19 @@ static int smfs_unlink(struct inode * dir,
                RETURN(-ENOENT);
        
        prepare_parent_dentry(&tmp, cache_dir);
-       cache_dentry = d_alloc(&tmp, &dentry->d_name); 
-       d_add(cache_dentry, cache_inode);
-       igrab(cache_inode);     
-       
+       smfs_prepare_dentry(&cache_dentry, &tmp, &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);
+               rc = cache_dir->i_op->unlink(cache_dir, &cache_dentry);
        
-
-       duplicate_inode(cache_dentry->d_inode, dentry->d_inode);
+       duplicate_inode(cache_dentry.d_inode, dentry->d_inode);
        duplicate_inode(cache_dir, dir);
        
-       d_unalloc(cache_dentry);        
+       smfs_clear_dentry(&cache_dentry);
        RETURN(rc);     
 }
+
 static int smfs_symlink (struct inode * dir,
                         struct dentry *dentry, 
                         const char * symname)
@@ -202,20 +256,20 @@ static int smfs_symlink (struct inode * dir,
        struct inode *cache_dir = I2CI(dir);
        struct inode *cache_inode = NULL;
        struct inode *inode = NULL;
-       struct dentry *cache_dentry = NULL
+       struct dentry cache_dentry
        struct dentry tmp; 
        int    rc = 0;
 
        if (!cache_dir) 
                RETURN(-ENOENT);
        
-       prepare_parent_dentry(&tmp, NULL);
-       cache_dentry = d_alloc(&tmp, &dentry->d_name); 
+       prepare_parent_dentry(&tmp, cache_dir);
+       smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name);
 
-       if (cache_inode->i_op->symlink)
-               rc = cache_dir->i_op->symlink(cache_dir, cache_dentry, symname);
+       if (cache_dir->i_op->symlink)
+               rc = cache_dir->i_op->symlink(cache_dir, &cache_dentry, symname);
        
-       cache_inode = cache_dentry->d_inode;
+       cache_inode = cache_dentry.d_inode;
        
        inode = iget(dir->i_sb, cache_inode->i_ino);
 
@@ -224,9 +278,10 @@ static int smfs_symlink (struct inode * dir,
        else
                rc = -ENOENT;
        
-       d_unalloc(cache_dentry);
+       smfs_clear_dentry(&cache_dentry);
        RETURN(rc);                     
 }
+
 static int smfs_mkdir(struct inode * dir, 
                      struct dentry * dentry, 
                      int mode)
@@ -234,20 +289,20 @@ static int smfs_mkdir(struct inode * dir,
        struct inode *cache_dir = I2CI(dir);
        struct inode *cache_inode = NULL;
        struct inode *inode = NULL;
-       struct dentry *cache_dentry = NULL;
+       struct dentry cache_dentry;
        struct dentry tmp;
        int    rc = 0;
 
        if (!cache_dir) 
                RETURN(-ENOENT);
        
-       prepare_parent_dentry(&tmp, NULL);
-       cache_dentry = d_alloc(&tmp, &dentry->d_name); 
+       prepare_parent_dentry(&tmp, cache_dir);
+       smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name);
        
        if (cache_dir->i_op->mkdir)
-               rc = cache_dir->i_op->mkdir(cache_dir, cache_dentry, mode);
+               rc = cache_dir->i_op->mkdir(cache_dir, &cache_dentry, mode);
 
-       cache_inode = cache_dentry->d_inode;
+       cache_inode = cache_dentry.d_inode;
 
        inode = iget(dir->i_sb, cache_inode->i_ino);
 
@@ -257,30 +312,33 @@ static int smfs_mkdir(struct inode * dir,
        d_instantiate(dentry, inode);   
        duplicate_inode(cache_dir, dir);
 exit:
-       d_unalloc(cache_dentry);
+       smfs_clear_dentry(&cache_dentry);
        RETURN(rc);             
 }
+
 static int  smfs_rmdir(struct inode * dir, 
                       struct dentry *dentry) 
 {
        struct inode *cache_dir = I2CI(dir);
-       struct dentry *cache_dentry = NULL;
+       struct inode *cache_inode = I2CI(dentry->d_inode);
+       struct dentry cache_dentry;
        struct dentry tmp;
        int    rc = 0;
 
        if (!cache_dir) 
                RETURN(-ENOENT);
        
-       prepare_parent_dentry(&tmp, NULL);
-       cache_dentry = d_alloc(&tmp, &dentry->d_name); 
+       prepare_parent_dentry(&tmp, cache_dir);
+       smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name);
+       d_add(&cache_dentry, cache_inode);
        
        if (cache_dir->i_op->rmdir)
-               rc = cache_dir->i_op->rmdir(cache_dir, cache_dentry);
+               rc = cache_dir->i_op->rmdir(cache_dir, &cache_dentry);
 
        duplicate_inode(cache_dir, dir);
-       duplicate_inode(cache_dentry->d_inode, dentry->d_inode);
+       duplicate_inode(cache_dentry.d_inode, dentry->d_inode);
 
-       d_unalloc(cache_dentry);
+       smfs_clear_dentry(&cache_dentry);
        RETURN(rc);             
 }
 
@@ -288,23 +346,29 @@ static int smfs_mknod(struct inode * dir, struct dentry *dentry,
                       int mode, int rdev)
 {
        struct inode *cache_dir = I2CI(dir);
-       struct dentry *cache_dentry = NULL;
+       struct inode *inode = NULL;
+       struct inode *cache_inode = NULL;
+       struct dentry cache_dentry;
        struct dentry tmp;
        int    rc = 0;
 
        if (!cache_dir) 
                RETURN(-ENOENT);
 
-       prepare_parent_dentry(&tmp, NULL);
-       cache_dentry = d_alloc(&tmp, &dentry->d_name); 
+       prepare_parent_dentry(&tmp, cache_dir);
+       smfs_prepare_dentry(&cache_dentry, &tmp, &dentry->d_name);
                
        if (cache_dir->i_op->mknod)
-               rc = cache_dir->i_op->mknod(cache_dir, dentry, mode, rdev);
-
-       duplicate_inode(cache_dir, dir);
-       duplicate_inode(cache_dentry->d_inode, dentry->d_inode);
-
-       d_unalloc(cache_dentry);
+               rc = cache_dir->i_op->mknod(cache_dir, &cache_dentry, mode, rdev);
+       
+       if (!rc) {
+               cache_inode = cache_dentry.d_inode;
+               inode = iget(dir->i_sb, cache_inode->i_ino);
+               d_instantiate(dentry, inode);
+               duplicate_inode(cache_dir, dir);
+               duplicate_inode(cache_dentry.d_inode, dentry->d_inode);
+       }
+       smfs_clear_dentry(&cache_dentry);
        RETURN(rc);             
 }
 static int smfs_rename(struct inode * old_dir, struct dentry *old_dentry,
@@ -315,8 +379,8 @@ static int smfs_rename(struct inode * old_dir, struct dentry *old_dentry,
        struct inode *cache_old_inode = I2CI(old_dentry->d_inode);
        struct inode *cache_new_inode = NULL;
        struct inode *new_inode = NULL;
-       struct dentry *cache_old_dentry = NULL;
-       struct dentry *cache_new_dentry = NULL;
+       struct dentry cache_old_dentry;
+       struct dentry cache_new_dentry;
        struct dentry tmp_new;
        struct dentry tmp_old;
        int    rc = 0;
@@ -324,27 +388,21 @@ static int smfs_rename(struct inode * old_dir, struct dentry *old_dentry,
        if (!cache_old_dir || !cache_new_dir || !cache_old_inode) 
                RETURN(-ENOENT);
        
-       prepare_parent_dentry(&tmp_old, old_dir);
-       cache_old_dentry = d_alloc(&tmp_old, &old_dentry->d_name); 
-       d_add(cache_old_dentry, cache_old_inode);
+       prepare_parent_dentry(&tmp_old, cache_old_dir);
+       smfs_prepare_dentry(&cache_old_dentry, &tmp_old, &old_dentry->d_name); 
+       d_add(&cache_old_dentry, cache_old_inode);
 
-       prepare_parent_dentry(&tmp_new, NULL);
-       cache_new_dentry = d_alloc(&tmp_new, &new_dentry->d_name); 
+       prepare_parent_dentry(&tmp_new, cache_new_dir);
+       smfs_prepare_dentry(&cache_new_dentry, &tmp_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);
-       
-       cache_new_inode = cache_new_dentry->d_inode; 
-       new_inode = iget(new_dir->i_sb, cache_new_inode->i_ino);
-       
-       d_instantiate(new_dentry, new_inode);
-               
+               rc = cache_old_dir->i_op->rename(cache_old_dir, &cache_old_dentry,
+                                                cache_new_dir, &cache_new_dentry);
+
        duplicate_inode(cache_old_dir, old_dir);
        duplicate_inode(cache_new_dir, new_dir);
-
-       d_unalloc(cache_old_dentry);
-       d_unalloc(cache_new_dentry);
+       smfs_clear_dentry(&cache_old_dentry);
+       smfs_clear_dentry(&cache_new_dentry);
 
        RETURN(rc);             
 }