Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
  cifs: fix parsing of hostname in dfs referrals
  cifs: display fsc in /proc/mounts
  cifs: enable fscache iff fsc mount option is used explicitly
  cifs: allow fsc mount option only if CONFIG_CIFS_FSCACHE is set
  cifs: Handle extended attribute name cifs_acl to generate cifs acl blob (try #4)
  cifs: Misc. cleanup in cifsacl handling [try #4]
  cifs: trivial comment fix for cifs_invalidate_mapping
  [CIFS] fs/cifs/Kconfig: CIFS depends on CRYPTO_HMAC
  cifs: don't take extra tlink reference in initiate_cifs_search
  cifs: Percolate error up to the caller during get/set acls [try #4]
  cifs: fix another memleak, in cifs_root_iget
  cifs: fix potential use-after-free in cifs_oplock_break_put
  • Loading branch information
Linus Torvalds committed Dec 2, 2010
2 parents fb82155 + ba03864 commit 8520eea
Show file tree
Hide file tree
Showing 11 changed files with 127 additions and 80 deletions.
8 changes: 8 additions & 0 deletions fs/cifs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ config CIFS
select NLS
select CRYPTO
select CRYPTO_MD5
select CRYPTO_HMAC
select CRYPTO_ARC4
help
This is the client VFS module for the Common Internet File System
Expand Down Expand Up @@ -143,6 +144,13 @@ config CIFS_FSCACHE
to be cached locally on disk through the general filesystem cache
manager. If unsure, say N.

config CIFS_ACL
bool "Provide CIFS ACL support (EXPERIMENTAL)"
depends on EXPERIMENTAL && CIFS_XATTR
help
Allows to fetch CIFS/NTFS ACL from the server. The DACL blob
is handed over to the application/caller.

config CIFS_EXPERIMENTAL
bool "CIFS Experimental Features (EXPERIMENTAL)"
depends on CIFS && EXPERIMENTAL
Expand Down
48 changes: 28 additions & 20 deletions fs/cifs/cifsacl.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,15 +560,17 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

if (IS_ERR(tlink))
return NULL;
return ERR_CAST(tlink);

xid = GetXid();
rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
FreeXid(xid);

cifs_put_tlink(tlink);

cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
if (rc)
return ERR_PTR(rc);
return pntsd;
}

Expand All @@ -583,31 +585,30 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

if (IS_ERR(tlink))
return NULL;
return ERR_CAST(tlink);

tcon = tlink_tcon(tlink);
xid = GetXid();

rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
&fid, &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
cERROR(1, "Unable to open file to get ACL");
goto out;
if (!rc) {
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
CIFSSMBClose(xid, tcon, fid);
}

rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);

CIFSSMBClose(xid, tcon, fid);
out:
cifs_put_tlink(tlink);
FreeXid(xid);

cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
if (rc)
return ERR_PTR(rc);
return pntsd;
}

/* Retrieve an ACL from the server */
static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
struct inode *inode, const char *path,
u32 *pacllen)
{
Expand Down Expand Up @@ -695,7 +696,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
}

/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
void
int
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
struct inode *inode, const char *path, const __u16 *pfid)
{
Expand All @@ -711,17 +712,21 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);

/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
if (pntsd)
if (IS_ERR(pntsd)) {
rc = PTR_ERR(pntsd);
cERROR(1, "%s: error %d getting sec desc", __func__, rc);
} else {
rc = parse_sec_desc(pntsd, acllen, fattr);
if (rc)
cFYI(1, "parse sec desc failed rc = %d", rc);
kfree(pntsd);
if (rc)
cERROR(1, "parse sec desc failed rc = %d", rc);
}

kfree(pntsd);
return;
return rc;
}

/* Convert mode bits to an ACL so we can update the ACL on the server */
int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
{
int rc = 0;
__u32 secdesclen = 0;
Expand All @@ -736,7 +741,10 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
/* Add three ACEs for owner, group, everyone getting rid of
other ACEs as chmod disables ACEs and set the security descriptor */

if (pntsd) {
if (IS_ERR(pntsd)) {
rc = PTR_ERR(pntsd);
cERROR(1, "%s: error %d getting sec desc", __func__, rc);
} else {
/* allocate memory for the smb header,
set security descriptor request security descriptor
parameters, and secuirty descriptor itself */
Expand Down
2 changes: 2 additions & 0 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
seq_printf(s, ",acl");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
seq_printf(s, ",mfsymlinks");
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
seq_printf(s, ",fsc");

seq_printf(s, ",rsize=%d", cifs_sb->rsize);
seq_printf(s, ",wsize=%d", cifs_sb->wsize);
Expand Down
6 changes: 4 additions & 2 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,12 @@ extern int cifs_get_file_info_unix(struct file *filp);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
struct super_block *sb, int xid);
extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct inode *inode,
const char *path, const __u16 *pfid);
extern int mode_to_acl(struct inode *inode, const char *path, __u64);
extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64);
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
const char *, u32 *);

extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
const char *);
Expand Down
5 changes: 5 additions & 0 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,11 @@ cifs_parse_mount_options(char *options, const char *devname,
"supported. Instead set "
"/proc/fs/cifs/LookupCacheEnabled to 0\n");
} else if (strnicmp(data, "fsc", 3) == 0) {
#ifndef CONFIG_CIFS_FSCACHE
cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE"
"kernel config option set");
return 1;
#endif
vol->fsc = true;
} else if (strnicmp(data, "mfsymlinks", 10) == 0) {
vol->mfsymlinks = true;
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/dns_resolve.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
/* Search for server name delimiter */
sep = memchr(hostname, '\\', len);
if (sep)
len = sep - unc;
len = sep - hostname;
else
cFYI(1, "%s: probably server name is whole unc: %s",
__func__, unc);
Expand Down
4 changes: 3 additions & 1 deletion fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -2271,8 +2271,10 @@ void cifs_oplock_break_get(struct cifsFileInfo *cfile)

void cifs_oplock_break_put(struct cifsFileInfo *cfile)
{
struct super_block *sb = cfile->dentry->d_sb;

cifsFileInfo_put(cfile);
cifs_sb_deactive(cfile->dentry->d_sb);
cifs_sb_deactive(sb);
}

const struct address_space_operations cifs_addr_ops = {
Expand Down
12 changes: 6 additions & 6 deletions fs/cifs/fscache.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* fs/cifs/fscache.c - CIFS filesystem cache interface
*
* Copyright (c) 2010 Novell, Inc.
* Author(s): Suresh Jayaraman (sjayaraman@suse.de>
* Author(s): Suresh Jayaraman <sjayaraman@suse.de>
*
* 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
Expand Down Expand Up @@ -67,10 +67,12 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode)
if (cifsi->fscache)
return;

cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
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,
cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache,
cifsi->fscache);
}
}

void cifs_fscache_release_inode_cookie(struct inode *inode)
Expand Down Expand Up @@ -101,10 +103,8 @@ void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
{
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
cifs_fscache_disable_inode_cookie(inode);
else {
else
cifs_fscache_enable_inode_cookie(inode);
cFYI(1, "CIFS: fscache inode cookie set");
}
}

void cifs_fscache_reset_inode_cookie(struct inode *inode)
Expand Down
36 changes: 24 additions & 12 deletions fs/cifs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -689,8 +689,13 @@ int cifs_get_inode_info(struct inode **pinode,
#ifdef CONFIG_CIFS_EXPERIMENTAL
/* fill in 0777 bits from ACL */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
cFYI(1, "Getting mode bits from ACL");
cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path,
pfid);
if (rc) {
cFYI(1, "%s: Getting ACL failed with error: %d",
__func__, rc);
goto cgii_exit;
}
}
#endif

Expand Down Expand Up @@ -881,8 +886,10 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
xid, NULL);

if (!inode)
return ERR_PTR(rc);
if (!inode) {
inode = ERR_PTR(rc);
goto out;
}

#ifdef CONFIG_CIFS_FSCACHE
/* populate tcon->resource_id */
Expand All @@ -898,13 +905,11 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
} else if (rc) {
kfree(full_path);
_FreeXid(xid);
iget_failed(inode);
return ERR_PTR(rc);
inode = ERR_PTR(rc);
}


out:
kfree(full_path);
/* can not call macro FreeXid here since in a void func
* TODO: This is no longer true
Expand Down Expand Up @@ -1670,7 +1675,9 @@ cifs_inode_needs_reval(struct inode *inode)
return false;
}

/* check invalid_mapping flag and zap the cache if it's set */
/*
* Zap the cache. Called when invalid_mapping flag is set.
*/
static void
cifs_invalidate_mapping(struct inode *inode)
{
Expand Down Expand Up @@ -2115,9 +2122,14 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_MODE) {
rc = 0;
#ifdef CONFIG_CIFS_EXPERIMENTAL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
rc = mode_to_acl(inode, full_path, mode);
else
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
rc = mode_to_cifs_acl(inode, full_path, mode);
if (rc) {
cFYI(1, "%s: Setting ACL failed with error: %d",
__func__, rc);
goto cifs_setattr_exit;
}
} else
#endif
if (((mode & S_IWUGO) == 0) &&
(cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
Expand Down
29 changes: 16 additions & 13 deletions fs/cifs/readdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,26 +226,29 @@ static int initiate_cifs_search(const int xid, struct file *file)
char *full_path = NULL;
struct cifsFileInfo *cifsFile;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
struct tcon_link *tlink;
struct tcon_link *tlink = NULL;
struct cifsTconInfo *pTcon;

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

if (file->private_data == NULL)
file->private_data =
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
if (file->private_data == NULL) {
rc = -ENOMEM;
goto error_exit;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);

cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
if (cifsFile == NULL) {
rc = -ENOMEM;
goto error_exit;
}
file->private_data = cifsFile;
cifsFile->tlink = cifs_get_tlink(tlink);
pTcon = tlink_tcon(tlink);
} else {
cifsFile = file->private_data;
pTcon = tlink_tcon(cifsFile->tlink);
}

cifsFile = file->private_data;
cifsFile->invalidHandle = true;
cifsFile->srch_inf.endOfSearch = false;
cifsFile->tlink = cifs_get_tlink(tlink);

full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL) {
Expand Down
Loading

0 comments on commit 8520eea

Please sign in to comment.