This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / fs / cifs / inode.c
index e48ed8c..e3c47ee 100644 (file)
@@ -345,8 +345,15 @@ cifs_unlink(struct inode *inode, struct dentry *direntry)
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
 
+/* Unlink can be called from rename so we can not grab
+       the sem here since we deadlock otherwise */
+/*     down(&direntry->d_sb->s_vfs_rename_sem);*/
        full_path = build_path_from_dentry(direntry);
-
+/*     up(&direntry->d_sb->s_vfs_rename_sem);*/
+       if(full_path == NULL) {
+               FreeXid(xid);
+               return -ENOMEM;
+       }
        rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
 
        if (!rc) {
@@ -427,7 +434,13 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
 
+       down(&inode->i_sb->s_vfs_rename_sem);
        full_path = build_path_from_dentry(direntry);
+       up(&inode->i_sb->s_vfs_rename_sem);
+       if(full_path == NULL) {
+               FreeXid(xid);
+               return -ENOMEM;
+       }
        /* BB add setting the equivalent of mode via CreateX w/ACLs */
        rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
        if (rc) {
@@ -480,7 +493,13 @@ cifs_rmdir(struct inode *inode, struct dentry *direntry)
        cifs_sb = CIFS_SB(inode->i_sb);
        pTcon = cifs_sb->tcon;
 
+       down(&inode->i_sb->s_vfs_rename_sem);
        full_path = build_path_from_dentry(direntry);
+       up(&inode->i_sb->s_vfs_rename_sem);
+       if(full_path == NULL) {
+               FreeXid(xid);
+               return -ENOMEM;
+       }
 
        rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
 
@@ -525,8 +544,14 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
                      different share. Might eventually add support for this */
        }
 
+       /* we already  have the rename sem so we do not need
+       to grab it again here to protect the path integrity */
        fromName = build_path_from_dentry(source_direntry);
        toName = build_path_from_dentry(target_direntry);
+       if((fromName == NULL) || (toName == NULL)) {
+               rc = -ENOMEM;
+               goto cifs_rename_exit;
+       }
 
        rc = CIFSSMBRename(xid, pTcon, fromName, toName,
                           cifs_sb_source->local_nls);
@@ -549,6 +574,8 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
                        CIFSSMBClose(xid, pTcon, netfid);
                }
        }
+
+cifs_rename_exit:
        if (fromName)
                kfree(fromName);
        if (toName)
@@ -586,7 +613,13 @@ cifs_revalidate(struct dentry *direntry)
 
        cifs_sb = CIFS_SB(direntry->d_sb);
 
+       /* can not safely grab the rename sem here if
+       rename calls revalidate since that would deadlock */
        full_path = build_path_from_dentry(direntry);
+       if(full_path == NULL) {
+               FreeXid(xid);
+               return -ENOMEM;
+       }
        cFYI(1,
             ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
              full_path, direntry->d_inode,
@@ -647,9 +680,12 @@ cifs_revalidate(struct dentry *direntry)
                }
        }
 
-
+       /* can not grab this sem since kernel filesys locking
+               documentation indicates i_sem may be taken by the kernel 
+               on lookup and rename which could deadlock if we grab
+               the i_sem here as well */
+/*     down(&direntry->d_inode->i_sem);*/
        /* need to write out dirty pages here  */
-       down(&direntry->d_inode->i_sem);
        if(direntry->d_inode->i_mapping) {
                /* do we need to lock inode until after invalidate completes below? */
                filemap_fdatawrite(direntry->d_inode->i_mapping);
@@ -663,9 +699,7 @@ cifs_revalidate(struct dentry *direntry)
                        invalidate_remote_inode(direntry->d_inode);
                }
        }
-
-
-       up(&direntry->d_inode->i_sem);
+/*     up(&direntry->d_inode->i_sem);*/
        
        if (full_path)
                kfree(full_path);
@@ -729,7 +763,13 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
        cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
        pTcon = cifs_sb->tcon;
 
+       down(&direntry->d_sb->s_vfs_rename_sem);
        full_path = build_path_from_dentry(direntry);
+       up(&direntry->d_sb->s_vfs_rename_sem);
+       if(full_path == NULL) {
+               FreeXid(xid);
+               return -ENOMEM;
+       }
        cifsInode = CIFS_I(direntry->d_inode);
 
        /* BB check if we need to refresh inode from server now ? BB */