blob: 35cb6a374a4544fade42fef8b01ea0d27015f9c5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/inode.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * 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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/stat.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/pagemap.h>
25#include <asm/div64.h>
26#include "cifsfs.h"
27#include "cifspdu.h"
28#include "cifsglob.h"
29#include "cifsproto.h"
30#include "cifs_debug.h"
31#include "cifs_fs_sb.h"
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +053032#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Christoph Hellwig70eff552008-02-15 20:55:05 +000034
David Howells01c64fe2011-01-14 18:45:47 +000035static void cifs_set_ops(struct inode *inode)
Christoph Hellwig70eff552008-02-15 20:55:05 +000036{
37 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
38
39 switch (inode->i_mode & S_IFMT) {
40 case S_IFREG:
41 inode->i_op = &cifs_file_inode_ops;
42 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
43 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
44 inode->i_fop = &cifs_file_direct_nobrl_ops;
45 else
46 inode->i_fop = &cifs_file_direct_ops;
Pavel Shilovsky8be7e6b2010-12-12 13:11:13 +030047 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
48 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
49 inode->i_fop = &cifs_file_strict_nobrl_ops;
50 else
51 inode->i_fop = &cifs_file_strict_ops;
Christoph Hellwig70eff552008-02-15 20:55:05 +000052 } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
53 inode->i_fop = &cifs_file_nobrl_ops;
54 else { /* not direct, send byte range locks */
55 inode->i_fop = &cifs_file_ops;
56 }
57
Christoph Hellwig70eff552008-02-15 20:55:05 +000058 /* check if server can support readpages */
Jeff Layton0d424ad2010-09-20 16:01:35 -070059 if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
Christoph Hellwig70eff552008-02-15 20:55:05 +000060 PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
61 inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
62 else
63 inode->i_data.a_ops = &cifs_addr_ops;
64 break;
65 case S_IFDIR:
Steve Frenchbc5b6e22008-03-11 21:07:48 +000066#ifdef CONFIG_CIFS_DFS_UPCALL
David Howells01c64fe2011-01-14 18:45:47 +000067 if (IS_AUTOMOUNT(inode)) {
Igor Mammedov79626702008-03-09 03:44:18 +000068 inode->i_op = &cifs_dfs_referral_inode_operations;
69 } else {
Steve Frenchbc5b6e22008-03-11 21:07:48 +000070#else /* NO DFS support, treat as a directory */
71 {
72#endif
Igor Mammedov79626702008-03-09 03:44:18 +000073 inode->i_op = &cifs_dir_inode_ops;
74 inode->i_fop = &cifs_dir_ops;
75 }
Christoph Hellwig70eff552008-02-15 20:55:05 +000076 break;
77 case S_IFLNK:
78 inode->i_op = &cifs_symlink_inode_ops;
79 break;
80 default:
81 init_special_inode(inode, inode->i_mode, inode->i_rdev);
82 break;
83 }
84}
85
Jeff Laytondf2cf172010-02-12 07:44:16 -050086/* check inode attributes against fattr. If they don't match, tag the
87 * inode for cache invalidation
88 */
89static void
90cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
91{
92 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
93
Steve Frenchf19159d2010-04-21 04:12:10 +000094 cFYI(1, "%s: revalidating inode %llu", __func__, cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -050095
96 if (inode->i_state & I_NEW) {
Steve Frenchf19159d2010-04-21 04:12:10 +000097 cFYI(1, "%s: inode %llu is new", __func__, cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -050098 return;
99 }
100
101 /* don't bother with revalidation if we have an oplock */
102 if (cifs_i->clientCanCacheRead) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000103 cFYI(1, "%s: inode %llu is oplocked", __func__,
104 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500105 return;
106 }
107
108 /* revalidate if mtime or size have changed */
109 if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) &&
110 cifs_i->server_eof == fattr->cf_eof) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000111 cFYI(1, "%s: inode %llu is unchanged", __func__,
112 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500113 return;
114 }
115
Steve Frenchf19159d2010-04-21 04:12:10 +0000116 cFYI(1, "%s: invalidating inode %llu mapping", __func__,
117 cifs_i->uniqueid);
Jeff Laytondf2cf172010-02-12 07:44:16 -0500118 cifs_i->invalid_mapping = true;
119}
120
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400121/* populate an inode with info from a cifs_fattr struct */
122void
123cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
Christoph Hellwig75f12982008-02-25 20:25:21 +0000124{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400125 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400126 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
127 unsigned long oldtime = cifs_i->time;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000128
Jeff Laytondf2cf172010-02-12 07:44:16 -0500129 cifs_revalidate_cache(inode, fattr);
130
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400131 inode->i_atime = fattr->cf_atime;
132 inode->i_mtime = fattr->cf_mtime;
133 inode->i_ctime = fattr->cf_ctime;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400134 inode->i_rdev = fattr->cf_rdev;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200135 set_nlink(inode, fattr->cf_nlink);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400136 inode->i_uid = fattr->cf_uid;
137 inode->i_gid = fattr->cf_gid;
138
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400139 /* if dynperm is set, don't clobber existing mode */
140 if (inode->i_state & I_NEW ||
141 !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
142 inode->i_mode = fattr->cf_mode;
143
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400144 cifs_i->cifsAttrs = fattr->cf_cifsattrs;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400145
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400146 if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
147 cifs_i->time = 0;
148 else
149 cifs_i->time = jiffies;
150
Joe Perchesb6b38f72010-04-21 03:50:45 +0000151 cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode,
152 oldtime, cifs_i->time);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400153
154 cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000155
Jeff Layton835a36c2010-02-10 16:21:33 -0500156 cifs_i->server_eof = fattr->cf_eof;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000157 /*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400158 * Can't safely change the file size here if the client is writing to
159 * it due to potential races.
Christoph Hellwig75f12982008-02-25 20:25:21 +0000160 */
Christoph Hellwig75f12982008-02-25 20:25:21 +0000161 spin_lock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400162 if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
163 i_size_write(inode, fattr->cf_eof);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000164
165 /*
166 * i_blocks is not related to (i_size / i_blksize),
167 * but instead 512 byte (2**9) size is required for
168 * calculating num blocks.
169 */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400170 inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
Christoph Hellwig75f12982008-02-25 20:25:21 +0000171 }
172 spin_unlock(&inode->i_lock);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400173
David Howells01c64fe2011-01-14 18:45:47 +0000174 if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
175 inode->i_flags |= S_AUTOMOUNT;
176 cifs_set_ops(inode);
Christoph Hellwig75f12982008-02-25 20:25:21 +0000177}
178
Jeff Layton4065c802010-05-17 07:18:58 -0400179void
180cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr)
181{
182 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
183
184 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
185 return;
186
187 fattr->cf_uniqueid = iunique(sb, ROOT_I);
188}
189
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400190/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
191void
192cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
193 struct cifs_sb_info *cifs_sb)
194{
195 memset(fattr, 0, sizeof(*fattr));
196 fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
197 fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
198 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
199
200 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
201 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
202 fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
203 fattr->cf_mode = le64_to_cpu(info->Permissions);
204
205 /*
206 * Since we set the inode type below we need to mask off
207 * to avoid strange results if bits set above.
208 */
209 fattr->cf_mode &= ~S_IFMT;
210 switch (le32_to_cpu(info->Type)) {
211 case UNIX_FILE:
212 fattr->cf_mode |= S_IFREG;
213 fattr->cf_dtype = DT_REG;
214 break;
215 case UNIX_SYMLINK:
216 fattr->cf_mode |= S_IFLNK;
217 fattr->cf_dtype = DT_LNK;
218 break;
219 case UNIX_DIR:
220 fattr->cf_mode |= S_IFDIR;
221 fattr->cf_dtype = DT_DIR;
222 break;
223 case UNIX_CHARDEV:
224 fattr->cf_mode |= S_IFCHR;
225 fattr->cf_dtype = DT_CHR;
226 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
227 le64_to_cpu(info->DevMinor) & MINORMASK);
228 break;
229 case UNIX_BLOCKDEV:
230 fattr->cf_mode |= S_IFBLK;
231 fattr->cf_dtype = DT_BLK;
232 fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
233 le64_to_cpu(info->DevMinor) & MINORMASK);
234 break;
235 case UNIX_FIFO:
236 fattr->cf_mode |= S_IFIFO;
237 fattr->cf_dtype = DT_FIFO;
238 break;
239 case UNIX_SOCKET:
240 fattr->cf_mode |= S_IFSOCK;
241 fattr->cf_dtype = DT_SOCK;
242 break;
243 default:
244 /* safest to call it a file if we do not know */
245 fattr->cf_mode |= S_IFREG;
246 fattr->cf_dtype = DT_REG;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000247 cFYI(1, "unknown type %d", le32_to_cpu(info->Type));
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400248 break;
249 }
250
251 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
252 fattr->cf_uid = cifs_sb->mnt_uid;
253 else
254 fattr->cf_uid = le64_to_cpu(info->Uid);
255
256 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
257 fattr->cf_gid = cifs_sb->mnt_gid;
258 else
259 fattr->cf_gid = le64_to_cpu(info->Gid);
260
261 fattr->cf_nlink = le64_to_cpu(info->Nlinks);
262}
Steve Frenchb9a32602008-05-20 21:52:32 +0000263
264/*
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400265 * Fill a cifs_fattr struct with fake inode info.
266 *
267 * Needed to setup cifs_fattr data for the directory which is the
268 * junction to the new submount (ie to setup the fake directory
269 * which represents a DFS referral).
Steve Frenchb9a32602008-05-20 21:52:32 +0000270 */
Steve Frenchf1230c92009-07-22 23:13:01 +0000271static void
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400272cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
Steve French0e4bbde2008-05-20 19:50:46 +0000273{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400274 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Steve French0e4bbde2008-05-20 19:50:46 +0000275
Joe Perchesb6b38f72010-04-21 03:50:45 +0000276 cFYI(1, "creating fake fattr for DFS referral");
Steve French0e4bbde2008-05-20 19:50:46 +0000277
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400278 memset(fattr, 0, sizeof(*fattr));
279 fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
280 fattr->cf_uid = cifs_sb->mnt_uid;
281 fattr->cf_gid = cifs_sb->mnt_gid;
282 fattr->cf_atime = CURRENT_TIME;
283 fattr->cf_ctime = CURRENT_TIME;
284 fattr->cf_mtime = CURRENT_TIME;
285 fattr->cf_nlink = 2;
286 fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
Steve French0e4bbde2008-05-20 19:50:46 +0000287}
288
Jeff Laytonabab0952010-02-12 07:44:18 -0500289int cifs_get_file_info_unix(struct file *filp)
290{
291 int rc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400292 unsigned int xid;
Jeff Laytonabab0952010-02-12 07:44:18 -0500293 FILE_UNIX_BASIC_INFO find_data;
294 struct cifs_fattr fattr;
295 struct inode *inode = filp->f_path.dentry->d_inode;
296 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Joe Perchesc21dfb62010-07-12 13:50:14 -0700297 struct cifsFileInfo *cfile = filp->private_data;
Steve French96daf2b2011-05-27 04:34:02 +0000298 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Jeff Laytonabab0952010-02-12 07:44:18 -0500299
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400300 xid = get_xid();
Jeff Laytonabab0952010-02-12 07:44:18 -0500301 rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
302 if (!rc) {
303 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
304 } else if (rc == -EREMOTE) {
305 cifs_create_dfs_fattr(&fattr, inode->i_sb);
306 rc = 0;
307 }
308
309 cifs_fattr_to_inode(inode, &fattr);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400310 free_xid(xid);
Jeff Laytonabab0952010-02-12 07:44:18 -0500311 return rc;
312}
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314int cifs_get_inode_info_unix(struct inode **pinode,
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400315 const unsigned char *full_path,
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400316 struct super_block *sb, unsigned int xid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400318 int rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000319 FILE_UNIX_BASIC_INFO find_data;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400320 struct cifs_fattr fattr;
Steve French96daf2b2011-05-27 04:34:02 +0000321 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400322 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Joe Perchesb6b38f72010-04-21 03:50:45 +0000325 cFYI(1, "Getting info on %s", full_path);
Igor Mammedov79626702008-03-09 03:44:18 +0000326
Jeff Layton7ffec372010-09-29 19:51:11 -0400327 tlink = cifs_sb_tlink(cifs_sb);
328 if (IS_ERR(tlink))
329 return PTR_ERR(tlink);
330 tcon = tlink_tcon(tlink);
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /* could have done a find first instead but this returns more info */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400333 rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
Steve French737b7582005-04-28 22:41:06 -0700334 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
335 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -0400336 cifs_put_tlink(tlink);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400337
338 if (!rc) {
339 cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
340 } else if (rc == -EREMOTE) {
341 cifs_create_dfs_fattr(&fattr, sb);
Jeff Laytone911d0c2008-07-12 13:47:59 -0700342 rc = 0;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400343 } else {
344 return rc;
Steve French0e4bbde2008-05-20 19:50:46 +0000345 }
346
Stefan Metzmacher1b12b9c2010-08-05 21:19:56 +0200347 /* check for Minshall+French symlinks */
348 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
349 int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
350 if (tmprc)
351 cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
352 }
353
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400354 if (*pinode == NULL) {
355 /* get new inode */
Jeff Layton4065c802010-05-17 07:18:58 -0400356 cifs_fill_uniqueid(sb, &fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400357 *pinode = cifs_iget(sb, &fattr);
358 if (!*pinode)
359 rc = -ENOMEM;
360 } else {
361 /* we already have inode, update it */
362 cifs_fattr_to_inode(*pinode, &fattr);
363 }
Steve French0e4bbde2008-05-20 19:50:46 +0000364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 return rc;
366}
367
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400368static int
369cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400370 struct cifs_sb_info *cifs_sb, unsigned int xid)
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800371{
372 int rc;
Steve French4b18f2a2008-04-29 00:06:05 +0000373 int oplock = 0;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800374 __u16 netfid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400375 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +0000376 struct cifs_tcon *tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +0000377 struct cifs_io_parms io_parms;
Steve French86c96b42005-11-18 20:25:31 -0800378 char buf[24];
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800379 unsigned int bytes_read;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000380 char *pbuf;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800381
382 pbuf = buf;
383
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400384 fattr->cf_mode &= ~S_IFMT;
385
386 if (fattr->cf_eof == 0) {
387 fattr->cf_mode |= S_IFIFO;
388 fattr->cf_dtype = DT_FIFO;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800389 return 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400390 } else if (fattr->cf_eof < 8) {
391 fattr->cf_mode |= S_IFREG;
392 fattr->cf_dtype = DT_REG;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800393 return -EINVAL; /* EOPNOTSUPP? */
394 }
Steve French50c2f752007-07-13 00:33:32 +0000395
Jeff Layton7ffec372010-09-29 19:51:11 -0400396 tlink = cifs_sb_tlink(cifs_sb);
397 if (IS_ERR(tlink))
398 return PTR_ERR(tlink);
399 tcon = tlink_tcon(tlink);
400
401 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ,
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800402 CREATE_NOT_DIR, &netfid, &oplock, NULL,
403 cifs_sb->local_nls,
404 cifs_sb->mnt_cifs_flags &
405 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000406 if (rc == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -0800407 int buf_type = CIFS_NO_BUFFER;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800408 /* Read header */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +0000409 io_parms.netfid = netfid;
410 io_parms.pid = current->tgid;
411 io_parms.tcon = tcon;
412 io_parms.offset = 0;
413 io_parms.length = 24;
414 rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf,
415 &buf_type);
Steve French4523cc32007-04-30 20:13:06 +0000416 if ((rc == 0) && (bytes_read >= 8)) {
417 if (memcmp("IntxBLK", pbuf, 8) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000418 cFYI(1, "Block device");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400419 fattr->cf_mode |= S_IFBLK;
420 fattr->cf_dtype = DT_BLK;
Steve French4523cc32007-04-30 20:13:06 +0000421 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800422 /* we have enough to decode dev num */
423 __u64 mjr; /* major */
424 __u64 mnr; /* minor */
425 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
426 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400427 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve French86c96b42005-11-18 20:25:31 -0800428 }
Steve French4523cc32007-04-30 20:13:06 +0000429 } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000430 cFYI(1, "Char device");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400431 fattr->cf_mode |= S_IFCHR;
432 fattr->cf_dtype = DT_CHR;
Steve French4523cc32007-04-30 20:13:06 +0000433 if (bytes_read == 24) {
Steve French86c96b42005-11-18 20:25:31 -0800434 /* we have enough to decode dev num */
435 __u64 mjr; /* major */
436 __u64 mnr; /* minor */
437 mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
438 mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400439 fattr->cf_rdev = MKDEV(mjr, mnr);
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000440 }
Steve French4523cc32007-04-30 20:13:06 +0000441 } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000442 cFYI(1, "Symlink");
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400443 fattr->cf_mode |= S_IFLNK;
444 fattr->cf_dtype = DT_LNK;
Steve French86c96b42005-11-18 20:25:31 -0800445 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400446 fattr->cf_mode |= S_IFREG; /* file? */
447 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000448 rc = -EOPNOTSUPP;
Steve French86c96b42005-11-18 20:25:31 -0800449 }
Steve French3020a1f2005-11-18 11:31:10 -0800450 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400451 fattr->cf_mode |= S_IFREG; /* then it is a file */
452 fattr->cf_dtype = DT_REG;
Steve Frenchfb8c4b12007-07-10 01:16:18 +0000453 rc = -EOPNOTSUPP; /* or some unknown SFU type */
454 }
Jeff Layton7ffec372010-09-29 19:51:11 -0400455 CIFSSMBClose(xid, tcon, netfid);
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800456 }
Jeff Layton7ffec372010-09-29 19:51:11 -0400457 cifs_put_tlink(tlink);
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800458 return rc;
Steve Frenchd6e2f2a42005-11-15 16:43:39 -0800459}
460
Steve French9e294f12005-11-17 16:59:21 -0800461#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
462
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400463/*
464 * Fetch mode bits as provided by SFU.
465 *
466 * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
467 */
468static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400469 struct cifs_sb_info *cifs_sb, unsigned int xid)
Steve French9e294f12005-11-17 16:59:21 -0800470{
Steve French3020a1f2005-11-18 11:31:10 -0800471#ifdef CONFIG_CIFS_XATTR
Steve French9e294f12005-11-17 16:59:21 -0800472 ssize_t rc;
473 char ea_value[4];
474 __u32 mode;
Jeff Layton7ffec372010-09-29 19:51:11 -0400475 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +0000476 struct cifs_tcon *tcon;
Steve French9e294f12005-11-17 16:59:21 -0800477
Jeff Layton7ffec372010-09-29 19:51:11 -0400478 tlink = cifs_sb_tlink(cifs_sb);
479 if (IS_ERR(tlink))
480 return PTR_ERR(tlink);
481 tcon = tlink_tcon(tlink);
482
483 rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS",
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400484 ea_value, 4 /* size of buf */, cifs_sb->local_nls,
485 cifs_sb->mnt_cifs_flags &
486 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -0400487 cifs_put_tlink(tlink);
Steve French4523cc32007-04-30 20:13:06 +0000488 if (rc < 0)
Steve French9e294f12005-11-17 16:59:21 -0800489 return (int)rc;
490 else if (rc > 3) {
491 mode = le32_to_cpu(*((__le32 *)ea_value));
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400492 fattr->cf_mode &= ~SFBITS_MASK;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000493 cFYI(1, "special bits 0%o org mode 0%o", mode,
494 fattr->cf_mode);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400495 fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000496 cFYI(1, "special mode bits 0%o", mode);
Steve French9e294f12005-11-17 16:59:21 -0800497 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400498
499 return 0;
Steve French3020a1f2005-11-18 11:31:10 -0800500#else
501 return -EOPNOTSUPP;
502#endif
Steve French9e294f12005-11-17 16:59:21 -0800503}
504
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400505/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
Steve Frenchf1230c92009-07-22 23:13:01 +0000506static void
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400507cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
508 struct cifs_sb_info *cifs_sb, bool adjust_tz)
Steve Frenchb9a32602008-05-20 21:52:32 +0000509{
Steve French96daf2b2011-05-27 04:34:02 +0000510 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
Jeff Layton0d424ad2010-09-20 16:01:35 -0700511
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400512 memset(fattr, 0, sizeof(*fattr));
513 fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
514 if (info->DeletePending)
515 fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
Steve Frenchb9a32602008-05-20 21:52:32 +0000516
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400517 if (info->LastAccessTime)
518 fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
519 else
520 fattr->cf_atime = CURRENT_TIME;
521
522 fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
523 fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
524
525 if (adjust_tz) {
Jeff Layton0d424ad2010-09-20 16:01:35 -0700526 fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
527 fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400528 }
529
530 fattr->cf_eof = le64_to_cpu(info->EndOfFile);
531 fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
Jeff Layton20054bd2011-01-07 11:30:27 -0500532 fattr->cf_createtime = le64_to_cpu(info->CreationTime);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400533
534 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
535 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
536 fattr->cf_dtype = DT_DIR;
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +0300537 /*
538 * Server can return wrong NumberOfLinks value for directories
539 * when Unix extensions are disabled - fake it.
540 */
541 fattr->cf_nlink = 2;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400542 } else {
543 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
544 fattr->cf_dtype = DT_REG;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400545
Jeff Laytond0c280d2009-07-09 01:46:44 -0400546 /* clear write bits if ATTR_READONLY is set */
547 if (fattr->cf_cifsattrs & ATTR_READONLY)
548 fattr->cf_mode &= ~(S_IWUGO);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400549
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +0300550 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
551 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400552
553 fattr->cf_uid = cifs_sb->mnt_uid;
554 fattr->cf_gid = cifs_sb->mnt_gid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000555}
556
Jeff Laytonabab0952010-02-12 07:44:18 -0500557int cifs_get_file_info(struct file *filp)
558{
559 int rc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400560 unsigned int xid;
Jeff Laytonabab0952010-02-12 07:44:18 -0500561 FILE_ALL_INFO find_data;
562 struct cifs_fattr fattr;
563 struct inode *inode = filp->f_path.dentry->d_inode;
564 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Joe Perchesc21dfb62010-07-12 13:50:14 -0700565 struct cifsFileInfo *cfile = filp->private_data;
Steve French96daf2b2011-05-27 04:34:02 +0000566 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Jeff Laytonabab0952010-02-12 07:44:18 -0500567
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400568 xid = get_xid();
Jeff Laytonabab0952010-02-12 07:44:18 -0500569 rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400570 switch (rc) {
571 case 0:
572 cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
573 break;
574 case -EREMOTE:
575 cifs_create_dfs_fattr(&fattr, inode->i_sb);
576 rc = 0;
577 break;
578 case -EOPNOTSUPP:
579 case -EINVAL:
Jeff Laytonabab0952010-02-12 07:44:18 -0500580 /*
581 * FIXME: legacy server -- fall back to path-based call?
Steve Frenchff2157132010-03-09 20:30:42 +0000582 * for now, just skip revalidating and mark inode for
583 * immediate reval.
584 */
Jeff Laytonabab0952010-02-12 07:44:18 -0500585 rc = 0;
586 CIFS_I(inode)->time = 0;
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400587 default:
Jeff Laytonabab0952010-02-12 07:44:18 -0500588 goto cgfi_exit;
Pavel Shilovsky42274bb2011-10-22 14:37:50 +0400589 }
Jeff Laytonabab0952010-02-12 07:44:18 -0500590
591 /*
592 * don't bother with SFU junk here -- just mark inode as needing
593 * revalidation.
594 */
Jeff Laytonabab0952010-02-12 07:44:18 -0500595 fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
596 fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
597 cifs_fattr_to_inode(inode, &fattr);
598cgfi_exit:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400599 free_xid(xid);
Jeff Laytonabab0952010-02-12 07:44:18 -0500600 return rc;
601}
602
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400603int
604cifs_get_inode_info(struct inode **inode, const char *full_path,
605 FILE_ALL_INFO *data, struct super_block *sb, int xid,
606 const __u16 *fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607{
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400608 int rc = 0, tmprc;
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400609 struct cifs_tcon *tcon;
610 struct TCP_Server_Info *server;
Jeff Layton7ffec372010-09-29 19:51:11 -0400611 struct tcon_link *tlink;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 char *buf = NULL;
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400614 bool adjust_tz = false;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400615 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
Jeff Layton7ffec372010-09-29 19:51:11 -0400617 tlink = cifs_sb_tlink(cifs_sb);
618 if (IS_ERR(tlink))
619 return PTR_ERR(tlink);
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400620 tcon = tlink_tcon(tlink);
621 server = tcon->ses->server;
Jeff Layton7ffec372010-09-29 19:51:11 -0400622
Joe Perchesb6b38f72010-04-21 03:50:45 +0000623 cFYI(1, "Getting info on %s", full_path);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400625 if ((data == NULL) && (*inode != NULL)) {
626 if (CIFS_I(*inode)->clientCanCacheRead) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000627 cFYI(1, "No need to revalidate cached inode sizes");
Jeff Layton7ffec372010-09-29 19:51:11 -0400628 goto cgii_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
630 }
631
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400632 /* if inode info is not passed, get it from server */
633 if (data == NULL) {
634 if (!server->ops->query_path_info) {
635 rc = -ENOSYS;
636 goto cgii_exit;
637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
Jeff Layton7ffec372010-09-29 19:51:11 -0400639 if (buf == NULL) {
640 rc = -ENOMEM;
641 goto cgii_exit;
642 }
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400643 data = (FILE_ALL_INFO *)buf;
644 rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path,
645 data, &adjust_tz);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400647
648 if (!rc) {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400649 cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *)data, cifs_sb,
650 adjust_tz);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400651 } else if (rc == -EREMOTE) {
652 cifs_create_dfs_fattr(&fattr, sb);
Steve Frenchb9a32602008-05-20 21:52:32 +0000653 rc = 0;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400654 } else {
Igor Mammedov79626702008-03-09 03:44:18 +0000655 goto cgii_exit;
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400658 /*
659 * If an inode wasn't passed in, then get the inode number
660 *
661 * Is an i_ino of zero legal? Can we use that to check if the server
662 * supports returning inode numbers? Are there other sanity checks we
663 * can use to ensure that the server is really filling in that field?
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400664 */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400665 if (*inode == NULL) {
Steve Frenchb9a32602008-05-20 21:52:32 +0000666 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400667 if (server->ops->get_srv_inum)
668 tmprc = server->ops->get_srv_inum(xid, tcon,
669 cifs_sb, full_path, &fattr.cf_uniqueid,
670 data);
671 else
672 tmprc = -ENOSYS;
673 if (tmprc || !fattr.cf_uniqueid) {
674 cFYI(1, "GetSrvInodeNum rc %d", tmprc);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400675 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Laytonec06aed2009-11-06 14:18:29 -0500676 cifs_autodisable_serverino(cifs_sb);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500677 }
Jeff Layton132ac7b2009-02-10 07:33:57 -0500678 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400679 fattr.cf_uniqueid = iunique(sb, ROOT_I);
Jeff Layton132ac7b2009-02-10 07:33:57 -0500680 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000681 } else {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400682 fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
Steve Frenchb9a32602008-05-20 21:52:32 +0000683 }
684
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400685 /* query for SFU type info if supported and needed */
686 if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
687 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
688 tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
689 if (tmprc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000690 cFYI(1, "cifs_sfu_type failed: %d", tmprc);
Steve Frenchb9a32602008-05-20 21:52:32 +0000691 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000692
Jeff Layton79df1ba2010-12-06 12:52:08 -0500693#ifdef CONFIG_CIFS_ACL
Steve Frenchb9a32602008-05-20 21:52:32 +0000694 /* fill in 0777 bits from ACL */
695 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400696 rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid);
Shirish Pargaonkar78415d22010-11-27 11:37:26 -0600697 if (rc) {
698 cFYI(1, "%s: Getting ACL failed with error: %d",
699 __func__, rc);
700 goto cgii_exit;
701 }
Steve Frenchb9a32602008-05-20 21:52:32 +0000702 }
Jeff Layton79df1ba2010-12-06 12:52:08 -0500703#endif /* CONFIG_CIFS_ACL */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400704
705 /* fill in remaining high mode bits e.g. SUID, VTX */
706 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
707 cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
708
Stefan Metzmacher1b12b9c2010-08-05 21:19:56 +0200709 /* check for Minshall+French symlinks */
710 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
711 tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
712 if (tmprc)
713 cFYI(1, "CIFSCheckMFSymlink: %d", tmprc);
714 }
715
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400716 if (!*inode) {
717 *inode = cifs_iget(sb, &fattr);
718 if (!*inode)
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400719 rc = -ENOMEM;
720 } else {
Pavel Shilovsky1208ef12012-05-27 17:34:43 +0400721 cifs_fattr_to_inode(*inode, &fattr);
Steve Frenchb9a32602008-05-20 21:52:32 +0000722 }
723
Igor Mammedov79626702008-03-09 03:44:18 +0000724cgii_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 kfree(buf);
Jeff Layton7ffec372010-09-29 19:51:11 -0400726 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return rc;
728}
729
Steve French7f8ed422007-09-28 22:28:55 +0000730static const struct inode_operations cifs_ipc_inode_ops = {
731 .lookup = cifs_lookup,
732};
733
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400734static int
735cifs_find_inode(struct inode *inode, void *opaque)
736{
737 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
738
Jeff Laytonf30b9c12010-07-19 18:00:17 -0400739 /* don't match inode with different uniqueid */
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400740 if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
741 return 0;
742
Jeff Layton20054bd2011-01-07 11:30:27 -0500743 /* use createtime like an i_generation field */
744 if (CIFS_I(inode)->createtime != fattr->cf_createtime)
745 return 0;
746
Jeff Laytonf30b9c12010-07-19 18:00:17 -0400747 /* don't match inode of different type */
748 if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
749 return 0;
750
Jeff Layton5acfec22010-08-02 17:43:54 -0400751 /* if it's not a directory or has no dentries, then flag it */
Al Virob3d9b7a2012-06-09 13:51:19 -0400752 if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
Jeff Layton3d694382010-05-11 14:59:55 -0400753 fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
Jeff Layton3d694382010-05-11 14:59:55 -0400754
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400755 return 1;
756}
757
758static int
759cifs_init_inode(struct inode *inode, void *opaque)
760{
761 struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;
762
763 CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
Jeff Layton20054bd2011-01-07 11:30:27 -0500764 CIFS_I(inode)->createtime = fattr->cf_createtime;
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400765 return 0;
766}
767
Jeff Layton5acfec22010-08-02 17:43:54 -0400768/*
769 * walk dentry list for an inode and report whether it has aliases that
770 * are hashed. We use this to determine if a directory inode can actually
771 * be used.
772 */
773static bool
774inode_has_hashed_dentries(struct inode *inode)
775{
776 struct dentry *dentry;
Al Virob3d9b7a2012-06-09 13:51:19 -0400777 struct hlist_node *p;
Jeff Layton5acfec22010-08-02 17:43:54 -0400778
Nick Piggin873feea2011-01-07 17:50:06 +1100779 spin_lock(&inode->i_lock);
Al Virob3d9b7a2012-06-09 13:51:19 -0400780 hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
Jeff Layton5acfec22010-08-02 17:43:54 -0400781 if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
Nick Piggin873feea2011-01-07 17:50:06 +1100782 spin_unlock(&inode->i_lock);
Jeff Layton5acfec22010-08-02 17:43:54 -0400783 return true;
784 }
785 }
Nick Piggin873feea2011-01-07 17:50:06 +1100786 spin_unlock(&inode->i_lock);
Jeff Layton5acfec22010-08-02 17:43:54 -0400787 return false;
788}
789
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400790/* Given fattrs, get a corresponding inode */
791struct inode *
792cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
793{
794 unsigned long hash;
795 struct inode *inode;
796
Jeff Layton3d694382010-05-11 14:59:55 -0400797retry_iget5_locked:
Joe Perchesb6b38f72010-04-21 03:50:45 +0000798 cFYI(1, "looking for uniqueid=%llu", fattr->cf_uniqueid);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400799
800 /* hash down to 32-bits on 32-bit arch */
801 hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);
802
803 inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400804 if (inode) {
Jeff Layton5acfec22010-08-02 17:43:54 -0400805 /* was there a potentially problematic inode collision? */
Jeff Layton3d694382010-05-11 14:59:55 -0400806 if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
Jeff Layton3d694382010-05-11 14:59:55 -0400807 fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
Jeff Layton5acfec22010-08-02 17:43:54 -0400808
809 if (inode_has_hashed_dentries(inode)) {
810 cifs_autodisable_serverino(CIFS_SB(sb));
811 iput(inode);
812 fattr->cf_uniqueid = iunique(sb, ROOT_I);
813 goto retry_iget5_locked;
814 }
Jeff Layton3d694382010-05-11 14:59:55 -0400815 }
816
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400817 cifs_fattr_to_inode(inode, fattr);
818 if (sb->s_flags & MS_NOATIME)
819 inode->i_flags |= S_NOATIME | S_NOCMTIME;
820 if (inode->i_state & I_NEW) {
821 inode->i_ino = hash;
Jeff Layton522440e2010-09-29 09:49:54 -0400822 if (S_ISREG(inode->i_mode))
823 inode->i_data.backing_dev_info = sb->s_bdi;
Steve French0ccd4802010-07-16 04:31:02 +0000824#ifdef CONFIG_CIFS_FSCACHE
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +0530825 /* initialize per-inode cache cookie pointer */
826 CIFS_I(inode)->fscache = NULL;
Steve French0ccd4802010-07-16 04:31:02 +0000827#endif
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400828 unlock_new_inode(inode);
829 }
830 }
831
832 return inode;
833}
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835/* gets root inode */
Shirish Pargaonkar9b6763e2011-02-21 23:56:59 -0600836struct inode *cifs_root_iget(struct super_block *sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837{
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400838 unsigned int xid;
Jeff Layton0d424ad2010-09-20 16:01:35 -0700839 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400840 struct inode *inode = NULL;
David Howellsce634ab2008-02-07 00:15:33 -0800841 long rc;
Steve French96daf2b2011-05-27 04:34:02 +0000842 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
David Howellsce634ab2008-02-07 00:15:33 -0800843
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400844 xid = get_xid();
Jeff Layton0d424ad2010-09-20 16:01:35 -0700845 if (tcon->unix_ext)
Steve Frenchf87d39d2011-05-27 03:50:55 +0000846 rc = cifs_get_inode_info_unix(&inode, "", sb, xid);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400847 else
Steve Frenchf87d39d2011-05-27 03:50:55 +0000848 rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL);
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400849
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000850 if (!inode) {
851 inode = ERR_PTR(rc);
852 goto out;
853 }
Jeff Laytoncc0bad72009-06-25 00:56:52 -0400854
Steve French0ccd4802010-07-16 04:31:02 +0000855#ifdef CONFIG_CIFS_FSCACHE
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530856 /* populate tcon->resource_id */
Jeff Layton0d424ad2010-09-20 16:01:35 -0700857 tcon->resource_id = CIFS_I(inode)->uniqueid;
Steve French0ccd4802010-07-16 04:31:02 +0000858#endif
Suresh Jayaramand03382c2010-07-05 18:12:27 +0530859
Jeff Layton0d424ad2010-09-20 16:01:35 -0700860 if (rc && tcon->ipc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000861 cFYI(1, "ipc connection - fake read inode");
Steve French7f8ed422007-09-28 22:28:55 +0000862 inode->i_mode |= S_IFDIR;
Miklos Szeredibfe86842011-10-28 14:13:29 +0200863 set_nlink(inode, 2);
Steve French7f8ed422007-09-28 22:28:55 +0000864 inode->i_op = &cifs_ipc_inode_ops;
865 inode->i_fop = &simple_dir_operations;
866 inode->i_uid = cifs_sb->mnt_uid;
867 inode->i_gid = cifs_sb->mnt_gid;
Steve Frenchad661332008-08-12 14:14:40 +0000868 } else if (rc) {
David Howellsce634ab2008-02-07 00:15:33 -0800869 iget_failed(inode);
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000870 inode = ERR_PTR(rc);
Steve French7f8ed422007-09-28 22:28:55 +0000871 }
872
Oskar Schirmera7851ce2010-11-10 21:06:13 +0000873out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400874 /* can not call macro free_xid here since in a void func
David Howellsce634ab2008-02-07 00:15:33 -0800875 * TODO: This is no longer true
876 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400877 _free_xid(xid);
David Howellsce634ab2008-02-07 00:15:33 -0800878 return inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879}
880
Steve French388e57b2008-09-16 23:50:58 +0000881static int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400882cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
Steve French388e57b2008-09-16 23:50:58 +0000883 char *full_path, __u32 dosattr)
884{
885 int rc;
886 int oplock = 0;
887 __u16 netfid;
888 __u32 netpid;
889 bool set_time = false;
890 struct cifsFileInfo *open_file;
891 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
892 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400893 struct tcon_link *tlink = NULL;
Steve French96daf2b2011-05-27 04:34:02 +0000894 struct cifs_tcon *pTcon;
Steve French388e57b2008-09-16 23:50:58 +0000895 FILE_BASIC_INFO info_buf;
896
Steve French1adcb712009-02-25 14:19:56 +0000897 if (attrs == NULL)
898 return -EINVAL;
899
Steve French388e57b2008-09-16 23:50:58 +0000900 if (attrs->ia_valid & ATTR_ATIME) {
901 set_time = true;
902 info_buf.LastAccessTime =
903 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
904 } else
905 info_buf.LastAccessTime = 0;
906
907 if (attrs->ia_valid & ATTR_MTIME) {
908 set_time = true;
909 info_buf.LastWriteTime =
910 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
911 } else
912 info_buf.LastWriteTime = 0;
913
914 /*
915 * Samba throws this field away, but windows may actually use it.
916 * Do not set ctime unless other time stamps are changed explicitly
917 * (i.e. by utimes()) since we would then have a mix of client and
918 * server times.
919 */
920 if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000921 cFYI(1, "CIFS - CTIME changed");
Steve French388e57b2008-09-16 23:50:58 +0000922 info_buf.ChangeTime =
923 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
924 } else
925 info_buf.ChangeTime = 0;
926
927 info_buf.CreationTime = 0; /* don't change */
928 info_buf.Attributes = cpu_to_le32(dosattr);
929
930 /*
931 * If the file is already open for write, just use that fileid
932 */
Jeff Layton6508d902010-09-29 19:51:11 -0400933 open_file = find_writable_file(cifsInode, true);
Steve French388e57b2008-09-16 23:50:58 +0000934 if (open_file) {
935 netfid = open_file->netfid;
936 netpid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -0400937 pTcon = tlink_tcon(open_file->tlink);
Steve French388e57b2008-09-16 23:50:58 +0000938 goto set_via_filehandle;
939 }
940
Jeff Layton7ffec372010-09-29 19:51:11 -0400941 tlink = cifs_sb_tlink(cifs_sb);
942 if (IS_ERR(tlink)) {
943 rc = PTR_ERR(tlink);
944 tlink = NULL;
945 goto out;
946 }
947 pTcon = tlink_tcon(tlink);
Jeff Laytonba00ba62010-09-20 16:01:31 -0700948
Steve French388e57b2008-09-16 23:50:58 +0000949 /*
950 * NT4 apparently returns success on this call, but it doesn't
951 * really work.
952 */
953 if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
954 rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
955 &info_buf, cifs_sb->local_nls,
956 cifs_sb->mnt_cifs_flags &
957 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +0000958 if (rc == 0) {
959 cifsInode->cifsAttrs = dosattr;
960 goto out;
961 } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
Steve French388e57b2008-09-16 23:50:58 +0000962 goto out;
963 }
964
Joe Perchesb6b38f72010-04-21 03:50:45 +0000965 cFYI(1, "calling SetFileInfo since SetPathInfo for "
966 "times not supported by this server");
Steve French388e57b2008-09-16 23:50:58 +0000967 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
968 SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
969 CREATE_NOT_DIR, &netfid, &oplock,
970 NULL, cifs_sb->local_nls,
971 cifs_sb->mnt_cifs_flags &
972 CIFS_MOUNT_MAP_SPECIAL_CHR);
973
974 if (rc != 0) {
975 if (rc == -EIO)
976 rc = -EINVAL;
977 goto out;
978 }
979
980 netpid = current->tgid;
981
982set_via_filehandle:
983 rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
Steve Frenchd3889082008-09-24 19:22:52 +0000984 if (!rc)
985 cifsInode->cifsAttrs = dosattr;
986
Steve French388e57b2008-09-16 23:50:58 +0000987 if (open_file == NULL)
988 CIFSSMBClose(xid, pTcon, netfid);
989 else
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400990 cifsFileInfo_put(open_file);
Steve French388e57b2008-09-16 23:50:58 +0000991out:
Jeff Layton7ffec372010-09-29 19:51:11 -0400992 if (tlink != NULL)
993 cifs_put_tlink(tlink);
Steve French388e57b2008-09-16 23:50:58 +0000994 return rc;
995}
996
Jeff Laytona12a1ac2008-09-23 11:48:35 -0400997/*
998 * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
999 * and rename it to a random name that hopefully won't conflict with
1000 * anything else.
1001 */
1002static int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001003cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
1004 unsigned int xid)
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001005{
1006 int oplock = 0;
1007 int rc;
1008 __u16 netfid;
Steve French32709582008-10-20 00:44:19 +00001009 struct inode *inode = dentry->d_inode;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001010 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1011 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001012 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001013 struct cifs_tcon *tcon;
Steve French32709582008-10-20 00:44:19 +00001014 __u32 dosattr, origattr;
1015 FILE_BASIC_INFO *info_buf = NULL;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001016
Jeff Layton7ffec372010-09-29 19:51:11 -04001017 tlink = cifs_sb_tlink(cifs_sb);
1018 if (IS_ERR(tlink))
1019 return PTR_ERR(tlink);
1020 tcon = tlink_tcon(tlink);
1021
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001022 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
Jeff Laytondd1db2d2008-10-16 19:27:12 -04001023 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001024 &netfid, &oplock, NULL, cifs_sb->local_nls,
1025 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1026 if (rc != 0)
1027 goto out;
1028
Steve French32709582008-10-20 00:44:19 +00001029 origattr = cifsInode->cifsAttrs;
1030 if (origattr == 0)
1031 origattr |= ATTR_NORMAL;
1032
1033 dosattr = origattr & ~ATTR_READONLY;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001034 if (dosattr == 0)
1035 dosattr |= ATTR_NORMAL;
1036 dosattr |= ATTR_HIDDEN;
1037
Steve French32709582008-10-20 00:44:19 +00001038 /* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
1039 if (dosattr != origattr) {
1040 info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
1041 if (info_buf == NULL) {
1042 rc = -ENOMEM;
1043 goto out_close;
1044 }
1045 info_buf->Attributes = cpu_to_le32(dosattr);
1046 rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1047 current->tgid);
1048 /* although we would like to mark the file hidden
1049 if that fails we will still try to rename it */
Steve French41346092008-10-20 18:24:42 +00001050 if (rc != 0)
Steve French32709582008-10-20 00:44:19 +00001051 cifsInode->cifsAttrs = dosattr;
1052 else
1053 dosattr = origattr; /* since not able to change them */
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001054 }
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001055
Jeff Laytondd1db2d2008-10-16 19:27:12 -04001056 /* rename the file */
1057 rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001058 cifs_sb->mnt_cifs_flags &
1059 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French32709582008-10-20 00:44:19 +00001060 if (rc != 0) {
1061 rc = -ETXTBSY;
1062 goto undo_setattr;
1063 }
Jeff Layton6d22f092008-09-23 11:48:35 -04001064
Steve French32709582008-10-20 00:44:19 +00001065 /* try to set DELETE_ON_CLOSE */
1066 if (!cifsInode->delete_pending) {
1067 rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
1068 current->tgid);
1069 /*
1070 * some samba versions return -ENOENT when we try to set the
1071 * file disposition here. Likely a samba bug, but work around
1072 * it for now. This means that some cifsXXX files may hang
1073 * around after they shouldn't.
1074 *
1075 * BB: remove this hack after more servers have the fix
1076 */
1077 if (rc == -ENOENT)
1078 rc = 0;
1079 else if (rc != 0) {
1080 rc = -ETXTBSY;
1081 goto undo_rename;
1082 }
1083 cifsInode->delete_pending = true;
1084 }
Jeff Layton7ce86d52008-09-24 11:32:59 -04001085
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001086out_close:
1087 CIFSSMBClose(xid, tcon, netfid);
1088out:
Steve French32709582008-10-20 00:44:19 +00001089 kfree(info_buf);
Jeff Layton7ffec372010-09-29 19:51:11 -04001090 cifs_put_tlink(tlink);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001091 return rc;
Steve French32709582008-10-20 00:44:19 +00001092
1093 /*
1094 * reset everything back to the original state. Don't bother
1095 * dealing with errors here since we can't do anything about
1096 * them anyway.
1097 */
1098undo_rename:
1099 CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
1100 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1101 CIFS_MOUNT_MAP_SPECIAL_CHR);
1102undo_setattr:
1103 if (dosattr != origattr) {
1104 info_buf->Attributes = cpu_to_le32(origattr);
1105 if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
1106 current->tgid))
1107 cifsInode->cifsAttrs = origattr;
1108 }
1109
1110 goto out_close;
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001111}
1112
Steve Frenchff694522009-04-20 19:45:13 +00001113
1114/*
1115 * If dentry->d_inode is null (usually meaning the cached dentry
1116 * is a negative dentry) then we would attempt a standard SMB delete, but
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001117 * if that fails we can not attempt the fall back mechanisms on EACCESS
1118 * but will return the EACCESS to the caller. Note that the VFS does not call
Steve Frenchff694522009-04-20 19:45:13 +00001119 * unlink on negative dentries currently.
1120 */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001121int cifs_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
1123 int rc = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001124 unsigned int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 char *full_path = NULL;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001126 struct inode *inode = dentry->d_inode;
Steve Frenchff694522009-04-20 19:45:13 +00001127 struct cifsInodeInfo *cifs_inode;
Jeff Layton5f0319a2008-09-16 14:05:16 -04001128 struct super_block *sb = dir->i_sb;
1129 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001130 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001131 struct cifs_tcon *tcon;
Steve French60502472008-10-07 18:42:52 +00001132 struct iattr *attrs = NULL;
1133 __u32 dosattr = 0, origattr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Joe Perchesb6b38f72010-04-21 03:50:45 +00001135 cFYI(1, "cifs_unlink, dir=0x%p, dentry=0x%p", dir, dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Jeff Layton7ffec372010-09-29 19:51:11 -04001137 tlink = cifs_sb_tlink(cifs_sb);
1138 if (IS_ERR(tlink))
1139 return PTR_ERR(tlink);
1140 tcon = tlink_tcon(tlink);
1141
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001142 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Jeff Layton5f0319a2008-09-16 14:05:16 -04001144 /* Unlink can be called from rename so we can not take the
1145 * sb->s_vfs_rename_mutex here */
1146 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301148 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001149 goto unlink_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
Steve French2d785a52007-07-15 01:48:57 +00001151
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001152 if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
1153 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001154 rc = CIFSPOSIXDelFile(xid, tcon, full_path,
Steve French2d785a52007-07-15 01:48:57 +00001155 SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
1156 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001157 cFYI(1, "posix del rc %d", rc);
Steve French2d785a52007-07-15 01:48:57 +00001158 if ((rc == 0) || (rc == -ENOENT))
1159 goto psx_del_no_retry;
1160 }
1161
Steve French60502472008-10-07 18:42:52 +00001162retry_std_delete:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001163 rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001164 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French60502472008-10-07 18:42:52 +00001165
Steve French2d785a52007-07-15 01:48:57 +00001166psx_del_no_retry:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 if (!rc) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001168 if (inode)
1169 drop_nlink(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 } else if (rc == -ENOENT) {
Jeff Layton5f0319a2008-09-16 14:05:16 -04001171 d_drop(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 } else if (rc == -ETXTBSY) {
Steve French32709582008-10-20 00:44:19 +00001173 rc = cifs_rename_pending_delete(full_path, dentry, xid);
Jeff Laytona12a1ac2008-09-23 11:48:35 -04001174 if (rc == 0)
1175 drop_nlink(inode);
Steve Frenchff694522009-04-20 19:45:13 +00001176 } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
Steve French388e57b2008-09-16 23:50:58 +00001177 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
1178 if (attrs == NULL) {
1179 rc = -ENOMEM;
1180 goto out_reval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
Steve French388e57b2008-09-16 23:50:58 +00001182
1183 /* try to reset dos attributes */
Steve Frenchff694522009-04-20 19:45:13 +00001184 cifs_inode = CIFS_I(inode);
1185 origattr = cifs_inode->cifsAttrs;
Steve French60502472008-10-07 18:42:52 +00001186 if (origattr == 0)
1187 origattr |= ATTR_NORMAL;
1188 dosattr = origattr & ~ATTR_READONLY;
Steve French388e57b2008-09-16 23:50:58 +00001189 if (dosattr == 0)
1190 dosattr |= ATTR_NORMAL;
1191 dosattr |= ATTR_HIDDEN;
1192
1193 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
Steve French388e57b2008-09-16 23:50:58 +00001194 if (rc != 0)
1195 goto out_reval;
Steve French60502472008-10-07 18:42:52 +00001196
1197 goto retry_std_delete;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 }
Steve French60502472008-10-07 18:42:52 +00001199
1200 /* undo the setattr if we errored out and it's needed */
1201 if (rc != 0 && dosattr != 0)
1202 cifs_set_file_info(inode, attrs, xid, full_path, origattr);
1203
Steve French388e57b2008-09-16 23:50:58 +00001204out_reval:
Jeff Layton5f0319a2008-09-16 14:05:16 -04001205 if (inode) {
Steve Frenchff694522009-04-20 19:45:13 +00001206 cifs_inode = CIFS_I(inode);
1207 cifs_inode->time = 0; /* will force revalidate to get info
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001208 when needed */
Jeff Layton5f0319a2008-09-16 14:05:16 -04001209 inode->i_ctime = current_fs_time(sb);
Steve Frenchb2aeb9d2005-05-17 13:16:18 -05001210 }
Jeff Layton5f0319a2008-09-16 14:05:16 -04001211 dir->i_ctime = dir->i_mtime = current_fs_time(sb);
Steve Frenchff694522009-04-20 19:45:13 +00001212 cifs_inode = CIFS_I(dir);
Steve French60502472008-10-07 18:42:52 +00001213 CIFS_I(dir)->time = 0; /* force revalidate of dir as well */
Jeff Layton7ffec372010-09-29 19:51:11 -04001214unlink_out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 kfree(full_path);
Steve French60502472008-10-07 18:42:52 +00001216 kfree(attrs);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001217 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001218 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 return rc;
1220}
1221
Al Viro18bb1db2011-07-26 01:41:39 -04001222int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
Jeff Layton6b37faa2008-10-06 21:54:41 +00001224 int rc = 0, tmprc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001225 unsigned int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001227 struct tcon_link *tlink;
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001228 struct cifs_tcon *tcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 char *full_path = NULL;
1230 struct inode *newinode = NULL;
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001231 struct cifs_fattr fattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
Al Viro18bb1db2011-07-26 01:41:39 -04001233 cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001236 tlink = cifs_sb_tlink(cifs_sb);
1237 if (IS_ERR(tlink))
1238 return PTR_ERR(tlink);
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001239 tcon = tlink_tcon(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001240
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001241 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
Steve French7f573562005-08-30 11:32:14 -07001243 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301245 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001246 goto mkdir_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 }
Steve French50c2f752007-07-13 00:33:32 +00001248
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001249 if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
1250 le64_to_cpu(tcon->fsUnixInfo.Capability))) {
Steve French2dd29d32007-04-23 22:07:35 +00001251 u32 oplock = 0;
Steve Frenchf6d09982008-01-08 23:18:22 +00001252 FILE_UNIX_BASIC_INFO *pInfo =
Steve French2dd29d32007-04-23 22:07:35 +00001253 kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001254 if (pInfo == NULL) {
Steve French2dd29d32007-04-23 22:07:35 +00001255 rc = -ENOMEM;
1256 goto mkdir_out;
1257 }
Steve French50c2f752007-07-13 00:33:32 +00001258
Al Viroce3b0f82009-03-29 19:08:22 -04001259 mode &= ~current_umask();
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001260 rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
Steve French2dd29d32007-04-23 22:07:35 +00001261 mode, NULL /* netfid */, pInfo, &oplock,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001262 full_path, cifs_sb->local_nls,
1263 cifs_sb->mnt_cifs_flags &
Steve French2dd29d32007-04-23 22:07:35 +00001264 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve Frenchc45d7072007-09-17 02:04:21 +00001265 if (rc == -EOPNOTSUPP) {
1266 kfree(pInfo);
1267 goto mkdir_retry_old;
1268 } else if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001269 cFYI(1, "posix mkdir returned 0x%x", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001270 d_drop(direntry);
1271 } else {
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001272 if (pInfo->Type == cpu_to_le32(-1)) {
1273 /* no return info, go query for it */
Steve French5a07cdf2007-09-16 23:12:47 +00001274 kfree(pInfo);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001275 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001276 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001277/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
1278 to set uid/gid */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001279
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001280 cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
Jeff Layton4065c802010-05-17 07:18:58 -04001281 cifs_fill_uniqueid(inode->i_sb, &fattr);
Jeff Laytoncc0bad72009-06-25 00:56:52 -04001282 newinode = cifs_iget(inode->i_sb, &fattr);
1283 if (!newinode) {
Steve French5a07cdf2007-09-16 23:12:47 +00001284 kfree(pInfo);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001285 goto mkdir_get_info;
Steve French5a07cdf2007-09-16 23:12:47 +00001286 }
Jeff Layton6b37faa2008-10-06 21:54:41 +00001287
Steve French2dd29d32007-04-23 22:07:35 +00001288 d_instantiate(direntry, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001289
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001290#ifdef CONFIG_CIFS_DEBUG2
Joe Perchesb6b38f72010-04-21 03:50:45 +00001291 cFYI(1, "instantiated dentry %p %s to inode %p",
1292 direntry, direntry->d_name.name, newinode);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001293
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001294 if (newinode->i_nlink != 2)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001295 cFYI(1, "unexpected number of links %d",
1296 newinode->i_nlink);
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001297#endif
Steve French2dd29d32007-04-23 22:07:35 +00001298 }
1299 kfree(pInfo);
1300 goto mkdir_out;
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001301 }
Steve Frenchc45d7072007-09-17 02:04:21 +00001302mkdir_retry_old:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 /* BB add setting the equivalent of mode via CreateX w/ACLs */
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001304 rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
Steve French737b7582005-04-28 22:41:06 -07001305 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001307 cFYI(1, "cifs_mkdir returned 0x%x", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 d_drop(direntry);
1309 } else {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001310mkdir_get_info:
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001311 if (tcon->unix_ext)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 rc = cifs_get_inode_info_unix(&newinode, full_path,
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001313 inode->i_sb, xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 else
1315 rc = cifs_get_inode_info(&newinode, full_path, NULL,
Steve French8b1327f2008-03-14 22:37:16 +00001316 inode->i_sb, xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 d_instantiate(direntry, newinode);
Steve French2dd29d32007-04-23 22:07:35 +00001319 /* setting nlink not necessary except in cases where we
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001320 * failed to get it from the server or was set bogus */
Steve French2dd29d32007-04-23 22:07:35 +00001321 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
Miklos Szeredibfe86842011-10-28 14:13:29 +02001322 set_nlink(direntry->d_inode, 2);
Jeff Layton95089912008-08-06 04:39:02 +00001323
Al Viroce3b0f82009-03-29 19:08:22 -04001324 mode &= ~current_umask();
Jeff Layton95089912008-08-06 04:39:02 +00001325 /* must turn on setgid bit if parent dir has it */
1326 if (inode->i_mode & S_ISGID)
1327 mode |= S_ISGID;
1328
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001329 if (tcon->unix_ext) {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001330 struct cifs_unix_set_info_args args = {
1331 .mode = mode,
1332 .ctime = NO_CHANGE_64,
1333 .atime = NO_CHANGE_64,
1334 .mtime = NO_CHANGE_64,
1335 .device = 0,
1336 };
Steve Frenchd0d2f2d2005-06-02 15:12:36 -07001337 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
David Howellsa001e5b2008-11-14 10:38:47 +11001338 args.uid = (__u64)current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001339 if (inode->i_mode & S_ISGID)
1340 args.gid = (__u64)inode->i_gid;
1341 else
David Howellsa001e5b2008-11-14 10:38:47 +11001342 args.gid = (__u64)current_fsgid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 } else {
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04001344 args.uid = NO_CHANGE_64;
1345 args.gid = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 }
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001347 CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
Jeff Layton01ea95e2009-07-09 20:02:49 -04001348 cifs_sb->local_nls,
1349 cifs_sb->mnt_cifs_flags &
1350 CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French3ce53fc2007-06-08 14:55:14 +00001351 } else {
Jeff Layton67750fb2008-05-09 22:28:02 +00001352 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1353 (mode & S_IWUGO) == 0) {
1354 FILE_BASIC_INFO pInfo;
Jeff Layton6b37faa2008-10-06 21:54:41 +00001355 struct cifsInodeInfo *cifsInode;
1356 u32 dosattrs;
1357
Jeff Layton67750fb2008-05-09 22:28:02 +00001358 memset(&pInfo, 0, sizeof(pInfo));
Jeff Layton6b37faa2008-10-06 21:54:41 +00001359 cifsInode = CIFS_I(newinode);
1360 dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
1361 pInfo.Attributes = cpu_to_le32(dosattrs);
Pavel Shilovsky29e20f92012-07-13 13:58:14 +04001362 tmprc = CIFSSMBSetPathInfo(xid, tcon,
Jeff Layton6b37faa2008-10-06 21:54:41 +00001363 full_path, &pInfo,
1364 cifs_sb->local_nls,
Jeff Layton67750fb2008-05-09 22:28:02 +00001365 cifs_sb->mnt_cifs_flags &
1366 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton6b37faa2008-10-06 21:54:41 +00001367 if (tmprc == 0)
1368 cifsInode->cifsAttrs = dosattrs;
Jeff Layton67750fb2008-05-09 22:28:02 +00001369 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001370 if (direntry->d_inode) {
Jeff Laytonb0fd30d2008-05-22 09:33:34 -04001371 if (cifs_sb->mnt_cifs_flags &
1372 CIFS_MOUNT_DYNPERM)
1373 direntry->d_inode->i_mode =
1374 (mode | S_IFDIR);
Steve French4e94a102008-05-23 18:22:46 +00001375
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001376 if (cifs_sb->mnt_cifs_flags &
Steve French6473a552005-11-29 20:20:10 -08001377 CIFS_MOUNT_SET_UID) {
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001378 direntry->d_inode->i_uid =
David Howellsa001e5b2008-11-14 10:38:47 +11001379 current_fsuid();
Jeff Layton95089912008-08-06 04:39:02 +00001380 if (inode->i_mode & S_ISGID)
1381 direntry->d_inode->i_gid =
1382 inode->i_gid;
1383 else
1384 direntry->d_inode->i_gid =
David Howellsa001e5b2008-11-14 10:38:47 +11001385 current_fsgid();
Steve French6473a552005-11-29 20:20:10 -08001386 }
1387 }
Steve French2a138ebb2005-11-29 21:22:19 -08001388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 }
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001390mkdir_out:
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001391 /*
1392 * Force revalidate to get parent dir info when needed since cached
1393 * attributes are invalid now.
1394 */
1395 CIFS_I(inode)->time = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001397 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001398 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 return rc;
1400}
1401
1402int cifs_rmdir(struct inode *inode, struct dentry *direntry)
1403{
1404 int rc = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001405 unsigned int xid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001407 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001408 struct cifs_tcon *pTcon;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 char *full_path = NULL;
1410 struct cifsInodeInfo *cifsInode;
1411
Joe Perchesb6b38f72010-04-21 03:50:45 +00001412 cFYI(1, "cifs_rmdir, inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001414 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
Steve French7f573562005-08-30 11:32:14 -07001416 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301418 rc = -ENOMEM;
Jeff Layton7ffec372010-09-29 19:51:11 -04001419 goto rmdir_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 }
1421
Jeff Layton7ffec372010-09-29 19:51:11 -04001422 cifs_sb = CIFS_SB(inode->i_sb);
1423 tlink = cifs_sb_tlink(cifs_sb);
1424 if (IS_ERR(tlink)) {
1425 rc = PTR_ERR(tlink);
1426 goto rmdir_exit;
1427 }
1428 pTcon = tlink_tcon(tlink);
1429
Steve French737b7582005-04-28 22:41:06 -07001430 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
1431 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -04001432 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
1434 if (!rc) {
Steve French3677db12007-02-26 16:46:11 +00001435 spin_lock(&direntry->d_inode->i_lock);
Steve Frenchfb8c4b12007-07-10 01:16:18 +00001436 i_size_write(direntry->d_inode, 0);
Dave Hansence71ec32006-09-30 23:29:06 -07001437 clear_nlink(direntry->d_inode);
Steve French3677db12007-02-26 16:46:11 +00001438 spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 }
1440
1441 cifsInode = CIFS_I(direntry->d_inode);
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001442 /* force revalidate to go get info when needed */
1443 cifsInode->time = 0;
Steve French42c24542009-01-13 22:03:55 +00001444
1445 cifsInode = CIFS_I(inode);
Pavel Shilovsky6de2ce42012-02-17 16:13:30 +03001446 /*
1447 * Force revalidate to get parent dir info when needed since cached
1448 * attributes are invalid now.
1449 */
1450 cifsInode->time = 0;
Steve French42c24542009-01-13 22:03:55 +00001451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
1453 current_fs_time(inode->i_sb);
1454
Jeff Layton7ffec372010-09-29 19:51:11 -04001455rmdir_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001457 free_xid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 return rc;
1459}
1460
Steve Frenchee2fd962008-09-23 18:23:33 +00001461static int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001462cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
1463 const char *fromPath, struct dentry *to_dentry,
1464 const char *toPath)
Steve Frenchee2fd962008-09-23 18:23:33 +00001465{
1466 struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001467 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001468 struct cifs_tcon *pTcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001469 __u16 srcfid;
1470 int oplock, rc;
1471
Jeff Layton7ffec372010-09-29 19:51:11 -04001472 tlink = cifs_sb_tlink(cifs_sb);
1473 if (IS_ERR(tlink))
1474 return PTR_ERR(tlink);
1475 pTcon = tlink_tcon(tlink);
1476
Steve Frenchee2fd962008-09-23 18:23:33 +00001477 /* try path-based rename first */
1478 rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
1479 cifs_sb->mnt_cifs_flags &
1480 CIFS_MOUNT_MAP_SPECIAL_CHR);
1481
1482 /*
1483 * don't bother with rename by filehandle unless file is busy and
1484 * source Note that cross directory moves do not work with
1485 * rename by filehandle to various Windows servers.
1486 */
1487 if (rc == 0 || rc != -ETXTBSY)
Jeff Layton7ffec372010-09-29 19:51:11 -04001488 goto do_rename_exit;
Steve Frenchee2fd962008-09-23 18:23:33 +00001489
Jeff Laytoned0e3ac2010-06-01 16:21:01 -04001490 /* open-file renames don't work across directories */
1491 if (to_dentry->d_parent != from_dentry->d_parent)
Jeff Layton7ffec372010-09-29 19:51:11 -04001492 goto do_rename_exit;
Jeff Laytoned0e3ac2010-06-01 16:21:01 -04001493
Steve Frenchee2fd962008-09-23 18:23:33 +00001494 /* open the file to be renamed -- we need DELETE perms */
1495 rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
1496 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
1497 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1498 CIFS_MOUNT_MAP_SPECIAL_CHR);
1499
1500 if (rc == 0) {
1501 rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
1502 (const char *) to_dentry->d_name.name,
1503 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
1504 CIFS_MOUNT_MAP_SPECIAL_CHR);
1505
1506 CIFSSMBClose(xid, pTcon, srcfid);
1507 }
Jeff Layton7ffec372010-09-29 19:51:11 -04001508do_rename_exit:
1509 cifs_put_tlink(tlink);
Steve Frenchee2fd962008-09-23 18:23:33 +00001510 return rc;
1511}
1512
Jeff Layton14121bd2008-10-20 14:45:22 -04001513int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
1514 struct inode *target_dir, struct dentry *target_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515{
Steve Frenchee2fd962008-09-23 18:23:33 +00001516 char *fromName = NULL;
1517 char *toName = NULL;
Jeff Layton639e7a92010-09-03 11:50:09 -04001518 struct cifs_sb_info *cifs_sb;
Jeff Layton7ffec372010-09-29 19:51:11 -04001519 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001520 struct cifs_tcon *tcon;
Steve Frenchee2fd962008-09-23 18:23:33 +00001521 FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
1522 FILE_UNIX_BASIC_INFO *info_buf_target;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001523 unsigned int xid;
1524 int rc, tmprc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
Jeff Layton639e7a92010-09-03 11:50:09 -04001526 cifs_sb = CIFS_SB(source_dir->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001527 tlink = cifs_sb_tlink(cifs_sb);
1528 if (IS_ERR(tlink))
1529 return PTR_ERR(tlink);
1530 tcon = tlink_tcon(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001532 xid = get_xid();
Steve Frenchee2fd962008-09-23 18:23:33 +00001533
1534 /*
Steve Frenchee2fd962008-09-23 18:23:33 +00001535 * we already have the rename sem so we do not need to
1536 * grab it again here to protect the path integrity
1537 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001538 fromName = build_path_from_dentry(source_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001539 if (fromName == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 rc = -ENOMEM;
1541 goto cifs_rename_exit;
1542 }
1543
Jeff Layton14121bd2008-10-20 14:45:22 -04001544 toName = build_path_from_dentry(target_dentry);
Steve Frenchee2fd962008-09-23 18:23:33 +00001545 if (toName == NULL) {
1546 rc = -ENOMEM;
1547 goto cifs_rename_exit;
1548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Jeff Layton14121bd2008-10-20 14:45:22 -04001550 rc = cifs_do_rename(xid, source_dentry, fromName,
1551 target_dentry, toName);
Steve Frenchee2fd962008-09-23 18:23:33 +00001552
Jeff Layton14121bd2008-10-20 14:45:22 -04001553 if (rc == -EEXIST && tcon->unix_ext) {
Steve Frenchee2fd962008-09-23 18:23:33 +00001554 /*
Jeff Layton14121bd2008-10-20 14:45:22 -04001555 * Are src and dst hardlinks of same inode? We can
1556 * only tell with unix extensions enabled
Steve Frenchee2fd962008-09-23 18:23:33 +00001557 */
Jeff Layton14121bd2008-10-20 14:45:22 -04001558 info_buf_source =
1559 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
1560 GFP_KERNEL);
1561 if (info_buf_source == NULL) {
1562 rc = -ENOMEM;
1563 goto cifs_rename_exit;
1564 }
1565
1566 info_buf_target = info_buf_source + 1;
Jeff Layton8d281ef2008-10-22 13:57:01 -04001567 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
Jeff Layton14121bd2008-10-20 14:45:22 -04001568 info_buf_source,
Jeff Layton639e7a92010-09-03 11:50:09 -04001569 cifs_sb->local_nls,
1570 cifs_sb->mnt_cifs_flags &
Jeff Layton14121bd2008-10-20 14:45:22 -04001571 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton8d281ef2008-10-22 13:57:01 -04001572 if (tmprc != 0)
Jeff Layton14121bd2008-10-20 14:45:22 -04001573 goto unlink_target;
1574
Jeff Layton639e7a92010-09-03 11:50:09 -04001575 tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
1576 info_buf_target,
1577 cifs_sb->local_nls,
1578 cifs_sb->mnt_cifs_flags &
Jeff Layton14121bd2008-10-20 14:45:22 -04001579 CIFS_MOUNT_MAP_SPECIAL_CHR);
1580
Jeff Layton8d281ef2008-10-22 13:57:01 -04001581 if (tmprc == 0 && (info_buf_source->UniqueId ==
Jeff Laytonae6884a2008-11-03 14:05:08 -05001582 info_buf_target->UniqueId)) {
Jeff Layton14121bd2008-10-20 14:45:22 -04001583 /* same file, POSIX says that this is a noop */
Jeff Laytonae6884a2008-11-03 14:05:08 -05001584 rc = 0;
Jeff Layton14121bd2008-10-20 14:45:22 -04001585 goto cifs_rename_exit;
Jeff Laytonae6884a2008-11-03 14:05:08 -05001586 }
Jeff Layton14121bd2008-10-20 14:45:22 -04001587 } /* else ... BB we could add the same check for Windows by
1588 checking the UniqueId via FILE_INTERNAL_INFO */
1589
Jeff Layton14121bd2008-10-20 14:45:22 -04001590unlink_target:
Jeff Laytonfc6f3942009-04-17 11:45:30 -04001591 /* Try unlinking the target dentry if it's not negative */
1592 if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
Jeff Layton8d281ef2008-10-22 13:57:01 -04001593 tmprc = cifs_unlink(target_dir, target_dentry);
Jeff Layton14121bd2008-10-20 14:45:22 -04001594 if (tmprc)
1595 goto cifs_rename_exit;
1596
Jeff Layton14121bd2008-10-20 14:45:22 -04001597 rc = cifs_do_rename(xid, source_dentry, fromName,
1598 target_dentry, toName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 }
1600
1601cifs_rename_exit:
Steve Frenchee2fd962008-09-23 18:23:33 +00001602 kfree(info_buf_source);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 kfree(fromName);
1604 kfree(toName);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001605 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001606 cifs_put_tlink(tlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 return rc;
1608}
1609
Jeff Laytondf2cf172010-02-12 07:44:16 -05001610static bool
1611cifs_inode_needs_reval(struct inode *inode)
1612{
1613 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301614 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Laytondf2cf172010-02-12 07:44:16 -05001615
1616 if (cifs_i->clientCanCacheRead)
1617 return false;
1618
1619 if (!lookupCacheEnabled)
1620 return true;
1621
1622 if (cifs_i->time == 0)
1623 return true;
1624
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301625 if (!time_in_range(jiffies, cifs_i->time,
1626 cifs_i->time + cifs_sb->actimeo))
Jeff Laytondf2cf172010-02-12 07:44:16 -05001627 return true;
1628
Jeff Laytondb192722010-05-17 14:51:49 -04001629 /* hardlinked files w/ noserverino get "special" treatment */
Suresh Jayaraman6d20e842010-12-01 14:42:28 +05301630 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
Jeff Laytondb192722010-05-17 14:51:49 -04001631 S_ISREG(inode->i_mode) && inode->i_nlink != 1)
1632 return true;
1633
Jeff Laytondf2cf172010-02-12 07:44:16 -05001634 return false;
1635}
1636
Suresh Jayaraman523fb8c2010-11-29 22:39:47 +05301637/*
1638 * Zap the cache. Called when invalid_mapping flag is set.
1639 */
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001640int
Jeff Laytondf2cf172010-02-12 07:44:16 -05001641cifs_invalidate_mapping(struct inode *inode)
1642{
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001643 int rc = 0;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001644 struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1645
1646 cifs_i->invalid_mapping = false;
1647
Jeff Laytondf2cf172010-02-12 07:44:16 -05001648 if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
Pavel Shilovsky257fb1f2011-03-16 01:55:32 +03001649 rc = invalidate_inode_pages2(inode->i_mapping);
1650 if (rc) {
1651 cERROR(1, "%s: could not invalidate inode %p", __func__,
1652 inode);
1653 cifs_i->invalid_mapping = true;
1654 }
Jeff Laytondf2cf172010-02-12 07:44:16 -05001655 }
Pavel Shilovsky257fb1f2011-03-16 01:55:32 +03001656
Suresh Jayaraman9451a9a2010-07-05 18:12:45 +05301657 cifs_fscache_reset_inode_cookie(inode);
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001658 return rc;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001659}
1660
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001661int cifs_revalidate_file_attr(struct file *filp)
Jeff Laytonabab0952010-02-12 07:44:18 -05001662{
1663 int rc = 0;
1664 struct inode *inode = filp->f_path.dentry->d_inode;
Jeff Laytonba00ba62010-09-20 16:01:31 -07001665 struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
Jeff Laytonabab0952010-02-12 07:44:18 -05001666
1667 if (!cifs_inode_needs_reval(inode))
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001668 return rc;
Jeff Laytonabab0952010-02-12 07:44:18 -05001669
Jeff Layton13cfb732010-09-29 19:51:11 -04001670 if (tlink_tcon(cfile->tlink)->unix_ext)
Jeff Laytonabab0952010-02-12 07:44:18 -05001671 rc = cifs_get_file_info_unix(filp);
1672 else
1673 rc = cifs_get_file_info(filp);
1674
Jeff Laytonabab0952010-02-12 07:44:18 -05001675 return rc;
1676}
1677
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001678int cifs_revalidate_dentry_attr(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679{
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001680 unsigned int xid;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001681 int rc = 0;
Jeff Laytondf2cf172010-02-12 07:44:16 -05001682 struct inode *inode = dentry->d_inode;
1683 struct super_block *sb = dentry->d_sb;
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001684 char *full_path = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
Jeff Laytondf2cf172010-02-12 07:44:16 -05001686 if (inode == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 return -ENOENT;
1688
Jeff Laytondf2cf172010-02-12 07:44:16 -05001689 if (!cifs_inode_needs_reval(inode))
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001690 return rc;
1691
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001692 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
1694 /* can not safely grab the rename sem here if rename calls revalidate
1695 since that would deadlock */
Jeff Laytondf2cf172010-02-12 07:44:16 -05001696 full_path = build_path_from_dentry(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05301698 rc = -ENOMEM;
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001699 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 }
Jeff Laytondf2cf172010-02-12 07:44:16 -05001701
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001702 cFYI(1, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time "
1703 "%ld jiffies %ld", full_path, inode, inode->i_count.counter,
Steve Frenchf19159d2010-04-21 04:12:10 +00001704 dentry, dentry->d_time, jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705
Jeff Layton0d424ad2010-09-20 16:01:35 -07001706 if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
Jeff Laytondf2cf172010-02-12 07:44:16 -05001707 rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
1708 else
1709 rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
1710 xid, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001712out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001714 free_xid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 return rc;
1716}
1717
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001718int cifs_revalidate_file(struct file *filp)
1719{
1720 int rc;
1721 struct inode *inode = filp->f_path.dentry->d_inode;
1722
1723 rc = cifs_revalidate_file_attr(filp);
1724 if (rc)
1725 return rc;
1726
1727 if (CIFS_I(inode)->invalid_mapping)
1728 rc = cifs_invalidate_mapping(inode);
1729 return rc;
1730}
1731
1732/* revalidate a dentry's inode attributes */
1733int cifs_revalidate_dentry(struct dentry *dentry)
1734{
1735 int rc;
1736 struct inode *inode = dentry->d_inode;
1737
1738 rc = cifs_revalidate_dentry_attr(dentry);
1739 if (rc)
1740 return rc;
1741
1742 if (CIFS_I(inode)->invalid_mapping)
1743 rc = cifs_invalidate_mapping(inode);
1744 return rc;
1745}
1746
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
Jeff Layton1c456012010-10-12 11:32:42 -04001748 struct kstat *stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749{
Jeff Layton3aa1c8c2010-10-07 14:46:28 -04001750 struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
Steve French96daf2b2011-05-27 04:34:02 +00001751 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001752 struct inode *inode = dentry->d_inode;
1753 int rc;
Jeff Layton3aa1c8c2010-10-07 14:46:28 -04001754
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001755 /*
1756 * We need to be sure that all dirty pages are written and the server
1757 * has actual ctime, mtime and file length.
1758 */
1759 if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
1760 inode->i_mapping->nrpages != 0) {
1761 rc = filemap_fdatawait(inode->i_mapping);
Steve French156ecb22011-05-20 17:00:01 +00001762 if (rc) {
1763 mapping_set_error(inode->i_mapping, rc);
1764 return rc;
1765 }
Steve French5fe14c82006-11-07 19:26:33 +00001766 }
Pavel Shilovsky6feb9892011-04-07 18:18:11 +04001767
1768 rc = cifs_revalidate_dentry_attr(dentry);
1769 if (rc)
1770 return rc;
1771
1772 generic_fillattr(inode, stat);
1773 stat->blksize = CIFS_MAX_MSGSIZE;
1774 stat->ino = CIFS_I(inode)->uniqueid;
1775
1776 /*
1777 * If on a multiuser mount without unix extensions, and the admin hasn't
1778 * overridden them, set the ownership to the fsuid/fsgid of the current
1779 * process.
1780 */
1781 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
1782 !tcon->unix_ext) {
1783 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
1784 stat->uid = current_fsuid();
1785 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
1786 stat->gid = current_fsgid();
1787 }
1788 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789}
1790
1791static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1792{
1793 pgoff_t index = from >> PAGE_CACHE_SHIFT;
1794 unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1795 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 int rc = 0;
1797
1798 page = grab_cache_page(mapping, index);
1799 if (!page)
1800 return -ENOMEM;
1801
Christoph Lametereebd2aa2008-02-04 22:28:29 -08001802 zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 unlock_page(page);
1804 page_cache_release(page);
1805 return rc;
1806}
1807
Christoph Hellwig1b947462010-07-18 17:51:21 -04001808static void cifs_setsize(struct inode *inode, loff_t offset)
Steve French3677db12007-02-26 16:46:11 +00001809{
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001810 loff_t oldsize;
Steve French3677db12007-02-26 16:46:11 +00001811
Steve Frenchba6a46a2007-02-26 20:06:29 +00001812 spin_lock(&inode->i_lock);
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001813 oldsize = inode->i_size;
Steve French3677db12007-02-26 16:46:11 +00001814 i_size_write(inode, offset);
Steve Frenchba6a46a2007-02-26 20:06:29 +00001815 spin_unlock(&inode->i_lock);
Christoph Hellwig1b947462010-07-18 17:51:21 -04001816
npiggin@suse.dec08d3b02009-08-21 02:35:06 +10001817 truncate_pagecache(inode, oldsize, offset);
Steve French3677db12007-02-26 16:46:11 +00001818}
1819
Jeff Layton8efdbde2008-07-23 21:28:12 +00001820static int
1821cifs_set_file_size(struct inode *inode, struct iattr *attrs,
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001822 unsigned int xid, char *full_path)
Jeff Layton8efdbde2008-07-23 21:28:12 +00001823{
1824 int rc;
1825 struct cifsFileInfo *open_file;
1826 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1827 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001828 struct tcon_link *tlink = NULL;
Steve French96daf2b2011-05-27 04:34:02 +00001829 struct cifs_tcon *pTcon = NULL;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001830 struct cifs_io_parms io_parms;
Jeff Layton8efdbde2008-07-23 21:28:12 +00001831
1832 /*
1833 * To avoid spurious oplock breaks from server, in the case of
1834 * inodes that we already have open, avoid doing path based
1835 * setting of file size if we can do it by handle.
1836 * This keeps our caching token (oplock) and avoids timeouts
1837 * when the local oplock break takes longer to flush
1838 * writebehind data than the SMB timeout for the SetPathInfo
1839 * request would allow
1840 */
Jeff Layton6508d902010-09-29 19:51:11 -04001841 open_file = find_writable_file(cifsInode, true);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001842 if (open_file) {
1843 __u16 nfid = open_file->netfid;
1844 __u32 npid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -04001845 pTcon = tlink_tcon(open_file->tlink);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001846 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
1847 npid, false);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001848 cifsFileInfo_put(open_file);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001849 cFYI(1, "SetFSize for attrs rc = %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001850 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1851 unsigned int bytes_written;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001852
1853 io_parms.netfid = nfid;
1854 io_parms.pid = npid;
1855 io_parms.tcon = pTcon;
1856 io_parms.offset = 0;
1857 io_parms.length = attrs->ia_size;
1858 rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
1859 NULL, NULL, 1);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001860 cFYI(1, "Wrt seteof rc %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001861 }
1862 } else
1863 rc = -EINVAL;
1864
1865 if (rc != 0) {
Jeff Layton7ffec372010-09-29 19:51:11 -04001866 if (pTcon == NULL) {
1867 tlink = cifs_sb_tlink(cifs_sb);
1868 if (IS_ERR(tlink))
1869 return PTR_ERR(tlink);
1870 pTcon = tlink_tcon(tlink);
1871 }
Jeff Laytonba00ba62010-09-20 16:01:31 -07001872
Jeff Layton8efdbde2008-07-23 21:28:12 +00001873 /* Set file size by pathname rather than by handle
1874 either because no valid, writeable file handle for
1875 it was found or because there was an error setting
1876 it by handle */
1877 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
1878 false, cifs_sb->local_nls,
1879 cifs_sb->mnt_cifs_flags &
1880 CIFS_MOUNT_MAP_SPECIAL_CHR);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001881 cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001882 if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1883 __u16 netfid;
1884 int oplock = 0;
1885
1886 rc = SMBLegacyOpen(xid, pTcon, full_path,
1887 FILE_OPEN, GENERIC_WRITE,
1888 CREATE_NOT_DIR, &netfid, &oplock, NULL,
1889 cifs_sb->local_nls,
1890 cifs_sb->mnt_cifs_flags &
1891 CIFS_MOUNT_MAP_SPECIAL_CHR);
1892 if (rc == 0) {
1893 unsigned int bytes_written;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001894
1895 io_parms.netfid = netfid;
1896 io_parms.pid = current->tgid;
1897 io_parms.tcon = pTcon;
1898 io_parms.offset = 0;
1899 io_parms.length = attrs->ia_size;
1900 rc = CIFSSMBWrite(xid, &io_parms,
1901 &bytes_written,
1902 NULL, NULL, 1);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001903 cFYI(1, "wrt seteof rc %d", rc);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001904 CIFSSMBClose(xid, pTcon, netfid);
1905 }
1906 }
Jeff Layton7ffec372010-09-29 19:51:11 -04001907 if (tlink)
1908 cifs_put_tlink(tlink);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001909 }
1910
1911 if (rc == 0) {
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001912 cifsInode->server_eof = attrs->ia_size;
Christoph Hellwig1b947462010-07-18 17:51:21 -04001913 cifs_setsize(inode, attrs->ia_size);
Jeff Layton8efdbde2008-07-23 21:28:12 +00001914 cifs_truncate_page(inode->i_mapping, inode->i_size);
1915 }
1916
1917 return rc;
1918}
1919
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001920static int
1921cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
1922{
1923 int rc;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001924 unsigned int xid;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001925 char *full_path = NULL;
1926 struct inode *inode = direntry->d_inode;
1927 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
1928 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001929 struct tcon_link *tlink;
Steve French96daf2b2011-05-27 04:34:02 +00001930 struct cifs_tcon *pTcon;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001931 struct cifs_unix_set_info_args *args = NULL;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04001932 struct cifsFileInfo *open_file;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001933
Joe Perchesb6b38f72010-04-21 03:50:45 +00001934 cFYI(1, "setattr_unix on file %s attrs->ia_valid=0x%x",
1935 direntry->d_name.name, attrs->ia_valid);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001936
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001937 xid = get_xid();
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001938
Christoph Hellwigdb78b872010-06-04 11:30:03 +02001939 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
1940 attrs->ia_valid |= ATTR_FORCE;
1941
1942 rc = inode_change_ok(inode, attrs);
1943 if (rc < 0)
1944 goto out;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001945
1946 full_path = build_path_from_dentry(direntry);
1947 if (full_path == NULL) {
1948 rc = -ENOMEM;
1949 goto out;
1950 }
1951
Jeff Layton0f4d6342009-03-26 13:35:37 -04001952 /*
1953 * Attempt to flush data before changing attributes. We need to do
1954 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
1955 * ownership or mode then we may also need to do this. Here, we take
1956 * the safe way out and just do the flush on all setattr requests. If
1957 * the flush returns error, store it to report later and continue.
1958 *
1959 * BB: This should be smarter. Why bother flushing pages that
1960 * will be truncated anyway? Also, should we error out here if
1961 * the flush returns error?
1962 */
1963 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04001964 mapping_set_error(inode->i_mapping, rc);
1965 rc = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04001966
1967 if (attrs->ia_valid & ATTR_SIZE) {
1968 rc = cifs_set_file_size(inode, attrs, xid, full_path);
1969 if (rc != 0)
1970 goto out;
1971 }
1972
1973 /* skip mode change if it's just for clearing setuid/setgid */
1974 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
1975 attrs->ia_valid &= ~ATTR_MODE;
1976
1977 args = kmalloc(sizeof(*args), GFP_KERNEL);
1978 if (args == NULL) {
1979 rc = -ENOMEM;
1980 goto out;
1981 }
1982
1983 /* set up the struct */
1984 if (attrs->ia_valid & ATTR_MODE)
1985 args->mode = attrs->ia_mode;
1986 else
1987 args->mode = NO_CHANGE_64;
1988
1989 if (attrs->ia_valid & ATTR_UID)
1990 args->uid = attrs->ia_uid;
1991 else
1992 args->uid = NO_CHANGE_64;
1993
1994 if (attrs->ia_valid & ATTR_GID)
1995 args->gid = attrs->ia_gid;
1996 else
1997 args->gid = NO_CHANGE_64;
1998
1999 if (attrs->ia_valid & ATTR_ATIME)
2000 args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
2001 else
2002 args->atime = NO_CHANGE_64;
2003
2004 if (attrs->ia_valid & ATTR_MTIME)
2005 args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
2006 else
2007 args->mtime = NO_CHANGE_64;
2008
2009 if (attrs->ia_valid & ATTR_CTIME)
2010 args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
2011 else
2012 args->ctime = NO_CHANGE_64;
2013
2014 args->device = 0;
Jeff Layton6508d902010-09-29 19:51:11 -04002015 open_file = find_writable_file(cifsInode, true);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002016 if (open_file) {
2017 u16 nfid = open_file->netfid;
2018 u32 npid = open_file->pid;
Jeff Layton13cfb732010-09-29 19:51:11 -04002019 pTcon = tlink_tcon(open_file->tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002020 rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04002021 cifsFileInfo_put(open_file);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002022 } else {
Jeff Layton7ffec372010-09-29 19:51:11 -04002023 tlink = cifs_sb_tlink(cifs_sb);
2024 if (IS_ERR(tlink)) {
2025 rc = PTR_ERR(tlink);
2026 goto out;
2027 }
2028 pTcon = tlink_tcon(tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002029 rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
Jeff Layton01ea95e2009-07-09 20:02:49 -04002030 cifs_sb->local_nls,
2031 cifs_sb->mnt_cifs_flags &
2032 CIFS_MOUNT_MAP_SPECIAL_CHR);
Jeff Layton7ffec372010-09-29 19:51:11 -04002033 cifs_put_tlink(tlink);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04002034 }
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002035
Christoph Hellwig10257742010-06-04 11:30:02 +02002036 if (rc)
2037 goto out;
Steve Frenchccd4bb12010-02-08 17:39:58 +00002038
Christoph Hellwig10257742010-06-04 11:30:02 +02002039 if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig1b947462010-07-18 17:51:21 -04002040 attrs->ia_size != i_size_read(inode))
2041 truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02002042
2043 setattr_copy(inode, attrs);
2044 mark_inode_dirty(inode);
2045
2046 /* force revalidate when any of these times are set since some
2047 of the fs types (eg ext3, fat) do not have fine enough
2048 time granularity to match protocol, and we do not have a
2049 a way (yet) to query the server fs's time granularity (and
2050 whether it rounds times down).
2051 */
2052 if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
2053 cifsInode->time = 0;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002054out:
2055 kfree(args);
2056 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002057 free_xid(xid);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002058 return rc;
2059}
2060
Jeff Layton0510eeb2008-08-02 07:26:12 -04002061static int
2062cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063{
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002064 unsigned int xid;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002065 uid_t uid = NO_CHANGE_32;
2066 gid_t gid = NO_CHANGE_32;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002067 struct inode *inode = direntry->d_inode;
2068 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002069 struct cifsInodeInfo *cifsInode = CIFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 char *full_path = NULL;
2071 int rc = -EACCES;
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002072 __u32 dosattr = 0;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04002073 __u64 mode = NO_CHANGE_64;
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002074
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002075 xid = get_xid();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
Joe Perchesb6b38f72010-04-21 03:50:45 +00002077 cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
2078 direntry->d_name.name, attrs->ia_valid);
Steve French6473a552005-11-29 20:20:10 -08002079
Christoph Hellwigdb78b872010-06-04 11:30:03 +02002080 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
2081 attrs->ia_valid |= ATTR_FORCE;
2082
2083 rc = inode_change_ok(inode, attrs);
2084 if (rc < 0) {
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002085 free_xid(xid);
Christoph Hellwigdb78b872010-06-04 11:30:03 +02002086 return rc;
Steve French6473a552005-11-29 20:20:10 -08002087 }
Steve French50c2f752007-07-13 00:33:32 +00002088
Steve French7f573562005-08-30 11:32:14 -07002089 full_path = build_path_from_dentry(direntry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 if (full_path == NULL) {
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302091 rc = -ENOMEM;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002092 free_xid(xid);
Suresh Jayaraman0f3bc092009-06-25 18:12:34 +05302093 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Jeff Layton0f4d6342009-03-26 13:35:37 -04002096 /*
2097 * Attempt to flush data before changing attributes. We need to do
2098 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
2099 * ownership or mode then we may also need to do this. Here, we take
2100 * the safe way out and just do the flush on all setattr requests. If
2101 * the flush returns error, store it to report later and continue.
2102 *
2103 * BB: This should be smarter. Why bother flushing pages that
2104 * will be truncated anyway? Also, should we error out here if
2105 * the flush returns error?
2106 */
2107 rc = filemap_write_and_wait(inode->i_mapping);
Jeff Laytoneb4b7562010-10-22 14:52:29 -04002108 mapping_set_error(inode->i_mapping, rc);
2109 rc = 0;
Jeff Laytoncea21802007-11-20 23:19:03 +00002110
Steve French50531442008-03-14 19:21:31 +00002111 if (attrs->ia_valid & ATTR_SIZE) {
Jeff Layton8efdbde2008-07-23 21:28:12 +00002112 rc = cifs_set_file_size(inode, attrs, xid, full_path);
2113 if (rc != 0)
Steve Frenche30dcf32005-09-20 20:49:16 -07002114 goto cifs_setattr_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 }
Jeff Layton4ca691a2008-05-22 09:33:34 -04002116
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002117 if (attrs->ia_valid & ATTR_UID)
2118 uid = attrs->ia_uid;
2119
2120 if (attrs->ia_valid & ATTR_GID)
2121 gid = attrs->ia_gid;
2122
2123#ifdef CONFIG_CIFS_ACL
2124 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2125 if (uid != NO_CHANGE_32 || gid != NO_CHANGE_32) {
2126 rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
2127 uid, gid);
2128 if (rc) {
2129 cFYI(1, "%s: Setting id failed with error: %d",
2130 __func__, rc);
2131 goto cifs_setattr_exit;
2132 }
2133 }
2134 } else
2135#endif /* CONFIG_CIFS_ACL */
Jeff Layton3fe5c1d2008-08-02 07:26:12 -04002136 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
Jeff Layton4ca691a2008-05-22 09:33:34 -04002137 attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138
Jeff Laytond32c4f22007-10-18 03:05:22 -07002139 /* skip mode change if it's just for clearing setuid/setgid */
2140 if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
2141 attrs->ia_valid &= ~ATTR_MODE;
2142
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 if (attrs->ia_valid & ATTR_MODE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 mode = attrs->ia_mode;
Steve Frenchcdbce9c2005-11-19 21:04:52 -08002145 rc = 0;
Jeff Layton79df1ba2010-12-06 12:52:08 -05002146#ifdef CONFIG_CIFS_ACL
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06002147 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05002148 rc = id_mode_to_cifs_acl(inode, full_path, mode,
2149 NO_CHANGE_32, NO_CHANGE_32);
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06002150 if (rc) {
2151 cFYI(1, "%s: Setting ACL failed with error: %d",
2152 __func__, rc);
2153 goto cifs_setattr_exit;
2154 }
2155 } else
Jeff Layton79df1ba2010-12-06 12:52:08 -05002156#endif /* CONFIG_CIFS_ACL */
Jeff Layton51328612008-05-22 09:33:34 -04002157 if (((mode & S_IWUGO) == 0) &&
2158 (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002159
2160 dosattr = cifsInode->cifsAttrs | ATTR_READONLY;
2161
Jeff Layton51328612008-05-22 09:33:34 -04002162 /* fix up mode if we're not using dynperm */
2163 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
2164 attrs->ia_mode = inode->i_mode & ~S_IWUGO;
2165 } else if ((mode & S_IWUGO) &&
2166 (cifsInode->cifsAttrs & ATTR_READONLY)) {
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002167
2168 dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
2169 /* Attributes of 0 are ignored */
2170 if (dosattr == 0)
2171 dosattr |= ATTR_NORMAL;
Jeff Layton51328612008-05-22 09:33:34 -04002172
2173 /* reset local inode permissions to normal */
2174 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
2175 attrs->ia_mode &= ~(S_IALLUGO);
2176 if (S_ISDIR(inode->i_mode))
2177 attrs->ia_mode |=
2178 cifs_sb->mnt_dir_mode;
2179 else
2180 attrs->ia_mode |=
2181 cifs_sb->mnt_file_mode;
2182 }
2183 } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
2184 /* ignore mode change - ATTR_READONLY hasn't changed */
2185 attrs->ia_valid &= ~ATTR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 }
2188
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002189 if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
2190 ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
2191 rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
2192 /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Steve Frenche30dcf32005-09-20 20:49:16 -07002194 /* Even if error on time set, no sense failing the call if
2195 the server would set the time to a reasonable value anyway,
2196 and this check ensures that we are not being called from
2197 sys_utimes in which case we ought to fail the call back to
2198 the user when the server rejects the call */
Steve Frenchfb8c4b12007-07-10 01:16:18 +00002199 if ((rc) && (attrs->ia_valid &
Jeff Laytonfeb3e202008-08-02 07:26:12 -04002200 (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
Steve Frenche30dcf32005-09-20 20:49:16 -07002201 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 }
2203
2204 /* do not need local check to inode_check_ok since the server does
2205 that */
Christoph Hellwig10257742010-06-04 11:30:02 +02002206 if (rc)
2207 goto cifs_setattr_exit;
2208
2209 if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig1b947462010-07-18 17:51:21 -04002210 attrs->ia_size != i_size_read(inode))
2211 truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02002212
2213 setattr_copy(inode, attrs);
2214 mark_inode_dirty(inode);
Christoph Hellwig10257742010-06-04 11:30:02 +02002215
Steve Frenche30dcf32005-09-20 20:49:16 -07002216cifs_setattr_exit:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 kfree(full_path);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002218 free_xid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return rc;
2220}
2221
Jeff Layton0510eeb2008-08-02 07:26:12 -04002222int
2223cifs_setattr(struct dentry *direntry, struct iattr *attrs)
2224{
2225 struct inode *inode = direntry->d_inode;
2226 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Steve French96daf2b2011-05-27 04:34:02 +00002227 struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
Jeff Layton0510eeb2008-08-02 07:26:12 -04002228
2229 if (pTcon->unix_ext)
2230 return cifs_setattr_unix(direntry, attrs);
2231
2232 return cifs_setattr_nounix(direntry, attrs);
2233
2234 /* BB: add cifs_setattr_legacy for really old servers */
2235}
2236
Steve French99ee4db2007-02-27 05:35:17 +00002237#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238void cifs_delete_inode(struct inode *inode)
2239{
Joe Perchesb6b38f72010-04-21 03:50:45 +00002240 cFYI(1, "In cifs_delete_inode, inode = 0x%p", inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 /* may have to add back in if and when safe distributed caching of
2242 directories added e.g. via FindNotify */
2243}
Steve French99ee4db2007-02-27 05:35:17 +00002244#endif