aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r--fs/cifs/inode.c919
1 files changed, 447 insertions, 472 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 745da3d0653..ed6208ff85a 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -124,10 +124,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
{
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
- unsigned long oldtime = cifs_i->time;
cifs_revalidate_cache(inode, fattr);
+ spin_lock(&inode->i_lock);
inode->i_atime = fattr->cf_atime;
inode->i_mtime = fattr->cf_mtime;
inode->i_ctime = fattr->cf_ctime;
@@ -148,9 +148,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
else
cifs_i->time = jiffies;
- cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode,
- oldtime, cifs_i->time);
-
cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
cifs_i->server_eof = fattr->cf_eof;
@@ -158,7 +155,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
* Can't safely change the file size here if the client is writing to
* it due to potential races.
*/
- spin_lock(&inode->i_lock);
if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
i_size_write(inode, fattr->cf_eof);
@@ -286,10 +282,11 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
}
-int cifs_get_file_info_unix(struct file *filp)
+static int
+cifs_get_file_info_unix(struct file *filp)
{
int rc;
- int xid;
+ unsigned int xid;
FILE_UNIX_BASIC_INFO find_data;
struct cifs_fattr fattr;
struct inode *inode = filp->f_path.dentry->d_inode;
@@ -297,8 +294,8 @@ int cifs_get_file_info_unix(struct file *filp)
struct cifsFileInfo *cfile = filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
- xid = GetXid();
- rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
+ xid = get_xid();
+ rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
if (!rc) {
cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
} else if (rc == -EREMOTE) {
@@ -307,13 +304,13 @@ int cifs_get_file_info_unix(struct file *filp)
}
cifs_fattr_to_inode(inode, &fattr);
- FreeXid(xid);
+ free_xid(xid);
return rc;
}
int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *full_path,
- struct super_block *sb, int xid)
+ struct super_block *sb, unsigned int xid)
{
int rc;
FILE_UNIX_BASIC_INFO find_data;
@@ -367,7 +364,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
static int
cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
- struct cifs_sb_info *cifs_sb, int xid)
+ struct cifs_sb_info *cifs_sb, unsigned int xid)
{
int rc;
int oplock = 0;
@@ -466,7 +463,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
* FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
*/
static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
- struct cifs_sb_info *cifs_sb, int xid)
+ struct cifs_sb_info *cifs_sb, unsigned int xid)
{
#ifdef CONFIG_CIFS_XATTR
ssize_t rc;
@@ -554,19 +551,24 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
fattr->cf_gid = cifs_sb->mnt_gid;
}
-int cifs_get_file_info(struct file *filp)
+static int
+cifs_get_file_info(struct file *filp)
{
int rc;
- int xid;
+ unsigned int xid;
FILE_ALL_INFO find_data;
struct cifs_fattr fattr;
struct inode *inode = filp->f_path.dentry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsFileInfo *cfile = filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ struct TCP_Server_Info *server = tcon->ses->server;
+
+ if (!server->ops->query_file_info)
+ return -ENOSYS;
- xid = GetXid();
- rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
+ xid = get_xid();
+ rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
switch (rc) {
case 0:
cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
@@ -596,71 +598,96 @@ int cifs_get_file_info(struct file *filp)
fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
cifs_fattr_to_inode(inode, &fattr);
cgfi_exit:
- FreeXid(xid);
+ free_xid(xid);
return rc;
}
-int cifs_get_inode_info(struct inode **pinode,
- const unsigned char *full_path, FILE_ALL_INFO *pfindData,
- struct super_block *sb, int xid, const __u16 *pfid)
+int
+cifs_get_inode_info(struct inode **inode, const char *full_path,
+ FILE_ALL_INFO *data, struct super_block *sb, int xid,
+ const __u16 *fid)
{
- int rc = 0, tmprc;
- struct cifs_tcon *pTcon;
+ bool validinum = false;
+ __u16 srchflgs;
+ int rc = 0, tmprc = ENOSYS;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
struct tcon_link *tlink;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
char *buf = NULL;
- bool adjustTZ = false;
+ bool adjust_tz = false;
struct cifs_fattr fattr;
+ struct cifs_search_info *srchinf = NULL;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
cFYI(1, "Getting info on %s", full_path);
- if ((pfindData == NULL) && (*pinode != NULL)) {
- if (CIFS_I(*pinode)->clientCanCacheRead) {
+ if ((data == NULL) && (*inode != NULL)) {
+ if (CIFS_I(*inode)->clientCanCacheRead) {
cFYI(1, "No need to revalidate cached inode sizes");
goto cgii_exit;
}
}
- /* if file info not passed in then get it from server */
- if (pfindData == NULL) {
+ /* if inode info is not passed, get it from server */
+ if (data == NULL) {
+ if (!server->ops->query_path_info) {
+ rc = -ENOSYS;
+ goto cgii_exit;
+ }
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (buf == NULL) {
rc = -ENOMEM;
goto cgii_exit;
}
- pfindData = (FILE_ALL_INFO *)buf;
-
- /* could do find first instead but this returns more info */
- rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
- 0 /* not legacy */,
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- /* BB optimize code so we do not make the above call
- when server claims no NT SMB support and the above call
- failed at least once - set flag in tcon or mount */
- if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
- rc = SMBQueryInformation(xid, pTcon, full_path,
- pfindData, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- adjustTZ = true;
- }
+ data = (FILE_ALL_INFO *)buf;
+ rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path,
+ data, &adjust_tz);
}
if (!rc) {
- cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData,
- cifs_sb, adjustTZ);
+ cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *)data, cifs_sb,
+ adjust_tz);
} else if (rc == -EREMOTE) {
cifs_create_dfs_fattr(&fattr, sb);
rc = 0;
- } else {
+ } else if (rc == -EACCES && backup_cred(cifs_sb)) {
+ srchinf = kzalloc(sizeof(struct cifs_search_info),
+ GFP_KERNEL);
+ if (srchinf == NULL) {
+ rc = -ENOMEM;
+ goto cgii_exit;
+ }
+
+ srchinf->endOfSearch = false;
+ srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
+
+ srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
+ CIFS_SEARCH_CLOSE_AT_END |
+ CIFS_SEARCH_BACKUP_SEARCH;
+
+ rc = CIFSFindFirst(xid, tcon, full_path,
+ cifs_sb, NULL, srchflgs, srchinf, false);
+ if (!rc) {
+ data =
+ (FILE_ALL_INFO *)srchinf->srch_entries_start;
+
+ cifs_dir_info_to_fattr(&fattr,
+ (FILE_DIRECTORY_INFO *)data, cifs_sb);
+ fattr.cf_uniqueid = le64_to_cpu(
+ ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
+ validinum = true;
+
+ cifs_buf_release(srchinf->ntwrk_buf_start);
+ }
+ kfree(srchinf);
+ } else
goto cgii_exit;
- }
/*
* If an inode wasn't passed in, then get the inode number
@@ -668,37 +695,24 @@ int cifs_get_inode_info(struct inode **pinode,
* Is an i_ino of zero legal? Can we use that to check if the server
* supports returning inode numbers? Are there other sanity checks we
* can use to ensure that the server is really filling in that field?
- *
- * We can not use the IndexNumber field by default from Windows or
- * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
- * CIFS spec claims that this value is unique within the scope of a
- * share, and the windows docs hint that it's actually unique
- * per-machine.
- *
- * There may be higher info levels that work but are there Windows
- * server or network appliances for which IndexNumber field is not
- * guaranteed unique?
*/
- if (*pinode == NULL) {
+ if (*inode == NULL) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
- int rc1 = 0;
-
- rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
- full_path, &fattr.cf_uniqueid,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc1 || !fattr.cf_uniqueid) {
- cFYI(1, "GetSrvInodeNum rc %d", rc1);
- fattr.cf_uniqueid = iunique(sb, ROOT_I);
- cifs_autodisable_serverino(cifs_sb);
+ if (validinum == false) {
+ if (server->ops->get_srv_inum)
+ tmprc = server->ops->get_srv_inum(xid,
+ tcon, cifs_sb, full_path,
+ &fattr.cf_uniqueid, data);
+ if (tmprc) {
+ cFYI(1, "GetSrvInodeNum rc %d", tmprc);
+ fattr.cf_uniqueid = iunique(sb, ROOT_I);
+ cifs_autodisable_serverino(cifs_sb);
+ }
}
- } else {
+ } else
fattr.cf_uniqueid = iunique(sb, ROOT_I);
- }
- } else {
- fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid;
- }
+ } else
+ fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
/* query for SFU type info if supported and needed */
if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
@@ -711,8 +725,7 @@ int cifs_get_inode_info(struct inode **pinode,
#ifdef CONFIG_CIFS_ACL
/* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
- rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path,
- pfid);
+ rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid);
if (rc) {
cFYI(1, "%s: Getting ACL failed with error: %d",
__func__, rc);
@@ -732,12 +745,12 @@ int cifs_get_inode_info(struct inode **pinode,
cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
}
- if (!*pinode) {
- *pinode = cifs_iget(sb, &fattr);
- if (!*pinode)
+ if (!*inode) {
+ *inode = cifs_iget(sb, &fattr);
+ if (!*inode)
rc = -ENOMEM;
} else {
- cifs_fattr_to_inode(*pinode, &fattr);
+ cifs_fattr_to_inode(*inode, &fattr);
}
cgii_exit:
@@ -750,38 +763,6 @@ static const struct inode_operations cifs_ipc_inode_ops = {
.lookup = cifs_lookup,
};
-char *cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
- struct cifs_tcon *tcon)
-{
- int pplen = vol->prepath ? strlen(vol->prepath) : 0;
- int dfsplen;
- char *full_path = NULL;
-
- /* if no prefix path, simply set path to the root of share to "" */
- if (pplen == 0) {
- full_path = kmalloc(1, GFP_KERNEL);
- if (full_path)
- full_path[0] = 0;
- return full_path;
- }
-
- if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
- dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
- else
- dfsplen = 0;
-
- full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
- if (full_path == NULL)
- return full_path;
-
- if (dfsplen)
- strncpy(full_path, tcon->treeName, dfsplen);
- strncpy(full_path + dfsplen, vol->prepath, pplen);
- convert_delimiter(full_path, CIFS_DIR_SEP(cifs_sb));
- full_path[dfsplen + pplen] = 0; /* add trailing null */
- return full_path;
-}
-
static int
cifs_find_inode(struct inode *inode, void *opaque)
{
@@ -800,7 +781,7 @@ cifs_find_inode(struct inode *inode, void *opaque)
return 0;
/* if it's not a directory or has no dentries, then flag it */
- if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
+ if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
return 1;
@@ -825,9 +806,10 @@ static bool
inode_has_hashed_dentries(struct inode *inode)
{
struct dentry *dentry;
+ struct hlist_node *p;
spin_lock(&inode->i_lock);
- list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
spin_unlock(&inode->i_lock);
return true;
@@ -885,13 +867,13 @@ retry_iget5_locked:
/* gets root inode */
struct inode *cifs_root_iget(struct super_block *sb)
{
- int xid;
+ unsigned int xid;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct inode *inode = NULL;
long rc;
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
- xid = GetXid();
+ xid = get_xid();
if (tcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
else
@@ -909,44 +891,43 @@ struct inode *cifs_root_iget(struct super_block *sb)
if (rc && tcon->ipc) {
cFYI(1, "ipc connection - fake read inode");
+ spin_lock(&inode->i_lock);
inode->i_mode |= S_IFDIR;
set_nlink(inode, 2);
inode->i_op = &cifs_ipc_inode_ops;
inode->i_fop = &simple_dir_operations;
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
+ spin_unlock(&inode->i_lock);
} else if (rc) {
iget_failed(inode);
inode = ERR_PTR(rc);
}
out:
- /* can not call macro FreeXid here since in a void func
+ /* can not call macro free_xid here since in a void func
* TODO: This is no longer true
*/
- _FreeXid(xid);
+ _free_xid(xid);
return inode;
}
-static int
-cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
- char *full_path, __u32 dosattr)
+int
+cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
+ char *full_path, __u32 dosattr)
{
- int rc;
- int oplock = 0;
- __u16 netfid;
- __u32 netpid;
bool set_time = false;
- struct cifsFileInfo *open_file;
- struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
- struct tcon_link *tlink = NULL;
- struct cifs_tcon *pTcon;
+ struct TCP_Server_Info *server;
FILE_BASIC_INFO info_buf;
if (attrs == NULL)
return -EINVAL;
+ server = cifs_sb_master_tcon(cifs_sb)->ses->server;
+ if (!server->ops->set_file_info)
+ return -ENOSYS;
+
if (attrs->ia_valid & ATTR_ATIME) {
set_time = true;
info_buf.LastAccessTime =
@@ -977,80 +958,17 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
info_buf.CreationTime = 0; /* don't change */
info_buf.Attributes = cpu_to_le32(dosattr);
- /*
- * If the file is already open for write, just use that fileid
- */
- open_file = find_writable_file(cifsInode, true);
- if (open_file) {
- netfid = open_file->netfid;
- netpid = open_file->pid;
- pTcon = tlink_tcon(open_file->tlink);
- goto set_via_filehandle;
- }
-
- tlink = cifs_sb_tlink(cifs_sb);
- if (IS_ERR(tlink)) {
- rc = PTR_ERR(tlink);
- tlink = NULL;
- goto out;
- }
- pTcon = tlink_tcon(tlink);
-
- /*
- * NT4 apparently returns success on this call, but it doesn't
- * really work.
- */
- if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
- rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
- &info_buf, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- cifsInode->cifsAttrs = dosattr;
- goto out;
- } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
- goto out;
- }
-
- cFYI(1, "calling SetFileInfo since SetPathInfo for "
- "times not supported by this server");
- rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
- SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
- CREATE_NOT_DIR, &netfid, &oplock,
- NULL, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
-
- if (rc != 0) {
- if (rc == -EIO)
- rc = -EINVAL;
- goto out;
- }
-
- netpid = current->tgid;
-
-set_via_filehandle:
- rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
- if (!rc)
- cifsInode->cifsAttrs = dosattr;
-
- if (open_file == NULL)
- CIFSSMBClose(xid, pTcon, netfid);
- else
- cifsFileInfo_put(open_file);
-out:
- if (tlink != NULL)
- cifs_put_tlink(tlink);
- return rc;
+ return server->ops->set_file_info(inode, full_path, &info_buf, xid);
}
/*
- * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
* and rename it to a random name that hopefully won't conflict with
* anything else.
*/
-static int
-cifs_rename_pending_delete(char *full_path, struct dentry *dentry, int xid)
+int
+cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
+ const unsigned int xid)
{
int oplock = 0;
int rc;
@@ -1159,6 +1077,15 @@ undo_setattr:
goto out_close;
}
+/* copied from fs/nfs/dir.c with small changes */
+static void
+cifs_drop_nlink(struct inode *inode)
+{
+ spin_lock(&inode->i_lock);
+ if (inode->i_nlink > 0)
+ drop_nlink(inode);
+ spin_unlock(&inode->i_lock);
+}
/*
* If dentry->d_inode is null (usually meaning the cached dentry
@@ -1170,7 +1097,7 @@ undo_setattr:
int cifs_unlink(struct inode *dir, struct dentry *dentry)
{
int rc = 0;
- int xid;
+ unsigned int xid;
char *full_path = NULL;
struct inode *inode = dentry->d_inode;
struct cifsInodeInfo *cifs_inode;
@@ -1178,6 +1105,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct tcon_link *tlink;
struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
struct iattr *attrs = NULL;
__u32 dosattr = 0, origattr = 0;
@@ -1187,8 +1115,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
if (IS_ERR(tlink))
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
- xid = GetXid();
+ xid = get_xid();
/* Unlink can be called from rename so we can not take the
* sb->s_vfs_rename_mutex here */
@@ -1198,9 +1127,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
goto unlink_out;
}
- if ((tcon->ses->capabilities & CAP_UNIX) &&
- (CIFS_UNIX_POSIX_PATH_OPS_CAP &
- le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+ if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+ le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = CIFSPOSIXDelFile(xid, tcon, full_path,
SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1210,19 +1138,28 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
}
retry_std_delete:
- rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (!server->ops->unlink) {
+ rc = -ENOSYS;
+ goto psx_del_no_retry;
+ }
+
+ rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
psx_del_no_retry:
if (!rc) {
if (inode)
- drop_nlink(inode);
+ cifs_drop_nlink(inode);
} else if (rc == -ENOENT) {
d_drop(dentry);
} else if (rc == -ETXTBSY) {
- rc = cifs_rename_pending_delete(full_path, dentry, xid);
- if (rc == 0)
- drop_nlink(inode);
+ if (server->ops->rename_pending_delete) {
+ rc = server->ops->rename_pending_delete(full_path,
+ dentry, xid);
+ if (rc == 0)
+ cifs_drop_nlink(inode);
+ }
+ if (rc == -ETXTBSY)
+ rc = -EBUSY;
} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
if (attrs == NULL) {
@@ -1264,21 +1201,156 @@ out_reval:
unlink_out:
kfree(full_path);
kfree(attrs);
- FreeXid(xid);
+ free_xid(xid);
cifs_put_tlink(tlink);
return rc;
}
+static int
+cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
+ const char *full_path, struct cifs_sb_info *cifs_sb,
+ struct cifs_tcon *tcon, const unsigned int xid)
+{
+ int rc = 0;
+ struct inode *inode = NULL;
+
+ if (tcon->unix_ext)
+ rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb,
+ xid);
+ else
+ rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb,
+ xid, NULL);
+
+ if (rc)
+ return rc;
+
+ /*
+ * setting nlink not necessary except in cases where we failed to get it
+ * from the server or was set bogus. Also, since this is a brand new
+ * inode, no need to grab the i_lock before setting the i_nlink.
+ */
+ if (inode->i_nlink < 2)
+ set_nlink(inode, 2);
+ mode &= ~current_umask();
+ /* must turn on setgid bit if parent dir has it */
+ if (parent->i_mode & S_ISGID)
+ mode |= S_ISGID;
+
+ if (tcon->unix_ext) {
+ 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 (parent->i_mode & S_ISGID)
+ args.gid = (__u64)parent->i_gid;
+ else
+ args.gid = (__u64)current_fsgid();
+ } else {
+ args.uid = NO_CHANGE_64;
+ args.gid = NO_CHANGE_64;
+ }
+ CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ } else {
+ struct TCP_Server_Info *server = tcon->ses->server;
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+ (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
+ server->ops->mkdir_setinfo(inode, full_path, cifs_sb,
+ tcon, xid);
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ inode->i_mode = (mode | S_IFDIR);
+
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ inode->i_uid = current_fsuid();
+ if (inode->i_mode & S_ISGID)
+ inode->i_gid = parent->i_gid;
+ else
+ inode->i_gid = current_fsgid();
+ }
+ }
+ d_instantiate(dentry, inode);
+ return rc;
+}
+
+static int
+cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
+ const char *full_path, struct cifs_sb_info *cifs_sb,
+ struct cifs_tcon *tcon, const unsigned int xid)
+{
+ int rc = 0;
+ u32 oplock = 0;
+ FILE_UNIX_BASIC_INFO *info = NULL;
+ struct inode *newinode = NULL;
+ struct cifs_fattr fattr;
+
+ info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+ if (info == NULL) {
+ rc = -ENOMEM;
+ goto posix_mkdir_out;
+ }
+
+ mode &= ~current_umask();
+ rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
+ NULL /* netfid */, info, &oplock, full_path,
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc == -EOPNOTSUPP)
+ goto posix_mkdir_out;
+ else if (rc) {
+ cFYI(1, "posix mkdir returned 0x%x", rc);
+ d_drop(dentry);
+ goto posix_mkdir_out;
+ }
+
+ if (info->Type == cpu_to_le32(-1))
+ /* no return info, go query for it */
+ goto posix_mkdir_get_info;
+ /*
+ * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
+ * need to set uid/gid.
+ */
+
+ cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
+ cifs_fill_uniqueid(inode->i_sb, &fattr);
+ newinode = cifs_iget(inode->i_sb, &fattr);
+ if (!newinode)
+ goto posix_mkdir_get_info;
+
+ d_instantiate(dentry, newinode);
+
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1, "instantiated dentry %p %s to inode %p", dentry,
+ dentry->d_name.name, newinode);
+
+ if (newinode->i_nlink != 2)
+ cFYI(1, "unexpected number of links %d", newinode->i_nlink);
+#endif
+
+posix_mkdir_out:
+ kfree(info);
+ return rc;
+posix_mkdir_get_info:
+ rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
+ xid);
+ goto posix_mkdir_out;
+}
+
int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
{
- int rc = 0, tmprc;
- int xid;
+ int rc = 0;
+ unsigned int xid;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
- struct cifs_tcon *pTcon;
- char *full_path = NULL;
- struct inode *newinode = NULL;
- struct cifs_fattr fattr;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
+ char *full_path;
cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
@@ -1286,9 +1358,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
- xid = GetXid();
+ xid = get_xid();
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
@@ -1296,148 +1368,31 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out;
}
- 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;
+ if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+ le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+ rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
+ tcon, xid);
+ if (rc != -EOPNOTSUPP)
goto mkdir_out;
- }
-
- mode &= ~current_umask();
- 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 == -EOPNOTSUPP) {
- kfree(pInfo);
- goto mkdir_retry_old;
- } else if (rc) {
- cFYI(1, "posix mkdir returned 0x%x", rc);
- d_drop(direntry);
- } else {
- if (pInfo->Type == cpu_to_le32(-1)) {
- /* no return info, go query for it */
- kfree(pInfo);
- goto mkdir_get_info;
- }
-/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
- to set uid/gid */
-
- cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
- cifs_fill_uniqueid(inode->i_sb, &fattr);
- newinode = cifs_iget(inode->i_sb, &fattr);
- if (!newinode) {
- kfree(pInfo);
- goto mkdir_get_info;
- }
-
- d_instantiate(direntry, newinode);
+ }
-#ifdef CONFIG_CIFS_DEBUG2
- cFYI(1, "instantiated dentry %p %s to inode %p",
- direntry, direntry->d_name.name, newinode);
+ server = tcon->ses->server;
- if (newinode->i_nlink != 2)
- cFYI(1, "unexpected number of links %d",
- newinode->i_nlink);
-#endif
- }
- kfree(pInfo);
+ if (!server->ops->mkdir) {
+ rc = -ENOSYS;
goto mkdir_out;
}
-mkdir_retry_old:
+
/* 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);
+ rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb);
if (rc) {
cFYI(1, "cifs_mkdir returned 0x%x", rc);
d_drop(direntry);
- } else {
-mkdir_get_info:
- if (pTcon->unix_ext)
- rc = cifs_get_inode_info_unix(&newinode, full_path,
- inode->i_sb, xid);
- else
- rc = cifs_get_inode_info(&newinode, full_path, NULL,
- inode->i_sb, xid, NULL);
-
- d_instantiate(direntry, newinode);
- /* 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))
- set_nlink(direntry->d_inode, 2);
-
- mode &= ~current_umask();
- /* must turn on setgid bit if parent dir has it */
- if (inode->i_mode & S_ISGID)
- mode |= S_ISGID;
-
- if (pTcon->unix_ext) {
- 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;
- }
- CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- } else {
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
- (mode & S_IWUGO) == 0) {
- FILE_BASIC_INFO pInfo;
- struct cifsInodeInfo *cifsInode;
- u32 dosattrs;
-
- memset(&pInfo, 0, sizeof(pInfo));
- cifsInode = CIFS_I(newinode);
- dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
- pInfo.Attributes = cpu_to_le32(dosattrs);
- tmprc = CIFSSMBSetPathInfo(xid, pTcon,
- full_path, &pInfo,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (tmprc == 0)
- cifsInode->cifsAttrs = dosattrs;
- }
- if (direntry->d_inode) {
- if (cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_DYNPERM)
- direntry->d_inode->i_mode =
- (mode | S_IFDIR);
-
- if (cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_SET_UID) {
- direntry->d_inode->i_uid =
- current_fsuid();
- if (inode->i_mode & S_ISGID)
- direntry->d_inode->i_gid =
- inode->i_gid;
- else
- direntry->d_inode->i_gid =
- current_fsgid();
- }
- }
- }
+ goto mkdir_out;
}
+
+ rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
+ xid);
mkdir_out:
/*
* Force revalidate to get parent dir info when needed since cached
@@ -1445,7 +1400,7 @@ mkdir_out:
*/
CIFS_I(inode)->time = 0;
kfree(full_path);
- FreeXid(xid);
+ free_xid(xid);
cifs_put_tlink(tlink);
return rc;
}
@@ -1453,16 +1408,17 @@ mkdir_out:
int cifs_rmdir(struct inode *inode, struct dentry *direntry)
{
int rc = 0;
- int xid;
+ unsigned int xid;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
char *full_path = NULL;
struct cifsInodeInfo *cifsInode;
cFYI(1, "cifs_rmdir, inode = 0x%p", inode);
- xid = GetXid();
+ xid = get_xid();
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
@@ -1476,10 +1432,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
rc = PTR_ERR(tlink);
goto rmdir_exit;
}
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
- rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (!server->ops->rmdir) {
+ rc = -ENOSYS;
+ cifs_put_tlink(tlink);
+ goto rmdir_exit;
+ }
+
+ rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
cifs_put_tlink(tlink);
if (!rc) {
@@ -1505,33 +1467,37 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
rmdir_exit:
kfree(full_path);
- FreeXid(xid);
+ free_xid(xid);
return rc;
}
static int
-cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
- struct dentry *to_dentry, const char *toPath)
+cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
+ const char *from_path, struct dentry *to_dentry,
+ const char *to_path)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
struct tcon_link *tlink;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
__u16 srcfid;
int oplock, rc;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+
+ if (!server->ops->rename)
+ return -ENOSYS;
/* try path-based rename first */
- rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
/*
- * don't bother with rename by filehandle unless file is busy and
- * source Note that cross directory moves do not work with
+ * Don't bother with rename by filehandle unless file is busy and
+ * source. Note that cross directory moves do not work with
* rename by filehandle to various Windows servers.
*/
if (rc == 0 || rc != -ETXTBSY)
@@ -1542,35 +1508,35 @@ cifs_do_rename(int xid, struct dentry *from_dentry, const char *fromPath,
goto do_rename_exit;
/* open the file to be renamed -- we need DELETE perms */
- rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
+ rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
CREATE_NOT_DIR, &srcfid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
-
if (rc == 0) {
- rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
+ rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
(const char *) to_dentry->d_name.name,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
-
- CIFSSMBClose(xid, pTcon, srcfid);
+ CIFSSMBClose(xid, tcon, srcfid);
}
do_rename_exit:
cifs_put_tlink(tlink);
return rc;
}
-int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
- struct inode *target_dir, struct dentry *target_dentry)
+int
+cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
+ struct inode *target_dir, struct dentry *target_dentry)
{
- char *fromName = NULL;
- char *toName = NULL;
+ char *from_name = NULL;
+ char *to_name = NULL;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
FILE_UNIX_BASIC_INFO *info_buf_target;
- int xid, rc, tmprc;
+ unsigned int xid;
+ int rc, tmprc;
cifs_sb = CIFS_SB(source_dir->i_sb);
tlink = cifs_sb_tlink(cifs_sb);
@@ -1578,31 +1544,31 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
- xid = GetXid();
+ xid = get_xid();
/*
* we already have the rename sem so we do not need to
* grab it again here to protect the path integrity
*/
- fromName = build_path_from_dentry(source_dentry);
- if (fromName == NULL) {
+ from_name = build_path_from_dentry(source_dentry);
+ if (from_name == NULL) {
rc = -ENOMEM;
goto cifs_rename_exit;
}
- toName = build_path_from_dentry(target_dentry);
- if (toName == NULL) {
+ to_name = build_path_from_dentry(target_dentry);
+ if (to_name == NULL) {
rc = -ENOMEM;
goto cifs_rename_exit;
}
- rc = cifs_do_rename(xid, source_dentry, fromName,
- target_dentry, toName);
+ rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
+ to_name);
if (rc == -EEXIST && tcon->unix_ext) {
/*
- * Are src and dst hardlinks of same inode? We can
- * only tell with unix extensions enabled
+ * Are src and dst hardlinks of same inode? We can only tell
+ * with unix extensions enabled.
*/
info_buf_source =
kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
@@ -1613,19 +1579,19 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
}
info_buf_target = info_buf_source + 1;
- tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
- info_buf_source,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
+ info_buf_source,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc != 0)
goto unlink_target;
- tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
- info_buf_target,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
+ info_buf_target,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc == 0 && (info_buf_source->UniqueId ==
info_buf_target->UniqueId)) {
@@ -1633,8 +1599,11 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
rc = 0;
goto cifs_rename_exit;
}
- } /* else ... BB we could add the same check for Windows by
- checking the UniqueId via FILE_INTERNAL_INFO */
+ }
+ /*
+ * else ... BB we could add the same check for Windows by
+ * checking the UniqueId via FILE_INTERNAL_INFO
+ */
unlink_target:
/* Try unlinking the target dentry if it's not negative */
@@ -1642,16 +1611,15 @@ unlink_target:
tmprc = cifs_unlink(target_dir, target_dentry);
if (tmprc)
goto cifs_rename_exit;
-
- rc = cifs_do_rename(xid, source_dentry, fromName,
- target_dentry, toName);
+ rc = cifs_do_rename(xid, source_dentry, from_name,
+ target_dentry, to_name);
}
cifs_rename_exit:
kfree(info_buf_source);
- kfree(fromName);
- kfree(toName);
- FreeXid(xid);
+ kfree(from_name);
+ kfree(to_name);
+ free_xid(xid);
cifs_put_tlink(tlink);
return rc;
}
@@ -1726,7 +1694,7 @@ int cifs_revalidate_file_attr(struct file *filp)
int cifs_revalidate_dentry_attr(struct dentry *dentry)
{
- int xid;
+ unsigned int xid;
int rc = 0;
struct inode *inode = dentry->d_inode;
struct super_block *sb = dentry->d_sb;
@@ -1738,7 +1706,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
if (!cifs_inode_needs_reval(inode))
return rc;
- xid = GetXid();
+ xid = get_xid();
/* can not safely grab the rename sem here if rename calls revalidate
since that would deadlock */
@@ -1760,7 +1728,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
out:
kfree(full_path);
- FreeXid(xid);
+ free_xid(xid);
return rc;
}
@@ -1823,11 +1791,12 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
stat->ino = CIFS_I(inode)->uniqueid;
/*
- * If on a multiuser mount without unix extensions, and the admin hasn't
- * overridden them, set the ownership to the fsuid/fsgid of the current
- * process.
+ * If on a multiuser mount without unix extensions or cifsacl being
+ * enabled, and the admin hasn't overridden them, set the ownership
+ * to the fsuid/fsgid of the current process.
*/
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
+ !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
!tcon->unix_ext) {
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
stat->uid = current_fsuid();
@@ -1868,14 +1837,15 @@ static void cifs_setsize(struct inode *inode, loff_t offset)
static int
cifs_set_file_size(struct inode *inode, struct iattr *attrs,
- int xid, char *full_path)
+ unsigned int xid, char *full_path)
{
int rc;
struct cifsFileInfo *open_file;
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = NULL;
- struct cifs_tcon *pTcon = NULL;
+ struct cifs_tcon *tcon = NULL;
+ struct TCP_Server_Info *server;
struct cifs_io_parms io_parms;
/*
@@ -1889,19 +1859,21 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
*/
open_file = find_writable_file(cifsInode, true);
if (open_file) {
- __u16 nfid = open_file->netfid;
- __u32 npid = open_file->pid;
- pTcon = tlink_tcon(open_file->tlink);
- rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
- npid, false);
+ tcon = tlink_tcon(open_file->tlink);
+ server = tcon->ses->server;
+ if (server->ops->set_file_size)
+ rc = server->ops->set_file_size(xid, tcon, open_file,
+ attrs->ia_size, false);
+ else
+ rc = -ENOSYS;
cifsFileInfo_put(open_file);
cFYI(1, "SetFSize for attrs rc = %d", rc);
if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
unsigned int bytes_written;
- io_parms.netfid = nfid;
- io_parms.pid = npid;
- io_parms.tcon = pTcon;
+ io_parms.netfid = open_file->fid.netfid;
+ io_parms.pid = open_file->pid;
+ io_parms.tcon = tcon;
io_parms.offset = 0;
io_parms.length = attrs->ia_size;
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
@@ -1911,52 +1883,55 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
} else
rc = -EINVAL;
- if (rc != 0) {
- if (pTcon == NULL) {
- tlink = cifs_sb_tlink(cifs_sb);
- if (IS_ERR(tlink))
- return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
- }
+ if (!rc)
+ goto set_size_out;
+
+ if (tcon == NULL) {
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+ }
- /* Set file size by pathname rather than by handle
- either because no valid, writeable file handle for
- it was found or because there was an error setting
- it by handle */
- rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
- false, cifs_sb->local_nls,
+ /*
+ * Set file size by pathname rather than by handle either because no
+ * valid, writeable file handle for it was found or because there was
+ * an error setting it by handle.
+ */
+ if (server->ops->set_path_size)
+ rc = server->ops->set_path_size(xid, tcon, full_path,
+ attrs->ia_size, cifs_sb, false);
+ else
+ rc = -ENOSYS;
+ cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
+ if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+ __u16 netfid;
+ int oplock = 0;
+
+ rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
+ GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
+ &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
- if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
- __u16 netfid;
- int oplock = 0;
-
- rc = SMBLegacyOpen(xid, pTcon, full_path,
- FILE_OPEN, GENERIC_WRITE,
- CREATE_NOT_DIR, &netfid, &oplock, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- unsigned int bytes_written;
-
- io_parms.netfid = netfid;
- io_parms.pid = current->tgid;
- io_parms.tcon = pTcon;
- io_parms.offset = 0;
- io_parms.length = attrs->ia_size;
- rc = CIFSSMBWrite(xid, &io_parms,
- &bytes_written,
- NULL, NULL, 1);
- cFYI(1, "wrt seteof rc %d", rc);
- CIFSSMBClose(xid, pTcon, netfid);
- }
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc == 0) {
+ unsigned int bytes_written;
+
+ io_parms.netfid = netfid;
+ io_parms.pid = current->tgid;
+ io_parms.tcon = tcon;
+ io_parms.offset = 0;
+ io_parms.length = attrs->ia_size;
+ rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL,
+ NULL, 1);
+ cFYI(1, "wrt seteof rc %d", rc);
+ CIFSSMBClose(xid, tcon, netfid);
}
- if (tlink)
- cifs_put_tlink(tlink);
}
+ if (tlink)
+ cifs_put_tlink(tlink);
+set_size_out:
if (rc == 0) {
cifsInode->server_eof = attrs->ia_size;
cifs_setsize(inode, attrs->ia_size);
@@ -1970,7 +1945,7 @@ static int
cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
{
int rc;
- int xid;
+ unsigned int xid;
char *full_path = NULL;
struct inode *inode = direntry->d_inode;
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
@@ -1983,7 +1958,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
cFYI(1, "setattr_unix on file %s attrs->ia_valid=0x%x",
direntry->d_name.name, attrs->ia_valid);
- xid = GetXid();
+ xid = get_xid();
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE;
@@ -2063,7 +2038,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
args->device = 0;
open_file = find_writable_file(cifsInode, true);
if (open_file) {
- u16 nfid = open_file->netfid;
+ u16 nfid = open_file->fid.netfid;
u32 npid = open_file->pid;
pTcon = tlink_tcon(open_file->tlink);
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
@@ -2103,14 +2078,14 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
out:
kfree(args);
kfree(full_path);
- FreeXid(xid);
+ free_xid(xid);
return rc;
}
static int
cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
{
- int xid;
+ unsigned int xid;
uid_t uid = NO_CHANGE_32;
gid_t gid = NO_CHANGE_32;
struct inode *inode = direntry->d_inode;
@@ -2121,7 +2096,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
__u32 dosattr = 0;
__u64 mode = NO_CHANGE_64;
- xid = GetXid();
+ xid = get_xid();
cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
direntry->d_name.name, attrs->ia_valid);
@@ -2131,14 +2106,14 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
rc = inode_change_ok(inode, attrs);
if (rc < 0) {
- FreeXid(xid);
+ free_xid(xid);
return rc;
}
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
rc = -ENOMEM;
- FreeXid(xid);
+ free_xid(xid);
return rc;
}
@@ -2264,7 +2239,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
cifs_setattr_exit:
kfree(full_path);
- FreeXid(xid);
+ free_xid(xid);
return rc;
}