[CIFS] New CIFS POSIX mkdir performance improvement
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
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;
|
||||
|
Reference in New Issue
Block a user