summaryrefslogtreecommitdiffstats
path: root/fs/cifs/misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/misc.c')
-rw-r--r--fs/cifs/misc.c142
1 files changed, 119 insertions, 23 deletions
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index a456febd4109..56791a692c8b 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -32,6 +32,9 @@
#include "cifs_unicode.h"
#include "smb2pdu.h"
#include "cifsfs.h"
+#ifdef CONFIG_CIFS_DFS_UPCALL
+#include "dns_resolve.h"
+#endif
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
@@ -421,7 +424,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
if (data_offset >
len - sizeof(struct file_notify_information)) {
- cifs_dbg(FYI, "invalid data_offset %u\n",
+ cifs_dbg(FYI, "Invalid data_offset %u\n",
data_offset);
return true;
}
@@ -449,7 +452,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
large dirty files cached on the client */
if ((NT_STATUS_INVALID_HANDLE) ==
le32_to_cpu(pSMB->hdr.Status.CifsError)) {
- cifs_dbg(FYI, "invalid handle on oplock break\n");
+ cifs_dbg(FYI, "Invalid handle on oplock break\n");
return true;
} else if (ERRbadfid ==
le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
@@ -530,9 +533,9 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
cifs_sb->mnt_cifs_serverino_autodisabled = true;
- cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s.\n",
+ cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s\n",
tcon ? tcon->treeName : "new server");
- cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS).\n");
+ cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS)\n");
cifs_dbg(VFS, "Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n");
}
@@ -874,7 +877,7 @@ setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
while (count && npages < max_pages) {
rc = iov_iter_get_pages(iter, pages, count, max_pages, &start);
if (rc < 0) {
- cifs_dbg(VFS, "couldn't get user pages (rc=%zd)\n", rc);
+ cifs_dbg(VFS, "Couldn't get user pages (rc=%zd)\n", rc);
break;
}
@@ -933,7 +936,7 @@ cifs_alloc_hash(const char *name,
*shash = crypto_alloc_shash(name, 0, 0);
if (IS_ERR(*shash)) {
- cifs_dbg(VFS, "could not allocate crypto %s\n", name);
+ cifs_dbg(VFS, "Could not allocate crypto %s\n", name);
rc = PTR_ERR(*shash);
*shash = NULL;
*sdesc = NULL;
@@ -1025,51 +1028,144 @@ int copy_path_name(char *dst, const char *src)
}
struct super_cb_data {
- struct TCP_Server_Info *server;
+ void *data;
struct super_block *sb;
};
-static void super_cb(struct super_block *sb, void *arg)
+static void tcp_super_cb(struct super_block *sb, void *arg)
{
- struct super_cb_data *d = arg;
+ struct super_cb_data *sd = arg;
+ struct TCP_Server_Info *server = sd->data;
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
- if (d->sb)
+ if (sd->sb)
return;
cifs_sb = CIFS_SB(sb);
tcon = cifs_sb_master_tcon(cifs_sb);
- if (tcon->ses->server == d->server)
- d->sb = sb;
+ if (tcon->ses->server == server)
+ sd->sb = sb;
}
-struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server)
+static struct super_block *__cifs_get_super(void (*f)(struct super_block *, void *),
+ void *data)
{
- struct super_cb_data d = {
- .server = server,
+ struct super_cb_data sd = {
+ .data = data,
.sb = NULL,
};
- iterate_supers_type(&cifs_fs_type, super_cb, &d);
+ iterate_supers_type(&cifs_fs_type, f, &sd);
- if (unlikely(!d.sb))
- return ERR_PTR(-ENOENT);
+ if (!sd.sb)
+ return ERR_PTR(-EINVAL);
/*
* Grab an active reference in order to prevent automounts (DFS links)
* of expiring and then freeing up our cifs superblock pointer while
* we're doing failover.
*/
- cifs_sb_active(d.sb);
- return d.sb;
+ cifs_sb_active(sd.sb);
+ return sd.sb;
}
-void cifs_put_tcp_super(struct super_block *sb)
+static void __cifs_put_super(struct super_block *sb)
{
if (!IS_ERR_OR_NULL(sb))
cifs_sb_deactive(sb);
}
+struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server)
+{
+ return __cifs_get_super(tcp_super_cb, server);
+}
+
+void cifs_put_tcp_super(struct super_block *sb)
+{
+ __cifs_put_super(sb);
+}
+
+#ifdef CONFIG_CIFS_DFS_UPCALL
+int match_target_ip(struct TCP_Server_Info *server,
+ const char *share, size_t share_len,
+ bool *result)
+{
+ int rc;
+ char *target, *tip = NULL;
+ struct sockaddr tipaddr;
+
+ *result = false;
+
+ target = kzalloc(share_len + 3, GFP_KERNEL);
+ if (!target) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ scnprintf(target, share_len + 3, "\\\\%.*s", (int)share_len, share);
+
+ cifs_dbg(FYI, "%s: target name: %s\n", __func__, target + 2);
+
+ rc = dns_resolve_server_name_to_ip(target, &tip);
+ if (rc < 0)
+ goto out;
+
+ cifs_dbg(FYI, "%s: target ip: %s\n", __func__, tip);
+
+ if (!cifs_convert_address(&tipaddr, tip, strlen(tip))) {
+ cifs_dbg(VFS, "%s: failed to convert target ip address\n",
+ __func__);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ *result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr,
+ &tipaddr);
+ cifs_dbg(FYI, "%s: ip addresses match: %u\n", __func__, *result);
+ rc = 0;
+
+out:
+ kfree(target);
+ kfree(tip);
+
+ return rc;
+}
+
+static void tcon_super_cb(struct super_block *sb, void *arg)
+{
+ struct super_cb_data *sd = arg;
+ struct cifs_tcon *tcon = sd->data;
+ struct cifs_sb_info *cifs_sb;
+
+ if (sd->sb)
+ return;
+
+ cifs_sb = CIFS_SB(sb);
+ if (tcon->dfs_path && cifs_sb->origin_fullpath &&
+ !strcasecmp(tcon->dfs_path, cifs_sb->origin_fullpath))
+ sd->sb = sb;
+}
+
+static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
+{
+ return __cifs_get_super(tcon_super_cb, tcon);
+}
+
+static inline void cifs_put_tcon_super(struct super_block *sb)
+{
+ __cifs_put_super(sb);
+}
+#else
+static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
+static inline void cifs_put_tcon_super(struct super_block *sb)
+{
+}
+#endif
+
int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
size_t prefix_len)
{
@@ -1077,7 +1173,7 @@ int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
struct cifs_sb_info *cifs_sb;
int rc = 0;
- sb = cifs_get_tcp_super(tcon->ses->server);
+ sb = cifs_get_tcon_super(tcon);
if (IS_ERR(sb))
return PTR_ERR(sb);
@@ -1099,6 +1195,6 @@ int update_super_prepath(struct cifs_tcon *tcon, const char *prefix,
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
out:
- cifs_put_tcp_super(sb);
+ cifs_put_tcon_super(sb);
return rc;
}