Beispiel #1
0
/*
 * mark the data attached to an inode as obsolete due to a write on the server
 * - might also want to ditch all the outstanding writes and dirty pages
 */
void afs_zap_data(struct afs_vnode *vnode)
{
	_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);

	/* nuke all the non-dirty pages that aren't locked, mapped or being
	 * written back in a regular file and completely discard the pages in a
	 * directory or symlink */
	if (S_ISREG(vnode->vfs_inode.i_mode))
		invalidate_remote_inode(&vnode->vfs_inode);
	else
		invalidate_inode_pages2(vnode->vfs_inode.i_mapping);
}
Beispiel #2
0
/*
 * This is called to update the inode attributes after
 * we've made changes to a file or directory.
 */
static int
smb_refresh_inode(struct dentry *dentry)
{
	struct inode *inode = dentry->d_inode;
	int error;
	struct smb_fattr fattr;

	error = smb_proc_getattr(dentry, &fattr);
	if (!error) {
		smb_renew_times(dentry);
		/*
		 * Check whether the type part of the mode changed,
		 * and don't update the attributes if it did.
		 *
		 * And don't dick with the root inode
		 */
		if (inode->i_ino == 2)
			return error;
		if (S_ISLNK(inode->i_mode))
			return error;	/* VFS will deal with it */

		if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
			smb_set_inode_attr(inode, &fattr);
		} else {
			/*
			 * Big trouble! The inode has become a new object,
			 * so any operations attempted on it are invalid.
			 *
			 * To limit damage, mark the inode as bad so that
			 * subsequent lookup validations will fail.
			 */
			PARANOIA("%s/%s changed mode, %07o to %07o\n",
				 DENTRY_PATH(dentry),
				 inode->i_mode, fattr.f_mode);

			fattr.f_mode = inode->i_mode; /* save mode */
			make_bad_inode(inode);
			inode->i_mode = fattr.f_mode; /* restore mode */
			/*
			 * No need to worry about unhashing the dentry: the
			 * lookup validation will see that the inode is bad.
			 * But we do want to invalidate the caches ...
			 */
			if (!S_ISDIR(inode->i_mode))
				invalidate_remote_inode(inode);
			else
				smb_invalid_dir_cache(inode);
			error = -EIO;
		}
	}
	return error;
}
Beispiel #3
0
/*
 * Update the inode, possibly causing it to invalidate its pages if mtime/size
 * is different from last time.
 */
void
smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
{
	struct smb_inode_info *ei = SMB_I(inode);

	/*
	 * A size change should have a different mtime, or same mtime
	 * but different size.
	 */
	time_t last_time = inode->i_mtime.tv_sec;
	loff_t last_sz = inode->i_size;

	inode->i_mode	= fattr->f_mode;
	inode->i_nlink	= fattr->f_nlink;
	inode->i_uid	= fattr->f_uid;
	inode->i_gid	= fattr->f_gid;
	inode->i_ctime	= fattr->f_ctime;
	inode->i_blksize= fattr->f_blksize;
	inode->i_blocks = fattr->f_blocks;
	inode->i_size	= fattr->f_size;
	inode->i_mtime	= fattr->f_mtime;
	inode->i_atime	= fattr->f_atime;
	ei->attr = fattr->attr;

	/*
	 * Update the "last time refreshed" field for revalidation.
	 */
	ei->oldmtime = jiffies;

	if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) {
		VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n",
			inode->i_ino,
			(long) last_time, (long) inode->i_mtime,
			(long) last_sz, (long) inode->i_size);

		if (!S_ISDIR(inode->i_mode))
			invalidate_remote_inode(inode);
	}
}
Beispiel #4
0
static void posix_fill_in_inode(struct inode *tmp_inode,
	FILE_UNIX_BASIC_INFO *pData, int isNewInode)
{
	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	loff_t local_size;
	struct timespec local_mtime;

	cifsInfo->time = jiffies;
	atomic_inc(&cifsInfo->inUse);

	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

	cifs_unix_info_to_inode(tmp_inode, pData, 0);
	cifs_set_ops(tmp_inode, false);

	if (!S_ISREG(tmp_inode->i_mode))
		return;

	/*
	 * No sense invalidating pages for new inode
	 * since we we have not started caching
	 * readahead file data yet.
	 */
	if (isNewInode)
		return;

	if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
		(local_size == tmp_inode->i_size)) {
		cFYI(1, ("inode exists but unchanged"));
	} else {
		/* file may have changed on server */
		cFYI(1, ("invalidate inode, readdir detected change"));
		invalidate_remote_inode(tmp_inode);
	}
}
static void unix_fill_in_inode(struct inode *tmp_inode,
	FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode)
{
	loff_t local_size;
	struct timespec local_mtime;

	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);

	__u32 type = le32_to_cpu(pfindData->Type);
	__u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes);
	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);
	cifsInfo->time = jiffies;
	atomic_inc(&cifsInfo->inUse);

	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

	tmp_inode->i_atime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
	tmp_inode->i_mtime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
	tmp_inode->i_ctime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));

	tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
	/* since we set the inode type below we need to mask off type
	   to avoid strange results if bits above were corrupt */
	tmp_inode->i_mode &= ~S_IFMT;
	if (type == UNIX_FILE) {
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
	} else if (type == UNIX_SYMLINK) {
		*pobject_type = DT_LNK;
		tmp_inode->i_mode |= S_IFLNK;
	} else if (type == UNIX_DIR) {
		*pobject_type = DT_DIR;
		tmp_inode->i_mode |= S_IFDIR;
	} else if (type == UNIX_CHARDEV) {
		*pobject_type = DT_CHR;
		tmp_inode->i_mode |= S_IFCHR;
		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
	} else if (type == UNIX_BLOCKDEV) {
		*pobject_type = DT_BLK;
		tmp_inode->i_mode |= S_IFBLK;
		tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
				le64_to_cpu(pfindData->DevMinor) & MINORMASK);
	} else if (type == UNIX_FIFO) {
		*pobject_type = DT_FIFO;
		tmp_inode->i_mode |= S_IFIFO;
	} else if (type == UNIX_SOCKET) {
		*pobject_type = DT_SOCK;
		tmp_inode->i_mode |= S_IFSOCK;
	} else {
		/* safest to just call it a file */
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
		cFYI(1, ("unknown inode type %d", type));
	}

	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
		tmp_inode->i_uid = cifs_sb->mnt_uid;
	else
		tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
		tmp_inode->i_gid = cifs_sb->mnt_gid;
	else
		tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
	tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);

	spin_lock(&tmp_inode->i_lock);
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
		/* can not safely change the file size here if the
		client is writing to it due to potential races */
		i_size_write(tmp_inode, end_of_file);

	/* 512 bytes (2**9) is the fake blocksize that must be used */
	/* for this calculation, not the real blocksize */
		tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
	}
	spin_unlock(&tmp_inode->i_lock);

	if (S_ISREG(tmp_inode->i_mode)) {
		cFYI(1, ("File inode"));
		tmp_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)
				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
			else
				tmp_inode->i_fop = &cifs_file_direct_ops;
		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
			tmp_inode->i_fop = &cifs_file_nobrl_ops;
		else
			tmp_inode->i_fop = &cifs_file_ops;

		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
		   (cifs_sb->tcon->ses->server->maxBuf <
			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
		else
			tmp_inode->i_data.a_ops = &cifs_addr_ops;

		if (isNewInode)
			return; /* No sense invalidating pages for new inode
				   since we have not started caching readahead
				   file data for it yet */

		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
			(local_size == tmp_inode->i_size)) {
			cFYI(1, ("inode exists but unchanged"));
		} else {
			/* file may have changed on server */
			cFYI(1, ("invalidate inode, readdir detected change"));
			invalidate_remote_inode(tmp_inode);
		}
	} else if (S_ISDIR(tmp_inode->i_mode)) {
		cFYI(1, ("Directory inode"));
		tmp_inode->i_op = &cifs_dir_inode_ops;
		tmp_inode->i_fop = &cifs_dir_ops;
	} else if (S_ISLNK(tmp_inode->i_mode)) {
		cFYI(1, ("Symbolic Link inode"));
		tmp_inode->i_op = &cifs_symlink_inode_ops;
/* tmp_inode->i_fop = *//* do not need to set to anything */
	} else {
		cFYI(1, ("Special inode"));
		init_special_inode(tmp_inode, tmp_inode->i_mode,
				   tmp_inode->i_rdev);
	}
}
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
			  char *buf, unsigned int *pobject_type, int isNewInode)
{
	loff_t local_size;
	struct timespec local_mtime;

	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
	__u32 attr;
	__u64 allocation_size;
	__u64 end_of_file;
	umode_t default_mode;

	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

	if (new_buf_type) {
		FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;

		attr = le32_to_cpu(pfindData->ExtFileAttributes);
		allocation_size = le64_to_cpu(pfindData->AllocationSize);
		end_of_file = le64_to_cpu(pfindData->EndOfFile);
		tmp_inode->i_atime =
		      cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
		tmp_inode->i_mtime =
		      cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
		tmp_inode->i_ctime =
		      cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
	} else { /* legacy, OS2 and DOS style */
/*		struct timespec ts;*/
		FIND_FILE_STANDARD_INFO *pfindData =
			(FIND_FILE_STANDARD_INFO *)buf;

		tmp_inode->i_mtime = cnvrtDosUnixTm(
				le16_to_cpu(pfindData->LastWriteDate),
				le16_to_cpu(pfindData->LastWriteTime));
		tmp_inode->i_atime = cnvrtDosUnixTm(
				le16_to_cpu(pfindData->LastAccessDate),
				le16_to_cpu(pfindData->LastAccessTime));
		tmp_inode->i_ctime = cnvrtDosUnixTm(
				le16_to_cpu(pfindData->LastWriteDate),
				le16_to_cpu(pfindData->LastWriteTime));
		AdjustForTZ(cifs_sb->tcon, tmp_inode);
		attr = le16_to_cpu(pfindData->Attributes);
		allocation_size = le32_to_cpu(pfindData->AllocationSize);
		end_of_file = le32_to_cpu(pfindData->DataSize);
	}

	/* Linux can not store file creation time unfortunately so ignore it */

	cifsInfo->cifsAttrs = attr;
#ifdef CONFIG_CIFS_EXPERIMENTAL
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
		/* get more accurate mode via ACL - so force inode refresh */
		cifsInfo->time = 0;
	} else
#endif /* CONFIG_CIFS_EXPERIMENTAL */
		cifsInfo->time = jiffies;

	/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
	/* 2767 perms - indicate mandatory locking */
		/* BB fill in uid and gid here? with help from winbind?
		   or retrieve from NTFS stream extended attribute */
	if (atomic_read(&cifsInfo->inUse) == 0) {
		tmp_inode->i_uid = cifs_sb->mnt_uid;
		tmp_inode->i_gid = cifs_sb->mnt_gid;
	}

	if (attr & ATTR_DIRECTORY)
		default_mode = cifs_sb->mnt_dir_mode;
	else
		default_mode = cifs_sb->mnt_file_mode;

	/* set initial permissions */
	if ((atomic_read(&cifsInfo->inUse) == 0) ||
	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
		tmp_inode->i_mode = default_mode;
	else {
		/* just reenable write bits if !ATTR_READONLY */
		if ((tmp_inode->i_mode & S_IWUGO) == 0 &&
		    (attr & ATTR_READONLY) == 0)
			tmp_inode->i_mode |= (S_IWUGO & default_mode);

		tmp_inode->i_mode &= ~S_IFMT;
	}

	/* clear write bits if ATTR_READONLY is set */
	if (attr & ATTR_READONLY)
		tmp_inode->i_mode &= ~S_IWUGO;

	/* set inode type */
	if ((attr & ATTR_SYSTEM) &&
	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) {
		if (end_of_file == 0)  {
			tmp_inode->i_mode |= S_IFIFO;
			*pobject_type = DT_FIFO;
		} else {
			/*
			 * trying to get the type can be slow, so just call
			 * this a regular file for now, and mark for reval
			 */
			tmp_inode->i_mode |= S_IFREG;
			*pobject_type = DT_REG;
			cifsInfo->time = 0;
		}
	} else {
		if (attr & ATTR_DIRECTORY) {
			tmp_inode->i_mode |= S_IFDIR;
			*pobject_type = DT_DIR;
		} else {
			tmp_inode->i_mode |= S_IFREG;
			*pobject_type = DT_REG;
		}
	}

	/* can not fill in nlink here as in qpathinfo version and Unx search */
	if (atomic_read(&cifsInfo->inUse) == 0)
		atomic_set(&cifsInfo->inUse, 1);

	spin_lock(&tmp_inode->i_lock);
	if (is_size_safe_to_change(cifsInfo, end_of_file)) {
		/* can not safely change the file size here if the
		client is writing to it due to potential races */
		i_size_write(tmp_inode, end_of_file);

	/* 512 bytes (2**9) is the fake blocksize that must be used */
	/* for this calculation, even though the reported blocksize is larger */
		tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
	}
	spin_unlock(&tmp_inode->i_lock);

	if (allocation_size < end_of_file)
		cFYI(1, ("May be sparse file, allocation less than file size"));
	cFYI(1, ("File Size %ld and blocks %llu",
		(unsigned long)tmp_inode->i_size,
		(unsigned long long)tmp_inode->i_blocks));
	if (S_ISREG(tmp_inode->i_mode)) {
		cFYI(1, ("File inode"));
		tmp_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)
				tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
			else
				tmp_inode->i_fop = &cifs_file_direct_ops;
		} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
			tmp_inode->i_fop = &cifs_file_nobrl_ops;
		else
			tmp_inode->i_fop = &cifs_file_ops;

		if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
		   (cifs_sb->tcon->ses->server->maxBuf <
			PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
			tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
		else
			tmp_inode->i_data.a_ops = &cifs_addr_ops;

		if (isNewInode)
			return; /* No sense invalidating pages for new inode
				   since have not started caching readahead file
				   data yet */

		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
			(local_size == tmp_inode->i_size)) {
			cFYI(1, ("inode exists but unchanged"));
		} else {
			/* file may have changed on server */
			cFYI(1, ("invalidate inode, readdir detected change"));
			invalidate_remote_inode(tmp_inode);
		}
	} else if (S_ISDIR(tmp_inode->i_mode)) {
		cFYI(1, ("Directory inode"));
		tmp_inode->i_op = &cifs_dir_inode_ops;
		tmp_inode->i_fop = &cifs_dir_ops;
	} else if (S_ISLNK(tmp_inode->i_mode)) {
		cFYI(1, ("Symbolic Link inode"));
		tmp_inode->i_op = &cifs_symlink_inode_ops;
	} else {
		cFYI(1, ("Init special inode"));
		init_special_inode(tmp_inode, tmp_inode->i_mode,
				   tmp_inode->i_rdev);
	}
}
Beispiel #7
0
/*
 * check that a dentry lookup hit has found a valid entry
 * - NOTE! the hit can be a negative hit too, so we can't assume we have an
 *   inode
 * (derived from nfs_lookup_revalidate)
 */
static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
	struct afs_dir_lookup_cookie cookie;
	struct dentry *parent;
	struct inode *inode, *dir;
	unsigned fpos;
	int ret;

	_enter("{sb=%p n=%s},", dentry->d_sb, dentry->d_name.name);

	/* lock down the parent dentry so we can peer at it */
	parent = dget_parent(dentry->d_parent);

	dir = parent->d_inode;
	inode = dentry->d_inode;

	/* handle a negative dentry */
	if (!inode)
		goto out_bad;

	/* handle a bad inode */
	if (is_bad_inode(inode)) {
		printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
		       dentry->d_parent->d_name.name, dentry->d_name.name);
		goto out_bad;
	}

	/* force a full look up if the parent directory changed since last the
	 * server was consulted
	 * - otherwise this inode must still exist, even if the inode details
	 *   themselves have changed
	 */
	if (AFS_FS_I(dir)->flags & AFS_VNODE_CHANGED)
		afs_vnode_fetch_status(AFS_FS_I(dir));

	if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) {
		_debug("%s: parent dir deleted", dentry->d_name.name);
		goto out_bad;
	}

	if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) {
		_debug("%s: file already deleted", dentry->d_name.name);
		goto out_bad;
	}

	if ((unsigned long) dentry->d_fsdata !=
	    (unsigned long) AFS_FS_I(dir)->status.version) {
		_debug("%s: parent changed %lu -> %u",
		       dentry->d_name.name,
		       (unsigned long) dentry->d_fsdata,
		       (unsigned) AFS_FS_I(dir)->status.version);

		/* search the directory for this vnode */
		cookie.name	= dentry->d_name.name;
		cookie.nlen	= dentry->d_name.len;
		cookie.fid.vid	= AFS_FS_I(inode)->volume->vid;
		cookie.found	= 0;

		fpos = 0;
		ret = afs_dir_iterate(dir, &fpos, &cookie,
				      afs_dir_lookup_filldir);
		if (ret < 0) {
			_debug("failed to iterate dir %s: %d",
			       parent->d_name.name, ret);
			goto out_bad;
		}

		if (!cookie.found) {
			_debug("%s: dirent not found", dentry->d_name.name);
			goto not_found;
		}

		/* if the vnode ID has changed, then the dirent points to a
		 * different file */
		if (cookie.fid.vnode != AFS_FS_I(inode)->fid.vnode) {
			_debug("%s: dirent changed", dentry->d_name.name);
			goto not_found;
		}

		/* if the vnode ID uniqifier has changed, then the file has
		 * been deleted */
		if (cookie.fid.unique != AFS_FS_I(inode)->fid.unique) {
			_debug("%s: file deleted (uq %u -> %u I:%lu)",
			       dentry->d_name.name,
			       cookie.fid.unique,
			       AFS_FS_I(inode)->fid.unique,
			       inode->i_version);
			spin_lock(&AFS_FS_I(inode)->lock);
			AFS_FS_I(inode)->flags |= AFS_VNODE_DELETED;
			spin_unlock(&AFS_FS_I(inode)->lock);
			invalidate_remote_inode(inode);
			goto out_bad;
		}

		dentry->d_fsdata =
			(void *) (unsigned long) AFS_FS_I(dir)->status.version;
	}

 out_valid:
	dput(parent);
	_leave(" = 1 [valid]");
	return 1;

	/* the dirent, if it exists, now points to a different vnode */
 not_found:
	spin_lock(&dentry->d_lock);
	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
	spin_unlock(&dentry->d_lock);

 out_bad:
	if (inode) {
		/* don't unhash if we have submounts */
		if (have_submounts(dentry))
			goto out_valid;
	}

	shrink_dcache_parent(dentry);

	_debug("dropping dentry %s/%s",
	       dentry->d_parent->d_name.name, dentry->d_name.name);
	d_drop(dentry);

	dput(parent);

	_leave(" = 0 [bad]");
	return 0;
} /* end afs_d_revalidate() */
Beispiel #8
0
static void fill_in_inode(struct inode *tmp_inode,
	FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode)
{
	loff_t local_size;
	struct timespec local_mtime;

	struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
	struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
	__u32 attr = le32_to_cpu(pfindData->ExtFileAttributes);
	__u64 allocation_size = le64_to_cpu(pfindData->AllocationSize);
	__u64 end_of_file = le64_to_cpu(pfindData->EndOfFile);

	cifsInfo->cifsAttrs = attr;
	cifsInfo->time = jiffies;

	/* save mtime and size */
	local_mtime = tmp_inode->i_mtime;
	local_size  = tmp_inode->i_size;

	/* Linux can not store file creation time unfortunately so ignore it */
	tmp_inode->i_atime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
	tmp_inode->i_mtime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
	tmp_inode->i_ctime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
	/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
	/* 2767 perms - indicate mandatory locking */
		/* BB fill in uid and gid here? with help from winbind? 
		   or retrieve from NTFS stream extended attribute */
	if (atomic_read(&cifsInfo->inUse) == 0) {
		tmp_inode->i_uid = cifs_sb->mnt_uid;
		tmp_inode->i_gid = cifs_sb->mnt_gid;
		/* set default mode. will override for dirs below */
		tmp_inode->i_mode = cifs_sb->mnt_file_mode;
	}

	if (attr & ATTR_DIRECTORY) {
		*pobject_type = DT_DIR;
		/* override default perms since we do not lock dirs */
		if(atomic_read(&cifsInfo->inUse) == 0) {
			tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
		}
		tmp_inode->i_mode |= S_IFDIR;
/* we no longer mark these because we could not follow them */
/*        } else if (attr & ATTR_REPARSE) {
                *pobject_type = DT_LNK;
                tmp_inode->i_mode |= S_IFLNK; */
	} else {
		*pobject_type = DT_REG;
		tmp_inode->i_mode |= S_IFREG;
		if (attr & ATTR_READONLY)
			tmp_inode->i_mode &= ~(S_IWUGO);
	} /* could add code here - to validate if device or weird share type? */

	/* can not fill in nlink here as in qpathinfo version and Unx search */
	if (atomic_read(&cifsInfo->inUse) == 0) {
		atomic_set(&cifsInfo->inUse, 1);
	}

	if (is_size_safe_to_change(cifsInfo)) {
		/* can not safely change the file size here if the 
		client is writing to it due to potential races */
		i_size_write(tmp_inode, end_of_file);

	/* 512 bytes (2**9) is the fake blocksize that must be used */
	/* for this calculation, even though the reported blocksize is larger */
		tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9;
	}

	if (allocation_size < end_of_file)
		cFYI(1, ("May be sparse file, allocation less than file size"));
	cFYI(1,
	     ("File Size %ld and blocks %ld and blocksize %ld",
	      (unsigned long)tmp_inode->i_size, tmp_inode->i_blocks,
	      tmp_inode->i_blksize));
	if (S_ISREG(tmp_inode->i_mode)) {
		cFYI(1, ("File inode"));
		tmp_inode->i_op = &cifs_file_inode_ops;
		if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
			tmp_inode->i_fop = &cifs_file_direct_ops;
		else
			tmp_inode->i_fop = &cifs_file_ops;
		tmp_inode->i_data.a_ops = &cifs_addr_ops;

		if(isNewInode)
			return; /* No sense invalidating pages for new inode since we
					   have not started caching readahead file data yet */

		if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
			(local_size == tmp_inode->i_size)) {
			cFYI(1, ("inode exists but unchanged"));
		} else {
			/* file may have changed on server */
			cFYI(1, ("invalidate inode, readdir detected change"));
			invalidate_remote_inode(tmp_inode);
		}
	} else if (S_ISDIR(tmp_inode->i_mode)) {
		cFYI(1, ("Directory inode"));
		tmp_inode->i_op = &cifs_dir_inode_ops;
		tmp_inode->i_fop = &cifs_dir_ops;
	} else if (S_ISLNK(tmp_inode->i_mode)) {
		cFYI(1, ("Symbolic Link inode"));
		tmp_inode->i_op = &cifs_symlink_inode_ops;
	} else {
		cFYI(1, ("Init special inode"));
		init_special_inode(tmp_inode, tmp_inode->i_mode,
				   tmp_inode->i_rdev);
	}
}
Beispiel #9
0
static int cifs_oplock_thread(void * dummyarg)
{
	struct oplock_q_entry * oplock_item;
	struct cifsTconInfo *pTcon;
	struct inode * inode;
	__u16  netfid;
	int rc;

	daemonize("cifsoplockd");
	allow_signal(SIGTERM);

	oplockThread = current;
	do {
		set_current_state(TASK_INTERRUPTIBLE);
		
		schedule_timeout(1*HZ);  
		spin_lock(&GlobalMid_Lock);
		if(list_empty(&GlobalOplock_Q)) {
			spin_unlock(&GlobalMid_Lock);
			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(39*HZ);
		} else {
			oplock_item = list_entry(GlobalOplock_Q.next, 
				struct oplock_q_entry, qhead);
			if(oplock_item) {
				cFYI(1,("found oplock item to write out")); 
				pTcon = oplock_item->tcon;
				inode = oplock_item->pinode;
				netfid = oplock_item->netfid;
				spin_unlock(&GlobalMid_Lock);
				DeleteOplockQEntry(oplock_item);
				/* can not grab inode sem here since it would
				deadlock when oplock received on delete 
				since vfs_unlink holds the i_sem across
				the call */
				/* down(&inode->i_sem);*/
				if (S_ISREG(inode->i_mode)) {
					rc = filemap_fdatawrite(inode->i_mapping);
					if(CIFS_I(inode)->clientCanCacheRead == 0) {
						filemap_fdatawait(inode->i_mapping);
						invalidate_remote_inode(inode);
					}
				} else
					rc = 0;
				/* up(&inode->i_sem);*/
				if (rc)
					CIFS_I(inode)->write_behind_rc = rc;
				cFYI(1,("Oplock flush inode %p rc %d",inode,rc));

				/* releasing a stale oplock after recent reconnection 
				of smb session using a now incorrect file 
				handle is not a data integrity issue but do  
				not bother sending an oplock release if session 
				to server still is disconnected since oplock 
				already released by the server in that case */
				if(pTcon->tidStatus != CifsNeedReconnect) {
				    rc = CIFSSMBLock(0, pTcon, netfid,
					    0 /* len */ , 0 /* offset */, 0, 
					    0, LOCKING_ANDX_OPLOCK_RELEASE,
					    0 /* wait flag */);
					cFYI(1,("Oplock release rc = %d ",rc));
				}
			} else
				spin_unlock(&GlobalMid_Lock);
		}
	} while(!signal_pending(current));
	complete_and_exit (&cifs_oplock_exited, 0);
	oplockThread = NULL;
}
Beispiel #10
0
static int cifs_oplock_thread(void *dummyarg)
{
	struct oplock_q_entry *oplock_item;
	struct cifsTconInfo *pTcon;
	struct inode *inode;
	__u16  netfid;
	int rc, waitrc = 0;

	set_freezable();
	do {
		if (try_to_freeze())
			continue;

		spin_lock(&GlobalMid_Lock);
		if (list_empty(&GlobalOplock_Q)) {
			spin_unlock(&GlobalMid_Lock);
			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(39*HZ);
		} else {
			oplock_item = list_entry(GlobalOplock_Q.next,
						struct oplock_q_entry, qhead);
			cFYI(1, ("found oplock item to write out"));
			pTcon = oplock_item->tcon;
			inode = oplock_item->pinode;
			netfid = oplock_item->netfid;
			spin_unlock(&GlobalMid_Lock);
			DeleteOplockQEntry(oplock_item);
			/* can not grab inode sem here since it would
				deadlock when oplock received on delete
				since vfs_unlink holds the i_mutex across
				the call */
			/* mutex_lock(&inode->i_mutex);*/
			if (S_ISREG(inode->i_mode)) {
#ifdef CONFIG_CIFS_EXPERIMENTAL
				if (CIFS_I(inode)->clientCanCacheAll == 0)
					break_lease(inode, FMODE_READ);
				else if (CIFS_I(inode)->clientCanCacheRead == 0)
					break_lease(inode, FMODE_WRITE);
#endif
				rc = filemap_fdatawrite(inode->i_mapping);
				if (CIFS_I(inode)->clientCanCacheRead == 0) {
					waitrc = filemap_fdatawait(
							      inode->i_mapping);
					invalidate_remote_inode(inode);
				}
				if (rc == 0)
					rc = waitrc;
			} else
				rc = 0;
			/* mutex_unlock(&inode->i_mutex);*/
			if (rc)
				CIFS_I(inode)->write_behind_rc = rc;
			cFYI(1, ("Oplock flush inode %p rc %d",
				inode, rc));

				/* releasing stale oplock after recent reconnect
				of smb session using a now incorrect file
				handle is not a data integrity issue but do
				not bother sending an oplock release if session
				to server still is disconnected since oplock
				already released by the server in that case */
			if (!pTcon->need_reconnect) {
				rc = CIFSSMBLock(0, pTcon, netfid,
						0 /* len */ , 0 /* offset */, 0,
						0, LOCKING_ANDX_OPLOCK_RELEASE,
						false /* wait flag */);
				cFYI(1, ("Oplock release rc = %d", rc));
			}
			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(1);  /* yield in case q were corrupt */
		}
	} while (!kthread_should_stop());

	return 0;
}
int
cifs_revalidate(struct dentry *direntry)
{
	int xid;
	int rc = 0;
	char *full_path;
	struct cifs_sb_info *cifs_sb;
	struct cifsInodeInfo *cifsInode;
	loff_t local_size;
	struct timespec local_mtime;
	int invalidate_inode = FALSE;

	if(direntry->d_inode == NULL)
		return -ENOENT;

	cifsInode = CIFS_I(direntry->d_inode);

	if(cifsInode == NULL)
		return -ENOENT;

	/* no sense revalidating inode info on file that no one can write */
	if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
		return rc;

	xid = GetXid();

	cifs_sb = CIFS_SB(direntry->d_sb);

	/* can not safely grab the rename sem here if
	rename calls revalidate since that would deadlock */
	full_path = build_path_from_dentry(direntry);
	if(full_path == NULL) {
		FreeXid(xid);
		return -ENOMEM;
	}
	cFYI(1,
	     ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
	      full_path, direntry->d_inode,
	      direntry->d_inode->i_count.counter, direntry,
	      direntry->d_time, jiffies));

	if (cifsInode->time == 0){
		/* was set to zero previously to force revalidate */
	} else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
	    if((S_ISREG(direntry->d_inode->i_mode) == 0) || 
			(direntry->d_inode->i_nlink == 1)) {  
			if (full_path)
				kfree(full_path);
			FreeXid(xid);
			return rc;
		} else {
			cFYI(1,("Have to revalidate file due to hardlinks"));
		}            
	}
	
	/* save mtime and size */
	local_mtime = direntry->d_inode->i_mtime;
	local_size  = direntry->d_inode->i_size;

	if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
		rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
					 direntry->d_sb,xid);
		if(rc) {
			cFYI(1,("error on getting revalidate info %d",rc));
/*			if(rc != -ENOENT)
				rc = 0; */ /* BB should we cache info on certain errors? */
		}
	} else {
		rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
				    direntry->d_sb,xid);
		if(rc) {
			cFYI(1,("error on getting revalidate info %d",rc));
/*			if(rc != -ENOENT)
				rc = 0; */  /* BB should we cache info on certain errors? */
		}
	}
	/* should we remap certain errors, access denied?, to zero */

	/* if not oplocked, we invalidate inode pages if mtime 
	   or file size had changed on server */

	if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
		(local_size == direntry->d_inode->i_size)) {
		cFYI(1,("cifs_revalidate - inode unchanged"));
	} else {
		/* file may have changed on server */
		if(cifsInode->clientCanCacheRead) {
			/* no need to invalidate inode pages since we were
			   the only ones who could have modified the file and
			   the server copy is staler than ours */
		} else {
			invalidate_inode = TRUE;
		}
	}

	/* can not grab this sem since kernel filesys locking
		documentation indicates i_sem may be taken by the kernel 
		on lookup and rename which could deadlock if we grab
		the i_sem here as well */
/*	down(&direntry->d_inode->i_sem);*/
	/* need to write out dirty pages here  */
	if(direntry->d_inode->i_mapping) {
		/* do we need to lock inode until after invalidate completes below? */
		filemap_fdatawrite(direntry->d_inode->i_mapping);
	}
	if(invalidate_inode) {
		filemap_fdatawait(direntry->d_inode->i_mapping);
		/* may eventually have to do this for open files too */
		if(list_empty(&(cifsInode->openFileList))) {
			/* Has changed on server - flush read ahead pages */
			cFYI(1,("Invalidating read ahead data on closed file"));
			invalidate_remote_inode(direntry->d_inode);
		}
	}
/*	up(&direntry->d_inode->i_sem);*/
	
	if (full_path)
		kfree(full_path);
	FreeXid(xid);

	return rc;
}