]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - fs/cifs/link.c
CIFS: Use pid saved from cifsFileInfo in writepages and set_file_size
[mirror_ubuntu-jammy-kernel.git] / fs / cifs / link.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/link.c
3 *
366781c1 4 * Copyright (C) International Business Machines Corp., 2002,2008
1da177e4
LT
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/fs.h>
22#include <linux/stat.h>
5a0e3ad6 23#include <linux/slab.h>
1da177e4
LT
24#include <linux/namei.h>
25#include "cifsfs.h"
26#include "cifspdu.h"
27#include "cifsglob.h"
28#include "cifsproto.h"
29#include "cifs_debug.h"
30#include "cifs_fs_sb.h"
c69c1b6e
SM
31
32#define CIFS_MF_SYMLINK_LEN_OFFSET (4+1)
33#define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1))
34#define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1))
35#define CIFS_MF_SYMLINK_LINK_MAXLEN (1024)
36#define CIFS_MF_SYMLINK_FILE_SIZE \
37 (CIFS_MF_SYMLINK_LINK_OFFSET + CIFS_MF_SYMLINK_LINK_MAXLEN)
38
39#define CIFS_MF_SYMLINK_LEN_FORMAT "XSym\n%04u\n"
40#define CIFS_MF_SYMLINK_MD5_FORMAT \
41 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n"
42#define CIFS_MF_SYMLINK_MD5_ARGS(md5_hash) \
43 md5_hash[0], md5_hash[1], md5_hash[2], md5_hash[3], \
44 md5_hash[4], md5_hash[5], md5_hash[6], md5_hash[7], \
45 md5_hash[8], md5_hash[9], md5_hash[10], md5_hash[11],\
46 md5_hash[12], md5_hash[13], md5_hash[14], md5_hash[15]
47
93c100c0
SF
48static int
49symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash)
50{
51 int rc;
52 unsigned int size;
53 struct crypto_shash *md5;
54 struct sdesc *sdescmd5;
55
56 md5 = crypto_alloc_shash("md5", 0, 0);
ee2c9258 57 if (IS_ERR(md5)) {
ffeb414a 58 rc = PTR_ERR(md5);
93c100c0 59 cERROR(1, "%s: Crypto md5 allocation error %d\n", __func__, rc);
ffeb414a 60 return rc;
93c100c0
SF
61 }
62 size = sizeof(struct shash_desc) + crypto_shash_descsize(md5);
63 sdescmd5 = kmalloc(size, GFP_KERNEL);
64 if (!sdescmd5) {
65 rc = -ENOMEM;
66 cERROR(1, "%s: Memory allocation failure\n", __func__);
67 goto symlink_hash_err;
68 }
69 sdescmd5->shash.tfm = md5;
70 sdescmd5->shash.flags = 0x0;
71
72 rc = crypto_shash_init(&sdescmd5->shash);
73 if (rc) {
74 cERROR(1, "%s: Could not init md5 shash\n", __func__);
75 goto symlink_hash_err;
76 }
77 crypto_shash_update(&sdescmd5->shash, link_str, link_len);
78 rc = crypto_shash_final(&sdescmd5->shash, md5_hash);
79
80symlink_hash_err:
81 crypto_free_shash(md5);
82 kfree(sdescmd5);
83
84 return rc;
85}
86
c69c1b6e
SM
87static int
88CIFSParseMFSymlink(const u8 *buf,
89 unsigned int buf_len,
90 unsigned int *_link_len,
91 char **_link_str)
92{
93 int rc;
94 unsigned int link_len;
95 const char *md5_str1;
96 const char *link_str;
c69c1b6e
SM
97 u8 md5_hash[16];
98 char md5_str2[34];
99
100 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
101 return -EINVAL;
102
103 md5_str1 = (const char *)&buf[CIFS_MF_SYMLINK_MD5_OFFSET];
104 link_str = (const char *)&buf[CIFS_MF_SYMLINK_LINK_OFFSET];
105
106 rc = sscanf(buf, CIFS_MF_SYMLINK_LEN_FORMAT, &link_len);
107 if (rc != 1)
108 return -EINVAL;
109
93c100c0
SF
110 rc = symlink_hash(link_len, link_str, md5_hash);
111 if (rc) {
112 cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
113 return rc;
114 }
c69c1b6e
SM
115
116 snprintf(md5_str2, sizeof(md5_str2),
117 CIFS_MF_SYMLINK_MD5_FORMAT,
118 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
119
120 if (strncmp(md5_str1, md5_str2, 17) != 0)
121 return -EINVAL;
122
123 if (_link_str) {
124 *_link_str = kstrndup(link_str, link_len, GFP_KERNEL);
125 if (!*_link_str)
126 return -ENOMEM;
127 }
128
129 *_link_len = link_len;
130 return 0;
131}
1da177e4 132
0fd43ae4 133static int
18bddd10
SM
134CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
135{
93c100c0 136 int rc;
18bddd10
SM
137 unsigned int link_len;
138 unsigned int ofs;
18bddd10
SM
139 u8 md5_hash[16];
140
141 if (buf_len != CIFS_MF_SYMLINK_FILE_SIZE)
142 return -EINVAL;
143
144 link_len = strlen(link_str);
145
146 if (link_len > CIFS_MF_SYMLINK_LINK_MAXLEN)
147 return -ENAMETOOLONG;
148
93c100c0
SF
149 rc = symlink_hash(link_len, link_str, md5_hash);
150 if (rc) {
151 cFYI(1, "%s: MD5 hash failure: %d\n", __func__, rc);
152 return rc;
153 }
18bddd10
SM
154
155 snprintf(buf, buf_len,
156 CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT,
157 link_len,
158 CIFS_MF_SYMLINK_MD5_ARGS(md5_hash));
159
160 ofs = CIFS_MF_SYMLINK_LINK_OFFSET;
161 memcpy(buf + ofs, link_str, link_len);
162
163 ofs += link_len;
164 if (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
165 buf[ofs] = '\n';
166 ofs++;
167 }
168
169 while (ofs < CIFS_MF_SYMLINK_FILE_SIZE) {
170 buf[ofs] = ' ';
171 ofs++;
172 }
173
174 return 0;
175}
176
8713d01d
SM
177static int
178CIFSCreateMFSymLink(const int xid, struct cifsTconInfo *tcon,
179 const char *fromName, const char *toName,
180 const struct nls_table *nls_codepage, int remap)
181{
182 int rc;
183 int oplock = 0;
184 __u16 netfid = 0;
185 u8 *buf;
186 unsigned int bytes_written = 0;
fa2989f4 187 struct cifs_io_parms io_parms;
8713d01d
SM
188
189 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
190 if (!buf)
191 return -ENOMEM;
192
193 rc = CIFSFormatMFSymlink(buf, CIFS_MF_SYMLINK_FILE_SIZE, toName);
194 if (rc != 0) {
195 kfree(buf);
196 return rc;
197 }
198
199 rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE,
200 CREATE_NOT_DIR, &netfid, &oplock, NULL,
201 nls_codepage, remap);
202 if (rc != 0) {
203 kfree(buf);
204 return rc;
205 }
206
fa2989f4
PS
207 io_parms.netfid = netfid;
208 io_parms.pid = current->tgid;
209 io_parms.tcon = tcon;
210 io_parms.offset = 0;
211 io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
212
213 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, buf, NULL, 0);
8713d01d
SM
214 CIFSSMBClose(xid, tcon, netfid);
215 kfree(buf);
216 if (rc != 0)
217 return rc;
218
219 if (bytes_written != CIFS_MF_SYMLINK_FILE_SIZE)
220 return -EIO;
221
222 return 0;
223}
224
225static int
0fd43ae4
SM
226CIFSQueryMFSymLink(const int xid, struct cifsTconInfo *tcon,
227 const unsigned char *searchName, char **symlinkinfo,
228 const struct nls_table *nls_codepage, int remap)
229{
230 int rc;
231 int oplock = 0;
232 __u16 netfid = 0;
233 u8 *buf;
234 char *pbuf;
235 unsigned int bytes_read = 0;
236 int buf_type = CIFS_NO_BUFFER;
237 unsigned int link_len = 0;
238 FILE_ALL_INFO file_info;
239
240 rc = CIFSSMBOpen(xid, tcon, searchName, FILE_OPEN, GENERIC_READ,
241 CREATE_NOT_DIR, &netfid, &oplock, &file_info,
242 nls_codepage, remap);
243 if (rc != 0)
244 return rc;
245
5443d130 246 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
0fd43ae4
SM
247 CIFSSMBClose(xid, tcon, netfid);
248 /* it's not a symlink */
249 return -EINVAL;
250 }
251
252 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
253 if (!buf)
254 return -ENOMEM;
255 pbuf = buf;
256
257 rc = CIFSSMBRead(xid, tcon, netfid,
258 CIFS_MF_SYMLINK_FILE_SIZE /* length */,
259 0 /* offset */,
260 &bytes_read, &pbuf, &buf_type);
261 CIFSSMBClose(xid, tcon, netfid);
262 if (rc != 0) {
263 kfree(buf);
264 return rc;
265 }
266
267 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, symlinkinfo);
268 kfree(buf);
269 if (rc != 0)
270 return rc;
271
272 return 0;
273}
274
8bfb50a8
SM
275bool
276CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
277{
278 if (!(fattr->cf_mode & S_IFREG))
279 /* it's not a symlink */
280 return false;
281
282 if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE)
283 /* it's not a symlink */
284 return false;
285
286 return true;
287}
288
289int
290CIFSCheckMFSymlink(struct cifs_fattr *fattr,
291 const unsigned char *path,
292 struct cifs_sb_info *cifs_sb, int xid)
293{
294 int rc;
295 int oplock = 0;
296 __u16 netfid = 0;
7ffec372
JL
297 struct tcon_link *tlink;
298 struct cifsTconInfo *pTcon;
8bfb50a8
SM
299 u8 *buf;
300 char *pbuf;
301 unsigned int bytes_read = 0;
302 int buf_type = CIFS_NO_BUFFER;
303 unsigned int link_len = 0;
304 FILE_ALL_INFO file_info;
305
306 if (!CIFSCouldBeMFSymlink(fattr))
307 /* it's not a symlink */
308 return 0;
309
7ffec372
JL
310 tlink = cifs_sb_tlink(cifs_sb);
311 if (IS_ERR(tlink))
312 return PTR_ERR(tlink);
313 pTcon = tlink_tcon(tlink);
314
8bfb50a8
SM
315 rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
316 CREATE_NOT_DIR, &netfid, &oplock, &file_info,
317 cifs_sb->local_nls,
318 cifs_sb->mnt_cifs_flags &
319 CIFS_MOUNT_MAP_SPECIAL_CHR);
320 if (rc != 0)
7ffec372 321 goto out;
8bfb50a8 322
5443d130 323 if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
8bfb50a8
SM
324 CIFSSMBClose(xid, pTcon, netfid);
325 /* it's not a symlink */
7ffec372 326 goto out;
8bfb50a8
SM
327 }
328
329 buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
7ffec372
JL
330 if (!buf) {
331 rc = -ENOMEM;
332 goto out;
333 }
8bfb50a8
SM
334 pbuf = buf;
335
336 rc = CIFSSMBRead(xid, pTcon, netfid,
337 CIFS_MF_SYMLINK_FILE_SIZE /* length */,
338 0 /* offset */,
339 &bytes_read, &pbuf, &buf_type);
340 CIFSSMBClose(xid, pTcon, netfid);
341 if (rc != 0) {
342 kfree(buf);
7ffec372 343 goto out;
8bfb50a8
SM
344 }
345
346 rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
347 kfree(buf);
7ffec372 348 if (rc == -EINVAL) {
8bfb50a8 349 /* it's not a symlink */
7ffec372
JL
350 rc = 0;
351 goto out;
352 }
353
8bfb50a8 354 if (rc != 0)
7ffec372 355 goto out;
8bfb50a8
SM
356
357 /* it is a symlink */
358 fattr->cf_eof = link_len;
359 fattr->cf_mode &= ~S_IFMT;
360 fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
361 fattr->cf_dtype = DT_LNK;
7ffec372
JL
362out:
363 cifs_put_tlink(tlink);
364 return rc;
8bfb50a8
SM
365}
366
1da177e4
LT
367int
368cifs_hardlink(struct dentry *old_file, struct inode *inode,
369 struct dentry *direntry)
370{
371 int rc = -EACCES;
372 int xid;
373 char *fromName = NULL;
374 char *toName = NULL;
7ffec372
JL
375 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
376 struct tcon_link *tlink;
1da177e4
LT
377 struct cifsTconInfo *pTcon;
378 struct cifsInodeInfo *cifsInode;
379
7ffec372
JL
380 tlink = cifs_sb_tlink(cifs_sb);
381 if (IS_ERR(tlink))
382 return PTR_ERR(tlink);
383 pTcon = tlink_tcon(tlink);
1da177e4 384
7ffec372 385 xid = GetXid();
1da177e4 386
7f57356b
SF
387 fromName = build_path_from_dentry(old_file);
388 toName = build_path_from_dentry(direntry);
fb8c4b14 389 if ((fromName == NULL) || (toName == NULL)) {
1da177e4
LT
390 rc = -ENOMEM;
391 goto cifs_hl_exit;
392 }
393
c18c842b 394 if (pTcon->unix_ext)
1da177e4 395 rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
7ffec372
JL
396 cifs_sb->local_nls,
397 cifs_sb->mnt_cifs_flags &
737b758c 398 CIFS_MOUNT_MAP_SPECIAL_CHR);
1da177e4
LT
399 else {
400 rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
7ffec372
JL
401 cifs_sb->local_nls,
402 cifs_sb->mnt_cifs_flags &
737b758c 403 CIFS_MOUNT_MAP_SPECIAL_CHR);
fb8c4b14
SF
404 if ((rc == -EIO) || (rc == -EINVAL))
405 rc = -EOPNOTSUPP;
1da177e4
LT
406 }
407
31ec35d6
SF
408 d_drop(direntry); /* force new lookup from server of target */
409
410 /* if source file is cached (oplocked) revalidate will not go to server
411 until the file is closed or oplock broken so update nlinks locally */
fb8c4b14 412 if (old_file->d_inode) {
31ec35d6 413 cifsInode = CIFS_I(old_file->d_inode);
fb8c4b14 414 if (rc == 0) {
31ec35d6 415 old_file->d_inode->i_nlink++;
1b2b2126
SF
416/* BB should we make this contingent on superblock flag NOATIME? */
417/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
31ec35d6
SF
418 /* parent dir timestamps will update from srv
419 within a second, would it really be worth it
420 to set the parent dir cifs inode time to zero
421 to force revalidate (faster) for it too? */
422 }
fb8c4b14 423 /* if not oplocked will force revalidate to get info
31ec35d6
SF
424 on source file from srv */
425 cifsInode->time = 0;
426
fb8c4b14 427 /* Will update parent dir timestamps from srv within a second.
31ec35d6
SF
428 Would it really be worth it to set the parent dir (cifs
429 inode) time field to zero to force revalidate on parent
fb8c4b14 430 directory faster ie
31ec35d6 431 CIFS_I(inode)->time = 0; */
1da177e4 432 }
1da177e4
LT
433
434cifs_hl_exit:
f99d49ad
JJ
435 kfree(fromName);
436 kfree(toName);
1da177e4 437 FreeXid(xid);
7ffec372 438 cifs_put_tlink(tlink);
1da177e4
LT
439 return rc;
440}
441
cc314eef 442void *
1da177e4
LT
443cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
444{
445 struct inode *inode = direntry->d_inode;
8b6427a2 446 int rc = -ENOMEM;
1da177e4
LT
447 int xid;
448 char *full_path = NULL;
8b6427a2
JL
449 char *target_path = NULL;
450 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
7ffec372
JL
451 struct tcon_link *tlink = NULL;
452 struct cifsTconInfo *tcon;
1da177e4
LT
453
454 xid = GetXid();
455
7ffec372
JL
456 tlink = cifs_sb_tlink(cifs_sb);
457 if (IS_ERR(tlink)) {
458 rc = PTR_ERR(tlink);
459 tlink = NULL;
460 goto out;
461 }
462 tcon = tlink_tcon(tlink);
463
8b6427a2
JL
464 /*
465 * For now, we just handle symlinks with unix extensions enabled.
466 * Eventually we should handle NTFS reparse points, and MacOS
467 * symlink support. For instance...
468 *
469 * rc = CIFSSMBQueryReparseLinkInfo(...)
470 *
471 * For now, just return -EACCES when the server doesn't support posix
472 * extensions. Note that we still allow querying symlinks when posix
473 * extensions are manually disabled. We could disable these as well
474 * but there doesn't seem to be any harm in allowing the client to
475 * read them.
476 */
1b12b9c1
SM
477 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
478 && !(tcon->ses->capabilities & CAP_UNIX)) {
8b6427a2
JL
479 rc = -EACCES;
480 goto out;
481 }
1da177e4 482
8b6427a2 483 full_path = build_path_from_dentry(direntry);
1da177e4 484 if (!full_path)
460b9696 485 goto out;
1da177e4 486
b6b38f70 487 cFYI(1, "Full path: %s inode = 0x%p", full_path, inode);
1da177e4 488
1b12b9c1
SM
489 rc = -EACCES;
490 /*
491 * First try Minshall+French Symlinks, if configured
492 * and fallback to UNIX Extensions Symlinks.
493 */
494 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
495 rc = CIFSQueryMFSymLink(xid, tcon, full_path, &target_path,
496 cifs_sb->local_nls,
497 cifs_sb->mnt_cifs_flags &
498 CIFS_MOUNT_MAP_SPECIAL_CHR);
499
500 if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
501 rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
502 cifs_sb->local_nls);
503
8b6427a2
JL
504 kfree(full_path);
505out:
460b9696 506 if (rc != 0) {
1da177e4
LT
507 kfree(target_path);
508 target_path = ERR_PTR(rc);
509 }
510
1da177e4 511 FreeXid(xid);
7ffec372
JL
512 if (tlink)
513 cifs_put_tlink(tlink);
1da177e4 514 nd_set_link(nd, target_path);
460b9696 515 return NULL;
1da177e4
LT
516}
517
518int
519cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
520{
521 int rc = -EOPNOTSUPP;
522 int xid;
7ffec372
JL
523 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
524 struct tcon_link *tlink;
1da177e4
LT
525 struct cifsTconInfo *pTcon;
526 char *full_path = NULL;
527 struct inode *newinode = NULL;
528
529 xid = GetXid();
530
7ffec372
JL
531 tlink = cifs_sb_tlink(cifs_sb);
532 if (IS_ERR(tlink)) {
533 rc = PTR_ERR(tlink);
534 goto symlink_exit;
535 }
536 pTcon = tlink_tcon(tlink);
1da177e4 537
7f57356b 538 full_path = build_path_from_dentry(direntry);
fb8c4b14 539 if (full_path == NULL) {
0f3bc09e 540 rc = -ENOMEM;
7ffec372 541 goto symlink_exit;
1da177e4
LT
542 }
543
b6b38f70
JP
544 cFYI(1, "Full path: %s", full_path);
545 cFYI(1, "symname is %s", symname);
1da177e4
LT
546
547 /* BB what if DFS and this volume is on different share? BB */
1b12b9c1
SM
548 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
549 rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
550 cifs_sb->local_nls,
551 cifs_sb->mnt_cifs_flags &
552 CIFS_MOUNT_MAP_SPECIAL_CHR);
553 else if (pTcon->unix_ext)
1da177e4
LT
554 rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
555 cifs_sb->local_nls);
556 /* else
fb8c4b14
SF
557 rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
558 cifs_sb_target->local_nls); */
1da177e4
LT
559
560 if (rc == 0) {
c18c842b 561 if (pTcon->unix_ext)
1da177e4 562 rc = cifs_get_inode_info_unix(&newinode, full_path,
fb8c4b14 563 inode->i_sb, xid);
1da177e4
LT
564 else
565 rc = cifs_get_inode_info(&newinode, full_path, NULL,
8b1327f6 566 inode->i_sb, xid, NULL);
1da177e4
LT
567
568 if (rc != 0) {
b6b38f70
JP
569 cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d",
570 rc);
1da177e4 571 } else {
1da177e4
LT
572 d_instantiate(direntry, newinode);
573 }
574 }
7ffec372 575symlink_exit:
f99d49ad 576 kfree(full_path);
7ffec372 577 cifs_put_tlink(tlink);
1da177e4
LT
578 FreeXid(xid);
579 return rc;
580}
581
cc314eef 582void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie)
1da177e4
LT
583{
584 char *p = nd_get_link(nd);
585 if (!IS_ERR(p))
586 kfree(p);
587}