[CIFS] Add support for new POSIX unlink

In the cleanup phase of the dbench test, we were noticing sharing
violation followed by failed directory removals when dbench
did not close the test files before the cleanup phase started.
Using the new POSIX unlink, which Samba has supported for a few
months, avoids this.

Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Steve French 2007-07-15 01:48:57 +00:00
parent 50c2f75388
commit 2d785a50a8
5 changed files with 103 additions and 11 deletions

View file

@ -1,7 +1,9 @@
Version 1.50 Version 1.50
------------ ------------
Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is
done with "serverino" mount option). done with "serverino" mount option). Add support for POSIX Unlink
(helps with certain sharing violation cases when server such as
Samba supports newer POSIX CIFS Protocol Extensions).
Version 1.49 Version 1.49
------------ ------------

View file

@ -2155,6 +2155,12 @@ typedef struct {
/* struct following varies based on requested level */ /* struct following varies based on requested level */
} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */ } __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
#define SMB_POSIX_UNLINK_FILE_TARGET 0
#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
struct unlink_psx_rq { /* level 0x20a SetPathInfo */
__le16 type;
} __attribute__((packed));
struct file_internal_info { struct file_internal_info {
__u64 UniqueId; /* inode number */ __u64 UniqueId; /* inode number */

View file

@ -196,7 +196,10 @@ extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
const char *name, const struct nls_table *nls_codepage, const char *name, const struct nls_table *nls_codepage,
int remap_special_chars); int remap_special_chars);
extern int CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon,
const char *name, __u16 type,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
const char *name, const char *name,
const struct nls_table *nls_codepage, const struct nls_table *nls_codepage,

View file

@ -788,6 +788,82 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
return rc; return rc;
} }
int
CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
__u16 type, const struct nls_table *nls_codepage, int remap)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
TRANSACTION2_SPI_RSP *pSMBr = NULL;
struct unlink_psx_rq *pRqD;
int name_len;
int rc = 0;
int bytes_returned = 0;
__u16 params, param_offset, offset, byte_count;
cFYI(1, ("In POSIX delete"));
PsxDelete:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB add path length overrun check */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, fileName, name_len);
}
params = 6 + name_len;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = 0; /* BB double check this with jra */
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
InformationLevel) - 4;
offset = param_offset + params;
/* Setup pointer to Request Data (inode type) */
pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
pRqD->type = cpu_to_le16(type);
pSMB->ParameterOffset = cpu_to_le16(param_offset);
pSMB->DataOffset = cpu_to_le16(offset);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cFYI(1, ("Posix delete returned %d", rc));
}
cifs_buf_release(pSMB);
cifs_stats_inc(&tcon->num_deletes);
if (rc == -EAGAIN)
goto PsxDelete;
return rc;
}
int int
CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName, CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
const struct nls_table *nls_codepage, int remap) const struct nls_table *nls_codepage, int remap)
@ -933,7 +1009,6 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
int name_len; int name_len;
int rc = 0; int rc = 0;
int bytes_returned = 0; int bytes_returned = 0;
char *data_offset;
__u16 params, param_offset, offset, byte_count, count; __u16 params, param_offset, offset, byte_count, count;
OPEN_PSX_REQ * pdata; OPEN_PSX_REQ * pdata;
OPEN_PSX_RSP * psx_rsp; OPEN_PSX_RSP * psx_rsp;
@ -969,7 +1044,6 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
param_offset = offsetof(struct smb_com_transaction2_spi_req, param_offset = offsetof(struct smb_com_transaction2_spi_req,
InformationLevel) - 4; InformationLevel) - 4;
offset = param_offset + params; offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset); pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
pdata->Level = SMB_QUERY_FILE_UNIX_BASIC; pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
pdata->Permissions = cpu_to_le64(mode); pdata->Permissions = cpu_to_le64(mode);
@ -1671,7 +1745,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
{ {
struct smb_com_transaction2_sfi_req *pSMB = NULL; struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
char *data_offset;
struct cifs_posix_lock *parm_data; struct cifs_posix_lock *parm_data;
int rc = 0; int rc = 0;
int timeout = 0; int timeout = 0;
@ -1698,8 +1771,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
offset = param_offset + params; offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
count = sizeof(struct cifs_posix_lock); count = sizeof(struct cifs_posix_lock);
pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
@ -2120,9 +2191,7 @@ CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_symlinks); cifs_stats_inc(&tcon->num_symlinks);
if (rc) { if (rc) {
cFYI(1, cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
("Send error in SetPathInfo (create symlink) = %d",
rc));
} }
if (pSMB) if (pSMB)

View file

@ -620,9 +620,21 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
if ((pTcon->ses->capabilities & CAP_UNIX) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, ("posix del rc %d", rc));
if ((rc == 0) || (rc == -ENOENT))
goto psx_del_no_retry;
}
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls, rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
psx_del_no_retry:
if (!rc) { if (!rc) {
if (direntry->d_inode) if (direntry->d_inode)
drop_nlink(direntry->d_inode); drop_nlink(direntry->d_inode);