forked from Minki/linux
[CIFS] New CIFS POSIX mkdir performance improvement
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
parent
5268df2ead
commit
2dd29d3133
@ -12,7 +12,10 @@ when archive dos attribute not set and we are changing mode back to writeable
|
||||
on server which does not support the Unix Extensions). Remove read only dos
|
||||
attribute on chmod when adding any write permission (ie on any of
|
||||
user/group/other (not all of user/group/other ie 0222) when
|
||||
mounted to windows.
|
||||
mounted to windows. Add support for POSIX MkDir (slight performance
|
||||
enhancement and eliminates the network race between the mkdir and set
|
||||
path info of the mode).
|
||||
|
||||
|
||||
Version 1.47
|
||||
------------
|
||||
|
@ -1388,7 +1388,7 @@ struct smb_t2_rsp {
|
||||
#define SMB_SET_POSIX_LOCK 0x208
|
||||
#define SMB_POSIX_OPEN 0x209
|
||||
#define SMB_POSIX_UNLINK 0x20a
|
||||
#define SMB_SET_FILE_UNIX_INFO2
|
||||
#define SMB_SET_FILE_UNIX_INFO2 0x20b
|
||||
#define SMB_SET_FILE_BASIC_INFO2 0x3ec
|
||||
#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */
|
||||
#define SMB_FILE_ALL_INFO2 0x3fa
|
||||
@ -2109,22 +2109,40 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
|
||||
|
||||
/* end of POSIX ACL definitions */
|
||||
|
||||
/* POSIX Open Flags */
|
||||
#define SMB_O_RDONLY 0x1
|
||||
#define SMB_O_WRONLY 0x2
|
||||
#define SMB_O_RDWR 0x4
|
||||
#define SMB_O_CREAT 0x10
|
||||
#define SMB_O_EXCL 0x20
|
||||
#define SMB_O_TRUNC 0x40
|
||||
#define SMB_O_APPEND 0x80
|
||||
#define SMB_O_SYNC 0x100
|
||||
#define SMB_O_DIRECTORY 0x200
|
||||
#define SMB_O_NOFOLLOW 0x400
|
||||
#define SMB_O_DIRECT 0x800
|
||||
|
||||
typedef struct {
|
||||
__u32 OpenFlags; /* same as NT CreateX */
|
||||
__u32 PosixOpenFlags;
|
||||
__u32 Mode;
|
||||
__u16 Level; /* reply level requested (see QPathInfo levels) */
|
||||
__u16 Pad; /* reserved - MBZ */
|
||||
__le32 OpenFlags; /* same as NT CreateX */
|
||||
__le32 PosixOpenFlags;
|
||||
__le64 Permissions;
|
||||
__le16 Level; /* reply level requested (see QPathInfo levels) */
|
||||
} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */
|
||||
|
||||
typedef struct {
|
||||
/* reply varies based on requested level */
|
||||
__le16 OplockFlags;
|
||||
__u16 Fid;
|
||||
__le32 CreateAction;
|
||||
__le16 ReturnedLevel;
|
||||
__le16 Pad;
|
||||
/* struct following varies based on requested level */
|
||||
} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
|
||||
|
||||
|
||||
struct file_internal_info {
|
||||
__u64 UniqueId; /* inode number */
|
||||
} __attribute__((packed)); /* level 0x3ee */
|
||||
|
||||
struct file_mode_info {
|
||||
__le32 Mode;
|
||||
} __attribute__((packed)); /* level 0x3f8 */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* fs/cifs/cifsproto.h
|
||||
*
|
||||
* Copyright (c) International Business Machines Corp., 2002,2006
|
||||
* Copyright (c) International Business Machines Corp., 2002,2007
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
@ -244,6 +244,11 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
|
||||
const int access_flags, const int omode,
|
||||
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
|
||||
const struct nls_table *nls_codepage, int remap);
|
||||
extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
|
||||
u32 posix_flags, __u64 mode, __u16 * netfid,
|
||||
FILE_UNIX_BASIC_INFO *pRetData,
|
||||
__u32 *pOplock, const char *name,
|
||||
const struct nls_table *nls_codepage, int remap);
|
||||
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
|
||||
const int smb_file_id);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* fs/cifs/cifssmb.c
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2006
|
||||
* Copyright (C) International Business Machines Corp., 2002,2007
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* Contains the routines for constructing the SMB PDUs themselves
|
||||
@ -24,8 +24,8 @@
|
||||
/* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
|
||||
/* These are mostly routines that operate on a pathname, or on a tree id */
|
||||
/* (mounted volume), but there are eight handle based routines which must be */
|
||||
/* treated slightly different for reconnection purposes since we never want */
|
||||
/* to reuse a stale file handle and the caller knows the file handle */
|
||||
/* treated slightly differently for reconnection purposes since we never */
|
||||
/* want to reuse a stale file handle and only the caller knows the file info */
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -913,6 +913,127 @@ MkDirRetry:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
|
||||
__u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
|
||||
__u32 *pOplock, const char *name,
|
||||
const struct nls_table *nls_codepage, int remap)
|
||||
{
|
||||
TRANSACTION2_SPI_REQ *pSMB = NULL;
|
||||
TRANSACTION2_SPI_RSP *pSMBr = NULL;
|
||||
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;
|
||||
|
||||
cFYI(1, ("In POSIX Create"));
|
||||
PsxCreat:
|
||||
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, name,
|
||||
PATH_MAX, nls_codepage, remap);
|
||||
name_len++; /* trailing null */
|
||||
name_len *= 2;
|
||||
} else { /* BB improve the check for buffer overruns BB */
|
||||
name_len = strnlen(name, PATH_MAX);
|
||||
name_len++; /* trailing null */
|
||||
strncpy(pSMB->FileName, name, name_len);
|
||||
}
|
||||
|
||||
params = 6 + name_len;
|
||||
count = sizeof(OPEN_PSX_REQ);
|
||||
pSMB->MaxParameterCount = cpu_to_le16(2);
|
||||
pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
|
||||
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;
|
||||
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);
|
||||
pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
|
||||
pdata->OpenFlags = cpu_to_le32(*pOplock);
|
||||
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 + count;
|
||||
|
||||
pSMB->DataCount = cpu_to_le16(count);
|
||||
pSMB->ParameterCount = cpu_to_le16(params);
|
||||
pSMB->TotalDataCount = pSMB->DataCount;
|
||||
pSMB->TotalParameterCount = pSMB->ParameterCount;
|
||||
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
|
||||
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 create returned %d", rc));
|
||||
goto psx_create_err;
|
||||
}
|
||||
|
||||
cFYI(1,("copying inode info"));
|
||||
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
||||
|
||||
if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
|
||||
rc = -EIO; /* bad smb */
|
||||
goto psx_create_err;
|
||||
}
|
||||
|
||||
/* copy return information to pRetData */
|
||||
psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
|
||||
+ le16_to_cpu(pSMBr->t2.DataOffset));
|
||||
|
||||
*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
|
||||
if(netfid)
|
||||
*netfid = psx_rsp->Fid; /* cifs fid stays in le */
|
||||
/* Let caller know file was created so we can set the mode. */
|
||||
/* Do we care about the CreateAction in any other cases? */
|
||||
if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
|
||||
*pOplock |= CIFS_CREATE_ACTION;
|
||||
/* check to make sure response data is there */
|
||||
if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC)
|
||||
pRetData->Type = -1; /* unknown */
|
||||
else {
|
||||
if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
|
||||
+ sizeof(FILE_UNIX_BASIC_INFO)) {
|
||||
cERROR(1,("Open response data too small"));
|
||||
pRetData->Type = -1;
|
||||
goto psx_create_err;
|
||||
}
|
||||
memcpy((char *) pRetData,
|
||||
(char *)&psx_rsp + sizeof(OPEN_PSX_RSP),
|
||||
sizeof (FILE_UNIX_BASIC_INFO));
|
||||
}
|
||||
|
||||
|
||||
psx_create_err:
|
||||
cifs_buf_release(pSMB);
|
||||
|
||||
cifs_stats_inc(&tcon->num_mkdirs);
|
||||
|
||||
if (rc == -EAGAIN)
|
||||
goto PsxCreat;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static __u16 convert_disposition(int disposition)
|
||||
{
|
||||
__u16 ofun = 0;
|
||||
|
184
fs/cifs/inode.c
184
fs/cifs/inode.c
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* fs/cifs/inode.c
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2005
|
||||
* Copyright (C) International Business Machines Corp., 2002,2007
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
@ -734,6 +734,133 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void posix_fill_in_inode(struct inode *tmp_inode,
|
||||
FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
|
||||
{
|
||||
loff_t local_size;
|
||||
struct timespec local_mtime;
|
||||
|
||||
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
|
||||
|
||||
__u32 type = le32_to_cpu(pData->Type);
|
||||
__u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
|
||||
__u64 end_of_file = le64_to_cpu(pData->EndOfFile);
|
||||
cifsInfo->time = jiffies;
|
||||
atomic_inc(&cifsInfo->inUse);
|
||||
|
||||
/* save mtime and size */
|
||||
local_mtime = tmp_inode->i_mtime;
|
||||
local_size = tmp_inode->i_size;
|
||||
|
||||
tmp_inode->i_atime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
|
||||
tmp_inode->i_mtime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
|
||||
tmp_inode->i_ctime =
|
||||
cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));
|
||||
|
||||
tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
|
||||
/* since we set the inode type below we need to mask off type
|
||||
to avoid strange results if bits above were corrupt */
|
||||
tmp_inode->i_mode &= ~S_IFMT;
|
||||
if (type == UNIX_FILE) {
|
||||
*pobject_type = DT_REG;
|
||||
tmp_inode->i_mode |= S_IFREG;
|
||||
} else if (type == UNIX_SYMLINK) {
|
||||
*pobject_type = DT_LNK;
|
||||
tmp_inode->i_mode |= S_IFLNK;
|
||||
} else if (type == UNIX_DIR) {
|
||||
*pobject_type = DT_DIR;
|
||||
tmp_inode->i_mode |= S_IFDIR;
|
||||
} else if (type == UNIX_CHARDEV) {
|
||||
*pobject_type = DT_CHR;
|
||||
tmp_inode->i_mode |= S_IFCHR;
|
||||
tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
|
||||
le64_to_cpu(pData->DevMinor) & MINORMASK);
|
||||
} else if (type == UNIX_BLOCKDEV) {
|
||||
*pobject_type = DT_BLK;
|
||||
tmp_inode->i_mode |= S_IFBLK;
|
||||
tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
|
||||
le64_to_cpu(pData->DevMinor) & MINORMASK);
|
||||
} else if (type == UNIX_FIFO) {
|
||||
*pobject_type = DT_FIFO;
|
||||
tmp_inode->i_mode |= S_IFIFO;
|
||||
} else if (type == UNIX_SOCKET) {
|
||||
*pobject_type = DT_SOCK;
|
||||
tmp_inode->i_mode |= S_IFSOCK;
|
||||
} else {
|
||||
/* safest to just call it a file */
|
||||
*pobject_type = DT_REG;
|
||||
tmp_inode->i_mode |= S_IFREG;
|
||||
cFYI(1,("unknown inode type %d",type));
|
||||
}
|
||||
|
||||
tmp_inode->i_uid = le64_to_cpu(pData->Uid);
|
||||
tmp_inode->i_gid = le64_to_cpu(pData->Gid);
|
||||
tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);
|
||||
|
||||
spin_lock(&tmp_inode->i_lock);
|
||||
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
|
||||
/* can not safely change the file size here if the
|
||||
client is writing to it due to potential races */
|
||||
i_size_write(tmp_inode, end_of_file);
|
||||
|
||||
/* 512 bytes (2**9) is the fake blocksize that must be used */
|
||||
/* for this calculation, not the real blocksize */
|
||||
tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
|
||||
}
|
||||
spin_unlock(&tmp_inode->i_lock);
|
||||
|
||||
if (S_ISREG(tmp_inode->i_mode)) {
|
||||
cFYI(1, ("File inode"));
|
||||
tmp_inode->i_op = &cifs_file_inode_ops;
|
||||
|
||||
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
|
||||
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
||||
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
|
||||
else
|
||||
tmp_inode->i_fop = &cifs_file_direct_ops;
|
||||
|
||||
} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
|
||||
tmp_inode->i_fop = &cifs_file_nobrl_ops;
|
||||
else
|
||||
tmp_inode->i_fop = &cifs_file_ops;
|
||||
|
||||
if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
|
||||
(cifs_sb->tcon->ses->server->maxBuf <
|
||||
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
|
||||
else
|
||||
tmp_inode->i_data.a_ops = &cifs_addr_ops;
|
||||
|
||||
if(isNewInode)
|
||||
return; /* No sense invalidating pages for new inode since we
|
||||
have not started caching readahead file data yet */
|
||||
|
||||
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
|
||||
(local_size == tmp_inode->i_size)) {
|
||||
cFYI(1, ("inode exists but unchanged"));
|
||||
} else {
|
||||
/* file may have changed on server */
|
||||
cFYI(1, ("invalidate inode, readdir detected change"));
|
||||
invalidate_remote_inode(tmp_inode);
|
||||
}
|
||||
} else if (S_ISDIR(tmp_inode->i_mode)) {
|
||||
cFYI(1, ("Directory inode"));
|
||||
tmp_inode->i_op = &cifs_dir_inode_ops;
|
||||
tmp_inode->i_fop = &cifs_dir_ops;
|
||||
} else if (S_ISLNK(tmp_inode->i_mode)) {
|
||||
cFYI(1, ("Symbolic Link inode"));
|
||||
tmp_inode->i_op = &cifs_symlink_inode_ops;
|
||||
/* tmp_inode->i_fop = *//* do not need to set to anything */
|
||||
} else {
|
||||
cFYI(1, ("Special inode"));
|
||||
init_special_inode(tmp_inode, tmp_inode->i_mode,
|
||||
tmp_inode->i_rdev);
|
||||
}
|
||||
}
|
||||
|
||||
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -755,6 +882,53 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
FreeXid(xid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if((pTcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||
le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
|
||||
u32 oplock = 0;
|
||||
FILE_UNIX_BASIC_INFO * pInfo =
|
||||
kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
|
||||
if(pInfo == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto mkdir_out;
|
||||
}
|
||||
|
||||
rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
|
||||
mode, NULL /* netfid */, pInfo, &oplock,
|
||||
full_path, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc) {
|
||||
cFYI(1, ("posix mkdir returned 0x%x", rc));
|
||||
d_drop(direntry);
|
||||
} else {
|
||||
if (pInfo->Type == -1) /* no return info - go query */
|
||||
goto mkdir_get_info;
|
||||
/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
|
||||
inc_nlink(inode);
|
||||
if (pTcon->nocase)
|
||||
direntry->d_op = &cifs_ci_dentry_ops;
|
||||
else
|
||||
direntry->d_op = &cifs_dentry_ops;
|
||||
d_instantiate(direntry, newinode);
|
||||
if (direntry->d_inode) {
|
||||
int obj_type;
|
||||
direntry->d_inode->i_nlink = 2;
|
||||
/* already checked in POSIXCreate whether
|
||||
frame was long enough */
|
||||
posix_fill_in_inode(direntry->d_inode,
|
||||
pInfo, &obj_type, 1 /* NewInode */);
|
||||
/* could double check that we actually
|
||||
* created what we thought we did ie
|
||||
* a directory
|
||||
*/
|
||||
}
|
||||
}
|
||||
kfree(pInfo);
|
||||
goto mkdir_out;
|
||||
}
|
||||
|
||||
/* BB add setting the equivalent of mode via CreateX w/ACLs */
|
||||
rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
@ -762,6 +936,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
cFYI(1, ("cifs_mkdir returned 0x%x", rc));
|
||||
d_drop(direntry);
|
||||
} else {
|
||||
mkdir_get_info:
|
||||
inc_nlink(inode);
|
||||
if (pTcon->ses->capabilities & CAP_UNIX)
|
||||
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
||||
@ -775,8 +950,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
else
|
||||
direntry->d_op = &cifs_dentry_ops;
|
||||
d_instantiate(direntry, newinode);
|
||||
if (direntry->d_inode)
|
||||
direntry->d_inode->i_nlink = 2;
|
||||
/* setting nlink not necessary except in cases where we
|
||||
* failed to get it from the server or was set bogus */
|
||||
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
|
||||
direntry->d_inode->i_nlink = 2;
|
||||
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
|
||||
@ -812,6 +989,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
mkdir_out:
|
||||
kfree(full_path);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
|
Loading…
Reference in New Issue
Block a user