@@ -91,6 +91,8 @@ extern u64 cifs_UnixTimeToNT(struct timespec);
extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
+extern void posix_fill_in_inode(struct inode *tmp_inode,
+ FILE_UNIX_BASIC_INFO *pData, int isNewInode);
extern struct inode *cifs_new_inode(struct super_block *sb, unsigned long inum);
extern int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path,
@@ -152,11 +152,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
int oplock = 0;
/* BB below access is too much for the mknod to request */
int desiredAccess = GENERIC_READ | GENERIC_WRITE;
+ __u32 posix_flags = SMB_O_CREAT | SMB_O_RDWR | SMB_O_TRUNC;
__u16 fileHandle;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *tcon;
char *full_path = NULL;
FILE_ALL_INFO *buf = NULL;
+ FILE_UNIX_BASIC_INFO *pinfo = NULL;
struct inode *newinode = NULL;
struct cifsInodeInfo *pCifsInode;
int disposition = FILE_OVERWRITE_IF;
@@ -169,32 +171,45 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
- FreeXid(xid);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto cifs_create_out;
}
mode &= ~current->fs->umask;
+ /* convert lookup intent to flags for create */
if (nd && (nd->flags & LOOKUP_OPEN)) {
int oflags = nd->intent.open.flags;
- desiredAccess = 0;
- if (oflags & FMODE_READ)
- desiredAccess |= GENERIC_READ;
- if (oflags & FMODE_WRITE) {
- desiredAccess |= GENERIC_WRITE;
- if (!(oflags & FMODE_READ))
- write_only = true;
+ if (oflags & (FMODE_READ | FMODE_WRITE)) {
+ desiredAccess = (GENERIC_READ | GENERIC_WRITE);
+ posix_flags = SMB_O_CREAT | SMB_O_RDWR;
+ } else if (oflags & FMODE_READ) {
+ desiredAccess = GENERIC_READ;
+ posix_flags = SMB_O_CREAT | SMB_O_RDONLY;
+ } else if (oflags & FMODE_WRITE) {
+ desiredAccess = GENERIC_WRITE;
+ posix_flags = SMB_O_CREAT | SMB_O_WRONLY;
+ write_only = true;
}
- if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
disposition = FILE_CREATE;
- else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
+ posix_flags |= SMB_O_EXCL;
+ } else if ((oflags & (O_CREAT | O_TRUNC)) ==
+ (O_CREAT | O_TRUNC)) {
disposition = FILE_OVERWRITE_IF;
- else if ((oflags & O_CREAT) == O_CREAT)
+ posix_flags |= SMB_O_TRUNC;
+ } else if ((oflags & O_CREAT) == O_CREAT)
disposition = FILE_OPEN_IF;
else
cFYI(1, ("Create flag not set in create function"));
+
+ if (oflags & O_APPEND)
+ posix_flags |= SMB_O_APPEND;
+ if (oflags & O_SYNC)
+ posix_flags |= SMB_O_SYNC;
+ /* BB: SMB_O_DIRECT ? */
}
/* BB add processing to set equivalent of mode - e.g. via CreateX with
@@ -202,11 +217,39 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if (oplockEnabled)
oplock = REQ_OPLOCK;
+ /* try POSIX create first */
+ if (tcon->unix_ext) {
+ pinfo = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+ if (pinfo == NULL) {
+ rc = -ENOMEM;
+ goto cifs_create_out;
+ }
+ rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, &fileHandle,
+ pinfo, &oplock, full_path,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (!rc) {
+ /* check for valid pinfo */
+ if (pinfo->Type == cpu_to_le32(-1))
+ goto cifs_create_reval;
+ newinode = cifs_new_inode(inode->i_sb, (unsigned long)
+ pinfo->UniqueId);
+ if (!newinode) {
+ rc = -ENOMEM;
+ goto cifs_create_out;
+ }
+
+ posix_fill_in_inode(newinode, pinfo, 1);
+ goto cifs_create_set_dentry;
+ } else if (rc != -EOPNOTSUPP)
+ goto cifs_create_out;
+ }
+
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (buf == NULL) {
- kfree(full_path);
- FreeXid(xid);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto cifs_create_out;
}
/*
@@ -231,123 +274,123 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
&fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
}
- if (rc) {
- cFYI(1, ("cifs_create returned 0x%x", rc));
+
+ if (rc)
+ goto cifs_create_out;
+
+ /*
+ * If old-style Open reported that we actually created a file
+ * then we now have to set the mode if possible
+ */
+ if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
+ struct cifs_unix_set_info_args args = {
+ .mode = mode,
+ .ctime = NO_CHANGE_64,
+ .atime = NO_CHANGE_64,
+ .mtime = NO_CHANGE_64,
+ .device = 0,
+ };
+
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ args.uid = (__u64) current_fsuid();
+ if (inode->i_mode & S_ISGID)
+ args.gid = (__u64) inode->i_gid;
+ else
+ args.gid = (__u64) current_fsgid();
+ } else {
+ args.uid = NO_CHANGE_64;
+ args.gid = NO_CHANGE_64;
+ }
+ CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
- /* If Open reported that we actually created a file
- then we now have to set the mode if possible */
- if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
- struct cifs_unix_set_info_args args = {
- .mode = mode,
- .ctime = NO_CHANGE_64,
- .atime = NO_CHANGE_64,
- .mtime = NO_CHANGE_64,
- .device = 0,
- };
-
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
- args.uid = (__u64) current_fsuid();
+ /* BB implement mode setting via Windows security
+ descriptors e.g. */
+ /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
+
+ /* Could set r/o dos attribute if mode & 0222 == 0 */
+ }
+
+ /* server might mask mode so we have to query for it */
+cifs_create_reval:
+ if (tcon->unix_ext)
+ rc = cifs_get_inode_info_unix(&newinode, full_path,
+ inode->i_sb, xid);
+ else {
+ rc = cifs_get_inode_info(&newinode, full_path,
+ buf, inode->i_sb, xid,
+ &fileHandle);
+ if (newinode) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ newinode->i_mode = mode;
+ if ((oplock & CIFS_CREATE_ACTION) &&
+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
+ newinode->i_uid = current_fsuid();
if (inode->i_mode & S_ISGID)
- args.gid = (__u64) inode->i_gid;
+ newinode->i_gid = inode->i_gid;
else
- args.gid = (__u64) current_fsgid();
- } else {
- args.uid = NO_CHANGE_64;
- args.gid = NO_CHANGE_64;
+ newinode->i_gid = current_fsgid();
}
- CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- } else {
- /* BB implement mode setting via Windows security
- descriptors e.g. */
- /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
-
- /* Could set r/o dos attribute if mode & 0222 == 0 */
}
+ }
- /* server might mask mode so we have to query for it */
- if (tcon->unix_ext)
- rc = cifs_get_inode_info_unix(&newinode, full_path,
- inode->i_sb, xid);
- else {
- rc = cifs_get_inode_info(&newinode, full_path,
- buf, inode->i_sb, xid,
- &fileHandle);
- if (newinode) {
- if (cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_DYNPERM)
- newinode->i_mode = mode;
- if ((oplock & CIFS_CREATE_ACTION) &&
- (cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_SET_UID)) {
- newinode->i_uid = current_fsuid();
- if (inode->i_mode & S_ISGID)
- newinode->i_gid =
- inode->i_gid;
- else
- newinode->i_gid =
- current_fsgid();
- }
- }
- }
+cifs_create_set_dentry:
+ if (rc != 0) {
+ cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
+ } else {
+ setup_cifs_dentry(tcon, direntry, newinode);
+ }
- if (rc != 0) {
- cFYI(1, ("Create worked, get_inode_info failed rc = %d",
- rc));
- } else
- setup_cifs_dentry(tcon, direntry, newinode);
-
- if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
- (!(nd->flags & LOOKUP_OPEN))) {
- /* mknod case - do not leave file open */
- CIFSSMBClose(xid, tcon, fileHandle);
- } else if (newinode) {
- struct cifsFileInfo *pCifsFile =
- kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
-
- if (pCifsFile == NULL)
- goto cifs_create_out;
- pCifsFile->netfid = fileHandle;
- pCifsFile->pid = current->tgid;
- pCifsFile->pInode = newinode;
- pCifsFile->invalidHandle = false;
- pCifsFile->closePend = false;
- init_MUTEX(&pCifsFile->fh_sem);
- mutex_init(&pCifsFile->lock_mutex);
- INIT_LIST_HEAD(&pCifsFile->llist);
- atomic_set(&pCifsFile->wrtPending, 0);
-
- /* set the following in open now
- pCifsFile->pfile = file; */
- write_lock(&GlobalSMBSeslock);
- list_add(&pCifsFile->tlist, &tcon->openFileList);
- pCifsInode = CIFS_I(newinode);
- if (pCifsInode) {
- /* if readable file instance put first in list*/
- if (write_only) {
- list_add_tail(&pCifsFile->flist,
- &pCifsInode->openFileList);
- } else {
- list_add(&pCifsFile->flist,
- &pCifsInode->openFileList);
- }
- if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
- pCifsInode->clientCanCacheAll = true;
- pCifsInode->clientCanCacheRead = true;
- cFYI(1, ("Exclusive Oplock inode %p",
- newinode));
- } else if ((oplock & 0xF) == OPLOCK_READ)
- pCifsInode->clientCanCacheRead = true;
- }
- write_unlock(&GlobalSMBSeslock);
+ /* if nd is NULL nfsd case - nfs srv does not set nd */
+ if (nd == NULL || (!(nd->flags & LOOKUP_OPEN))) {
+ /* mknod case - do not leave file open */
+ CIFSSMBClose(xid, tcon, fileHandle);
+ } else if (newinode) {
+ struct cifsFileInfo *pCifsFile =
+ kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+
+ if (pCifsFile == NULL)
+ goto cifs_create_out;
+ pCifsFile->netfid = fileHandle;
+ pCifsFile->pid = current->tgid;
+ pCifsFile->pInode = newinode;
+ pCifsFile->invalidHandle = false;
+ pCifsFile->closePend = false;
+ init_MUTEX(&pCifsFile->fh_sem);
+ mutex_init(&pCifsFile->lock_mutex);
+ INIT_LIST_HEAD(&pCifsFile->llist);
+ atomic_set(&pCifsFile->wrtPending, 0);
+
+ write_lock(&GlobalSMBSeslock);
+ list_add(&pCifsFile->tlist, &tcon->openFileList);
+ pCifsInode = CIFS_I(newinode);
+ if (pCifsInode) {
+ /* if readable file instance put first in list*/
+ if (write_only)
+ list_add_tail(&pCifsFile->flist,
+ &pCifsInode->openFileList);
+ else
+ list_add(&pCifsFile->flist,
+ &pCifsInode->openFileList);
+
+ if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+ pCifsInode->clientCanCacheAll = true;
+ pCifsInode->clientCanCacheRead = true;
+ cFYI(1, ("Exclusive Oplock inode %p",
+ newinode));
+ } else if ((oplock & 0xF) == OPLOCK_READ)
+ pCifsInode->clientCanCacheRead = true;
}
+ write_unlock(&GlobalSMBSeslock);
}
cifs_create_out:
kfree(buf);
+ kfree(pinfo);
kfree(full_path);
FreeXid(xid);
+ cFYI(1, ("cifs_create returned %d", rc));
return rc;
}
@@ -1045,7 +1045,7 @@ out_reval:
return rc;
}
-static void posix_fill_in_inode(struct inode *tmp_inode,
+void posix_fill_in_inode(struct inode *tmp_inode,
FILE_UNIX_BASIC_INFO *pData, int isNewInode)
{
struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
This reduces the number of calls to the server when creating files, and also makes the force_create_mode option in samba work correctly. This also refactors some of the error handling in this function to reduce layers of indentation. Signed-off-by: Jeff Layton <jlayton@redhat.com> --- fs/cifs/cifsproto.h | 2 + fs/cifs/dir.c | 281 +++++++++++++++++++++++++++++---------------------- fs/cifs/inode.c | 2 +- 3 files changed, 165 insertions(+), 120 deletions(-)