Blame view

fs/cifs/ioctl.c 8.11 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   *   fs/cifs/ioctl.c
   *
   *   vfs operations that deal with io control
   *
64a5cfa6d   Steve French   Allow setting per...
6
   *   Copyright (C) International Business Machines  Corp., 2005,2013
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   *   Author(s): Steve French (sfrench@us.ibm.com)
   *
   *   This library is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU Lesser General Public License as published
   *   by the Free Software Foundation; either version 2.1 of the License, or
   *   (at your option) any later version.
   *
   *   This library is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
   *   the GNU Lesser General Public License for more details.
   *
   *   You should have received a copy of the GNU Lesser General Public License
   *   along with this library; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
f654bac22   Steve French   [PATCH] cifs: add...
23

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/fs.h>
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
25
26
27
28
  #include <linux/file.h>
  #include <linux/mount.h>
  #include <linux/mm.h>
  #include <linux/pagemap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
  #include "cifspdu.h"
  #include "cifsglob.h"
  #include "cifsproto.h"
  #include "cifs_debug.h"
c67593a03   Steve French   [PATCH] cifs: Ena...
33
  #include "cifsfs.h"
0de1f4c6f   Steve French   Add way to query ...
34
  #include "cifs_ioctl.h"
02b166654   Steve French   Add reflink copy ...
35
  #include <linux/btrfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

04b38d601   Christoph Hellwig   vfs: pull btrfs c...
37
38
  static int cifs_file_clone_range(unsigned int xid, struct file *src_file,
  			  struct file *dst_file)
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
39
  {
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
40
  	struct inode *src_inode = file_inode(src_file);
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
41
  	struct inode *target_inode = file_inode(dst_file);
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
42
  	struct cifsFileInfo *smb_file_src;
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
43
  	struct cifsFileInfo *smb_file_target;
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
44
  	struct cifs_tcon *src_tcon;
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
45
46
  	struct cifs_tcon *target_tcon;
  	int rc;
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
47
48
49
  
  	cifs_dbg(FYI, "ioctl clone range
  ");
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
50

04b38d601   Christoph Hellwig   vfs: pull btrfs c...
51
  	if (!src_file->private_data || !dst_file->private_data) {
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
52
53
54
  		rc = -EBADF;
  		cifs_dbg(VFS, "missing cifsFileInfo on copy range src file
  ");
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
55
  		goto out;
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
56
57
58
59
  	}
  
  	rc = -EXDEV;
  	smb_file_target = dst_file->private_data;
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
60
  	smb_file_src = src_file->private_data;
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
61
62
  	src_tcon = tlink_tcon(smb_file_src->tlink);
  	target_tcon = tlink_tcon(smb_file_target->tlink);
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
63
  	if (src_tcon->ses != target_tcon->ses) {
7b52e2793   Steve French   Allow copy offloa...
64
65
  		cifs_dbg(VFS, "source and target of copy not on same server
  ");
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
66
  		goto out;
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
67
  	}
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
68
69
70
71
72
  	/*
  	 * Note: cifs case is easier than btrfs since server responsible for
  	 * checks for proper open modes and file type and if it wants
  	 * server could even support copy of range where source = target
  	 */
378ff1a53   Al Viro   fix deadlock in c...
73
  	lock_two_nondirectories(target_inode, src_inode);
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
74

41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
75
76
77
  	cifs_dbg(FYI, "about to flush pages
  ");
  	/* should we flush first and last page first */
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
78
  	truncate_inode_pages(&target_inode->i_data, 0);
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
79

04b38d601   Christoph Hellwig   vfs: pull btrfs c...
80
  	if (target_tcon->ses->server->ops->clone_range)
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
81
  		rc = target_tcon->ses->server->ops->clone_range(xid,
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
82
  			smb_file_src, smb_file_target, 0, src_inode->i_size, 0);
02b166654   Steve French   Add reflink copy ...
83
84
  	else
  		rc = -EOPNOTSUPP;
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
85
86
87
88
  
  	/* force revalidate of size and timestamps of target file now
  	   that target is updated on the server */
  	CIFS_I(target_inode)->time = 0;
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
89
90
  	/* although unlocking in the reverse order from locking is not
  	   strictly necessary here it is a little cleaner to be consistent */
378ff1a53   Al Viro   fix deadlock in c...
91
  	unlock_two_nondirectories(src_inode, target_inode);
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  out:
  	return rc;
  }
  
  static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
  			unsigned long srcfd)
  {
  	int rc;
  	struct fd src_file;
  	struct inode *src_inode;
  
  	cifs_dbg(FYI, "ioctl clone range
  ");
  	/* the destination must be opened for writing */
  	if (!(dst_file->f_mode & FMODE_WRITE)) {
  		cifs_dbg(FYI, "file target not open for write
  ");
  		return -EINVAL;
  	}
  
  	/* check if target volume is readonly and take reference */
  	rc = mnt_want_write_file(dst_file);
  	if (rc) {
  		cifs_dbg(FYI, "mnt_want_write failed with rc %d
  ", rc);
  		return rc;
  	}
  
  	src_file = fdget(srcfd);
  	if (!src_file.file) {
  		rc = -EBADF;
  		goto out_drop_write;
  	}
  
  	if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) {
  		rc = -EBADF;
  		cifs_dbg(VFS, "src file seems to be from a different filesystem type
  ");
  		goto out_fput;
  	}
  
  	src_inode = file_inode(src_file.file);
  	rc = -EINVAL;
  	if (S_ISDIR(src_inode->i_mode))
  		goto out_fput;
  
  	rc = cifs_file_clone_range(xid, src_file.file, dst_file);
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
139
140
141
142
143
144
  out_fput:
  	fdput(src_file);
  out_drop_write:
  	mnt_drop_write_file(dst_file);
  	return rc;
  }
0de1f4c6f   Steve French   Add way to query ...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
  				void __user *arg)
  {
  	int rc = 0;
  	struct smb_mnt_fs_info *fsinf;
  
  	fsinf = kzalloc(sizeof(struct smb_mnt_fs_info), GFP_KERNEL);
  	if (fsinf == NULL)
  		return -ENOMEM;
  
  	fsinf->version = 1;
  	fsinf->protocol_id = tcon->ses->server->vals->protocol_id;
  	fsinf->device_characteristics =
  			le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics);
  	fsinf->device_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
  	fsinf->fs_attributes = le32_to_cpu(tcon->fsAttrInfo.Attributes);
  	fsinf->max_path_component =
  		le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength);
  #ifdef CONFIG_CIFS_SMB2
  	fsinf->vol_serial_number = tcon->vol_serial_number;
  	fsinf->vol_create_time = le64_to_cpu(tcon->vol_create_time);
  	fsinf->share_flags = tcon->share_flags;
  	fsinf->share_caps = le32_to_cpu(tcon->capabilities);
  	fsinf->sector_flags = tcon->ss_flags;
  	fsinf->optimal_sector_size = tcon->perf_sector_size;
  	fsinf->max_bytes_chunk = tcon->max_bytes_chunk;
  	fsinf->maximal_access = tcon->maximal_access;
  #endif /* SMB2 */
  	fsinf->cifs_posix_caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
  
  	if (copy_to_user(arg, fsinf, sizeof(struct smb_mnt_fs_info)))
  		rc = -EFAULT;
  
  	kfree(fsinf);
  	return rc;
  }
f9ddcca4c   Steve French   [CIFS] BKL-remova...
181
  long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  {
496ad9aa8   Al Viro   new helper: file_...
183
  	struct inode *inode = file_inode(filep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  	int rc = -ENOTTY; /* strange error - but the precedent */
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
185
  	unsigned int xid;
c81156dd2   Steve French   [PATCH] cifs: cle...
186
  	struct cifs_sb_info *cifs_sb;
ba00ba64c   Jeff Layton   cifs: make variou...
187
  	struct cifsFileInfo *pSMBFile = filep->private_data;
96daf2b09   Steve French   [CIFS] Rename thr...
188
  	struct cifs_tcon *tcon;
f654bac22   Steve French   [PATCH] cifs: add...
189
  	__u64	ExtAttrBits = 0;
618763958   Jeff Layton   cifs: make cifs_i...
190
  	__u64   caps;
f654bac22   Steve French   [PATCH] cifs: add...
191

6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
192
  	xid = get_xid();
f654bac22   Steve French   [PATCH] cifs: add...
193
194
  
  	cifs_sb = CIFS_SB(inode->i_sb);
9f9d98246   Pavel Shilovsky   CIFS: Decrease ve...
195
196
  	cifs_dbg(FYI, "cifs ioctl 0x%x
  ", command);
5fdae1f68   Steve French   [CIFS] whitespace...
197
  	switch (command) {
36695673b   David Howells   [PATCH] BLOCK: Mo...
198
  		case FS_IOC_GETFLAGS:
618763958   Jeff Layton   cifs: make cifs_i...
199
200
201
202
  			if (pSMBFile == NULL)
  				break;
  			tcon = tlink_tcon(pSMBFile->tlink);
  			caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
64a5cfa6d   Steve French   Allow setting per...
203
  #ifdef CONFIG_CIFS_POSIX
5fdae1f68   Steve French   [CIFS] whitespace...
204
  			if (CIFS_UNIX_EXTATTR_CAP & caps) {
f10d9ba40   Steve French   Fix unused variab...
205
  				__u64	ExtAttrMask = 0;
4b4de76e3   Pavel Shilovsky   CIFS: Replace net...
206
207
208
  				rc = CIFSGetExtAttr(xid, tcon,
  						    pSMBFile->fid.netfid,
  						    &ExtAttrBits, &ExtAttrMask);
5fdae1f68   Steve French   [CIFS] whitespace...
209
  				if (rc == 0)
f654bac22   Steve French   [PATCH] cifs: add...
210
  					rc = put_user(ExtAttrBits &
36695673b   David Howells   [PATCH] BLOCK: Mo...
211
  						FS_FL_USER_VISIBLE,
f654bac22   Steve French   [PATCH] cifs: add...
212
  						(int __user *)arg);
64a5cfa6d   Steve French   Allow setting per...
213
214
215
216
217
218
219
220
221
222
  				if (rc != EOPNOTSUPP)
  					break;
  			}
  #endif /* CONFIG_CIFS_POSIX */
  			rc = 0;
  			if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) {
  				/* add in the compressed bit */
  				ExtAttrBits = FS_COMPR_FL;
  				rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
  					      (int __user *)arg);
f654bac22   Steve French   [PATCH] cifs: add...
223
224
  			}
  			break;
36695673b   David Howells   [PATCH] BLOCK: Mo...
225
  		case FS_IOC_SETFLAGS:
618763958   Jeff Layton   cifs: make cifs_i...
226
227
228
229
  			if (pSMBFile == NULL)
  				break;
  			tcon = tlink_tcon(pSMBFile->tlink);
  			caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
64a5cfa6d   Steve French   Allow setting per...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  
  			if (get_user(ExtAttrBits, (int __user *)arg)) {
  				rc = -EFAULT;
  				break;
  			}
  
  			/*
  			 * if (CIFS_UNIX_EXTATTR_CAP & caps)
  			 *	rc = CIFSSetExtAttr(xid, tcon,
  			 *		       pSMBFile->fid.netfid,
  			 *		       extAttrBits,
  			 *		       &ExtAttrMask);
  			 * if (rc != EOPNOTSUPP)
  			 *	break;
  			 */
  
  			/* Currently only flag we can set is compressed flag */
  			if ((ExtAttrBits & FS_COMPR_FL) == 0)
  				break;
  
  			/* Try to set compress flag */
  			if (tcon->ses->server->ops->set_compression) {
  				rc = tcon->ses->server->ops->set_compression(
  							xid, tcon, pSMBFile);
  				cifs_dbg(FYI, "set compress flag rc %d
  ", rc);
f654bac22   Steve French   [PATCH] cifs: add...
256
  			}
f654bac22   Steve French   [PATCH] cifs: add...
257
  			break;
f19e84df3   Steve French   [CIFS] Do not use...
258
  		case CIFS_IOC_COPYCHUNK_FILE:
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
259
  			rc = cifs_ioctl_clone(xid, filep, arg);
41c1358e9   Steve French   CIFS: SMB2/SMB3 C...
260
  			break;
b3152e2c7   Steve French   Add ioctl to set ...
261
262
263
264
265
266
267
268
269
270
  		case CIFS_IOC_SET_INTEGRITY:
  			if (pSMBFile == NULL)
  				break;
  			tcon = tlink_tcon(pSMBFile->tlink);
  			if (tcon->ses->server->ops->set_integrity)
  				rc = tcon->ses->server->ops->set_integrity(xid,
  						tcon, pSMBFile);
  			else
  				rc = -EOPNOTSUPP;
  			break;
0de1f4c6f   Steve French   Add way to query ...
271
272
273
274
  		case CIFS_IOC_GET_MNT_INFO:
  			tcon = tlink_tcon(pSMBFile->tlink);
  			rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg);
  			break;
834170c85   Steve French   Enable previous v...
275
276
277
278
279
280
281
282
283
284
285
286
  		case CIFS_ENUMERATE_SNAPSHOTS:
  			if (arg == 0) {
  				rc = -EINVAL;
  				goto cifs_ioc_exit;
  			}
  			tcon = tlink_tcon(pSMBFile->tlink);
  			if (tcon->ses->server->ops->enum_snapshots)
  				rc = tcon->ses->server->ops->enum_snapshots(xid, tcon,
  						pSMBFile, (void __user *)arg);
  			else
  				rc = -EOPNOTSUPP;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  		default:
f96637be0   Joe Perches   [CIFS] cifs: Rena...
288
289
  			cifs_dbg(FYI, "unsupported ioctl
  ");
f28ac91b0   Steve French   [PATCH] cifs: CIF...
290
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  	}
834170c85   Steve French   Enable previous v...
292
  cifs_ioc_exit:
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
293
  	free_xid(xid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  	return rc;
5fdae1f68   Steve French   [CIFS] whitespace...
295
  }