static void cifs_fscache_disable_inode_cookie(struct inode *inode) { struct cifsInodeInfo *cifsi = CIFS_I(inode); if (cifsi->fscache) { cFYI(1, "%s: (0x%p)", __func__, cifsi->fscache); fscache_uncache_all_inode_pages(cifsi->fscache, inode); fscache_relinquish_cookie(cifsi->fscache, 1); cifsi->fscache = NULL; } }
/* Check if directory that we are searching has changed so we can decide whether we can use the cached search results from the previous search */ static int is_dir_changed(struct file *file) { struct inode *inode = file->f_path.dentry->d_inode; struct cifsInodeInfo *cifsInfo = CIFS_I(inode); if (cifsInfo->time == 0) return 1; /* directory was changed, perhaps due to unlink */ else return 0; }
static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; ssize_t written; written = generic_file_aio_write(iocb, iov, nr_segs, pos); if (!CIFS_I(inode)->clientCanCacheAll) filemap_fdatawrite(inode->i_mapping); return written; }
/* * When called with struct file pointer set to NULL, there is no way we could * update file->private_data, but getting it stuck on openFileList provides a * way to access it from cifs_fill_filedata and thereby set file->private_data * from cifs_open. */ struct cifsFileInfo * cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, struct vfsmount *mnt, unsigned int oflags) { int oplock = 0; struct cifsFileInfo *pCifsFile; struct cifsInodeInfo *pCifsInode; struct cifs_sb_info *cifs_sb = CIFS_SB(mnt->mnt_sb); pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); if (pCifsFile == NULL) return pCifsFile; if (oplockEnabled) oplock = REQ_OPLOCK; pCifsFile->netfid = fileHandle; pCifsFile->pid = current->tgid; pCifsFile->pInode = igrab(newinode); pCifsFile->mnt = mnt; pCifsFile->pfile = file; pCifsFile->invalidHandle = false; pCifsFile->closePend = false; mutex_init(&pCifsFile->fh_mutex); mutex_init(&pCifsFile->lock_mutex); INIT_LIST_HEAD(&pCifsFile->llist); atomic_set(&pCifsFile->count, 1); slow_work_init(&pCifsFile->oplock_break, &cifs_oplock_break_ops); write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); pCifsInode = CIFS_I(newinode); if (pCifsInode) { /* if readable file instance put first in list*/ if (oflags & FMODE_READ) list_add(&pCifsFile->flist, &pCifsInode->openFileList); else list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList); if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { pCifsInode->clientCanCacheAll = true; pCifsInode->clientCanCacheRead = true; cFYI(1, "Exclusive Oplock inode %p", newinode); } else if ((oplock & 0xF) == OPLOCK_READ) pCifsInode->clientCanCacheRead = true; } write_unlock(&GlobalSMBSeslock); file->private_data = pCifsFile; return pCifsFile; }
/* Set an ACL on the server */ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, struct inode *inode, const char *path) { struct cifsFileInfo *open_file; bool unlock_file = false; int xid; int rc = -EIO; __u16 fid; struct super_block *sb; struct cifs_sb_info *cifs_sb; cFYI(DBG2, ("set ACL for %s from mode 0x%x", path, inode->i_mode)); if (!inode) return rc; sb = inode->i_sb; if (sb == NULL) return rc; cifs_sb = CIFS_SB(sb); xid = GetXid(); open_file = find_readable_file(CIFS_I(inode)); if (open_file) { unlock_file = true; fid = open_file->netfid; } else { int oplock = 0; /* open file */ rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0, &fid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc != 0) { cERROR(1, ("Unable to open file to set ACL")); FreeXid(xid); return rc; } } rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); cFYI(DBG2, ("SetCIFSACL rc = %d", rc)); if (unlock_file) atomic_dec(&open_file->wrtPending); else CIFSSMBClose(xid, cifs_sb->tcon, fid); FreeXid(xid); return rc; }
static int cifs_clone_file_range(struct file *src_file, loff_t off, struct file *dst_file, loff_t destoff, u64 len) { struct inode *src_inode = file_inode(src_file); struct inode *target_inode = file_inode(dst_file); struct cifsFileInfo *smb_file_src = src_file->private_data; struct cifsFileInfo *smb_file_target = dst_file->private_data; struct cifs_tcon *target_tcon = tlink_tcon(smb_file_target->tlink); unsigned int xid; int rc; cifs_dbg(FYI, "clone range\n"); xid = get_xid(); if (!src_file->private_data || !dst_file->private_data) { rc = -EBADF; cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); goto out; } /* * Note: cifs case is easier than btrfs since server responsible for * checks for proper open modes and file type and if it wants * server could even support copy of range where source = target */ lock_two_nondirectories(target_inode, src_inode); if (len == 0) len = src_inode->i_size - off; cifs_dbg(FYI, "about to flush pages\n"); /* should we flush first and last page first */ truncate_inode_pages_range(&target_inode->i_data, destoff, PAGE_ALIGN(destoff + len)-1); if (target_tcon->ses->server->ops->duplicate_extents) rc = target_tcon->ses->server->ops->duplicate_extents(xid, smb_file_src, smb_file_target, off, len, destoff); else rc = -EOPNOTSUPP; /* force revalidate of size and timestamps of target file now that target is updated on the server */ CIFS_I(target_inode)->time = 0; /* although unlocking in the reverse order from locking is not strictly necessary here it is a little cleaner to be consistent */ unlock_two_nondirectories(src_inode, target_inode); out: free_xid(xid); return rc; }
int cifs_fscache_release_page(struct page *page, gfp_t gfp) { if (PageFsCache(page)) { struct inode *inode = page->mapping->host; struct cifsInodeInfo *cifsi = CIFS_I(inode); cFYI(1, "CIFS: fscache release page (0x%p/0x%p)", page, cifsi->fscache); if (!fscache_maybe_release_page(cifsi->fscache, page, gfp)) return 0; } return 1; }
static ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct inode *inode = file_inode(iocb->ki_filp); struct cifsInodeInfo *cinode = CIFS_I(inode); ssize_t written; int rc; if (iocb->ki_filp->f_flags & O_DIRECT) { written = cifs_user_writev(iocb, from); if (written > 0 && CIFS_CACHE_READ(cinode)) { cifs_zap_mapping(inode); cifs_dbg(FYI, "Set no oplock for inode=%p after a write operation\n", inode); cinode->oplock = 0; } return written; } written = cifs_get_writer(cinode); if (written) return written; written = generic_file_write_iter(iocb, from); if (CIFS_CACHE_WRITE(CIFS_I(inode))) goto out; rc = filemap_fdatawrite(inode->i_mapping); if (rc) cifs_dbg(FYI, "cifs_file_write_iter: %d rc on %p inode\n", rc, inode); out: cifs_put_writer(cinode); return written; }
static void cifs_fill_fileinfo(struct inode *newinode, __u16 fileHandle, struct cifsTconInfo *tcon, bool write_only) { int oplock = 0; struct cifsFileInfo *pCifsFile; struct cifsInodeInfo *pCifsInode; pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); if (pCifsFile == NULL) return; if (oplockEnabled) oplock = REQ_OPLOCK; pCifsFile->netfid = fileHandle; pCifsFile->pid = current->tgid; pCifsFile->pInode = newinode; pCifsFile->invalidHandle = false; pCifsFile->closePend = false; mutex_init(&pCifsFile->fh_mutex); mutex_init(&pCifsFile->lock_mutex); INIT_LIST_HEAD(&pCifsFile->llist); atomic_set(&pCifsFile->wrtPending, 0); /* set the following in open now pCifsFile->pfile = file; */ write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist, &tcon->openFileList); pCifsInode = CIFS_I(newinode); if (pCifsInode) { /* if readable file instance put first in list*/ if (write_only) list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList); else list_add(&pCifsFile->flist, &pCifsInode->openFileList); if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { pCifsInode->clientCanCacheAll = true; pCifsInode->clientCanCacheRead = true; cFYI(1, ("Exclusive Oplock inode %p", newinode)); } else if ((oplock & 0xF) == OPLOCK_READ) pCifsInode->clientCanCacheRead = true; } write_unlock(&GlobalSMBSeslock); }
static struct dentry * cifs_readdir_lookup(struct dentry *parent, struct qstr *name, struct cifs_fattr *fattr) { struct dentry *dentry, *alias; struct inode *inode; struct super_block *sb = parent->d_inode->i_sb; cFYI(1, "For %s", name->name); if (parent->d_op && parent->d_op->d_hash) parent->d_op->d_hash(parent, parent->d_inode, name); else name->hash = full_name_hash(name->name, name->len); dentry = d_lookup(parent, name); if (dentry) { inode = dentry->d_inode; /* update inode in place if i_ino didn't change */ if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { cifs_fattr_to_inode(inode, fattr); return dentry; } d_drop(dentry); dput(dentry); } dentry = d_alloc(parent, name); if (dentry == NULL) return NULL; inode = cifs_iget(sb, fattr); if (!inode) { dput(dentry); return NULL; } alias = d_materialise_unique(dentry, inode); if (alias != NULL) { dput(dentry); if (IS_ERR(alias)) return NULL; dentry = alias; } return dentry; }
static void cifs_fscache_enable_inode_cookie(struct inode *inode) { struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); if (cifsi->fscache) return; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) { cifsi->fscache = fscache_acquire_cookie(tcon->fscache, &cifs_fscache_inode_object_def, cifsi); cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache, cifsi->fscache); } }
/* Retrieve an ACL from the server */ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, struct inode *inode, const char *path, u32 *pacllen) { struct cifs_ntsd *pntsd = NULL; struct cifsFileInfo *open_file = NULL; if (inode) open_file = find_readable_file(CIFS_I(inode)); if (!open_file) return get_cifs_acl_by_path(cifs_sb, path, pacllen); pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen); cifsFileInfo_put(open_file); return pntsd; }
/* Set an ACL on the server */ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, struct inode *inode, const char *path) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsFileInfo *open_file; int rc; cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode); open_file = find_readable_file(CIFS_I(inode)); if (!open_file) return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen); cifsFileInfo_put(open_file); return rc; }
static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) { /* origin == SEEK_END => we must revalidate the cached file length */ if (origin == SEEK_END) { int retval; /* some applications poll for the file length in this strange way so we must seek to end on non-oplocked files by setting the revalidate time to zero */ CIFS_I(file->f_path.dentry->d_inode)->time = 0; retval = cifs_revalidate_file(file); if (retval < 0) return (loff_t)retval; } return generic_file_llseek_unlocked(file, offset, origin); }
void cifs_fscache_reset_inode_cookie(struct inode *inode) { struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct fscache_cookie *old = cifsi->fscache; if (cifsi->fscache) { /* retire the current fscache cache and get a new one */ fscache_relinquish_cookie(cifsi->fscache, 1); cifsi->fscache = fscache_acquire_cookie( cifs_sb_master_tcon(cifs_sb)->fscache, &cifs_fscache_inode_object_def, cifsi); cFYI(1, "CIFS: new cookie 0x%p oldcookie 0x%p", cifsi->fscache, old); } }
static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { struct inode *inode = file_inode(iocb->ki_filp); ssize_t written; int rc; written = generic_file_aio_write(iocb, iov, nr_segs, pos); if (CIFS_I(inode)->clientCanCacheAll) return written; rc = filemap_fdatawrite(inode->i_mapping); if (rc) cFYI(1, "cifs_file_aio_write: %d rc on %p inode", rc, inode); return written; }
int cifs_rmdir(struct inode *inode, struct dentry *direntry) { int rc = 0; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct cifsInodeInfo *cifsInode; cFYI(1, ("cifs_rmdir, inode = 0x%p", inode)); xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; full_path = build_path_from_dentry(direntry); if (full_path == NULL) { FreeXid(xid); return -ENOMEM; } rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { drop_nlink(inode); spin_lock(&direntry->d_inode->i_lock); i_size_write(direntry->d_inode, 0); clear_nlink(direntry->d_inode); spin_unlock(&direntry->d_inode->i_lock); } cifsInode = CIFS_I(direntry->d_inode); cifsInode->time = 0; /* force revalidate to go get info when needed */ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); kfree(full_path); FreeXid(xid); return rc; }
static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { struct inode *inode = file_inode(iocb->ki_filp); ssize_t written; int rc; written = generic_file_aio_write(iocb, iov, nr_segs, pos); if (CIFS_CACHE_WRITE(CIFS_I(inode))) return written; rc = filemap_fdatawrite(inode->i_mapping); if (rc) cifs_dbg(FYI, "cifs_file_aio_write: %d rc on %p inode\n", rc, inode); return written; }
int cifs_rmdir(struct inode *inode, struct dentry *direntry) { int rc = 0; int xid; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; struct cifsInodeInfo *cifsInode; cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode)); xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; down(&inode->i_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&inode->i_sb->s_vfs_rename_sem); if(full_path == NULL) { FreeXid(xid); return -ENOMEM; } rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls); if (!rc) { inode->i_nlink--; i_size_write(direntry->d_inode,0); direntry->d_inode->i_nlink = 0; } cifsInode = CIFS_I(direntry->d_inode); cifsInode->time = 0; /* force revalidate to go get info when needed */ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; if (full_path) kfree(full_path); FreeXid(xid); return rc; }
static ssize_t cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size, loff_t * poffset) { if(file == NULL) return -EIO; else if(file->f_dentry == NULL) return -EIO; else if(file->f_dentry->d_inode == NULL) return -EIO; cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset)); #ifdef CONFIG_CIFS_EXPERIMENTAL /* check whether we can cache writes locally */ if(file->f_dentry->d_sb) { struct cifs_sb_info *cifs_sb; cifs_sb = CIFS_SB(file->f_dentry->d_sb); if(cifs_sb != NULL) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) return cifs_user_read(file,read_data, read_size,poffset); } } #endif /* CIFS_EXPERIMENTAL */ if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { return generic_file_read(file,read_data,read_size,poffset); } else { /* BB do we need to lock inode from here until after invalidate? */ /* if(file->f_dentry->d_inode->i_mapping) { filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); filemap_fdatawait(file->f_dentry->d_inode->i_mapping); }*/ /* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ /* BB we should make timer configurable - perhaps by simply calling cifs_revalidate here */ /* invalidate_remote_inode(file->f_dentry->d_inode);*/ return generic_file_read(file,read_data,read_size,poffset); } }
static int cifs_creation_time_get(struct dentry *dentry, struct inode *inode, void *value, size_t size) { ssize_t rc; __u64 * pcreatetime; rc = cifs_revalidate_dentry_attr(dentry); if (rc) return rc; if ((value == NULL) || (size == 0)) return sizeof(__u64); else if (size < sizeof(__u64)) return -ERANGE; /* return dos attributes as pseudo xattr */ pcreatetime = (__u64 *)value; *pcreatetime = CIFS_I(inode)->createtime; return sizeof(__u64); }
void smb2_mkdir_setinfo(struct inode *inode, const char *name, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, const unsigned int xid) { FILE_BASIC_INFO data; struct cifsInodeInfo *cifs_i; u32 dosattrs; int tmprc; memset(&data, 0, sizeof(data)); cifs_i = CIFS_I(inode); dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; data.Attributes = cpu_to_le32(dosattrs); tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name, FILE_WRITE_ATTRIBUTES, FILE_CREATE, CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO); if (tmprc == 0) cifs_i->cifsAttrs = dosattrs; }
static ssize_t cifs_write_wrapper(struct file * file, const char __user *write_data, size_t write_size, loff_t * poffset) { ssize_t written; if(file->f_dentry == NULL) return -EIO; else if(file->f_dentry->d_inode == NULL) return -EIO; cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); written = generic_file_write(file,write_data,write_size,poffset); if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { if(file->f_dentry->d_inode->i_mapping) { filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); } } return written; }
static int cifs_attrib_get(struct dentry *dentry, struct inode *inode, void *value, size_t size) { ssize_t rc; __u32 *pattribute; rc = cifs_revalidate_dentry_attr(dentry); if (rc) return rc; if ((value == NULL) || (size == 0)) return sizeof(__u32); else if (size < sizeof(__u32)) return -ERANGE; /* return dos attributes as pseudo xattr */ pattribute = (__u32 *)value; *pattribute = CIFS_I(inode)->cifsAttrs; return sizeof(__u32); }
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 ssize_t cifs_write_wrapper(struct file * file, const char __user *write_data, size_t write_size, loff_t * poffset) { ssize_t written; if(file == NULL) return -EIO; else if(file->f_dentry == NULL) return -EIO; else if(file->f_dentry->d_inode == NULL) return -EIO; cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); #ifdef CONFIG_CIFS_EXPERIMENTAL /* BB fixme - fix user char * to kernel char * mapping here BB */ /* check whether we can cache writes locally */ if(file->f_dentry->d_sb) { struct cifs_sb_info *cifs_sb; cifs_sb = CIFS_SB(file->f_dentry->d_sb); if(cifs_sb != NULL) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { return cifs_user_write(file,write_data, write_size,poffset); } } } #endif /* CIFS_EXPERIMENTAL */ written = generic_file_write(file,write_data,write_size,poffset); if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { if(file->f_dentry->d_inode->i_mapping) { filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); } } return written; }
int cifs_hardlink(struct dentry *old_file, struct inode *inode, struct dentry *direntry) { int rc = -EACCES; int xid; char *fromName = NULL; char *toName = NULL; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct tcon_link *tlink; struct cifsTconInfo *pTcon; struct cifsInodeInfo *cifsInode; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) return PTR_ERR(tlink); pTcon = tlink_tcon(tlink); xid = GetXid(); fromName = build_path_from_dentry(old_file); toName = build_path_from_dentry(direntry); if ((fromName == NULL) || (toName == NULL)) { rc = -ENOMEM; goto cifs_hl_exit; } if (pTcon->unix_ext) rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else { rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if ((rc == -EIO) || (rc == -EINVAL)) rc = -EOPNOTSUPP; } d_drop(direntry); /* force new lookup from server of target */ /* if source file is cached (oplocked) revalidate will not go to server until the file is closed or oplock broken so update nlinks locally */ if (old_file->d_inode) { cifsInode = CIFS_I(old_file->d_inode); if (rc == 0) { old_file->d_inode->i_nlink++; /* BB should we make this contingent on superblock flag NOATIME? */ /* old_file->d_inode->i_ctime = CURRENT_TIME;*/ /* parent dir timestamps will update from srv within a second, would it really be worth it to set the parent dir cifs inode time to zero to force revalidate (faster) for it too? */ } /* if not oplocked will force revalidate to get info on source file from srv */ cifsInode->time = 0; /* Will update parent dir timestamps from srv within a second. Would it really be worth it to set the parent dir (cifs inode) time field to zero to force revalidate on parent directory faster ie CIFS_I(inode)->time = 0; */ } cifs_hl_exit: kfree(fromName); kfree(toName); FreeXid(xid); cifs_put_tlink(tlink); return rc; }
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 cifs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); }
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); } }