summaryrefslogtreecommitdiff
path: root/fs/smb/client/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/smb/client/inode.c')
-rw-r--r--fs/smb/client/inode.c346
1 files changed, 263 insertions, 83 deletions
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 60afab5c83d4..75be4b46bc6f 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -28,14 +28,26 @@
#include "cached_dir.h"
#include "reparse.h"
+/*
+ * Set parameters for the netfs library
+ */
+static void cifs_set_netfs_context(struct inode *inode)
+{
+ struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+
+ netfs_inode_init(&cifs_i->netfs, &cifs_req_ops, true);
+}
+
static void cifs_set_ops(struct inode *inode)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct netfs_inode *ictx = netfs_inode(inode);
switch (inode->i_mode & S_IFMT) {
case S_IFREG:
inode->i_op = &cifs_file_inode_ops;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ set_bit(NETFS_ICTX_UNBUFFERED, &ictx->flags);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_direct_nobrl_ops;
else
@@ -57,6 +69,7 @@ static void cifs_set_ops(struct inode *inode)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
inode->i_data.a_ops = &cifs_addr_ops;
+ mapping_set_large_folios(inode->i_mapping);
break;
case S_IFDIR:
if (IS_AUTOMOUNT(inode)) {
@@ -159,6 +172,8 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
CIFS_I(inode)->time = 0; /* force reval */
return -ESTALE;
}
+ if (inode->i_state & I_NEW)
+ CIFS_I(inode)->netfs.zero_point = fattr->cf_eof;
cifs_revalidate_cache(inode, fattr);
@@ -221,8 +236,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,
if (fattr->cf_flags & CIFS_FATTR_JUNCTION)
inode->i_flags |= S_AUTOMOUNT;
- if (inode->i_state & I_NEW)
+ if (inode->i_state & I_NEW) {
+ cifs_set_netfs_context(inode);
cifs_set_ops(inode);
+ }
return 0;
}
@@ -512,6 +529,8 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
struct cifs_fid fid;
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms = {0};
+ char *symlink_buf_utf16;
+ unsigned int symlink_len_utf16;
char buf[24];
unsigned int bytes_read;
char *pbuf;
@@ -522,10 +541,11 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
fattr->cf_mode &= ~S_IFMT;
if (fattr->cf_eof == 0) {
+ cifs_dbg(FYI, "Fifo\n");
fattr->cf_mode |= S_IFIFO;
fattr->cf_dtype = DT_FIFO;
return 0;
- } else if (fattr->cf_eof < 8) {
+ } else if (fattr->cf_eof > 1 && fattr->cf_eof < 8) {
fattr->cf_mode |= S_IFREG;
fattr->cf_dtype = DT_REG;
return -EINVAL; /* EOPNOTSUPP? */
@@ -567,7 +587,7 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms,
&bytes_read, &pbuf, &buf_type);
if ((rc == 0) && (bytes_read >= 8)) {
- if (memcmp("IntxBLK", pbuf, 8) == 0) {
+ if (memcmp("IntxBLK\0", pbuf, 8) == 0) {
cifs_dbg(FYI, "Block device\n");
fattr->cf_mode |= S_IFBLK;
fattr->cf_dtype = DT_BLK;
@@ -578,8 +598,19 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
fattr->cf_rdev = MKDEV(mjr, mnr);
+ } else if (bytes_read == 16) {
+ /*
+ * Windows NFS server before Windows Server 2012
+ * stores major and minor number in SFU-modified
+ * style, just as 32-bit numbers. Recognize it.
+ */
+ __u32 mjr; /* major */
+ __u32 mnr; /* minor */
+ mjr = le32_to_cpu(*(__le32 *)(pbuf+8));
+ mnr = le32_to_cpu(*(__le32 *)(pbuf+12));
+ fattr->cf_rdev = MKDEV(mjr, mnr);
}
- } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
+ } else if (memcmp("IntxCHR\0", pbuf, 8) == 0) {
cifs_dbg(FYI, "Char device\n");
fattr->cf_mode |= S_IFCHR;
fattr->cf_dtype = DT_CHR;
@@ -590,11 +621,59 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
fattr->cf_rdev = MKDEV(mjr, mnr);
+ } else if (bytes_read == 16) {
+ /*
+ * Windows NFS server before Windows Server 2012
+ * stores major and minor number in SFU-modified
+ * style, just as 32-bit numbers. Recognize it.
+ */
+ __u32 mjr; /* major */
+ __u32 mnr; /* minor */
+ mjr = le32_to_cpu(*(__le32 *)(pbuf+8));
+ mnr = le32_to_cpu(*(__le32 *)(pbuf+12));
+ fattr->cf_rdev = MKDEV(mjr, mnr);
}
- } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
+ } else if (memcmp("LnxSOCK", pbuf, 8) == 0) {
+ cifs_dbg(FYI, "Socket\n");
+ fattr->cf_mode |= S_IFSOCK;
+ fattr->cf_dtype = DT_SOCK;
+ } else if (memcmp("IntxLNK\1", pbuf, 8) == 0) {
cifs_dbg(FYI, "Symlink\n");
fattr->cf_mode |= S_IFLNK;
fattr->cf_dtype = DT_LNK;
+ if ((fattr->cf_eof > 8) && (fattr->cf_eof % 2 == 0)) {
+ symlink_buf_utf16 = kmalloc(fattr->cf_eof-8 + 1, GFP_KERNEL);
+ if (symlink_buf_utf16) {
+ io_parms.offset = 8;
+ io_parms.length = fattr->cf_eof-8 + 1;
+ buf_type = CIFS_NO_BUFFER;
+ rc = tcon->ses->server->ops->sync_read(xid, &fid, &io_parms,
+ &symlink_len_utf16,
+ &symlink_buf_utf16,
+ &buf_type);
+ /*
+ * Check that read buffer has valid length and does not
+ * contain UTF-16 null codepoint (via UniStrnlen() call)
+ * because Linux cannot process symlink with null byte.
+ */
+ if ((rc == 0) &&
+ (symlink_len_utf16 > 0) &&
+ (symlink_len_utf16 < fattr->cf_eof-8 + 1) &&
+ (symlink_len_utf16 % 2 == 0) &&
+ (UniStrnlen((wchar_t *)symlink_buf_utf16, symlink_len_utf16/2) == symlink_len_utf16/2)) {
+ fattr->cf_symlink_target =
+ cifs_strndup_from_utf16(symlink_buf_utf16,
+ symlink_len_utf16,
+ true,
+ cifs_sb->local_nls);
+ if (!fattr->cf_symlink_target)
+ rc = -ENOMEM;
+ }
+ kfree(symlink_buf_utf16);
+ } else {
+ rc = -ENOMEM;
+ }
+ }
} else if (memcmp("LnxFIFO", pbuf, 8) == 0) {
cifs_dbg(FYI, "FIFO\n");
fattr->cf_mode |= S_IFIFO;
@@ -604,6 +683,10 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
fattr->cf_dtype = DT_REG;
rc = -EOPNOTSUPP;
}
+ } else if ((rc == 0) && (bytes_read == 1) && (pbuf[0] == '\0')) {
+ cifs_dbg(FYI, "Socket\n");
+ fattr->cf_mode |= S_IFSOCK;
+ fattr->cf_dtype = DT_SOCK;
} else {
fattr->cf_mode |= S_IFREG; /* then it is a file */
fattr->cf_dtype = DT_REG;
@@ -663,6 +746,88 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
#endif
}
+#define POSIX_TYPE_FILE 0
+#define POSIX_TYPE_DIR 1
+#define POSIX_TYPE_SYMLINK 2
+#define POSIX_TYPE_CHARDEV 3
+#define POSIX_TYPE_BLKDEV 4
+#define POSIX_TYPE_FIFO 5
+#define POSIX_TYPE_SOCKET 6
+
+#define POSIX_X_OTH 0000001
+#define POSIX_W_OTH 0000002
+#define POSIX_R_OTH 0000004
+#define POSIX_X_GRP 0000010
+#define POSIX_W_GRP 0000020
+#define POSIX_R_GRP 0000040
+#define POSIX_X_USR 0000100
+#define POSIX_W_USR 0000200
+#define POSIX_R_USR 0000400
+#define POSIX_STICKY 0001000
+#define POSIX_SET_GID 0002000
+#define POSIX_SET_UID 0004000
+
+#define POSIX_OTH_MASK 0000007
+#define POSIX_GRP_MASK 0000070
+#define POSIX_USR_MASK 0000700
+#define POSIX_PERM_MASK 0000777
+#define POSIX_FILETYPE_MASK 0070000
+
+#define POSIX_FILETYPE_SHIFT 12
+
+static u32 wire_perms_to_posix(u32 wire)
+{
+ u32 mode = 0;
+
+ mode |= (wire & POSIX_X_OTH) ? S_IXOTH : 0;
+ mode |= (wire & POSIX_W_OTH) ? S_IWOTH : 0;
+ mode |= (wire & POSIX_R_OTH) ? S_IROTH : 0;
+ mode |= (wire & POSIX_X_GRP) ? S_IXGRP : 0;
+ mode |= (wire & POSIX_W_GRP) ? S_IWGRP : 0;
+ mode |= (wire & POSIX_R_GRP) ? S_IRGRP : 0;
+ mode |= (wire & POSIX_X_USR) ? S_IXUSR : 0;
+ mode |= (wire & POSIX_W_USR) ? S_IWUSR : 0;
+ mode |= (wire & POSIX_R_USR) ? S_IRUSR : 0;
+ mode |= (wire & POSIX_STICKY) ? S_ISVTX : 0;
+ mode |= (wire & POSIX_SET_GID) ? S_ISGID : 0;
+ mode |= (wire & POSIX_SET_UID) ? S_ISUID : 0;
+
+ return mode;
+}
+
+static u32 posix_filetypes[] = {
+ S_IFREG,
+ S_IFDIR,
+ S_IFLNK,
+ S_IFCHR,
+ S_IFBLK,
+ S_IFIFO,
+ S_IFSOCK
+};
+
+static u32 wire_filetype_to_posix(u32 wire_type)
+{
+ if (wire_type >= ARRAY_SIZE(posix_filetypes)) {
+ pr_warn("Unexpected type %u", wire_type);
+ return 0;
+ }
+ return posix_filetypes[wire_type];
+}
+
+umode_t wire_mode_to_posix(u32 wire, bool is_dir)
+{
+ u32 wire_type;
+ u32 mode;
+
+ wire_type = (wire & POSIX_FILETYPE_MASK) >> POSIX_FILETYPE_SHIFT;
+ /* older servers do not set POSIX file type in the mode field in the response */
+ if ((wire_type == 0) && is_dir)
+ mode = wire_perms_to_posix(wire) | S_IFDIR;
+ else
+ mode = (wire_perms_to_posix(wire) | wire_filetype_to_posix(wire_type));
+ return (umode_t)mode;
+}
+
/* Fill a cifs_fattr struct with info from POSIX info struct */
static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
struct cifs_open_info_data *data,
@@ -699,20 +864,14 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
fattr->cf_nlink = le32_to_cpu(info->HardLinks);
- fattr->cf_mode = (umode_t) le32_to_cpu(info->Mode);
+ fattr->cf_mode = wire_mode_to_posix(le32_to_cpu(info->Mode),
+ fattr->cf_cifsattrs & ATTR_DIRECTORY);
if (cifs_open_data_reparse(data) &&
cifs_reparse_point_to_fattr(cifs_sb, fattr, data))
goto out_reparse;
- fattr->cf_mode &= ~S_IFMT;
- if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
- fattr->cf_mode |= S_IFDIR;
- fattr->cf_dtype = DT_DIR;
- } else { /* file */
- fattr->cf_mode |= S_IFREG;
- fattr->cf_dtype = DT_REG;
- }
+ fattr->cf_dtype = S_DT(fattr->cf_mode);
out_reparse:
if (S_ISLNK(fattr->cf_mode)) {
@@ -779,10 +938,6 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
fattr->cf_dtype = DT_REG;
- /* clear write bits if ATTR_READONLY is set */
- if (fattr->cf_cifsattrs & ATTR_READONLY)
- fattr->cf_mode &= ~(S_IWUGO);
-
/*
* Don't accept zero nlink from non-unix servers unless
* delete is pending. Instead mark it as unknown.
@@ -795,6 +950,10 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
}
}
+ /* clear write bits if ATTR_READONLY is set */
+ if (fattr->cf_cifsattrs & ATTR_READONLY)
+ fattr->cf_mode &= ~(S_IWUGO);
+
out_reparse:
if (S_ISLNK(fattr->cf_mode)) {
if (likely(data->symlink_target))
@@ -831,7 +990,7 @@ cifs_get_file_info(struct file *filp)
/* TODO: add support to query reparse tag */
data.adjust_tz = false;
if (data.symlink_target) {
- data.symlink = true;
+ data.reparse_point = true;
data.reparse.tag = IO_REPARSE_TAG_SYMLINK;
}
path = build_path_from_dentry(dentry, page);
@@ -1023,25 +1182,66 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
}
rc = -EOPNOTSUPP;
- switch ((data->reparse.tag = tag)) {
- case 0: /* SMB1 symlink */
+ data->reparse.tag = tag;
+ if (!data->reparse.tag) {
if (server->ops->query_symlink) {
rc = server->ops->query_symlink(xid, tcon,
cifs_sb, full_path,
&data->symlink_target);
}
+ if (rc == -EOPNOTSUPP)
+ data->reparse.tag = IO_REPARSE_TAG_INTERNAL;
+ }
+
+ switch (data->reparse.tag) {
+ case 0: /* SMB1 symlink */
break;
- case IO_REPARSE_TAG_MOUNT_POINT:
- cifs_create_junction_fattr(fattr, sb);
+ case IO_REPARSE_TAG_INTERNAL:
rc = 0;
- goto out;
+ if (le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY) {
+ cifs_create_junction_fattr(fattr, sb);
+ goto out;
+ }
+ break;
default:
/* Check for cached reparse point data */
if (data->symlink_target || data->reparse.buf) {
rc = 0;
- } else if (iov && server->ops->parse_reparse_point) {
- rc = server->ops->parse_reparse_point(cifs_sb,
- iov, data);
+ } else if (iov && server->ops->get_reparse_point_buffer) {
+ struct reparse_data_buffer *reparse_buf;
+ u32 reparse_len;
+
+ reparse_buf = server->ops->get_reparse_point_buffer(iov, &reparse_len);
+ rc = parse_reparse_point(reparse_buf, reparse_len,
+ cifs_sb, full_path, data);
+ /*
+ * If the reparse point was not handled but it is the
+ * name surrogate which points to directory, then treat
+ * is as a new mount point. Name surrogate reparse point
+ * represents another named entity in the system.
+ */
+ if (rc == -EOPNOTSUPP &&
+ IS_REPARSE_TAG_NAME_SURROGATE(data->reparse.tag) &&
+ (le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY)) {
+ rc = 0;
+ cifs_create_junction_fattr(fattr, sb);
+ goto out;
+ }
+ /*
+ * If the reparse point is unsupported by the Linux SMB
+ * client then let it process by the SMB server. So mask
+ * the -EOPNOTSUPP error code. This will allow Linux SMB
+ * client to send SMB OPEN request to server. If server
+ * does not support this reparse point too then server
+ * will return error during open the path.
+ */
+ if (rc == -EOPNOTSUPP)
+ rc = 0;
+ }
+
+ if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) {
+ bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY;
+ rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb);
}
break;
}
@@ -1199,11 +1399,14 @@ handle_mnt_opt:
__func__, rc);
goto out;
}
- }
-
- /* fill in remaining high mode bits e.g. SUID, VTX */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
+ /* fill in remaining high mode bits e.g. SUID, VTX */
cifs_sfu_mode(fattr, full_path, cifs_sb, xid);
+ else if (!(tcon->posix_extensions))
+ /* clear write bits if ATTR_READONLY is set */
+ if (fattr->cf_cifsattrs & ATTR_READONLY)
+ fattr->cf_mode &= ~(S_IWUGO);
+
/* check for Minshall+French symlinks */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
@@ -1227,7 +1430,7 @@ int cifs_get_inode_info(struct inode **inode,
struct cifs_fattr fattr = {};
int rc;
- if (is_inode_cache_good(*inode)) {
+ if (!data && is_inode_cache_good(*inode)) {
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
return 0;
}
@@ -1326,7 +1529,7 @@ int smb311_posix_get_inode_info(struct inode **inode,
struct cifs_fattr fattr = {};
int rc;
- if (is_inode_cache_good(*inode)) {
+ if (!data && is_inode_cache_good(*inode)) {
cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
return 0;
}
@@ -1771,6 +1974,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
goto unlink_out;
}
+ netfs_wait_for_outstanding_io(inode);
cifs_close_deferred_file_under_dentry(tcon, full_path);
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
@@ -2012,8 +2216,8 @@ posix_mkdir_get_info:
}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
-int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode,
- struct dentry *direntry, umode_t mode)
+struct dentry *cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode,
+ struct dentry *direntry, umode_t mode)
{
int rc = 0;
unsigned int xid;
@@ -2029,10 +2233,10 @@ int cifs_mkdir(struct mnt_idmap *idmap, struct inode *inode,
cifs_sb = CIFS_SB(inode->i_sb);
if (unlikely(cifs_forced_shutdown(cifs_sb)))
- return -EIO;
+ return ERR_PTR(-EIO);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
- return PTR_ERR(tlink);
+ return ERR_CAST(tlink);
tcon = tlink_tcon(tlink);
xid = get_xid();
@@ -2088,7 +2292,7 @@ mkdir_out:
free_dentry_path(page);
free_xid(xid);
cifs_put_tlink(tlink);
- return rc;
+ return ERR_PTR(rc);
}
int cifs_rmdir(struct inode *inode, struct dentry *direntry)
@@ -2215,6 +2419,13 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
if (to_dentry->d_parent != from_dentry->d_parent)
goto do_rename_exit;
+ /*
+ * CIFSSMBRenameOpenFile() uses SMB_SET_FILE_RENAME_INFORMATION
+ * which is SMB PASSTHROUGH level.
+ */
+ if (!(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU))
+ goto do_rename_exit;
+
oparms = (struct cifs_open_parms) {
.tcon = tcon,
.cifs_sb = cifs_sb,
@@ -2288,8 +2499,10 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir,
}
cifs_close_deferred_file_under_dentry(tcon, from_name);
- if (d_inode(target_dentry) != NULL)
+ if (d_inode(target_dentry) != NULL) {
+ netfs_wait_for_outstanding_io(d_inode(target_dentry));
cifs_close_deferred_file_under_dentry(tcon, to_name);
+ }
rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
to_name);
@@ -2396,13 +2609,10 @@ cifs_dentry_needs_reval(struct dentry *dentry)
return true;
if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) {
- spin_lock(&cfid->fid_lock);
if (cfid->time && cifs_i->time > cfid->time) {
- spin_unlock(&cfid->fid_lock);
close_cached_dir(cfid);
return false;
}
- spin_unlock(&cfid->fid_lock);
close_cached_dir(cfid);
}
/*
@@ -2431,24 +2641,6 @@ cifs_dentry_needs_reval(struct dentry *dentry)
return false;
}
-/*
- * Zap the cache. Called when invalid_mapping flag is set.
- */
-int
-cifs_invalidate_mapping(struct inode *inode)
-{
- int rc = 0;
-
- if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
- rc = invalidate_inode_pages2(inode->i_mapping);
- if (rc)
- cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n",
- __func__, inode, rc);
- }
-
- return rc;
-}
-
/**
* cifs_wait_bit_killable - helper for functions that are sleeping on bit locks
*
@@ -2468,7 +2660,8 @@ int
cifs_revalidate_mapping(struct inode *inode)
{
int rc;
- unsigned long *flags = &CIFS_I(inode)->flags;
+ struct cifsInodeInfo *cifs_inode = CIFS_I(inode);
+ unsigned long *flags = &cifs_inode->flags;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
/* swapfiles are not supposed to be shared */
@@ -2485,9 +2678,13 @@ cifs_revalidate_mapping(struct inode *inode)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)
goto skip_invalidate;
- rc = cifs_invalidate_mapping(inode);
- if (rc)
+ cifs_inode->netfs.zero_point = cifs_inode->netfs.remote_i_size;
+ rc = filemap_invalidate_inode(inode, true, 0, LLONG_MAX);
+ if (rc) {
+ cifs_dbg(VFS, "%s: invalidate inode %p failed with rc %d\n",
+ __func__, inode, rc);
set_bit(CIFS_INO_INVALID_MAPPING, flags);
+ }
}
skip_invalidate:
@@ -2713,23 +2910,6 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
return -EOPNOTSUPP;
}
-int cifs_truncate_page(struct address_space *mapping, loff_t from)
-{
- pgoff_t index = from >> PAGE_SHIFT;
- unsigned offset = from & (PAGE_SIZE - 1);
- struct page *page;
- int rc = 0;
-
- page = grab_cache_page(mapping, index);
- if (!page)
- return -ENOMEM;
-
- zero_user_segment(page, offset, PAGE_SIZE);
- unlock_page(page);
- put_page(page);
- return rc;
-}
-
void cifs_setsize(struct inode *inode, loff_t offset)
{
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
@@ -2824,8 +3004,6 @@ set_size_out:
*/
attrs->ia_ctime = attrs->ia_mtime = current_time(inode);
attrs->ia_valid |= ATTR_CTIME | ATTR_MTIME;
-
- cifs_truncate_page(inode->i_mapping, inode->i_size);
}
return rc;
@@ -2998,6 +3176,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
int rc = -EACCES;
__u32 dosattr = 0;
__u64 mode = NO_CHANGE_64;
+ bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
xid = get_xid();
@@ -3088,7 +3267,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
mode = attrs->ia_mode;
rc = 0;
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
- (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
+ (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) ||
+ posix) {
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
INVALID_UID, INVALID_GID);
if (rc) {