Skip to content

Commit

Permalink
[CIFS] Add support for new POSIX unlink
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Steve French committed Jul 15, 2007
1 parent 50c2f75 commit 2d785a5
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 11 deletions.
4 changes: 3 additions & 1 deletion fs/cifs/CHANGES
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
Version 1.50
------------
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
------------
Expand Down
6 changes: 6 additions & 0 deletions fs/cifs/cifspdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -2155,6 +2155,12 @@ typedef struct {
/* struct following varies based on requested level */
} __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 {
__u64 UniqueId; /* inode number */
Expand Down
5 changes: 4 additions & 1 deletion fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,10 @@ extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
const char *name, const struct nls_table *nls_codepage,
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,
const char *name,
const struct nls_table *nls_codepage,
Expand Down
85 changes: 77 additions & 8 deletions fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,82 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
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
CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
const struct nls_table *nls_codepage, int remap)
Expand Down Expand Up @@ -933,7 +1009,6 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
int name_len;
int rc = 0;
int bytes_returned = 0;
char *data_offset;
__u16 params, param_offset, offset, byte_count, count;
OPEN_PSX_REQ * pdata;
OPEN_PSX_RSP * psx_rsp;
Expand Down Expand Up @@ -969,7 +1044,6 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
param_offset = offsetof(struct smb_com_transaction2_spi_req,
InformationLevel) - 4;
offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
pdata->Permissions = cpu_to_le64(mode);
Expand Down Expand Up @@ -1671,7 +1745,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
char *data_offset;
struct cifs_posix_lock *parm_data;
int rc = 0;
int timeout = 0;
Expand All @@ -1698,8 +1771,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
offset = param_offset + params;

data_offset = (char *) (&pSMB->hdr.Protocol) + offset;

count = sizeof(struct cifs_posix_lock);
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
Expand Down Expand Up @@ -2120,9 +2191,7 @@ CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_symlinks);
if (rc) {
cFYI(1,
("Send error in SetPathInfo (create symlink) = %d",
rc));
cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
}

if (pSMB)
Expand Down
14 changes: 13 additions & 1 deletion fs/cifs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,9 +620,21 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,

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,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
psx_del_no_retry:
if (!rc) {
if (direntry->d_inode)
drop_nlink(direntry->d_inode);
Expand Down

0 comments on commit 2d785a5

Please sign in to comment.