aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-04-03 14:33:42 -0700
committerDavid S. Miller <davem@davemloft.net>2008-04-03 14:33:42 -0700
commit3bb5da3837cc1aa17736b05139c9a22c3794851a (patch)
treec92d5684a866542b1cb20641607ac1643ce03a47 /fs
parent7feb49c82a74bc7c091b8ab2a3f96baa33d08ece (diff)
parent9597362d354f8655ece324b01d0c640a0e99c077 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/cell.c16
-rw-r--r--fs/afs/internal.h1
-rw-r--r--fs/afs/mntpt.c8
-rw-r--r--fs/afs/super.c1
-rw-r--r--fs/aio.c8
-rw-r--r--fs/anon_inodes.c18
-rw-r--r--fs/bio.c2
-rw-r--r--fs/buffer.c17
-rw-r--r--fs/cifs/cifs_dfs_ref.c19
-rw-r--r--fs/cifs/cifsacl.c29
-rw-r--r--fs/cifs/cifsproto.h9
-rw-r--r--fs/cifs/dir.c5
-rw-r--r--fs/cifs/dns_resolve.c8
-rw-r--r--fs/cifs/file.c4
-rw-r--r--fs/cifs/inode.c161
-rw-r--r--fs/cifs/link.c2
-rw-r--r--fs/dquot.c2
-rw-r--r--fs/ecryptfs/dentry.c2
-rw-r--r--fs/efs/inode.c2
-rw-r--r--fs/ext3/acl.c8
-rw-r--r--fs/ext3/resize.c4
-rw-r--r--fs/ext3/xattr.c4
-rw-r--r--fs/file_table.c6
-rw-r--r--fs/fs-writeback.c6
-rw-r--r--fs/hppfs/hppfs_kern.c435
-rw-r--r--fs/hugetlbfs/inode.c2
-rw-r--r--fs/isofs/compress.c11
-rw-r--r--fs/jbd/journal.c9
-rw-r--r--fs/jbd/recovery.c2
-rw-r--r--fs/jbd/revoke.c4
-rw-r--r--fs/jbd/transaction.c8
-rw-r--r--fs/jbd2/journal.c12
-rw-r--r--fs/jbd2/recovery.c2
-rw-r--r--fs/jbd2/revoke.c4
-rw-r--r--fs/locks.c4
-rw-r--r--fs/namei.c69
-rw-r--r--fs/namespace.c200
-rw-r--r--fs/nfs/read.c5
-rw-r--r--fs/nfs/super.c2
-rw-r--r--fs/nfs/write.c8
-rw-r--r--fs/open.c12
-rw-r--r--fs/pipe.c19
-rw-r--r--fs/pnode.c2
-rw-r--r--fs/proc/base.c22
-rw-r--r--fs/proc/task_mmu.c50
-rw-r--r--fs/reiserfs/do_balan.c8
-rw-r--r--fs/reiserfs/fix_node.c8
-rw-r--r--fs/reiserfs/lbalance.c2
-rw-r--r--fs/reiserfs/namei.c2
-rw-r--r--fs/reiserfs/xattr.c110
-rw-r--r--fs/romfs/inode.c30
-rw-r--r--fs/smbfs/smbiod.c2
-rw-r--r--fs/super.c7
-rw-r--r--fs/sysfs/file.c8
-rw-r--r--fs/ufs/balloc.c4
55 files changed, 687 insertions, 718 deletions
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 970d38f3056..584bb0f9c36 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -127,14 +127,21 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist)
_enter("%s,%s", name, vllist);
+ down_write(&afs_cells_sem);
+ read_lock(&afs_cells_lock);
+ list_for_each_entry(cell, &afs_cells, link) {
+ if (strcasecmp(cell->name, name) == 0)
+ goto duplicate_name;
+ }
+ read_unlock(&afs_cells_lock);
+
cell = afs_cell_alloc(name, vllist);
if (IS_ERR(cell)) {
_leave(" = %ld", PTR_ERR(cell));
+ up_write(&afs_cells_sem);
return cell;
}
- down_write(&afs_cells_sem);
-
/* add a proc directory for this cell */
ret = afs_proc_cell_setup(cell);
if (ret < 0)
@@ -167,6 +174,11 @@ error:
kfree(cell);
_leave(" = %d", ret);
return ERR_PTR(ret);
+
+duplicate_name:
+ read_unlock(&afs_cells_lock);
+ up_write(&afs_cells_sem);
+ return ERR_PTR(-EEXIST);
}
/*
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 5ca3625cd39..9ba16edc0af 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -573,7 +573,6 @@ extern const struct file_operations afs_mntpt_file_operations;
extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
extern void afs_mntpt_kill_timer(void);
-extern void afs_umount_begin(struct vfsmount *, int);
/*
* proc.c
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index a3510b8ba3e..2f5503902c3 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -283,11 +283,3 @@ void afs_mntpt_kill_timer(void)
cancel_delayed_work(&afs_mntpt_expiry_timer);
flush_scheduled_work();
}
-
-/*
- * begin unmount by attempting to remove all automounted mountpoints we added
- */
-void afs_umount_begin(struct vfsmount *vfsmnt, int flags)
-{
- shrink_submounts(vfsmnt, &afs_vfsmounts);
-}
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 36bbce45f44..4b572b801d8 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -50,7 +50,6 @@ static const struct super_operations afs_super_ops = {
.write_inode = afs_write_inode,
.destroy_inode = afs_destroy_inode,
.clear_inode = afs_clear_inode,
- .umount_begin = afs_umount_begin,
.put_super = afs_put_super,
.show_options = generic_show_options,
};
diff --git a/fs/aio.c b/fs/aio.c
index b74c567383b..6af92194062 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -996,6 +996,14 @@ put_rq:
/* everything turned out well, dispose of the aiocb. */
ret = __aio_put_req(ctx, iocb);
+ /*
+ * We have to order our ring_info tail store above and test
+ * of the wait list below outside the wait lock. This is
+ * like in wake_up_bit() where clearing a bit has to be
+ * ordered with the unlocked test.
+ */
+ smp_mb();
+
if (waitqueue_active(&ctx->wait))
wake_up(&ctx->wait);
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 23321889d9b..f42be069e08 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -81,13 +81,10 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
if (IS_ERR(anon_inode_inode))
return -ENODEV;
- file = get_empty_filp();
- if (!file)
- return -ENFILE;
error = get_unused_fd();
if (error < 0)
- goto err_put_filp;
+ return error;
fd = error;
/*
@@ -114,14 +111,15 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
dentry->d_flags &= ~DCACHE_UNHASHED;
d_instantiate(dentry, anon_inode_inode);
- file->f_path.mnt = mntget(anon_inode_mnt);
- file->f_path.dentry = dentry;
+ error = -ENFILE;
+ file = alloc_file(anon_inode_mnt, dentry,
+ FMODE_READ | FMODE_WRITE, fops);
+ if (!file)
+ goto err_dput;
file->f_mapping = anon_inode_inode->i_mapping;
file->f_pos = 0;
file->f_flags = O_RDWR;
- file->f_op = fops;
- file->f_mode = FMODE_READ | FMODE_WRITE;
file->f_version = 0;
file->private_data = priv;
@@ -132,10 +130,10 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
*pfile = file;
return 0;
+err_dput:
+ dput(dentry);
err_put_unused_fd:
put_unused_fd(fd);
-err_put_filp:
- put_filp(file);
return error;
}
EXPORT_SYMBOL_GPL(anon_inode_getfd);
diff --git a/fs/bio.c b/fs/bio.c
index 3312fcc3c09..553b5b7960a 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1194,6 +1194,8 @@ EXPORT_SYMBOL(bio_hw_segments);
EXPORT_SYMBOL(bio_add_page);
EXPORT_SYMBOL(bio_add_pc_page);
EXPORT_SYMBOL(bio_get_nr_vecs);
+EXPORT_SYMBOL(bio_map_user);
+EXPORT_SYMBOL(bio_unmap_user);
EXPORT_SYMBOL(bio_map_kern);
EXPORT_SYMBOL(bio_pair_release);
EXPORT_SYMBOL(bio_split);
diff --git a/fs/buffer.c b/fs/buffer.c
index ddfdd2c80bf..98196327ddf 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2564,14 +2564,13 @@ int nobh_write_end(struct file *file, struct address_space *mapping,
struct inode *inode = page->mapping->host;
struct buffer_head *head = fsdata;
struct buffer_head *bh;
+ BUG_ON(fsdata != NULL && page_has_buffers(page));
- if (!PageMappedToDisk(page)) {
- if (unlikely(copied < len) && !page_has_buffers(page))
- attach_nobh_buffers(page, head);
- if (page_has_buffers(page))
- return generic_write_end(file, mapping, pos, len,
- copied, page, fsdata);
- }
+ if (unlikely(copied < len) && !page_has_buffers(page))
+ attach_nobh_buffers(page, head);
+ if (page_has_buffers(page))
+ return generic_write_end(file, mapping, pos, len,
+ copied, page, fsdata);
SetPageUptodate(page);
set_page_dirty(page);
@@ -3213,7 +3212,7 @@ static int buffer_cpu_notify(struct notifier_block *self,
}
/**
- * bh_uptodate_or_lock: Test whether the buffer is uptodate
+ * bh_uptodate_or_lock - Test whether the buffer is uptodate
* @bh: struct buffer_head
*
* Return true if the buffer is up-to-date and false,
@@ -3232,7 +3231,7 @@ int bh_uptodate_or_lock(struct buffer_head *bh)
EXPORT_SYMBOL(bh_uptodate_or_lock);
/**
- * bh_submit_read: Submit a locked buffer for reading
+ * bh_submit_read - Submit a locked buffer for reading
* @bh: struct buffer_head
*
* Returns zero on success and -EIO on error.
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index 7f883825341..56c924033b7 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -33,7 +33,6 @@ void dfs_shrink_umount_helper(struct vfsmount *vfsmnt)
{
mark_mounts_for_expiry(&cifs_dfs_automount_list);
mark_mounts_for_expiry(&cifs_dfs_automount_list);
- shrink_submounts(vfsmnt, &cifs_dfs_automount_list);
}
/**
@@ -74,7 +73,7 @@ static char *cifs_get_share_name(const char *node_name)
pSep = memchr(UNC+2, '\\', len-2);
if (!pSep) {
cERROR(1, ("%s: no server name end in node name: %s",
- __FUNCTION__, node_name));
+ __func__, node_name));
kfree(UNC);
return NULL;
}
@@ -84,7 +83,7 @@ static char *cifs_get_share_name(const char *node_name)
pSep = memchr(UNC+(pSep-UNC), '\\', len-(pSep-UNC));
if (!pSep) {
cERROR(1, ("%s:2 cant find share name in node name: %s",
- __FUNCTION__, node_name));
+ __func__, node_name));
kfree(UNC);
return NULL;
}
@@ -127,7 +126,7 @@ static char *compose_mount_options(const char *sb_mountdata,
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
if (rc != 0) {
cERROR(1, ("%s: Failed to resolve server part of %s to IP",
- __FUNCTION__, *devname));
+ __func__, *devname));
mountdata = ERR_PTR(rc);
goto compose_mount_options_out;
}
@@ -181,8 +180,8 @@ static char *compose_mount_options(const char *sb_mountdata,
}
}
- /*cFYI(1,("%s: parent mountdata: %s", __FUNCTION__,sb_mountdata));*/
- /*cFYI(1, ("%s: submount mountdata: %s", __FUNCTION__, mountdata ));*/
+ /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
+ /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/
compose_mount_options_out:
kfree(srvIP);
@@ -302,7 +301,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
int rc = 0;
struct vfsmount *mnt = ERR_PTR(-ENOENT);
- cFYI(1, ("in %s", __FUNCTION__));
+ cFYI(1, ("in %s", __func__));
BUG_ON(IS_ROOT(dentry));
xid = GetXid();
@@ -336,7 +335,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
len = strlen(referrals[i].node_name);
if (len < 2) {
cERROR(1, ("%s: Net Address path too short: %s",
- __FUNCTION__, referrals[i].node_name));
+ __func__, referrals[i].node_name));
rc = -EINVAL;
goto out_err;
}
@@ -344,7 +343,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
nd->path.dentry,
referrals[i].node_name);
cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p",
- __FUNCTION__,
+ __func__,
referrals[i].node_name, mnt));
/* complete mount procedure if we accured submount */
@@ -365,7 +364,7 @@ out:
FreeXid(xid);
free_dfs_info_array(referrals, num_referrals);
kfree(full_path);
- cFYI(1, ("leaving %s" , __FUNCTION__));
+ cFYI(1, ("leaving %s" , __func__));
return ERR_PTR(rc);
out_err:
path_put(&nd->path);
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index f93932c2177..1cb5b0a9f2a 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsacl.c
*
- * Copyright (C) International Business Machines Corp., 2007
+ * Copyright (C) International Business Machines Corp., 2007,2008
* Author(s): Steve French (sfrench@us.ibm.com)
*
* Contains the routines for mapping CIFS/NTFS ACLs
@@ -261,7 +261,7 @@ static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
return;
}
-static __le16 fill_ace_for_sid(struct cifs_ace *pntace,
+static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
const struct cifs_sid *psid, __u64 nmode, umode_t bits)
{
int i;
@@ -411,7 +411,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
struct cifs_sid *pgrpsid, __u64 nmode)
{
- __le16 size = 0;
+ u16 size = 0;
struct cifs_acl *pnndacl;
pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
@@ -556,9 +556,9 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
/* Retrieve an ACL from the server */
static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
- const char *path)
+ const char *path, const __u16 *pfid)
{
- struct cifsFileInfo *open_file;
+ struct cifsFileInfo *open_file = NULL;
int unlock_file = FALSE;
int xid;
int rc = -EIO;
@@ -573,7 +573,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
return NULL;
xid = GetXid();
- open_file = find_readable_file(CIFS_I(inode));
+ if (pfid == NULL)
+ open_file = find_readable_file(CIFS_I(inode));
+ else
+ fid = *pfid;
+
sb = inode->i_sb;
if (sb == NULL) {
FreeXid(xid);
@@ -584,7 +588,7 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
if (open_file) {
unlock_file = TRUE;
fid = open_file->netfid;
- } else {
+ } else if (pfid == NULL) {
int oplock = FALSE;
/* open file */
rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
@@ -600,10 +604,11 @@ static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
- if (unlock_file == TRUE)
+ if (unlock_file == TRUE) /* find_readable_file increments ref count */
atomic_dec(&open_file->wrtPending);
- else
+ else if (pfid == NULL) /* if opened above we have to close the handle */
CIFSSMBClose(xid, cifs_sb->tcon, fid);
+ /* else handle was passed in by caller */
FreeXid(xid);
return pntsd;
@@ -664,14 +669,14 @@ 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 acl_to_uid_mode(struct inode *inode, const char *path)
+void acl_to_uid_mode(struct inode *inode, const char *path, const __u16 *pfid)
{
struct cifs_ntsd *pntsd = NULL;
u32 acllen = 0;
int rc = 0;
cFYI(DBG2, ("converting ACL to mode for %s", path));
- pntsd = get_cifs_acl(&acllen, inode, path);
+ pntsd = get_cifs_acl(&acllen, inode, path, pfid);
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
if (pntsd)
@@ -694,7 +699,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
cFYI(DBG2, ("set ACL from mode for %s", path));
/* Get the security descriptor */
- pntsd = get_cifs_acl(&acllen, inode, path);
+ pntsd = get_cifs_acl(&acllen, inode, path, NULL);
/* Add three ACEs for owner, group, everyone getting rid of
other ACEs as chmod disables ACEs and set the security descriptor */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0af63e6b426..7e5e0e78cd7 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -39,8 +39,8 @@ extern int smb_send(struct socket *, struct smb_hdr *,
unsigned int /* length */ , struct sockaddr *);
extern unsigned int _GetXid(void);
extern void _FreeXid(unsigned int);
-#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
-#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,(int)rc));}
+#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid));
+#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
extern char *build_path_from_dentry(struct dentry *);
extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
/* extern void renew_parental_timestamps(struct dentry *direntry);*/
@@ -92,11 +92,12 @@ extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
extern int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path,
FILE_ALL_INFO * pfile_info,
- struct super_block *sb, int xid);
+ struct super_block *sb, int xid, const __u16 *pfid);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
struct super_block *sb, int xid);
-extern void acl_to_uid_mode(struct inode *inode, const char *search_path);
+extern void acl_to_uid_mode(struct inode *inode, const char *path,
+ const __u16 *pfid);
extern int mode_to_acl(struct inode *inode, const char *path, __u64);
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 4e83b47c4b3..0f5c62ba403 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -229,7 +229,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
inode->i_sb, xid);
else {
rc = cifs_get_inode_info(&newinode, full_path,
- buf, inode->i_sb, xid);
+ buf, inode->i_sb, xid,
+ &fileHandle);
if (newinode) {
newinode->i_mode = mode;
if ((oplock & CIFS_CREATE_ACTION) &&
@@ -483,7 +484,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
parent_dir_inode->i_sb, xid);
else
rc = cifs_get_inode_info(&newInode, full_path, NULL,
- parent_dir_inode->i_sb, xid);
+ parent_dir_inode->i_sb, xid, NULL);
if ((rc == 0) && (newInode != NULL)) {
if (pTcon->nocase)
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c
index ef7f4382434..7cc86c41818 100644
--- a/fs/cifs/dns_resolve.c
+++ b/fs/cifs/dns_resolve.c
@@ -77,14 +77,14 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
/* search for server name delimiter */
len = strlen(unc);
if (len < 3) {
- cFYI(1, ("%s: unc is too short: %s", __FUNCTION__, unc));
+ cFYI(1, ("%s: unc is too short: %s", __func__, unc));
return -EINVAL;
}
len -= 2;
name = memchr(unc+2, '\\', len);
if (!name) {
cFYI(1, ("%s: probably server name is whole unc: %s",
- __FUNCTION__, unc));
+ __func__, unc));
} else {
len = (name - unc) - 2/* leading // */;
}
@@ -104,7 +104,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
if (*ip_addr) {
memcpy(*ip_addr, rkey->payload.data, len);
(*ip_addr)[len] = '\0';
- cFYI(1, ("%s: resolved: %s to %s", __FUNCTION__,
+ cFYI(1, ("%s: resolved: %s to %s", __func__,
rkey->description,
*ip_addr
));
@@ -114,7 +114,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
}
key_put(rkey);
} else {
- cERROR(1, ("%s: unable to resolve: %s", __FUNCTION__, name));
+ cERROR(1, ("%s: unable to resolve: %s", __func__, name));
}
kfree(name);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index fa849c91d32..40b690073fc 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -145,7 +145,7 @@ client_can_cache:
full_path, inode->i_sb, xid);
else
rc = cifs_get_inode_info(&file->f_path.dentry->d_inode,
- full_path, buf, inode->i_sb, xid);
+ full_path, buf, inode->i_sb, xid, NULL);
if ((*oplock & 0xF) == OPLOCK_EXCLUSIVE) {
pCifsInode->clientCanCacheAll = TRUE;
@@ -440,7 +440,7 @@ reopen_error_exit:
else
rc = cifs_get_inode_info(&inode,
full_path, NULL, inode->i_sb,
- xid);
+ xid, NULL);
} /* else we are writing out data to server already
and could deadlock if we tried to flush data, and
since we do not know if we have data that would
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 24eb4d39215..bc673c8c1e6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -30,7 +30,7 @@
#include "cifs_fs_sb.h"
-static void cifs_set_ops(struct inode *inode)
+static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -57,8 +57,16 @@ static void cifs_set_ops(struct inode *inode)
inode->i_data.a_ops = &cifs_addr_ops;
break;
case S_IFDIR:
- inode->i_op = &cifs_dir_inode_ops;
- inode->i_fop = &cifs_dir_ops;
+#ifdef CONFIG_CIFS_DFS_UPCALL
+ if (is_dfs_referral) {
+ inode->i_op = &cifs_dfs_referral_inode_operations;
+ } else {
+#else /* NO DFS support, treat as a directory */
+ {
+#endif
+ inode->i_op = &cifs_dir_inode_ops;
+ inode->i_fop = &cifs_dir_ops;
+ }
break;
case S_IFLNK:
inode->i_op = &cifs_symlink_inode_ops;
@@ -153,6 +161,30 @@ static void cifs_unix_info_to_inode(struct inode *inode,
spin_unlock(&inode->i_lock);
}
+static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon,
+ const char *search_path)
+{
+ int tree_len;
+ int path_len;
+ char *tmp_path;
+
+ if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
+ return search_path;
+
+ /* use full path name for working with DFS */
+ tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
+ path_len = strnlen(search_path, MAX_PATHCONF);
+
+ tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL);
+ if (tmp_path == NULL)
+ return search_path;
+
+ strncpy(tmp_path, pTcon->treeName, tree_len);
+ strncpy(tmp_path+tree_len, search_path, path_len);
+ tmp_path[tree_len+path_len] = 0;
+ return tmp_path;
+}
+
int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, struct super_block *sb, int xid)
{
@@ -161,41 +193,31 @@ int cifs_get_inode_info_unix(struct inode **pinode,
struct cifsTconInfo *pTcon;
struct inode *inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
- char *tmp_path;
+ const unsigned char *full_path;
+ bool is_dfs_referral = false;
pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path));
+
+ full_path = cifs_get_search_path(pTcon, search_path);
+
+try_again_CIFSSMBUnixQPathInfo:
/* could have done a find first instead but this returns more info */
- rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
+ rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
/* dump_mem("\nUnixQPathInfo return data", &findData,
sizeof(findData)); */
if (rc) {
- if (rc == -EREMOTE) {
- tmp_path =
- kmalloc(strnlen(pTcon->treeName,
- MAX_TREE_SIZE + 1) +
- strnlen(search_path, MAX_PATHCONF) + 1,
- GFP_KERNEL);
- if (tmp_path == NULL)
- return -ENOMEM;
-
- /* have to skip first of the double backslash of
- UNC name */
- strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
- strncat(tmp_path, search_path, MAX_PATHCONF);
- rc = connect_to_dfs_path(xid, pTcon->ses,
- /* treename + */ tmp_path,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- kfree(tmp_path);
-
- /* BB fix up inode etc. */
- } else if (rc) {
- return rc;
+ if (rc == -EREMOTE && !is_dfs_referral) {
+ is_dfs_referral = true;
+ if (full_path != search_path) {
+ kfree(full_path);
+ full_path = search_path;
+ }
+ goto try_again_CIFSSMBUnixQPathInfo;