Commit d2c12719 authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Al Viro

cifs: implement i_op->atomic_open()

Add an ->atomic_open implementation which replaces the atomic lookup+open+create
operation implemented via ->lookup and ->create operations.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
CC: Steve French <sfrench@samba.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c8ccbe03
...@@ -777,6 +777,7 @@ struct file_system_type cifs_fs_type = { ...@@ -777,6 +777,7 @@ struct file_system_type cifs_fs_type = {
}; };
const struct inode_operations cifs_dir_inode_ops = { const struct inode_operations cifs_dir_inode_ops = {
.create = cifs_create, .create = cifs_create,
.atomic_open = cifs_atomic_open,
.lookup = cifs_lookup, .lookup = cifs_lookup,
.getattr = cifs_getattr, .getattr = cifs_getattr,
.unlink = cifs_unlink, .unlink = cifs_unlink,
......
...@@ -46,6 +46,9 @@ extern const struct inode_operations cifs_dir_inode_ops; ...@@ -46,6 +46,9 @@ extern const struct inode_operations cifs_dir_inode_ops;
extern struct inode *cifs_root_iget(struct super_block *); extern struct inode *cifs_root_iget(struct super_block *);
extern int cifs_create(struct inode *, struct dentry *, umode_t, extern int cifs_create(struct inode *, struct dentry *, umode_t,
struct nameidata *); struct nameidata *);
extern struct file *cifs_atomic_open(struct inode *, struct dentry *,
struct opendata *, unsigned, umode_t,
bool *);
extern struct dentry *cifs_lookup(struct inode *, struct dentry *, extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
struct nameidata *); struct nameidata *);
extern int cifs_unlink(struct inode *dir, struct dentry *dentry); extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
......
...@@ -133,91 +133,125 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -133,91 +133,125 @@ build_path_from_dentry(struct dentry *direntry)
return full_path; return full_path;
} }
/*
* Don't allow the separator character in a path component.
* The VFS will not allow "/", but "\" is allowed by posix.
*/
static int
check_name(struct dentry *direntry)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
int i;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
for (i = 0; i < direntry->d_name.len; i++) {
if (direntry->d_name.name[i] == '\\') {
cFYI(1, "Invalid file name");
return -EINVAL;
}
}
}
return 0;
}
/* Inode operations in similar order to how they appear in Linux file fs.h */ /* Inode operations in similar order to how they appear in Linux file fs.h */
int static int cifs_do_create(struct inode *inode, struct dentry *direntry,
cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, int xid, struct tcon_link *tlink, unsigned oflags,
struct nameidata *nd) umode_t mode, __u32 *oplock, __u16 *fileHandle,
bool *created)
{ {
int rc = -ENOENT; int rc = -ENOENT;
int xid;
int create_options = CREATE_NOT_DIR; int create_options = CREATE_NOT_DIR;
__u32 oplock = 0; int desiredAccess;
int oflags; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
/* struct cifs_tcon *tcon = tlink_tcon(tlink);
* BB below access is probably too much for mknod to request
* but we have to do query and setpathinfo so requesting
* less could fail (unless we want to request getatr and setatr
* permissions (only). At least for POSIX we do not have to
* request so much.
*/
int desiredAccess = GENERIC_READ | GENERIC_WRITE;
__u16 fileHandle;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
char *full_path = NULL; char *full_path = NULL;
FILE_ALL_INFO *buf = NULL; FILE_ALL_INFO *buf = NULL;
struct inode *newinode = NULL; struct inode *newinode = NULL;
int disposition = FILE_OVERWRITE_IF; int disposition;
xid = GetXid();
cifs_sb = CIFS_SB(inode->i_sb);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) {
FreeXid(xid);
return PTR_ERR(tlink);
}
tcon = tlink_tcon(tlink);
*oplock = 0;
if (tcon->ses->server->oplocks) if (tcon->ses->server->oplocks)
oplock = REQ_OPLOCK; *oplock = REQ_OPLOCK;
if (nd)
oflags = nd->intent.open.file->f_flags;
else
oflags = O_RDONLY | O_CREAT;
full_path = build_path_from_dentry(direntry); full_path = build_path_from_dentry(direntry);
if (full_path == NULL) { if (full_path == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
goto cifs_create_out; goto out;
} }
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
!tcon->broken_posix_open &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP & (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) { le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = cifs_posix_open(full_path, &newinode, rc = cifs_posix_open(full_path, &newinode,
inode->i_sb, mode, oflags, &oplock, &fileHandle, xid); inode->i_sb, mode, oflags, oplock, fileHandle, xid);
/* EIO could indicate that (posix open) operation is not switch (rc) {
supported, despite what server claimed in capability case 0:
negotiation. EREMOTE indicates DFS junction, which is not if (newinode == NULL) {
handled in posix open */ /* query inode info */
goto cifs_create_get_file_info;
if (rc == 0) { }
if (newinode == NULL) /* query inode info */
if (!S_ISREG(newinode->i_mode)) {
/*
* The server may allow us to open things like
* FIFOs, but the client isn't set up to deal
* with that. If it's not a regular file, just
* close it and proceed as if it were a normal
* lookup.
*/
CIFSSMBClose(xid, tcon, *fileHandle);
goto cifs_create_get_file_info; goto cifs_create_get_file_info;
else /* success, no need to query */ }
/* success, no need to query */
goto cifs_create_set_dentry; goto cifs_create_set_dentry;
} else if ((rc != -EIO) && (rc != -EREMOTE) &&
(rc != -EOPNOTSUPP) && (rc != -EINVAL)) case -ENOENT:
goto cifs_create_out; goto cifs_create_get_file_info;
/* else fallthrough to retry, using older open call, this is
case where server does not support this SMB level, and case -EIO:
falsely claims capability (also get here for DFS case case -EINVAL:
which should be rare for path not covered on files) */ /*
} * EIO could indicate that (posix open) operation is not
* supported, despite what server claimed in capability
if (nd) { * negotiation.
/* if the file is going to stay open, then we *
need to set the desired access properly */ * POSIX open in samba versions 3.3.1 and earlier could
* incorrectly fail with invalid parameter.
*/
tcon->broken_posix_open = true;
break;
case -EREMOTE:
case -EOPNOTSUPP:
/*
* EREMOTE indicates DFS junction, which is not handled
* in posix open. If either that or op not supported
* returned, follow the normal lookup.
*/
break;
default:
goto out;
}
/*
* fallthrough to retry, using older open call, this is case
* where server does not support this SMB level, and falsely
* claims capability (also get here for DFS case which should be
* rare for path not covered on files)
*/
}
desiredAccess = 0; desiredAccess = 0;
if (OPEN_FMODE(oflags) & FMODE_READ) if (OPEN_FMODE(oflags) & FMODE_READ)
desiredAccess |= GENERIC_READ; /* is this too little? */ desiredAccess |= GENERIC_READ; /* is this too little? */
if (OPEN_FMODE(oflags) & FMODE_WRITE) if (OPEN_FMODE(oflags) & FMODE_WRITE)
desiredAccess |= GENERIC_WRITE; desiredAccess |= GENERIC_WRITE;
disposition = FILE_OVERWRITE_IF;
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
disposition = FILE_CREATE; disposition = FILE_CREATE;
else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
...@@ -226,7 +260,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -226,7 +260,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
disposition = FILE_OPEN_IF; disposition = FILE_OPEN_IF;
else else
cFYI(1, "Create flag not set in create function"); cFYI(1, "Create flag not set in create function");
}
/* BB add processing to set equivalent of mode - e.g. via CreateX with /* BB add processing to set equivalent of mode - e.g. via CreateX with
ACLs */ ACLs */
...@@ -234,7 +267,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -234,7 +267,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (buf == NULL) { if (buf == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
goto cifs_create_out; goto out;
} }
/* /*
...@@ -250,7 +283,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -250,7 +283,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
if (tcon->ses->capabilities & CAP_NT_SMBS) if (tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, tcon, full_path, disposition, rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
desiredAccess, create_options, desiredAccess, create_options,
&fileHandle, &oplock, buf, cifs_sb->local_nls, fileHandle, oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
else else
rc = -EIO; /* no NT SMB support fall into legacy open below */ rc = -EIO; /* no NT SMB support fall into legacy open below */
...@@ -259,17 +292,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -259,17 +292,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
/* old server, retry the open legacy style */ /* old server, retry the open legacy style */
rc = SMBLegacyOpen(xid, tcon, full_path, disposition, rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
desiredAccess, create_options, desiredAccess, create_options,
&fileHandle, &oplock, buf, cifs_sb->local_nls, fileHandle, oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
if (rc) { if (rc) {
cFYI(1, "cifs_create returned 0x%x", rc); cFYI(1, "cifs_create returned 0x%x", rc);
goto cifs_create_out; goto out;
} }
/* If Open reported that we actually created a file /* If Open reported that we actually created a file
then we now have to set the mode if possible */ then we now have to set the mode if possible */
if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
struct cifs_unix_set_info_args args = { struct cifs_unix_set_info_args args = {
.mode = mode, .mode = mode,
.ctime = NO_CHANGE_64, .ctime = NO_CHANGE_64,
...@@ -278,6 +311,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -278,6 +311,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
.device = 0, .device = 0,
}; };
*created = true;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
args.uid = (__u64) current_fsuid(); args.uid = (__u64) current_fsuid();
if (inode->i_mode & S_ISGID) if (inode->i_mode & S_ISGID)
...@@ -288,7 +322,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -288,7 +322,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
args.uid = NO_CHANGE_64; args.uid = NO_CHANGE_64;
args.gid = NO_CHANGE_64; args.gid = NO_CHANGE_64;
} }
CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle, CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle,
current->tgid); current->tgid);
} else { } else {
/* BB implement mode setting via Windows security /* BB implement mode setting via Windows security
...@@ -305,11 +339,11 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -305,11 +339,11 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
inode->i_sb, xid); inode->i_sb, xid);
else { else {
rc = cifs_get_inode_info(&newinode, full_path, buf, rc = cifs_get_inode_info(&newinode, full_path, buf,
inode->i_sb, xid, &fileHandle); inode->i_sb, xid, fileHandle);
if (newinode) { if (newinode) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
newinode->i_mode = mode; newinode->i_mode = mode;
if ((oplock & CIFS_CREATE_ACTION) && if ((*oplock & CIFS_CREATE_ACTION) &&
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
newinode->i_uid = current_fsuid(); newinode->i_uid = current_fsuid();
if (inode->i_mode & S_ISGID) if (inode->i_mode & S_ISGID)
...@@ -321,37 +355,139 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, ...@@ -321,37 +355,139 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
} }
cifs_create_set_dentry: cifs_create_set_dentry:
if (rc == 0) if (rc != 0) {
d_instantiate(direntry, newinode);
else
cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
goto out;
}
d_drop(direntry);
d_add(direntry, newinode);
if (newinode && nd) { /* ENOENT for create? How weird... */
struct cifsFileInfo *pfile_info; rc = -ENOENT;
if (!newinode) {
CIFSSMBClose(xid, tcon, *fileHandle);
goto out;
}
rc = 0;
out:
kfree(buf);
kfree(full_path);
return rc;
}
struct file *
cifs_atomic_open(struct inode *inode, struct dentry *direntry,
struct opendata *od, unsigned oflags, umode_t mode,
bool *created)
{
int rc;
int xid;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
__u16 fileHandle;
__u32 oplock;
struct file *filp; struct file *filp;
struct cifsFileInfo *pfile_info;
filp = lookup_instantiate_filp(nd, direntry, generic_file_open); /* Posix open is only called (at lookup time) for file create now. For
* opens (rather than creates), because we do not know if it is a file
* or directory yet, and current Samba no longer allows us to do posix
* open on dirs, we could end up wasting an open call on what turns out
* to be a dir. For file opens, we wait to call posix open till
* cifs_open. It could be added to atomic_open in the future but the
* performance tradeoff of the extra network request when EISDIR or
* EACCES is returned would have to be weighed against the 50% reduction
* in network traffic in the other paths.
*/
if (!(oflags & O_CREAT)) {
struct dentry *res = cifs_lookup(inode, direntry, NULL);
if (IS_ERR(res))
return ERR_CAST(res);
finish_no_open(od, res);
return NULL;
}
rc = check_name(direntry);
if (rc)
return ERR_PTR(rc);
xid = GetXid();
cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
inode, direntry->d_name.name, direntry);
tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
filp = ERR_CAST(tlink);
if (IS_ERR(tlink))
goto free_xid;
tcon = tlink_tcon(tlink);
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
&oplock, &fileHandle, created);
if (rc) {
filp = ERR_PTR(rc);
goto out;
}
filp = finish_open(od, direntry, generic_file_open);
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
rc = PTR_ERR(filp);
CIFSSMBClose(xid, tcon, fileHandle); CIFSSMBClose(xid, tcon, fileHandle);
goto cifs_create_out; goto out;
} }
pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock); pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
if (pfile_info == NULL) { if (pfile_info == NULL) {
fput(filp);
CIFSSMBClose(xid, tcon, fileHandle);
rc = -ENOMEM;
}
} else {
CIFSSMBClose(xid, tcon, fileHandle); CIFSSMBClose(xid, tcon, fileHandle);
fput(filp);
filp = ERR_PTR(-ENOMEM);
} }
cifs_create_out: out:
kfree(buf); cifs_put_tlink(tlink);
kfree(full_path); free_xid:
FreeXid(xid);
return filp;
}
int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
struct nameidata *nd)
{
int rc;
int xid = GetXid();
/*
* BB below access is probably too much for mknod to request
* but we have to do query and setpathinfo so requesting
* less could fail (unless we want to request getatr and setatr
* permissions (only). At least for POSIX we do not have to
* request so much.
*/
unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
struct tcon_link *tlink;
__u16 fileHandle;
__u32 oplock;
bool created = true;
cFYI(1, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p",
inode, direntry->d_name.name, direntry);
tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
rc = PTR_ERR(tlink);
if (IS_ERR(tlink))
goto free_xid;
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
&oplock, &fileHandle, &created);
if (!rc)
CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
free_xid:
FreeXid(xid); FreeXid(xid);
return rc; return rc;
} }
...@@ -492,16 +628,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -492,16 +628,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
{ {
int xid; int xid;
int rc = 0; /* to get around spurious gcc warning, set to zero here */ int rc = 0; /* to get around spurious gcc warning, set to zero here */
__u32 oplock;
__u16 fileHandle = 0;
bool posix_open = false;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *pTcon; struct cifs_tcon *pTcon;
struct cifsFileInfo *cfile;
struct inode *newInode = NULL; struct inode *newInode = NULL;
char *full_path = NULL; char *full_path = NULL;
struct file *filp;
xid = GetXid(); xid = GetXid();
...@@ -518,31 +649,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -518,31 +649,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
} }
pTcon = tlink_tcon(tlink); pTcon = tlink_tcon(tlink);
oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0; rc = check_name(direntry);
if (rc)
/*
* Don't allow the separator character in a path component.
* The VFS will not allow "/", but "\" is allowed by posix.
*/
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
int i;
for (i = 0; i < direntry->d_name.len; i++)
if (direntry->d_name.name[i] == '\\') {
cFYI(1, "Invalid file name");
rc = -EINVAL;
goto lookup_out;
}
}
/*
* O_EXCL: optimize away the lookup, but don't hash the dentry. Let
* the VFS handle the create.
*/
if (nd && (nd->flags & LOOKUP_EXCL)) {
d_instantiate(direntry, NULL);
rc = 0;
goto lookup_out; goto lookup_out;
}
/* can not grab the rename sem here since it would /* can not grab the rename sem here since it would
deadlock in the cases (beginning of sys_rename itself) deadlock in the cases (beginning of sys_rename itself)
...@@ -560,80 +669,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -560,80 +669,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
} }
cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode); cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
/* Posix open is only called (at lookup time) for file create now.
* For opens (rather than creates), because we do not know if it
* is a file or directory yet, and current Samba no longer allows
* us to do posix open on dirs, we could end up wasting an open call
* on what turns out to be a dir. For file opens, we wait to call posix
* open till cifs_open. It could be added here (lookup) in the future
* but the performance tradeoff of the extra network request when EISDIR
* or EACCES is returned would have to be weighed against the 50%
* reduction in network traffic in the other paths.
*/
if (pTcon->unix_ext) { if (pTcon->unix_ext) {
if (nd && !(nd->flags & LOOKUP_DIRECTORY) &&
(nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
(nd->intent.open.file->f_flags & O_CREAT)) {
rc = cifs_posix_open(full_path, &newInode,
parent_dir_inode->i_sb,
nd->intent.open.create_mode,
nd->intent.open.file->f_flags, &oplock,
&fileHandle, xid);
/*
* The check below works around a bug in POSIX
* open in samba versions 3.3.1 and earlier where
* open could incorrectly fail with invalid parameter.
* If either that or op not supported returned, follow
* the normal lookup.
*/
switch (rc) {
case 0:
/*
* The server may allow us to open things like
* FIFOs, but the client isn't set up to deal
* with that. If it's not a regular file, just
* close it and proceed as if it were a normal
* lookup.
*/
if (newInode && !S_ISREG(newInode->i_mode)) {
CIFSSMBClose(xid, pTcon, fileHandle);
break;
}
case -ENOENT:
posix_open = true;
case -EOPNOTSUPP:
break;
default:
pTcon->broken_posix_open = true;
}
}
if (!posix_open)
rc = cifs_get_inode_info_unix(&newInode, full_path, rc = cifs_get_inode_info_unix(&newInode, full_path,
parent_dir_inode->i_sb, xid); parent_dir_inode->i_sb, xid);
} else } else {
rc = cifs_get_inode_info(&newInode, full_path, NULL, rc = cifs_get_inode_info(&newInode, full_path, NULL,
parent_dir_inode->i_sb, xid, NULL); parent_dir_inode->i_sb, xid, NULL);
}
if ((rc == 0) && (newInode != NULL)) { if ((rc == 0) && (newInode != NULL)) {
d_add(direntry, newInode); d_add(direntry, newInode);
if (posix_open) {
filp = lookup_instantiate_filp(nd, direntry,
generic_file_open);
if (IS_ERR(filp)) {
rc = PTR_ERR(filp);
CIFSSMBClose(xid, pTcon, fileHandle);
goto lookup_out;
}
cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
oplock);
if (cfile == NULL) {
fput(filp);
CIFSSMBClose(xid, pTcon, fileHandle);
rc = -ENOMEM;
goto lookup_out;
}
}
/* since paths are not looked up by component - the parent /* since paths are not looked up by component - the parent
directories are presumed to be good here */ directories are presumed to be good here */
renew_parental_timestamps(direntry); renew_parental_timestamps(direntry);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment