int cifs_unlink(struct inode *inode, struct dentry *direntry) { int rc = 0; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct cifsInodeInfo *cifsInode; FILE_BASIC_INFO * pinfo_buf; cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); xid = GetXid(); 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) { direntry->d_inode->i_nlink--; } else if (rc == -ENOENT) { d_drop(direntry); } else if (rc == -ETXTBSY) { int oplock = FALSE; __u16 netfid; rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, &netfid, &oplock, NULL, cifs_sb->local_nls); if(rc==0) { CIFSSMBRenameOpenFile(xid,pTcon,netfid, NULL, cifs_sb->local_nls); CIFSSMBClose(xid, pTcon, netfid); direntry->d_inode->i_nlink--; } } else if (rc == -EACCES) { /* try only if r/o attribute set in local lookup data? */ pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL); if(pinfo_buf) { memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO)); /* ATTRS set to normal clears r/o bit */ pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf, cifs_sb->local_nls); kfree(pinfo_buf); } if(rc==0) { rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); if (!rc) { direntry->d_inode->i_nlink--; } else if (rc == -ETXTBSY) { int oplock = FALSE; __u16 netfid; rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, &netfid, &oplock, NULL, cifs_sb->local_nls); if(rc==0) { CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls); CIFSSMBClose(xid, pTcon, netfid); direntry->d_inode->i_nlink--; } /* BB if rc = -ETXTBUSY goto the rename logic BB */ } } } cifsInode = CIFS_I(direntry->d_inode); cifsInode->time = 0; /* will force revalidate to get info when needed */ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; cifsInode = CIFS_I(inode); cifsInode->time = 0; /* force revalidate of dir as well */ if (full_path) kfree(full_path); FreeXid(xid); return rc; }
int cifs_unlink(struct inode *inode, struct dentry *direntry) { int rc = 0; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct cifsInodeInfo *cifsInode; FILE_BASIC_INFO *pinfo_buf; cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); xid = GetXid(); 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, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { if (direntry->d_inode) direntry->d_inode->i_nlink--; } else if (rc == -ENOENT) { d_drop(direntry); } else if (rc == -ETXTBSY) { int oplock = FALSE; __u16 netfid; rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); if (direntry->d_inode) direntry->d_inode->i_nlink--; } } else if (rc == -EACCES) { /* try only if r/o attribute set in local lookup data? */ pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL); if (pinfo_buf) { memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO)); /* ATTRS set to normal clears r/o bit */ pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); if (!(pTcon->ses->flags & CIFS_SES_NT4)) rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else rc = -EOPNOTSUPP; if (rc == -EOPNOTSUPP) { int oplock = FALSE; __u16 netfid; /* rc = CIFSSMBSetAttrLegacy(xid, pTcon, full_path, (__u16)ATTR_NORMAL, cifs_sb->local_nls); For some strange reason it seems that NT4 eats the old setattr call without actually setting the attributes so on to the third attempted workaround */ /* BB could scan to see if we already have it open and pass in pid of opener to function */ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, 0, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { rc = CIFSSMBSetFileTimes(xid, pTcon, pinfo_buf, netfid); CIFSSMBClose(xid, pTcon, netfid); } } kfree(pinfo_buf); } if (rc==0) { rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { if (direntry->d_inode) direntry->d_inode->i_nlink--; } else if (rc == -ETXTBSY) { int oplock = FALSE; __u16 netfid; rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc==0) { CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); if (direntry->d_inode) direntry->d_inode->i_nlink--; } /* BB if rc = -ETXTBUSY goto the rename logic BB */ } } } if (direntry->d_inode) { cifsInode = CIFS_I(direntry->d_inode); cifsInode->time = 0; /* will force revalidate to get info when needed */ direntry->d_inode->i_ctime = current_fs_time(inode->i_sb); } inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); cifsInode = CIFS_I(inode); cifsInode->time = 0; /* force revalidate of dir as well */ kfree(full_path); FreeXid(xid); return rc; }