Blame view

fs/cifs/cifs_dfs_ref.c 9.77 KB
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
1
2
3
4
5
  /*
   *   Contains the CIFS DFS referral mounting routines used for handling
   *   traversal via DFS junction point
   *
   *   Copyright (c) 2007 Igor Mammedov
366781c19   Steve French   [CIFS] DFS build ...
6
   *   Copyright (C) International Business Machines  Corp., 2008
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
7
   *   Author(s): Igor Mammedov (niallain@gmail.com)
366781c19   Steve French   [CIFS] DFS build ...
8
   *		Steve French (sfrench@us.ibm.com)
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
9
10
11
12
13
14
15
16
17
   *   This program is free software; you can redistribute it and/or
   *   modify it under the terms of the GNU General Public License
   *   as published by the Free Software Foundation; either version
   *   2 of the License, or (at your option) any later version.
   */
  
  #include <linux/dcache.h>
  #include <linux/mount.h>
  #include <linux/namei.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
19
20
  #include <linux/vfs.h>
  #include <linux/fs.h>
166faf21b   Jeff Layton   cifs: fix potenti...
21
  #include <linux/inet.h>
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
22
23
24
25
26
  #include "cifsglob.h"
  #include "cifsproto.h"
  #include "cifsfs.h"
  #include "dns_resolve.h"
  #include "cifs_debug.h"
8d142137b   Steve French   [CIFS] make cifs_...
27
  static LIST_HEAD(cifs_dfs_automount_list);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
28

78d31a3a8   Igor Mammedov   cifs: timeout dfs...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
  static void cifs_dfs_expire_automounts(struct work_struct *work);
  static DECLARE_DELAYED_WORK(cifs_dfs_automount_task,
  			    cifs_dfs_expire_automounts);
  static int cifs_dfs_mountpoint_expiry_timeout = 500 * HZ;
  
  static void cifs_dfs_expire_automounts(struct work_struct *work)
  {
  	struct list_head *list = &cifs_dfs_automount_list;
  
  	mark_mounts_for_expiry(list);
  	if (!list_empty(list))
  		schedule_delayed_work(&cifs_dfs_automount_task,
  				      cifs_dfs_mountpoint_expiry_timeout);
  }
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
43

78d31a3a8   Igor Mammedov   cifs: timeout dfs...
44
  void cifs_dfs_release_automount_timer(void)
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
45
  {
78d31a3a8   Igor Mammedov   cifs: timeout dfs...
46
  	BUG_ON(!list_empty(&cifs_dfs_automount_list));
3e24e1328   Tejun Heo   cifs: cancel_dela...
47
  	cancel_delayed_work_sync(&cifs_dfs_automount_task);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
48
49
50
  }
  
  /**
d9deef0a3   Jeff Layton   cifs: fix composi...
51
52
53
   * cifs_build_devname - build a devicename from a UNC and optional prepath
   * @nodename:	pointer to UNC string
   * @prepath:	pointer to prefixpath (or NULL if there isn't one)
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
54
   *
d9deef0a3   Jeff Layton   cifs: fix composi...
55
56
57
58
59
60
   * Build a new cifs devicename after chasing a DFS referral. Allocate a buffer
   * big enough to hold the final thing. Copy the UNC from the nodename, and
   * concatenate the prepath onto the end of it if there is one.
   *
   * Returns pointer to the built string, or a ERR_PTR. Caller is responsible
   * for freeing the returned string.
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
61
   */
d9deef0a3   Jeff Layton   cifs: fix composi...
62
63
  static char *
  cifs_build_devname(char *nodename, const char *prepath)
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
64
  {
d9deef0a3   Jeff Layton   cifs: fix composi...
65
66
67
68
  	size_t pplen;
  	size_t unclen;
  	char *dev;
  	char *pos;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
69

d9deef0a3   Jeff Layton   cifs: fix composi...
70
71
72
  	/* skip over any preceding delimiters */
  	nodename += strspn(nodename, "\\");
  	if (!*nodename)
7b91e2661   Jeff Layton   cifs: fix error h...
73
  		return ERR_PTR(-EINVAL);
d9deef0a3   Jeff Layton   cifs: fix composi...
74
75
76
77
78
79
80
81
82
  
  	/* get length of UNC and set pos to last char */
  	unclen = strlen(nodename);
  	pos = nodename + unclen - 1;
  
  	/* trim off any trailing delimiters */
  	while (*pos == '\\') {
  		--pos;
  		--unclen;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
83
  	}
d9deef0a3   Jeff Layton   cifs: fix composi...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  	/* allocate a buffer:
  	 * +2 for preceding "//"
  	 * +1 for delimiter between UNC and prepath
  	 * +1 for trailing NULL
  	 */
  	pplen = prepath ? strlen(prepath) : 0;
  	dev = kmalloc(2 + unclen + 1 + pplen + 1, GFP_KERNEL);
  	if (!dev)
  		return ERR_PTR(-ENOMEM);
  
  	pos = dev;
  	/* add the initial "//" */
  	*pos = '/';
  	++pos;
  	*pos = '/';
  	++pos;
  
  	/* copy in the UNC portion from referral */
  	memcpy(pos, nodename, unclen);
  	pos += unclen;
  
  	/* copy the prefixpath remainder (if there is one) */
  	if (pplen) {
  		*pos = '/';
  		++pos;
  		memcpy(pos, prepath, pplen);
  		pos += pplen;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
111
  	}
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
112

d9deef0a3   Jeff Layton   cifs: fix composi...
113
114
115
116
117
  	/* NULL terminator */
  	*pos = '\0';
  
  	convert_delimiter(dev, '/');
  	return dev;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
118
119
120
121
  }
  
  
  /**
c6c00919a   Steve French   [CIFS] Rename co...
122
   * cifs_compose_mount_options	-	creates mount options for refferral
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
123
   * @sb_mountdata:	parent/root DFS mount options (template)
c6c00919a   Steve French   [CIFS] Rename co...
124
   * @fullpath:		full path in UNC format
2c55608f2   Igor Mammedov   Fixed parsing of ...
125
   * @ref:		server's referral
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
126
127
128
129
130
131
132
133
   * @devname:		pointer for saving device name
   *
   * creates mount options for submount based on template options sb_mountdata
   * and replacing unc,ip,prefixpath options with ones we've got form ref_unc.
   *
   * Returns: pointer to new mount options or ERR_PTR.
   * Caller is responcible for freeing retunrned value if it is not error.
   */
c6c00919a   Steve French   [CIFS] Rename co...
134
135
  char *cifs_compose_mount_options(const char *sb_mountdata,
  				   const char *fullpath,
2c55608f2   Igor Mammedov   Fixed parsing of ...
136
  				   const struct dfs_info3_param *ref,
366781c19   Steve French   [CIFS] DFS build ...
137
  				   char **devname)
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
138
139
  {
  	int rc;
c6fbba054   Steve French   [CIFS] make sure ...
140
  	char *mountdata = NULL;
d9deef0a3   Jeff Layton   cifs: fix composi...
141
  	const char *prepath = NULL;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
142
143
144
145
146
147
148
149
  	int md_len;
  	char *tkn_e;
  	char *srvIP = NULL;
  	char sep = ',';
  	int off, noff;
  
  	if (sb_mountdata == NULL)
  		return ERR_PTR(-EINVAL);
d9deef0a3   Jeff Layton   cifs: fix composi...
150
151
152
153
  	if (strlen(fullpath) - ref->path_consumed)
  		prepath = fullpath + ref->path_consumed;
  
  	*devname = cifs_build_devname(ref->node_name, prepath);
7b91e2661   Jeff Layton   cifs: fix error h...
154
155
156
157
158
  	if (IS_ERR(*devname)) {
  		rc = PTR_ERR(*devname);
  		*devname = NULL;
  		goto compose_mount_options_err;
  	}
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
159
  	rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
67b7626a0   David Howells   CIFS: Make cifs_c...
160
  	if (rc < 0) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
161
162
163
  		cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d
  ",
  			 __func__, *devname, rc);
c6fbba054   Steve French   [CIFS] make sure ...
164
  		goto compose_mount_options_err;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
165
  	}
b80289833   Jeff Layton   cifs: demote DFS ...
166

d9deef0a3   Jeff Layton   cifs: fix composi...
167
168
169
170
171
  	/*
  	 * In most cases, we'll be building a shorter string than the original,
  	 * but we do have to assume that the address in the ip= option may be
  	 * much longer than the original. Add the max length of an address
  	 * string to the length of the original string to allow for worst case.
2c55608f2   Igor Mammedov   Fixed parsing of ...
172
  	 */
d9deef0a3   Jeff Layton   cifs: fix composi...
173
174
  	md_len = strlen(sb_mountdata) + INET6_ADDRSTRLEN;
  	mountdata = kzalloc(md_len + 1, GFP_KERNEL);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
175
  	if (mountdata == NULL) {
c6fbba054   Steve French   [CIFS] make sure ...
176
177
  		rc = -ENOMEM;
  		goto compose_mount_options_err;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
178
179
180
181
182
183
184
185
186
  	}
  
  	/* copy all options except of unc,ip,prefixpath */
  	off = 0;
  	if (strncmp(sb_mountdata, "sep=", 4) == 0) {
  			sep = sb_mountdata[4];
  			strncpy(mountdata, sb_mountdata, 5);
  			off += 5;
  	}
2c55608f2   Igor Mammedov   Fixed parsing of ...
187
188
189
190
191
192
193
194
195
  
  	do {
  		tkn_e = strchr(sb_mountdata + off, sep);
  		if (tkn_e == NULL)
  			noff = strlen(sb_mountdata + off);
  		else
  			noff = tkn_e - (sb_mountdata + off) + 1;
  
  		if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) {
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
196
197
198
  			off += noff;
  			continue;
  		}
2c55608f2   Igor Mammedov   Fixed parsing of ...
199
  		if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) {
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
200
201
202
  			off += noff;
  			continue;
  		}
2c55608f2   Igor Mammedov   Fixed parsing of ...
203
  		if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) {
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
204
205
206
  			off += noff;
  			continue;
  		}
2c55608f2   Igor Mammedov   Fixed parsing of ...
207
  		strncat(mountdata, sb_mountdata + off, noff);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
208
  		off += noff;
2c55608f2   Igor Mammedov   Fixed parsing of ...
209
210
  	} while (tkn_e);
  	strcat(mountdata, sb_mountdata + off);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
211
212
213
  	mountdata[md_len] = '\0';
  
  	/* copy new IP and ref share name */
2c55608f2   Igor Mammedov   Fixed parsing of ...
214
215
216
  	if (mountdata[strlen(mountdata) - 1] != sep)
  		strncat(mountdata, &sep, 1);
  	strcat(mountdata, "ip=");
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
217
  	strcat(mountdata, srvIP);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
218

f96637be0   Joe Perches   [CIFS] cifs: Rena...
219
220
221
222
  	/*cifs_dbg(FYI, "%s: parent mountdata: %s
  ", __func__, sb_mountdata);*/
  	/*cifs_dbg(FYI, "%s: submount mountdata: %s
  ", __func__, mountdata );*/
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
223
224
225
226
  
  compose_mount_options_out:
  	kfree(srvIP);
  	return mountdata;
c6fbba054   Steve French   [CIFS] make sure ...
227
228
229
230
  
  compose_mount_options_err:
  	kfree(mountdata);
  	mountdata = ERR_PTR(rc);
10b8c7dff   Cong Ding   fs/cifs/cifs_dfs_...
231
232
  	kfree(*devname);
  	*devname = NULL;
c6fbba054   Steve French   [CIFS] make sure ...
233
  	goto compose_mount_options_out;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
234
  }
f67909cf8   Steve French   [CIFS] remove red...
235
236
237
238
239
240
241
242
  /**
   * cifs_dfs_do_refmount - mounts specified path using provided refferal
   * @cifs_sb:		parent/root superblock
   * @fullpath:		full path in UNC format
   * @ref:		server's referral
   */
  static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb,
  		const char *fullpath, const struct dfs_info3_param *ref)
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
243
  {
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
244
245
  	struct vfsmount *mnt;
  	char *mountdata;
366781c19   Steve French   [CIFS] DFS build ...
246
  	char *devname = NULL;
c6c00919a   Steve French   [CIFS] Rename co...
247

f67909cf8   Steve French   [CIFS] remove red...
248
  	/* strip first '\' from fullpath */
c6c00919a   Steve French   [CIFS] Rename co...
249
250
  	mountdata = cifs_compose_mount_options(cifs_sb->mountdata,
  			fullpath + 1, ref, &devname);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
251
252
253
254
255
256
257
258
259
260
  
  	if (IS_ERR(mountdata))
  		return (struct vfsmount *)mountdata;
  
  	mnt = vfs_kern_mount(&cifs_fs_type, 0, devname, mountdata);
  	kfree(mountdata);
  	kfree(devname);
  	return mnt;
  
  }
366781c19   Steve French   [CIFS] DFS build ...
261
  static void dump_referral(const struct dfs_info3_param *ref)
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
262
  {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
263
264
265
266
267
268
269
270
271
272
  	cifs_dbg(FYI, "DFS: ref path: %s
  ", ref->path_name);
  	cifs_dbg(FYI, "DFS: node path: %s
  ", ref->node_name);
  	cifs_dbg(FYI, "DFS: fl: %hd, srv_type: %hd
  ",
  		 ref->flags, ref->server_type);
  	cifs_dbg(FYI, "DFS: ref_flags: %hd, path_consumed: %hd
  ",
  		 ref->ref_flag, ref->path_consumed);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
273
  }
01c64feac   David Howells   CIFS: Use d_autom...
274
275
276
277
  /*
   * Create a vfsmount that we can automount
   */
  static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
278
279
280
281
  {
  	struct dfs_info3_param *referrals = NULL;
  	unsigned int num_referrals = 0;
  	struct cifs_sb_info *cifs_sb;
96daf2b09   Steve French   [CIFS] Rename thr...
282
  	struct cifs_ses *ses;
01c64feac   David Howells   CIFS: Use d_autom...
283
  	char *full_path;
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
284
285
  	unsigned int xid;
  	int i;
01c64feac   David Howells   CIFS: Use d_autom...
286
287
  	int rc;
  	struct vfsmount *mnt;
7ffec3724   Jeff Layton   cifs: add refcoun...
288
  	struct tcon_link *tlink;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
289

f96637be0   Joe Perches   [CIFS] cifs: Rena...
290
291
  	cifs_dbg(FYI, "in %s
  ", __func__);
01c64feac   David Howells   CIFS: Use d_autom...
292
  	BUG_ON(IS_ROOT(mntpt));
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
293

c6fbba054   Steve French   [CIFS] make sure ...
294
295
296
297
298
299
  	/*
  	 * The MSDFS spec states that paths in DFS referral requests and
  	 * responses must be prefixed by a single '\' character instead of
  	 * the double backslashes usually used in the UNC. This function
  	 * gives us the latter, so we must adjust the result.
  	 */
01c64feac   David Howells   CIFS: Use d_autom...
300
301
302
  	mnt = ERR_PTR(-ENOMEM);
  	full_path = build_path_from_dentry(mntpt);
  	if (full_path == NULL)
31c2659d7   Jeff Layton   cifs: clean up so...
303
  		goto cdda_exit;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
304

01c64feac   David Howells   CIFS: Use d_autom...
305
  	cifs_sb = CIFS_SB(mntpt->d_inode->i_sb);
7ffec3724   Jeff Layton   cifs: add refcoun...
306
307
  	tlink = cifs_sb_tlink(cifs_sb);
  	if (IS_ERR(tlink)) {
01c64feac   David Howells   CIFS: Use d_autom...
308
309
  		mnt = ERR_CAST(tlink);
  		goto free_full_path;
7ffec3724   Jeff Layton   cifs: add refcoun...
310
311
  	}
  	ses = tlink_tcon(tlink)->ses;
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
312
  	xid = get_xid();
7ffec3724   Jeff Layton   cifs: add refcoun...
313
  	rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls,
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
314
315
  		&num_referrals, &referrals,
  		cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
316
  	free_xid(xid);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
317

7ffec3724   Jeff Layton   cifs: add refcoun...
318
  	cifs_put_tlink(tlink);
01c64feac   David Howells   CIFS: Use d_autom...
319
  	mnt = ERR_PTR(-ENOENT);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
320
  	for (i = 0; i < num_referrals; i++) {
cf398e3a1   Steve French   [CIFS] Fix build ...
321
  		int len;
01c64feac   David Howells   CIFS: Use d_autom...
322
  		dump_referral(referrals + i);
1af28ceb9   Igor Mammedov   Enable dfs submou...
323
  		/* connect to a node */
1af28ceb9   Igor Mammedov   Enable dfs submou...
324
325
  		len = strlen(referrals[i].node_name);
  		if (len < 2) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
326
327
328
  			cifs_dbg(VFS, "%s: Net Address path too short: %s
  ",
  				 __func__, referrals[i].node_name);
01c64feac   David Howells   CIFS: Use d_autom...
329
330
  			mnt = ERR_PTR(-EINVAL);
  			break;
1af28ceb9   Igor Mammedov   Enable dfs submou...
331
  		}
f67909cf8   Steve French   [CIFS] remove red...
332
333
  		mnt = cifs_dfs_do_refmount(cifs_sb,
  				full_path, referrals + i);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
334
335
336
  		cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p
  ",
  			 __func__, referrals[i].node_name, mnt);
1af28ceb9   Igor Mammedov   Enable dfs submou...
337
  		if (!IS_ERR(mnt))
01c64feac   David Howells   CIFS: Use d_autom...
338
  			goto success;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
339
  	}
01c64feac   David Howells   CIFS: Use d_autom...
340
341
342
343
  	/* no valid submounts were found; return error from get_dfs_path() by
  	 * preference */
  	if (rc != 0)
  		mnt = ERR_PTR(rc);
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
344

01c64feac   David Howells   CIFS: Use d_autom...
345
  success:
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
346
  	free_dfs_info_array(referrals, num_referrals);
01c64feac   David Howells   CIFS: Use d_autom...
347
  free_full_path:
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
348
  	kfree(full_path);
31c2659d7   Jeff Layton   cifs: clean up so...
349
  cdda_exit:
f96637be0   Joe Perches   [CIFS] cifs: Rena...
350
351
  	cifs_dbg(FYI, "leaving %s
  " , __func__);
01c64feac   David Howells   CIFS: Use d_autom...
352
353
354
355
356
357
358
359
360
  	return mnt;
  }
  
  /*
   * Attempt to automount the referral
   */
  struct vfsmount *cifs_dfs_d_automount(struct path *path)
  {
  	struct vfsmount *newmnt;
01c64feac   David Howells   CIFS: Use d_autom...
361

f96637be0   Joe Perches   [CIFS] cifs: Rena...
362
363
  	cifs_dbg(FYI, "in %s
  ", __func__);
01c64feac   David Howells   CIFS: Use d_autom...
364
365
366
  
  	newmnt = cifs_dfs_do_automount(path->dentry);
  	if (IS_ERR(newmnt)) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
367
368
  		cifs_dbg(FYI, "leaving %s [automount failed]
  " , __func__);
01c64feac   David Howells   CIFS: Use d_autom...
369
370
  		return newmnt;
  	}
ea5b778a8   David Howells   Unexport do_add_m...
371
372
373
374
  	mntget(newmnt); /* prevent immediate expiration */
  	mnt_set_expiry(newmnt, &cifs_dfs_automount_list);
  	schedule_delayed_work(&cifs_dfs_automount_task,
  			      cifs_dfs_mountpoint_expiry_timeout);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
375
376
  	cifs_dbg(FYI, "leaving %s [ok]
  " , __func__);
ea5b778a8   David Howells   Unexport do_add_m...
377
  	return newmnt;
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
378
  }
6e1d5dcc2   Alexey Dobriyan   const: mark remai...
379
  const struct inode_operations cifs_dfs_referral_inode_operations = {
6d5ae0deb   Igor Mammedov   [CIFS] DFS suppor...
380
  };