/* * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid changed, then drop it and recreate it. */ 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); } /* * If we know that the inode will need to be revalidated immediately, * then don't create a new dentry for it. We'll end up doing an on * the wire call either way and this spares us an invalidation. */ if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) return NULL; 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; }
/* * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT * * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid changed, then drop it and recreate it. */ static void cifs_prime_dcache(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; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); cFYI(1, "%s: for %s", __func__, name->name); dentry = d_hash_and_lookup(parent, name); if (unlikely(IS_ERR(dentry))) return; if (dentry) { int err; inode = dentry->d_inode; if (inode) { /* * If we're generating inode numbers, then we don't * want to clobber the existing one with the one that * the readdir code created. */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) fattr->cf_uniqueid = CIFS_I(inode)->uniqueid; /* update inode in place if i_ino didn't change */ if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { cifs_fattr_to_inode(inode, fattr); goto out; } } err = d_invalidate(dentry); dput(dentry); if (err) return; } dentry = d_alloc(parent, name); if (!dentry) return; inode = cifs_iget(sb, fattr); if (!inode) goto out; alias = d_materialise_unique(dentry, inode); if (alias && !IS_ERR(alias)) dput(alias); out: dput(dentry); }
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; }
/* * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid changed, then drop it and recreate it. */ 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) { /* FIXME: check for inode number changes? */ if (dentry->d_inode != NULL) 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; }
/* * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid changed, then drop it and recreate it. */ 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)); dentry = d_lookup(parent, name); if (dentry) { /* FIXME: check for inode number changes? */ if (dentry->d_inode != NULL) 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; } if (CIFS_SB(sb)->tcon->nocase) dentry->d_op = &cifs_ci_dentry_ops; else dentry->d_op = &cifs_dentry_ops; alias = d_materialise_unique(dentry, inode); if (alias != NULL) { dput(dentry); if (IS_ERR(alias)) return NULL; dentry = alias; } return dentry; }
/* * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT * * Find the dentry that matches "name". If there isn't one, create one. If it's * a negative dentry or the uniqueid or filetype(mode) changed, * then drop it and recreate it. */ static void cifs_prime_dcache(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; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); cifs_dbg(FYI, "%s: for %s\n", __func__, name->name); dentry = d_hash_and_lookup(parent, name); if (unlikely(IS_ERR(dentry))) return; if (dentry) { inode = dentry->d_inode; if (inode) { /* * If we're generating inode numbers, then we don't * want to clobber the existing one with the one that * the readdir code created. */ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) fattr->cf_uniqueid = CIFS_I(inode)->uniqueid; /* update inode in place * if both i_ino and i_mode didn't change */ if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid && (inode->i_mode & S_IFMT) == (fattr->cf_mode & S_IFMT)) { cifs_fattr_to_inode(inode, fattr); goto out; } } d_invalidate(dentry); dput(dentry); } /* * If we know that the inode will need to be revalidated immediately, * then don't create a new dentry for it. We'll end up doing an on * the wire call either way and this spares us an invalidation. */ if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) return; dentry = d_alloc(parent, name); if (!dentry) return; inode = cifs_iget(sb, fattr); if (!inode) goto out; alias = d_splice_alias(inode, dentry); if (alias && !IS_ERR(alias)) dput(alias); out: dput(dentry); }
int cifs_posix_open(char *full_path, struct inode **pinode, struct super_block *sb, int mode, int oflags, __u32 *poplock, __u16 *pnetfid, int xid) { int rc; FILE_UNIX_BASIC_INFO *presp_data; __u32 posix_flags = 0; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifs_fattr fattr; cFYI(1, "posix open %s", full_path); presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); if (presp_data == NULL) return -ENOMEM; /* So far cifs posix extensions can only map the following flags. There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but so far we do not seem to need them, and we can treat them as local only */ if ((oflags & (FMODE_READ | FMODE_WRITE)) == (FMODE_READ | FMODE_WRITE)) posix_flags = SMB_O_RDWR; else if (oflags & FMODE_READ) posix_flags = SMB_O_RDONLY; else if (oflags & FMODE_WRITE) posix_flags = SMB_O_WRONLY; if (oflags & O_CREAT) posix_flags |= SMB_O_CREAT; if (oflags & O_EXCL) posix_flags |= SMB_O_EXCL; if (oflags & O_TRUNC) posix_flags |= SMB_O_TRUNC; /* be safe and imply O_SYNC for O_DSYNC */ if (oflags & O_DSYNC) posix_flags |= SMB_O_SYNC; if (oflags & O_DIRECTORY) posix_flags |= SMB_O_DIRECTORY; if (oflags & O_NOFOLLOW) posix_flags |= SMB_O_NOFOLLOW; if (oflags & O_DIRECT) posix_flags |= SMB_O_DIRECT; mode &= ~current_umask(); rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode, pnetfid, presp_data, poplock, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) goto posix_open_ret; if (presp_data->Type == cpu_to_le32(-1)) goto posix_open_ret; /* open ok, caller does qpathinfo */ if (!pinode) goto posix_open_ret; /* caller does not need info */ cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); /* get new inode and set it up */ if (*pinode == NULL) { cifs_fill_uniqueid(sb, &fattr); *pinode = cifs_iget(sb, &fattr); if (!*pinode) { rc = -ENOMEM; goto posix_open_ret; } } else { cifs_fattr_to_inode(*pinode, &fattr); } posix_open_ret: kfree(presp_data); return rc; }