inode.c 60.4 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3
/*
 *   fs/cifs/inode.c
 *
4
 *   Copyright (C) International Business Machines  Corp., 2002,2010
Linus Torvalds's avatar
Linus Torvalds committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <linux/fs.h>
#include <linux/stat.h>
23
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
24 25 26 27 28 29 30 31
#include <linux/pagemap.h>
#include <asm/div64.h>
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
32
#include "fscache.h"
Linus Torvalds's avatar
Linus Torvalds committed
33

34

35
static void cifs_set_ops(struct inode *inode)
36 37 38 39 40 41 42 43 44 45 46
{
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);

	switch (inode->i_mode & S_IFMT) {
	case S_IFREG:
		inode->i_op = &cifs_file_inode_ops;
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
				inode->i_fop = &cifs_file_direct_nobrl_ops;
			else
				inode->i_fop = &cifs_file_direct_ops;
47 48 49 50 51
		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) {
			if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
				inode->i_fop = &cifs_file_strict_nobrl_ops;
			else
				inode->i_fop = &cifs_file_strict_ops;
52 53 54 55 56 57 58
		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
			inode->i_fop = &cifs_file_nobrl_ops;
		else { /* not direct, send byte range locks */
			inode->i_fop = &cifs_file_ops;
		}

		/* check if server can support readpages */
59
		if (cifs_sb_master_tcon(cifs_sb)->ses->server->maxBuf <
60 61 62 63 64 65
				PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
			inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
		else
			inode->i_data.a_ops = &cifs_addr_ops;
		break;
	case S_IFDIR:
Steve French's avatar
Steve French committed
66
#ifdef CONFIG_CIFS_DFS_UPCALL
67
		if (IS_AUTOMOUNT(inode)) {
68 69
			inode->i_op = &cifs_dfs_referral_inode_operations;
		} else {
Steve French's avatar
Steve French committed
70 71 72
#else /* NO DFS support, treat as a directory */
		{
#endif
73 74 75
			inode->i_op = &cifs_dir_inode_ops;
			inode->i_fop = &cifs_dir_ops;
		}
76 77 78 79 80 81 82 83 84 85
		break;
	case S_IFLNK:
		inode->i_op = &cifs_symlink_inode_ops;
		break;
	default:
		init_special_inode(inode, inode->i_mode, inode->i_rdev);
		break;
	}
}

86 87 88 89 90 91 92 93
/* check inode attributes against fattr. If they don't match, tag the
 * inode for cache invalidation
 */
static void
cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
{
	struct cifsInodeInfo *cifs_i = CIFS_I(inode);

94 95
	cifs_dbg(FYI, "%s: revalidating inode %llu\n",
		 __func__, cifs_i->uniqueid);
96 97

	if (inode->i_state & I_NEW) {
98 99
		cifs_dbg(FYI, "%s: inode %llu is new\n",
			 __func__, cifs_i->uniqueid);
100 101 102 103 104
		return;
	}

	/* don't bother with revalidation if we have an oplock */
	if (cifs_i->clientCanCacheRead) {
105 106
		cifs_dbg(FYI, "%s: inode %llu is oplocked\n",
			 __func__, cifs_i->uniqueid);
107 108 109 110 111 112
		return;
	}

	 /* revalidate if mtime or size have changed */
	if (timespec_equal(&inode->i_mtime, &fattr->cf_mtime) &&
	    cifs_i->server_eof == fattr->cf_eof) {
113 114
		cifs_dbg(FYI, "%s: inode %llu is unchanged\n",
			 __func__, cifs_i->uniqueid);
115 116 117
		return;
	}

118 119
	cifs_dbg(FYI, "%s: invalidating inode %llu mapping\n",
		 __func__, cifs_i->uniqueid);
120 121 122
	cifs_i->invalid_mapping = true;
}

123 124 125
/* populate an inode with info from a cifs_fattr struct */
void
cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
126
{
127
	struct cifsInodeInfo *cifs_i = CIFS_I(inode);
128
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
129

130 131
	cifs_revalidate_cache(inode, fattr);

132
	spin_lock(&inode->i_lock);
133 134 135 136
	inode->i_atime = fattr->cf_atime;
	inode->i_mtime = fattr->cf_mtime;
	inode->i_ctime = fattr->cf_ctime;
	inode->i_rdev = fattr->cf_rdev;
Miklos Szeredi's avatar
Miklos Szeredi committed
137
	set_nlink(inode, fattr->cf_nlink);
138 139 140
	inode->i_uid = fattr->cf_uid;
	inode->i_gid = fattr->cf_gid;

141 142 143 144 145
	/* if dynperm is set, don't clobber existing mode */
	if (inode->i_state & I_NEW ||
	    !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
		inode->i_mode = fattr->cf_mode;

146
	cifs_i->cifsAttrs = fattr->cf_cifsattrs;
147

148 149 150 151 152 153
	if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
		cifs_i->time = 0;
	else
		cifs_i->time = jiffies;

	cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
154

155
	cifs_i->server_eof = fattr->cf_eof;
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	/*
	 * Can't safely change the file size here if the client is writing to
	 * it due to potential races.
	 */
	if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
		i_size_write(inode, fattr->cf_eof);

		/*
		 * i_blocks is not related to (i_size / i_blksize),
		 * but instead 512 byte (2**9) size is required for
		 * calculating num blocks.
		 */
		inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9;
	}
	spin_unlock(&inode->i_lock);

172 173
	if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL)
		inode->i_flags |= S_AUTOMOUNT;
174 175
	if (inode->i_state & I_NEW)
		cifs_set_ops(inode);
176 177
}

178 179 180 181 182 183 184 185 186 187 188
void
cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr)
{
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);

	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
		return;

	fattr->cf_uniqueid = iunique(sb, ROOT_I);
}

189 190 191 192 193 194 195 196 197 198 199 200 201 202
/* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */
void
cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
			 struct cifs_sb_info *cifs_sb)
{
	memset(fattr, 0, sizeof(*fattr));
	fattr->cf_uniqueid = le64_to_cpu(info->UniqueId);
	fattr->cf_bytes = le64_to_cpu(info->NumOfBytes);
	fattr->cf_eof = le64_to_cpu(info->EndOfFile);

	fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime);
	fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange);
	fattr->cf_mode = le64_to_cpu(info->Permissions);
203 204 205 206 207

	/*
	 * Since we set the inode type below we need to mask off
	 * to avoid strange results if bits set above.
	 */
208
	fattr->cf_mode &= ~S_IFMT;
209 210
	switch (le32_to_cpu(info->Type)) {
	case UNIX_FILE:
211 212
		fattr->cf_mode |= S_IFREG;
		fattr->cf_dtype = DT_REG;
213 214
		break;
	case UNIX_SYMLINK:
215 216
		fattr->cf_mode |= S_IFLNK;
		fattr->cf_dtype = DT_LNK;
217 218
		break;
	case UNIX_DIR:
219 220
		fattr->cf_mode |= S_IFDIR;
		fattr->cf_dtype = DT_DIR;
221 222
		break;
	case UNIX_CHARDEV:
223 224 225 226
		fattr->cf_mode |= S_IFCHR;
		fattr->cf_dtype = DT_CHR;
		fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
				       le64_to_cpu(info->DevMinor) & MINORMASK);
227 228
		break;
	case UNIX_BLOCKDEV:
229 230 231 232
		fattr->cf_mode |= S_IFBLK;
		fattr->cf_dtype = DT_BLK;
		fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor),
				       le64_to_cpu(info->DevMinor) & MINORMASK);
233 234
		break;
	case UNIX_FIFO:
235 236
		fattr->cf_mode |= S_IFIFO;
		fattr->cf_dtype = DT_FIFO;
237 238
		break;
	case UNIX_SOCKET:
239 240
		fattr->cf_mode |= S_IFSOCK;
		fattr->cf_dtype = DT_SOCK;
241 242 243
		break;
	default:
		/* safest to call it a file if we do not know */
244 245
		fattr->cf_mode |= S_IFREG;
		fattr->cf_dtype = DT_REG;
246
		cifs_dbg(FYI, "unknown type %d\n", le32_to_cpu(info->Type));
247 248 249
		break;
	}

250 251 252
	fattr->cf_uid = cifs_sb->mnt_uid;
	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) {
		u64 id = le64_to_cpu(info->Uid);
253 254 255 256 257
		if (id < ((uid_t)-1)) {
			kuid_t uid = make_kuid(&init_user_ns, id);
			if (uid_valid(uid))
				fattr->cf_uid = uid;
		}
258 259 260 261 262
	}
	
	fattr->cf_gid = cifs_sb->mnt_gid;
	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) {
		u64 id = le64_to_cpu(info->Gid);
263 264 265 266 267
		if (id < ((gid_t)-1)) {
			kgid_t gid = make_kgid(&init_user_ns, id);
			if (gid_valid(gid))
				fattr->cf_gid = gid;
		}
268
	}
269

270
	fattr->cf_nlink = le64_to_cpu(info->Nlinks);
271 272
}

273
/*
274 275 276 277 278
 * Fill a cifs_fattr struct with fake inode info.
 *
 * Needed to setup cifs_fattr data for the directory which is the
 * junction to the new submount (ie to setup the fake directory
 * which represents a DFS referral).
279
 */
Steve French's avatar
Steve French committed
280
static void
281
cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
282
{
283
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
284

285
	cifs_dbg(FYI, "creating fake fattr for DFS referral\n");
286 287 288 289 290 291 292 293 294 295

	memset(fattr, 0, sizeof(*fattr));
	fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
	fattr->cf_uid = cifs_sb->mnt_uid;
	fattr->cf_gid = cifs_sb->mnt_gid;
	fattr->cf_atime = CURRENT_TIME;
	fattr->cf_ctime = CURRENT_TIME;
	fattr->cf_mtime = CURRENT_TIME;
	fattr->cf_nlink = 2;
	fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
296 297
}

298 299
static int
cifs_get_file_info_unix(struct file *filp)
Jeff Layton's avatar
Jeff Layton committed
300 301
{
	int rc;
302
	unsigned int xid;
Jeff Layton's avatar
Jeff Layton committed
303 304
	FILE_UNIX_BASIC_INFO find_data;
	struct cifs_fattr fattr;
Al Viro's avatar
Al Viro committed
305
	struct inode *inode = file_inode(filp);
Jeff Layton's avatar
Jeff Layton committed
306
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
307
	struct cifsFileInfo *cfile = filp->private_data;
308
	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
Jeff Layton's avatar
Jeff Layton committed
309

310
	xid = get_xid();
311
	rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
Jeff Layton's avatar
Jeff Layton committed
312 313 314 315 316 317 318 319
	if (!rc) {
		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
	} else if (rc == -EREMOTE) {
		cifs_create_dfs_fattr(&fattr, inode->i_sb);
		rc = 0;
	}

	cifs_fattr_to_inode(inode, &fattr);
320
	free_xid(xid);
Jeff Layton's avatar
Jeff Layton committed
321 322 323
	return rc;
}

Linus Torvalds's avatar
Linus Torvalds committed
324
int cifs_get_inode_info_unix(struct inode **pinode,
325
			     const unsigned char *full_path,
326
			     struct super_block *sb, unsigned int xid)
Linus Torvalds's avatar
Linus Torvalds committed
327
{
328
	int rc;
329
	FILE_UNIX_BASIC_INFO find_data;
330
	struct cifs_fattr fattr;
331
	struct cifs_tcon *tcon;
332
	struct tcon_link *tlink;
Linus Torvalds's avatar
Linus Torvalds committed
333 334
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);

335
	cifs_dbg(FYI, "Getting info on %s\n", full_path);
336

337 338 339 340 341
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	tcon = tlink_tcon(tlink);

Linus Torvalds's avatar
Linus Torvalds committed
342
	/* could have done a find first instead but this returns more info */
343
	rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data,
344 345
				  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
					CIFS_MOUNT_MAP_SPECIAL_CHR);
346
	cifs_put_tlink(tlink);
347

348 349 350 351 352 353 354 355
	if (!rc) {
		cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
	} else if (rc == -EREMOTE) {
		cifs_create_dfs_fattr(&fattr, sb);
		rc = 0;
	} else {
		return rc;
	}
Linus Torvalds's avatar
Linus Torvalds committed
356

357 358 359 360
	/* check for Minshall+French symlinks */
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
		int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
		if (tmprc)
361
			cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc);
362 363
	}

364
	if (*pinode == NULL) {
365
		/* get new inode */
366
		cifs_fill_uniqueid(sb, &fattr);
367 368
		*pinode = cifs_iget(sb, &fattr);
		if (!*pinode)
369
			rc = -ENOMEM;
370 371 372
	} else {
		/* we already have inode, update it */
		cifs_fattr_to_inode(*pinode, &fattr);
373
	}
Linus Torvalds's avatar
Linus Torvalds committed
374 375 376 377

	return rc;
}

378 379
static int
cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path,
380
	      struct cifs_sb_info *cifs_sb, unsigned int xid)
381 382
{
	int rc;
383
	int oplock = 0;
384
	__u16 netfid;
385
	struct tcon_link *tlink;
386
	struct cifs_tcon *tcon;
387
	struct cifs_io_parms io_parms;
388
	char buf[24];
389
	unsigned int bytes_read;
Steve French's avatar
Steve French committed
390
	char *pbuf;
391 392 393

	pbuf = buf;

394 395 396 397 398
	fattr->cf_mode &= ~S_IFMT;

	if (fattr->cf_eof == 0) {
		fattr->cf_mode |= S_IFIFO;
		fattr->cf_dtype = DT_FIFO;
399
		return 0;
400 401 402
	} else if (fattr->cf_eof < 8) {
		fattr->cf_mode |= S_IFREG;
		fattr->cf_dtype = DT_REG;
403 404
		return -EINVAL;	 /* EOPNOTSUPP? */
	}
405

406 407 408 409 410 411
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	tcon = tlink_tcon(tlink);

	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, GENERIC_READ,
412 413 414 415
			 CREATE_NOT_DIR, &netfid, &oplock, NULL,
			 cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags &
				CIFS_MOUNT_MAP_SPECIAL_CHR);
Steve French's avatar
Steve French committed
416
	if (rc == 0) {
417
		int buf_type = CIFS_NO_BUFFER;
418
			/* Read header */
419 420 421 422 423 424 425
		io_parms.netfid = netfid;
		io_parms.pid = current->tgid;
		io_parms.tcon = tcon;
		io_parms.offset = 0;
		io_parms.length = 24;
		rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf,
				 &buf_type);
426 427
		if ((rc == 0) && (bytes_read >= 8)) {
			if (memcmp("IntxBLK", pbuf, 8) == 0) {
428
				cifs_dbg(FYI, "Block device\n");
429 430
				fattr->cf_mode |= S_IFBLK;
				fattr->cf_dtype = DT_BLK;
431
				if (bytes_read == 24) {
432 433 434 435 436
					/* we have enough to decode dev num */
					__u64 mjr; /* major */
					__u64 mnr; /* minor */
					mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
					mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
437
					fattr->cf_rdev = MKDEV(mjr, mnr);
438
				}
439
			} else if (memcmp("IntxCHR", pbuf, 8) == 0) {
440
				cifs_dbg(FYI, "Char device\n");
441 442
				fattr->cf_mode |= S_IFCHR;
				fattr->cf_dtype = DT_CHR;
443
				if (bytes_read == 24) {
444 445 446 447 448
					/* we have enough to decode dev num */
					__u64 mjr; /* major */
					__u64 mnr; /* minor */
					mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
					mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
449
					fattr->cf_rdev = MKDEV(mjr, mnr);
Steve French's avatar
Steve French committed
450
				}
451
			} else if (memcmp("IntxLNK", pbuf, 7) == 0) {
452
				cifs_dbg(FYI, "Symlink\n");
453 454
				fattr->cf_mode |= S_IFLNK;
				fattr->cf_dtype = DT_LNK;
455
			} else {
456 457
				fattr->cf_mode |= S_IFREG; /* file? */
				fattr->cf_dtype = DT_REG;
Steve French's avatar
Steve French committed
458
				rc = -EOPNOTSUPP;
459
			}
460
		} else {
461 462
			fattr->cf_mode |= S_IFREG; /* then it is a file */
			fattr->cf_dtype = DT_REG;
Steve French's avatar
Steve French committed
463 464
			rc = -EOPNOTSUPP; /* or some unknown SFU type */
		}
465
		CIFSSMBClose(xid, tcon, netfid);
466
	}
467
	cifs_put_tlink(tlink);
468 469 470
	return rc;
}

471 472
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID)  /* SETFILEBITS valid bits */

473 474 475 476 477 478
/*
 * Fetch mode bits as provided by SFU.
 *
 * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ?
 */
static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
479
			 struct cifs_sb_info *cifs_sb, unsigned int xid)
480
{
481
#ifdef CONFIG_CIFS_XATTR
482 483 484
	ssize_t rc;
	char ea_value[4];
	__u32 mode;
485
	struct tcon_link *tlink;
486
	struct cifs_tcon *tcon;
487 488 489 490 491

	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	tcon = tlink_tcon(tlink);
492

493 494 495 496 497 498 499 500 501
	if (tcon->ses->server->ops->query_all_EAs == NULL) {
		cifs_put_tlink(tlink);
		return -EOPNOTSUPP;
	}

	rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path,
			"SETFILEBITS", ea_value, 4 /* size of buf */,
			cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
502
	cifs_put_tlink(tlink);
503
	if (rc < 0)
504 505 506
		return (int)rc;
	else if (rc > 3) {
		mode = le32_to_cpu(*((__le32 *)ea_value));
507
		fattr->cf_mode &= ~SFBITS_MASK;
508 509
		cifs_dbg(FYI, "special bits 0%o org mode 0%o\n",
			 mode, fattr->cf_mode);
510
		fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode;
511
		cifs_dbg(FYI, "special mode bits 0%o\n", mode);
512
	}
513 514

	return 0;
515 516 517
#else
	return -EOPNOTSUPP;
#endif
518 519
}

520
/* Fill a cifs_fattr struct with info from FILE_ALL_INFO */
Steve French's avatar
Steve French committed
521
static void
522 523
cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
		       struct cifs_sb_info *cifs_sb, bool adjust_tz)
524
{
525
	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
526

527 528 529 530 531 532 533 534 535 536 537 538 539 540
	memset(fattr, 0, sizeof(*fattr));
	fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
	if (info->DeletePending)
		fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;

	if (info->LastAccessTime)
		fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime);
	else
		fattr->cf_atime = CURRENT_TIME;

	fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
	fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);

	if (adjust_tz) {
541 542
		fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
		fattr->cf_mtime.tv_sec += tcon->ses->server->timeAdj;
543 544 545 546
	}

	fattr->cf_eof = le64_to_cpu(info->EndOfFile);
	fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
547
	fattr->cf_createtime = le64_to_cpu(info->CreationTime);
548 549 550 551

	if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
		fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
		fattr->cf_dtype = DT_DIR;
552 553 554 555 556
		/*
		 * Server can return wrong NumberOfLinks value for directories
		 * when Unix extensions are disabled - fake it.
		 */
		fattr->cf_nlink = 2;
557 558 559 560
	} else {
		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
		fattr->cf_dtype = DT_REG;

561 562 563
		/* clear write bits if ATTR_READONLY is set */
		if (fattr->cf_cifsattrs & ATTR_READONLY)
			fattr->cf_mode &= ~(S_IWUGO);
564

565
		fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
566 567 568 569 570
		if (fattr->cf_nlink < 1) {
			cifs_dbg(1, "replacing bogus file nlink value %u\n",
				fattr->cf_nlink);
			fattr->cf_nlink = 1;
		}
571
	}
572 573 574

	fattr->cf_uid = cifs_sb->mnt_uid;
	fattr->cf_gid = cifs_sb->mnt_gid;
575 576
}

577 578
static int
cifs_get_file_info(struct file *filp)
Jeff Layton's avatar
Jeff Layton committed
579 580
{
	int rc;
581
	unsigned int xid;
Jeff Layton's avatar
Jeff Layton committed
582 583
	FILE_ALL_INFO find_data;
	struct cifs_fattr fattr;
Al Viro's avatar
Al Viro committed
584
	struct inode *inode = file_inode(filp);
Jeff Layton's avatar
Jeff Layton committed
585
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
586
	struct cifsFileInfo *cfile = filp->private_data;
587
	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
588 589 590 591
	struct TCP_Server_Info *server = tcon->ses->server;

	if (!server->ops->query_file_info)
		return -ENOSYS;
Jeff Layton's avatar
Jeff Layton committed
592

593
	xid = get_xid();
594
	rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
595 596 597 598 599 600 601 602 603 604
	switch (rc) {
	case 0:
		cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
		break;
	case -EREMOTE:
		cifs_create_dfs_fattr(&fattr, inode->i_sb);
		rc = 0;
		break;
	case -EOPNOTSUPP:
	case -EINVAL:
Jeff Layton's avatar
Jeff Layton committed
605 606
		/*
		 * FIXME: legacy server -- fall back to path-based call?
Steve French's avatar
Steve French committed
607 608 609
		 * for now, just skip revalidating and mark inode for
		 * immediate reval.
		 */
Jeff Layton's avatar
Jeff Layton committed
610 611
		rc = 0;
		CIFS_I(inode)->time = 0;
612
	default:
Jeff Layton's avatar
Jeff Layton committed
613
		goto cgfi_exit;
614
	}
Jeff Layton's avatar
Jeff Layton committed
615 616 617 618 619 620 621 622 623

	/*
	 * don't bother with SFU junk here -- just mark inode as needing
	 * revalidation.
	 */
	fattr.cf_uniqueid = CIFS_I(inode)->uniqueid;
	fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
	cifs_fattr_to_inode(inode, &fattr);
cgfi_exit:
624
	free_xid(xid);
Jeff Layton's avatar
Jeff Layton committed
625 626 627
	return rc;
}

628 629 630 631
int
cifs_get_inode_info(struct inode **inode, const char *full_path,
		    FILE_ALL_INFO *data, struct super_block *sb, int xid,
		    const __u16 *fid)
Linus Torvalds's avatar
Linus Torvalds committed
632
{
633 634 635
	bool validinum = false;
	__u16 srchflgs;
	int rc = 0, tmprc = ENOSYS;
636 637
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
638
	struct tcon_link *tlink;
Linus Torvalds's avatar
Linus Torvalds committed
639 640
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	char *buf = NULL;
641
	bool adjust_tz = false;
642
	struct cifs_fattr fattr;
643
	struct cifs_search_info *srchinf = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
644

645 646 647
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
648 649
	tcon = tlink_tcon(tlink);
	server = tcon->ses->server;
650

651
	cifs_dbg(FYI, "Getting info on %s\n", full_path);
Linus Torvalds's avatar
Linus Torvalds committed
652

653 654
	if ((data == NULL) && (*inode != NULL)) {
		if (CIFS_I(*inode)->clientCanCacheRead) {
655
			cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
656
			goto cgii_exit;
Linus Torvalds's avatar
Linus Torvalds committed
657 658 659
		}
	}

660 661 662 663 664 665
	/* if inode info is not passed, get it from server */
	if (data == NULL) {
		if (!server->ops->query_path_info) {
			rc = -ENOSYS;
			goto cgii_exit;
		}
Linus Torvalds's avatar
Linus Torvalds committed
666
		buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
667 668 669 670
		if (buf == NULL) {
			rc = -ENOMEM;
			goto cgii_exit;
		}
671 672 673
		data = (FILE_ALL_INFO *)buf;
		rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path,
						  data, &adjust_tz);
Linus Torvalds's avatar
Linus Torvalds committed
674
	}
675 676

	if (!rc) {
677 678
		cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *)data, cifs_sb,
				       adjust_tz);
679 680
	} else if (rc == -EREMOTE) {
		cifs_create_dfs_fattr(&fattr, sb);
681
		rc = 0;
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
	} else if (rc == -EACCES && backup_cred(cifs_sb)) {
			srchinf = kzalloc(sizeof(struct cifs_search_info),
						GFP_KERNEL);
			if (srchinf == NULL) {
				rc = -ENOMEM;
				goto cgii_exit;
			}

			srchinf->endOfSearch = false;
			srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;

			srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
					CIFS_SEARCH_CLOSE_AT_END |
					CIFS_SEARCH_BACKUP_SEARCH;

			rc = CIFSFindFirst(xid, tcon, full_path,
				cifs_sb, NULL, srchflgs, srchinf, false);
			if (!rc) {
				data =
				(FILE_ALL_INFO *)srchinf->srch_entries_start;

				cifs_dir_info_to_fattr(&fattr,
				(FILE_DIRECTORY_INFO *)data, cifs_sb);
				fattr.cf_uniqueid = le64_to_cpu(
				((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
				validinum = true;

				cifs_buf_release(srchinf->ntwrk_buf_start);
			}
			kfree(srchinf);
	} else
713
		goto cgii_exit;
Linus Torvalds's avatar
Linus Torvalds committed
714

715 716 717 718 719 720 721
	/*
	 * If an inode wasn't passed in, then get the inode number
	 *
	 * Is an i_ino of zero legal? Can we use that to check if the server
	 * supports returning inode numbers?  Are there other sanity checks we
	 * can use to ensure that the server is really filling in that field?
	 */
722
	if (*inode == NULL) {
723
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
724 725 726 727 728 729
			if (validinum == false) {
				if (server->ops->get_srv_inum)
					tmprc = server->ops->get_srv_inum(xid,
						tcon, cifs_sb, full_path,
						&fattr.cf_uniqueid, data);
				if (tmprc) {
730 731
					cifs_dbg(FYI, "GetSrvInodeNum rc %d\n",
						 tmprc);
732 733 734
					fattr.cf_uniqueid = iunique(sb, ROOT_I);
					cifs_autodisable_serverino(cifs_sb);
				}
735
			}
736
		} else
737
			fattr.cf_uniqueid = iunique(sb, ROOT_I);
738
	} else
739
		fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
740

741 742 743 744 745
	/* query for SFU type info if supported and needed */
	if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
	    cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
		tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid);
		if (tmprc)
746
			cifs_dbg(FYI, "cifs_sfu_type failed: %d\n", tmprc);
747
	}
Linus Torvalds's avatar
Linus Torvalds committed
748

Jeff Layton's avatar
Jeff Layton committed
749
#ifdef CONFIG_CIFS_ACL
750 751
	/* fill in 0777 bits from ACL */
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
752
		rc = cifs_acl_to_fattr(cifs_sb, &fattr, *inode, full_path, fid);
753
		if (rc) {
754 755
			cifs_dbg(FYI, "%s: Getting ACL failed with error: %d\n",
				 __func__, rc);
756 757
			goto cgii_exit;
		}
758
	}
Jeff Layton's avatar
Jeff Layton committed
759
#endif /* CONFIG_CIFS_ACL */
760

761 762 763
	/* fill in remaining high mode bits e.g. SUID, VTX */
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
		cifs_sfu_mode(&fattr, full_path, cifs_sb, xid);
764

765 766 767 768
	/* check for Minshall+French symlinks */
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
		tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
		if (tmprc)
769
			cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc);
770 771
	}

772 773 774
	if (!*inode) {
		*inode = cifs_iget(sb, &fattr);
		if (!*inode)
775 776
			rc = -ENOMEM;
	} else {
777
		cifs_fattr_to_inode(*inode, &fattr);
778
	}
779

780
cgii_exit:
Linus Torvalds's avatar
Linus Torvalds committed
781
	kfree(buf);
782
	cifs_put_tlink(tlink);
Linus Torvalds's avatar
Linus Torvalds committed
783 784 785
	return rc;
}

786 787 788 789
static const struct inode_operations cifs_ipc_inode_ops = {
	.lookup = cifs_lookup,
};

790 791 792 793 794
static int
cifs_find_inode(struct inode *inode, void *opaque)
{
	struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;

795
	/* don't match inode with different uniqueid */
796 797 798
	if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid)
		return 0;

799 800 801 802
	/* use createtime like an i_generation field */
	if (CIFS_I(inode)->createtime != fattr->cf_createtime)
		return 0;

803 804 805 806
	/* don't match inode of different type */
	if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
		return 0;

807
	/* if it's not a directory or has no dentries, then flag it */
808
	if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
809 810
		fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;

811 812 813 814 815 816 817 818 819
	return 1;
}

static int
cifs_init_inode(struct inode *inode, void *opaque)
{
	struct cifs_fattr *fattr = (struct cifs_fattr *) opaque;

	CIFS_I(inode)->uniqueid = fattr->cf_uniqueid;
820
	CIFS_I(inode)->createtime = fattr->cf_createtime;
821 822 823
	return 0;
}

824 825 826 827 828 829 830 831 832 833
/*
 * walk dentry list for an inode and report whether it has aliases that
 * are hashed. We use this to determine if a directory inode can actually
 * be used.
 */
static bool
inode_has_hashed_dentries(struct inode *inode)
{
	struct dentry *dentry;

834
	spin_lock(&inode->i_lock);
835
	hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
836
		if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
837
			spin_unlock(&inode->i_lock);
838 839 840
			return true;
		}
	}
841
	spin_unlock(&inode->i_lock);
842 843 844
	return false;
}

845 846 847 848 849 850 851
/* Given fattrs, get a corresponding inode */
struct inode *
cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
{
	unsigned long hash;
	struct inode *inode;

852
retry_iget5_locked:
853
	cifs_dbg(FYI, "looking for uniqueid=%llu\n", fattr->cf_uniqueid);
854 855 856 857 858 859

	/* hash down to 32-bits on 32-bit arch */
	hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid);

	inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
	if (inode) {
860
		/* was there a potentially problematic inode collision? */
861 862
		if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
			fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
863 864 865 866 867 868 869

			if (inode_has_hashed_dentries(inode)) {
				cifs_autodisable_serverino(CIFS_SB(sb));
				iput(inode);
				fattr->cf_uniqueid = iunique(sb, ROOT_I);
				goto retry_iget5_locked;
			}
870 871
		}

872 873 874 875 876
		cifs_fattr_to_inode(inode, fattr);
		if (sb->s_flags & MS_NOATIME)
			inode->i_flags |= S_NOATIME | S_NOCMTIME;
		if (inode->i_state & I_NEW) {
			inode->i_ino = hash;
877 878
			if (S_ISREG(inode->i_mode))
				inode->i_data.backing_dev_info = sb->s_bdi;
Steve French's avatar
Steve French committed
879
#ifdef CONFIG_CIFS_FSCACHE
880 881
			/* initialize per-inode cache cookie pointer */
			CIFS_I(inode)->fscache = NULL;
Steve French's avatar
Steve French committed
882
#endif
883 884 885 886 887 888 889
			unlock_new_inode(inode);
		}
	}

	return inode;
}

Linus Torvalds's avatar
Linus Torvalds committed
890
/* gets root inode */
891
struct inode *cifs_root_iget(struct super_block *sb)
Linus Torvalds's avatar
Linus Torvalds committed
892
{
893
	unsigned int xid;
894
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
895
	struct inode *inode = NULL;
896
	long rc;
897
	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
	char *path = NULL;
	int len;

	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
	    && cifs_sb->prepath) {
		len = strlen(cifs_sb->prepath);
		path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
		if (path == NULL)
			return ERR_PTR(-ENOMEM);
		path[0] = '/';
		memcpy(path+1, cifs_sb->prepath, len);
	} else {
		path = kstrdup("", GFP_KERNEL);
		if (path == NULL)
			return ERR_PTR(-ENOMEM);
	}
914

915
	xid = get_xid();
916
	convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
917
	if (tcon->unix_ext)
918
		rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
919
	else
920
		rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
921

922 923 924 925
	if (!inode) {
		inode = ERR_PTR(rc);
		goto out;
	}
926

Steve French's avatar
Steve French committed
927
#ifdef CONFIG_CIFS_FSCACHE
928
	/* populate tcon->resource_id */
929
	tcon->resource_id = CIFS_I(inode)->uniqueid;
Steve French's avatar
Steve French committed
930
#endif
931

932
	if (rc && tcon->ipc) {
933
		cifs_dbg(FYI, "ipc connection - fake read inode\n");
934
		spin_lock(&inode->i_lock);
935
		inode->i_mode |= S_IFDIR;
Miklos Szeredi's avatar
Miklos Szeredi committed
936
		set_nlink(inode, 2);
937 938 939 940
		inode->i_op = &cifs_ipc_inode_ops;
		inode->i_fop = &simple_dir_operations;
		inode->i_uid = cifs_sb->mnt_uid;
		inode->i_gid = cifs_sb->mnt_gid;
941
		spin_unlock(&inode->i_lock);
942
	} else if (rc) {
943
		iget_failed(inode);
944
		inode = ERR_PTR(rc);
945 946
	}

947
out:
948
	kfree(path);
949
	/* can not call macro free_xid here since in a void func
950 951
	 * TODO: This is no longer true
	 */
952
	_free_xid(xid);
953
	return inode;
Linus Torvalds's avatar
Linus Torvalds committed
954 955
}

956
int
957
cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
958
		   char *full_path, __u32 dosattr)
959 960 961
{
	bool set_time = false;
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
962
	struct TCP_Server_Info *server;
963 964
	FILE_BASIC_INFO	info_buf;

965 966 967
	if (attrs == NULL)
		return -EINVAL;

968 969 970 971
	server = cifs_sb_master_tcon(cifs_sb)->ses->server;
	if (!server->ops->set_file_info)
		return -ENOSYS;

972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
	if (attrs->ia_valid & ATTR_ATIME) {
		set_time = true;
		info_buf.LastAccessTime =
			cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
	} else
		info_buf.LastAccessTime = 0;

	if (attrs->ia_valid & ATTR_MTIME) {
		set_time = true;
		info_buf.LastWriteTime =
		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
	} else
		info_buf.LastWriteTime = 0;

	/*
	 * Samba throws this field away, but windows may actually use it.
	 * Do not set ctime unless other time stamps are changed explicitly
	 * (i.e. by utimes()) since we would then have a mix of client and
	 * server times.
	 */
	if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
993
		cifs_dbg(FYI, "CIFS - CTIME changed\n");
994 995 996 997 998 999 1000 1001
		info_buf.ChangeTime =
		    cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
	} else
		info_buf.ChangeTime = 0;

	info_buf.CreationTime = 0;	/* don't change */
	info_buf.Attributes = cpu_to_le32(dosattr);

1002
	return server->ops->set_file_info(inode, full_path, &info_buf, xid);
1003 1004
}

1005
/*
1006
 * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
1007 1008 1009
 * and rename it to a random name that hopefully won't conflict with
 * anything else.
 */
1010 1011 1012
int
cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
			   const unsigned int xid)
1013 1014 1015 1016
{
	int oplock = 0;
	int rc;
	__u16 netfid;
1017
	struct inode *inode = dentry->d_inode;
1018 1019
	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1020
	struct tcon_link *tlink;
1021
	struct cifs_tcon *tcon;
1022 1023
	__u32 dosattr, origattr;
	FILE_BASIC_INFO *info_buf = NULL;
1024

1025 1026 1027 1028 1029
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	tcon = tlink_tcon(tlink);

1030 1031 1032 1033 1034 1035 1036 1037 1038
	/*
	 * We cannot rename the file if the server doesn't support
	 * CAP_INFOLEVEL_PASSTHRU
	 */
	if (!(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)) {
		rc = -EBUSY;
		goto out;
	}

1039
	rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
1040
			 DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
1041 1042 1043 1044 1045
			 &netfid, &oplock, NULL, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc != 0)
		goto out;

1046 1047 1048 1049 1050
	origattr = cifsInode->cifsAttrs;
	if (origattr == 0)
		origattr |= ATTR_NORMAL;

	dosattr = origattr & ~ATTR_READONLY;
1051 1052 1053 1054
	if (dosattr == 0)
		dosattr |= ATTR_NORMAL;
	dosattr |= ATTR_HIDDEN;

1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
	/* set ATTR_HIDDEN and clear ATTR_READONLY, but only if needed */
	if (dosattr != origattr) {
		info_buf = kzalloc(sizeof(*info_buf), GFP_KERNEL);
		if (info_buf == NULL) {
			rc = -ENOMEM;
			goto out_close;
		}
		info_buf->Attributes = cpu_to_le32(dosattr);
		rc = CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
					current->tgid);
		/* although we would like to mark the file hidden
 		   if that fails we will still try to rename it */
1067
		if (!rc)
1068 1069 1070
			cifsInode->cifsAttrs = dosattr;
		else
			dosattr = origattr; /* since not able to change them */
1071 1072
	}

1073 1074
	/* rename the file */
	rc = CIFSSMBRenameOpenFile(xid, tcon, netfid, NULL, cifs_sb->local_nls,
1075 1076
				   cifs_sb->mnt_cifs_flags &
					    CIFS_MOUNT_MAP_SPECIAL_CHR);
1077
	if (rc != 0) {
1078
		rc = -EBUSY;
1079 1080
		goto undo_setattr;
	}
1081

1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
	/* try to set DELETE_ON_CLOSE */
	if (!cifsInode->delete_pending) {
		rc = CIFSSMBSetFileDisposition(xid, tcon, true, netfid,
					       current->tgid);
		/*
		 * some samba versions return -ENOENT when we try to set the
		 * file disposition here. Likely a samba bug, but work around
		 * it for now. This means that some cifsXXX files may hang
		 * around after they shouldn't.
		 *
		 * BB: remove this hack after more servers have the fix
		 */
		if (rc == -ENOENT)
			rc = 0;
		else if (rc != 0) {
1097
			rc = -EBUSY;
1098 1099 1100 1101
			goto undo_rename;
		}
		cifsInode->delete_pending = true;
	}
1102

1103 1104 1105
out_close:
	CIFSSMBClose(xid, tcon, netfid);
out:
1106
	kfree(info_buf);
1107
	cifs_put_tlink(tlink);
1108
	return rc;
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127

	/*
	 * reset everything back to the original state. Don't bother
	 * dealing with errors here since we can't do anything about
	 * them anyway.
	 */
undo_rename:
	CIFSSMBRenameOpenFile(xid, tcon, netfid, dentry->d_name.name,
				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
					    CIFS_MOUNT_MAP_SPECIAL_CHR);
undo_setattr:
	if (dosattr != origattr) {
		info_buf->Attributes = cpu_to_le32(origattr);
		if (!CIFSSMBSetFileInfo(xid, tcon, info_buf, netfid,
					current->tgid))
			cifsInode->cifsAttrs = origattr;
	}

	goto out_close;
1128 1129
}

1130 1131 1132 1133 1134 1135 1136 1137 1138
/* copied from fs/nfs/dir.c with small changes */
static void
cifs_drop_nlink(struct inode *inode)
{
	spin_lock(&inode->i_lock);
	if (inode->i_nlink > 0)
		drop_nlink(inode);
	spin_unlock(&inode->i_lock);
}
1139 1140 1141 1142

/*
 * If dentry->d_inode is null (usually meaning the cached dentry
 * is a negative dentry) then we would attempt a standard SMB delete, but
1143 1144
 * if that fails we can not attempt the fall back mechanisms on EACCESS
 * but will return the EACCESS to the caller. Note that the VFS does not call
1145 1146
 * unlink on negative dentries currently.
 */
1147
int cifs_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds's avatar
Linus Torvalds committed
1148 1149
{
	int rc = 0;
1150
	unsigned int xid;
Linus Torvalds's avatar
Linus Torvalds committed
1151
	char *full_path = NULL;
1152
	struct inode *inode = dentry->d_inode;
1153
	struct cifsInodeInfo *cifs_inode;
1154 1155
	struct super_block *sb = dir->i_sb;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1156
	struct tcon_link *tlink;
1157
	struct cifs_tcon *tcon;
1158
	struct TCP_Server_Info *server;
1159 1160
	struct iattr *attrs = NULL;
	__u32 dosattr = 0, origattr = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1161

1162
	cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry);
Linus Torvalds's avatar
Linus Torvalds committed
1163

1164 1165 1166 1167
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	tcon = tlink_tcon(tlink);
1168
	server = tcon->ses->server;
1169

1170
	xid = get_xid();
Linus Torvalds's avatar
Linus Torvalds committed
1171

1172 1173 1174
	/* Unlink can be called from rename so we can not take the
	 * sb->s_vfs_rename_mutex here */
	full_path = build_path_from_dentry(dentry);
Linus Torvalds's avatar
Linus Torvalds committed
1175
	if (full_path == NULL) {
1176
		rc = -ENOMEM;
1177
		goto unlink_out;
Linus Torvalds's avatar
Linus Torvalds committed
1178
	}
1179

1180 1181
	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1182
		rc = CIFSPOSIXDelFile(xid, tcon, full_path,
1183
			SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
1184
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1185
		cifs_dbg(FYI, "posix del rc %d\n", rc);
1186 1187 1188
		if ((rc == 0) || (rc == -ENOENT))
			goto psx_del_no_retry;
	}
Linus Torvalds's avatar
Linus Torvalds committed
1189

1190
retry_std_delete:
1191 1192 1193 1194 1195 1196
	if (!server->ops->unlink) {
		rc = -ENOSYS;
		goto psx_del_no_retry;
	}

	rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
1197

1198
psx_del_no_retry:
Linus Torvalds's avatar
Linus Torvalds committed
1199
	if (!rc) {
1200
		if (inode)
1201
			cifs_drop_nlink(inode);
Linus Torvalds's avatar
Linus Torvalds committed
1202
	} else if (rc == -ENOENT) {
1203
		d_drop(dentry);
1204
	} else if (rc == -EBUSY) {
1205 1206 1207 1208 1209 1210
		if (server->ops->rename_pending_delete) {
			rc = server->ops->rename_pending_delete(full_path,
								dentry, xid);
			if (rc == 0)
				cifs_drop_nlink(inode);
		}
1211
	} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
1212 1213 1214 1215
		attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
		if (attrs == NULL) {
			rc = -ENOMEM;
			goto out_reval;
Linus Torvalds's avatar
Linus Torvalds committed
1216
		}
1217 1218

		/* try to reset dos attributes */
1219 1220
		cifs_inode = CIFS_I(inode);
		origattr = cifs_inode->cifsAttrs;
1221 1222 1223
		if (origattr == 0)
			origattr |= ATTR_NORMAL;
		dosattr = origattr & ~ATTR_READONLY;
1224 1225 1226 1227 1228 1229 1230
		if (dosattr == 0)
			dosattr |= ATTR_NORMAL;
		dosattr |= ATTR_HIDDEN;

		rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
		if (rc != 0)
			goto out_reval;
1231 1232

		goto retry_std_delete;
Linus Torvalds's avatar
Linus Torvalds committed
1233
	}
1234 1235 1236 1237 1238

	/* undo the setattr if we errored out and it's needed */
	if (rc != 0 && dosattr != 0)
		cifs_set_file_info(inode, attrs, xid, full_path, origattr);

1239
out_reval:
1240
	if (inode) {
1241 1242
		cifs_inode = CIFS_I(inode);
		cifs_inode->time = 0;	/* will force revalidate to get info
1243 1244
					   when needed */
		inode->i_ctime = current_fs_time(sb);
1245
	}
1246
	dir->i_ctime = dir->i_mtime = current_fs_time(sb);
1247
	cifs_inode = CIFS_I(dir);
1248
	CIFS_I(dir)->time = 0;	/* force revalidate of dir as well */
1249
unlink_out:
Linus Torvalds's avatar
Linus Torvalds committed
1250
	kfree(full_path);
1251
	kfree(attrs);
1252
	free_xid(xid);
1253
	cifs_put_tlink(tlink);
Linus Torvalds's avatar
Linus Torvalds committed
1254 1255 1256
	return rc;
}

1257
static int
1258
cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode,
1259 1260 1261 1262
		 const char *full_path, struct cifs_sb_info *cifs_sb,
		 struct cifs_tcon *tcon, const unsigned int xid)
{
	int rc = 0;
1263
	struct inode *inode = NULL;
1264 1265

	if (tcon->unix_ext)
1266
		rc = cifs_get_inode_info_unix(&inode, full_path, parent->i_sb,
1267 1268
					      xid);
	else
1269 1270 1271
		rc = cifs_get_inode_info(&inode, full_path, NULL, parent->i_sb,
					 xid, NULL);

1272 1273 1274 1275 1276
	if (rc)
		return rc;

	/*
	 * setting nlink not necessary except in cases where we failed to get it
1277 1278
	 * from the server or was set bogus. Also, since this is a brand new
	 * inode, no need to grab the i_lock before setting the i_nlink.
1279
	 */
1280 1281
	if (inode->i_nlink < 2)
		set_nlink(inode, 2);
1282 1283
	mode &= ~current_umask();
	/* must turn on setgid bit if parent dir has it */
1284
	if (parent->i_mode & S_ISGID)
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
		mode |= S_ISGID;

	if (tcon->unix_ext) {
		struct cifs_unix_set_info_args args = {
			.mode	= mode,
			.ctime	= NO_CHANGE_64,
			.atime	= NO_CHANGE_64,
			.mtime	= NO_CHANGE_64,
			.device	= 0,
		};
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
1296
			args.uid = current_fsuid();
1297
			if (parent->i_mode & S_ISGID)
1298
				args.gid = parent->i_gid;
1299
			else
1300
				args.gid = current_fsgid();
1301
		} else {
1302 1303
			args.uid = INVALID_UID; /* no change */
			args.gid = INVALID_GID; /* no change */
1304 1305 1306 1307 1308 1309
		}
		CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
				       cifs_sb->local_nls,
				       cifs_sb->mnt_cifs_flags &
				       CIFS_MOUNT_MAP_SPECIAL_CHR);
	} else {
1310
		struct TCP_Server_Info *server = tcon->ses->server;
1311
		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1312
		    (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
1313
			server->ops->mkdir_setinfo(inode, full_path, cifs_sb,
1314
						   tcon, xid);
1315 1316 1317 1318 1319 1320 1321 1322 1323
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
			inode->i_mode = (mode | S_IFDIR);

		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
			inode->i_uid = current_fsuid();
			if (inode->i_mode & S_ISGID)
				inode->i_gid = parent->i_gid;
			else
				inode->i_gid = current_fsgid();
1324 1325
		}
	}
1326
	d_instantiate(dentry, inode);
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
	return rc;
}

static int
cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
		 const char *full_path, struct cifs_sb_info *cifs_sb,
		 struct cifs_tcon *tcon, const unsigned int xid)
{
	int rc = 0;
	u32 oplock = 0;
	FILE_UNIX_BASIC_INFO *info = NULL;
	struct inode *newinode = NULL;
	struct cifs_fattr fattr;

	info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
	if (info == NULL) {
		rc = -ENOMEM;
		goto posix_mkdir_out;
	}

	mode &= ~current_umask();
	rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
			     NULL /* netfid */, info, &oplock, full_path,
			     cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
			     CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc == -EOPNOTSUPP)
		goto posix_mkdir_out;
	else if (rc) {
1355
		cifs_dbg(FYI, "posix mkdir returned 0x%x\n", rc);
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376
		d_drop(dentry);
		goto posix_mkdir_out;
	}

	if (info->Type == cpu_to_le32(-1))
		/* no return info, go query for it */
		goto posix_mkdir_get_info;
	/*
	 * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
	 * need to set uid/gid.
	 */

	cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
	cifs_fill_uniqueid(inode->i_sb, &fattr);
	newinode = cifs_iget(inode->i_sb, &fattr);
	if (!newinode)
		goto posix_mkdir_get_info;

	d_instantiate(dentry, newinode);

#ifdef CONFIG_CIFS_DEBUG2
1377 1378
	cifs_dbg(FYI, "instantiated dentry %p %s to inode %p\n",
		 dentry, dentry->d_name.name, newinode);
1379 1380

	if (newinode->i_nlink != 2)
1381 1382
		cifs_dbg(FYI, "unexpected number of links %d\n",
			 newinode->i_nlink);
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
#endif

posix_mkdir_out:
	kfree(info);
	return rc;
posix_mkdir_get_info:
	rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
			      xid);
	goto posix_mkdir_out;
}

1394
int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
Linus Torvalds's avatar
Linus Torvalds committed
1395
{
1396
	int rc = 0;
1397
	unsigned int xid;
Linus Torvalds's avatar
Linus Torvalds committed
1398
	struct cifs_sb_info *cifs_sb;
1399
	struct tcon_link *tlink;
1400
	struct cifs_tcon *tcon;
1401
	struct TCP_Server_Info *server;
1402
	char *full_path;
Linus Torvalds's avatar
Linus Torvalds committed
1403

1404 1405
	cifs_dbg(FYI, "In cifs_mkdir, mode = 0x%hx inode = 0x%p\n",
		 mode, inode);
Linus Torvalds's avatar
Linus Torvalds committed
1406 1407

	cifs_sb = CIFS_SB(inode->i_sb);
1408 1409 1410
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
1411
	tcon = tlink_tcon(tlink);
1412

1413
	xid = get_xid();
Linus Torvalds's avatar
Linus Torvalds committed
1414

1415
	full_path = build_path_from_dentry(direntry);
Linus Torvalds's avatar
Linus Torvalds committed
1416
	if (full_path == NULL) {
1417
		rc = -ENOMEM;
1418
		goto mkdir_out;
Linus Torvalds's avatar
Linus Torvalds committed
1419
	}
1420

1421 1422
	if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
				le64_to_cpu(tcon->fsUnixInfo.Capability))) {
1423 1424 1425
		rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
				      tcon, xid);
		if (rc != -EOPNOTSUPP)
1426
			goto mkdir_out;
Steve French's avatar
Steve French committed
1427
	}
1428

1429 1430 1431 1432 1433 1434 1435
	server = tcon->ses->server;

	if (!server->ops->mkdir) {
		rc = -ENOSYS;
		goto mkdir_out;
	}

Linus Torvalds's avatar
Linus Torvalds committed
1436
	/* BB add setting the equivalent of mode via CreateX w/ACLs */
1437
	rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb);
Linus Torvalds's avatar
Linus Torvalds committed
1438
	if (rc) {
1439
		cifs_dbg(FYI, "cifs_mkdir returned 0x%x\n", rc);
Linus Torvalds's avatar
Linus Torvalds committed
1440
		d_drop(direntry);
1441
		goto mkdir_out;
Linus Torvalds's avatar
Linus Torvalds committed
1442
	}
1443 1444 1445

	rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
			      xid);
Steve French's avatar
Steve French committed
1446
mkdir_out:
1447 1448 1449 1450 1451
	/*
	 * Force revalidate to get parent dir info when needed since cached
	 * attributes are invalid now.
	 */
	CIFS_I(inode)->time = 0;
Linus Torvalds's avatar
Linus Torvalds committed
1452
	kfree(full_path);
1453
	free_xid(xid);
1454
	cifs_put_tlink(tlink);
Linus Torvalds's avatar
Linus Torvalds committed
1455 1456 1457 1458 1459 1460
	return rc;
}

int cifs_rmdir(struct inode *inode, struct dentry *direntry)
{
	int rc = 0;
1461
	unsigned int xid;
Linus Torvalds's avatar
Linus Torvalds committed
1462
	struct cifs_sb_info *cifs_sb;
1463
	struct tcon_link *tlink;
1464 1465
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
Linus Torvalds's avatar
Linus Torvalds committed
1466 1467 1468
	char *full_path = NULL;
	struct cifsInodeInfo *cifsInode;

1469
	cifs_dbg(FYI, "cifs_rmdir, inode = 0x%p\n", inode);
Linus Torvalds's avatar
Linus Torvalds committed
1470

1471
	xid = get_xid();
Linus Torvalds's avatar
Linus Torvalds committed
1472

1473
	full_path = build_path_from_dentry(direntry);
Linus Torvalds's avatar
Linus Torvalds committed
1474
	if (full_path == NULL) {
1475
		rc = -ENOMEM;
1476
		goto rmdir_exit;
Linus Torvalds's avatar
Linus Torvalds committed
1477 1478
	}

1479 1480 1481 1482 1483 1484
	cifs_sb = CIFS_SB(inode->i_sb);
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink)) {
		rc = PTR_ERR(tlink);
		goto rmdir_exit;
	}
1485 1486 1487 1488 1489 1490 1491 1492
	tcon = tlink_tcon(tlink);
	server = tcon->ses->server;

	if (!server->ops->rmdir) {
		rc = -ENOSYS;
		cifs_put_tlink(tlink);
		goto rmdir_exit;
	}
1493

1494
	rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
1495
	cifs_put_tlink(tlink);
Linus Torvalds's avatar
Linus Torvalds committed
1496 1497

	if (!rc) {
1498
		spin_lock(&direntry->d_inode->i_lock);
Steve French's avatar
Steve French committed
1499
		i_size_write(direntry->d_inode, 0);
1500
		clear_nlink(direntry->d_inode);
1501
		spin_unlock(&direntry->d_inode->i_lock);
Linus Torvalds's avatar
Linus Torvalds committed
1502 1503 1504
	}

	cifsInode = CIFS_I(direntry->d_inode);
1505 1506
	/* force revalidate to go get info when needed */
	cifsInode->time = 0;
1507 1508

	cifsInode = CIFS_I(inode);
1509 1510 1511 1512 1513
	/*
	 * Force revalidate to get parent dir info when needed since cached
	 * attributes are invalid now.
	 */
	cifsInode->time = 0;
1514

Linus Torvalds's avatar
Linus Torvalds committed
1515 1516 1517
	direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
		current_fs_time(inode->i_sb);

1518
rmdir_exit:
Linus Torvalds's avatar
Linus Torvalds committed
1519
	kfree(full_path);
1520
	free_xid(xid);
Linus Torvalds's avatar
Linus Torvalds committed
1521 1522 1523
	return rc;
}

1524
static int
1525 1526 1527
cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
	       const char *from_path, struct dentry *to_dentry,
	       const char *to_path)
1528 1529
{
	struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
1530
	struct tcon_link *tlink;
1531 1532
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;
1533 1534 1535
	__u16 srcfid;
	int oplock, rc;

1536 1537 1538
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
1539 1540 1541 1542 1543
	tcon = tlink_tcon(tlink);
	server = tcon->ses->server;

	if (!server->ops->rename)
		return -ENOSYS;
1544

1545
	/* try path-based rename first */
1546
	rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
1547 1548

	/*
1549 1550
	 * Don't bother with rename by filehandle unless file is busy and
	 * source. Note that cross directory moves do not work with
1551 1552
	 * rename by filehandle to various Windows servers.
	 */
1553
	if (rc == 0 || rc != -EBUSY)
1554
		goto do_rename_exit;
1555

1556 1557
	/* open-file renames don't work across directories */
	if (to_dentry->d_parent != from_dentry->d_parent)
1558
		goto do_rename_exit;
1559

1560
	/* open the file to be renamed -- we need DELETE perms */
1561
	rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
1562 1563 1564 1565
			 CREATE_NOT_DIR, &srcfid, &oplock, NULL,
			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
				CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc == 0) {
1566
		rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
1567 1568 1569
				(const char *) to_dentry->d_name.name,
				cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
					CIFS_MOUNT_MAP_SPECIAL_CHR);
1570
		CIFSSMBClose(xid, tcon, srcfid);
1571
	}
1572 1573
do_rename_exit:
	cifs_put_tlink(tlink);
1574 1575 1576
	return rc;
}

1577 1578 1579
int
cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
	    struct inode *target_dir, struct dentry *target_dentry)
Linus Torvalds's avatar
Linus Torvalds committed
1580
{
1581 1582
	char *from_name = NULL;
	char *to_name = NULL;
1583
	struct cifs_sb_info *cifs_sb;
1584
	struct tcon_link *tlink;
1585
	struct cifs_tcon *tcon;
1586 1587
	FILE_UNIX_BASIC_INFO *info_buf_source = NULL;
	FILE_UNIX_BASIC_INFO *info_buf_target;
1588 1589
	unsigned int xid;
	int rc, tmprc;
Linus Torvalds's avatar
Linus Torvalds committed
1590

1591
	cifs_sb = CIFS_SB(source_dir->i_sb);
1592 1593 1594 1595
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	tcon = tlink_tcon(tlink);
Linus Torvalds's avatar
Linus Torvalds committed
1596

1597
	xid = get_xid();
1598 1599 1600 1601 1602

	/*
	 * we already have the rename sem so we do not need to
	 * grab it again here to protect the path integrity
	 */
1603 1604
	from_name = build_path_from_dentry(source_dentry);
	if (from_name == NULL) {
1605 1606 1607 1608
		rc = -ENOMEM;
		goto cifs_rename_exit;
	}

1609 1610
	to_name = build_path_from_dentry(target_dentry);
	if (to_name == NULL) {
Linus Torvalds's avatar
Linus Torvalds committed
1611 1612 1613 1614
		rc = -ENOMEM;
		goto cifs_rename_exit;
	}

1615 1616
	rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
			    to_name);
1617

1618 1619
	if (rc == -EEXIST && tcon->unix_ext) {
		/*
1620 1621
		 * Are src and dst hardlinks of same inode? We can only tell
		 * with unix extensions enabled.
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
		 */
		info_buf_source =
			kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
					GFP_KERNEL);
		if (info_buf_source == NULL) {
			rc = -ENOMEM;
			goto cifs_rename_exit;
		}

		info_buf_target = info_buf_source + 1;
1632 1633 1634 1635 1636
		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
					     info_buf_source,
					     cifs_sb->local_nls,
					     cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);
1637
		if (tmprc != 0)
1638
			goto unlink_target;
1639

1640 1641 1642 1643 1644
		tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
					     info_buf_target,
					     cifs_sb->local_nls,
					     cifs_sb->mnt_cifs_flags &
						CIFS_MOUNT_MAP_SPECIAL_CHR);
1645

1646
		if (tmprc == 0 && (info_buf_source->UniqueId ==
1647
				   info_buf_target->UniqueId)) {
1648
			/* same file, POSIX says that this is a noop */
1649
			rc = 0;
1650
			goto cifs_rename_exit;
1651
		}
1652 1653 1654 1655 1656
	}
	/*
	 * else ... BB we could add the same check for Windows by
	 * checking the UniqueId via FILE_INTERNAL_INFO
	 */
1657

1658
unlink_target:
1659 1660
	/* Try unlinking the target dentry if it's not negative */
	if (target_dentry->d_inode && (rc == -EACCES || rc == -EEXIST)) {
1661 1662 1663 1664
		if (S_ISDIR(target_dentry->d_inode->i_mode))
			tmprc = cifs_rmdir(target_dir, target_dentry);
		else
			tmprc = cifs_unlink(target_dir, target_dentry);
1665 1666
		if (tmprc)
			goto cifs_rename_exit;
1667 1668
		rc = cifs_do_rename(xid, source_dentry, from_name,
				    target_dentry, to_name);
Linus Torvalds's avatar
Linus Torvalds committed
1669 1670
	}

1671 1672 1673 1674 1675 1676
	/* force revalidate to go get info when needed */
	CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;

	source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime =
		target_dir->i_mtime = current_fs_time(source_dir->i_sb);

Linus Torvalds's avatar
Linus Torvalds committed
1677
cifs_rename_exit:
1678
	kfree(info_buf_source);
1679 1680
	kfree(from_name);
	kfree(to_name);
1681
	free_xid(xid);
1682
	cifs_put_tlink(tlink);
Linus Torvalds's avatar
Linus Torvalds committed
1683 1684 1685
	return rc;
}

1686 1687
static bool
cifs_inode_needs_reval(struct inode *inode)
Linus Torvalds's avatar
Linus Torvalds committed
1688
{
1689
	struct cifsInodeInfo *cifs_i = CIFS_I(inode);
1690
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Linus Torvalds's avatar
Linus Torvalds committed
1691

1692 1693
	if (cifs_i->clientCanCacheRead)
		return false;
Linus Torvalds's avatar
Linus Torvalds committed
1694

1695 1696
	if (!lookupCacheEnabled)
		return true;
Linus Torvalds's avatar
Linus Torvalds committed
1697

1698 1699
	if (cifs_i->time == 0)
		return true;
Linus Torvalds's avatar
Linus Torvalds committed
1700

1701 1702
	if (!time_in_range(jiffies, cifs_i->time,
				cifs_i->time + cifs_sb->actimeo))
1703 1704
		return true;

1705
	/* hardlinked files w/ noserverino get "special" treatment */
1706
	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
1707 1708 1709
	    S_ISREG(inode->i_mode) && inode->i_nlink != 1)
		return true;

1710 1711 1712
	return false;
}

1713 1714 1715
/*
 * Zap the cache. Called when invalid_mapping flag is set.
 */
1716
int
1717 1718
cifs_invalidate_mapping(struct inode *inode)
{
1719
	int rc = 0;
1720 1721 1722 1723 1724
	struct cifsInodeInfo *cifs_i = CIFS_I(inode);

	cifs_i->invalid_mapping = false;

	if (inode->i_mapping && inode->i_mapping->nrpages != 0) {
1725 1726
		rc = invalidate_inode_pages2(inode->i_mapping);
		if (rc) {
1727 1728
			cifs_dbg(VFS, "%s: could not invalidate inode %p\n",
				 __func__, inode);
1729 1730
			cifs_i->invalid_mapping = true;
		}
1731
	}
1732

1733
	cifs_fscache_reset_inode_cookie(inode);
1734
	return rc;
1735 1736
}

1737
int cifs_revalidate_file_attr(struct file *filp)
Jeff Layton's avatar
Jeff Layton committed
1738 1739
{
	int rc = 0;
Al Viro's avatar
Al Viro committed
1740
	struct inode *inode = file_inode(filp);
1741
	struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data;
Jeff Layton's avatar
Jeff Layton committed
1742 1743

	if (!cifs_inode_needs_reval(inode))
1744
		return rc;
Jeff Layton's avatar
Jeff Layton committed
1745

1746
	if (tlink_tcon(cfile->tlink)->unix_ext)
Jeff Layton's avatar
Jeff Layton committed
1747 1748 1749 1750 1751 1752 1753
		rc = cifs_get_file_info_unix(filp);
	else
		rc = cifs_get_file_info(filp);

	return rc;
}

1754
int cifs_revalidate_dentry_attr(struct dentry *dentry)
1755
{
1756
	unsigned int xid;
1757 1758 1759
	int rc = 0;
	struct inode *inode = dentry->d_inode;
	struct super_block *sb = dentry->d_sb;
1760
	char *full_path = NULL;
1761 1762 1763

	if (inode == NULL)
		return -ENOENT;
Linus Torvalds's avatar
Linus Torvalds committed
1764

1765
	if (!cifs_inode_needs_reval(inode))
1766 1767
		return rc;

1768
	xid = get_xid();
Linus Torvalds's avatar
Linus Torvalds committed
1769 1770 1771

	/* can not safely grab the rename sem here if rename calls revalidate
	   since that would deadlock */
1772
	full_path = build_path_from_dentry(dentry);
Linus Torvalds's avatar
Linus Torvalds committed
1773
	if (full_path == NULL) {
1774
		rc = -ENOMEM;
1775
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
1776 1777
	}

1778 1779
	cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n",
		 full_path, inode, inode->i_count.counter,
1780
		 dentry, dentry->d_time, jiffies);
Linus Torvalds's avatar
Linus Torvalds committed
1781

1782
	if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
1783 1784 1785 1786
		rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
	else
		rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
					 xid, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
1787

1788
out:
Linus Torvalds's avatar
Linus Torvalds committed
1789
	kfree(full_path);
1790
	free_xid(xid);
Linus Torvalds's avatar
Linus Torvalds committed
1791 1792 1793
	return rc;
}

1794 1795 1796
int cifs_revalidate_file(struct file *filp)
{
	int rc;
Al Viro's avatar
Al Viro committed
1797
	struct inode *inode = file_inode(filp);
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822

	rc = cifs_revalidate_file_attr(filp);
	if (rc)
		return rc;

	if (CIFS_I(inode)->invalid_mapping)
		rc = cifs_invalidate_mapping(inode);
	return rc;
}

/* revalidate a dentry's inode attributes */
int cifs_revalidate_dentry(struct dentry *dentry)
{
	int rc;
	struct inode *inode = dentry->d_inode;

	rc = cifs_revalidate_dentry_attr(dentry);
	if (rc)
		return rc;

	if (CIFS_I(inode)->invalid_mapping)
		rc = cifs_invalidate_mapping(inode);
	return rc;
}

Linus Torvalds's avatar
Linus Torvalds committed
1823
int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1824
		 struct kstat *stat)
Linus Torvalds's avatar
Linus Torvalds committed
1825
{
1826
	struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
1827
	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
1828 1829
	struct inode *inode = dentry->d_inode;
	int rc;
1830

1831 1832 1833 1834 1835 1836 1837
	/*
	 * We need to be sure that all dirty pages are written and the server
	 * has actual ctime, mtime and file length.
	 */
	if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
	    inode->i_mapping->nrpages != 0) {
		rc = filemap_fdatawait(inode->i_mapping);
1838 1839 1840 1841
		if (rc) {
			mapping_set_error(inode->i_mapping, rc);
			return rc;
		}
1842
	}
1843

1844 1845 1846 1847 1848 1849 1850 1851 1852
	rc = cifs_revalidate_dentry_attr(dentry);
	if (rc)
		return rc;

	generic_fillattr(inode, stat);
	stat->blksize = CIFS_MAX_MSGSIZE;
	stat->ino = CIFS_I(inode)->uniqueid;

	/*
1853 1854 1855
	 * If on a multiuser mount without unix extensions or cifsacl being
	 * enabled, and the admin hasn't overridden them, set the ownership
	 * to the fsuid/fsgid of the current process.
1856 1857
	 */
	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
1858
	    !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
1859 1860 1861 1862 1863
	    !tcon->unix_ext) {
		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
			stat->uid = current_fsuid();
		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
			stat->gid = current_fsgid();
1864
	}
1865
	return rc;
Linus Torvalds's avatar
Linus Torvalds committed
1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
}

static int cifs_truncate_page(struct address_space *mapping, loff_t from)
{
	pgoff_t index = from >> PAGE_CACHE_SHIFT;
	unsigned offset = from & (PAGE_CACHE_SIZE - 1);
	struct page *page;
	int rc = 0;

	page = grab_cache_page(mapping, index);
	if (!page)
		return -ENOMEM;

1879
	zero_user_segment(page, offset, PAGE_CACHE_SIZE);
Linus Torvalds's avatar
Linus Torvalds committed
1880 1881 1882 1883 1884
	unlock_page(page);
	page_cache_release(page);
	return rc;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1885
static void cifs_setsize(struct inode *inode, loff_t offset)
1886
{
npiggin@suse.de's avatar
npiggin@suse.de committed
1887
	loff_t oldsize;
1888

1889
	spin_lock(&inode->i_lock);
npiggin@suse.de's avatar
npiggin@suse.de committed
1890
	oldsize = inode->i_size;
1891
	i_size_write(inode, offset);
1892
	spin_unlock(&inode->i_lock);
Christoph Hellwig's avatar
Christoph Hellwig committed
1893

npiggin@suse.de's avatar
npiggin@suse.de committed
1894
	truncate_pagecache(inode, oldsize, offset);
1895 1896
}

1897 1898
static int
cifs_set_file_size(struct inode *inode, struct iattr *attrs,
1899
		   unsigned int xid, char *full_path)
1900 1901 1902 1903 1904
{
	int rc;
	struct cifsFileInfo *open_file;
	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1905
	struct tcon_link *tlink = NULL;
1906 1907
	struct cifs_tcon *tcon = NULL;
	struct TCP_Server_Info *server;
1908
	struct cifs_io_parms io_parms;
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918

	/*
	 * To avoid spurious oplock breaks from server, in the case of
	 * inodes that we already have open, avoid doing path based
	 * setting of file size if we can do it by handle.
	 * This keeps our caching token (oplock) and avoids timeouts
	 * when the local oplock break takes longer to flush
	 * writebehind data than the SMB timeout for the SetPathInfo
	 * request would allow
	 */
1919
	open_file = find_writable_file(cifsInode, true);
1920
	if (open_file) {
1921 1922 1923 1924 1925 1926 1927
		tcon = tlink_tcon(open_file->tlink);
		server = tcon->ses->server;
		if (server->ops->set_file_size)
			rc = server->ops->set_file_size(xid, tcon, open_file,
							attrs->ia_size, false);
		else
			rc = -ENOSYS;
1928
		cifsFileInfo_put(open_file);
1929
		cifs_dbg(FYI, "SetFSize for attrs rc = %d\n", rc);
1930 1931
		if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
			unsigned int bytes_written;
1932

1933 1934 1935
			io_parms.netfid = open_file->fid.netfid;
			io_parms.pid = open_file->pid;
			io_parms.tcon = tcon;
1936 1937 1938 1939
			io_parms.offset = 0;
			io_parms.length = attrs->ia_size;
			rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
					  NULL, NULL, 1);
1940
			cifs_dbg(FYI, "Wrt seteof rc %d\n", rc);
1941 1942 1943 1944
		}
	} else
		rc = -EINVAL;

1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
	if (!rc)
		goto set_size_out;

	if (tcon == NULL) {
		tlink = cifs_sb_tlink(cifs_sb);
		if (IS_ERR(tlink))
			return PTR_ERR(tlink);
		tcon = tlink_tcon(tlink);
		server = tcon->ses->server;
	}
1955

1956 1957 1958 1959 1960 1961 1962 1963 1964 1965
	/*
	 * Set file size by pathname rather than by handle either because no
	 * valid, writeable file handle for it was found or because there was
	 * an error setting it by handle.
	 */
	if (server->ops->set_path_size)
		rc = server->ops->set_path_size(xid, tcon, full_path,
						attrs->ia_size, cifs_sb, false);
	else
		rc = -ENOSYS;
1966
	cifs_dbg(FYI, "SetEOF by path (setattrs) rc = %d\n", rc);
1967 1968 1969 1970 1971 1972 1973
	if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
		__u16 netfid;
		int oplock = 0;

		rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
				   GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
				   &oplock, NULL, cifs_sb->local_nls,
1974
				   cifs_sb->mnt_cifs_flags &
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985
						CIFS_MOUNT_MAP_SPECIAL_CHR);
		if (rc == 0) {
			unsigned int bytes_written;

			io_parms.netfid = netfid;
			io_parms.pid = current->tgid;
			io_parms.tcon = tcon;
			io_parms.offset = 0;
			io_parms.length = attrs->ia_size;
			rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL,
					  NULL,  1);
1986
			cifs_dbg(FYI, "wrt seteof rc %d\n", rc);
1987
			CIFSSMBClose(xid, tcon, netfid);
1988 1989
		}
	}
1990 1991
	if (tlink)
		cifs_put_tlink(tlink);
1992

1993
set_size_out:
1994
	if (rc == 0) {
1995
		cifsInode->server_eof = attrs->ia_size;
Christoph Hellwig's avatar
Christoph Hellwig committed
1996
		cifs_setsize(inode, attrs->ia_size);
1997 1998 1999 2000 2001 2002
		cifs_truncate_page(inode->i_mapping, inode->i_size);
	}

	return rc;
}

2003 2004 2005 2006
static int
cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
{
	int rc;
2007
	unsigned int xid;
2008 2009 2010 2011
	char *full_path = NULL;
	struct inode *inode = direntry->d_inode;
	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
2012
	struct tcon_link *tlink;
2013
	struct cifs_tcon *pTcon;
2014
	struct cifs_unix_set_info_args *args = NULL;
2015
	struct cifsFileInfo *open_file;
2016

2017
	cifs_dbg(FYI, "setattr_unix on file %s attrs->ia_valid=0x%x\n",
2018
		 direntry->d_name.name, attrs->ia_valid);
2019

2020
	xid = get_xid();
2021

2022 2023 2024 2025 2026 2027
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
		attrs->ia_valid |= ATTR_FORCE;

	rc = inode_change_ok(inode, attrs);
	if (rc < 0)
		goto out;
2028 2029 2030 2031 2032 2033 2034

	full_path = build_path_from_dentry(direntry);
	if (full_path == NULL) {
		rc = -ENOMEM;
		goto out;
	}

Jeff Layton's avatar
Jeff Layton committed
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046
	/*
	 * Attempt to flush data before changing attributes. We need to do
	 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
	 * ownership or mode then we may also need to do this. Here, we take
	 * the safe way out and just do the flush on all setattr requests. If
	 * the flush returns error, store it to report later and continue.
	 *
	 * BB: This should be smarter. Why bother flushing pages that
	 * will be truncated anyway? Also, should we error out here if
	 * the flush returns error?
	 */
	rc = filemap_write_and_wait(inode->i_mapping);
2047 2048
	mapping_set_error(inode->i_mapping, rc);
	rc = 0;
2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074

	if (attrs->ia_valid & ATTR_SIZE) {
		rc = cifs_set_file_size(inode, attrs, xid, full_path);
		if (rc != 0)
			goto out;
	}

	/* skip mode change if it's just for clearing setuid/setgid */
	if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
		attrs->ia_valid &= ~ATTR_MODE;

	args = kmalloc(sizeof(*args), GFP_KERNEL);
	if (args == NULL) {
		rc = -ENOMEM;
		goto out;
	}

	/* set up the struct */
	if (attrs->ia_valid & ATTR_MODE)
		args->mode = attrs->ia_mode;
	else
		args->mode = NO_CHANGE_64;

	if (attrs->ia_valid & ATTR_UID)
		args->uid = attrs->ia_uid;
	else
2075
		args->uid = INVALID_UID; /* no change */
2076 2077 2078 2079

	if (attrs->ia_valid & ATTR_GID)
		args->gid = attrs->ia_gid;
	else
2080
		args->gid = INVALID_GID; /* no change */
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097

	if (attrs->ia_valid & ATTR_ATIME)
		args->atime = cifs_UnixTimeToNT(attrs->ia_atime);
	else
		args->atime = NO_CHANGE_64;

	if (attrs->ia_valid & ATTR_MTIME)
		args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime);
	else
		args->mtime = NO_CHANGE_64;

	if (attrs->ia_valid & ATTR_CTIME)
		args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime);
	else
		args->ctime = NO_CHANGE_64;

	args->device = 0;
2098
	open_file = find_writable_file(cifsInode, true);
2099
	if (open_file) {
2100
		u16 nfid = open_file->fid.netfid;
2101
		u32 npid = open_file->pid;
2102
		pTcon = tlink_tcon(open_file->tlink);
2103
		rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
2104
		cifsFileInfo_put(open_file);
2105
	} else {
2106 2107 2108 2109 2110 2111
		tlink = cifs_sb_tlink(cifs_sb);
		if (IS_ERR(tlink)) {
			rc = PTR_ERR(tlink);
			goto out;
		}
		pTcon = tlink_tcon(tlink);
2112
		rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args,
2113 2114 2115
				    cifs_sb->local_nls,
				    cifs_sb->mnt_cifs_flags &
					CIFS_MOUNT_MAP_SPECIAL_CHR);
2116
		cifs_put_tlink(tlink);
2117
	}
2118

Christoph Hellwig's avatar
Christoph Hellwig committed
2119 2120
	if (rc)
		goto out;
2121

Christoph Hellwig's avatar
Christoph Hellwig committed
2122
	if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig's avatar
Christoph Hellwig committed
2123 2124
	    attrs->ia_size != i_size_read(inode))
		truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig's avatar
Christoph Hellwig committed
2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136

	setattr_copy(inode, attrs);
	mark_inode_dirty(inode);

	/* force revalidate when any of these times are set since some
	   of the fs types (eg ext3, fat) do not have fine enough
	   time granularity to match protocol, and we do not have a
	   a way (yet) to query the server fs's time granularity (and
	   whether it rounds times down).
	*/
	if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
		cifsInode->time = 0;
2137 2138 2139
out:
	kfree(args);
	kfree(full_path);
2140
	free_xid(xid);
2141 2142 2143
	return rc;
}

2144 2145
static int
cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
Linus Torvalds's avatar
Linus Torvalds committed
2146
{
2147
	unsigned int xid;
2148 2149
	kuid_t uid = INVALID_UID;
	kgid_t gid = INVALID_GID;
2150 2151 2152
	struct inode *inode = direntry->d_inode;
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct cifsInodeInfo *cifsInode = CIFS_I(inode);
Linus Torvalds's avatar
Linus Torvalds committed
2153 2154
	char *full_path = NULL;
	int rc = -EACCES;
2155
	__u32 dosattr = 0;
2156
	__u64 mode = NO_CHANGE_64;
2157

2158
	xid = get_xid();
Linus Torvalds's avatar
Linus Torvalds committed
2159

2160
	cifs_dbg(FYI, "setattr on file %s attrs->iavalid 0x%x\n",
2161
		 direntry->d_name.name, attrs->ia_valid);
2162

2163 2164 2165 2166 2167
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
		attrs->ia_valid |= ATTR_FORCE;

	rc = inode_change_ok(inode, attrs);
	if (rc < 0) {
2168
		free_xid(xid);
2169
		return rc;
2170
	}
2171

2172
	full_path = build_path_from_dentry(direntry);
Linus Torvalds's avatar
Linus Torvalds committed
2173
	if (full_path == NULL) {
2174
		rc = -ENOMEM;
2175
		free_xid(xid);
2176
		return rc;
Linus Torvalds's avatar
Linus Torvalds committed
2177 2178
	}

Jeff Layton's avatar
Jeff Layton committed
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190
	/*
	 * Attempt to flush data before changing attributes. We need to do
	 * this for ATTR_SIZE and ATTR_MTIME for sure, and if we change the
	 * ownership or mode then we may also need to do this. Here, we take
	 * the safe way out and just do the flush on all setattr requests. If
	 * the flush returns error, store it to report later and continue.
	 *
	 * BB: This should be smarter. Why bother flushing pages that
	 * will be truncated anyway? Also, should we error out here if
	 * the flush returns error?
	 */
	rc = filemap_write_and_wait(inode->i_mapping);
2191 2192
	mapping_set_error(inode->i_mapping, rc);
	rc = 0;
2193

2194
	if (attrs->ia_valid & ATTR_SIZE) {
2195 2196
		rc = cifs_set_file_size(inode, attrs, xid, full_path);
		if (rc != 0)
2197
			goto cifs_setattr_exit;
Linus Torvalds's avatar
Linus Torvalds committed
2198
	}
2199

2200 2201 2202 2203 2204 2205 2206 2207
	if (attrs->ia_valid & ATTR_UID)
		uid = attrs->ia_uid;

	if (attrs->ia_valid & ATTR_GID)
		gid = attrs->ia_gid;

#ifdef CONFIG_CIFS_ACL
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2208
		if (uid_valid(uid) || gid_valid(gid)) {
2209 2210 2211
			rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64,
							uid, gid);
			if (rc) {
2212 2213
				cifs_dbg(FYI, "%s: Setting id failed with error: %d\n",
					 __func__, rc);
2214 2215 2216 2217 2218
				goto cifs_setattr_exit;
			}
		}
	} else
#endif /* CONFIG_CIFS_ACL */
2219
	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID))
2220
		attrs->ia_valid &= ~(ATTR_UID | ATTR_GID);
Linus Torvalds's avatar
Linus Torvalds committed
2221

2222 2223 2224 2225
	/* skip mode change if it's just for clearing setuid/setgid */
	if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
		attrs->ia_valid &= ~ATTR_MODE;

Linus Torvalds's avatar
Linus Torvalds committed
2226 2227
	if (attrs->ia_valid & ATTR_MODE) {
		mode = attrs->ia_mode;
2228
		rc = 0;
Jeff Layton's avatar
Jeff Layton committed
2229
#ifdef CONFIG_CIFS_ACL
2230
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
2231
			rc = id_mode_to_cifs_acl(inode, full_path, mode,
2232
						INVALID_UID, INVALID_GID);
2233
			if (rc) {
2234 2235
				cifs_dbg(FYI, "%s: Setting ACL failed with error: %d\n",
					 __func__, rc);
2236 2237 2238
				goto cifs_setattr_exit;
			}
		} else
Jeff Layton's avatar
Jeff Layton committed
2239
#endif /* CONFIG_CIFS_ACL */
2240 2241
		if (((mode & S_IWUGO) == 0) &&
		    (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
2242 2243 2244

			dosattr = cifsInode->cifsAttrs | ATTR_READONLY;

2245 2246 2247 2248 2249
			/* fix up mode if we're not using dynperm */
			if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
				attrs->ia_mode = inode->i_mode & ~S_IWUGO;
		} else if ((mode & S_IWUGO) &&
			   (cifsInode->cifsAttrs & ATTR_READONLY)) {
2250 2251 2252 2253 2254

			dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY;
			/* Attributes of 0 are ignored */
			if (dosattr == 0)
				dosattr |= ATTR_NORMAL;
2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268

			/* reset local inode permissions to normal */
			if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
				attrs->ia_mode &= ~(S_IALLUGO);
				if (S_ISDIR(inode->i_mode))
					attrs->ia_mode |=
						cifs_sb->mnt_dir_mode;
				else
					attrs->ia_mode |=
						cifs_sb->mnt_file_mode;
			}
		} else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
			/* ignore mode change - ATTR_READONLY hasn't changed */
			attrs->ia_valid &= ~ATTR_MODE;
Linus Torvalds's avatar
Linus Torvalds committed
2269 2270 2271
		}
	}

2272 2273 2274 2275
	if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) ||
	    ((attrs->ia_valid & ATTR_MODE) && dosattr)) {
		rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr);
		/* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */
Linus Torvalds's avatar
Linus Torvalds committed
2276

2277 2278 2279 2280 2281
		/* Even if error on time set, no sense failing the call if
		the server would set the time to a reasonable value anyway,
		and this check ensures that we are not being called from
		sys_utimes in which case we ought to fail the call back to
		the user when the server rejects the call */
Steve French's avatar
Steve French committed
2282
		if ((rc) && (attrs->ia_valid &
2283
				(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
2284
			rc = 0;
Linus Torvalds's avatar
Linus Torvalds committed
2285 2286 2287 2288
	}

	/* do not need local check to inode_check_ok since the server does
	   that */
Christoph Hellwig's avatar
Christoph Hellwig committed
2289 2290 2291 2292
	if (rc)
		goto cifs_setattr_exit;

	if ((attrs->ia_valid & ATTR_SIZE) &&
Christoph Hellwig's avatar
Christoph Hellwig committed
2293 2294
	    attrs->ia_size != i_size_read(inode))
		truncate_setsize(inode, attrs->ia_size);
Christoph Hellwig's avatar
Christoph Hellwig committed
2295 2296 2297 2298

	setattr_copy(inode, attrs);
	mark_inode_dirty(inode);

2299
cifs_setattr_exit:
Linus Torvalds's avatar
Linus Torvalds committed
2300
	kfree(full_path);
2301
	free_xid(xid);
Linus Torvalds's avatar
Linus Torvalds committed
2302 2303 2304
	return rc;
}

2305 2306 2307 2308 2309
int
cifs_setattr(struct dentry *direntry, struct iattr *attrs)
{
	struct inode *inode = direntry->d_inode;
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
2310
	struct cifs_tcon *pTcon = cifs_sb_master_tcon(cifs_sb);
2311 2312 2313 2314 2315 2316 2317 2318 2319

	if (pTcon->unix_ext)
		return cifs_setattr_unix(direntry, attrs);

	return cifs_setattr_nounix(direntry, attrs);

	/* BB: add cifs_setattr_legacy for really old servers */
}

2320
#if 0
Linus Torvalds's avatar
Linus Torvalds committed
2321 2322
void cifs_delete_inode(struct inode *inode)
{
2323
	cifs_dbg(FYI, "In cifs_delete_inode, inode = 0x%p\n", inode);
Linus Torvalds's avatar
Linus Torvalds committed
2324 2325 2326
	/* may have to add back in if and when safe distributed caching of
	   directories added e.g. via FindNotify */
}
2327
#endif