diff options
Diffstat (limited to 'fs')
76 files changed, 1163 insertions, 642 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index be7288184fa..0ea965c3bb7 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -427,6 +427,8 @@ v9fs_create(struct inode *dir, v9fs_mistat2inode(fcall->params.rstat.stat, file_inode, sb); kfree(fcall); + fcall = NULL; + file_dentry->d_op = &v9fs_dentry_operations; d_instantiate(file_dentry, file_inode); if (perm & V9FS_DMDIR) { diff --git a/fs/Kconfig b/fs/Kconfig index 7d6ae369ce4..d5255e627b5 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1601,9 +1601,10 @@ config CIFS PC operating systems. The CIFS protocol is fully supported by file servers such as Windows 2000 (including Windows 2003, NT 4 and Windows XP) as well by Samba (which provides excellent CIFS - server support for Linux and many other operating systems). Currently - you must use the smbfs client filesystem to access older SMB servers - such as Windows 9x and OS/2. + server support for Linux and many other operating systems). Limited + support for Windows ME and similar servers is provided as well. + You must use the smbfs client filesystem to access older SMB servers + such as OS/2 and DOS. The intent of the cifs module is to provide an advanced network file system client for mounting to CIFS compliant servers, @@ -1614,7 +1615,7 @@ config CIFS cifs if running only a (Samba) server. It is possible to enable both smbfs and cifs (e.g. if you are using CIFS for accessing Windows 2003 and Samba 3 servers, and smbfs for accessing old servers). If you need - to mount to Samba or Windows 2003 servers from this machine, say Y. + to mount to Samba or Windows from this machine, say Y. config CIFS_STATS bool "CIFS statistics" @@ -1623,8 +1624,22 @@ config CIFS_STATS Enabling this option will cause statistics for each server share mounted by the cifs client to be displayed in /proc/fs/cifs/Stats +config CIFS_STATS2 + bool "CIFS extended statistics" + depends on CIFS_STATS + help + Enabling this option will allow more detailed statistics on SMB + request timing to be displayed in /proc/fs/cifs/DebugData and also + allow optional logging of slow responses to dmesg (depending on the + value of /proc/fs/cifs/cifsFYI, see fs/cifs/README for more details). + These additional statistics may have a minor effect on performance + and memory utilization. + + Unless you are a developer or are doing network performance analysis + or tuning, say N. + config CIFS_XATTR - bool "CIFS extended attributes (EXPERIMENTAL)" + bool "CIFS extended attributes" depends on CIFS help Extended attributes are name:value pairs associated with inodes by @@ -1636,11 +1651,11 @@ config CIFS_XATTR prefaced by the user namespace prefix. The system namespace (used by some filesystems to store ACLs) is not supported at this time. - + If unsure, say N. config CIFS_POSIX - bool "CIFS POSIX Extensions (EXPERIMENTAL)" + bool "CIFS POSIX Extensions" depends on CIFS_XATTR help Enabling this option will cause the cifs client to attempt to @@ -1653,10 +1668,28 @@ config CIFS_POSIX config CIFS_EXPERIMENTAL bool "CIFS Experimental Features (EXPERIMENTAL)" - depends on CIFS + depends on CIFS && EXPERIMENTAL + help + Enables cifs features under testing. These features are + experimental and currently include support for writepages + (multipage writebehind performance improvements) and directory + change notification ie fcntl(F_DNOTIFY) as well as some security + improvements. Some also depend on setting at runtime the + pseudo-file /proc/fs/cifs/Experimental (which is disabled by + default). See the file fs/cifs/README for more details. + + If unsure, say N. + +config CIFS_UPCALL + bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" + depends on CIFS_EXPERIMENTAL + select CONNECTOR help - Enables cifs features under testing. These features - are highly experimental. If unsure, say N. + Enables an upcall mechanism for CIFS which will be used to contact + userspace helper utilities to provide SPNEGO packaged Kerberos + tickets which are needed to mount to certain secure servers + (for which more secure Kerberos authentication is required). If + unsure, say N. config NCP_FS tristate "NCP file system support (to mount NetWare volumes)" diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 2fd62f89ae0..9cb206e9d4b 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -19,6 +19,7 @@ #include "server.h" #include "vnode.h" #include "internal.h" +#include "cmservice.h" /*****************************************************************************/ /* @@ -457,6 +457,8 @@ static inline struct kiocb *aio_get_req(struct kioctx *ctx) static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) { + assert_spin_locked(&ctx->ctx_lock); + if (req->ki_dtor) req->ki_dtor(req); kmem_cache_free(kiocb_cachep, req); @@ -498,6 +500,8 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) dprintk(KERN_DEBUG "aio_put(%p): f_count=%d\n", req, atomic_read(&req->ki_filp->f_count)); + assert_spin_locked(&ctx->ctx_lock); + req->ki_users --; if (unlikely(req->ki_users < 0)) BUG(); @@ -619,14 +623,13 @@ static void unuse_mm(struct mm_struct *mm) * the kiocb (to tell the caller to activate the work * queue to process it), or 0, if it found that it was * already queued. - * - * Should be called with the spin lock iocb->ki_ctx->ctx_lock - * held */ static inline int __queue_kicked_iocb(struct kiocb *iocb) { struct kioctx *ctx = iocb->ki_ctx; + assert_spin_locked(&ctx->ctx_lock); + if (list_empty(&iocb->ki_run_list)) { list_add_tail(&iocb->ki_run_list, &ctx->run_list); @@ -771,13 +774,15 @@ out: * Process all pending retries queued on the ioctx * run list. * Assumes it is operating within the aio issuer's mm - * context. Expects to be called with ctx->ctx_lock held + * context. */ static int __aio_run_iocbs(struct kioctx *ctx) { struct kiocb *iocb; LIST_HEAD(run_list); + assert_spin_locked(&ctx->ctx_lock); + list_splice_init(&ctx->run_list, &run_list); while (!list_empty(&run_list)) { iocb = list_entry(run_list.next, struct kiocb, @@ -937,28 +942,19 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2) unsigned long tail; int ret; - /* Special case handling for sync iocbs: events go directly - * into the iocb for fast handling. Note that this will not - * work if we allow sync kiocbs to be cancelled. in which - * case the usage count checks will have to move under ctx_lock - * for all cases. + /* + * Special case handling for sync iocbs: + * - events go directly into the iocb for fast handling + * - the sync task with the iocb in its stack holds the single iocb + * ref, no other paths have a way to get another ref + * - the sync task helpfully left a reference to itself in the iocb */ if (is_sync_kiocb(iocb)) { - int ret; - + BUG_ON(iocb->ki_users != 1); iocb->ki_user_data = res; - if (iocb->ki_users == 1) { - iocb->ki_users = 0; - ret = 1; - } else { - spin_lock_irq(&ctx->ctx_lock); - iocb->ki_users--; - ret = (0 == iocb->ki_users); - spin_unlock_irq(&ctx->ctx_lock); - } - /* sync iocbs put the task here for us */ + iocb->ki_users = 0; wake_up_process(iocb->ki_obj.tsk); - return ret; + return 1; } info = &ctx->ring_info; @@ -1613,12 +1609,14 @@ asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr, /* lookup_kiocb * Finds a given iocb for cancellation. - * MUST be called with ctx->ctx_lock held. */ static struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb, u32 key) { struct list_head *pos; + + assert_spin_locked(&ctx->ctx_lock); + /* TODO: use a hash or array, this sucks. */ list_for_each(pos, &ctx->active_reqs) { struct kiocb *kiocb = list_kiocb(pos); diff --git a/fs/befs/attribute.c b/fs/befs/attribute.c deleted file mode 100644 index e329d727053..00000000000 --- a/fs/befs/attribute.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * linux/fs/befs/attribute.c - * - * Copyright (C) 2002 Will Dyson <will_dyson@pobox.com> - * - * Many thanks to Dominic Giampaolo, author of "Practical File System - * Design with the Be File System", for such a helpful book. - * - */ - -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/string.h> - -#include "befs.h" -#include "endian.h" - -#define SD_DATA(sd)\ - (void*)((char*)sd + sizeof(*sd) + (sd->name_size - sizeof(sd->name))) - -#define SD_NEXT(sd)\ - (befs_small_data*)((char*)sd + sizeof(*sd) + (sd->name_size - \ - sizeof(sd->name) + sd->data_size)) - -int -list_small_data(struct super_block *sb, befs_inode * inode, filldir_t filldir); - -befs_small_data * -find_small_data(struct super_block *sb, befs_inode * inode, - const char *name); -int -read_small_data(struct super_block *sb, befs_inode * inode, - befs_small_data * sdata, void *buf, size_t bufsize); - -/** - * - * - * - * - * - */ -befs_small_data * -find_small_data(struct super_block *sb, befs_inode * inode, const char *name) -{ - befs_small_data *sdata = inode->small_data; - - while (sdata->type != 0) { - if (strcmp(name, sdata->name) != 0) { - return sdata; - } - sdata = SD_NEXT(sdata); - } - return NULL; -} - -/** - * - * - * - * - * - */ -int -read_small_data(struct super_block *sb, befs_inode * inode, - const char *name, void *buf, size_t bufsize) -{ - befs_small_data *sdata; - - sdata = find_small_data(sb, inode, name); - if (sdata == NULL) - return BEFS_ERR; - else if (sdata->data_size > bufsize) - return BEFS_ERR; - - memcpy(buf, SD_DATA(sdata), sdata->data_size); - - return BEFS_OK; -} - -/** - * - * - * - * - * - */ -int -list_small_data(struct super_block *sb, befs_inode * inode) -{ - -} - -/** - * - * - * - * - * - */ -int -list_attr(struct super_block *sb, befs_inode * inode) -{ - -} - -/** - * - * - * - * - * - */ -int -read_attr(struct super_block *sb, befs_inode * inode) -{ - -} diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 5bab24f5905..943ef9b8224 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,8 +1,12 @@ Version 1.39 ------------ -Defer close of a file handle slightly if pending writes depend on that file handle +Defer close of a file handle slightly if pending writes depend on that handle (this reduces the EBADF bad file handle errors that can be logged under heavy -stress on writes). +stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 +Fix SFU style symlinks and mknod needed for servers which do not support the +CIFS Unix Extensions. Fix setfacl/getfacl on bigendian. Timeout negative +dentries so files that the client sees as deleted but that later get created +on the server will be recognized. Add client side permission check on setattr. Version 1.38 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index bb90941826a..e5d09a2fc7a 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -278,7 +278,9 @@ A partial list of the supported mount options follows: (such as Windows), permissions can also be checked at the client, and a crude form of client side permission checking can be enabled by specifying file_mode and dir_mode on - the client + the client. Note that the mount.cifs helper must be + at version 1.10 or higher to support specifying the uid + (or gid) in non-numberic form. gid If CIFS Unix extensions are not supported by the server this overrides the default gid for inodes. file_mode If CIFS Unix extensions are not supported by the server @@ -345,7 +347,10 @@ A partial list of the supported mount options follows: client system. It is typically only needed when the server supports the CIFS Unix Extensions but the UIDs/GIDs on the client and server system do not match closely enough to allow - access by the user doing the mount. + access by the user doing the mount, but it may be useful with + non CIFS Unix Extension mounts for cases in which the default + mode is specified on the mount but is not to be enforced on the + client (e.g. perhaps when MultiUserMount is enabled) Note that this does not affect the normal ACL check on the target machine done by the server software (of the server ACL against the user name provided at mount time). @@ -368,15 +373,21 @@ A partial list of the supported mount options follows: setuids If the CIFS Unix extensions are negotiated with the server the client will attempt to set the effective uid and gid of the local process on newly created files, directories, and - devices (create, mkdir, mknod). + devices (create, mkdir, mknod). If the CIFS Unix Extensions + are not negotiated, for newly created files and directories + instead of using the default uid and gid specified on the + the mount, cache the new file's uid and gid locally which means + that the uid for the file can change when the inode is + reloaded (or the user remounts the share). nosetuids The client will not attempt to set the uid and gid on on newly created files, directories, and devices (create, mkdir, mknod) which will result in the server setting the uid and gid to the default (usually the server uid of the user who mounted the share). Letting the server (rather than - the client) set the uid and gid is the default. This - parameter has no effect if the CIFS Unix Extensions are not - negotiated. + the client) set the uid and gid is the default. If the CIFS + Unix Extensions are not negotiated then the uid and gid for + new files will appear to be the uid (gid) of the mounter or the + uid (gid) parameter specified on the mount. netbiosname When mounting to servers via port 139, specifies the RFC1001 source name to use to represent the client netbios machine name when doing the RFC1001 netbios session initialize. @@ -418,6 +429,13 @@ A partial list of the supported mount options follows: byte range locks). remount remount the share (often used to change from ro to rw mounts or vice versa) + sfu When the CIFS Unix Extensions are not negotiated, attempt to + create device files and fifos in a format compatible with + Services for Unix (SFU). In addition retrieve bits 10-12 + of the mode via the SETFILEBITS extended attribute (as + SFU does). In the future the bottom 9 bits of the mode + mode also will be emulated using queries of the security + descriptor (ACL). The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/TODO b/fs/cifs/TODO index c909298d11e..fc34c74ec4b 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -version 1.37 October 9, 2005 +Version 1.39 November 30, 2005 A Partial List of Missing Features ================================== @@ -58,7 +58,7 @@ o) Improve performance of readpages by sending more than one read at a time when 8 pages or more are requested. In conjuntion add support for async_cifs_readpages. -p) Add support for storing symlink and fifo info to Windows servers +p) Add support for storing symlink info to Windows servers in the Extended Attribute format their SFU clients would recognize. q) Finish fcntl D_NOTIFY support so kde and gnome file list windows diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 99a096d3f84..d2b12825594 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifs_unicode.c * - * Copyright (c) International Business Machines Corp., 2000,2002 + * Copyright (c) International Business Machines Corp., 2000,2005 * Modified by Steve French (sfrench@us.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -31,7 +31,7 @@ * */ int -cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ +cifs_strfromUCS_le(char *to, const __le16 * from, int len, const struct nls_table *codepage) { int i; @@ -60,24 +60,26 @@ cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ * */ int -cifs_strtoUCS(wchar_t * to, const char *from, int len, +cifs_strtoUCS(__le16 * to, const char *from, int len, const struct nls_table *codepage) { int charlen; int i; + wchar_t * wchar_to = (wchar_t *)to; /* needed to quiet sparse */ for (i = 0; len && *from; i++, from += charlen, len -= charlen) { /* works for 2.4.0 kernel or later */ - charlen = codepage->char2uni(from, len, &to[i]); + charlen = codepage->char2uni(from, len, &wchar_to[i]); if (charlen < 1) { cERROR(1, ("cifs_strtoUCS: char2uni returned %d", charlen)); - to[i] = cpu_to_le16(0x003f); /* a question mark */ + /* A question mark */ + to[i] = cpu_to_le16(0x003f); charlen = 1; } else - to[i] = cpu_to_le16(to[i]); + to[i] = cpu_to_le16(wchar_to[i]); } diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index da8dde96527..39e5b970325 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -5,7 +5,7 @@ * Convert a unicode character to upper or lower case using * compressed tables. * - * Copyright (c) International Business Machines Corp., 2000,2002 + * Copyright (c) International Business Machines Corp., 2000,2005555555555555555555555555555555555555555555555555555555 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,8 +59,8 @@ extern struct UniCaseRange UniLowerRange[]; #endif /* UNIUPR_NOLOWER */ #ifdef __KERNEL__ -int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); -int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); +int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); +int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); #endif /* diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 1959c7c4b18..fe2bb7c4c91 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -149,7 +149,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ char temp_hash[16]; struct HMACMD5Context ctx; char * ucase_buf; - wchar_t * unicode_buf; + __le16 * unicode_buf; unsigned int i,user_name_len,dom_name_len; if(ses == NULL) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 877095a1192..2a13a2bac8f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -32,6 +32,7 @@ #include <linux/seq_file.h> #include <linux/vfs.h> #include <linux/mempool.h> +#include <linux/delay.h> #include "cifsfs.h" #include "cifspdu.h" #define DECLARE_GLOBALS_HERE @@ -405,6 +406,7 @@ static struct quotactl_ops cifs_quotactl_ops = { }; #endif +#ifdef CONFIG_CIFS_EXPERIMENTAL static void cifs_umount_begin(struct super_block * sblock) { struct cifs_sb_info *cifs_sb; @@ -422,16 +424,23 @@ static void cifs_umount_begin(struct super_block * sblock) tcon->tidStatus = CifsExiting; up(&tcon->tconSem); + /* cancel_brl_requests(tcon); */ + /* cancel_notify_requests(tcon); */ if(tcon->ses && tcon->ses->server) { - cERROR(1,("wake up tasks now - umount begin not complete")); + cFYI(1,("wake up tasks now - umount begin not complete")); wake_up_all(&tcon->ses->server->request_q); + wake_up_all(&tcon->ses->server->response_q); + msleep(1); /* yield */ + /* we have to kick the requests once more */ + wake_up_all(&tcon->ses->server->response_q); + msleep(1); } /* BB FIXME - finish add checks for tidStatus BB */ return; } - +#endif static int cifs_remount(struct super_block *sb, int *flags, char *data) { @@ -450,7 +459,9 @@ struct super_operations cifs_super_ops = { unless later we add lazy close of inodes or unless the kernel forgets to call us with the same number of releases (closes) as opens */ .show_options = cifs_show_options, -/* .umount_begin = cifs_umount_begin, */ /* BB finish in the future */ +#ifdef CONFIG_CIFS_EXPERIMENTAL + .umount_begin = cifs_umount_begin, +#endif .remount_fs = cifs_remount, }; @@ -478,57 +489,30 @@ cifs_get_sb(struct file_system_type *fs_type, return sb; } -static ssize_t -cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size, - loff_t * poffset) +static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) { - 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)); + struct inode *inode = file->f_dentry->d_inode; + ssize_t written; - 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); - } + written = generic_file_writev(file, iov, nr_segs, ppos); + if (!CIFS_I(inode)->clientCanCacheAll) + filemap_fdatawrite(inode->i_mapping); + return written; } -static ssize_t -cifs_write_wrapper(struct file * file, const char __user *write_data, - size_t write_size, loff_t * poffset) +static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf, + size_t count, loff_t pos) { + struct inode *inode = iocb->ki_filp->f_dentry->d_inode; 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); - } - } + written = generic_file_aio_write(iocb, buf, count, pos); + if (!CIFS_I(inode)->clientCanCacheAll) + filemap_fdatawrite(inode->i_mapping); return written; } - static struct file_system_type cifs_fs_type = { .owner = THIS_MODULE, .name = "cifs", @@ -589,8 +573,12 @@ struct inode_operations cifs_symlink_inode_ops = { }; struct file_operations cifs_file_ops = { - .read = cifs_read_wrapper, - .write = cifs_write_wrapper, + .read = do_sync_read, + .write = do_sync_write, + .readv = generic_file_readv, + .writev = cifs_file_writev, + .aio_read = generic_file_aio_read, + .aio_write = cifs_file_aio_write, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -603,10 +591,6 @@ struct file_operations cifs_file_ops = { #endif /* CONFIG_CIFS_POSIX */ #ifdef CONFIG_CIFS_EXPERIMENTAL - .readv = generic_file_readv, - .writev = generic_file_writev, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; @@ -630,6 +614,46 @@ struct file_operations cifs_file_direct_ops = { .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; +struct file_operations cifs_file_nobrl_ops = { + .read = do_sync_read, + .write = do_sync_write, + .readv = generic_file_readv, + .writev = cifs_file_writev, + .aio_read = generic_file_aio_read, + .aio_write = cifs_file_aio_write, + .open = cifs_open, + .release = cifs_close, + .fsync = cifs_fsync, + .flush = cifs_flush, + .mmap = cifs_file_mmap, + .sendfile = generic_file_sendfile, +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + +#ifdef CONFIG_CIFS_EXPERIMENTAL + .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ +}; + +struct file_operations cifs_file_direct_nobrl_ops = { + /* no mmap, no aio, no readv - + BB reevaluate whether they can be done with directio, no cache */ + .read = cifs_user_read, + .write = cifs_user_write, + .open = cifs_open, + .release = cifs_close, + .fsync = cifs_fsync, + .flush = cifs_flush, + .sendfile = generic_file_sendfile, /* BB removeme BB */ +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + +#ifdef CONFIG_CIFS_EXPERIMENTAL + .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ +}; struct file_operations cifs_dir_ops = { .readdir = cifs_readdir, @@ -877,6 +901,9 @@ static int cifs_oplock_thread(void * dummyarg) static int cifs_dnotify_thread(void * dummyarg) { + struct list_head *tmp; + struct cifsSesInfo *ses; + daemonize("cifsdnotifyd"); allow_signal(SIGTERM); @@ -885,7 +912,19 @@ static int cifs_dnotify_thread(void * dummyarg) if(try_to_freeze()) continue; set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(39*HZ); + schedule_timeout(15*HZ); + read_lock(&GlobalSMBSeslock); + /* check if any stuck requests that need + to be woken up and wakeq so the + thread can wake up and error out */ + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, + cifsSessionList); + if(ses && ses->server && + atomic_read(&ses->server->inFlight)) + wake_up_all(&ses->server->response_q); + } + read_unlock(&GlobalSMBSeslock); } while(!signal_pending(current)); complete_and_exit (&cifs_dnotify_exited, 0); } diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 1223fa81dbd..9ec40e0e54f 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -63,6 +63,8 @@ extern struct inode_operations cifs_symlink_inode_ops; /* Functions related to files and directories */ extern struct file_operations cifs_file_ops; extern struct file_operations cifs_file_direct_ops; /* if directio mount */ +extern struct file_operations cifs_file_nobrl_ops; +extern struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */ extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file); diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 48a05b9df7e..33e1859fd2f 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -603,7 +603,9 @@ typedef struct smb_com_logoff_andx_rsp { __u16 ByteCount; } __attribute__((packed)) LOGOFF_ANDX_RSP; -typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ +typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on + tree_connect PDU to effect disconnect */ + /* tdis is probably simplest SMB PDU */ struct { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bcc = 0 */ @@ -2025,6 +2027,12 @@ typedef struct { } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ +struct win_dev { + unsigned char type[8]; /* IntxCHR or IntxBLK */ + __le64 major; + __le64 minor; +} __attribute__((packed)); + struct gea { unsigned char name_len; char name[1]; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d301149b1bb..1b73f4f4c5c 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -242,11 +242,11 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 offset, unsigned int *nbytes, struct kvec *iov, const int nvec, const int long_op); +#endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, const struct nls_table *nls_codepage, int remap_special_chars); -#endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, const struct nls_table * codepage); extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9312bfc5668..6867e556d37 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -90,6 +90,18 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, check for tcp and smb session status done differently for those three - in the calling routine */ if(tcon) { + if(tcon->tidStatus == CifsExiting) { + /* only tree disconnect, open, and write, + (and ulogoff which does not have tcon) + are allowed as we start force umount */ + if((smb_command != SMB_COM_WRITE_ANDX) && + (smb_command != SMB_COM_OPEN_ANDX) && + (smb_command != SMB_COM_TREE_DISCONNECT)) { + cFYI(1,("can not send cmd %d while umounting", + smb_command)); + return -ENODEV; + } + } if((tcon->ses) && (tcon->ses->status != CifsExiting) && (tcon->ses->server)){ struct nls_table *nls_codepage; @@ -187,6 +199,19 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, check for tcp and smb session status done differently for those three - in the calling routine */ if(tcon) { + if(tcon->tidStatus == CifsExiting) { + /* only tree disconnect, open, and write, + (and ulogoff which does not have tcon) + are allowed as we start force umount */ + if((smb_command != SMB_COM_WRITE_ANDX) && + (smb_command != SMB_COM_OPEN_ANDX) && + (smb_command != SMB_COM_TREE_DISCONNECT)) { + cFYI(1,("can not send cmd %d while umounting", + smb_command)); + return -ENODEV; + } + } + if((tcon->ses) && (tcon->ses->status != CifsExiting) && (tcon->ses->server)){ struct nls_table *nls_codepage; @@ -1142,7 +1167,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, int bytes_returned, wct; int smb_hdr_len; - cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ + /* BB removeme BB */ + cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); + if(tcon->ses->capabilities & CAP_LARGE_FILES) wct = 14; else @@ -1553,7 +1580,7 @@ createSymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX + cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -1577,7 +1604,7 @@ createSymLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX + cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len_target++; /* trailing null */ @@ -1803,7 +1830,7 @@ querySymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX + cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -1860,7 +1887,7 @@ querySymLinkRetry: min_t(const int, buflen,count) / 2); /* BB FIXME investigate remapping reserved chars here */ cifs_strfromUCS_le(symlinkinfo, - (wchar_t *) ((char *)&pSMBr->hdr.Protocol + + (__le16 *) ((char *)&pSMBr->hdr.Protocol + data_offset), name_len, nls_codepage); } else { @@ -1951,7 +1978,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, reparse_buf->TargetNameOffset), min(buflen/2, reparse_buf->TargetNameLen / 2)); cifs_strfromUCS_le(symlinkinfo, - (wchar_t *) (reparse_buf->LinkNamesBuf + + (__le16 *) (reparse_buf->LinkNamesBuf + reparse_buf->TargetNameOffset), name_len, nls_codepage); } else { /* ASCII names */ @@ -1983,9 +2010,9 @@ qreparse_out: static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace) { /* u8 cifs fields do not need le conversion */ - ace->e_perm = (__u16)cifs_ace->cifs_e_perm; - ace->e_tag = (__u16)cifs_ace->cifs_e_tag; - ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid); + ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm); + ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag); + ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid)); /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */ return; @@ -2037,7 +2064,7 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen, } else if(size > buflen) { return -ERANGE; } else /* buffer big enough */ { - local_acl->a_version = POSIX_ACL_XATTR_VERSION; + local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); for(i = 0;i < count ;i++) { cifs_convert_ace(&local_acl->a_entries[i],pACE); pACE ++; @@ -2051,14 +2078,14 @@ static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace, { __u16 rc = 0; /* 0 = ACL converted ok */ - cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm); - cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag); + cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm); + cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag); /* BB is there a better way to handle the large uid? */ - if(local_ace->e_id == -1) { + if(local_ace->e_id == cpu_to_le32(-1)) { /* Probably no need to le convert -1 on any arch but can not hurt */ cifs_ace->cifs_uid = cpu_to_le64(-1); } else - cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id); + cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id)); /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/ return rc; } @@ -2078,16 +2105,17 @@ static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int bufl count = posix_acl_xattr_count((size_t)buflen); cFYI(1,("setting acl with %d entries from buf of length %d and version of %d", - count,buflen,local_acl->a_version)); - if(local_acl->a_version != 2) { - cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version)); + count, buflen, le32_to_cpu(local_acl->a_version))); + if(le32_to_cpu(local_acl->a_version) != 2) { + cFYI(1,("unknown POSIX ACL version %d", + le32_to_cpu(local_acl->a_version))); return 0; } cifs_acl->version = cpu_to_le16(1); if(acl_type == ACL_TYPE_ACCESS) - cifs_acl->access_entry_count = count; + cifs_acl->access_entry_count = cpu_to_le16(count); else if(acl_type == ACL_TYPE_DEFAULT) - cifs_acl->default_entry_count = count; + cifs_acl->default_entry_count = cpu_to_le16(count); else { cFYI(1,("unknown ACL type %d",acl_type)); return 0; @@ -2959,7 +2987,6 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, @@ -3053,7 +3080,6 @@ GetInodeNumOut: goto GetInodeNumberRetry; return rc; } -#endif /* CIFS_EXPERIMENTAL */ int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, @@ -3205,7 +3231,7 @@ getDFSRetry: temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset); if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { cifs_strfromUCS_le(*targetUNCs, - (wchar_t *) temp, name_len, nls_codepage); + (__le16 *) temp, name_len, nls_codepage); } else { strncpy(*targetUNCs,temp,name_len); } diff --git a/fs/cifs/cn_cifs.h b/fs/cifs/cn_cifs.h new file mode 100644 index 00000000000..ea59ccac2eb --- /dev/null +++ b/fs/cifs/cn_cifs.h @@ -0,0 +1,37 @@ +/* + * fs/cifs/cn_cifs.h + * + * Copyright (c) International Business Machines Corp., 2002 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * 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 + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CN_CIFS_H +#define _CN_CIFS_H +#ifdef CONFIG_CIFS_UPCALL +#include <linux/types.h> +#include <linux/connector.h> + +struct cifs_upcall { + char signature[4]; /* CIFS */ + enum command { + CIFS_GET_IP = 0x00000001, /* get ip address for hostname */ + CIFS_GET_SECBLOB = 0x00000002, /* get SPNEGO wrapped blob */ + } command; + /* union cifs upcall data follows */ +}; +#endif /* CIFS_UPCALL */ +#endif /* _CN_CIFS_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 450ab75d654..c467de85761 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -42,6 +42,7 @@ #include "ntlmssp.h" #include "nterr.h" #include "rfc1002pdu.h" +#include "cn_cifs.h" #define CIFS_PORT 445 #define RFC1001_PORT 139 @@ -1985,32 +1986,32 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bytes_returned = 0; /* skill null user */ else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, + cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); /* convert number of 16 bit words to bytes */ bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* trailing null */ if (domain == NULL) bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, + cifs_strtoUCS((__le16 *) bcc_ptr, "CIFS_LINUX_DOM", 32, nls_codepage); else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -2080,7 +2081,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverOS == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverOS, - (wchar_t *)bcc_ptr, len,nls_codepage); + (__le16 *)bcc_ptr, len,nls_codepage); bcc_ptr += 2 * (len + 1); remaining_words -= len + 1; ses->serverOS[2 * len] = 0; @@ -2092,7 +2093,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverNOS == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverNOS, - (wchar_t *)bcc_ptr,len,nls_codepage); + (__le16 *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverNOS[2 * len] = 0; ses->serverNOS[1 + (2 * len)] = 0; @@ -2110,7 +2111,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverDomain == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverDomain, - (wchar_t *)bcc_ptr,len,nls_codepage); + (__le16 *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; @@ -2254,30 +2255,30 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); + cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ bcc_ptr += 2; /* trailing null */ if (domain == NULL) bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, + cifs_strtoUCS((__le16 *) bcc_ptr, "CIFS_LINUX_DOM", 32, nls_codepage); else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -2356,7 +2357,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2371,7 +2372,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, - (wchar_t *)bcc_ptr, + (__le16 *)bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2383,9 +2384,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, - (wchar_t *)bcc_ptr, - len, - nls_codepage); + (__le16 *)bcc_ptr, + len, nls_codepage); bcc_ptr += 2*(len+1); ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; @@ -2559,16 +2559,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null terminate Linux version */ bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; @@ -2672,7 +2672,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2689,7 +2689,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); @@ -2707,23 +2707,15 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, 1), GFP_KERNEL); cifs_strfromUCS_le - (ses-> - serverDomain, - (wchar_t *) - bcc_ptr, len, - nls_codepage); + (ses->serverDomain, + (__le16 *)bcc_ptr, + len, nls_codepage); bcc_ptr += 2 * (len + 1); - ses-> - serverDomain[2 - * len] + ses->serverDomain[2*len] = 0; - ses-> - serverDomain[1 - + - (2 - * - len)] + ses->serverDomain + [1 + (2 * len)] = 0; } /* else no more room so create dummy domain string */ else @@ -2902,7 +2894,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.MaximumLength = 0; } else { __u16 len = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); len *= 2; SecurityBlob->DomainName.MaximumLength = @@ -2920,7 +2912,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->UserName.MaximumLength = 0; } else { __u16 len = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, nls_codepage); len *= 2; SecurityBlob->UserName.MaximumLength = @@ -2933,7 +2925,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, cpu_to_le16(len); } - /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage); + /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); SecurityBlob->WorkstationName.Length *= 2; SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); @@ -2946,16 +2938,16 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null term version string */ bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; @@ -3068,7 +3060,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -3085,7 +3077,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); @@ -3104,7 +3096,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, cifs_strfromUCS_le (ses-> serverDomain, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += @@ -3226,7 +3218,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; length = - cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage); + cifs_strtoUCS((__le16 *) bcc_ptr, tree, 100, nls_codepage); bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ bcc_ptr += 2; /* skip trailing null */ } else { /* ASCII */ @@ -3262,7 +3254,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, tcon->nativeFileSystem = kzalloc(length + 2, GFP_KERNEL); cifs_strfromUCS_le(tcon->nativeFileSystem, - (wchar_t *) bcc_ptr, + (__le16 *) bcc_ptr, length, nls_codepage); bcc_ptr += 2 * length; bcc_ptr[0] = 0; /* null terminate the string */ diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 8dfe717a332..32cc96cafa3 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -228,8 +228,15 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, else { rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,xid); - if(newinode) + if(newinode) { newinode->i_mode = mode; + if((oplock & CIFS_CREATE_ACTION) && + (cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_SET_UID)) { + newinode->i_uid = current->fsuid; + newinode->i_gid = current->fsgid; + } + } } if (rc != 0) { @@ -292,7 +299,8 @@ cifs_create_out: return rc; } -int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) +int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, + dev_t device_number) { int rc = -EPERM; int xid; @@ -368,7 +376,34 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev if(!rc) { /* BB Do not bother to decode buf since no - local inode yet to put timestamps in */ + local inode yet to put timestamps in, + but we can reuse it safely */ + int bytes_written; + struct win_dev *pdev; + pdev = (struct win_dev *)buf; + if(S_ISCHR(mode)) { + memcpy(pdev->type, "IntxCHR", 8); + pdev->major = + cpu_to_le64(MAJOR(device_number)); + pdev->minor = + cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, pTcon, + fileHandle, + sizeof(struct win_dev), + 0, &bytes_written, (char *)pdev, + NULL, 0); + } else if(S_ISBLK(mode)) { + memcpy(pdev->type, "IntxBLK", 8); + pdev->major = + cpu_to_le64(MAJOR(device_number)); + pdev->minor = + cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, pTcon, + fileHandle, + sizeof(struct win_dev), + 0, &bytes_written, (char *)pdev, + NULL, 0); + } /* else if(S_ISFIFO */ CIFSSMBClose(xid, pTcon, fileHandle); d_drop(direntry); } @@ -437,12 +472,20 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name direntry->d_op = &cifs_dentry_ops; d_add(direntry, newInode); - /* since paths are not looked up by component - the parent directories are presumed to be good here */ + /* since paths are not looked up by component - the parent + directories are presumed to be good here */ renew_parental_timestamps(direntry); } else if (rc == -ENOENT) { rc = 0; + direntry->d_time = jiffies; + if (pTcon->nocase) + direntry->d_op = &cifs_ci_dentry_ops; + else + direntry->d_op = &cifs_dentry_ops; d_add(direntry, NULL); + /* if it was once a directory (but how can we tell?) we could do + shrink_dcache_parent(direntry); */ } else { cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s", rc,full_path)); @@ -461,21 +504,20 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) { int isValid = 1; -/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */ - if (direntry->d_inode) { if (cifs_revalidate(direntry)) { - /* unlock_kernel(); */ return 0; } } else { - cFYI(1, - ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p", - direntry->d_name.name, direntry)); + cFYI(1, ("neg dentry 0x%p name = %s", + direntry, direntry->d_name.name)); + if(time_after(jiffies, direntry->d_time + HZ) || + !lookupCacheEnabled) { + d_drop(direntry); + isValid = 0; + } } -/* unlock_kernel(); */ - return isValid; } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index da4f5e10b3c..14a1c72ced9 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -489,8 +489,10 @@ int cifs_close(struct inode *inode, struct file *file) the struct would be in each open file, but this should give enough time to clear the socket */ + write_unlock(&file->f_owner.lock); cERROR(1,("close with pending writes")); msleep(timeout); + write_lock(&file->f_owner.lock); timeout *= 4; } write_unlock(&file->f_owner.lock); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 912d401600f..411c1f7f84d 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, char *tmp_path; pTcon = cifs_sb->tcon; - cFYI(1, (" Getting info on %s ", search_path)); + cFYI(1, ("Getting info on %s ", search_path)); /* could have done a find first instead but this returns more info */ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); - cFYI(1, (" Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld ", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, (" New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld ", cifsInfo->time)); /* this is ok to set on every inode revalidate */ atomic_set(&cifsInfo->inUse,1); @@ -111,6 +111,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); inode->i_mode = le64_to_cpu(findData.Permissions); + /* since we set the inode type below we need to mask off + to avoid strange results if bits set above */ + inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { @@ -129,6 +132,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_mode |= S_IFIFO; } else if (type == UNIX_SOCKET) { inode->i_mode |= S_IFSOCK; + } else { + /* safest to call it a file if we do not know */ + inode->i_mode |= S_IFREG; + cFYI(1,("unknown type %d",type)); } inode->i_uid = le64_to_cpu(findData.Uid); inode->i_gid = le64_to_cpu(findData.Gid); @@ -155,34 +162,39 @@ int cifs_get_inode_info_unix(struct inode **pinode, } if (num_of_bytes < end_of_file) - cFYI(1, ("allocation size less than end of file ")); + cFYI(1, ("allocation size less than end of file")); cFYI(1, ("Size %ld and blocks %ld", (unsigned long) inode->i_size, inode->i_blocks)); if (S_ISREG(inode->i_mode)) { - cFYI(1, (" File inode ")); + cFYI(1, ("File inode")); inode->i_op = &cifs_file_inode_ops; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - inode->i_fop = &cifs_file_direct_ops; - else + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = + &cifs_file_direct_nobrl_ops; + else + inode->i_fop = &cifs_file_direct_ops; + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = &cifs_file_nobrl_ops; + else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - inode->i_fop->lock = NULL; + inode->i_data.a_ops = &cifs_addr_ops; /* check if server can support readpages */ if(pTcon->ses->server->maxBuf < 4096 + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops->readpages = NULL; } else if (S_ISDIR(inode->i_mode)) { - cFYI(1, (" Directory inode")); + cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(inode->i_mode)) { - cFYI(1, (" Symbolic Link inode ")); + cFYI(1, ("Symbolic Link inode")); inode->i_op = &cifs_symlink_inode_ops; /* tmp_inode->i_fop = */ /* do not need to set to anything */ } else { - cFYI(1, (" Init special inode ")); + cFYI(1, ("Init special inode")); init_special_inode(inode, inode->i_mode, inode->i_rdev); } @@ -190,6 +202,111 @@ int cifs_get_inode_info_unix(struct inode **pinode, return rc; } +static int decode_sfu_inode(struct inode * inode, __u64 size, + const unsigned char *path, + struct cifs_sb_info *cifs_sb, int xid) +{ + int rc; + int oplock = FALSE; + __u16 netfid; + struct cifsTconInfo *pTcon = cifs_sb->tcon; + char buf[24]; + unsigned int bytes_read; + char * pbuf; + + pbuf = buf; + + if(size == 0) { + inode->i_mode |= S_IFIFO; + return 0; + } else if (size < 8) { + return -EINVAL; /* EOPNOTSUPP? */ + } + + rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, &netfid, &oplock, NULL, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc==0) { + /* Read header */ + rc = CIFSSMBRead(xid, pTcon, + netfid, + 24 /* length */, 0 /* offset */, + &bytes_read, &pbuf); + if((rc == 0) && (bytes_read >= 8)) { + if(memcmp("IntxBLK", pbuf, 8) == 0) { + cFYI(1,("Block device")); + inode->i_mode |= S_IFBLK; + if(bytes_read == 24) { + /* we have enough to decode dev num */ + __u64 mjr; /* major */ + __u64 mnr; /* minor */ + mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); + mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); + inode->i_rdev = MKDEV(mjr, mnr); + } + } else if(memcmp("IntxCHR", pbuf, 8) == 0) { + cFYI(1,("Char device")); + inode->i_mode |= S_IFCHR; + if(bytes_read == 24) { + /* we have enough to decode dev num */ + __u64 mjr; /* major */ + __u64 mnr; /* minor */ + mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); + mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); + inode->i_rdev = MKDEV(mjr, mnr); + } + } else if(memcmp("IntxLNK", pbuf, 7) == 0) { + cFYI(1,("Symlink")); + inode->i_mode |= S_IFLNK; + } else { + inode->i_mode |= S_IFREG; /* file? */ + rc = -EOPNOTSUPP; + } + } else { + inode->i_mode |= S_IFREG; /* then it is a file */ + rc = -EOPNOTSUPP; /* or some unknown SFU type */ + } + CIFSSMBClose(xid, pTcon, netfid); + } + return rc; + +} + +#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ + +static int get_sfu_uid_mode(struct inode * inode, + const unsigned char *path, + struct cifs_sb_info *cifs_sb, int xid) +{ +#ifdef CONFIG_CIFS_XATTR + ssize_t rc; + char ea_value[4]; + __u32 mode; + + rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", + ea_value, 4 /* size of buf */, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if(rc < 0) + return (int)rc; + else if (rc > 3) { + mode = le32_to_cpu(*((__le32 *)ea_value)); + inode->i_mode &= ~SFBITS_MASK; + cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode)); + inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; + cFYI(1,("special mode bits 0%o", mode)); + return 0; + } else { + return 0; + } +#else + return -EOPNOTSUPP; +#endif + + +} + int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO *pfindData, struct super_block *sb, int xid) @@ -202,7 +319,7 @@ int cifs_get_inode_info(struct inode **pinode, char *buf = NULL; pTcon = cifs_sb->tcon; - cFYI(1,("Getting info on %s ", search_path)); + cFYI(1,("Getting info on %s", search_path)); if ((pfindData == NULL) && (*pinode != NULL)) { if (CIFS_I(*pinode)->clientCanCacheRead) { @@ -283,7 +400,6 @@ int cifs_get_inode_info(struct inode **pinode, there Windows server or network appliances for which IndexNumber field is not guaranteed unique? */ -#ifdef CONFIG_CIFS_EXPERIMENTAL if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){ int rc1 = 0; __u64 inode_num; @@ -299,15 +415,14 @@ int cifs_get_inode_info(struct inode **pinode, } else /* do we need cast or hash to ino? */ (*pinode)->i_ino = inode_num; } /* else ino incremented to unique num in new_inode*/ -#endif /* CIFS_EXPERIMENTAL */ insert_inode_hash(*pinode); } inode = *pinode; cifsInfo = CIFS_I(inode); cifsInfo->cifsAttrs = attr; - cFYI(1, (" Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld ", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, (" New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld ", cifsInfo->time)); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize @@ -321,13 +436,15 @@ int cifs_get_inode_info(struct inode **pinode, cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); - cFYI(0, (" Attributes came in as 0x%x ", attr)); + cFYI(0, ("Attributes came in as 0x%x ", attr)); /* set default mode. will override for dirs below */ if (atomic_read(&cifsInfo->inUse) == 0) /* new inode, can safely set these fields */ inode->i_mode = cifs_sb->mnt_file_mode; - + else /* since we set the inode type below we need to mask off + to avoid strange results if type changes and both get orred in */ + inode->i_mode &= ~S_IFMT; /* if (attr & ATTR_REPARSE) */ /* We no longer handle these as symlinks because we could not follow them due to the absolute path with drive letter */ @@ -342,10 +459,16 @@ int cifs_get_inode_info(struct inode **pinode, (pfindData->EndOfFile == 0)) { inode->i_mode = cifs_sb->mnt_file_mode; inode->i_mode |= S_IFIFO; -/* BB Finish for SFU style symlinks and devies */ -/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */ - +/* BB Finish for SFU style symlinks and devices */ + } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && + (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { + if (decode_sfu_inode(inode, + le64_to_cpu(pfindData->EndOfFile), + search_path, + cifs_sb, xid)) { + cFYI(1,("Unrecognized sfu inode type")); + } + cFYI(1,("sfu mode 0%o",inode->i_mode)); } else { inode->i_mode |= S_IFREG; /* treat the dos attribute of read-only as read-only @@ -370,7 +493,10 @@ int cifs_get_inode_info(struct inode **pinode, /* BB fill in uid and gid here? with help from winbind? or retrieve from NTFS stream extended attribute */ - if (atomic_read(&cifsInfo->inUse) == 0) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { + /* fill in uid, gid, mode from server ACL */ + get_sfu_uid_mode(inode, search_path, cifs_sb, xid); + } else if (atomic_read(&cifsInfo->inUse) == 0) { inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; /* set so we do not keep refreshing these fields with @@ -379,24 +505,29 @@ int cifs_get_inode_info(struct inode **pinode, } if (S_ISREG(inode->i_mode)) { - cFYI(1, (" File inode ")); + cFYI(1, ("File inode")); inode->i_op = &cifs_file_inode_ops; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - inode->i_fop = &cifs_file_direct_ops; - else + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = + &cifs_file_direct_nobrl_ops; + else + inode->i_fop = &cifs_file_direct_ops; + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = &cifs_file_nobrl_ops; + else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - inode->i_fop->lock = NULL; + inode->i_data.a_ops = &cifs_addr_ops; if(pTcon->ses->server->maxBuf < 4096 + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops->readpages = NULL; } else if (S_ISDIR(inode->i_mode)) { - cFYI(1, (" Directory inode ")); + cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(inode->i_mode)) { - cFYI(1, (" Symbolic Link inode ")); + cFYI(1, ("Symbolic Link inode")); inode->i_op = &cifs_symlink_inode_ops; } else { init_special_inode(inode, inode->i_mode, @@ -433,7 +564,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) struct cifsInodeInfo *cifsInode; FILE_BASIC_INFO *pinfo_buf; - cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); + cFYI(1, ("cifs_unlink, inode = 0x%p with ", inode)); xid = GetXid(); @@ -579,7 +710,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) char *full_path = NULL; struct inode *newinode = NULL; - cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode)); + cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode)); xid = GetXid(); @@ -637,6 +768,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) /* BB to be implemented via Windows secrty descriptors eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, -1, -1, local_nls); */ + if(direntry->d_inode) { + direntry->d_inode->i_mode = mode; + direntry->d_inode->i_mode |= S_IFDIR; + if(cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_SET_UID) { + direntry->d_inode->i_uid = + current->fsuid; + direntry->d_inode->i_gid = + current->fsgid; + } + } } } kfree(full_path); @@ -653,7 +795,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) char *full_path = NULL; struct cifsInodeInfo *cifsInode; - cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode)); + cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode)); xid = GetXid(); @@ -908,14 +1050,20 @@ int cifs_revalidate(struct dentry *direntry) filemap_fdatawrite(direntry->d_inode->i_mapping); } if (invalidate_inode) { - if (direntry->d_inode->i_mapping) - 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); + /* shrink_dcache not necessary now that cifs dentry ops + are exported for negative dentries */ +/* if(S_ISDIR(direntry->d_inode->i_mode)) + shrink_dcache_parent(direntry); */ + if (S_ISREG(direntry->d_inode->i_mode)) { + if (direntry->d_inode->i_mapping) + filemap_fdatawait(direntry->d_inode->i_mapping); + /* may eventually have to do this for open files too */ + if (list_empty(&(cifsInode->openFileList))) { + /* 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); */ @@ -972,11 +1120,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) xid = GetXid(); - cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ", + cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ", direntry->d_name.name, attrs->ia_valid)); + cifs_sb = CIFS_SB(direntry->d_inode->i_sb); pTcon = cifs_sb->tcon; + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { + /* check if we have permission to change attrs */ + rc = inode_change_ok(direntry->d_inode, attrs); + if(rc < 0) { + FreeXid(xid); + return rc; + } else + rc = 0; + } + down(&direntry->d_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&direntry->d_sb->s_vfs_rename_sem); @@ -1016,7 +1175,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) 1 /* 45 seconds */); cFYI(1,("Wrt seteof rc %d", rc)); } - } + } else + rc = -EINVAL; + if (rc != 0) { /* Set file size by pathname rather than by handle either because no valid, writeable file handle for @@ -1088,6 +1249,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else if (attrs->ia_valid & ATTR_MODE) { + rc = 0; if ((mode & S_IWUGO) == 0) /* not writeable */ { if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) time_buf.Attributes = diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 34a06692e4f..94baf6c8ecb 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -397,12 +397,12 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) if(smb->Command == SMB_COM_LOCKING_ANDX) return 0; else - cERROR(1, ("Rcvd Request not response ")); + cERROR(1, ("Rcvd Request not response")); } } else { /* bad signature or mid */ if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) cERROR(1, - ("Bad protocol string signature header %x ", + ("Bad protocol string signature header %x", *(unsigned int *) smb->Protocol)); if (mid != smb->Mid) cERROR(1, ("Mids do not match")); @@ -417,7 +417,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) __u32 len = smb->smb_buf_length; __u32 clc_len; /* calculated length */ cFYI(0, - ("Entering checkSMB with Length: %x, smb_buf_length: %x ", + ("Entering checkSMB with Length: %x, smb_buf_length: %x", length, len)); if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { @@ -451,9 +451,16 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); /* Windows XP can return a few bytes too much, presumably an illegal pad, at the end of byte range lock responses - so we allow for up to eight byte pad, as long as actual + so we allow for that three byte pad, as long as actual received length is as long or longer than calculated length */ - if((4+len > clc_len) && (len <= clc_len + 3)) + /* We have now had to extend this more, since there is a + case in which it needs to be bigger still to handle a + malformed response to transact2 findfirst from WinXP when + access denied is returned and thus bcc and wct are zero + but server says length is 0x21 bytes too long as if the server + forget to reset the smb rfc1001 length when it reset the + wct and bcc to minimum size and drop the t2 parms and data */ + if((4+len > clc_len) && (len <= clc_len + 512)) return 0; else return 1; @@ -678,7 +685,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, __u16 temp; if(!mapChars) - return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); + return cifs_strtoUCS(target, source, PATH_MAX, cp); for(i = 0, j = 0; i < maxlen; j++) { src_char = source[i]; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index f7814689844..5de74d216fd 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -330,7 +330,7 @@ static const struct { ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { - ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, { + ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, { ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { @@ -676,7 +676,7 @@ static const struct { ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, { ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, { ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, { - ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, { + ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_MUST_CHANGE}, { ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, { ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, { ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index a86bd1c0760..9bdaaecae36 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -142,6 +142,11 @@ static void fill_in_inode(struct inode *tmp_inode, 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; + } else { + /* mask off the type bits since it gets set + below and we do not want to get two type + bits set */ + tmp_inode->i_mode &= ~S_IFMT; } if (attr & ATTR_DIRECTORY) { @@ -152,12 +157,18 @@ static void fill_in_inode(struct inode *tmp_inode, } tmp_inode->i_mode |= S_IFDIR; } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (attr & ATTR_SYSTEM) && (end_of_file == 0)) { - *pobject_type = DT_FIFO; - tmp_inode->i_mode |= S_IFIFO; -/* BB Finish for SFU style symlinks and devies */ -/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (attr & ATTR_SYSTEM) && ) { */ + (attr & ATTR_SYSTEM)) { + if (end_of_file == 0) { + *pobject_type = DT_FIFO; + tmp_inode->i_mode |= S_IFIFO; + } else { + /* rather than get the type here, we mark the + inode as needing revalidate and get the real type + (blk vs chr vs. symlink) later ie in lookup */ + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + cifsInfo->time = 0; + } /* we no longer mark these because we could not follow them */ /* } else if (attr & ATTR_REPARSE) { *pobject_type = DT_LNK; @@ -193,8 +204,14 @@ static void fill_in_inode(struct inode *tmp_inode, 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; + 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->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) @@ -258,6 +275,9 @@ static void unix_fill_in_inode(struct inode *tmp_inode, 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; @@ -283,6 +303,11 @@ static void unix_fill_in_inode(struct inode *tmp_inode, } 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)); } tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); @@ -699,7 +724,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, (__le16 *)filename, len/2, nlt); else pqst->len = cifs_strfromUCS_le((char *)pqst->name, - (wchar_t *)filename,len/2,nlt); + (__le16 *)filename,len/2,nlt); } else { pqst->name = filename; pqst->len = len; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 981ea0d8b9c..f8871196098 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -515,6 +515,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, *pbytes_returned = in_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ + /* BB special case Errbadpassword and pwdexpired here */ rc = map_smb_to_linux_error(in_buf); /* convert ByteCount if necessary */ @@ -522,7 +523,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, sizeof (struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * in_buf->WordCount) + 2 /* bcc */ ) - BCC(in_buf) = le16_to_cpu(BCC(in_buf)); + BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf)); } else { rc = -EIO; cFYI(1,("Bad MID state?")); @@ -786,7 +787,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, sizeof (struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) - BCC(out_buf) = le16_to_cpu(BCC(out_buf)); + BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { rc = -EIO; cERROR(1,("Bad MID state? ")); diff --git a/fs/compat.c b/fs/compat.c index 8e71cdbecc7..818634120b6 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -168,8 +168,8 @@ asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs if (!error) { struct kstatfs tmp; error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); - if (!error && put_compat_statfs(buf, &tmp)) - error = -EFAULT; + if (!error) + error = put_compat_statfs(buf, &tmp); path_release(&nd); } return error; @@ -186,8 +186,8 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user if (!file) goto out; error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp); - if (!error && put_compat_statfs(buf, &tmp)) - error = -EFAULT; + if (!error) + error = put_compat_statfs(buf, &tmp); fput(file); out: return error; @@ -236,8 +236,8 @@ asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, s if (!error) { struct kstatfs tmp; error = vfs_statfs(nd.dentry->d_inode->i_sb, &tmp); - if (!error && put_compat_statfs64(buf, &tmp)) - error = -EFAULT; + if (!error) + error = put_compat_statfs64(buf, &tmp); path_release(&nd); } return error; @@ -257,8 +257,8 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c if (!file) goto out; error = vfs_statfs(file->f_dentry->d_inode->i_sb, &tmp); - if (!error && put_compat_statfs64(buf, &tmp)) - error = -EFAULT; + if (!error) + error = put_compat_statfs64(buf, &tmp); fput(file); out: return error; @@ -268,7 +268,6 @@ out: #define IOCTL_HASHSIZE 256 static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; -static DECLARE_RWSEM(ioctl32_sem); extern struct ioctl_trans ioctl_start[]; extern int ioctl_table_size; @@ -390,14 +389,10 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, break; } - /* When register_ioctl32_conversion is finally gone remove - this lock! -AK */ - down_read(&ioctl32_sem); for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) { if (t->cmd == cmd) goto found_handler; } - up_read(&ioctl32_sem); if (S_ISSOCK(filp->f_dentry->d_inode->i_mode) && cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { @@ -417,11 +412,9 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, lock_kernel(); error = t->handler(fd, cmd, arg, filp); unlock_kernel(); - up_read(&ioctl32_sem); goto out_fput; } - up_read(&ioctl32_sem); do_ioctl: error = vfs_ioctl(filp, fd, cmd, arg); out_fput: diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 26300fccb4f..43a2508ac69 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -49,6 +49,8 @@ #include <linux/vt_kern.h> #include <linux/fb.h> #include <linux/ext2_fs.h> +#include <linux/ext3_jbd.h> +#include <linux/ext3_fs.h> #include <linux/videodev.h> #include <linux/netdevice.h> #include <linux/raw.h> @@ -121,6 +123,11 @@ #include <linux/hiddev.h> +#include <linux/dvb/audio.h> +#include <linux/dvb/dmx.h> +#include <linux/dvb/frontend.h> +#include <linux/dvb/video.h> + #undef INCLUDES #endif @@ -129,6 +136,15 @@ /* Aiee. Someone does not find a difference between int and long */ #define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) #define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) +#define EXT3_IOC32_GETVERSION _IOR('f', 3, int) +#define EXT3_IOC32_SETVERSION _IOW('f', 4, int) +#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int) +#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int) +#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int) +#ifdef CONFIG_JBD_DEBUG +#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int) +#endif + #define EXT2_IOC32_GETVERSION _IOR('v', 1, int) #define EXT2_IOC32_SETVERSION _IOW('v', 2, int) @@ -175,6 +191,22 @@ static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg)); } +static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* These are just misnamed, they actually get/put from/to user an int */ + switch (cmd) { + case EXT3_IOC32_GETVERSION: cmd = EXT3_IOC_GETVERSION; break; + case EXT3_IOC32_SETVERSION: cmd = EXT3_IOC_SETVERSION; break; + case EXT3_IOC32_GETRSVSZ: cmd = EXT3_IOC_GETRSVSZ; break; + case EXT3_IOC32_SETRSVSZ: cmd = EXT3_IOC_SETRSVSZ; break; + case EXT3_IOC32_GROUP_EXTEND: cmd = EXT3_IOC_GROUP_EXTEND; break; +#ifdef CONFIG_JBD_DEBUG + case EXT3_IOC32_WAIT_FOR_READONLY: cmd = EXT3_IOC_WAIT_FOR_READONLY; break; +#endif + } + return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg)); +} + struct video_tuner32 { compat_int_t tuner; char name[32]; @@ -413,6 +445,128 @@ out: return err; } +struct compat_dmx_event { + dmx_event_t event; + compat_time_t timeStamp; + union + { + dmx_scrambling_status_t scrambling; + } u; +}; + +static int do_dmx_get_event(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct dmx_event kevent; + mm_segment_t old_fs = get_fs(); + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long) &kevent); + set_fs(old_fs); + + if (!err) { + struct compat_dmx_event __user *up = compat_ptr(arg); + + err = put_user(kevent.event, &up->event); + err |= put_user(kevent.timeStamp, &up->timeStamp); + err |= put_user(kevent.u.scrambling, &up->u.scrambling); + if (err) + err = -EFAULT; + } + + return err; +} + +struct compat_video_event { + int32_t type; + compat_time_t timestamp; + union { + video_size_t size; + unsigned int frame_rate; + } u; +}; + +static int do_video_get_event(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct video_event kevent; + mm_segment_t old_fs = get_fs(); + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long) &kevent); + set_fs(old_fs); + + if (!err) { + struct compat_video_event __user *up = compat_ptr(arg); + + err = put_user(kevent.type, &up->type); + err |= put_user(kevent.timestamp, &up->timestamp); + err |= put_user(kevent.u.size.w, &up->u.size.w); + err |= put_user(kevent.u.size.h, &up->u.size.h); + err |= put_user(kevent.u.size.aspect_ratio, + &up->u.size.aspect_ratio); + if (err) + err = -EFAULT; + } + + return err; +} + +struct compat_video_still_picture { + compat_uptr_t iFrame; + int32_t size; +}; + +static int do_video_stillpicture(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct compat_video_still_picture __user *up; + struct video_still_picture __user *up_native; + compat_uptr_t fp; + int32_t size; + int err; + + up = (struct compat_video_still_picture __user *) arg; + err = get_user(fp, &up->iFrame); + err |= get_user(size, &up->size); + if (err) + return -EFAULT; + + up_native = + compat_alloc_user_space(sizeof(struct video_still_picture)); + + put_user(compat_ptr(fp), &up_native->iFrame); + put_user(size, &up_native->size); + + err = sys_ioctl(fd, cmd, (unsigned long) up_native); + + return err; +} + +struct compat_video_spu_palette { + int length; + compat_uptr_t palette; +}; + +static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct compat_video_spu_palette __user *up; + struct video_spu_palette __user *up_native; + compat_uptr_t palp; + int length, err; + + up = (struct compat_video_spu_palette __user *) arg; + err = get_user(palp, &up->palette); + err |= get_user(length, &up->length); + + up_native = compat_alloc_user_space(sizeof(struct video_spu_palette)); + put_user(compat_ptr(palp), &up_native->palette); + put_user(length, &up_native->length); + + err = sys_ioctl(fd, cmd, (unsigned long) up_native); + + return err; +} + #ifdef CONFIG_NET static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) { @@ -532,7 +686,8 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) ifr = ifc.ifc_req; ifr32 = compat_ptr(ifc32.ifcbuf); - for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; + for (i = 0, j = 0; + i + sizeof (struct ifreq32) < ifc32.ifc_len && j < ifc.ifc_len; i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) return -EFAULT; @@ -548,10 +703,7 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); ifc32.ifc_len = i; } else { - if (i <= ifc32.ifc_len) - ifc32.ifc_len = i; - else - ifc32.ifc_len = i - sizeof (struct ifreq32); + ifc32.ifc_len = i; } if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32))) return -EFAULT; @@ -2854,6 +3006,15 @@ HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl) HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl) HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl) HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl) +HANDLE_IOCTL(EXT3_IOC32_GETVERSION, do_ext3_ioctl) +HANDLE_IOCTL(EXT3_IOC32_SETVERSION, do_ext3_ioctl) +HANDLE_IOCTL(EXT3_IOC32_GETRSVSZ, do_ext3_ioctl) +HANDLE_IOCTL(EXT3_IOC32_SETRSVSZ, do_ext3_ioctl) +HANDLE_IOCTL(EXT3_IOC32_GROUP_EXTEND, do_ext3_ioctl) +COMPATIBLE_IOCTL(EXT3_IOC_GROUP_ADD) +#ifdef CONFIG_JBD_DEBUG +HANDLE_IOCTL(EXT3_IOC32_WAIT_FOR_READONLY, do_ext3_ioctl) +#endif HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl) HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl) HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl) @@ -2954,5 +3115,11 @@ HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata) HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata) #endif +/* dvb */ +HANDLE_IOCTL(DMX_GET_EVENT, do_dmx_get_event) +HANDLE_IOCTL(VIDEO_GET_EVENT, do_video_get_event) +HANDLE_IOCTL(VIDEO_STILLPICTURE, do_video_stillpicture) +HANDLE_IOCTL(VIDEO_SET_SPU_PALETTE, do_video_set_spu_palette) + #undef DECLARES #endif diff --git a/fs/dquot.c b/fs/dquot.c index 05b60283c9c..2a62b3dc20e 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -1513,10 +1513,16 @@ int vfs_quota_on_mount(struct super_block *sb, char *qf_name, if (IS_ERR(dentry)) return PTR_ERR(dentry); + if (!dentry->d_inode) { + error = -ENOENT; + goto out; + } + error = security_quota_on(dentry); if (!error) error = vfs_quota_on_inode(dentry->d_inode, type, format_id); +out: dput(dentry); return error; } diff --git a/fs/exec.c b/fs/exec.c index c466fec5de2..22533cce061 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -306,9 +306,6 @@ void install_arg_page(struct vm_area_struct *vma, struct page *page, unsigned long address) { struct mm_struct *mm = vma->vm_mm; - pgd_t * pgd; - pud_t * pud; - pmd_t * pmd; pte_t * pte; spinlock_t *ptl; @@ -316,14 +313,7 @@ void install_arg_page(struct vm_area_struct *vma, goto out; flush_dcache_page(page); - pgd = pgd_offset(mm, address); - pud = pud_alloc(mm, pgd, address); - if (!pud) - goto out; - pmd = pmd_alloc(mm, pud, address); - if (!pmd) - goto out; - pte = pte_alloc_map_lock(mm, pmd, address, &ptl); + pte = get_locked_pte(mm, address, &ptl); if (!pte) goto out; if (!pte_none(*pte)) { @@ -668,7 +658,7 @@ static inline int de_thread(struct task_struct *tsk) if (!thread_group_leader(current)) { struct task_struct *parent; struct dentry *proc_dentry1, *proc_dentry2; - unsigned long exit_state, ptrace; + unsigned long ptrace; /* * Wait for the thread group leader to be a zombie. @@ -726,15 +716,15 @@ static inline int de_thread(struct task_struct *tsk) list_del(¤t->tasks); list_add_tail(¤t->tasks, &init_task.tasks); current->exit_signal = SIGCHLD; - exit_state = leader->exit_state; + + BUG_ON(leader->exit_state != EXIT_ZOMBIE); + leader->exit_state = EXIT_DEAD; write_unlock_irq(&tasklist_lock); spin_unlock(&leader->proc_lock); spin_unlock(¤t->proc_lock); proc_pid_flush(proc_dentry1); proc_pid_flush(proc_dentry2); - - BUG_ON(exit_state != EXIT_ZOMBIE); } /* diff --git a/fs/ext2/super.c b/fs/ext2/super.c index e4ed4b31a43..522fa70dd8e 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -881,7 +881,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) } if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) ext2_warning(sb, __FUNCTION__, - "mounting ext3 filesystem as ext2\n"); + "mounting ext3 filesystem as ext2"); ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY); percpu_counter_mod(&sbi->s_freeblocks_counter, ext2_count_free_blocks(sb)); diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 5d9b00e2883..8824e84f8a5 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1384,8 +1384,10 @@ static int ext3_journalled_writepage(struct page *page, ClearPageChecked(page); ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, ext3_get_block); - if (ret != 0) + if (ret != 0) { + ext3_journal_stop(handle); goto out_unlock; + } ret = walk_page_buffers(handle, page_buffers(page), 0, PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 1be78b4b4de..6104ad31050 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -767,6 +767,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) if (input->group != EXT3_SB(sb)->s_groups_count) { ext3_warning(sb, __FUNCTION__, "multiple resizers run on filesystem!\n"); + err = -EBUSY; goto exit_journal; } diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c index d3f6b2835bc..2d71128bd8d 100644 --- a/fs/freevxfs/vxfs_bmap.c +++ b/fs/freevxfs/vxfs_bmap.c @@ -36,6 +36,7 @@ #include "vxfs.h" #include "vxfs_inode.h" +#include "vxfs_extern.h" #ifdef DIAGNOSTIC diff --git a/fs/freevxfs/vxfs_olt.c b/fs/freevxfs/vxfs_olt.c index 133476201d8..76a0708ae97 100644 --- a/fs/freevxfs/vxfs_olt.c +++ b/fs/freevxfs/vxfs_olt.c @@ -36,6 +36,7 @@ #include "vxfs.h" #include "vxfs_olt.h" +#include "vxfs_extern.h" static inline void diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index c045cc70c74..51f5da65277 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -74,6 +74,24 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) return 1; } +static int dir_alias(struct inode *inode) +{ + if (S_ISDIR(inode->i_mode)) { + /* Don't allow creating an alias to a directory */ + struct dentry *alias = d_find_alias(inode); + if (alias) { + dput(alias); + return 1; + } + } + return 0; +} + +static inline int invalid_nodeid(u64 nodeid) +{ + return !nodeid || nodeid == FUSE_ROOT_ID; +} + static struct dentry_operations fuse_dentry_operations = { .d_revalidate = fuse_dentry_revalidate, }; @@ -97,7 +115,7 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry, fuse_lookup_init(req, dir, entry, &outarg); request_send(fc, req); err = req->out.h.error; - if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID)) + if (!err && invalid_nodeid(outarg.nodeid)) err = -EIO; if (!err) { inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, @@ -193,7 +211,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, } err = -EIO; - if (!S_ISREG(outentry.attr.mode)) + if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) goto out_free_ff; inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, @@ -250,7 +268,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, fuse_put_request(fc, req); return err; } - if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) { + if (invalid_nodeid(outarg.nodeid)) { fuse_put_request(fc, req); return -EIO; } @@ -263,7 +281,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, fuse_put_request(fc, req); /* Don't allow userspace to do really stupid things... */ - if ((inode->i_mode ^ mode) & S_IFMT) { + if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) { iput(inode); return -EIO; } @@ -874,14 +892,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, err = fuse_lookup_iget(dir, entry, &inode); if (err) return ERR_PTR(err); - if (inode && S_ISDIR(inode->i_mode)) { - /* Don't allow creating an alias to a directory */ - struct dentry *alias = d_find_alias(inode); - if (alias) { - dput(alias); - iput(inode); - return ERR_PTR(-EIO); - } + if (inode && dir_alias(inode)) { + iput(inode); + return ERR_PTR(-EIO); } d_add(entry, inode); return NULL; diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index c60e5635498..df16fcbff3f 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -151,6 +151,7 @@ struct hfsplus_sb_info { #define HFSPLUS_SB_WRITEBACKUP 0x0001 #define HFSPLUS_SB_NODECOMPOSE 0x0002 +#define HFSPLUS_SB_FORCE 0x0004 struct hfsplus_inode_info { diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index 5bad37cfdb2..b4fbed63321 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h @@ -123,11 +123,13 @@ struct hfsplus_vh { } __packed; /* HFS+ volume attributes */ -#define HFSPLUS_VOL_UNMNT (1 << 8) -#define HFSPLUS_VOL_SPARE_BLK (1 << 9) -#define HFSPLUS_VOL_NOCACHE (1 << 10) -#define HFSPLUS_VOL_INCNSTNT (1 << 11) -#define HFSPLUS_VOL_SOFTLOCK (1 << 15) +#define HFSPLUS_VOL_UNMNT (1 << 8) +#define HFSPLUS_VOL_SPARE_BLK (1 << 9) +#define HFSPLUS_VOL_NOCACHE (1 << 10) +#define HFSPLUS_VOL_INCNSTNT (1 << 11) +#define HFSPLUS_VOL_NODEID_REUSED (1 << 12) +#define HFSPLUS_VOL_JOURNALED (1 << 13) +#define HFSPLUS_VOL_SOFTLOCK (1 << 15) /* HFS+ BTree node descriptor */ struct hfs_bnode_desc { diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c index cca0818aa4c..935dafba007 100644 --- a/fs/hfsplus/options.c +++ b/fs/hfsplus/options.c @@ -22,7 +22,7 @@ enum { opt_umask, opt_uid, opt_gid, opt_part, opt_session, opt_nls, opt_nodecompose, opt_decompose, - opt_err + opt_force, opt_err }; static match_table_t tokens = { @@ -36,6 +36,7 @@ static match_table_t tokens = { { opt_nls, "nls=%s" }, { opt_decompose, "decompose" }, { opt_nodecompose, "nodecompose" }, + { opt_force, "force" }, { opt_err, NULL } }; @@ -145,6 +146,9 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) case opt_nodecompose: sbi->flags |= HFSPLUS_SB_NODECOMPOSE; break; + case opt_force: + sbi->flags |= HFSPLUS_SB_FORCE; + break; default: return 0; } diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 0ce1c455ae5..8093351bd7c 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -251,16 +251,28 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data) return 0; if (!(*flags & MS_RDONLY)) { struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; + struct hfsplus_sb_info sbi; + + memset(&sbi, 0, sizeof(struct hfsplus_sb_info)); + sbi.nls = HFSPLUS_SB(sb).nls; + if (!hfsplus_parse_options(data, &sbi)) + return -EINVAL; if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " "running fsck.hfsplus is recommended. leaving read-only.\n"); sb->s_flags |= MS_RDONLY; *flags |= MS_RDONLY; + } else if (sbi.flags & HFSPLUS_SB_FORCE) { + /* nothing */ } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { printk("HFS+-fs: Filesystem is marked locked, leaving read-only.\n"); sb->s_flags |= MS_RDONLY; *flags |= MS_RDONLY; + } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { + printk("HFS+-fs: Filesystem is marked journaled, leaving read-only.\n"); + sb->s_flags |= MS_RDONLY; + *flags |= MS_RDONLY; } } return 0; @@ -352,11 +364,19 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " "running fsck.hfsplus is recommended. mounting read-only.\n"); sb->s_flags |= MS_RDONLY; + } else if (sbi->flags & HFSPLUS_SB_FORCE) { + /* nothing */ } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { if (!silent) printk("HFS+-fs: Filesystem is marked locked, mounting read-only.\n"); sb->s_flags |= MS_RDONLY; + } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { + if (!silent) + printk("HFS+-fs: write access to a jounaled filesystem is not supported, " + "use the force option at your own risk, mounting read-only.\n"); + sb->s_flags |= MS_RDONLY; } + sbi->flags &= ~HFSPLUS_SB_FORCE; /* Load metadata objects (B*Trees) */ HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 4684eb7d48c..b3ad0bd0312 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -501,11 +501,16 @@ int hostfs_commit_write(struct file *file, struct page *page, unsigned from, long long start; int err = 0; - start = (long long) (page->index << PAGE_CACHE_SHIFT) + from; + start = (((long long) page->index) << PAGE_CACHE_SHIFT) + from; buffer = kmap(page); err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from, to - from); if(err > 0) err = 0; + + /* Actually, if !err, write_file has added to-from to start, so, despite + * the appearance, we are comparing i_size against the _last_ written + * location, as we should. */ + if(!err && (start > inode->i_size)) inode->i_size = start; @@ -910,10 +915,8 @@ static struct inode_operations hostfs_dir_iops = { int hostfs_link_readpage(struct file *file, struct page *page) { char *buffer, *name; - long long start; int err; - start = page->index << PAGE_CACHE_SHIFT; buffer = kmap(page); name = inode_name(page->mapping->host, 0); if(name == NULL) return(-ENOMEM); diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 64983ab5558..8c1cef3bb67 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -512,10 +512,14 @@ static int hugetlbfs_statfs(struct super_block *sb, struct kstatfs *buf) buf->f_bsize = HPAGE_SIZE; if (sbinfo) { spin_lock(&sbinfo->stat_lock); - buf->f_blocks = sbinfo->max_blocks; - buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; - buf->f_files = sbinfo->max_inodes; - buf->f_ffree = sbinfo->free_inodes; + /* If no limits set, just report 0 for max/free/used + * blocks, like simple_statfs() */ + if (sbinfo->max_blocks >= 0) { + buf->f_blocks = sbinfo->max_blocks; + buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; + buf->f_files = sbinfo->max_inodes; + buf->f_ffree = sbinfo->free_inodes; + } spin_unlock(&sbinfo->stat_lock); } buf->f_namelen = NAME_MAX; diff --git a/fs/inotify.c b/fs/inotify.c index bf7ce1d2412..2fecb7af4a7 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -364,11 +364,12 @@ static int inotify_dev_get_wd(struct inotify_device *dev, /* * find_inode - resolve a user-given path to a specific inode and return a nd */ -static int find_inode(const char __user *dirname, struct nameidata *nd) +static int find_inode(const char __user *dirname, struct nameidata *nd, + unsigned flags) { int error; - error = __user_walk(dirname, LOOKUP_FOLLOW, nd); + error = __user_walk(dirname, flags, nd); if (error) return error; /* you can only watch an inode if you have read permissions on it */ @@ -933,6 +934,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) struct file *filp; int ret, fput_needed; int mask_add = 0; + unsigned flags = 0; filp = fget_light(fd, &fput_needed); if (unlikely(!filp)) @@ -944,7 +946,12 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) goto fput_and_out; } - ret = find_inode(path, &nd); + if (!(mask & IN_DONT_FOLLOW)) + flags |= LOOKUP_FOLLOW; + if (mask & IN_ONLYDIR) + flags |= LOOKUP_DIRECTORY; + + ret = find_inode(path, &nd, flags); if (unlikely(ret)) goto fput_and_out; diff --git a/fs/ioprio.c b/fs/ioprio.c index d1c1f2b2c9d..4bf1c6365a1 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -22,6 +22,7 @@ #include <linux/kernel.h> #include <linux/ioprio.h> #include <linux/blkdev.h> +#include <linux/syscalls.h> static int set_task_ioprio(struct task_struct *task, int ioprio) { diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c index 053e3a98a27..6da13b309bd 100644 --- a/fs/jffs/jffs_fm.c +++ b/fs/jffs/jffs_fm.c @@ -20,6 +20,7 @@ #include <linux/blkdev.h> #include <linux/jffs.h> #include "jffs_fm.h" +#include "intrep.h" #if defined(JFFS_MARK_OBSOLETE) && JFFS_MARK_OBSOLETE static int jffs_mark_obsolete(struct jffs_fmcontrol *fmc, __u32 fm_offset); diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index f193d43a8a5..162af6dfe29 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h @@ -82,28 +82,28 @@ do { \ printk(JFFS2_ERR_MSG_PREFIX \ " (%d) %s: " fmt, current->pid, \ - __FUNCTION__, ##__VA_ARGS__); \ + __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_WARNING(fmt, ...) \ do { \ printk(JFFS2_WARN_MSG_PREFIX \ " (%d) %s: " fmt, current->pid, \ - __FUNCTION__, ##__VA_ARGS__); \ + __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_NOTICE(fmt, ...) \ do { \ printk(JFFS2_NOTICE_MSG_PREFIX \ " (%d) %s: " fmt, current->pid, \ - __FUNCTION__, ##__VA_ARGS__); \ + __FUNCTION__ , ##__VA_ARGS__); \ } while(0) #define JFFS2_DEBUG(fmt, ...) \ do { \ printk(JFFS2_DBG_MSG_PREFIX \ " (%d) %s: " fmt, current->pid, \ - __FUNCTION__, ##__VA_ARGS__); \ + __FUNCTION__ , ##__VA_ARGS__); \ } while(0) /* diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 543420665c5..d0fcc5f3497 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -234,6 +234,7 @@ void jffs2_read_inode (struct inode *inode) c = JFFS2_SB_INFO(inode->i_sb); jffs2_init_inode_info(f); + down(&f->sem); ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); @@ -400,6 +401,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i f = JFFS2_INODE_INFO(inode); jffs2_init_inode_info(f); + down(&f->sem); memset(ri, 0, sizeof(*ri)); /* Set OS-specific defaults for new inodes */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 0e7456ec99f..3e51dd1da8a 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -284,9 +284,6 @@ int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf, D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen)); return -EIO; } - D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs)); - D2(printk(KERN_DEBUG "000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15])); return 0; } diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 9e0b5458d9c..93883817cbd 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -51,7 +51,7 @@ static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long f if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { - init_MUTEX_LOCKED(&ei->sem); + init_MUTEX(&ei->sem); inode_init_once(&ei->vfs_inode); } } diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 006bb9e1457..3eaf6e70108 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -157,6 +157,8 @@ void nlmclnt_mark_reclaim(struct nlm_host *host) inode = fl->fl_file->f_dentry->d_inode; if (inode->i_sb->s_magic != NFS_SUPER_MAGIC) continue; + if (fl->fl_u.nfs_fl.owner == NULL) + continue; if (fl->fl_u.nfs_fl.owner->host != host) continue; if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_GRANTED)) @@ -226,6 +228,8 @@ restart: inode = fl->fl_file->f_dentry->d_inode; if (inode->i_sb->s_magic != NFS_SUPER_MAGIC) continue; + if (fl->fl_u.nfs_fl.owner == NULL) + continue; if (fl->fl_u.nfs_fl.owner->host != host) continue; if (!(fl->fl_u.nfs_fl.flags & NFS_LCK_RECLAIM)) diff --git a/fs/locks.c b/fs/locks.c index a1e8b224801..250ef53d25e 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1105,7 +1105,6 @@ static void time_out_leases(struct inode *inode) before = &fl->fl_next; continue; } - printk(KERN_INFO "lease broken - owner pid = %d\n", fl->fl_pid); lease_modify(before, fl->fl_type & ~F_INPROGRESS); if (fl == *before) /* lease_modify may have freed fl */ before = &fl->fl_next; @@ -1430,7 +1429,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) lock_kernel(); error = __setlease(filp, arg, &flp); - if (error) + if (error || arg == F_UNLCK) goto out_unlock; error = fasync_helper(fd, filp, 1, &flp->fl_fasync); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 7370583b61e..c0d1a214572 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1287,6 +1287,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name); nfs_begin_data_update(dentry->d_inode); error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly); + nfs_mark_for_revalidate(dentry->d_inode); nfs_end_data_update(dentry->d_inode); } else error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, @@ -1334,6 +1335,7 @@ static int nfs_safe_remove(struct dentry *dentry) /* The VFS may want to delete this inode */ if (error == 0) inode->i_nlink--; + nfs_mark_for_revalidate(inode); nfs_end_data_update(inode); } else error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); @@ -1556,6 +1558,7 @@ go_ahead: nfs_begin_data_update(old_inode); error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); + nfs_mark_for_revalidate(old_inode); nfs_end_data_update(old_inode); nfs_end_data_update(new_dir); nfs_end_data_update(old_dir); diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index b497c71384e..07922881760 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -678,15 +678,9 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t if (!count) goto out; - if (mapping->nrpages) { - retval = filemap_fdatawrite(mapping); - if (retval == 0) - retval = nfs_wb_all(inode); - if (retval == 0) - retval = filemap_fdatawait(mapping); - if (retval) - goto out; - } + retval = nfs_sync_mapping(mapping); + if (retval) + goto out; retval = nfs_direct_read(inode, ctx, &iov, pos, 1); if (retval > 0) @@ -764,15 +758,9 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, if (!count) goto out; - if (mapping->nrpages) { - retval = filemap_fdatawrite(mapping); - if (retval == 0) - retval = nfs_wb_all(inode); - if (retval == 0) - retval = filemap_fdatawait(mapping); - if (retval) - goto out; - } + retval = nfs_sync_mapping(mapping); + if (retval) + goto out; retval = nfs_direct_write(inode, ctx, &iov, pos, 1); if (mapping->nrpages) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 57d3e77d97e..7a79fbe9f53 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -433,11 +433,7 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) * Flush all pending writes before doing anything * with locks.. */ - filemap_fdatawrite(filp->f_mapping); - down(&inode->i_sem); - nfs_wb_all(inode); - up(&inode->i_sem); - filemap_fdatawait(filp->f_mapping); + nfs_sync_mapping(filp->f_mapping); /* NOTE: special case * If we're signalled while cleaning up locks on process exit, we @@ -465,15 +461,8 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) * Flush all pending writes before doing anything * with locks.. */ - status = filemap_fdatawrite(filp->f_mapping); - if (status == 0) { - down(&inode->i_sem); - status = nfs_wb_all(inode); - up(&inode->i_sem); - if (status == 0) - status = filemap_fdatawait(filp->f_mapping); - } - if (status < 0) + status = nfs_sync_mapping(filp->f_mapping); + if (status != 0) goto out; lock_kernel(); @@ -497,11 +486,7 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) * Make sure we clear the cache whenever we try to get the lock. * This makes locking act as a cache coherency point. */ - filemap_fdatawrite(filp->f_mapping); - down(&inode->i_sem); - nfs_wb_all(inode); /* we may have slept */ - up(&inode->i_sem); - filemap_fdatawait(filp->f_mapping); + nfs_sync_mapping(filp->f_mapping); nfs_zap_caches(inode); out: rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset); @@ -524,7 +509,8 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) return -EINVAL; /* No mandatory locks over NFS */ - if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID && + fl->fl_type != F_UNLCK) return -ENOLCK; if (IS_GETLK(cmd)) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6391d896421..432f41cd75e 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -54,7 +54,7 @@ #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) static void nfs_invalidate_inode(struct inode *); -static int nfs_update_inode(struct inode *, struct nfs_fattr *, unsigned long); +static int nfs_update_inode(struct inode *, struct nfs_fattr *); static struct inode *nfs_alloc_inode(struct super_block *sb); static void nfs_destroy_inode(struct inode *); @@ -640,17 +640,35 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) return 0; } +/** + * nfs_sync_mapping - helper to flush all mmapped dirty data to disk + */ +int nfs_sync_mapping(struct address_space *mapping) +{ + int ret; + + if (mapping->nrpages == 0) + return 0; + unmap_mapping_range(mapping, 0, 0, 0); + ret = filemap_fdatawrite(mapping); + if (ret != 0) + goto out; + ret = filemap_fdatawait(mapping); + if (ret != 0) + goto out; + ret = nfs_wb_all(mapping->host); +out: + return ret; +} + /* * Invalidate the local caches */ -void -nfs_zap_caches(struct inode *inode) +static void nfs_zap_caches_locked(struct inode *inode) { struct nfs_inode *nfsi = NFS_I(inode); int mode = inode->i_mode; - spin_lock(&inode->i_lock); - NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; @@ -659,7 +677,12 @@ nfs_zap_caches(struct inode *inode) nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; else nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; +} +void nfs_zap_caches(struct inode *inode) +{ + spin_lock(&inode->i_lock); + nfs_zap_caches_locked(inode); spin_unlock(&inode->i_lock); } @@ -676,16 +699,13 @@ static void nfs_zap_acl_cache(struct inode *inode) } /* - * Invalidate, but do not unhash, the inode + * Invalidate, but do not unhash, the inode. + * NB: must be called with inode->i_lock held! */ -static void -nfs_invalidate_inode(struct inode *inode) +static void nfs_invalidate_inode(struct inode *inode) { - umode_t save_mode = inode->i_mode; - - make_bad_inode(inode); - inode->i_mode = save_mode; - nfs_zap_caches(inode); + set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); + nfs_zap_caches_locked(inode); } struct nfs_find_desc { @@ -1081,8 +1101,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) int status = -ESTALE; struct nfs_fattr fattr; struct nfs_inode *nfsi = NFS_I(inode); - unsigned long verifier; - unsigned long cache_validity; dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); @@ -1107,8 +1125,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) } } - /* Protect against RPC races by saving the change attribute */ - verifier = nfs_save_change_attribute(inode); status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr); if (status != 0) { dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", @@ -1123,7 +1139,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) } spin_lock(&inode->i_lock); - status = nfs_update_inode(inode, &fattr, verifier); + status = nfs_update_inode(inode, &fattr); if (status) { spin_unlock(&inode->i_lock); dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", @@ -1131,20 +1147,11 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) (long long)NFS_FILEID(inode), status); goto out; } - cache_validity = nfsi->cache_validity; - nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; - - /* - * We may need to keep the attributes marked as invalid if - * we raced with nfs_end_attr_update(). - */ - if (time_after_eq(verifier, nfsi->cache_change_attribute)) - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); spin_unlock(&inode->i_lock); nfs_revalidate_mapping(inode, inode->i_mapping); - if (cache_validity & NFS_INO_INVALID_ACL) + if (nfsi->cache_validity & NFS_INO_INVALID_ACL) nfs_zap_acl_cache(inode); dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", @@ -1193,11 +1200,8 @@ void nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) struct nfs_inode *nfsi = NFS_I(inode); if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { - if (S_ISREG(inode->i_mode)) { - if (filemap_fdatawrite(mapping) == 0) - filemap_fdatawait(mapping); - nfs_wb_all(inode); - } + if (S_ISREG(inode->i_mode)) + nfs_sync_mapping(mapping); invalidate_inode_pages2(mapping); spin_lock(&inode->i_lock); @@ -1347,10 +1351,8 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) return 0; spin_lock(&inode->i_lock); nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE; - if (nfs_verify_change_attribute(inode, fattr->time_start)) - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); if (time_after(fattr->time_start, nfsi->last_updated)) - status = nfs_update_inode(inode, fattr, fattr->time_start); + status = nfs_update_inode(inode, fattr); else status = nfs_check_inode_attributes(inode, fattr); @@ -1376,10 +1378,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS; goto out; } - status = nfs_update_inode(inode, fattr, fattr->time_start); - if (time_after_eq(fattr->time_start, nfsi->cache_change_attribute)) - nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); - nfsi->cache_change_attribute = jiffies; + status = nfs_update_inode(inode, fattr); out: spin_unlock(&inode->i_lock); return status; @@ -1397,12 +1396,12 @@ out: * * A very similar scenario holds for the dir cache. */ -static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) +static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) { struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_isize, new_isize; unsigned int invalid = 0; - int data_unstable; + int data_stable; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", __FUNCTION__, inode->i_sb->s_id, inode->i_ino, @@ -1433,8 +1432,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign nfsi->last_updated = jiffies; /* Are we racing with known updates of the metadata on the server? */ - data_unstable = ! (nfs_verify_change_attribute(inode, verifier) || - (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)); + data_stable = nfs_verify_change_attribute(inode, fattr->time_start); + if (data_stable) + nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); /* Check if our cached file size is stale */ new_isize = nfs_size_to_loff_t(fattr->size); @@ -1443,7 +1443,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign /* Do we perhaps have any outstanding writes? */ if (nfsi->npages == 0) { /* No, but did we race with nfs_end_data_update()? */ - if (time_after_eq(verifier, nfsi->cache_change_attribute)) { + if (data_stable) { inode->i_size = new_isize; invalid |= NFS_INO_INVALID_DATA; } @@ -1452,6 +1452,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign inode->i_size = new_isize; invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } + nfsi->cache_change_attribute = jiffies; dprintk("NFS: isize change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); } @@ -1461,8 +1462,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); dprintk("NFS: mtime change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); - if (!data_unstable) - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; + nfsi->cache_change_attribute = jiffies; } if ((fattr->valid & NFS_ATTR_FATTR_V4) @@ -1470,15 +1471,15 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign dprintk("NFS: change_attr change on server for file %s/%ld\n", inode->i_sb->s_id, inode->i_ino); nfsi->change_attr = fattr->change_attr; - if (!data_unstable) - invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + nfsi->cache_change_attribute = jiffies; } /* If ctime has changed we should definitely clear access+acl caches */ if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) { - if (!data_unstable) - invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; + invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); + nfsi->cache_change_attribute = jiffies; } memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); @@ -1516,6 +1517,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) invalid &= ~NFS_INO_INVALID_DATA; + if (data_stable) + invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE); if (!nfs_have_delegation(inode, FMODE_READ)) nfsi->cache_validity |= invalid; @@ -1528,14 +1531,13 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode); #endif + out_err: /* * No need to worry about unhashing the dentry, as the * lookup validation will know that the inode is bad. * (But we fall through to invalidate the caches.) */ nfs_invalidate_inode(inode); - out_err: - set_bit(NFS_INO_STALE, &NFS_FLAGS(inode)); return -ESTALE; } @@ -2068,6 +2070,7 @@ static struct inode *nfs_alloc_inode(struct super_block *sb) return NULL; nfsi->flags = 0UL; nfsi->cache_validity = 0UL; + nfsi->cache_change_attribute = jiffies; #ifdef CONFIG_NFS_V3_ACL nfsi->acl_access = ERR_PTR(-EAGAIN); nfsi->acl_default = ERR_PTR(-EAGAIN); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 21482b2518f..f988a9417b1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1506,10 +1506,15 @@ static int _nfs4_proc_write(struct nfs_write_data *wdata) dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); + wdata->args.bitmask = server->attr_bitmask; + wdata->res.server = server; nfs_fattr_init(fattr); status = rpc_call_sync(server->client, &msg, rpcflags); dprintk("NFS reply write: %d\n", status); - return status; + if (status < 0) + return status; + nfs_post_op_update_inode(inode, fattr); + return wdata->res.count; } static int nfs4_proc_write(struct nfs_write_data *wdata) @@ -1540,9 +1545,13 @@ static int _nfs4_proc_commit(struct nfs_write_data *cdata) dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, (long long) cdata->args.offset); + cdata->args.bitmask = server->attr_bitmask; + cdata->res.server = server; nfs_fattr_init(fattr); status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply commit: %d\n", status); + if (status >= 0) + nfs_post_op_update_inode(inode, fattr); return status; } @@ -3071,15 +3080,15 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock struct nfs4_client *clp = state->owner->so_client; int status; - down_read(&clp->cl_sem); /* Is this a delegated open? */ - if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { + if (NFS_I(state->inode)->delegation_state != 0) { /* Yes: cache locks! */ status = do_vfs_lock(request->fl_file, request); /* ...but avoid races with delegation recall... */ if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags)) - goto out; + return status; } + down_read(&clp->cl_sem); status = nfs4_set_lock_state(state, request); if (status != 0) goto out; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0675f3215e0..5ef4c57618f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -644,12 +644,15 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) { + struct rpc_sequence *sequence = counter->sequence; struct nfs_seqid *new; new = kmalloc(sizeof(*new), GFP_KERNEL); if (new != NULL) { new->sequence = counter; - INIT_LIST_HEAD(&new->list); + spin_lock(&sequence->lock); + list_add_tail(&new->list, &sequence->list); + spin_unlock(&sequence->lock); } return new; } @@ -658,12 +661,10 @@ void nfs_free_seqid(struct nfs_seqid *seqid) { struct rpc_sequence *sequence = seqid->sequence->sequence; - if (!list_empty(&seqid->list)) { - spin_lock(&sequence->lock); - list_del(&seqid->list); - spin_unlock(&sequence->lock); - } - rpc_wake_up_next(&sequence->wait); + spin_lock(&sequence->lock); + list_del(&seqid->list); + spin_unlock(&sequence->lock); + rpc_wake_up(&sequence->wait); kfree(seqid); } @@ -722,11 +723,10 @@ int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task) if (sequence->list.next == &seqid->list) goto out; spin_lock(&sequence->lock); - if (!list_empty(&sequence->list)) { + if (sequence->list.next != &seqid->list) { rpc_sleep_on(&sequence->wait, task, NULL, NULL); status = -EAGAIN; - } else - list_add(&seqid->list, &sequence->list); + } spin_unlock(&sequence->lock); out: return status; diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index a48a003242c..e1e3ca5d746 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -375,6 +375,7 @@ nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) dprintk("NFS call link %s\n", name->name); status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0); + nfs_mark_for_revalidate(inode); nfs_mark_for_revalidate(dir); dprintk("NFS reply link: %d\n", status); return status; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 8f71e766cc5..3107908e5f3 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -189,6 +189,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, (long long)NFS_FILEID(inode), count, (long long)(page_offset(page) + offset)); + set_page_writeback(page); nfs_begin_data_update(inode); do { if (count < wsize) @@ -221,6 +222,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, io_error: nfs_end_data_update(inode); + end_page_writeback(page); nfs_writedata_free(wdata); return written ? written : result; } @@ -929,7 +931,7 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) atomic_set(&req->wb_complete, requests); ClearPageError(page); - SetPageWriteback(page); + set_page_writeback(page); offset = 0; nbytes = req->wb_bytes; do { @@ -992,7 +994,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) nfs_list_remove_request(req); nfs_list_add_request(req, &data->pages); ClearPageError(req->wb_page); - SetPageWriteback(req->wb_page); + set_page_writeback(req->wb_page); *pages++ = req->wb_page; count += req->wb_bytes; } diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 7cbf0682b2f..fc95c4df669 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -107,7 +107,7 @@ static int nfsacld_proc_setacl(struct svc_rqst * rqstp, dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); fh = fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); + nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR); if (!nfserr) { nfserr = nfserrno( nfsd_set_posix_acl( diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 64ba40572fe..16e10c170ae 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -101,7 +101,7 @@ static int nfsd3_proc_setacl(struct svc_rqst * rqstp, int nfserr = 0; fh = fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); + nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR); if (!nfserr) { nfserr = nfserrno( nfsd_set_posix_acl( diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig index deb25b661f0..656bc43431b 100644 --- a/fs/partitions/Kconfig +++ b/fs/partitions/Kconfig @@ -203,7 +203,7 @@ config ULTRIX_PARTITION config SUN_PARTITION bool "Sun partition tables support" if PARTITION_ADVANCED - default y if (SPARC32 || SPARC64 || SUN3 || SUN3X) + default y if (SPARC || SUN3 || SUN3X) ---help--- Like most systems, SunOS uses its own hard disk partition table format, incompatible with all others. Saying Y here allows you to diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c index 8a8d4d9db31..ec852c11dce 100644 --- a/fs/partitions/ultrix.c +++ b/fs/partitions/ultrix.c @@ -7,6 +7,7 @@ */ #include "check.h" +#include "ultrix.h" int ultrix_partition(struct parsed_partitions *state, struct block_device *bdev) { diff --git a/fs/proc/generic.c b/fs/proc/generic.c index b638fb50074..72b431d0a0a 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -54,6 +54,18 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes, ssize_t n, count; char *start; struct proc_dir_entry * dp; + unsigned long long pos; + + /* + * Gaah, please just use "seq_file" instead. The legacy /proc + * interfaces cut loff_t down to off_t for reads, and ignore + * the offset entirely for writes.. + */ + pos = *ppos; + if (pos > MAX_NON_LFS) + return 0; + if (nbytes > MAX_NON_LFS - pos) + nbytes = MAX_NON_LFS - pos; dp = PDE(inode); if (!(page = (char*) __get_free_page(GFP_KERNEL))) @@ -202,30 +214,17 @@ proc_file_write(struct file *file, const char __user *buffer, static loff_t proc_file_lseek(struct file *file, loff_t offset, int orig) { - lock_kernel(); - - switch (orig) { - case 0: - if (offset < 0) - goto out; - file->f_pos = offset; - unlock_kernel(); - return(file->f_pos); - case 1: - if (offset + file->f_pos < 0) - goto out; - file->f_pos += offset; - unlock_kernel(); - return(file->f_pos); - case 2: - goto out; - default: - goto out; - } - -out: - unlock_kernel(); - return -EINVAL; + loff_t retval = -EINVAL; + switch (orig) { + case 1: + offset += file->f_pos; + /* fallthrough */ + case 0: + if (offset < 0 || offset > MAX_NON_LFS) + break; + file->f_pos = retval = offset; + } + return retval; } static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index d2fa42006d8..50bd5a8f044 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -195,7 +195,7 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats static int show_map(struct seq_file *m, void *v) { - return show_map_internal(m, v, 0); + return show_map_internal(m, v, NULL); } static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd, @@ -402,12 +402,11 @@ struct numa_maps { /* * Calculate numa node maps for a vma */ -static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma) +static struct numa_maps *get_numa_maps(struct vm_area_struct *vma) { + int i; struct page *page; unsigned long vaddr; - struct mm_struct *mm = vma->vm_mm; - int i; struct numa_maps *md = kmalloc(sizeof(struct numa_maps), GFP_KERNEL); if (!md) @@ -420,7 +419,7 @@ static struct numa_maps *get_numa_maps(const struct vm_area_struct *vma) md->node[i] =0; for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr += PAGE_SIZE) { - page = follow_page(mm, vaddr, 0); + page = follow_page(vma, vaddr, 0); if (page) { int count = page_mapcount(page); diff --git a/fs/reiserfs/hashes.c b/fs/reiserfs/hashes.c index 37c1306eb9b..a3ec238fd9e 100644 --- a/fs/reiserfs/hashes.c +++ b/fs/reiserfs/hashes.c @@ -19,6 +19,7 @@ // #include <linux/kernel.h> +#include <linux/reiserfs_fs.h> #include <asm/types.h> #include <asm/bug.h> diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 5f82352b97e..a5e3a0ddbe5 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -32,6 +32,7 @@ void reiserfs_delete_inode(struct inode *inode) JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); struct reiserfs_transaction_handle th; + int err; truncate_inode_pages(&inode->i_data, 0); @@ -49,15 +50,13 @@ void reiserfs_delete_inode(struct inode *inode) } reiserfs_update_inode_transaction(inode); - if (reiserfs_delete_object(&th, inode)) { - up(&inode->i_sem); - goto out; - } + err = reiserfs_delete_object(&th, inode); /* Do quota update inside a transaction for journaled quotas. We must do that * after delete_object so that quota updates go into the same transaction as * stat data deletion */ - DQUOT_FREE_INODE(inode); + if (!err) + DQUOT_FREE_INODE(inode); if (journal_end(&th, inode->i_sb, jbegin_count)) { up(&inode->i_sem); @@ -66,6 +65,12 @@ void reiserfs_delete_inode(struct inode *inode) up(&inode->i_sem); + /* check return value from reiserfs_delete_object after + * ending the transaction + */ + if (err) + goto out; + /* all items of file are deleted, so we can remove "save" link */ remove_save_link(inode, 0 /* not truncate */ ); /* we can't do anything * about an error here */ @@ -2099,6 +2104,7 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) struct page *page = NULL; int error; struct buffer_head *bh = NULL; + int err2; reiserfs_write_lock(p_s_inode->i_sb); @@ -2136,14 +2142,18 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) transaction of truncating gets committed - on reboot the file either appears truncated properly or not truncated at all */ add_save_link(&th, p_s_inode, 1); - error = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps); - if (error) - goto out; + err2 = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps); error = journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1); if (error) goto out; + /* check reiserfs_do_truncate after ending the transaction */ + if (err2) { + error = err2; + goto out; + } + if (update_timestamps) { error = remove_save_link(p_s_inode, 1 /* truncate */ ); if (error) @@ -2194,7 +2204,7 @@ static int map_block_for_writepage(struct inode *inode, INITIALIZE_PATH(path); int pos_in_item; int jbegin_count = JOURNAL_PER_BALANCE_CNT; - loff_t byte_offset = (block << inode->i_sb->s_blocksize_bits) + 1; + loff_t byte_offset = ((loff_t)block << inode->i_sb->s_blocksize_bits)+1; int retval; int use_get_block = 0; int bytes_copied = 0; diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 4b15761434b..3f17ef844fb 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -1039,6 +1039,10 @@ static int flush_commit_list(struct super_block *s, } atomic_dec(&journal->j_async_throttle); + /* We're skipping the commit if there's an error */ + if (retval || reiserfs_is_journal_aborted(journal)) + barrier = 0; + /* wait on everything written so far before writing the commit * if we are in barrier mode, send the commit down now */ @@ -1077,10 +1081,16 @@ static int flush_commit_list(struct super_block *s, BUG_ON(atomic_read(&(jl->j_commit_left)) != 1); if (!barrier) { - if (buffer_dirty(jl->j_commit_bh)) - BUG(); - mark_buffer_dirty(jl->j_commit_bh); - sync_dirty_buffer(jl->j_commit_bh); + /* If there was a write error in the journal - we can't commit + * this transaction - it will be invalid and, if successful, + * will just end up propogating the write error out to + * the file system. */ + if (likely(!retval && !reiserfs_is_journal_aborted (journal))) { + if (buffer_dirty(jl->j_commit_bh)) + BUG(); + mark_buffer_dirty(jl->j_commit_bh) ; + sync_dirty_buffer(jl->j_commit_bh) ; + } } else wait_on_buffer(jl->j_commit_bh); @@ -2757,6 +2767,15 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, journal->j_cnode_used = 0; journal->j_must_wait = 0; + if (journal->j_cnode_free == 0) { + reiserfs_warning(p_s_sb, "journal-2004: Journal cnode memory " + "allocation failed (%ld bytes). Journal is " + "too large for available memory. Usually " + "this is due to a journal that is too large.", + sizeof (struct reiserfs_journal_cnode) * num_cnodes); + goto free_and_return; + } + init_journal_hash(p_s_sb); jl = journal->j_current_jl; jl->j_list_bitmap = get_list_bitmap(p_s_sb, jl); diff --git a/fs/relayfs/relay.c b/fs/relayfs/relay.c index 16446a15c96..2a6f7f12b7f 100644 --- a/fs/relayfs/relay.c +++ b/fs/relayfs/relay.c @@ -333,8 +333,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length) return length; toobig: - printk(KERN_WARNING "relayfs: event too large (%Zd)\n", length); - WARN_ON(1); + buf->chan->last_toobig = length; return 0; } @@ -399,6 +398,11 @@ void relay_close(struct rchan *chan) relay_close_buf(chan->buf[i]); } + if (chan->last_toobig) + printk(KERN_WARNING "relayfs: one or more items not logged " + "[item size (%Zd) > sub-buffer size (%Zd)]\n", + chan->last_toobig, chan->subbuf_size); + kref_put(&chan->kref, relay_destroy_channel); } diff --git a/fs/xattr.c b/fs/xattr.c index a9db2255799..bcc2156d4d2 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -245,7 +245,7 @@ listxattr(struct dentry *d, char __user *list, size_t size) error = d->d_inode->i_op->listxattr(d, klist, size); } else { error = security_inode_listsecurity(d->d_inode, klist, size); - if (size && error >= size) + if (size && error > size) error = -ERANGE; } if (error > 0) { diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index c6108971b4e..94d3cdfbf9b 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -941,13 +941,12 @@ __linvfs_get_block( int retpbbm = 1; int error; - if (blocks) { - offset = blocks << inode->i_blkbits; /* 64 bit goodness */ - size = (ssize_t) min_t(xfs_off_t, offset, LONG_MAX); - } else { - size = 1 << inode->i_blkbits; - } offset = (xfs_off_t)iblock << inode->i_blkbits; + if (blocks) + size = (ssize_t) min_t(xfs_off_t, LONG_MAX, + (xfs_off_t)blocks << inode->i_blkbits); + else + size = 1 << inode->i_blkbits; VOP_BMAP(vp, offset, size, create ? flags : BMAPI_READ, &iomap, &retpbbm, error); @@ -1007,7 +1006,7 @@ __linvfs_get_block( ASSERT(iomap.iomap_bsize - iomap.iomap_delta > 0); offset = min_t(xfs_off_t, iomap.iomap_bsize - iomap.iomap_delta, - blocks << inode->i_blkbits); + (xfs_off_t)blocks << inode->i_blkbits); bh_result->b_size = (u32) min_t(xfs_off_t, UINT_MAX, offset); } diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 1aea42d71a6..5328a293712 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -78,7 +78,7 @@ STATIC int xfs_qm_dqhashlock_nowait(xfs_dquot_t *); STATIC int xfs_qm_init_quotainos(xfs_mount_t *); STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); -STATIC int xfs_qm_shake(int, unsigned int); +STATIC int xfs_qm_shake(int, gfp_t); #ifdef DEBUG extern mutex_t qcheck_lock; @@ -2197,7 +2197,7 @@ xfs_qm_shake_freelist( */ /* ARGSUSED */ STATIC int -xfs_qm_shake(int nr_to_scan, unsigned int gfp_mask) +xfs_qm_shake(int nr_to_scan, gfp_t gfp_mask) { int ndqused, nfree, n; diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 35e557b00db..1c7421840c1 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -310,7 +310,8 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) * Fix up the start offset of the attribute fork */ totsize -= size; - if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname) { + if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname && + !(mp->m_flags & XFS_MOUNT_COMPAT_ATTR)) { /* * Last attribute now removed, revert to original * inode format making all literal area available @@ -328,7 +329,8 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); ASSERT(dp->i_d.di_forkoff); - ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname); + ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname || + (mp->m_flags & XFS_MOUNT_COMPAT_ATTR)); dp->i_afp->if_ext_max = XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); dp->i_df.if_ext_max = @@ -737,7 +739,8 @@ xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp) + name_loc->namelen + INT_GET(name_loc->valuelen, ARCH_CONVERT); } - if (bytes == sizeof(struct xfs_attr_sf_hdr)) + if (!(dp->i_mount->m_flags & XFS_MOUNT_COMPAT_ATTR) && + (bytes == sizeof(struct xfs_attr_sf_hdr))) return(-1); return(xfs_attr_shortform_bytesfit(dp, bytes)); } @@ -775,6 +778,8 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff) goto out; if (forkoff == -1) { + ASSERT(!(dp->i_mount->m_flags & XFS_MOUNT_COMPAT_ATTR)); + /* * Last attribute was removed, revert to original * inode format making all literal area available diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 7ceabd0e2d9..d1236d6f404 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -550,7 +550,7 @@ xfs_fs_goingdown( struct vfs *vfsp = XFS_MTOVFS(mp); struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev); - if (sb) { + if (sb && !IS_ERR(sb)) { xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); thaw_bdev(sb->s_bdev, sb); } diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index fcd6d63bb68..3ce204a524b 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h @@ -69,7 +69,7 @@ typedef struct xfs_iomap { xfs_buftarg_t *iomap_target; xfs_off_t iomap_offset; /* offset of mapping, bytes */ xfs_off_t iomap_bsize; /* size of mapping, bytes */ - size_t iomap_delta; /* offset into mapping, bytes */ + xfs_off_t iomap_delta; /* offset into mapping, bytes */ iomap_flags_t iomap_flags; } xfs_iomap_t; diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index 8f285149681..4518b188ade 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h @@ -494,10 +494,8 @@ typedef struct log { #define XLOG_FORCED_SHUTDOWN(log) ((log)->l_flags & XLOG_IO_ERROR) -#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \ - xlog_grant_sub_space(log,bytes,type) -static inline void xlog_grant_sub_space(struct log *log, int bytes, int type) -{ +#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \ + { \ if (type == 'w') { \ (log)->l_grant_write_bytes -= (bytes); \ if ((log)->l_grant_write_bytes < 0) { \ @@ -511,13 +509,9 @@ static inline void xlog_grant_sub_space(struct log *log, int bytes, int type) (log)->l_grant_reserve_cycle--; \ } \ } \ -} - -#define XLOG_GRANT_ADD_SPACE(log,bytes,type) \ - xlog_grant_add_space(log,bytes,type) -static inline void -xlog_grant_add_space(struct log *log, int bytes, int type) -{ + } +#define XLOG_GRANT_ADD_SPACE(log,bytes,type) \ + { \ if (type == 'w') { \ (log)->l_grant_write_bytes += (bytes); \ if ((log)->l_grant_write_bytes > (log)->l_logsize) { \ @@ -531,12 +525,9 @@ xlog_grant_add_space(struct log *log, int bytes, int type) (log)->l_grant_reserve_cycle++; \ } \ } \ -} - -#define XLOG_INS_TICKETQ(q, tic) xlog_ins_ticketq(q, tic) -static inline void -xlog_ins_ticketq(struct xlog_ticket *q, struct xlog_ticket *tic) -{ \ + } +#define XLOG_INS_TICKETQ(q, tic) \ + { \ if (q) { \ (tic)->t_next = (q); \ (tic)->t_prev = (q)->t_prev; \ @@ -547,12 +538,9 @@ xlog_ins_ticketq(struct xlog_ticket *q, struct xlog_ticket *tic) (q) = (tic); \ } \ (tic)->t_flags |= XLOG_TIC_IN_Q; \ -} - -#define XLOG_DEL_TICKETQ(q, tic) xlog_del_ticketq(q, tic) -static inline void -xlog_del_ticketq(struct xlog_ticket *q, struct xlog_ticket *tic) -{ \ + } +#define XLOG_DEL_TICKETQ(q, tic) \ + { \ if ((tic) == (tic)->t_next) { \ (q) = NULL; \ } else { \ @@ -562,7 +550,7 @@ xlog_del_ticketq(struct xlog_ticket *q, struct xlog_ticket *tic) } \ (tic)->t_next = (tic)->t_prev = NULL; \ (tic)->t_flags &= ~XLOG_TIC_IN_Q; \ -} + } /* common routines */ extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 7c1f7453146..e03fa2a3d5e 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -3958,8 +3958,9 @@ xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock) } } XFS_MOUNT_IUNLOCK(mp); - xfs_finish_reclaim(ip, noblock, - XFS_IFLUSH_DELWRI_ELSE_ASYNC); + if (xfs_finish_reclaim(ip, noblock, + XFS_IFLUSH_DELWRI_ELSE_ASYNC)) + delay(1); purged = 1; break; } |