cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

link.c (17651B)


      1// SPDX-License-Identifier: LGPL-2.1
      2/*
      3 *
      4 *   Copyright (C) International Business Machines  Corp., 2002,2008
      5 *   Author(s): Steve French (sfrench@us.ibm.com)
      6 *
      7 */
      8#include <linux/fs.h>
      9#include <linux/stat.h>
     10#include <linux/slab.h>
     11#include <linux/namei.h>
     12#include "cifsfs.h"
     13#include "cifspdu.h"
     14#include "cifsglob.h"
     15#include "cifsproto.h"
     16#include "cifs_debug.h"
     17#include "cifs_fs_sb.h"
     18#include "cifs_unicode.h"
     19#include "smb2proto.h"
     20#include "cifs_ioctl.h"
     21
     22/*
     23 * M-F Symlink Functions - Begin
     24 */
     25
     26#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
     27#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
     28#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
     29#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
     30#define CIFS_MF_SYMLINK_FILE_SIZE \
     31	(CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
     32
     33#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
     34#define CIFS_MF_SYMLINK_MD5_FORMAT "%16phN\n"
     35#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) md5_hash
     36
     37static int
     38symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
     39{
     40	int rc;
     41	struct crypto_shash *md5 = NULL;
     42	struct sdesc *sdescmd5 = NULL;
     43
     44	rc = cifs_alloc_hash("md5", &md5, &sdescmd5);
     45	if (rc)
     46		goto symlink_hash_err;
     47
     48	rc = crypto_shash_init(&sdescmd5->shash);
     49	if (rc) {
     50		cifs_dbg(VFS, "%s: Could not init md5 shash\n", __func__);
     51		goto symlink_hash_err;
     52	}
     53	rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len);
     54	if (rc) {
     55		cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__);
     56		goto symlink_hash_err;
     57	}
     58	rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
     59	if (rc)
     60		cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
     61
     62symlink_hash_err:
     63	cifs_free_hash(&md5, &sdescmd5);
     64	return rc;
     65}
     66
     67static int
     68parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len,
     69		 char **_link_str)
     70{
     71	int rc;
     72	unsigned int link_len;
     73	const char *md5_str1;
     74	const char *link_str;
     75	u8 md5_hash[16];
     76	char md5_str2[34];
     77
     78	if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
     79		return -EINVAL;
     80
     81	md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET];
     82	link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET];
     83
     84	rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len);
     85	if (rc != 1)
     86		return -EINVAL;
     87
     88	if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
     89		return -EINVAL;
     90
     91	rc = symlink_hash(link_len, link_str, md5_hash);
     92	if (rc) {
     93		cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
     94		return rc;
     95	}
     96
     97	scnprintf(md5_str2, sizeof(md5_str2),
     98		  CIFS_MF_SYMLINK_MD5_FORMAT,
     99		  CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
    100
    101	if (strncmp(md5_str1, md5_str2, 17) != 0)
    102		return -EINVAL;
    103
    104	if (_link_str) {
    105		*_link_str = kstrndup(link_str, link_len, GFP_KERNEL);
    106		if (!*_link_str)
    107			return -ENOMEM;
    108	}
    109
    110	*_link_len = link_len;
    111	return 0;
    112}
    113
    114static int
    115format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str)
    116{
    117	int rc;
    118	unsigned int link_len;
    119	unsigned int ofs;
    120	u8 md5_hash[16];
    121
    122	if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
    123		return -EINVAL;
    124
    125	link_len = strlen(link_str);
    126
    127	if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
    128		return -ENAMETOOLONG;
    129
    130	rc = symlink_hash(link_len, link_str, md5_hash);
    131	if (rc) {
    132		cifs_dbg(FYI, "%s: MD5 hash failure: %d\n", __func__, rc);
    133		return rc;
    134	}
    135
    136	scnprintf(buf, buf_len,
    137		  CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
    138		  link_len,
    139		  CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
    140
    141	ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
    142	memcpy(buf + ofs, link_str, link_len);
    143
    144	ofs += link_len;
    145	if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
    146		buf[ofs] = '\n';
    147		ofs++;
    148	}
    149
    150	while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
    151		buf[ofs] = ' ';
    152		ofs++;
    153	}
    154
    155	return 0;
    156}
    157
    158bool
    159couldbe_mf_symlink(const struct cifs_fattr *fattr)
    160{
    161	if (!S_ISREG(fattr->cf_mode))
    162		/* it's not a symlink */
    163		return false;
    164
    165	if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
    166		/* it's not a symlink */
    167		return false;
    168
    169	return true;
    170}
    171
    172static int
    173create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
    174		  struct cifs_sb_info *cifs_sb, const char *fromName,
    175		  const char *toName)
    176{
    177	int rc;
    178	u8 *buf;
    179	unsigned int bytes_written = 0;
    180
    181	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
    182	if (!buf)
    183		return -ENOMEM;
    184
    185	rc = format_mf_symlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
    186	if (rc)
    187		goto out;
    188
    189	if (tcon->ses->server->ops->create_mf_symlink)
    190		rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon,
    191					cifs_sb, fromName, buf, &bytes_written);
    192	else
    193		rc = -EOPNOTSUPP;
    194
    195	if (rc)
    196		goto out;
    197
    198	if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
    199		rc = -EIO;
    200out:
    201	kfree(buf);
    202	return rc;
    203}
    204
    205static int
    206query_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
    207		 struct cifs_sb_info *cifs_sb, const unsigned char *path,
    208		 char **symlinkinfo)
    209{
    210	int rc;
    211	u8 *buf = NULL;
    212	unsigned int link_len = 0;
    213	unsigned int bytes_read = 0;
    214
    215	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
    216	if (!buf)
    217		return -ENOMEM;
    218
    219	if (tcon->ses->server->ops->query_mf_symlink)
    220		rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
    221					      cifs_sb, path, buf, &bytes_read);
    222	else
    223		rc = -ENOSYS;
    224
    225	if (rc)
    226		goto out;
    227
    228	if (bytes_read == 0) { /* not a symlink */
    229		rc = -EINVAL;
    230		goto out;
    231	}
    232
    233	rc = parse_mf_symlink(buf, bytes_read, &link_len, symlinkinfo);
    234out:
    235	kfree(buf);
    236	return rc;
    237}
    238
    239int
    240check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
    241		 struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
    242		 const unsigned char *path)
    243{
    244	int rc;
    245	u8 *buf = NULL;
    246	unsigned int link_len = 0;
    247	unsigned int bytes_read = 0;
    248
    249	if (!couldbe_mf_symlink(fattr))
    250		/* it's not a symlink */
    251		return 0;
    252
    253	buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
    254	if (!buf)
    255		return -ENOMEM;
    256
    257	if (tcon->ses->server->ops->query_mf_symlink)
    258		rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon,
    259					      cifs_sb, path, buf, &bytes_read);
    260	else
    261		rc = -ENOSYS;
    262
    263	if (rc)
    264		goto out;
    265
    266	if (bytes_read == 0) /* not a symlink */
    267		goto out;
    268
    269	rc = parse_mf_symlink(buf, bytes_read, &link_len, NULL);
    270	if (rc == -EINVAL) {
    271		/* it's not a symlink */
    272		rc = 0;
    273		goto out;
    274	}
    275
    276	if (rc != 0)
    277		goto out;
    278
    279	/* it is a symlink */
    280	fattr->cf_eof = link_len;
    281	fattr->cf_mode &= ~S_IFMT;
    282	fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
    283	fattr->cf_dtype = DT_LNK;
    284out:
    285	kfree(buf);
    286	return rc;
    287}
    288
    289/*
    290 * SMB 1.0 Protocol specific functions
    291 */
    292
    293int
    294cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
    295		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
    296		      char *pbuf, unsigned int *pbytes_read)
    297{
    298	int rc;
    299	int oplock = 0;
    300	struct cifs_fid fid;
    301	struct cifs_open_parms oparms;
    302	struct cifs_io_parms io_parms = {0};
    303	int buf_type = CIFS_NO_BUFFER;
    304	FILE_ALL_INFO file_info;
    305
    306	oparms.tcon = tcon;
    307	oparms.cifs_sb = cifs_sb;
    308	oparms.desired_access = GENERIC_READ;
    309	oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
    310	oparms.disposition = FILE_OPEN;
    311	oparms.path = path;
    312	oparms.fid = &fid;
    313	oparms.reconnect = false;
    314
    315	rc = CIFS_open(xid, &oparms, &oplock, &file_info);
    316	if (rc)
    317		return rc;
    318
    319	if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
    320		rc = -ENOENT;
    321		/* it's not a symlink */
    322		goto out;
    323	}
    324
    325	io_parms.netfid = fid.netfid;
    326	io_parms.pid = current->tgid;
    327	io_parms.tcon = tcon;
    328	io_parms.offset = 0;
    329	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
    330
    331	rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
    332out:
    333	CIFSSMBClose(xid, tcon, fid.netfid);
    334	return rc;
    335}
    336
    337int
    338cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
    339		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
    340		       char *pbuf, unsigned int *pbytes_written)
    341{
    342	int rc;
    343	int oplock = 0;
    344	struct cifs_fid fid;
    345	struct cifs_open_parms oparms;
    346	struct cifs_io_parms io_parms = {0};
    347
    348	oparms.tcon = tcon;
    349	oparms.cifs_sb = cifs_sb;
    350	oparms.desired_access = GENERIC_WRITE;
    351	oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
    352	oparms.disposition = FILE_CREATE;
    353	oparms.path = path;
    354	oparms.fid = &fid;
    355	oparms.reconnect = false;
    356
    357	rc = CIFS_open(xid, &oparms, &oplock, NULL);
    358	if (rc)
    359		return rc;
    360
    361	io_parms.netfid = fid.netfid;
    362	io_parms.pid = current->tgid;
    363	io_parms.tcon = tcon;
    364	io_parms.offset = 0;
    365	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
    366
    367	rc = CIFSSMBWrite(xid, &io_parms, pbytes_written, pbuf);
    368	CIFSSMBClose(xid, tcon, fid.netfid);
    369	return rc;
    370}
    371
    372/*
    373 * SMB 2.1/SMB3 Protocol specific functions
    374 */
    375int
    376smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
    377		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
    378		      char *pbuf, unsigned int *pbytes_read)
    379{
    380	int rc;
    381	struct cifs_fid fid;
    382	struct cifs_open_parms oparms;
    383	struct cifs_io_parms io_parms = {0};
    384	int buf_type = CIFS_NO_BUFFER;
    385	__le16 *utf16_path;
    386	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
    387	struct smb2_file_all_info *pfile_info = NULL;
    388
    389	oparms.tcon = tcon;
    390	oparms.cifs_sb = cifs_sb;
    391	oparms.desired_access = GENERIC_READ;
    392	oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
    393	oparms.disposition = FILE_OPEN;
    394	oparms.fid = &fid;
    395	oparms.reconnect = false;
    396
    397	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
    398	if (utf16_path == NULL)
    399		return -ENOMEM;
    400
    401	pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
    402			     GFP_KERNEL);
    403
    404	if (pfile_info == NULL) {
    405		kfree(utf16_path);
    406		return  -ENOMEM;
    407	}
    408
    409	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL,
    410		       NULL, NULL);
    411	if (rc)
    412		goto qmf_out_open_fail;
    413
    414	if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
    415		/* it's not a symlink */
    416		rc = -ENOENT; /* Is there a better rc to return? */
    417		goto qmf_out;
    418	}
    419
    420	io_parms.netfid = fid.netfid;
    421	io_parms.pid = current->tgid;
    422	io_parms.tcon = tcon;
    423	io_parms.offset = 0;
    424	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
    425	io_parms.persistent_fid = fid.persistent_fid;
    426	io_parms.volatile_fid = fid.volatile_fid;
    427	rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
    428qmf_out:
    429	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
    430qmf_out_open_fail:
    431	kfree(utf16_path);
    432	kfree(pfile_info);
    433	return rc;
    434}
    435
    436int
    437smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
    438		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
    439		       char *pbuf, unsigned int *pbytes_written)
    440{
    441	int rc;
    442	struct cifs_fid fid;
    443	struct cifs_open_parms oparms;
    444	struct cifs_io_parms io_parms = {0};
    445	__le16 *utf16_path;
    446	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
    447	struct kvec iov[2];
    448
    449	cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
    450
    451	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
    452	if (!utf16_path)
    453		return -ENOMEM;
    454
    455	oparms.tcon = tcon;
    456	oparms.cifs_sb = cifs_sb;
    457	oparms.desired_access = GENERIC_WRITE;
    458	oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
    459	oparms.disposition = FILE_CREATE;
    460	oparms.fid = &fid;
    461	oparms.reconnect = false;
    462
    463	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
    464		       NULL, NULL);
    465	if (rc) {
    466		kfree(utf16_path);
    467		return rc;
    468	}
    469
    470	io_parms.netfid = fid.netfid;
    471	io_parms.pid = current->tgid;
    472	io_parms.tcon = tcon;
    473	io_parms.offset = 0;
    474	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
    475	io_parms.persistent_fid = fid.persistent_fid;
    476	io_parms.volatile_fid = fid.volatile_fid;
    477
    478	/* iov[0] is reserved for smb header */
    479	iov[1].iov_base = pbuf;
    480	iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
    481
    482	rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
    483
    484	/* Make sure we wrote all of the symlink data */
    485	if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
    486		rc = -EIO;
    487
    488	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
    489
    490	kfree(utf16_path);
    491	return rc;
    492}
    493
    494/*
    495 * M-F Symlink Functions - End
    496 */
    497
    498int
    499cifs_hardlink(struct dentry *old_file, struct inode *inode,
    500	      struct dentry *direntry)
    501{
    502	int rc = -EACCES;
    503	unsigned int xid;
    504	const char *from_name, *to_name;
    505	void *page1, *page2;
    506	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
    507	struct tcon_link *tlink;
    508	struct cifs_tcon *tcon;
    509	struct TCP_Server_Info *server;
    510	struct cifsInodeInfo *cifsInode;
    511
    512	if (unlikely(cifs_forced_shutdown(cifs_sb)))
    513		return -EIO;
    514
    515	tlink = cifs_sb_tlink(cifs_sb);
    516	if (IS_ERR(tlink))
    517		return PTR_ERR(tlink);
    518	tcon = tlink_tcon(tlink);
    519
    520	xid = get_xid();
    521	page1 = alloc_dentry_path();
    522	page2 = alloc_dentry_path();
    523
    524	from_name = build_path_from_dentry(old_file, page1);
    525	if (IS_ERR(from_name)) {
    526		rc = PTR_ERR(from_name);
    527		goto cifs_hl_exit;
    528	}
    529	to_name = build_path_from_dentry(direntry, page2);
    530	if (IS_ERR(to_name)) {
    531		rc = PTR_ERR(to_name);
    532		goto cifs_hl_exit;
    533	}
    534
    535	if (tcon->unix_ext)
    536		rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
    537					    cifs_sb->local_nls,
    538					    cifs_remap(cifs_sb));
    539	else {
    540		server = tcon->ses->server;
    541		if (!server->ops->create_hardlink) {
    542			rc = -ENOSYS;
    543			goto cifs_hl_exit;
    544		}
    545		rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
    546						  cifs_sb);
    547		if ((rc == -EIO) || (rc == -EINVAL))
    548			rc = -EOPNOTSUPP;
    549	}
    550
    551	d_drop(direntry);	/* force new lookup from server of target */
    552
    553	/*
    554	 * if source file is cached (oplocked) revalidate will not go to server
    555	 * until the file is closed or oplock broken so update nlinks locally
    556	 */
    557	if (d_really_is_positive(old_file)) {
    558		cifsInode = CIFS_I(d_inode(old_file));
    559		if (rc == 0) {
    560			spin_lock(&d_inode(old_file)->i_lock);
    561			inc_nlink(d_inode(old_file));
    562			spin_unlock(&d_inode(old_file)->i_lock);
    563
    564			/*
    565			 * parent dir timestamps will update from srv within a
    566			 * second, would it really be worth it to set the parent
    567			 * dir cifs inode time to zero to force revalidate
    568			 * (faster) for it too?
    569			 */
    570		}
    571		/*
    572		 * if not oplocked will force revalidate to get info on source
    573		 * file from srv.  Note Samba server prior to 4.2 has bug -
    574		 * not updating src file ctime on hardlinks but Windows servers
    575		 * handle it properly
    576		 */
    577		cifsInode->time = 0;
    578
    579		/*
    580		 * Will update parent dir timestamps from srv within a second.
    581		 * Would it really be worth it to set the parent dir (cifs
    582		 * inode) time field to zero to force revalidate on parent
    583		 * directory faster ie
    584		 *
    585		 * CIFS_I(inode)->time = 0;
    586		 */
    587	}
    588
    589cifs_hl_exit:
    590	free_dentry_path(page1);
    591	free_dentry_path(page2);
    592	free_xid(xid);
    593	cifs_put_tlink(tlink);
    594	return rc;
    595}
    596
    597const char *
    598cifs_get_link(struct dentry *direntry, struct inode *inode,
    599	      struct delayed_call *done)
    600{
    601	int rc = -ENOMEM;
    602	unsigned int xid;
    603	const char *full_path;
    604	void *page;
    605	char *target_path = NULL;
    606	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
    607	struct tcon_link *tlink = NULL;
    608	struct cifs_tcon *tcon;
    609	struct TCP_Server_Info *server;
    610
    611	if (!direntry)
    612		return ERR_PTR(-ECHILD);
    613
    614	xid = get_xid();
    615
    616	tlink = cifs_sb_tlink(cifs_sb);
    617	if (IS_ERR(tlink)) {
    618		free_xid(xid);
    619		return ERR_CAST(tlink);
    620	}
    621	tcon = tlink_tcon(tlink);
    622	server = tcon->ses->server;
    623
    624	page = alloc_dentry_path();
    625	full_path = build_path_from_dentry(direntry, page);
    626	if (IS_ERR(full_path)) {
    627		free_xid(xid);
    628		cifs_put_tlink(tlink);
    629		free_dentry_path(page);
    630		return ERR_CAST(full_path);
    631	}
    632
    633	cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode);
    634
    635	rc = -EACCES;
    636	/*
    637	 * First try Minshall+French Symlinks, if configured
    638	 * and fallback to UNIX Extensions Symlinks.
    639	 */
    640	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
    641		rc = query_mf_symlink(xid, tcon, cifs_sb, full_path,
    642				      &target_path);
    643
    644	if (rc != 0 && server->ops->query_symlink) {
    645		struct cifsInodeInfo *cifsi = CIFS_I(inode);
    646		bool reparse_point = false;
    647
    648		if (cifsi->cifsAttrs & ATTR_REPARSE)
    649			reparse_point = true;
    650
    651		rc = server->ops->query_symlink(xid, tcon, cifs_sb, full_path,
    652						&target_path, reparse_point);
    653	}
    654
    655	free_dentry_path(page);
    656	free_xid(xid);
    657	cifs_put_tlink(tlink);
    658	if (rc != 0) {
    659		kfree(target_path);
    660		return ERR_PTR(rc);
    661	}
    662	set_delayed_call(done, kfree_link, target_path);
    663	return target_path;
    664}
    665
    666int
    667cifs_symlink(struct user_namespace *mnt_userns, struct inode *inode,
    668	     struct dentry *direntry, const char *symname)
    669{
    670	int rc = -EOPNOTSUPP;
    671	unsigned int xid;
    672	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
    673	struct tcon_link *tlink;
    674	struct cifs_tcon *pTcon;
    675	const char *full_path;
    676	void *page;
    677	struct inode *newinode = NULL;
    678
    679	if (unlikely(cifs_forced_shutdown(cifs_sb)))
    680		return -EIO;
    681
    682	page = alloc_dentry_path();
    683	if (!page)
    684		return -ENOMEM;
    685
    686	xid = get_xid();
    687
    688	tlink = cifs_sb_tlink(cifs_sb);
    689	if (IS_ERR(tlink)) {
    690		rc = PTR_ERR(tlink);
    691		goto symlink_exit;
    692	}
    693	pTcon = tlink_tcon(tlink);
    694
    695	full_path = build_path_from_dentry(direntry, page);
    696	if (IS_ERR(full_path)) {
    697		rc = PTR_ERR(full_path);
    698		goto symlink_exit;
    699	}
    700
    701	cifs_dbg(FYI, "Full path: %s\n", full_path);
    702	cifs_dbg(FYI, "symname is %s\n", symname);
    703
    704	/* BB what if DFS and this volume is on different share? BB */
    705	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
    706		rc = create_mf_symlink(xid, pTcon, cifs_sb, full_path, symname);
    707	else if (pTcon->unix_ext)
    708		rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
    709					   cifs_sb->local_nls,
    710					   cifs_remap(cifs_sb));
    711	/* else
    712	   rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
    713					cifs_sb_target->local_nls); */
    714
    715	if (rc == 0) {
    716		if (pTcon->posix_extensions)
    717			rc = smb311_posix_get_inode_info(&newinode, full_path, inode->i_sb, xid);
    718		else if (pTcon->unix_ext)
    719			rc = cifs_get_inode_info_unix(&newinode, full_path,
    720						      inode->i_sb, xid);
    721		else
    722			rc = cifs_get_inode_info(&newinode, full_path, NULL,
    723						 inode->i_sb, xid, NULL);
    724
    725		if (rc != 0) {
    726			cifs_dbg(FYI, "Create symlink ok, getinodeinfo fail rc = %d\n",
    727				 rc);
    728		} else {
    729			d_instantiate(direntry, newinode);
    730		}
    731	}
    732symlink_exit:
    733	free_dentry_path(page);
    734	cifs_put_tlink(tlink);
    735	free_xid(xid);
    736	return rc;
    737}