mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
This commit is contained in:
commit
0a7d5f8ce9
2138 changed files with 52985 additions and 23373 deletions
|
|
@ -673,8 +673,10 @@ struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
|
|||
struct cbuf *bufp = &buffer;
|
||||
|
||||
size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
|
||||
if (extended && extension!=NULL)
|
||||
size += 2 + strlen(extension); /* extension[s] */
|
||||
if (extended) {
|
||||
size += 2 + /* extension[s] */
|
||||
(extension == NULL ? 0 : strlen(extension));
|
||||
}
|
||||
|
||||
fc = v9fs_create_common(bufp, size, TCREATE);
|
||||
if (IS_ERR(fc))
|
||||
|
|
|
|||
|
|
@ -434,11 +434,11 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
|
|||
result = v9fs_t_remove(v9ses, fid, &fcall);
|
||||
if (result < 0) {
|
||||
PRINT_FCALL_ERROR("remove fails", fcall);
|
||||
} else {
|
||||
v9fs_put_idpool(fid, &v9ses->fidpool);
|
||||
v9fs_fid_destroy(v9fid);
|
||||
}
|
||||
|
||||
v9fs_put_idpool(fid, &v9ses->fidpool);
|
||||
v9fs_fid_destroy(v9fid);
|
||||
|
||||
kfree(fcall);
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1801,6 +1801,7 @@ config CIFS_POSIX
|
|||
|
||||
config CIFS_DEBUG2
|
||||
bool "Enable additional CIFS debugging routines"
|
||||
depends on CIFS
|
||||
help
|
||||
Enabling this option adds a few more debugging routines
|
||||
to the cifs code which slightly increases the size of
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ static struct adfs_discmap *adfs_read_map(struct super_block *sb, struct adfs_di
|
|||
if (adfs_checkmap(sb, dm))
|
||||
return dm;
|
||||
|
||||
adfs_error(sb, NULL, "map corrupted");
|
||||
adfs_error(sb, "map corrupted");
|
||||
|
||||
error_free:
|
||||
while (--zone >= 0)
|
||||
|
|
|
|||
|
|
@ -512,7 +512,11 @@ befs_utf2nls(struct super_block *sb, const char *in,
|
|||
wchar_t uni;
|
||||
int unilen, utflen;
|
||||
char *result;
|
||||
int maxlen = in_len; /* The utf8->nls conversion can't make more chars */
|
||||
/* The utf8->nls conversion won't make the final nls string bigger
|
||||
* than the utf one, but if the string is pure ascii they'll have the
|
||||
* same width and an extra char is needed to save the additional \0
|
||||
*/
|
||||
int maxlen = in_len + 1;
|
||||
|
||||
befs_debug(sb, "---> utf2nls()");
|
||||
|
||||
|
|
@ -588,7 +592,10 @@ befs_nls2utf(struct super_block *sb, const char *in,
|
|||
wchar_t uni;
|
||||
int unilen, utflen;
|
||||
char *result;
|
||||
int maxlen = 3 * in_len;
|
||||
/* There're nls characters that will translate to 3-chars-wide UTF-8
|
||||
* characters, a additional byte is needed to save the final \0
|
||||
* in special cases */
|
||||
int maxlen = (3 * in_len) + 1;
|
||||
|
||||
befs_debug(sb, "---> nls2utf()\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -1185,8 +1185,6 @@ static int maydump(struct vm_area_struct *vma)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
||||
|
||||
/* An ELF note in memory */
|
||||
struct memelfnote
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
114
fs/block_dev.c
114
fs/block_dev.c
|
|
@ -884,6 +884,61 @@ void bd_set_size(struct block_device *bdev, loff_t size)
|
|||
}
|
||||
EXPORT_SYMBOL(bd_set_size);
|
||||
|
||||
static int __blkdev_put(struct block_device *bdev, unsigned int subclass)
|
||||
{
|
||||
int ret = 0;
|
||||
struct inode *bd_inode = bdev->bd_inode;
|
||||
struct gendisk *disk = bdev->bd_disk;
|
||||
|
||||
mutex_lock_nested(&bdev->bd_mutex, subclass);
|
||||
lock_kernel();
|
||||
if (!--bdev->bd_openers) {
|
||||
sync_blockdev(bdev);
|
||||
kill_bdev(bdev);
|
||||
}
|
||||
if (bdev->bd_contains == bdev) {
|
||||
if (disk->fops->release)
|
||||
ret = disk->fops->release(bd_inode, NULL);
|
||||
} else {
|
||||
mutex_lock_nested(&bdev->bd_contains->bd_mutex,
|
||||
subclass + 1);
|
||||
bdev->bd_contains->bd_part_count--;
|
||||
mutex_unlock(&bdev->bd_contains->bd_mutex);
|
||||
}
|
||||
if (!bdev->bd_openers) {
|
||||
struct module *owner = disk->fops->owner;
|
||||
|
||||
put_disk(disk);
|
||||
module_put(owner);
|
||||
|
||||
if (bdev->bd_contains != bdev) {
|
||||
kobject_put(&bdev->bd_part->kobj);
|
||||
bdev->bd_part = NULL;
|
||||
}
|
||||
bdev->bd_disk = NULL;
|
||||
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
|
||||
if (bdev != bdev->bd_contains)
|
||||
__blkdev_put(bdev->bd_contains, subclass + 1);
|
||||
bdev->bd_contains = NULL;
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
bdput(bdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int blkdev_put(struct block_device *bdev)
|
||||
{
|
||||
return __blkdev_put(bdev, BD_MUTEX_NORMAL);
|
||||
}
|
||||
EXPORT_SYMBOL(blkdev_put);
|
||||
|
||||
int blkdev_put_partition(struct block_device *bdev)
|
||||
{
|
||||
return __blkdev_put(bdev, BD_MUTEX_PARTITION);
|
||||
}
|
||||
EXPORT_SYMBOL(blkdev_put_partition);
|
||||
|
||||
static int
|
||||
blkdev_get_whole(struct block_device *bdev, mode_t mode, unsigned flags);
|
||||
|
||||
|
|
@ -980,7 +1035,7 @@ out_first:
|
|||
bdev->bd_disk = NULL;
|
||||
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
|
||||
if (bdev != bdev->bd_contains)
|
||||
blkdev_put(bdev->bd_contains);
|
||||
__blkdev_put(bdev->bd_contains, BD_MUTEX_WHOLE);
|
||||
bdev->bd_contains = NULL;
|
||||
put_disk(disk);
|
||||
module_put(owner);
|
||||
|
|
@ -1079,63 +1134,6 @@ static int blkdev_open(struct inode * inode, struct file * filp)
|
|||
return res;
|
||||
}
|
||||
|
||||
static int __blkdev_put(struct block_device *bdev, unsigned int subclass)
|
||||
{
|
||||
int ret = 0;
|
||||
struct inode *bd_inode = bdev->bd_inode;
|
||||
struct gendisk *disk = bdev->bd_disk;
|
||||
|
||||
mutex_lock_nested(&bdev->bd_mutex, subclass);
|
||||
lock_kernel();
|
||||
if (!--bdev->bd_openers) {
|
||||
sync_blockdev(bdev);
|
||||
kill_bdev(bdev);
|
||||
}
|
||||
if (bdev->bd_contains == bdev) {
|
||||
if (disk->fops->release)
|
||||
ret = disk->fops->release(bd_inode, NULL);
|
||||
} else {
|
||||
mutex_lock_nested(&bdev->bd_contains->bd_mutex,
|
||||
subclass + 1);
|
||||
bdev->bd_contains->bd_part_count--;
|
||||
mutex_unlock(&bdev->bd_contains->bd_mutex);
|
||||
}
|
||||
if (!bdev->bd_openers) {
|
||||
struct module *owner = disk->fops->owner;
|
||||
|
||||
put_disk(disk);
|
||||
module_put(owner);
|
||||
|
||||
if (bdev->bd_contains != bdev) {
|
||||
kobject_put(&bdev->bd_part->kobj);
|
||||
bdev->bd_part = NULL;
|
||||
}
|
||||
bdev->bd_disk = NULL;
|
||||
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
|
||||
if (bdev != bdev->bd_contains)
|
||||
__blkdev_put(bdev->bd_contains, subclass + 1);
|
||||
bdev->bd_contains = NULL;
|
||||
}
|
||||
unlock_kernel();
|
||||
mutex_unlock(&bdev->bd_mutex);
|
||||
bdput(bdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int blkdev_put(struct block_device *bdev)
|
||||
{
|
||||
return __blkdev_put(bdev, BD_MUTEX_NORMAL);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(blkdev_put);
|
||||
|
||||
int blkdev_put_partition(struct block_device *bdev)
|
||||
{
|
||||
return __blkdev_put(bdev, BD_MUTEX_PARTITION);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(blkdev_put_partition);
|
||||
|
||||
static int blkdev_close(struct inode * inode, struct file * filp)
|
||||
{
|
||||
struct block_device *bdev = I_BDEV(filp->f_mapping->host);
|
||||
|
|
|
|||
|
|
@ -470,13 +470,18 @@ out:
|
|||
pass does the actual I/O. */
|
||||
void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers)
|
||||
{
|
||||
struct address_space *mapping = bdev->bd_inode->i_mapping;
|
||||
|
||||
if (mapping->nrpages == 0)
|
||||
return;
|
||||
|
||||
invalidate_bh_lrus();
|
||||
/*
|
||||
* FIXME: what about destroy_dirty_buffers?
|
||||
* We really want to use invalidate_inode_pages2() for
|
||||
* that, but not until that's cleaned up.
|
||||
*/
|
||||
invalidate_inode_pages(bdev->bd_inode->i_mapping);
|
||||
invalidate_inode_pages(mapping);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -182,6 +182,28 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* register_chrdev() - Register a major number for character devices.
|
||||
* @major: major device number or 0 for dynamic allocation
|
||||
* @name: name of this range of devices
|
||||
* @fops: file operations associated with this devices
|
||||
*
|
||||
* If @major == 0 this functions will dynamically allocate a major and return
|
||||
* its number.
|
||||
*
|
||||
* If @major > 0 this function will attempt to reserve a device with the given
|
||||
* major number and will return zero on success.
|
||||
*
|
||||
* Returns a -ve errno on failure.
|
||||
*
|
||||
* The name of this device has nothing to do with the name of the device in
|
||||
* /dev. It only helps to keep track of the different owners of devices. If
|
||||
* your module name has only one type of devices it's ok to use e.g. the name
|
||||
* of the module here.
|
||||
*
|
||||
* This function registers a range of 256 minor numbers. The first minor number
|
||||
* is 0.
|
||||
*/
|
||||
int register_chrdev(unsigned int major, const char *name,
|
||||
const struct file_operations *fops)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,13 @@
|
|||
Version 1.45
|
||||
------------
|
||||
Do not time out lockw calls when using posix extensions. Do not
|
||||
time out requests if server still responding reasonably fast
|
||||
on requests on other threads. Improve POSIX locking emulation,
|
||||
(lock cancel now works, and unlock of merged range works even
|
||||
to Windows servers now). Fix oops on mount to lanman servers
|
||||
(win9x, os/2 etc.) when null password. Do not send listxattr
|
||||
(SMB to query all EAs) if nouser_xattr specified.
|
||||
|
||||
Version 1.44
|
||||
------------
|
||||
Rewritten sessionsetup support, including support for legacy SMB
|
||||
|
|
|
|||
|
|
@ -408,7 +408,7 @@ A partial list of the supported mount options follows:
|
|||
user_xattr Allow getting and setting user xattrs as OS/2 EAs (extended
|
||||
attributes) to the server (default) e.g. via setfattr
|
||||
and getfattr utilities.
|
||||
nouser_xattr Do not allow getfattr/setfattr to get/set xattrs
|
||||
nouser_xattr Do not allow getfattr/setfattr to get/set/list xattrs
|
||||
mapchars Translate six of the seven reserved characters (not backslash)
|
||||
*?<>|:
|
||||
to the remap range (above 0xF000), which also
|
||||
|
|
|
|||
|
|
@ -277,7 +277,8 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
|
|||
return;
|
||||
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
|
||||
if(ses->password)
|
||||
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
|
||||
|
||||
if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
|
||||
if(extended_security & CIFSSEC_MAY_PLNTXT) {
|
||||
|
|
|
|||
|
|
@ -402,7 +402,6 @@ static struct quotactl_ops cifs_quotactl_ops = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
|
|
@ -422,7 +421,7 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
|
|||
tcon->tidStatus = CifsExiting;
|
||||
up(&tcon->tconSem);
|
||||
|
||||
/* cancel_brl_requests(tcon); */
|
||||
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
|
||||
/* cancel_notify_requests(tcon); */
|
||||
if(tcon->ses && tcon->ses->server)
|
||||
{
|
||||
|
|
@ -438,7 +437,6 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
|
|||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cifs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
|
|
@ -457,9 +455,7 @@ 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,
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
.umount_begin = cifs_umount_begin,
|
||||
#endif
|
||||
.remount_fs = cifs_remount,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
|
|||
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
||||
extern int cifs_ioctl (struct inode * inode, struct file * filep,
|
||||
unsigned int command, unsigned long arg);
|
||||
#define CIFS_VERSION "1.44"
|
||||
#define CIFS_VERSION "1.45"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2006
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
* Jeremy Allison (jra@samba.org)
|
||||
*
|
||||
* 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
|
||||
|
|
@ -158,7 +159,8 @@ struct TCP_Server_Info {
|
|||
/* 16th byte of RFC1001 workstation name is always null */
|
||||
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
__u32 sequence_number; /* needed for CIFS PDU signature */
|
||||
char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
|
||||
char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
|
||||
unsigned long lstrp; /* when we got last response from this server */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -266,14 +268,14 @@ struct cifsTconInfo {
|
|||
};
|
||||
|
||||
/*
|
||||
* This info hangs off the cifsFileInfo structure. This is used to track
|
||||
* byte stream locks on the file
|
||||
* This info hangs off the cifsFileInfo structure, pointed to by llist.
|
||||
* This is used to track byte stream locks on the file
|
||||
*/
|
||||
struct cifsLockInfo {
|
||||
struct cifsLockInfo *next;
|
||||
int start;
|
||||
int length;
|
||||
int type;
|
||||
struct list_head llist; /* pointer to next cifsLockInfo */
|
||||
__u64 offset;
|
||||
__u64 length;
|
||||
__u8 type;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -304,6 +306,8 @@ struct cifsFileInfo {
|
|||
/* lock scope id (0 if none) */
|
||||
struct file * pfile; /* needed for writepage */
|
||||
struct inode * pInode; /* needed for oplock break */
|
||||
struct semaphore lock_sem;
|
||||
struct list_head llist; /* list of byte range locks we have. */
|
||||
unsigned closePend:1; /* file is marked to close */
|
||||
unsigned invalidHandle:1; /* file closed via session abend */
|
||||
atomic_t wrtPending; /* handle in use - defer close */
|
||||
|
|
|
|||
|
|
@ -50,6 +50,10 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
|||
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
|
||||
struct kvec *, int /* nvec to send */,
|
||||
int * /* type of buf returned */ , const int long_op);
|
||||
extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *,
|
||||
struct smb_hdr * /* input */ ,
|
||||
struct smb_hdr * /* out */ ,
|
||||
int * /* bytes returned */);
|
||||
extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
|
||||
extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
|
||||
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
|
||||
|
|
|
|||
|
|
@ -477,7 +477,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||
/* BB get server time for time conversions and add
|
||||
code to use it and timezone since this is not UTC */
|
||||
|
||||
if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
|
||||
if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
|
||||
memcpy(server->cryptKey, rsp->EncryptionKey,
|
||||
CIFS_CRYPTO_KEY_SIZE);
|
||||
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
|
||||
|
|
@ -1460,8 +1460,13 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->hdr.smb_buf_length += count;
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
if (waitFlag) {
|
||||
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned);
|
||||
} else {
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
|
||||
}
|
||||
cifs_stats_inc(&tcon->num_locks);
|
||||
if (rc) {
|
||||
cFYI(1, ("Send error in Lock = %d", rc));
|
||||
|
|
@ -1484,6 +1489,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
char *data_offset;
|
||||
struct cifs_posix_lock *parm_data;
|
||||
int rc = 0;
|
||||
int timeout = 0;
|
||||
int bytes_returned = 0;
|
||||
__u16 params, param_offset, offset, byte_count, count;
|
||||
|
||||
|
|
@ -1503,7 +1509,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->MaxSetupCount = 0;
|
||||
pSMB->Reserved = 0;
|
||||
pSMB->Flags = 0;
|
||||
pSMB->Timeout = 0;
|
||||
pSMB->Reserved2 = 0;
|
||||
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
|
||||
offset = param_offset + params;
|
||||
|
|
@ -1529,8 +1534,13 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
(((char *) &pSMB->hdr.Protocol) + offset);
|
||||
|
||||
parm_data->lock_type = cpu_to_le16(lock_type);
|
||||
if(waitFlag)
|
||||
if(waitFlag) {
|
||||
timeout = 3; /* blocking operation, no timeout */
|
||||
parm_data->lock_flags = cpu_to_le16(1);
|
||||
pSMB->Timeout = cpu_to_le32(-1);
|
||||
} else
|
||||
pSMB->Timeout = 0;
|
||||
|
||||
parm_data->pid = cpu_to_le32(current->tgid);
|
||||
parm_data->start = cpu_to_le64(pLockData->fl_start);
|
||||
parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
|
||||
|
|
@ -1541,8 +1551,14 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
|||
pSMB->Reserved4 = 0;
|
||||
pSMB->hdr.smb_buf_length += byte_count;
|
||||
pSMB->ByteCount = cpu_to_le16(byte_count);
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
if (waitFlag) {
|
||||
rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned);
|
||||
} else {
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, timeout);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
cFYI(1, ("Send error in Posix Lock = %d", rc));
|
||||
} else if (get_flag) {
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
|
||||
while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
|
||||
{
|
||||
try_to_freeze();
|
||||
if(server->protocolType == IPV6) {
|
||||
rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
|
||||
} else {
|
||||
|
|
@ -612,6 +613,10 @@ multi_t2_fnd:
|
|||
#ifdef CONFIG_CIFS_STATS2
|
||||
mid_entry->when_received = jiffies;
|
||||
#endif
|
||||
/* so we do not time out requests to server
|
||||
which is still responding (since server could
|
||||
be busy but not dead) */
|
||||
server->lstrp = jiffies;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1266,33 +1271,35 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
|
|||
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each(tmp, &GlobalTreeConnectionList) {
|
||||
cFYI(1, ("Next tcon - "));
|
||||
cFYI(1, ("Next tcon"));
|
||||
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
|
||||
if (tcon->ses) {
|
||||
if (tcon->ses->server) {
|
||||
cFYI(1,
|
||||
(" old ip addr: %x == new ip %x ?",
|
||||
("old ip addr: %x == new ip %x ?",
|
||||
tcon->ses->server->addr.sockAddr.sin_addr.
|
||||
s_addr, new_target_ip_addr));
|
||||
if (tcon->ses->server->addr.sockAddr.sin_addr.
|
||||
s_addr == new_target_ip_addr) {
|
||||
/* BB lock tcon and server and tcp session and increment use count here? */
|
||||
/* BB lock tcon, server and tcp session and increment use count here? */
|
||||
/* found a match on the TCP session */
|
||||
/* BB check if reconnection needed */
|
||||
cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
|
||||
cFYI(1,("IP match, old UNC: %s new: %s",
|
||||
tcon->treeName, uncName));
|
||||
if (strncmp
|
||||
(tcon->treeName, uncName,
|
||||
MAX_TREE_SIZE) == 0) {
|
||||
cFYI(1,
|
||||
("Matched UNC, old user: %s == new: %s ?",
|
||||
("and old usr: %s new: %s",
|
||||
tcon->treeName, uncName));
|
||||
if (strncmp
|
||||
(tcon->ses->userName,
|
||||
userName,
|
||||
MAX_USERNAME_SIZE) == 0) {
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
return tcon;/* also matched user (smb session)*/
|
||||
/* matched smb session
|
||||
(user name */
|
||||
return tcon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1969,7 +1976,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
}
|
||||
|
||||
cFYI(1,("Negotiate caps 0x%x",(int)cap));
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG2
|
||||
if(cap & CIFS_UNIX_FCNTL_CAP)
|
||||
cFYI(1,("FCNTL cap"));
|
||||
if(cap & CIFS_UNIX_EXTATTR_CAP)
|
||||
cFYI(1,("EXTATTR cap"));
|
||||
if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
|
||||
cFYI(1,("POSIX path cap"));
|
||||
if(cap & CIFS_UNIX_XATTR_CAP)
|
||||
cFYI(1,("XATTR cap"));
|
||||
if(cap & CIFS_UNIX_POSIX_ACL_CAP)
|
||||
cFYI(1,("POSIX ACL cap"));
|
||||
#endif /* CIFS_DEBUG2 */
|
||||
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
|
||||
cFYI(1,("setting capabilities failed"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,6 +267,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
pCifsFile->invalidHandle = FALSE;
|
||||
pCifsFile->closePend = FALSE;
|
||||
init_MUTEX(&pCifsFile->fh_sem);
|
||||
init_MUTEX(&pCifsFile->lock_sem);
|
||||
INIT_LIST_HEAD(&pCifsFile->llist);
|
||||
atomic_set(&pCifsFile->wrtPending,0);
|
||||
|
||||
/* set the following in open now
|
||||
pCifsFile->pfile = file; */
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2003
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
* Jeremy Allison (jra@samba.org)
|
||||
*
|
||||
* 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
|
||||
|
|
@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private(
|
|||
private_data->netfid = netfid;
|
||||
private_data->pid = current->tgid;
|
||||
init_MUTEX(&private_data->fh_sem);
|
||||
init_MUTEX(&private_data->lock_sem);
|
||||
INIT_LIST_HEAD(&private_data->llist);
|
||||
private_data->pfile = file; /* needed for writepage */
|
||||
private_data->pInode = inode;
|
||||
private_data->invalidHandle = FALSE;
|
||||
|
|
@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file)
|
|||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
if (pSMBFile) {
|
||||
struct cifsLockInfo *li, *tmp;
|
||||
|
||||
pSMBFile->closePend = TRUE;
|
||||
if (pTcon) {
|
||||
/* no sense reconnecting to close a file that is
|
||||
|
|
@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file)
|
|||
pSMBFile->netfid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete any outstanding lock records.
|
||||
We'll lose them when the file is closed anyway. */
|
||||
down(&pSMBFile->lock_sem);
|
||||
list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
|
||||
list_del(&li->llist);
|
||||
kfree(li);
|
||||
}
|
||||
up(&pSMBFile->lock_sem);
|
||||
|
||||
write_lock(&GlobalSMBSeslock);
|
||||
list_del(&pSMBFile->flist);
|
||||
list_del(&pSMBFile->tlist);
|
||||
|
|
@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
|
||||
__u64 offset, __u8 lockType)
|
||||
{
|
||||
struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
|
||||
if (li == NULL)
|
||||
return -ENOMEM;
|
||||
li->offset = offset;
|
||||
li->length = len;
|
||||
li->type = lockType;
|
||||
down(&fid->lock_sem);
|
||||
list_add(&li->llist, &fid->llist);
|
||||
up(&fid->lock_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
{
|
||||
int rc, xid;
|
||||
|
|
@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||
struct cifsTconInfo *pTcon;
|
||||
__u16 netfid;
|
||||
__u8 lockType = LOCKING_ANDX_LARGE_FILES;
|
||||
int posix_locking;
|
||||
|
||||
length = 1 + pfLock->fl_end - pfLock->fl_start;
|
||||
rc = -EACCES;
|
||||
|
|
@ -639,15 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||
}
|
||||
netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
|
||||
|
||||
posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
|
||||
|
||||
/* BB add code here to normalize offset and length to
|
||||
account for negative length which we can not accept over the
|
||||
wire */
|
||||
if (IS_GETLK(cmd)) {
|
||||
if(experimEnabled &&
|
||||
(cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_FCNTL_CAP &
|
||||
le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
|
||||
if(posix_locking) {
|
||||
int posix_lock_type;
|
||||
if(lockType & LOCKING_ANDX_SHARED_LOCK)
|
||||
posix_lock_type = CIFS_RDLCK;
|
||||
|
|
@ -683,10 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
if (experimEnabled &&
|
||||
(cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_FCNTL_CAP &
|
||||
le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) {
|
||||
|
||||
if (!numLock && !numUnlock) {
|
||||
/* if no lock or unlock then nothing
|
||||
to do since we do not know what it is */
|
||||
FreeXid(xid);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (posix_locking) {
|
||||
int posix_lock_type;
|
||||
if(lockType & LOCKING_ANDX_SHARED_LOCK)
|
||||
posix_lock_type = CIFS_RDLCK;
|
||||
|
|
@ -695,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
|||
|
||||
if(numUnlock == 1)
|
||||
posix_lock_type = CIFS_UNLCK;
|
||||
else if(numLock == 0) {
|
||||
/* if no lock or unlock then nothing
|
||||
to do since we do not know what it is */
|
||||
FreeXid(xid);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
|
||||
length, pfLock,
|
||||
posix_lock_type, wait_flag);
|
||||
} else
|
||||
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
|
||||
numUnlock, numLock, lockType, wait_flag);
|
||||
} else {
|
||||
struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data;
|
||||
|
||||
if (numLock) {
|
||||
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
|
||||
0, numLock, lockType, wait_flag);
|
||||
|
||||
if (rc == 0) {
|
||||
/* For Windows locks we must store them. */
|
||||
rc = store_file_lock(fid, length,
|
||||
pfLock->fl_start, lockType);
|
||||
}
|
||||
} else if (numUnlock) {
|
||||
/* For each stored lock that this unlock overlaps
|
||||
completely, unlock it. */
|
||||
int stored_rc = 0;
|
||||
struct cifsLockInfo *li, *tmp;
|
||||
|
||||
down(&fid->lock_sem);
|
||||
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
|
||||
if (pfLock->fl_start <= li->offset &&
|
||||
length >= li->length) {
|
||||
stored_rc = CIFSSMBLock(xid, pTcon, netfid,
|
||||
li->length, li->offset,
|
||||
1, 0, li->type, FALSE);
|
||||
if (stored_rc)
|
||||
rc = stored_rc;
|
||||
|
||||
list_del(&li->llist);
|
||||
kfree(li);
|
||||
}
|
||||
}
|
||||
up(&fid->lock_sem);
|
||||
}
|
||||
}
|
||||
|
||||
if (pfLock->fl_flags & FL_POSIX)
|
||||
posix_lock_file_wait(file, pfLock);
|
||||
FreeXid(xid);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
|
|||
{ERRinvlevel,-EOPNOTSUPP},
|
||||
{ERRdirnotempty, -ENOTEMPTY},
|
||||
{ERRnotlocked, -ENOLCK},
|
||||
{ERRcancelviolation, -ENOLCK},
|
||||
{ERRalreadyexists, -EEXIST},
|
||||
{ERRmoredata, -EOVERFLOW},
|
||||
{ERReasnotsupported,-EOPNOTSUPP},
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
|
|||
FIND_FILE_STANDARD_INFO * pFindData =
|
||||
(FIND_FILE_STANDARD_INFO *)current_entry;
|
||||
filename = &pFindData->FileName[0];
|
||||
len = le32_to_cpu(pFindData->FileNameLength);
|
||||
len = pFindData->FileNameLength;
|
||||
} else {
|
||||
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||
|
||||
/* no capabilities flags in old lanman negotiation */
|
||||
|
||||
pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE;
|
||||
pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
|
||||
/* BB calculate hash with password */
|
||||
/* and copy into bcc */
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@
|
|||
#define ERRinvlevel 124
|
||||
#define ERRdirnotempty 145
|
||||
#define ERRnotlocked 158
|
||||
#define ERRcancelviolation 173
|
||||
#define ERRalreadyexists 183
|
||||
#define ERRbadpipe 230
|
||||
#define ERRpipebusy 231
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2005
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* Jeremy Allison (jra@samba.org) 2006.
|
||||
*
|
||||
* 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
|
||||
|
|
@ -36,7 +37,7 @@ extern mempool_t *cifs_mid_poolp;
|
|||
extern kmem_cache_t *cifs_oplock_cachep;
|
||||
|
||||
static struct mid_q_entry *
|
||||
AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
||||
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
||||
{
|
||||
struct mid_q_entry *temp;
|
||||
|
||||
|
|
@ -203,6 +204,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
|
|||
rc = 0;
|
||||
}
|
||||
|
||||
/* Don't want to modify the buffer as a
|
||||
side effect of this call. */
|
||||
smb_buffer->smb_buf_length = smb_buf_length;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -217,6 +222,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
|
|||
unsigned int len = iov[0].iov_len;
|
||||
unsigned int total_len;
|
||||
int first_vec = 0;
|
||||
unsigned int smb_buf_length = smb_buffer->smb_buf_length;
|
||||
|
||||
if(ssocket == NULL)
|
||||
return -ENOTSOCK; /* BB eventually add reconnect code here */
|
||||
|
|
@ -293,9 +299,123 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
|
|||
} else
|
||||
rc = 0;
|
||||
|
||||
/* Don't want to modify the buffer as a
|
||||
side effect of this call. */
|
||||
smb_buffer->smb_buf_length = smb_buf_length;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
|
||||
{
|
||||
if(long_op == -1) {
|
||||
/* oplock breaks must not be held up */
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
} else {
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
while(1) {
|
||||
if(atomic_read(&ses->server->inFlight) >=
|
||||
cifs_max_pending){
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->num_waiters);
|
||||
#endif
|
||||
wait_event(ses->server->request_q,
|
||||
atomic_read(&ses->server->inFlight)
|
||||
< cifs_max_pending);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->num_waiters);
|
||||
#endif
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
} else {
|
||||
if(ses->server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* can not count locking commands against total since
|
||||
they are allowed to block on server */
|
||||
|
||||
/* update # of requests on the wire to server */
|
||||
if (long_op < 3)
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
|
||||
struct mid_q_entry **ppmidQ)
|
||||
{
|
||||
if (ses->server->tcpStatus == CifsExiting) {
|
||||
return -ENOENT;
|
||||
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
|
||||
cFYI(1,("tcp session dead - return to caller to retry"));
|
||||
return -EAGAIN;
|
||||
} else if (ses->status != CifsGood) {
|
||||
/* check if SMB session is bad because we are setting it up */
|
||||
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
|
||||
(in_buf->Command != SMB_COM_NEGOTIATE)) {
|
||||
return -EAGAIN;
|
||||
} /* else ok - we are setting up session */
|
||||
}
|
||||
*ppmidQ = AllocMidQEntry(in_buf, ses);
|
||||
if (*ppmidQ == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wait_for_response(struct cifsSesInfo *ses,
|
||||
struct mid_q_entry *midQ,
|
||||
unsigned long timeout,
|
||||
unsigned long time_to_wait)
|
||||
{
|
||||
unsigned long curr_timeout;
|
||||
|
||||
for (;;) {
|
||||
curr_timeout = timeout + jiffies;
|
||||
wait_event(ses->server->response_q,
|
||||
(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
|
||||
time_after(jiffies, curr_timeout) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
|
||||
if (time_after(jiffies, curr_timeout) &&
|
||||
(midQ->midState == MID_REQUEST_SUBMITTED) &&
|
||||
((ses->server->tcpStatus == CifsGood) ||
|
||||
(ses->server->tcpStatus == CifsNew))) {
|
||||
|
||||
unsigned long lrt;
|
||||
|
||||
/* We timed out. Is the server still
|
||||
sending replies ? */
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
lrt = ses->server->lstrp;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
|
||||
/* Calculate time_to_wait past last receive time.
|
||||
Although we prefer not to time out if the
|
||||
server is still responding - we will time
|
||||
out if the server takes more than 15 (or 45
|
||||
or 180) seconds to respond to this request
|
||||
and has not responded to any request from
|
||||
other threads on the client within 10 seconds */
|
||||
lrt += time_to_wait;
|
||||
if (time_after(jiffies, lrt)) {
|
||||
/* No replies for time_to_wait. */
|
||||
cERROR(1,("server not responding"));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
|
||||
|
|
@ -323,75 +443,27 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
/* Ensure that we do not send more than 50 overlapping requests
|
||||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
if(long_op == -1) {
|
||||
/* oplock breaks must not be held up */
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
} else {
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
while(1) {
|
||||
if(atomic_read(&ses->server->inFlight) >=
|
||||
cifs_max_pending){
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->num_waiters);
|
||||
#endif
|
||||
wait_event(ses->server->request_q,
|
||||
atomic_read(&ses->server->inFlight)
|
||||
< cifs_max_pending);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->num_waiters);
|
||||
#endif
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
} else {
|
||||
if(ses->server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
cifs_small_buf_release(in_buf);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* can not count locking commands against total since
|
||||
they are allowed to block on server */
|
||||
|
||||
if(long_op < 3) {
|
||||
/* update # of requests on the wire to server */
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
rc = wait_for_free_request(ses, long_op);
|
||||
if (rc) {
|
||||
cifs_small_buf_release(in_buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure that we sign in the same order that we send on this socket
|
||||
and avoid races inside tcp sendmsg code that could cause corruption
|
||||
of smb data */
|
||||
|
||||
down(&ses->server->tcpSem);
|
||||
|
||||
if (ses->server->tcpStatus == CifsExiting) {
|
||||
rc = -ENOENT;
|
||||
goto out_unlock2;
|
||||
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
|
||||
cFYI(1,("tcp session dead - return to caller to retry"));
|
||||
rc = -EAGAIN;
|
||||
goto out_unlock2;
|
||||
} else if (ses->status != CifsGood) {
|
||||
/* check if SMB session is bad because we are setting it up */
|
||||
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
|
||||
(in_buf->Command != SMB_COM_NEGOTIATE)) {
|
||||
rc = -EAGAIN;
|
||||
goto out_unlock2;
|
||||
} /* else ok - we are setting up session */
|
||||
}
|
||||
midQ = AllocMidQEntry(in_buf, ses);
|
||||
if (midQ == NULL) {
|
||||
rc = allocate_mid(ses, in_buf, &midQ);
|
||||
if (rc) {
|
||||
up(&ses->server->tcpSem);
|
||||
cifs_small_buf_release(in_buf);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
return -ENOMEM;
|
||||
/* Update # of requests on wire to server */
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
|
||||
|
|
@ -406,32 +478,23 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
#endif
|
||||
if(rc < 0) {
|
||||
DeleteMidQEntry(midQ);
|
||||
up(&ses->server->tcpSem);
|
||||
cifs_small_buf_release(in_buf);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
return rc;
|
||||
} else {
|
||||
up(&ses->server->tcpSem);
|
||||
cifs_small_buf_release(in_buf);
|
||||
}
|
||||
|
||||
up(&ses->server->tcpSem);
|
||||
cifs_small_buf_release(in_buf);
|
||||
|
||||
if(rc < 0)
|
||||
goto out;
|
||||
|
||||
if (long_op == -1)
|
||||
goto cifs_no_response_exit2;
|
||||
goto out;
|
||||
else if (long_op == 2) /* writes past end of file can take loong time */
|
||||
timeout = 180 * HZ;
|
||||
else if (long_op == 1)
|
||||
timeout = 45 * HZ; /* should be greater than
|
||||
servers oplock break timeout (about 43 seconds) */
|
||||
else if (long_op > 2) {
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
} else
|
||||
else
|
||||
timeout = 15 * HZ;
|
||||
|
||||
/* wait for 15 seconds or until woken up due to response arriving or
|
||||
due to last connection to this server being unmounted */
|
||||
if (signal_pending(current)) {
|
||||
|
|
@ -441,19 +504,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
}
|
||||
|
||||
/* No user interrupts in wait - wreaks havoc with performance */
|
||||
if(timeout != MAX_SCHEDULE_TIMEOUT) {
|
||||
timeout += jiffies;
|
||||
wait_event(ses->server->response_q,
|
||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
||||
time_after(jiffies, timeout) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
} else {
|
||||
wait_event(ses->server->response_q,
|
||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
}
|
||||
wait_for_response(ses, midQ, timeout, 10 * HZ);
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->resp_buf) {
|
||||
|
|
@ -481,11 +532,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
DeleteMidQEntry(midQ);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
/* Update # of requests on wire to server */
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -536,24 +585,12 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
cFYI(1,("Bad MID state?"));
|
||||
}
|
||||
}
|
||||
cifs_no_response_exit2:
|
||||
|
||||
out:
|
||||
|
||||
DeleteMidQEntry(midQ);
|
||||
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
out_unlock2:
|
||||
up(&ses->server->tcpSem);
|
||||
cifs_small_buf_release(in_buf);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -583,85 +620,34 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
/* Ensure that we do not send more than 50 overlapping requests
|
||||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
if(long_op == -1) {
|
||||
/* oplock breaks must not be held up */
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
} else {
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
while(1) {
|
||||
if(atomic_read(&ses->server->inFlight) >=
|
||||
cifs_max_pending){
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->num_waiters);
|
||||
#endif
|
||||
wait_event(ses->server->request_q,
|
||||
atomic_read(&ses->server->inFlight)
|
||||
< cifs_max_pending);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->num_waiters);
|
||||
#endif
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
} else {
|
||||
if(ses->server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* can not count locking commands against total since
|
||||
they are allowed to block on server */
|
||||
|
||||
if(long_op < 3) {
|
||||
/* update # of requests on the wire to server */
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
rc = wait_for_free_request(ses, long_op);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* make sure that we sign in the same order that we send on this socket
|
||||
and avoid races inside tcp sendmsg code that could cause corruption
|
||||
of smb data */
|
||||
|
||||
down(&ses->server->tcpSem);
|
||||
|
||||
if (ses->server->tcpStatus == CifsExiting) {
|
||||
rc = -ENOENT;
|
||||
goto out_unlock;
|
||||
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
|
||||
cFYI(1,("tcp session dead - return to caller to retry"));
|
||||
rc = -EAGAIN;
|
||||
goto out_unlock;
|
||||
} else if (ses->status != CifsGood) {
|
||||
/* check if SMB session is bad because we are setting it up */
|
||||
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
|
||||
(in_buf->Command != SMB_COM_NEGOTIATE)) {
|
||||
rc = -EAGAIN;
|
||||
goto out_unlock;
|
||||
} /* else ok - we are setting up session */
|
||||
}
|
||||
midQ = AllocMidQEntry(in_buf, ses);
|
||||
if (midQ == NULL) {
|
||||
rc = allocate_mid(ses, in_buf, &midQ);
|
||||
if (rc) {
|
||||
up(&ses->server->tcpSem);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
return -ENOMEM;
|
||||
/* Update # of requests on wire to server */
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
up(&ses->server->tcpSem);
|
||||
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length));
|
||||
DeleteMidQEntry(midQ);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
up(&ses->server->tcpSem);
|
||||
/* Update # of requests on wire to server */
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -677,27 +663,19 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
#endif
|
||||
if(rc < 0) {
|
||||
DeleteMidQEntry(midQ);
|
||||
up(&ses->server->tcpSem);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
return rc;
|
||||
} else
|
||||
up(&ses->server->tcpSem);
|
||||
up(&ses->server->tcpSem);
|
||||
|
||||
if(rc < 0)
|
||||
goto out;
|
||||
|
||||
if (long_op == -1)
|
||||
goto cifs_no_response_exit;
|
||||
goto out;
|
||||
else if (long_op == 2) /* writes past end of file can take loong time */
|
||||
timeout = 180 * HZ;
|
||||
else if (long_op == 1)
|
||||
timeout = 45 * HZ; /* should be greater than
|
||||
servers oplock break timeout (about 43 seconds) */
|
||||
else if (long_op > 2) {
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
} else
|
||||
else
|
||||
timeout = 15 * HZ;
|
||||
/* wait for 15 seconds or until woken up due to response arriving or
|
||||
due to last connection to this server being unmounted */
|
||||
|
|
@ -708,19 +686,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
}
|
||||
|
||||
/* No user interrupts in wait - wreaks havoc with performance */
|
||||
if(timeout != MAX_SCHEDULE_TIMEOUT) {
|
||||
timeout += jiffies;
|
||||
wait_event(ses->server->response_q,
|
||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
||||
time_after(jiffies, timeout) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
} else {
|
||||
wait_event(ses->server->response_q,
|
||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
}
|
||||
wait_for_response(ses, midQ, timeout, 10 * HZ);
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->resp_buf) {
|
||||
|
|
@ -748,11 +714,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
DeleteMidQEntry(midQ);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
/* Update # of requests on wire to server */
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -799,23 +763,253 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
cERROR(1,("Bad MID state?"));
|
||||
}
|
||||
}
|
||||
cifs_no_response_exit:
|
||||
|
||||
out:
|
||||
|
||||
DeleteMidQEntry(midQ);
|
||||
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
out_unlock:
|
||||
up(&ses->server->tcpSem);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
|
||||
|
||||
static int
|
||||
send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
|
||||
struct mid_q_entry *midQ)
|
||||
{
|
||||
int rc = 0;
|
||||
struct cifsSesInfo *ses = tcon->ses;
|
||||
__u16 mid = in_buf->Mid;
|
||||
|
||||
header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
|
||||
in_buf->Mid = mid;
|
||||
down(&ses->server->tcpSem);
|
||||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||
if (rc) {
|
||||
up(&ses->server->tcpSem);
|
||||
return rc;
|
||||
}
|
||||
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
|
||||
(struct sockaddr *) &(ses->server->addr.sockAddr));
|
||||
up(&ses->server->tcpSem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
|
||||
blocking lock to return. */
|
||||
|
||||
static int
|
||||
send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||
struct smb_hdr *in_buf,
|
||||
struct smb_hdr *out_buf)
|
||||
{
|
||||
int bytes_returned;
|
||||
struct cifsSesInfo *ses = tcon->ses;
|
||||
LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
|
||||
|
||||
/* We just modify the current in_buf to change
|
||||
the type of lock from LOCKING_ANDX_SHARED_LOCK
|
||||
or LOCKING_ANDX_EXCLUSIVE_LOCK to
|
||||
LOCKING_ANDX_CANCEL_LOCK. */
|
||||
|
||||
pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
|
||||
pSMB->Timeout = 0;
|
||||
pSMB->hdr.Mid = GetNextMid(ses->server);
|
||||
|
||||
return SendReceive(xid, ses, in_buf, out_buf,
|
||||
&bytes_returned, 0);
|
||||
}
|
||||
|
||||
int
|
||||
SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||
struct smb_hdr *in_buf, struct smb_hdr *out_buf,
|
||||
int *pbytes_returned)
|
||||
{
|
||||
int rc = 0;
|
||||
int rstart = 0;
|
||||
unsigned int receive_len;
|
||||
struct mid_q_entry *midQ;
|
||||
struct cifsSesInfo *ses;
|
||||
|
||||
if (tcon == NULL || tcon->ses == NULL) {
|
||||
cERROR(1,("Null smb session"));
|
||||
return -EIO;
|
||||
}
|
||||
ses = tcon->ses;
|
||||
|
||||
if(ses->server == NULL) {
|
||||
cERROR(1,("Null tcp session"));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if(ses->server->tcpStatus == CifsExiting)
|
||||
return -ENOENT;
|
||||
|
||||
/* Ensure that we do not send more than 50 overlapping requests
|
||||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
|
||||
rc = wait_for_free_request(ses, 3);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* make sure that we sign in the same order that we send on this socket
|
||||
and avoid races inside tcp sendmsg code that could cause corruption
|
||||
of smb data */
|
||||
|
||||
down(&ses->server->tcpSem);
|
||||
|
||||
rc = allocate_mid(ses, in_buf, &midQ);
|
||||
if (rc) {
|
||||
up(&ses->server->tcpSem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
up(&ses->server->tcpSem);
|
||||
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length));
|
||||
DeleteMidQEntry(midQ);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||
|
||||
midQ->midState = MID_REQUEST_SUBMITTED;
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->inSend);
|
||||
#endif
|
||||
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
|
||||
(struct sockaddr *) &(ses->server->addr.sockAddr));
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
#endif
|
||||
up(&ses->server->tcpSem);
|
||||
|
||||
if(rc < 0) {
|
||||
DeleteMidQEntry(midQ);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Wait for a reply - allow signals to interrupt. */
|
||||
rc = wait_event_interruptible(ses->server->response_q,
|
||||
(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
|
||||
/* Were we interrupted by a signal ? */
|
||||
if ((rc == -ERESTARTSYS) &&
|
||||
(midQ->midState == MID_REQUEST_SUBMITTED) &&
|
||||
((ses->server->tcpStatus == CifsGood) ||
|
||||
(ses->server->tcpStatus == CifsNew))) {
|
||||
|
||||
if (in_buf->Command == SMB_COM_TRANSACTION2) {
|
||||
/* POSIX lock. We send a NT_CANCEL SMB to cause the
|
||||
blocking lock to return. */
|
||||
|
||||
rc = send_nt_cancel(tcon, in_buf, midQ);
|
||||
if (rc) {
|
||||
DeleteMidQEntry(midQ);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
/* Windows lock. We send a LOCKINGX_CANCEL_LOCK
|
||||
to cause the blocking lock to return. */
|
||||
|
||||
rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
|
||||
|
||||
/* If we get -ENOLCK back the lock may have
|
||||
already been removed. Don't exit in this case. */
|
||||
if (rc && rc != -ENOLCK) {
|
||||
DeleteMidQEntry(midQ);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait 5 seconds for the response. */
|
||||
if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ)==0) {
|
||||
/* We got the response - restart system call. */
|
||||
rstart = 1;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->resp_buf) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
} else {
|
||||
cERROR(1,("No response for cmd %d mid %d",
|
||||
midQ->command, midQ->mid));
|
||||
if(midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||
if(ses->server->tcpStatus == CifsExiting)
|
||||
rc = -EHOSTDOWN;
|
||||
else {
|
||||
ses->server->tcpStatus = CifsNeedReconnect;
|
||||
midQ->midState = MID_RETRY_NEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc != -EHOSTDOWN) {
|
||||
if(midQ->midState == MID_RETRY_NEEDED) {
|
||||
rc = -EAGAIN;
|
||||
cFYI(1,("marking request for retry"));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
}
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
DeleteMidQEntry(midQ);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
|
||||
receive_len, xid));
|
||||
rc = -EIO;
|
||||
} else { /* rcvd frame is ok */
|
||||
|
||||
if (midQ->resp_buf && out_buf
|
||||
&& (midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||
out_buf->smb_buf_length = receive_len;
|
||||
memcpy((char *)out_buf + 4,
|
||||
(char *)midQ->resp_buf + 4,
|
||||
receive_len);
|
||||
|
||||
dump_smb(out_buf, 92);
|
||||
/* convert the length into a more usable form */
|
||||
if((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(out_buf,
|
||||
ses->server->mac_signing_key,
|
||||
midQ->sequence_number+1);
|
||||
if(rc) {
|
||||
cERROR(1,("Unexpected SMB signature"));
|
||||
/* BB FIXME add code to kill session */
|
||||
}
|
||||
}
|
||||
|
||||
*pbytes_returned = out_buf->smb_buf_length;
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(out_buf);
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >=
|
||||
sizeof (struct smb_hdr) -
|
||||
4 /* do not count RFC1001 header */ +
|
||||
(2 * out_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cERROR(1,("Bad MID state?"));
|
||||
}
|
||||
}
|
||||
DeleteMidQEntry(midQ);
|
||||
if (rstart && rc == -EACCES)
|
||||
return -ERESTARTSYS;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,11 +330,15 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
|
|||
sb = direntry->d_inode->i_sb;
|
||||
if(sb == NULL)
|
||||
return -EIO;
|
||||
xid = GetXid();
|
||||
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
|
||||
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
full_path = build_path_from_dentry(direntry);
|
||||
if(full_path == NULL) {
|
||||
FreeXid(xid);
|
||||
|
|
|
|||
|
|
@ -136,10 +136,8 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
|
|||
coda_vfs_stat.open++;
|
||||
|
||||
cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
|
||||
if (!cfi) {
|
||||
unlock_kernel();
|
||||
if (!cfi)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
lock_kernel();
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ static int efs_symlink_readpage(struct file *file, struct page *page)
|
|||
|
||||
err = -ENAMETOOLONG;
|
||||
if (size > 2 * EFS_BLOCKSIZE)
|
||||
goto fail;
|
||||
goto fail_notlocked;
|
||||
|
||||
lock_kernel();
|
||||
/* read first 512 bytes of link target */
|
||||
|
|
@ -47,6 +47,7 @@ static int efs_symlink_readpage(struct file *file, struct page *page)
|
|||
return 0;
|
||||
fail:
|
||||
unlock_kernel();
|
||||
fail_notlocked:
|
||||
SetPageError(page);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
|
|
|
|||
|
|
@ -1168,7 +1168,7 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
|
|||
eexit_1:
|
||||
|
||||
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
|
||||
current, ep, epi->file, error));
|
||||
current, ep, epi->ffd.file, error));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
|
@ -1236,7 +1236,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
|
|||
struct eventpoll *ep = epi->ep;
|
||||
|
||||
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
|
||||
current, epi->file, epi, ep));
|
||||
current, epi->ffd.file, epi, ep));
|
||||
|
||||
write_lock_irqsave(&ep->lock, flags);
|
||||
|
||||
|
|
|
|||
10
fs/exec.c
10
fs/exec.c
|
|
@ -486,8 +486,6 @@ struct file *open_exec(const char *name)
|
|||
if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
|
||||
S_ISREG(inode->i_mode)) {
|
||||
int err = vfs_permission(&nd, MAY_EXEC);
|
||||
if (!err && !(inode->i_mode & 0111))
|
||||
err = -EACCES;
|
||||
file = ERR_PTR(err);
|
||||
if (!err) {
|
||||
file = nameidata_to_filp(&nd, O_RDONLY);
|
||||
|
|
@ -753,7 +751,7 @@ no_thread_group:
|
|||
|
||||
write_lock_irq(&tasklist_lock);
|
||||
spin_lock(&oldsighand->siglock);
|
||||
spin_lock(&newsighand->siglock);
|
||||
spin_lock_nested(&newsighand->siglock, SINGLE_DEPTH_NESTING);
|
||||
|
||||
rcu_assign_pointer(current->sighand, newsighand);
|
||||
recalc_sigpending();
|
||||
|
|
@ -922,12 +920,6 @@ int prepare_binprm(struct linux_binprm *bprm)
|
|||
int retval;
|
||||
|
||||
mode = inode->i_mode;
|
||||
/*
|
||||
* Check execute perms again - if the caller has CAP_DAC_OVERRIDE,
|
||||
* generic_permission lets a non-executable through
|
||||
*/
|
||||
if (!(mode & 0111)) /* with at least _one_ execute bit set */
|
||||
return -EACCES;
|
||||
if (bprm->file->f_op == NULL)
|
||||
return -EACCES;
|
||||
|
||||
|
|
|
|||
|
|
@ -775,7 +775,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
|
|||
if (EXT2_INODE_SIZE(sb) == 0)
|
||||
goto cantfind_ext2;
|
||||
sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb);
|
||||
if (sbi->s_inodes_per_block == 0)
|
||||
if (sbi->s_inodes_per_block == 0 || sbi->s_inodes_per_group == 0)
|
||||
goto cantfind_ext2;
|
||||
sbi->s_itb_per_group = sbi->s_inodes_per_group /
|
||||
sbi->s_inodes_per_block;
|
||||
|
|
|
|||
|
|
@ -62,9 +62,6 @@ extern int ext3_permission (struct inode *, int, struct nameidata *);
|
|||
extern int ext3_acl_chmod (struct inode *);
|
||||
extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
|
||||
|
||||
extern int init_ext3_acl(void);
|
||||
extern void exit_ext3_acl(void);
|
||||
|
||||
#else /* CONFIG_EXT3_FS_POSIX_ACL */
|
||||
#include <linux/sched.h>
|
||||
#define ext3_permission NULL
|
||||
|
|
|
|||
|
|
@ -1269,12 +1269,12 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
|
|||
goal = le32_to_cpu(es->s_first_data_block);
|
||||
group_no = (goal - le32_to_cpu(es->s_first_data_block)) /
|
||||
EXT3_BLOCKS_PER_GROUP(sb);
|
||||
goal_group = group_no;
|
||||
retry_alloc:
|
||||
gdp = ext3_get_group_desc(sb, group_no, &gdp_bh);
|
||||
if (!gdp)
|
||||
goto io_error;
|
||||
|
||||
goal_group = group_no;
|
||||
retry:
|
||||
free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
|
||||
/*
|
||||
* if there is not enough free blocks to make a new resevation
|
||||
|
|
@ -1349,7 +1349,7 @@ retry:
|
|||
if (my_rsv) {
|
||||
my_rsv = NULL;
|
||||
group_no = goal_group;
|
||||
goto retry;
|
||||
goto retry_alloc;
|
||||
}
|
||||
/* No space left on the device */
|
||||
*errp = -ENOSPC;
|
||||
|
|
|
|||
|
|
@ -1158,7 +1158,7 @@ retry:
|
|||
ret = PTR_ERR(handle);
|
||||
goto out;
|
||||
}
|
||||
if (test_opt(inode->i_sb, NOBH))
|
||||
if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode))
|
||||
ret = nobh_prepare_write(page, from, to, ext3_get_block);
|
||||
else
|
||||
ret = block_prepare_write(page, from, to, ext3_get_block);
|
||||
|
|
@ -1244,7 +1244,7 @@ static int ext3_writeback_commit_write(struct file *file, struct page *page,
|
|||
if (new_i_size > EXT3_I(inode)->i_disksize)
|
||||
EXT3_I(inode)->i_disksize = new_i_size;
|
||||
|
||||
if (test_opt(inode->i_sb, NOBH))
|
||||
if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode))
|
||||
ret = nobh_commit_write(file, page, from, to);
|
||||
else
|
||||
ret = generic_commit_write(file, page, from, to);
|
||||
|
|
@ -1494,7 +1494,7 @@ static int ext3_writeback_writepage(struct page *page,
|
|||
goto out_fail;
|
||||
}
|
||||
|
||||
if (test_opt(inode->i_sb, NOBH))
|
||||
if (test_opt(inode->i_sb, NOBH) && ext3_should_writeback_data(inode))
|
||||
ret = nobh_writepage(page, ext3_get_block, wbc);
|
||||
else
|
||||
ret = block_write_full_page(page, ext3_get_block, wbc);
|
||||
|
|
@ -2402,14 +2402,15 @@ static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb,
|
|||
struct buffer_head *bh;
|
||||
struct ext3_group_desc * gdp;
|
||||
|
||||
|
||||
if ((ino != EXT3_ROOT_INO && ino != EXT3_JOURNAL_INO &&
|
||||
ino != EXT3_RESIZE_INO && ino < EXT3_FIRST_INO(sb)) ||
|
||||
ino > le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)) {
|
||||
ext3_error(sb, "ext3_get_inode_block",
|
||||
"bad inode number: %lu", ino);
|
||||
if (!ext3_valid_inum(sb, ino)) {
|
||||
/*
|
||||
* This error is already checked for in namei.c unless we are
|
||||
* looking at an NFS filehandle, in which case no error
|
||||
* report is needed
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
|
||||
if (block_group >= EXT3_SB(sb)->s_groups_count) {
|
||||
ext3_error(sb,"ext3_get_inode_block","group >= groups count");
|
||||
|
|
|
|||
|
|
@ -1000,7 +1000,12 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
|
|||
if (bh) {
|
||||
unsigned long ino = le32_to_cpu(de->inode);
|
||||
brelse (bh);
|
||||
inode = iget(dir->i_sb, ino);
|
||||
if (!ext3_valid_inum(dir->i_sb, ino)) {
|
||||
ext3_error(dir->i_sb, "ext3_lookup",
|
||||
"bad inode number: %lu", ino);
|
||||
inode = NULL;
|
||||
} else
|
||||
inode = iget(dir->i_sb, ino);
|
||||
|
||||
if (!inode)
|
||||
return ERR_PTR(-EACCES);
|
||||
|
|
@ -1028,7 +1033,13 @@ struct dentry *ext3_get_parent(struct dentry *child)
|
|||
return ERR_PTR(-ENOENT);
|
||||
ino = le32_to_cpu(de->inode);
|
||||
brelse(bh);
|
||||
inode = iget(child->d_inode->i_sb, ino);
|
||||
|
||||
if (!ext3_valid_inum(child->d_inode->i_sb, ino)) {
|
||||
ext3_error(child->d_inode->i_sb, "ext3_get_parent",
|
||||
"bad inode number: %lu", ino);
|
||||
inode = NULL;
|
||||
} else
|
||||
inode = iget(child->d_inode->i_sb, ino);
|
||||
|
||||
if (!inode)
|
||||
return ERR_PTR(-EACCES);
|
||||
|
|
|
|||
14
fs/file.c
14
fs/file.c
|
|
@ -240,13 +240,9 @@ static struct fdtable *alloc_fdtable(int nr)
|
|||
if (!fdt)
|
||||
goto out;
|
||||
|
||||
nfds = 8 * L1_CACHE_BYTES;
|
||||
/* Expand to the max in easy steps */
|
||||
while (nfds <= nr) {
|
||||
nfds = nfds * 2;
|
||||
if (nfds > NR_OPEN)
|
||||
nfds = NR_OPEN;
|
||||
}
|
||||
nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1));
|
||||
if (nfds > NR_OPEN)
|
||||
nfds = NR_OPEN;
|
||||
|
||||
new_openset = alloc_fdset(nfds);
|
||||
new_execset = alloc_fdset(nfds);
|
||||
|
|
@ -277,11 +273,13 @@ static struct fdtable *alloc_fdtable(int nr)
|
|||
} while (nfds <= nr);
|
||||
new_fds = alloc_fd_array(nfds);
|
||||
if (!new_fds)
|
||||
goto out;
|
||||
goto out2;
|
||||
fdt->fd = new_fds;
|
||||
fdt->max_fds = nfds;
|
||||
fdt->free_files = NULL;
|
||||
return fdt;
|
||||
out2:
|
||||
nfds = fdt->max_fdset;
|
||||
out:
|
||||
if (new_openset)
|
||||
free_fdset(new_openset, nfds);
|
||||
|
|
|
|||
|
|
@ -246,6 +246,8 @@ vxfs_readdir(struct file *fp, void *retp, filldir_t filler)
|
|||
u_long page, npages, block, pblocks, nblocks, offset;
|
||||
loff_t pos;
|
||||
|
||||
lock_kernel();
|
||||
|
||||
switch ((long)fp->f_pos) {
|
||||
case 0:
|
||||
if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0)
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
|
|||
|
||||
/*
|
||||
* Add a connection to the control filesystem (if it exists). Caller
|
||||
* must host fuse_mutex
|
||||
* must hold fuse_mutex
|
||||
*/
|
||||
int fuse_ctl_add_conn(struct fuse_conn *fc)
|
||||
{
|
||||
|
|
@ -139,7 +139,7 @@ int fuse_ctl_add_conn(struct fuse_conn *fc)
|
|||
|
||||
/*
|
||||
* Remove a connection from the control filesystem (if it exists).
|
||||
* Caller must host fuse_mutex
|
||||
* Caller must hold fuse_mutex
|
||||
*/
|
||||
void fuse_ctl_remove_conn(struct fuse_conn *fc)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,33 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#if BITS_PER_LONG >= 64
|
||||
static inline void fuse_dentry_settime(struct dentry *entry, u64 time)
|
||||
{
|
||||
entry->d_time = time;
|
||||
}
|
||||
|
||||
static inline u64 fuse_dentry_time(struct dentry *entry)
|
||||
{
|
||||
return entry->d_time;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* On 32 bit archs store the high 32 bits of time in d_fsdata
|
||||
*/
|
||||
static void fuse_dentry_settime(struct dentry *entry, u64 time)
|
||||
{
|
||||
entry->d_time = time;
|
||||
entry->d_fsdata = (void *) (unsigned long) (time >> 32);
|
||||
}
|
||||
|
||||
static u64 fuse_dentry_time(struct dentry *entry)
|
||||
{
|
||||
return (u64) entry->d_time +
|
||||
((u64) (unsigned long) entry->d_fsdata << 32);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FUSE caches dentries and attributes with separate timeout. The
|
||||
* time in jiffies until the dentry/attributes are valid is stored in
|
||||
|
|
@ -23,10 +50,13 @@
|
|||
/*
|
||||
* Calculate the time in jiffies until a dentry/attributes are valid
|
||||
*/
|
||||
static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec)
|
||||
static u64 time_to_jiffies(unsigned long sec, unsigned long nsec)
|
||||
{
|
||||
struct timespec ts = {sec, nsec};
|
||||
return jiffies + timespec_to_jiffies(&ts);
|
||||
if (sec || nsec) {
|
||||
struct timespec ts = {sec, nsec};
|
||||
return get_jiffies_64() + timespec_to_jiffies(&ts);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -35,7 +65,8 @@ static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec)
|
|||
*/
|
||||
static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
|
||||
{
|
||||
entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
|
||||
fuse_dentry_settime(entry,
|
||||
time_to_jiffies(o->entry_valid, o->entry_valid_nsec));
|
||||
if (entry->d_inode)
|
||||
get_fuse_inode(entry->d_inode)->i_time =
|
||||
time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
|
||||
|
|
@ -47,7 +78,7 @@ static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
|
|||
*/
|
||||
void fuse_invalidate_attr(struct inode *inode)
|
||||
{
|
||||
get_fuse_inode(inode)->i_time = jiffies - 1;
|
||||
get_fuse_inode(inode)->i_time = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -60,7 +91,7 @@ void fuse_invalidate_attr(struct inode *inode)
|
|||
*/
|
||||
static void fuse_invalidate_entry_cache(struct dentry *entry)
|
||||
{
|
||||
entry->d_time = jiffies - 1;
|
||||
fuse_dentry_settime(entry, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -102,7 +133,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
|
|||
|
||||
if (inode && is_bad_inode(inode))
|
||||
return 0;
|
||||
else if (time_after(jiffies, entry->d_time)) {
|
||||
else if (fuse_dentry_time(entry) < get_jiffies_64()) {
|
||||
int err;
|
||||
struct fuse_entry_out outarg;
|
||||
struct fuse_conn *fc;
|
||||
|
|
@ -666,7 +697,7 @@ static int fuse_revalidate(struct dentry *entry)
|
|||
if (!fuse_allow_task(fc, current))
|
||||
return -EACCES;
|
||||
if (get_node_id(inode) != FUSE_ROOT_ID &&
|
||||
time_before_eq(jiffies, fi->i_time))
|
||||
fi->i_time >= get_jiffies_64())
|
||||
return 0;
|
||||
|
||||
return fuse_do_getattr(inode);
|
||||
|
|
|
|||
|
|
@ -395,14 +395,16 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
|
|||
struct fuse_readpages_data data;
|
||||
int err;
|
||||
|
||||
err = -EIO;
|
||||
if (is_bad_inode(inode))
|
||||
return -EIO;
|
||||
goto clean_pages_up;
|
||||
|
||||
data.file = file;
|
||||
data.inode = inode;
|
||||
data.req = fuse_get_req(fc);
|
||||
err = PTR_ERR(data.req);
|
||||
if (IS_ERR(data.req))
|
||||
return PTR_ERR(data.req);
|
||||
goto clean_pages_up;
|
||||
|
||||
err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
|
||||
if (!err) {
|
||||
|
|
@ -412,6 +414,10 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
|
|||
fuse_put_request(fc, data.req);
|
||||
}
|
||||
return err;
|
||||
|
||||
clean_pages_up:
|
||||
put_pages_list(pages);
|
||||
return err;
|
||||
}
|
||||
|
||||
static size_t fuse_send_write(struct fuse_req *req, struct file *file,
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ struct fuse_inode {
|
|||
struct fuse_req *forget_req;
|
||||
|
||||
/** Time in jiffies until the file attributes are valid */
|
||||
unsigned long i_time;
|
||||
u64 i_time;
|
||||
};
|
||||
|
||||
/** FUSE specific file data */
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
|
|||
return NULL;
|
||||
|
||||
fi = get_fuse_inode(inode);
|
||||
fi->i_time = jiffies - 1;
|
||||
fi->i_time = 0;
|
||||
fi->nodeid = 0;
|
||||
fi->nlookup = 0;
|
||||
fi->forget_req = fuse_request_alloc();
|
||||
|
|
|
|||
|
|
@ -83,8 +83,6 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
|
||||
ret = -ENOMEM;
|
||||
len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
|
||||
if (!(vma->vm_flags & VM_WRITE) && len > inode->i_size)
|
||||
goto out;
|
||||
|
||||
if (vma->vm_flags & VM_MAYSHARE &&
|
||||
hugetlb_reserve_pages(inode, vma->vm_pgoff >> (HPAGE_SHIFT-PAGE_SHIFT),
|
||||
|
|
@ -93,7 +91,7 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
|
||||
ret = 0;
|
||||
hugetlb_prefault_arch_hook(vma->vm_mm);
|
||||
if (inode->i_size < len)
|
||||
if (vma->vm_flags & VM_WRITE && inode->i_size < len)
|
||||
inode->i_size = len;
|
||||
out:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ static struct inotify_kernel_event * kernel_event(s32 wd, u32 mask, u32 cookie,
|
|||
{
|
||||
struct inotify_kernel_event *kevent;
|
||||
|
||||
kevent = kmem_cache_alloc(event_cachep, GFP_KERNEL);
|
||||
kevent = kmem_cache_alloc(event_cachep, GFP_NOFS);
|
||||
if (unlikely(!kevent))
|
||||
return NULL;
|
||||
|
||||
|
|
|
|||
30
fs/ioprio.c
30
fs/ioprio.c
|
|
@ -44,6 +44,9 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
|
|||
task->ioprio = ioprio;
|
||||
|
||||
ioc = task->io_context;
|
||||
/* see wmb() in current_io_context() */
|
||||
smp_read_barrier_depends();
|
||||
|
||||
if (ioc && ioc->set_ioprio)
|
||||
ioc->set_ioprio(ioc, ioprio);
|
||||
|
||||
|
|
@ -111,9 +114,9 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
|
|||
continue;
|
||||
ret = set_task_ioprio(p, ioprio);
|
||||
if (ret)
|
||||
break;
|
||||
goto free_uid;
|
||||
} while_each_thread(g, p);
|
||||
|
||||
free_uid:
|
||||
if (who)
|
||||
free_uid(user);
|
||||
break;
|
||||
|
|
@ -137,6 +140,29 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ioprio_best(unsigned short aprio, unsigned short bprio)
|
||||
{
|
||||
unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
|
||||
unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
|
||||
|
||||
if (!ioprio_valid(aprio))
|
||||
return bprio;
|
||||
if (!ioprio_valid(bprio))
|
||||
return aprio;
|
||||
|
||||
if (aclass == IOPRIO_CLASS_NONE)
|
||||
aclass = IOPRIO_CLASS_BE;
|
||||
if (bclass == IOPRIO_CLASS_NONE)
|
||||
bclass = IOPRIO_CLASS_BE;
|
||||
|
||||
if (aclass == bclass)
|
||||
return min(aprio, bprio);
|
||||
if (aclass > bclass)
|
||||
return bprio;
|
||||
else
|
||||
return aprio;
|
||||
}
|
||||
|
||||
asmlinkage long sys_ioprio_get(int which, int who)
|
||||
{
|
||||
struct task_struct *g, *p;
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ void journal_commit_transaction(journal_t *journal)
|
|||
struct buffer_head *bh = jh2bh(jh);
|
||||
|
||||
jbd_lock_bh_state(bh);
|
||||
kfree(jh->b_committed_data);
|
||||
jbd_slab_free(jh->b_committed_data, bh->b_size);
|
||||
jh->b_committed_data = NULL;
|
||||
jbd_unlock_bh_state(bh);
|
||||
}
|
||||
|
|
@ -745,14 +745,14 @@ restart_loop:
|
|||
* Otherwise, we can just throw away the frozen data now.
|
||||
*/
|
||||
if (jh->b_committed_data) {
|
||||
kfree(jh->b_committed_data);
|
||||
jbd_slab_free(jh->b_committed_data, bh->b_size);
|
||||
jh->b_committed_data = NULL;
|
||||
if (jh->b_frozen_data) {
|
||||
jh->b_committed_data = jh->b_frozen_data;
|
||||
jh->b_frozen_data = NULL;
|
||||
}
|
||||
} else if (jh->b_frozen_data) {
|
||||
kfree(jh->b_frozen_data);
|
||||
jbd_slab_free(jh->b_frozen_data, bh->b_size);
|
||||
jh->b_frozen_data = NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ EXPORT_SYMBOL(journal_force_commit);
|
|||
|
||||
static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
|
||||
static void __journal_abort_soft (journal_t *journal, int errno);
|
||||
static int journal_create_jbd_slab(size_t slab_size);
|
||||
|
||||
/*
|
||||
* Helper function used to manage commit timeouts
|
||||
|
|
@ -328,10 +329,10 @@ repeat:
|
|||
char *tmp;
|
||||
|
||||
jbd_unlock_bh_state(bh_in);
|
||||
tmp = jbd_rep_kmalloc(bh_in->b_size, GFP_NOFS);
|
||||
tmp = jbd_slab_alloc(bh_in->b_size, GFP_NOFS);
|
||||
jbd_lock_bh_state(bh_in);
|
||||
if (jh_in->b_frozen_data) {
|
||||
kfree(tmp);
|
||||
jbd_slab_free(tmp, bh_in->b_size);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
|
|
@ -1069,17 +1070,17 @@ static int load_superblock(journal_t *journal)
|
|||
int journal_load(journal_t *journal)
|
||||
{
|
||||
int err;
|
||||
journal_superblock_t *sb;
|
||||
|
||||
err = load_superblock(journal);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sb = journal->j_superblock;
|
||||
/* If this is a V2 superblock, then we have to check the
|
||||
* features flags on it. */
|
||||
|
||||
if (journal->j_format_version >= 2) {
|
||||
journal_superblock_t *sb = journal->j_superblock;
|
||||
|
||||
if ((sb->s_feature_ro_compat &
|
||||
~cpu_to_be32(JFS_KNOWN_ROCOMPAT_FEATURES)) ||
|
||||
(sb->s_feature_incompat &
|
||||
|
|
@ -1090,6 +1091,13 @@ int journal_load(journal_t *journal)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a slab for this blocksize
|
||||
*/
|
||||
err = journal_create_jbd_slab(cpu_to_be32(sb->s_blocksize));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Let the recovery code check whether it needs to recover any
|
||||
* data from the journal. */
|
||||
if (journal_recover(journal))
|
||||
|
|
@ -1611,6 +1619,77 @@ void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry)
|
|||
return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* jbd slab management: create 1k, 2k, 4k, 8k slabs as needed
|
||||
* and allocate frozen and commit buffers from these slabs.
|
||||
*
|
||||
* Reason for doing this is to avoid, SLAB_DEBUG - since it could
|
||||
* cause bh to cross page boundary.
|
||||
*/
|
||||
|
||||
#define JBD_MAX_SLABS 5
|
||||
#define JBD_SLAB_INDEX(size) (size >> 11)
|
||||
|
||||
static kmem_cache_t *jbd_slab[JBD_MAX_SLABS];
|
||||
static const char *jbd_slab_names[JBD_MAX_SLABS] = {
|
||||
"jbd_1k", "jbd_2k", "jbd_4k", NULL, "jbd_8k"
|
||||
};
|
||||
|
||||
static void journal_destroy_jbd_slabs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < JBD_MAX_SLABS; i++) {
|
||||
if (jbd_slab[i])
|
||||
kmem_cache_destroy(jbd_slab[i]);
|
||||
jbd_slab[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int journal_create_jbd_slab(size_t slab_size)
|
||||
{
|
||||
int i = JBD_SLAB_INDEX(slab_size);
|
||||
|
||||
BUG_ON(i >= JBD_MAX_SLABS);
|
||||
|
||||
/*
|
||||
* Check if we already have a slab created for this size
|
||||
*/
|
||||
if (jbd_slab[i])
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Create a slab and force alignment to be same as slabsize -
|
||||
* this will make sure that allocations won't cross the page
|
||||
* boundary.
|
||||
*/
|
||||
jbd_slab[i] = kmem_cache_create(jbd_slab_names[i],
|
||||
slab_size, slab_size, 0, NULL, NULL);
|
||||
if (!jbd_slab[i]) {
|
||||
printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void * jbd_slab_alloc(size_t size, gfp_t flags)
|
||||
{
|
||||
int idx;
|
||||
|
||||
idx = JBD_SLAB_INDEX(size);
|
||||
BUG_ON(jbd_slab[idx] == NULL);
|
||||
return kmem_cache_alloc(jbd_slab[idx], flags | __GFP_NOFAIL);
|
||||
}
|
||||
|
||||
void jbd_slab_free(void *ptr, size_t size)
|
||||
{
|
||||
int idx;
|
||||
|
||||
idx = JBD_SLAB_INDEX(size);
|
||||
BUG_ON(jbd_slab[idx] == NULL);
|
||||
kmem_cache_free(jbd_slab[idx], ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Journal_head storage management
|
||||
*/
|
||||
|
|
@ -1799,13 +1878,13 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
|
|||
printk(KERN_WARNING "%s: freeing "
|
||||
"b_frozen_data\n",
|
||||
__FUNCTION__);
|
||||
kfree(jh->b_frozen_data);
|
||||
jbd_slab_free(jh->b_frozen_data, bh->b_size);
|
||||
}
|
||||
if (jh->b_committed_data) {
|
||||
printk(KERN_WARNING "%s: freeing "
|
||||
"b_committed_data\n",
|
||||
__FUNCTION__);
|
||||
kfree(jh->b_committed_data);
|
||||
jbd_slab_free(jh->b_committed_data, bh->b_size);
|
||||
}
|
||||
bh->b_private = NULL;
|
||||
jh->b_bh = NULL; /* debug, really */
|
||||
|
|
@ -1961,6 +2040,7 @@ static void journal_destroy_caches(void)
|
|||
journal_destroy_revoke_caches();
|
||||
journal_destroy_journal_head_cache();
|
||||
journal_destroy_handle_cache();
|
||||
journal_destroy_jbd_slabs();
|
||||
}
|
||||
|
||||
static int __init journal_init(void)
|
||||
|
|
|
|||
|
|
@ -666,8 +666,9 @@ repeat:
|
|||
if (!frozen_buffer) {
|
||||
JBUFFER_TRACE(jh, "allocate memory for buffer");
|
||||
jbd_unlock_bh_state(bh);
|
||||
frozen_buffer = jbd_kmalloc(jh2bh(jh)->b_size,
|
||||
GFP_NOFS);
|
||||
frozen_buffer =
|
||||
jbd_slab_alloc(jh2bh(jh)->b_size,
|
||||
GFP_NOFS);
|
||||
if (!frozen_buffer) {
|
||||
printk(KERN_EMERG
|
||||
"%s: OOM for frozen_buffer\n",
|
||||
|
|
@ -879,7 +880,7 @@ int journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
|
|||
|
||||
repeat:
|
||||
if (!jh->b_committed_data) {
|
||||
committed_data = jbd_kmalloc(jh2bh(jh)->b_size, GFP_NOFS);
|
||||
committed_data = jbd_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS);
|
||||
if (!committed_data) {
|
||||
printk(KERN_EMERG "%s: No memory for committed data\n",
|
||||
__FUNCTION__);
|
||||
|
|
@ -906,7 +907,7 @@ repeat:
|
|||
out:
|
||||
journal_put_journal_head(jh);
|
||||
if (unlikely(committed_data))
|
||||
kfree(committed_data);
|
||||
jbd_slab_free(committed_data, bh->b_size);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,16 +168,15 @@ void jfs_dirty_inode(struct inode *inode)
|
|||
set_cflag(COMMIT_Dirty, inode);
|
||||
}
|
||||
|
||||
static int
|
||||
jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks,
|
||||
struct buffer_head *bh_result, int create)
|
||||
int jfs_get_block(struct inode *ip, sector_t lblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
s64 lblock64 = lblock;
|
||||
int rc = 0;
|
||||
xad_t xad;
|
||||
s64 xaddr;
|
||||
int xflag;
|
||||
s32 xlen = max_blocks;
|
||||
s32 xlen = bh_result->b_size >> ip->i_blkbits;
|
||||
|
||||
/*
|
||||
* Take appropriate lock on inode
|
||||
|
|
@ -188,7 +187,7 @@ jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks,
|
|||
IREAD_LOCK(ip);
|
||||
|
||||
if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) &&
|
||||
(!xtLookup(ip, lblock64, max_blocks, &xflag, &xaddr, &xlen, 0)) &&
|
||||
(!xtLookup(ip, lblock64, xlen, &xflag, &xaddr, &xlen, 0)) &&
|
||||
xaddr) {
|
||||
if (xflag & XAD_NOTRECORDED) {
|
||||
if (!create)
|
||||
|
|
@ -255,13 +254,6 @@ jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int jfs_get_block(struct inode *ip, sector_t lblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
return jfs_get_blocks(ip, lblock, bh_result->b_size >> ip->i_blkbits,
|
||||
bh_result, create);
|
||||
}
|
||||
|
||||
static int jfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
return nobh_writepage(page, jfs_get_block, wbc);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ extern void jfs_truncate_nolock(struct inode *, loff_t);
|
|||
extern void jfs_free_zero_link(struct inode *);
|
||||
extern struct dentry *jfs_get_parent(struct dentry *dentry);
|
||||
extern void jfs_set_inode_flags(struct inode *);
|
||||
extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
||||
|
||||
extern const struct address_space_operations jfs_aops;
|
||||
extern struct inode_operations jfs_dir_inode_operations;
|
||||
|
|
|
|||
|
|
@ -2944,7 +2944,7 @@ int jfs_sync(void *arg)
|
|||
* Inode is being freed
|
||||
*/
|
||||
list_del_init(&jfs_ip->anon_inode_list);
|
||||
} else if (! !mutex_trylock(&jfs_ip->commit_mutex)) {
|
||||
} else if (mutex_trylock(&jfs_ip->commit_mutex)) {
|
||||
/*
|
||||
* inode will be removed from anonymous list
|
||||
* when it is committed
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
|
|||
|
||||
out3:
|
||||
txEnd(tid);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
if (rc) {
|
||||
free_ea_wmap(ip);
|
||||
ip->i_nlink = 0;
|
||||
|
|
@ -300,8 +300,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
|
|||
|
||||
out3:
|
||||
txEnd(tid);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
if (rc) {
|
||||
free_ea_wmap(ip);
|
||||
ip->i_nlink = 0;
|
||||
|
|
@ -384,8 +384,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
|
|||
if (rc == -EIO)
|
||||
txAbort(tid, 1);
|
||||
txEnd(tid);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
|
||||
goto out2;
|
||||
}
|
||||
|
|
@ -422,8 +422,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
|
|||
|
||||
txEnd(tid);
|
||||
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
|
||||
/*
|
||||
* Truncating the directory index table is not guaranteed. It
|
||||
|
|
@ -503,8 +503,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
|
|||
if (rc == -EIO)
|
||||
txAbort(tid, 1); /* Marks FS Dirty */
|
||||
txEnd(tid);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
IWRITE_UNLOCK(ip);
|
||||
goto out1;
|
||||
}
|
||||
|
|
@ -527,8 +527,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
|
|||
if ((new_size = commitZeroLink(tid, ip)) < 0) {
|
||||
txAbort(tid, 1); /* Marks FS Dirty */
|
||||
txEnd(tid);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
IWRITE_UNLOCK(ip);
|
||||
rc = new_size;
|
||||
goto out1;
|
||||
|
|
@ -556,9 +556,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
|
|||
|
||||
txEnd(tid);
|
||||
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
|
||||
while (new_size && (rc == 0)) {
|
||||
tid = txBegin(dip->i_sb, 0);
|
||||
|
|
@ -847,8 +846,8 @@ static int jfs_link(struct dentry *old_dentry,
|
|||
out:
|
||||
txEnd(tid);
|
||||
|
||||
mutex_unlock(&JFS_IP(dir)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(dir)->commit_mutex);
|
||||
|
||||
jfs_info("jfs_link: rc:%d", rc);
|
||||
return rc;
|
||||
|
|
@ -1037,8 +1036,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
|
|||
|
||||
out3:
|
||||
txEnd(tid);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(dip)->commit_mutex);
|
||||
if (rc) {
|
||||
free_ea_wmap(ip);
|
||||
ip->i_nlink = 0;
|
||||
|
|
@ -1160,10 +1159,11 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
if (S_ISDIR(new_ip->i_mode)) {
|
||||
new_ip->i_nlink--;
|
||||
if (new_ip->i_nlink) {
|
||||
mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
|
||||
if (old_dir != new_dir)
|
||||
mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
|
||||
if (!S_ISDIR(old_ip->i_mode) && new_ip)
|
||||
IWRITE_UNLOCK(new_ip);
|
||||
jfs_error(new_ip->i_sb,
|
||||
|
|
@ -1281,13 +1281,12 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
|
||||
out4:
|
||||
txEnd(tid);
|
||||
|
||||
mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
|
||||
if (old_dir != new_dir)
|
||||
mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
|
||||
if (new_ip)
|
||||
mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
|
||||
if (old_dir != new_dir)
|
||||
mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
|
||||
mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
|
||||
|
||||
while (new_size && (rc == 0)) {
|
||||
tid = txBegin(new_ip->i_sb, 0);
|
||||
|
|
|
|||
118
fs/jfs/super.c
118
fs/jfs/super.c
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/moduleparam.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
|
|
@ -298,7 +299,7 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
|
|||
break;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_QUOTA)
|
||||
#ifdef CONFIG_QUOTA
|
||||
case Opt_quota:
|
||||
case Opt_usrquota:
|
||||
*flag |= JFS_USRQUOTA;
|
||||
|
|
@ -597,7 +598,7 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|||
if (sbi->flag & JFS_NOINTEGRITY)
|
||||
seq_puts(seq, ",nointegrity");
|
||||
|
||||
#if defined(CONFIG_QUOTA)
|
||||
#ifdef CONFIG_QUOTA
|
||||
if (sbi->flag & JFS_USRQUOTA)
|
||||
seq_puts(seq, ",usrquota");
|
||||
|
||||
|
|
@ -608,6 +609,113 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
|
||||
/* Read data from quotafile - avoid pagecache and such because we cannot afford
|
||||
* acquiring the locks... As quota files are never truncated and quota code
|
||||
* itself serializes the operations (and noone else should touch the files)
|
||||
* we don't have to be afraid of races */
|
||||
static ssize_t jfs_quota_read(struct super_block *sb, int type, char *data,
|
||||
size_t len, loff_t off)
|
||||
{
|
||||
struct inode *inode = sb_dqopt(sb)->files[type];
|
||||
sector_t blk = off >> sb->s_blocksize_bits;
|
||||
int err = 0;
|
||||
int offset = off & (sb->s_blocksize - 1);
|
||||
int tocopy;
|
||||
size_t toread;
|
||||
struct buffer_head tmp_bh;
|
||||
struct buffer_head *bh;
|
||||
loff_t i_size = i_size_read(inode);
|
||||
|
||||
if (off > i_size)
|
||||
return 0;
|
||||
if (off+len > i_size)
|
||||
len = i_size-off;
|
||||
toread = len;
|
||||
while (toread > 0) {
|
||||
tocopy = sb->s_blocksize - offset < toread ?
|
||||
sb->s_blocksize - offset : toread;
|
||||
|
||||
tmp_bh.b_state = 0;
|
||||
tmp_bh.b_size = 1 << inode->i_blkbits;
|
||||
err = jfs_get_block(inode, blk, &tmp_bh, 0);
|
||||
if (err)
|
||||
return err;
|
||||
if (!buffer_mapped(&tmp_bh)) /* A hole? */
|
||||
memset(data, 0, tocopy);
|
||||
else {
|
||||
bh = sb_bread(sb, tmp_bh.b_blocknr);
|
||||
if (!bh)
|
||||
return -EIO;
|
||||
memcpy(data, bh->b_data+offset, tocopy);
|
||||
brelse(bh);
|
||||
}
|
||||
offset = 0;
|
||||
toread -= tocopy;
|
||||
data += tocopy;
|
||||
blk++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Write to quotafile */
|
||||
static ssize_t jfs_quota_write(struct super_block *sb, int type,
|
||||
const char *data, size_t len, loff_t off)
|
||||
{
|
||||
struct inode *inode = sb_dqopt(sb)->files[type];
|
||||
sector_t blk = off >> sb->s_blocksize_bits;
|
||||
int err = 0;
|
||||
int offset = off & (sb->s_blocksize - 1);
|
||||
int tocopy;
|
||||
size_t towrite = len;
|
||||
struct buffer_head tmp_bh;
|
||||
struct buffer_head *bh;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
while (towrite > 0) {
|
||||
tocopy = sb->s_blocksize - offset < towrite ?
|
||||
sb->s_blocksize - offset : towrite;
|
||||
|
||||
tmp_bh.b_state = 0;
|
||||
tmp_bh.b_size = 1 << inode->i_blkbits;
|
||||
err = jfs_get_block(inode, blk, &tmp_bh, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
if (offset || tocopy != sb->s_blocksize)
|
||||
bh = sb_bread(sb, tmp_bh.b_blocknr);
|
||||
else
|
||||
bh = sb_getblk(sb, tmp_bh.b_blocknr);
|
||||
if (!bh) {
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
lock_buffer(bh);
|
||||
memcpy(bh->b_data+offset, data, tocopy);
|
||||
flush_dcache_page(bh->b_page);
|
||||
set_buffer_uptodate(bh);
|
||||
mark_buffer_dirty(bh);
|
||||
unlock_buffer(bh);
|
||||
brelse(bh);
|
||||
offset = 0;
|
||||
towrite -= tocopy;
|
||||
data += tocopy;
|
||||
blk++;
|
||||
}
|
||||
out:
|
||||
if (len == towrite)
|
||||
return err;
|
||||
if (inode->i_size < off+len-towrite)
|
||||
i_size_write(inode, off+len-towrite);
|
||||
inode->i_version++;
|
||||
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||
mark_inode_dirty(inode);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return len - towrite;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static struct super_operations jfs_super_operations = {
|
||||
.alloc_inode = jfs_alloc_inode,
|
||||
.destroy_inode = jfs_destroy_inode,
|
||||
|
|
@ -621,7 +729,11 @@ static struct super_operations jfs_super_operations = {
|
|||
.unlockfs = jfs_unlockfs,
|
||||
.statfs = jfs_statfs,
|
||||
.remount_fs = jfs_remount,
|
||||
.show_options = jfs_show_options
|
||||
.show_options = jfs_show_options,
|
||||
#ifdef CONFIG_QUOTA
|
||||
.quota_read = jfs_quota_read,
|
||||
.quota_write = jfs_quota_write,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct export_operations jfs_export_operations = {
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
|
|||
fl->fl_ops = &nlmclnt_lock_ops;
|
||||
}
|
||||
|
||||
static void do_vfs_lock(struct file_lock *fl)
|
||||
static int do_vfs_lock(struct file_lock *fl)
|
||||
{
|
||||
int res = 0;
|
||||
switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
|
||||
|
|
@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl)
|
|||
default:
|
||||
BUG();
|
||||
}
|
||||
if (res < 0)
|
||||
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
|
||||
__FUNCTION__);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -498,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
|||
struct nlm_host *host = req->a_host;
|
||||
struct nlm_res *resp = &req->a_res;
|
||||
struct nlm_wait *block = NULL;
|
||||
unsigned char fl_flags = fl->fl_flags;
|
||||
int status = -ENOLCK;
|
||||
|
||||
if (!host->h_monitored && nsm_monitor(host) < 0) {
|
||||
|
|
@ -505,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
|||
host->h_name);
|
||||
goto out;
|
||||
}
|
||||
fl->fl_flags |= FL_ACCESS;
|
||||
status = do_vfs_lock(fl);
|
||||
if (status < 0)
|
||||
goto out;
|
||||
|
||||
block = nlmclnt_prepare_block(host, fl);
|
||||
again:
|
||||
|
|
@ -539,9 +542,10 @@ again:
|
|||
up_read(&host->h_rwsem);
|
||||
goto again;
|
||||
}
|
||||
fl->fl_flags |= FL_SLEEP;
|
||||
/* Ensure the resulting lock will get added to granted list */
|
||||
do_vfs_lock(fl);
|
||||
fl->fl_flags = fl_flags | FL_SLEEP;
|
||||
if (do_vfs_lock(fl) < 0)
|
||||
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
|
||||
up_read(&host->h_rwsem);
|
||||
}
|
||||
status = nlm_stat_to_errno(resp->status);
|
||||
|
|
@ -552,6 +556,7 @@ out_unblock:
|
|||
nlmclnt_cancel(host, req->a_args.block, fl);
|
||||
out:
|
||||
nlm_release_call(req);
|
||||
fl->fl_flags = fl_flags;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -606,15 +611,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
|||
{
|
||||
struct nlm_host *host = req->a_host;
|
||||
struct nlm_res *resp = &req->a_res;
|
||||
int status;
|
||||
int status = 0;
|
||||
|
||||
/*
|
||||
* Note: the server is supposed to either grant us the unlock
|
||||
* request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
|
||||
* case, we want to unlock.
|
||||
*/
|
||||
fl->fl_flags |= FL_EXISTS;
|
||||
down_read(&host->h_rwsem);
|
||||
do_vfs_lock(fl);
|
||||
if (do_vfs_lock(fl) == -ENOENT) {
|
||||
up_read(&host->h_rwsem);
|
||||
goto out;
|
||||
}
|
||||
up_read(&host->h_rwsem);
|
||||
|
||||
if (req->a_flags & RPC_TASK_ASYNC)
|
||||
|
|
@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
|||
if (status < 0)
|
||||
goto out;
|
||||
|
||||
status = 0;
|
||||
if (resp->status == NLM_LCK_GRANTED)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -638,9 +638,6 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
|
|||
if (task->tk_status < 0) {
|
||||
/* RPC error: Re-insert for retransmission */
|
||||
timeout = 10 * HZ;
|
||||
} else if (block->b_done) {
|
||||
/* Block already removed, kill it for real */
|
||||
timeout = 0;
|
||||
} else {
|
||||
/* Call was successful, now wait for client callback */
|
||||
timeout = 60 * HZ;
|
||||
|
|
@ -709,13 +706,10 @@ nlmsvc_retry_blocked(void)
|
|||
break;
|
||||
if (time_after(block->b_when,jiffies))
|
||||
break;
|
||||
dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
|
||||
block, block->b_when, block->b_done);
|
||||
dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
|
||||
block, block->b_when);
|
||||
kref_get(&block->b_count);
|
||||
if (block->b_done)
|
||||
nlmsvc_unlink_block(block);
|
||||
else
|
||||
nlmsvc_grant_blocked(block);
|
||||
nlmsvc_grant_blocked(block);
|
||||
nlmsvc_release_block(block);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -237,19 +237,22 @@ static int
|
|||
nlm_traverse_files(struct nlm_host *host, int action)
|
||||
{
|
||||
struct nlm_file *file, **fp;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
mutex_lock(&nlm_file_mutex);
|
||||
for (i = 0; i < FILE_NRHASH; i++) {
|
||||
fp = nlm_files + i;
|
||||
while ((file = *fp) != NULL) {
|
||||
file->f_count++;
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
|
||||
/* Traverse locks, blocks and shares of this file
|
||||
* and update file->f_locks count */
|
||||
if (nlm_inspect_file(host, file, action)) {
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
return 1;
|
||||
}
|
||||
if (nlm_inspect_file(host, file, action))
|
||||
ret = 1;
|
||||
|
||||
mutex_lock(&nlm_file_mutex);
|
||||
file->f_count--;
|
||||
/* No more references to this file. Let go of it. */
|
||||
if (!file->f_blocks && !file->f_locks
|
||||
&& !file->f_shares && !file->f_count) {
|
||||
|
|
@ -262,7 +265,7 @@ nlm_traverse_files(struct nlm_host *host, int action)
|
|||
}
|
||||
}
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
29
fs/locks.c
29
fs/locks.c
|
|
@ -725,6 +725,10 @@ next_task:
|
|||
/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
|
||||
* at the head of the list, but that's secret knowledge known only to
|
||||
* flock_lock_file and posix_lock_file.
|
||||
*
|
||||
* Note that if called with an FL_EXISTS argument, the caller may determine
|
||||
* whether or not a lock was successfully freed by testing the return
|
||||
* value for -ENOENT.
|
||||
*/
|
||||
static int flock_lock_file(struct file *filp, struct file_lock *request)
|
||||
{
|
||||
|
|
@ -735,6 +739,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
|||
int found = 0;
|
||||
|
||||
lock_kernel();
|
||||
if (request->fl_flags & FL_ACCESS)
|
||||
goto find_conflict;
|
||||
for_each_lock(inode, before) {
|
||||
struct file_lock *fl = *before;
|
||||
if (IS_POSIX(fl))
|
||||
|
|
@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
|||
break;
|
||||
}
|
||||
|
||||
if (request->fl_type == F_UNLCK)
|
||||
if (request->fl_type == F_UNLCK) {
|
||||
if ((request->fl_flags & FL_EXISTS) && !found)
|
||||
error = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
error = -ENOMEM;
|
||||
new_fl = locks_alloc_lock();
|
||||
|
|
@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
|||
if (found)
|
||||
cond_resched();
|
||||
|
||||
find_conflict:
|
||||
for_each_lock(inode, before) {
|
||||
struct file_lock *fl = *before;
|
||||
if (IS_POSIX(fl))
|
||||
|
|
@ -777,6 +787,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
|
|||
locks_insert_block(fl, request);
|
||||
goto out;
|
||||
}
|
||||
if (request->fl_flags & FL_ACCESS)
|
||||
goto out;
|
||||
locks_copy_lock(new_fl, request);
|
||||
locks_insert_lock(&inode->i_flock, new_fl);
|
||||
new_fl = NULL;
|
||||
|
|
@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
|
|||
|
||||
error = 0;
|
||||
if (!added) {
|
||||
if (request->fl_type == F_UNLCK)
|
||||
if (request->fl_type == F_UNLCK) {
|
||||
if (request->fl_flags & FL_EXISTS)
|
||||
error = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!new_fl) {
|
||||
error = -ENOLCK;
|
||||
|
|
@ -996,6 +1011,10 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
|
|||
* Add a POSIX style lock to a file.
|
||||
* We merge adjacent & overlapping locks whenever possible.
|
||||
* POSIX locks are sorted by owner task, then by starting address
|
||||
*
|
||||
* Note that if called with an FL_EXISTS argument, the caller may determine
|
||||
* whether or not a lock was successfully freed by testing the return
|
||||
* value for -ENOENT.
|
||||
*/
|
||||
int posix_lock_file(struct file *filp, struct file_lock *fl)
|
||||
{
|
||||
|
|
@ -1402,8 +1421,9 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
|
|||
if (!leases_enable)
|
||||
goto out;
|
||||
|
||||
error = lease_alloc(filp, arg, &fl);
|
||||
if (error)
|
||||
error = -ENOMEM;
|
||||
fl = locks_alloc_lock();
|
||||
if (fl == NULL)
|
||||
goto out;
|
||||
|
||||
locks_copy_lock(fl, lease);
|
||||
|
|
@ -1411,6 +1431,7 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
|
|||
locks_insert_lock(before, fl);
|
||||
|
||||
*flp = fl;
|
||||
error = 0;
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,6 +204,8 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
|
|||
/*
|
||||
* Allocate the buffer map to keep the superblock small.
|
||||
*/
|
||||
if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0)
|
||||
goto out_illegal_sb;
|
||||
i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh);
|
||||
map = kmalloc(i, GFP_KERNEL);
|
||||
if (!map)
|
||||
|
|
@ -263,7 +265,7 @@ out_no_root:
|
|||
|
||||
out_no_bitmap:
|
||||
printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
|
||||
out_freemap:
|
||||
out_freemap:
|
||||
for (i = 0; i < sbi->s_imap_blocks; i++)
|
||||
brelse(sbi->s_imap[i]);
|
||||
for (i = 0; i < sbi->s_zmap_blocks; i++)
|
||||
|
|
@ -276,11 +278,16 @@ out_no_map:
|
|||
printk("MINIX-fs: can't allocate map\n");
|
||||
goto out_release;
|
||||
|
||||
out_illegal_sb:
|
||||
if (!silent)
|
||||
printk("MINIX-fs: bad superblock\n");
|
||||
goto out_release;
|
||||
|
||||
out_no_fs:
|
||||
if (!silent)
|
||||
printk("VFS: Can't find a Minix or Minix V2 filesystem "
|
||||
"on device %s\n", s->s_id);
|
||||
out_release:
|
||||
out_release:
|
||||
brelse(bh);
|
||||
goto out;
|
||||
|
||||
|
|
@ -290,7 +297,7 @@ out_bad_hblock:
|
|||
|
||||
out_bad_sb:
|
||||
printk("MINIX-fs: unable to read superblock\n");
|
||||
out:
|
||||
out:
|
||||
s->s_fs_info = NULL;
|
||||
kfree(sbi);
|
||||
return -EINVAL;
|
||||
|
|
|
|||
27
fs/namei.c
27
fs/namei.c
|
|
@ -159,7 +159,7 @@ char * getname(const char __user * filename)
|
|||
#ifdef CONFIG_AUDITSYSCALL
|
||||
void putname(const char *name)
|
||||
{
|
||||
if (unlikely(current->audit_context))
|
||||
if (unlikely(!audit_dummy_context()))
|
||||
audit_putname(name);
|
||||
else
|
||||
__putname(name);
|
||||
|
|
@ -227,10 +227,10 @@ int generic_permission(struct inode *inode, int mask,
|
|||
|
||||
int permission(struct inode *inode, int mask, struct nameidata *nd)
|
||||
{
|
||||
umode_t mode = inode->i_mode;
|
||||
int retval, submask;
|
||||
|
||||
if (mask & MAY_WRITE) {
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
/*
|
||||
* Nobody gets write access to a read-only fs.
|
||||
|
|
@ -247,6 +247,13 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* MAY_EXEC on regular files requires special handling: We override
|
||||
* filesystem execute permissions if the mode bits aren't set.
|
||||
*/
|
||||
if ((mask & MAY_EXEC) && S_ISREG(mode) && !(mode & S_IXUGO))
|
||||
return -EACCES;
|
||||
|
||||
/* Ordinary permission routines do not understand MAY_APPEND. */
|
||||
submask = mask & ~MAY_APPEND;
|
||||
if (inode->i_op && inode->i_op->permission)
|
||||
|
|
@ -1125,7 +1132,7 @@ static int fastcall do_path_lookup(int dfd, const char *name,
|
|||
retval = link_path_walk(name, nd);
|
||||
out:
|
||||
if (likely(retval == 0)) {
|
||||
if (unlikely(current->audit_context && nd && nd->dentry &&
|
||||
if (unlikely(!audit_dummy_context() && nd && nd->dentry &&
|
||||
nd->dentry->d_inode))
|
||||
audit_inode(name, nd->dentry->d_inode);
|
||||
}
|
||||
|
|
@ -1357,7 +1364,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
|
|||
return -ENOENT;
|
||||
|
||||
BUG_ON(victim->d_parent->d_inode != dir);
|
||||
audit_inode_child(victim->d_name.name, victim->d_inode, dir->i_ino);
|
||||
audit_inode_child(victim->d_name.name, victim->d_inode, dir);
|
||||
|
||||
error = permission(dir,MAY_WRITE | MAY_EXEC, NULL);
|
||||
if (error)
|
||||
|
|
@ -1659,6 +1666,7 @@ do_last:
|
|||
* It already exists.
|
||||
*/
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
audit_inode_update(path.dentry->d_inode);
|
||||
|
||||
error = -EEXIST;
|
||||
if (flag & O_EXCL)
|
||||
|
|
@ -1669,6 +1677,7 @@ do_last:
|
|||
if (flag & O_NOFOLLOW)
|
||||
goto exit_dput;
|
||||
}
|
||||
|
||||
error = -ENOENT;
|
||||
if (!path.dentry->d_inode)
|
||||
goto exit_dput;
|
||||
|
|
@ -1712,8 +1721,14 @@ do_link:
|
|||
if (error)
|
||||
goto exit_dput;
|
||||
error = __do_follow_link(&path, nd);
|
||||
if (error)
|
||||
if (error) {
|
||||
/* Does someone understand code flow here? Or it is only
|
||||
* me so stupid? Anathema to whoever designed this non-sense
|
||||
* with "intent.open".
|
||||
*/
|
||||
release_open_intent(nd);
|
||||
return error;
|
||||
}
|
||||
nd->flags &= ~LOOKUP_PARENT;
|
||||
if (nd->last_type == LAST_BIND)
|
||||
goto ok;
|
||||
|
|
@ -1759,6 +1774,8 @@ struct dentry *lookup_create(struct nameidata *nd, int is_dir)
|
|||
if (nd->last_type != LAST_NORM)
|
||||
goto fail;
|
||||
nd->flags &= ~LOOKUP_PARENT;
|
||||
nd->flags |= LOOKUP_CREATE;
|
||||
nd->intent.open.flags = O_EXCL;
|
||||
|
||||
/*
|
||||
* Do the final lookup.
|
||||
|
|
|
|||
|
|
@ -690,7 +690,9 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
|
|||
goto out_force;
|
||||
/* This is an open(2) */
|
||||
if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
|
||||
!(server->flags & NFS_MOUNT_NOCTO))
|
||||
!(server->flags & NFS_MOUNT_NOCTO) &&
|
||||
(S_ISREG(inode->i_mode) ||
|
||||
S_ISDIR(inode->i_mode)))
|
||||
goto out_force;
|
||||
}
|
||||
return nfs_revalidate_inode(server, inode);
|
||||
|
|
|
|||
435
fs/nfs/direct.c
435
fs/nfs/direct.c
|
|
@ -67,25 +67,19 @@ struct nfs_direct_req {
|
|||
struct kref kref; /* release manager */
|
||||
|
||||
/* I/O parameters */
|
||||
struct list_head list, /* nfs_read/write_data structs */
|
||||
rewrite_list; /* saved nfs_write_data structs */
|
||||
struct nfs_open_context *ctx; /* file open context info */
|
||||
struct kiocb * iocb; /* controlling i/o request */
|
||||
struct inode * inode; /* target file of i/o */
|
||||
unsigned long user_addr; /* location of user's buffer */
|
||||
size_t user_count; /* total bytes to move */
|
||||
loff_t pos; /* starting offset in file */
|
||||
struct page ** pages; /* pages in our buffer */
|
||||
unsigned int npages; /* count of pages */
|
||||
|
||||
/* completion state */
|
||||
atomic_t io_count; /* i/os we're waiting for */
|
||||
spinlock_t lock; /* protect completion state */
|
||||
int outstanding; /* i/os we're waiting for */
|
||||
ssize_t count, /* bytes actually processed */
|
||||
error; /* any reported error */
|
||||
struct completion completion; /* wait for i/o completion */
|
||||
|
||||
/* commit state */
|
||||
struct list_head rewrite_list; /* saved nfs_write_data structs */
|
||||
struct nfs_write_data * commit_data; /* special write_data for commits */
|
||||
int flags;
|
||||
#define NFS_ODIRECT_DO_COMMIT (1) /* an unstable reply was received */
|
||||
|
|
@ -93,8 +87,37 @@ struct nfs_direct_req {
|
|||
struct nfs_writeverf verf; /* unstable write verifier */
|
||||
};
|
||||
|
||||
static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync);
|
||||
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode);
|
||||
static const struct rpc_call_ops nfs_write_direct_ops;
|
||||
|
||||
static inline void get_dreq(struct nfs_direct_req *dreq)
|
||||
{
|
||||
atomic_inc(&dreq->io_count);
|
||||
}
|
||||
|
||||
static inline int put_dreq(struct nfs_direct_req *dreq)
|
||||
{
|
||||
return atomic_dec_and_test(&dreq->io_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* "size" is never larger than rsize or wsize.
|
||||
*/
|
||||
static inline int nfs_direct_count_pages(unsigned long user_addr, size_t size)
|
||||
{
|
||||
int page_count;
|
||||
|
||||
page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
page_count -= user_addr >> PAGE_SHIFT;
|
||||
BUG_ON(page_count < 0);
|
||||
|
||||
return page_count;
|
||||
}
|
||||
|
||||
static inline unsigned int nfs_max_pages(unsigned int size)
|
||||
{
|
||||
return (size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_direct_IO - NFS address space operation for direct I/O
|
||||
|
|
@ -118,50 +141,21 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
|
||||
static void nfs_direct_dirty_pages(struct page **pages, int npages)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < npages; i++) {
|
||||
struct page *page = pages[i];
|
||||
if (do_dirty && !PageCompound(page))
|
||||
if (!PageCompound(page))
|
||||
set_page_dirty_lock(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
kfree(pages);
|
||||
}
|
||||
|
||||
static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages)
|
||||
static void nfs_direct_release_pages(struct page **pages, int npages)
|
||||
{
|
||||
int result = -ENOMEM;
|
||||
unsigned long page_count;
|
||||
size_t array_size;
|
||||
|
||||
page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
page_count -= user_addr >> PAGE_SHIFT;
|
||||
|
||||
array_size = (page_count * sizeof(struct page *));
|
||||
*pages = kmalloc(array_size, GFP_KERNEL);
|
||||
if (*pages) {
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
result = get_user_pages(current, current->mm, user_addr,
|
||||
page_count, (rw == READ), 0,
|
||||
*pages, NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (result != page_count) {
|
||||
/*
|
||||
* If we got fewer pages than expected from
|
||||
* get_user_pages(), the user buffer runs off the
|
||||
* end of a mapping; return EFAULT.
|
||||
*/
|
||||
if (result >= 0) {
|
||||
nfs_free_user_pages(*pages, result, 0);
|
||||
result = -EFAULT;
|
||||
} else
|
||||
kfree(*pages);
|
||||
*pages = NULL;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
int i;
|
||||
for (i = 0; i < npages; i++)
|
||||
page_cache_release(pages[i]);
|
||||
}
|
||||
|
||||
static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
|
||||
|
|
@ -173,13 +167,13 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
|
|||
return NULL;
|
||||
|
||||
kref_init(&dreq->kref);
|
||||
kref_get(&dreq->kref);
|
||||
init_completion(&dreq->completion);
|
||||
INIT_LIST_HEAD(&dreq->list);
|
||||
INIT_LIST_HEAD(&dreq->rewrite_list);
|
||||
dreq->iocb = NULL;
|
||||
dreq->ctx = NULL;
|
||||
spin_lock_init(&dreq->lock);
|
||||
dreq->outstanding = 0;
|
||||
atomic_set(&dreq->io_count, 0);
|
||||
dreq->count = 0;
|
||||
dreq->error = 0;
|
||||
dreq->flags = 0;
|
||||
|
|
@ -220,18 +214,11 @@ out:
|
|||
}
|
||||
|
||||
/*
|
||||
* We must hold a reference to all the pages in this direct read request
|
||||
* until the RPCs complete. This could be long *after* we are woken up in
|
||||
* nfs_direct_wait (for instance, if someone hits ^C on a slow server).
|
||||
*
|
||||
* In addition, synchronous I/O uses a stack-allocated iocb. Thus we
|
||||
* can't trust the iocb is still valid here if this is a synchronous
|
||||
* request. If the waiter is woken prematurely, the iocb is long gone.
|
||||
* Synchronous I/O uses a stack-allocated iocb. Thus we can't trust
|
||||
* the iocb is still valid here if this is a synchronous request.
|
||||
*/
|
||||
static void nfs_direct_complete(struct nfs_direct_req *dreq)
|
||||
{
|
||||
nfs_free_user_pages(dreq->pages, dreq->npages, 1);
|
||||
|
||||
if (dreq->iocb) {
|
||||
long res = (long) dreq->error;
|
||||
if (!res)
|
||||
|
|
@ -244,48 +231,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
|
|||
}
|
||||
|
||||
/*
|
||||
* Note we also set the number of requests we have in the dreq when we are
|
||||
* done. This prevents races with I/O completion so we will always wait
|
||||
* until all requests have been dispatched and completed.
|
||||
* We must hold a reference to all the pages in this direct read request
|
||||
* until the RPCs complete. This could be long *after* we are woken up in
|
||||
* nfs_direct_wait (for instance, if someone hits ^C on a slow server).
|
||||
*/
|
||||
static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, size_t rsize)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct nfs_direct_req *dreq;
|
||||
unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
|
||||
dreq = nfs_direct_req_alloc();
|
||||
if (!dreq)
|
||||
return NULL;
|
||||
|
||||
list = &dreq->list;
|
||||
for(;;) {
|
||||
struct nfs_read_data *data = nfs_readdata_alloc(rpages);
|
||||
|
||||
if (unlikely(!data)) {
|
||||
while (!list_empty(list)) {
|
||||
data = list_entry(list->next,
|
||||
struct nfs_read_data, pages);
|
||||
list_del(&data->pages);
|
||||
nfs_readdata_free(data);
|
||||
}
|
||||
kref_put(&dreq->kref, nfs_direct_req_release);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&data->pages);
|
||||
list_add(&data->pages, list);
|
||||
|
||||
data->req = (struct nfs_page *) dreq;
|
||||
dreq->outstanding++;
|
||||
if (nbytes <= rsize)
|
||||
break;
|
||||
nbytes -= rsize;
|
||||
}
|
||||
kref_get(&dreq->kref);
|
||||
return dreq;
|
||||
}
|
||||
|
||||
static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_read_data *data = calldata;
|
||||
|
|
@ -294,6 +243,9 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
|
|||
if (nfs_readpage_result(task, data) != 0)
|
||||
return;
|
||||
|
||||
nfs_direct_dirty_pages(data->pagevec, data->npages);
|
||||
nfs_direct_release_pages(data->pagevec, data->npages);
|
||||
|
||||
spin_lock(&dreq->lock);
|
||||
|
||||
if (likely(task->tk_status >= 0))
|
||||
|
|
@ -301,13 +253,10 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
|
|||
else
|
||||
dreq->error = task->tk_status;
|
||||
|
||||
if (--dreq->outstanding) {
|
||||
spin_unlock(&dreq->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_unlock(&dreq->lock);
|
||||
nfs_direct_complete(dreq);
|
||||
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_complete(dreq);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs_read_direct_ops = {
|
||||
|
|
@ -316,41 +265,60 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
|
|||
};
|
||||
|
||||
/*
|
||||
* For each nfs_read_data struct that was allocated on the list, dispatch
|
||||
* an NFS READ operation
|
||||
* For each rsize'd chunk of the user's buffer, dispatch an NFS READ
|
||||
* operation. If nfs_readdata_alloc() or get_user_pages() fails,
|
||||
* bail and stop sending more reads. Read length accounting is
|
||||
* handled automatically by nfs_direct_read_result(). Otherwise, if
|
||||
* no requests have been sent, just return an error.
|
||||
*/
|
||||
static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
|
||||
static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
|
||||
{
|
||||
struct nfs_open_context *ctx = dreq->ctx;
|
||||
struct inode *inode = ctx->dentry->d_inode;
|
||||
struct list_head *list = &dreq->list;
|
||||
struct page **pages = dreq->pages;
|
||||
size_t count = dreq->user_count;
|
||||
loff_t pos = dreq->pos;
|
||||
size_t rsize = NFS_SERVER(inode)->rsize;
|
||||
unsigned int curpage, pgbase;
|
||||
unsigned int rpages = nfs_max_pages(rsize);
|
||||
unsigned int pgbase;
|
||||
int result;
|
||||
ssize_t started = 0;
|
||||
|
||||
curpage = 0;
|
||||
pgbase = dreq->user_addr & ~PAGE_MASK;
|
||||
get_dreq(dreq);
|
||||
|
||||
pgbase = user_addr & ~PAGE_MASK;
|
||||
do {
|
||||
struct nfs_read_data *data;
|
||||
size_t bytes;
|
||||
|
||||
result = -ENOMEM;
|
||||
data = nfs_readdata_alloc(rpages);
|
||||
if (unlikely(!data))
|
||||
break;
|
||||
|
||||
bytes = rsize;
|
||||
if (count < rsize)
|
||||
bytes = count;
|
||||
|
||||
BUG_ON(list_empty(list));
|
||||
data = list_entry(list->next, struct nfs_read_data, pages);
|
||||
list_del_init(&data->pages);
|
||||
data->npages = nfs_direct_count_pages(user_addr, bytes);
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
result = get_user_pages(current, current->mm, user_addr,
|
||||
data->npages, 1, 0, data->pagevec, NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (unlikely(result < data->npages)) {
|
||||
if (result > 0)
|
||||
nfs_direct_release_pages(data->pagevec, result);
|
||||
nfs_readdata_release(data);
|
||||
break;
|
||||
}
|
||||
|
||||
get_dreq(dreq);
|
||||
|
||||
data->req = (struct nfs_page *) dreq;
|
||||
data->inode = inode;
|
||||
data->cred = ctx->cred;
|
||||
data->args.fh = NFS_FH(inode);
|
||||
data->args.context = ctx;
|
||||
data->args.offset = pos;
|
||||
data->args.pgbase = pgbase;
|
||||
data->args.pages = &pages[curpage];
|
||||
data->args.pages = data->pagevec;
|
||||
data->args.count = bytes;
|
||||
data->res.fattr = &data->fattr;
|
||||
data->res.eof = 0;
|
||||
|
|
@ -373,33 +341,35 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
|
|||
bytes,
|
||||
(unsigned long long)data->args.offset);
|
||||
|
||||
started += bytes;
|
||||
user_addr += bytes;
|
||||
pos += bytes;
|
||||
pgbase += bytes;
|
||||
curpage += pgbase >> PAGE_SHIFT;
|
||||
pgbase &= ~PAGE_MASK;
|
||||
|
||||
count -= bytes;
|
||||
} while (count != 0);
|
||||
BUG_ON(!list_empty(list));
|
||||
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_complete(dreq);
|
||||
|
||||
if (started)
|
||||
return 0;
|
||||
return result < 0 ? (ssize_t) result : -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, unsigned int nr_pages)
|
||||
static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t result;
|
||||
ssize_t result = 0;
|
||||
sigset_t oldset;
|
||||
struct inode *inode = iocb->ki_filp->f_mapping->host;
|
||||
struct rpc_clnt *clnt = NFS_CLIENT(inode);
|
||||
struct nfs_direct_req *dreq;
|
||||
|
||||
dreq = nfs_direct_read_alloc(count, NFS_SERVER(inode)->rsize);
|
||||
dreq = nfs_direct_req_alloc();
|
||||
if (!dreq)
|
||||
return -ENOMEM;
|
||||
|
||||
dreq->user_addr = user_addr;
|
||||
dreq->user_count = count;
|
||||
dreq->pos = pos;
|
||||
dreq->pages = pages;
|
||||
dreq->npages = nr_pages;
|
||||
dreq->inode = inode;
|
||||
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
|
||||
if (!is_sync_kiocb(iocb))
|
||||
|
|
@ -407,8 +377,9 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
|
|||
|
||||
nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
|
||||
rpc_clnt_sigmask(clnt, &oldset);
|
||||
nfs_direct_read_schedule(dreq);
|
||||
result = nfs_direct_wait(dreq);
|
||||
result = nfs_direct_read_schedule(dreq, user_addr, count, pos);
|
||||
if (!result)
|
||||
result = nfs_direct_wait(dreq);
|
||||
rpc_clnt_sigunmask(clnt, &oldset);
|
||||
|
||||
return result;
|
||||
|
|
@ -416,10 +387,10 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
|
|||
|
||||
static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
|
||||
{
|
||||
list_splice_init(&dreq->rewrite_list, &dreq->list);
|
||||
while (!list_empty(&dreq->list)) {
|
||||
struct nfs_write_data *data = list_entry(dreq->list.next, struct nfs_write_data, pages);
|
||||
while (!list_empty(&dreq->rewrite_list)) {
|
||||
struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages);
|
||||
list_del(&data->pages);
|
||||
nfs_direct_release_pages(data->pagevec, data->npages);
|
||||
nfs_writedata_release(data);
|
||||
}
|
||||
}
|
||||
|
|
@ -427,14 +398,51 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
|
|||
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
||||
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
|
||||
{
|
||||
struct list_head *pos;
|
||||
struct inode *inode = dreq->inode;
|
||||
struct list_head *p;
|
||||
struct nfs_write_data *data;
|
||||
|
||||
list_splice_init(&dreq->rewrite_list, &dreq->list);
|
||||
list_for_each(pos, &dreq->list)
|
||||
dreq->outstanding++;
|
||||
dreq->count = 0;
|
||||
get_dreq(dreq);
|
||||
|
||||
nfs_direct_write_schedule(dreq, FLUSH_STABLE);
|
||||
list_for_each(p, &dreq->rewrite_list) {
|
||||
data = list_entry(p, struct nfs_write_data, pages);
|
||||
|
||||
get_dreq(dreq);
|
||||
|
||||
/*
|
||||
* Reset data->res.
|
||||
*/
|
||||
nfs_fattr_init(&data->fattr);
|
||||
data->res.count = data->args.count;
|
||||
memset(&data->verf, 0, sizeof(data->verf));
|
||||
|
||||
/*
|
||||
* Reuse data->task; data->args should not have changed
|
||||
* since the original request was sent.
|
||||
*/
|
||||
rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC,
|
||||
&nfs_write_direct_ops, data);
|
||||
NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE);
|
||||
|
||||
data->task.tk_priority = RPC_PRIORITY_NORMAL;
|
||||
data->task.tk_cookie = (unsigned long) inode;
|
||||
|
||||
/*
|
||||
* We're called via an RPC callback, so BKL is already held.
|
||||
*/
|
||||
rpc_execute(&data->task);
|
||||
|
||||
dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
|
||||
data->task.tk_pid,
|
||||
inode->i_sb->s_id,
|
||||
(long long)NFS_FILEID(inode),
|
||||
data->args.count,
|
||||
(unsigned long long)data->args.offset);
|
||||
}
|
||||
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_write_complete(dreq, inode);
|
||||
}
|
||||
|
||||
static void nfs_direct_commit_result(struct rpc_task *task, void *calldata)
|
||||
|
|
@ -471,8 +479,8 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
|
|||
data->cred = dreq->ctx->cred;
|
||||
|
||||
data->args.fh = NFS_FH(data->inode);
|
||||
data->args.offset = dreq->pos;
|
||||
data->args.count = dreq->user_count;
|
||||
data->args.offset = 0;
|
||||
data->args.count = 0;
|
||||
data->res.count = 0;
|
||||
data->res.fattr = &data->fattr;
|
||||
data->res.verf = &data->verf;
|
||||
|
|
@ -534,47 +542,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
|
|||
}
|
||||
#endif
|
||||
|
||||
static struct nfs_direct_req *nfs_direct_write_alloc(size_t nbytes, size_t wsize)
|
||||
{
|
||||
struct list_head *list;
|
||||
struct nfs_direct_req *dreq;
|
||||
unsigned int wpages = (wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
||||
|
||||
dreq = nfs_direct_req_alloc();
|
||||
if (!dreq)
|
||||
return NULL;
|
||||
|
||||
list = &dreq->list;
|
||||
for(;;) {
|
||||
struct nfs_write_data *data = nfs_writedata_alloc(wpages);
|
||||
|
||||
if (unlikely(!data)) {
|
||||
while (!list_empty(list)) {
|
||||
data = list_entry(list->next,
|
||||
struct nfs_write_data, pages);
|
||||
list_del(&data->pages);
|
||||
nfs_writedata_free(data);
|
||||
}
|
||||
kref_put(&dreq->kref, nfs_direct_req_release);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&data->pages);
|
||||
list_add(&data->pages, list);
|
||||
|
||||
data->req = (struct nfs_page *) dreq;
|
||||
dreq->outstanding++;
|
||||
if (nbytes <= wsize)
|
||||
break;
|
||||
nbytes -= wsize;
|
||||
}
|
||||
|
||||
nfs_alloc_commit_data(dreq);
|
||||
|
||||
kref_get(&dreq->kref);
|
||||
return dreq;
|
||||
}
|
||||
|
||||
static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_write_data *data = calldata;
|
||||
|
|
@ -604,8 +571,6 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
|
|||
}
|
||||
}
|
||||
}
|
||||
/* In case we have to resend */
|
||||
data->args.stable = NFS_FILE_SYNC;
|
||||
|
||||
spin_unlock(&dreq->lock);
|
||||
}
|
||||
|
|
@ -619,14 +584,8 @@ static void nfs_direct_write_release(void *calldata)
|
|||
struct nfs_write_data *data = calldata;
|
||||
struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req;
|
||||
|
||||
spin_lock(&dreq->lock);
|
||||
if (--dreq->outstanding) {
|
||||
spin_unlock(&dreq->lock);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&dreq->lock);
|
||||
|
||||
nfs_direct_write_complete(dreq, data->inode);
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_write_complete(dreq, data->inode);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs_write_direct_ops = {
|
||||
|
|
@ -635,41 +594,62 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
|
|||
};
|
||||
|
||||
/*
|
||||
* For each nfs_write_data struct that was allocated on the list, dispatch
|
||||
* an NFS WRITE operation
|
||||
* For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE
|
||||
* operation. If nfs_writedata_alloc() or get_user_pages() fails,
|
||||
* bail and stop sending more writes. Write length accounting is
|
||||
* handled automatically by nfs_direct_write_result(). Otherwise, if
|
||||
* no requests have been sent, just return an error.
|
||||
*/
|
||||
static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
|
||||
static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
|
||||
{
|
||||
struct nfs_open_context *ctx = dreq->ctx;
|
||||
struct inode *inode = ctx->dentry->d_inode;
|
||||
struct list_head *list = &dreq->list;
|
||||
struct page **pages = dreq->pages;
|
||||
size_t count = dreq->user_count;
|
||||
loff_t pos = dreq->pos;
|
||||
size_t wsize = NFS_SERVER(inode)->wsize;
|
||||
unsigned int curpage, pgbase;
|
||||
unsigned int wpages = nfs_max_pages(wsize);
|
||||
unsigned int pgbase;
|
||||
int result;
|
||||
ssize_t started = 0;
|
||||
|
||||
curpage = 0;
|
||||
pgbase = dreq->user_addr & ~PAGE_MASK;
|
||||
get_dreq(dreq);
|
||||
|
||||
pgbase = user_addr & ~PAGE_MASK;
|
||||
do {
|
||||
struct nfs_write_data *data;
|
||||
size_t bytes;
|
||||
|
||||
result = -ENOMEM;
|
||||
data = nfs_writedata_alloc(wpages);
|
||||
if (unlikely(!data))
|
||||
break;
|
||||
|
||||
bytes = wsize;
|
||||
if (count < wsize)
|
||||
bytes = count;
|
||||
|
||||
BUG_ON(list_empty(list));
|
||||
data = list_entry(list->next, struct nfs_write_data, pages);
|
||||
data->npages = nfs_direct_count_pages(user_addr, bytes);
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
result = get_user_pages(current, current->mm, user_addr,
|
||||
data->npages, 0, 0, data->pagevec, NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
if (unlikely(result < data->npages)) {
|
||||
if (result > 0)
|
||||
nfs_direct_release_pages(data->pagevec, result);
|
||||
nfs_writedata_release(data);
|
||||
break;
|
||||
}
|
||||
|
||||
get_dreq(dreq);
|
||||
|
||||
list_move_tail(&data->pages, &dreq->rewrite_list);
|
||||
|
||||
data->req = (struct nfs_page *) dreq;
|
||||
data->inode = inode;
|
||||
data->cred = ctx->cred;
|
||||
data->args.fh = NFS_FH(inode);
|
||||
data->args.context = ctx;
|
||||
data->args.offset = pos;
|
||||
data->args.pgbase = pgbase;
|
||||
data->args.pages = &pages[curpage];
|
||||
data->args.pages = data->pagevec;
|
||||
data->args.count = bytes;
|
||||
data->res.fattr = &data->fattr;
|
||||
data->res.count = bytes;
|
||||
|
|
@ -693,19 +673,26 @@ static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
|
|||
bytes,
|
||||
(unsigned long long)data->args.offset);
|
||||
|
||||
started += bytes;
|
||||
user_addr += bytes;
|
||||
pos += bytes;
|
||||
pgbase += bytes;
|
||||
curpage += pgbase >> PAGE_SHIFT;
|
||||
pgbase &= ~PAGE_MASK;
|
||||
|
||||
count -= bytes;
|
||||
} while (count != 0);
|
||||
BUG_ON(!list_empty(list));
|
||||
|
||||
if (put_dreq(dreq))
|
||||
nfs_direct_write_complete(dreq, inode);
|
||||
|
||||
if (started)
|
||||
return 0;
|
||||
return result < 0 ? (ssize_t) result : -EFAULT;
|
||||
}
|
||||
|
||||
static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, int nr_pages)
|
||||
static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t result;
|
||||
ssize_t result = 0;
|
||||
sigset_t oldset;
|
||||
struct inode *inode = iocb->ki_filp->f_mapping->host;
|
||||
struct rpc_clnt *clnt = NFS_CLIENT(inode);
|
||||
|
|
@ -713,17 +700,14 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
|
|||
size_t wsize = NFS_SERVER(inode)->wsize;
|
||||
int sync = 0;
|
||||
|
||||
dreq = nfs_direct_write_alloc(count, wsize);
|
||||
dreq = nfs_direct_req_alloc();
|
||||
if (!dreq)
|
||||
return -ENOMEM;
|
||||
nfs_alloc_commit_data(dreq);
|
||||
|
||||
if (dreq->commit_data == NULL || count < wsize)
|
||||
sync = FLUSH_STABLE;
|
||||
|
||||
dreq->user_addr = user_addr;
|
||||
dreq->user_count = count;
|
||||
dreq->pos = pos;
|
||||
dreq->pages = pages;
|
||||
dreq->npages = nr_pages;
|
||||
dreq->inode = inode;
|
||||
dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
|
||||
if (!is_sync_kiocb(iocb))
|
||||
|
|
@ -734,8 +718,9 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
|
|||
nfs_begin_data_update(inode);
|
||||
|
||||
rpc_clnt_sigmask(clnt, &oldset);
|
||||
nfs_direct_write_schedule(dreq, sync);
|
||||
result = nfs_direct_wait(dreq);
|
||||
result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
|
||||
if (!result)
|
||||
result = nfs_direct_wait(dreq);
|
||||
rpc_clnt_sigunmask(clnt, &oldset);
|
||||
|
||||
return result;
|
||||
|
|
@ -765,8 +750,6 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
|
|||
ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t retval = -EINVAL;
|
||||
int page_count;
|
||||
struct page **pages;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
|
||||
|
|
@ -788,14 +771,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count,
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = nfs_get_user_pages(READ, (unsigned long) buf,
|
||||
count, &pages);
|
||||
if (retval < 0)
|
||||
goto out;
|
||||
page_count = retval;
|
||||
|
||||
retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos,
|
||||
pages, page_count);
|
||||
retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos);
|
||||
if (retval > 0)
|
||||
iocb->ki_pos = pos + retval;
|
||||
|
||||
|
|
@ -831,8 +807,6 @@ out:
|
|||
ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
|
||||
{
|
||||
ssize_t retval;
|
||||
int page_count;
|
||||
struct page **pages;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
|
||||
|
|
@ -860,14 +834,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = nfs_get_user_pages(WRITE, (unsigned long) buf,
|
||||
count, &pages);
|
||||
if (retval < 0)
|
||||
goto out;
|
||||
page_count = retval;
|
||||
|
||||
retval = nfs_direct_write(iocb, (unsigned long) buf, count,
|
||||
pos, pages, page_count);
|
||||
retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
|
||||
|
||||
/*
|
||||
* XXX: nfs_end_data_update() already ensures this file's
|
||||
|
|
|
|||
|
|
@ -312,7 +312,13 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
|
|||
|
||||
static int nfs_release_page(struct page *page, gfp_t gfp)
|
||||
{
|
||||
return !nfs_wb_page(page->mapping->host, page);
|
||||
if (gfp & __GFP_FS)
|
||||
return !nfs_wb_page(page->mapping->host, page);
|
||||
else
|
||||
/*
|
||||
* Avoid deadlock on nfs_wait_on_request().
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct address_space_operations nfs_file_aops = {
|
||||
|
|
|
|||
|
|
@ -130,9 +130,7 @@ nfs_idmap_delete(struct nfs4_client *clp)
|
|||
|
||||
if (!idmap)
|
||||
return;
|
||||
dput(idmap->idmap_dentry);
|
||||
idmap->idmap_dentry = NULL;
|
||||
rpc_unlink(idmap->idmap_path);
|
||||
rpc_unlink(idmap->idmap_dentry);
|
||||
clp->cl_idmap = NULL;
|
||||
kfree(idmap);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry,
|
|||
namelen = dentry->d_name.len;
|
||||
buflen -= namelen + 1;
|
||||
if (buflen < 0)
|
||||
goto Elong;
|
||||
goto Elong_unlock;
|
||||
end -= namelen;
|
||||
memcpy(end, dentry->d_name.name, namelen);
|
||||
*--end = '/';
|
||||
|
|
@ -68,6 +68,8 @@ char *nfs_path(const char *base, const struct dentry *dentry,
|
|||
end -= namelen;
|
||||
memcpy(end, base, namelen);
|
||||
return end;
|
||||
Elong_unlock:
|
||||
spin_unlock(&dcache_lock);
|
||||
Elong:
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2668,7 +2668,7 @@ out:
|
|||
nfs4_set_cached_acl(inode, acl);
|
||||
}
|
||||
|
||||
static inline ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
|
||||
static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
|
||||
{
|
||||
struct page *pages[NFS4ACL_MAXPAGES];
|
||||
struct nfs_getaclargs args = {
|
||||
|
|
@ -2721,6 +2721,19 @@ out_free:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
ssize_t ret;
|
||||
do {
|
||||
ret = __nfs4_get_acl_uncached(inode, buf, buflen);
|
||||
if (ret >= 0)
|
||||
break;
|
||||
ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
|
||||
} while (exception.retry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
|
|
@ -2737,7 +2750,7 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
|
|||
return nfs4_get_acl_uncached(inode, buf, buflen);
|
||||
}
|
||||
|
||||
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
|
||||
static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
struct page *pages[NFS4ACL_MAXPAGES];
|
||||
|
|
@ -2763,6 +2776,18 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
|
||||
{
|
||||
struct nfs4_exception exception = { };
|
||||
int err;
|
||||
do {
|
||||
err = nfs4_handle_exception(NFS_SERVER(inode),
|
||||
__nfs4_proc_set_acl(inode, buf, buflen),
|
||||
&exception);
|
||||
} while (exception.retry);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
|
||||
{
|
||||
|
|
@ -3144,9 +3169,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
|
|||
default:
|
||||
BUG();
|
||||
}
|
||||
if (res < 0)
|
||||
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
|
||||
__FUNCTION__);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -3258,8 +3280,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
|
|||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/* Unlock _before_ we do the RPC call */
|
||||
do_vfs_lock(fl->fl_file, fl);
|
||||
return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);
|
||||
}
|
||||
|
||||
|
|
@ -3270,30 +3290,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
|
|||
struct rpc_task *task;
|
||||
int status = 0;
|
||||
|
||||
status = nfs4_set_lock_state(state, request);
|
||||
/* Unlock _before_ we do the RPC call */
|
||||
request->fl_flags |= FL_EXISTS;
|
||||
if (do_vfs_lock(request->fl_file, request) == -ENOENT)
|
||||
goto out;
|
||||
if (status != 0)
|
||||
goto out;
|
||||
/* Is this a delegated lock? */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags))
|
||||
goto out_unlock;
|
||||
/* Is this open_owner holding any locks on the server? */
|
||||
if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
|
||||
goto out_unlock;
|
||||
|
||||
status = nfs4_set_lock_state(state, request);
|
||||
if (status != 0)
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
lsp = request->fl_u.nfs4_fl.owner;
|
||||
status = -ENOMEM;
|
||||
seqid = nfs_alloc_seqid(&lsp->ls_seqid);
|
||||
status = -ENOMEM;
|
||||
if (seqid == NULL)
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
|
||||
status = PTR_ERR(task);
|
||||
if (IS_ERR(task))
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
status = nfs4_wait_for_completion_rpc_task(task);
|
||||
rpc_release_task(task);
|
||||
return status;
|
||||
out_unlock:
|
||||
do_vfs_lock(request->fl_file, request);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -3461,10 +3479,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
|
|||
struct nfs4_exception exception = { };
|
||||
int err;
|
||||
|
||||
/* Cache the lock if possible... */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags))
|
||||
return 0;
|
||||
do {
|
||||
/* Cache the lock if possible... */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
|
||||
return 0;
|
||||
err = _nfs4_do_setlk(state, F_SETLK, request, 1);
|
||||
if (err != -NFS4ERR_DELAY)
|
||||
break;
|
||||
|
|
@ -3483,6 +3501,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
|
|||
if (err != 0)
|
||||
return err;
|
||||
do {
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
|
||||
return 0;
|
||||
err = _nfs4_do_setlk(state, F_SETLK, request, 0);
|
||||
if (err != -NFS4ERR_DELAY)
|
||||
break;
|
||||
|
|
@ -3494,29 +3514,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
|
|||
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
||||
{
|
||||
struct nfs4_client *clp = state->owner->so_client;
|
||||
unsigned char fl_flags = request->fl_flags;
|
||||
int status;
|
||||
|
||||
/* Is this a delegated open? */
|
||||
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))
|
||||
return status;
|
||||
}
|
||||
down_read(&clp->cl_sem);
|
||||
status = nfs4_set_lock_state(state, request);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
request->fl_flags |= FL_ACCESS;
|
||||
status = do_vfs_lock(request->fl_file, request);
|
||||
if (status < 0)
|
||||
goto out;
|
||||
down_read(&clp->cl_sem);
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
|
||||
struct nfs_inode *nfsi = NFS_I(state->inode);
|
||||
/* Yes: cache locks! */
|
||||
down_read(&nfsi->rwsem);
|
||||
/* ...but avoid races with delegation recall... */
|
||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
|
||||
request->fl_flags = fl_flags & ~FL_SLEEP;
|
||||
status = do_vfs_lock(request->fl_file, request);
|
||||
up_read(&nfsi->rwsem);
|
||||
goto out_unlock;
|
||||
}
|
||||
up_read(&nfsi->rwsem);
|
||||
}
|
||||
status = _nfs4_do_setlk(state, cmd, request, 0);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
/* Note: we always want to sleep here! */
|
||||
request->fl_flags |= FL_SLEEP;
|
||||
request->fl_flags = fl_flags | FL_SLEEP;
|
||||
if (do_vfs_lock(request->fl_file, request) < 0)
|
||||
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
|
||||
out:
|
||||
out_unlock:
|
||||
up_read(&clp->cl_sem);
|
||||
out:
|
||||
request->fl_flags = fl_flags;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3355,7 +3355,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
|
|||
struct kvec *iov = rcvbuf->head;
|
||||
unsigned int nr, pglen = rcvbuf->page_len;
|
||||
uint32_t *end, *entry, *p, *kaddr;
|
||||
uint32_t len, attrlen;
|
||||
uint32_t len, attrlen, xlen;
|
||||
int hdrlen, recvd, status;
|
||||
|
||||
status = decode_op_hdr(xdr, OP_READDIR);
|
||||
|
|
@ -3377,10 +3377,10 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
|
|||
|
||||
BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
|
||||
kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
|
||||
end = (uint32_t *) ((char *)p + pglen + readdir->pgbase);
|
||||
end = p + ((pglen + readdir->pgbase) >> 2);
|
||||
entry = p;
|
||||
for (nr = 0; *p++; nr++) {
|
||||
if (p + 3 > end)
|
||||
if (end - p < 3)
|
||||
goto short_pkt;
|
||||
dprintk("cookie = %Lu, ", *((unsigned long long *)p));
|
||||
p += 2; /* cookie */
|
||||
|
|
@ -3389,18 +3389,19 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
|
|||
printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
|
||||
goto err_unmap;
|
||||
}
|
||||
xlen = XDR_QUADLEN(len);
|
||||
if (end - p < xlen + 1)
|
||||
goto short_pkt;
|
||||
dprintk("filename = %*s\n", len, (char *)p);
|
||||
p += XDR_QUADLEN(len);
|
||||
if (p + 1 > end)
|
||||
goto short_pkt;
|
||||
p += xlen;
|
||||
len = ntohl(*p++); /* bitmap length */
|
||||
if (end - p < len + 1)
|
||||
goto short_pkt;
|
||||
p += len;
|
||||
if (p + 1 > end)
|
||||
goto short_pkt;
|
||||
attrlen = XDR_QUADLEN(ntohl(*p++));
|
||||
p += attrlen; /* attributes */
|
||||
if (p + 2 > end)
|
||||
if (end - p < attrlen + 2)
|
||||
goto short_pkt;
|
||||
p += attrlen; /* attributes */
|
||||
entry = p;
|
||||
}
|
||||
if (!nr && (entry[0] != 0 || entry[1] == 0))
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
|
|||
return p;
|
||||
}
|
||||
|
||||
void nfs_readdata_free(struct nfs_read_data *p)
|
||||
static void nfs_readdata_free(struct nfs_read_data *p)
|
||||
{
|
||||
if (p && (p->pagevec != &p->page_array[0]))
|
||||
kfree(p->pagevec);
|
||||
|
|
@ -116,10 +116,17 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data)
|
|||
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
|
||||
base &= ~PAGE_CACHE_MASK;
|
||||
pglen = PAGE_CACHE_SIZE - base;
|
||||
if (pglen < remainder)
|
||||
for (;;) {
|
||||
if (remainder <= pglen) {
|
||||
memclear_highpage_flush(*pages, base, remainder);
|
||||
break;
|
||||
}
|
||||
memclear_highpage_flush(*pages, base, pglen);
|
||||
else
|
||||
memclear_highpage_flush(*pages, base, remainder);
|
||||
pages++;
|
||||
remainder -= pglen;
|
||||
pglen = PAGE_CACHE_SIZE;
|
||||
base = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -476,6 +483,8 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
|
|||
unsigned int base = data->args.pgbase;
|
||||
struct page **pages;
|
||||
|
||||
if (data->res.eof)
|
||||
count = data->args.count;
|
||||
if (unlikely(count == 0))
|
||||
return;
|
||||
pages = &data->args.pages[base >> PAGE_CACHE_SHIFT];
|
||||
|
|
@ -483,11 +492,7 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data)
|
|||
count += base;
|
||||
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
|
||||
SetPageUptodate(*pages);
|
||||
/*
|
||||
* Was this an eof or a short read? If the latter, don't mark the page
|
||||
* as uptodate yet.
|
||||
*/
|
||||
if (count > 0 && (data->res.eof || data->args.count == data->res.count))
|
||||
if (count != 0)
|
||||
SetPageUptodate(*pages);
|
||||
}
|
||||
|
||||
|
|
@ -502,6 +507,8 @@ static void nfs_readpage_set_pages_error(struct nfs_read_data *data)
|
|||
count += base;
|
||||
for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++)
|
||||
SetPageError(*pages);
|
||||
if (count != 0)
|
||||
SetPageError(*pages);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
|
|||
return p;
|
||||
}
|
||||
|
||||
void nfs_writedata_free(struct nfs_write_data *p)
|
||||
static void nfs_writedata_free(struct nfs_write_data *p)
|
||||
{
|
||||
if (p && (p->pagevec != &p->page_array[0]))
|
||||
kfree(p->pagevec);
|
||||
|
|
@ -578,7 +578,7 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void nfs_cancel_requests(struct list_head *head)
|
||||
static void nfs_cancel_dirty_list(struct list_head *head)
|
||||
{
|
||||
struct nfs_page *req;
|
||||
while(!list_empty(head)) {
|
||||
|
|
@ -589,6 +589,19 @@ static void nfs_cancel_requests(struct list_head *head)
|
|||
}
|
||||
}
|
||||
|
||||
static void nfs_cancel_commit_list(struct list_head *head)
|
||||
{
|
||||
struct nfs_page *req;
|
||||
|
||||
while(!list_empty(head)) {
|
||||
req = nfs_list_entry(head->next);
|
||||
nfs_list_remove_request(req);
|
||||
nfs_inode_remove_request(req);
|
||||
nfs_clear_page_writeback(req);
|
||||
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs_scan_dirty - Scan an inode for dirty requests
|
||||
* @inode: NFS inode to scan
|
||||
|
|
@ -1381,6 +1394,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
|
|||
nfs_list_remove_request(req);
|
||||
nfs_mark_request_commit(req);
|
||||
nfs_clear_page_writeback(req);
|
||||
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
@ -1499,7 +1513,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
|
|||
if (pages != 0) {
|
||||
spin_unlock(&nfsi->req_lock);
|
||||
if (how & FLUSH_INVALIDATE)
|
||||
nfs_cancel_requests(&head);
|
||||
nfs_cancel_dirty_list(&head);
|
||||
else
|
||||
ret = nfs_flush_list(inode, &head, pages, how);
|
||||
spin_lock(&nfsi->req_lock);
|
||||
|
|
@ -1512,7 +1526,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
|
|||
break;
|
||||
if (how & FLUSH_INVALIDATE) {
|
||||
spin_unlock(&nfsi->req_lock);
|
||||
nfs_cancel_requests(&head);
|
||||
nfs_cancel_commit_list(&head);
|
||||
spin_lock(&nfsi->req_lock);
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -721,6 +721,12 @@ nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
|
|||
return nfs_ok;
|
||||
}
|
||||
|
||||
static inline void nfsd4_increment_op_stats(u32 opnum)
|
||||
{
|
||||
if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
|
||||
nfsdstats.nfs4_opcount[opnum]++;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* COMPOUND call.
|
||||
|
|
@ -930,6 +936,8 @@ encode_op:
|
|||
/* XXX Ugh, we need to get rid of this kind of special case: */
|
||||
if (op->opnum == OP_READ && op->u.read.rd_filp)
|
||||
fput(op->u.read.rd_filp);
|
||||
|
||||
nfsd4_increment_op_stats(op->opnum);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -187,6 +187,11 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Set user creds for this exportpoint */
|
||||
error = nfserrno(nfsd_setuser(rqstp, exp));
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Look up the dentry using the NFS file handle.
|
||||
*/
|
||||
|
|
@ -241,16 +246,17 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
|
|||
dprintk("nfsd: fh_verify - just checking\n");
|
||||
dentry = fhp->fh_dentry;
|
||||
exp = fhp->fh_export;
|
||||
/* Set user creds for this exportpoint; necessary even
|
||||
* in the "just checking" case because this may be a
|
||||
* filehandle that was created by fh_compose, and that
|
||||
* is about to be used in another nfsv4 compound
|
||||
* operation */
|
||||
error = nfserrno(nfsd_setuser(rqstp, exp));
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
cache_get(&exp->h);
|
||||
|
||||
/* Set user creds for this exportpoint; necessary even in the "just
|
||||
* checking" case because this may be a filehandle that was created by
|
||||
* fh_compose, and that is about to be used in another nfsv4 compound
|
||||
* operation */
|
||||
error = nfserrno(nfsd_setuser(rqstp, exp));
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type);
|
||||
if (error)
|
||||
|
|
|
|||
|
|
@ -72,6 +72,16 @@ static int nfsd_proc_show(struct seq_file *seq, void *v)
|
|||
/* show my rpc info */
|
||||
svc_seq_show(seq, &nfsd_svcstats);
|
||||
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
/* Show count for individual nfsv4 operations */
|
||||
/* Writing operation numbers 0 1 2 also for maintaining uniformity */
|
||||
seq_printf(seq,"proc4ops %u", LAST_NFS4_OP + 1);
|
||||
for (i = 0; i <= LAST_NFS4_OP; i++)
|
||||
seq_printf(seq, " %u", nfsdstats.nfs4_opcount[i]);
|
||||
|
||||
seq_putc(seq, '\n');
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2375,7 +2375,6 @@ leave:
|
|||
mlog(0, "returning %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dlm_migrate_lockres);
|
||||
|
||||
int dlm_lock_basts_flushed(struct dlm_ctxt *dlm, struct dlm_lock *lock)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm,
|
|||
else
|
||||
status = dlm_get_unlock_actions(dlm, res, lock, lksb, &actions);
|
||||
|
||||
if (status != DLM_NORMAL)
|
||||
if (status != DLM_NORMAL && (status != DLM_CANCELGRANT || !master_node))
|
||||
goto leave;
|
||||
|
||||
/* By now this has been masked out of cancel requests. */
|
||||
|
|
@ -183,8 +183,7 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm,
|
|||
spin_lock(&lock->spinlock);
|
||||
/* if the master told us the lock was already granted,
|
||||
* let the ast handle all of these actions */
|
||||
if (status == DLM_NORMAL &&
|
||||
lksb->status == DLM_CANCELGRANT) {
|
||||
if (status == DLM_CANCELGRANT) {
|
||||
actions &= ~(DLM_UNLOCK_REMOVE_LOCK|
|
||||
DLM_UNLOCK_REGRANT_LOCK|
|
||||
DLM_UNLOCK_CLEAR_CONVERT_TYPE);
|
||||
|
|
@ -349,14 +348,9 @@ static enum dlm_status dlm_send_remote_unlock_request(struct dlm_ctxt *dlm,
|
|||
vec, veclen, owner, &status);
|
||||
if (tmpret >= 0) {
|
||||
// successfully sent and received
|
||||
if (status == DLM_CANCELGRANT)
|
||||
ret = DLM_NORMAL;
|
||||
else if (status == DLM_FORWARD) {
|
||||
if (status == DLM_FORWARD)
|
||||
mlog(0, "master was in-progress. retry\n");
|
||||
ret = DLM_FORWARD;
|
||||
} else
|
||||
ret = status;
|
||||
lksb->status = status;
|
||||
ret = status;
|
||||
} else {
|
||||
mlog_errno(tmpret);
|
||||
if (dlm_is_host_down(tmpret)) {
|
||||
|
|
@ -372,7 +366,6 @@ static enum dlm_status dlm_send_remote_unlock_request(struct dlm_ctxt *dlm,
|
|||
/* something bad. this will BUG in ocfs2 */
|
||||
ret = dlm_err_to_dlm_status(tmpret);
|
||||
}
|
||||
lksb->status = ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -483,6 +476,10 @@ int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data)
|
|||
|
||||
/* lock was found on queue */
|
||||
lksb = lock->lksb;
|
||||
if (flags & (LKM_VALBLK|LKM_PUT_LVB) &&
|
||||
lock->ml.type != LKM_EXMODE)
|
||||
flags &= ~(LKM_VALBLK|LKM_PUT_LVB);
|
||||
|
||||
/* unlockast only called on originating node */
|
||||
if (flags & LKM_PUT_LVB) {
|
||||
lksb->flags |= DLM_LKSB_PUT_LVB;
|
||||
|
|
@ -507,11 +504,8 @@ not_found:
|
|||
"cookie=%u:%llu\n",
|
||||
dlm_get_lock_cookie_node(unlock->cookie),
|
||||
dlm_get_lock_cookie_seq(unlock->cookie));
|
||||
else {
|
||||
/* send the lksb->status back to the other node */
|
||||
status = lksb->status;
|
||||
else
|
||||
dlm_lock_put(lock);
|
||||
}
|
||||
|
||||
leave:
|
||||
if (res)
|
||||
|
|
@ -533,26 +527,22 @@ static enum dlm_status dlm_get_cancel_actions(struct dlm_ctxt *dlm,
|
|||
|
||||
if (dlm_lock_on_list(&res->blocked, lock)) {
|
||||
/* cancel this outright */
|
||||
lksb->status = DLM_NORMAL;
|
||||
status = DLM_NORMAL;
|
||||
*actions = (DLM_UNLOCK_CALL_AST |
|
||||
DLM_UNLOCK_REMOVE_LOCK);
|
||||
} else if (dlm_lock_on_list(&res->converting, lock)) {
|
||||
/* cancel the request, put back on granted */
|
||||
lksb->status = DLM_NORMAL;
|
||||
status = DLM_NORMAL;
|
||||
*actions = (DLM_UNLOCK_CALL_AST |
|
||||
DLM_UNLOCK_REMOVE_LOCK |
|
||||
DLM_UNLOCK_REGRANT_LOCK |
|
||||
DLM_UNLOCK_CLEAR_CONVERT_TYPE);
|
||||
} else if (dlm_lock_on_list(&res->granted, lock)) {
|
||||
/* too late, already granted. DLM_CANCELGRANT */
|
||||
lksb->status = DLM_CANCELGRANT;
|
||||
status = DLM_NORMAL;
|
||||
/* too late, already granted. */
|
||||
status = DLM_CANCELGRANT;
|
||||
*actions = DLM_UNLOCK_CALL_AST;
|
||||
} else {
|
||||
mlog(ML_ERROR, "lock to cancel is not on any list!\n");
|
||||
lksb->status = DLM_IVLOCKID;
|
||||
status = DLM_IVLOCKID;
|
||||
*actions = 0;
|
||||
}
|
||||
|
|
@ -569,13 +559,11 @@ static enum dlm_status dlm_get_unlock_actions(struct dlm_ctxt *dlm,
|
|||
|
||||
/* unlock request */
|
||||
if (!dlm_lock_on_list(&res->granted, lock)) {
|
||||
lksb->status = DLM_DENIED;
|
||||
status = DLM_DENIED;
|
||||
dlm_error(status);
|
||||
*actions = 0;
|
||||
} else {
|
||||
/* unlock granted lock */
|
||||
lksb->status = DLM_NORMAL;
|
||||
status = DLM_NORMAL;
|
||||
*actions = (DLM_UNLOCK_FREE_LOCK |
|
||||
DLM_UNLOCK_CALL_AST |
|
||||
|
|
@ -632,6 +620,8 @@ retry:
|
|||
|
||||
spin_lock(&res->spinlock);
|
||||
is_master = (res->owner == dlm->node_num);
|
||||
if (flags & LKM_VALBLK && lock->ml.type != LKM_EXMODE)
|
||||
flags &= ~LKM_VALBLK;
|
||||
spin_unlock(&res->spinlock);
|
||||
|
||||
if (is_master) {
|
||||
|
|
@ -665,7 +655,7 @@ retry:
|
|||
}
|
||||
|
||||
if (call_ast) {
|
||||
mlog(0, "calling unlockast(%p, %d)\n", data, lksb->status);
|
||||
mlog(0, "calling unlockast(%p, %d)\n", data, status);
|
||||
if (is_master) {
|
||||
/* it is possible that there is one last bast
|
||||
* pending. make sure it is flushed, then
|
||||
|
|
@ -677,9 +667,12 @@ retry:
|
|||
wait_event(dlm->ast_wq,
|
||||
dlm_lock_basts_flushed(dlm, lock));
|
||||
}
|
||||
(*unlockast)(data, lksb->status);
|
||||
(*unlockast)(data, status);
|
||||
}
|
||||
|
||||
if (status == DLM_CANCELGRANT)
|
||||
status = DLM_NORMAL;
|
||||
|
||||
if (status == DLM_NORMAL) {
|
||||
mlog(0, "kicking the thread\n");
|
||||
dlm_kick_thread(dlm, res);
|
||||
|
|
|
|||
|
|
@ -840,6 +840,12 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
|
|||
|
||||
mlog(0, "Allocating %u clusters for a new window.\n",
|
||||
ocfs2_local_alloc_window_bits(osb));
|
||||
|
||||
/* Instruct the allocation code to try the most recently used
|
||||
* cluster group. We'll re-record the group used this pass
|
||||
* below. */
|
||||
ac->ac_last_group = osb->la_last_gd;
|
||||
|
||||
/* we used the generic suballoc reserve function, but we set
|
||||
* everything up nicely, so there's no reason why we can't use
|
||||
* the more specific cluster api to claim bits. */
|
||||
|
|
@ -852,6 +858,8 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
|
|||
goto bail;
|
||||
}
|
||||
|
||||
osb->la_last_gd = ac->ac_last_group;
|
||||
|
||||
la->la_bm_off = cpu_to_le32(cluster_off);
|
||||
alloc->id1.bitmap1.i_total = cpu_to_le32(cluster_count);
|
||||
/* just in case... In the future when we find space ourselves,
|
||||
|
|
|
|||
|
|
@ -197,7 +197,6 @@ struct ocfs2_super
|
|||
struct ocfs2_node_map recovery_map;
|
||||
struct ocfs2_node_map umount_map;
|
||||
|
||||
u32 num_clusters;
|
||||
u64 root_blkno;
|
||||
u64 system_dir_blkno;
|
||||
u64 bitmap_blkno;
|
||||
|
|
@ -237,6 +236,7 @@ struct ocfs2_super
|
|||
|
||||
enum ocfs2_local_alloc_state local_alloc_state;
|
||||
struct buffer_head *local_alloc_bh;
|
||||
u64 la_last_gd;
|
||||
|
||||
/* Next two fields are for local node slot recovery during
|
||||
* mount. */
|
||||
|
|
|
|||
|
|
@ -70,12 +70,6 @@ static int ocfs2_block_group_search(struct inode *inode,
|
|||
struct buffer_head *group_bh,
|
||||
u32 bits_wanted, u32 min_bits,
|
||||
u16 *bit_off, u16 *bits_found);
|
||||
static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
||||
u32 bits_wanted,
|
||||
u32 min_bits,
|
||||
u16 *bit_off,
|
||||
unsigned int *num_bits,
|
||||
u64 *bg_blkno);
|
||||
static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
|
||||
struct ocfs2_alloc_context *ac,
|
||||
u32 bits_wanted,
|
||||
|
|
@ -85,11 +79,6 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
|
|||
u64 *bg_blkno);
|
||||
static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh,
|
||||
int nr);
|
||||
static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb,
|
||||
struct buffer_head *bg_bh,
|
||||
unsigned int bits_wanted,
|
||||
u16 *bit_off,
|
||||
u16 *bits_found);
|
||||
static inline int ocfs2_block_group_set_bits(struct ocfs2_journal_handle *handle,
|
||||
struct inode *alloc_inode,
|
||||
struct ocfs2_group_desc *bg,
|
||||
|
|
@ -143,6 +132,64 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl)
|
|||
return (u32)le16_to_cpu(cl->cl_cpg) * (u32)le16_to_cpu(cl->cl_bpc);
|
||||
}
|
||||
|
||||
/* somewhat more expensive than our other checks, so use sparingly. */
|
||||
static int ocfs2_check_group_descriptor(struct super_block *sb,
|
||||
struct ocfs2_dinode *di,
|
||||
struct ocfs2_group_desc *gd)
|
||||
{
|
||||
unsigned int max_bits;
|
||||
|
||||
if (!OCFS2_IS_VALID_GROUP_DESC(gd)) {
|
||||
OCFS2_RO_ON_INVALID_GROUP_DESC(sb, gd);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (di->i_blkno != gd->bg_parent_dinode) {
|
||||
ocfs2_error(sb, "Group descriptor # %llu has bad parent "
|
||||
"pointer (%llu, expected %llu)",
|
||||
(unsigned long long)le64_to_cpu(gd->bg_blkno),
|
||||
(unsigned long long)le64_to_cpu(gd->bg_parent_dinode),
|
||||
(unsigned long long)le64_to_cpu(di->i_blkno));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) * le16_to_cpu(di->id2.i_chain.cl_bpc);
|
||||
if (le16_to_cpu(gd->bg_bits) > max_bits) {
|
||||
ocfs2_error(sb, "Group descriptor # %llu has bit count of %u",
|
||||
(unsigned long long)le64_to_cpu(gd->bg_blkno),
|
||||
le16_to_cpu(gd->bg_bits));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(gd->bg_chain) >=
|
||||
le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) {
|
||||
ocfs2_error(sb, "Group descriptor # %llu has bad chain %u",
|
||||
(unsigned long long)le64_to_cpu(gd->bg_blkno),
|
||||
le16_to_cpu(gd->bg_chain));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits)) {
|
||||
ocfs2_error(sb, "Group descriptor # %llu has bit count %u but "
|
||||
"claims that %u are free",
|
||||
(unsigned long long)le64_to_cpu(gd->bg_blkno),
|
||||
le16_to_cpu(gd->bg_bits),
|
||||
le16_to_cpu(gd->bg_free_bits_count));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size))) {
|
||||
ocfs2_error(sb, "Group descriptor # %llu has bit count %u but "
|
||||
"max bitmap bits of %u",
|
||||
(unsigned long long)le64_to_cpu(gd->bg_blkno),
|
||||
le16_to_cpu(gd->bg_bits),
|
||||
8 * le16_to_cpu(gd->bg_size));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ocfs2_block_group_fill(struct ocfs2_journal_handle *handle,
|
||||
struct inode *alloc_inode,
|
||||
struct buffer_head *bg_bh,
|
||||
|
|
@ -663,6 +710,7 @@ static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh,
|
|||
static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb,
|
||||
struct buffer_head *bg_bh,
|
||||
unsigned int bits_wanted,
|
||||
unsigned int total_bits,
|
||||
u16 *bit_off,
|
||||
u16 *bits_found)
|
||||
{
|
||||
|
|
@ -679,10 +727,8 @@ static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb,
|
|||
found = start = best_offset = best_size = 0;
|
||||
bitmap = bg->bg_bitmap;
|
||||
|
||||
while((offset = ocfs2_find_next_zero_bit(bitmap,
|
||||
le16_to_cpu(bg->bg_bits),
|
||||
start)) != -1) {
|
||||
if (offset == le16_to_cpu(bg->bg_bits))
|
||||
while((offset = ocfs2_find_next_zero_bit(bitmap, total_bits, start)) != -1) {
|
||||
if (offset == total_bits)
|
||||
break;
|
||||
|
||||
if (!ocfs2_test_bg_bit_allocatable(bg_bh, offset)) {
|
||||
|
|
@ -911,14 +957,35 @@ static int ocfs2_cluster_group_search(struct inode *inode,
|
|||
{
|
||||
int search = -ENOSPC;
|
||||
int ret;
|
||||
struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) group_bh->b_data;
|
||||
struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data;
|
||||
u16 tmp_off, tmp_found;
|
||||
unsigned int max_bits, gd_cluster_off;
|
||||
|
||||
BUG_ON(!ocfs2_is_cluster_bitmap(inode));
|
||||
|
||||
if (bg->bg_free_bits_count) {
|
||||
if (gd->bg_free_bits_count) {
|
||||
max_bits = le16_to_cpu(gd->bg_bits);
|
||||
|
||||
/* Tail groups in cluster bitmaps which aren't cpg
|
||||
* aligned are prone to partial extention by a failed
|
||||
* fs resize. If the file system resize never got to
|
||||
* update the dinode cluster count, then we don't want
|
||||
* to trust any clusters past it, regardless of what
|
||||
* the group descriptor says. */
|
||||
gd_cluster_off = ocfs2_blocks_to_clusters(inode->i_sb,
|
||||
le64_to_cpu(gd->bg_blkno));
|
||||
if ((gd_cluster_off + max_bits) >
|
||||
OCFS2_I(inode)->ip_clusters) {
|
||||
max_bits = OCFS2_I(inode)->ip_clusters - gd_cluster_off;
|
||||
mlog(0, "Desc %llu, bg_bits %u, clusters %u, use %u\n",
|
||||
(unsigned long long)le64_to_cpu(gd->bg_blkno),
|
||||
le16_to_cpu(gd->bg_bits),
|
||||
OCFS2_I(inode)->ip_clusters, max_bits);
|
||||
}
|
||||
|
||||
ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb),
|
||||
group_bh, bits_wanted,
|
||||
max_bits,
|
||||
&tmp_off, &tmp_found);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -951,17 +1018,109 @@ static int ocfs2_block_group_search(struct inode *inode,
|
|||
if (bg->bg_free_bits_count)
|
||||
ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb),
|
||||
group_bh, bits_wanted,
|
||||
le16_to_cpu(bg->bg_bits),
|
||||
bit_off, bits_found);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_alloc_dinode_update_counts(struct inode *inode,
|
||||
struct ocfs2_journal_handle *handle,
|
||||
struct buffer_head *di_bh,
|
||||
u32 num_bits,
|
||||
u16 chain)
|
||||
{
|
||||
int ret;
|
||||
u32 tmp_used;
|
||||
struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data;
|
||||
struct ocfs2_chain_list *cl = (struct ocfs2_chain_list *) &di->id2.i_chain;
|
||||
|
||||
ret = ocfs2_journal_access(handle, inode, di_bh,
|
||||
OCFS2_JOURNAL_ACCESS_WRITE);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp_used = le32_to_cpu(di->id1.bitmap1.i_used);
|
||||
di->id1.bitmap1.i_used = cpu_to_le32(num_bits + tmp_used);
|
||||
le32_add_cpu(&cl->cl_recs[chain].c_free, -num_bits);
|
||||
|
||||
ret = ocfs2_journal_dirty(handle, di_bh);
|
||||
if (ret < 0)
|
||||
mlog_errno(ret);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
|
||||
u32 bits_wanted,
|
||||
u32 min_bits,
|
||||
u16 *bit_off,
|
||||
unsigned int *num_bits,
|
||||
u64 gd_blkno,
|
||||
u16 *bits_left)
|
||||
{
|
||||
int ret;
|
||||
u16 found;
|
||||
struct buffer_head *group_bh = NULL;
|
||||
struct ocfs2_group_desc *gd;
|
||||
struct inode *alloc_inode = ac->ac_inode;
|
||||
struct ocfs2_journal_handle *handle = ac->ac_handle;
|
||||
|
||||
ret = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), gd_blkno,
|
||||
&group_bh, OCFS2_BH_CACHED, alloc_inode);
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gd = (struct ocfs2_group_desc *) group_bh->b_data;
|
||||
if (!OCFS2_IS_VALID_GROUP_DESC(gd)) {
|
||||
OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, gd);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, min_bits,
|
||||
bit_off, &found);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENOSPC)
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*num_bits = found;
|
||||
|
||||
ret = ocfs2_alloc_dinode_update_counts(alloc_inode, handle, ac->ac_bh,
|
||||
*num_bits,
|
||||
le16_to_cpu(gd->bg_chain));
|
||||
if (ret < 0) {
|
||||
mlog_errno(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ocfs2_block_group_set_bits(handle, alloc_inode, gd, group_bh,
|
||||
*bit_off, *num_bits);
|
||||
if (ret < 0)
|
||||
mlog_errno(ret);
|
||||
|
||||
*bits_left = le16_to_cpu(gd->bg_free_bits_count);
|
||||
|
||||
out:
|
||||
brelse(group_bh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
||||
u32 bits_wanted,
|
||||
u32 min_bits,
|
||||
u16 *bit_off,
|
||||
unsigned int *num_bits,
|
||||
u64 *bg_blkno)
|
||||
u64 *bg_blkno,
|
||||
u16 *bits_left)
|
||||
{
|
||||
int status;
|
||||
u16 chain, tmp_bits;
|
||||
|
|
@ -988,9 +1147,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
|||
goto bail;
|
||||
}
|
||||
bg = (struct ocfs2_group_desc *) group_bh->b_data;
|
||||
if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
|
||||
OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
|
||||
status = -EIO;
|
||||
status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, bg);
|
||||
if (status) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
|
|
@ -1018,9 +1177,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
|||
goto bail;
|
||||
}
|
||||
bg = (struct ocfs2_group_desc *) group_bh->b_data;
|
||||
if (!OCFS2_IS_VALID_GROUP_DESC(bg)) {
|
||||
OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, bg);
|
||||
status = -EIO;
|
||||
status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, bg);
|
||||
if (status) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
|
@ -1099,6 +1258,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
|
|||
(unsigned long long)fe->i_blkno);
|
||||
|
||||
*bg_blkno = le64_to_cpu(bg->bg_blkno);
|
||||
*bits_left = le16_to_cpu(bg->bg_free_bits_count);
|
||||
bail:
|
||||
if (group_bh)
|
||||
brelse(group_bh);
|
||||
|
|
@ -1120,6 +1280,8 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
|
|||
{
|
||||
int status;
|
||||
u16 victim, i;
|
||||
u16 bits_left = 0;
|
||||
u64 hint_blkno = ac->ac_last_group;
|
||||
struct ocfs2_chain_list *cl;
|
||||
struct ocfs2_dinode *fe;
|
||||
|
||||
|
|
@ -1146,6 +1308,28 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
|
|||
goto bail;
|
||||
}
|
||||
|
||||
if (hint_blkno) {
|
||||
/* Attempt to short-circuit the usual search mechanism
|
||||
* by jumping straight to the most recently used
|
||||
* allocation group. This helps us mantain some
|
||||
* contiguousness across allocations. */
|
||||
status = ocfs2_search_one_group(ac, bits_wanted, min_bits,
|
||||
bit_off, num_bits,
|
||||
hint_blkno, &bits_left);
|
||||
if (!status) {
|
||||
/* Be careful to update *bg_blkno here as the
|
||||
* caller is expecting it to be filled in, and
|
||||
* ocfs2_search_one_group() won't do that for
|
||||
* us. */
|
||||
*bg_blkno = hint_blkno;
|
||||
goto set_hint;
|
||||
}
|
||||
if (status < 0 && status != -ENOSPC) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
cl = (struct ocfs2_chain_list *) &fe->id2.i_chain;
|
||||
|
||||
victim = ocfs2_find_victim_chain(cl);
|
||||
|
|
@ -1153,9 +1337,9 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
|
|||
ac->ac_allow_chain_relink = 1;
|
||||
|
||||
status = ocfs2_search_chain(ac, bits_wanted, min_bits, bit_off,
|
||||
num_bits, bg_blkno);
|
||||
num_bits, bg_blkno, &bits_left);
|
||||
if (!status)
|
||||
goto bail;
|
||||
goto set_hint;
|
||||
if (status < 0 && status != -ENOSPC) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
|
|
@ -1177,8 +1361,8 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
|
|||
|
||||
ac->ac_chain = i;
|
||||
status = ocfs2_search_chain(ac, bits_wanted, min_bits,
|
||||
bit_off, num_bits,
|
||||
bg_blkno);
|
||||
bit_off, num_bits, bg_blkno,
|
||||
&bits_left);
|
||||
if (!status)
|
||||
break;
|
||||
if (status < 0 && status != -ENOSPC) {
|
||||
|
|
@ -1186,8 +1370,19 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
|
|||
goto bail;
|
||||
}
|
||||
}
|
||||
bail:
|
||||
|
||||
set_hint:
|
||||
if (status != -ENOSPC) {
|
||||
/* If the next search of this group is not likely to
|
||||
* yield a suitable extent, then we reset the last
|
||||
* group hint so as to not waste a disk read */
|
||||
if (bits_left < min_bits)
|
||||
ac->ac_last_group = 0;
|
||||
else
|
||||
ac->ac_last_group = *bg_blkno;
|
||||
}
|
||||
|
||||
bail:
|
||||
mlog_exit(status);
|
||||
return status;
|
||||
}
|
||||
|
|
@ -1341,7 +1536,7 @@ int ocfs2_claim_clusters(struct ocfs2_super *osb,
|
|||
{
|
||||
int status;
|
||||
unsigned int bits_wanted = ac->ac_bits_wanted - ac->ac_bits_given;
|
||||
u64 bg_blkno;
|
||||
u64 bg_blkno = 0;
|
||||
u16 bg_bit_off;
|
||||
|
||||
mlog_entry_void();
|
||||
|
|
@ -1494,9 +1689,9 @@ static int ocfs2_free_suballoc_bits(struct ocfs2_journal_handle *handle,
|
|||
}
|
||||
|
||||
group = (struct ocfs2_group_desc *) group_bh->b_data;
|
||||
if (!OCFS2_IS_VALID_GROUP_DESC(group)) {
|
||||
OCFS2_RO_ON_INVALID_GROUP_DESC(alloc_inode->i_sb, group);
|
||||
status = -EIO;
|
||||
status = ocfs2_check_group_descriptor(alloc_inode->i_sb, fe, group);
|
||||
if (status) {
|
||||
mlog_errno(status);
|
||||
goto bail;
|
||||
}
|
||||
BUG_ON((count + start_bit) > le16_to_cpu(group->bg_bits));
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ struct ocfs2_alloc_context {
|
|||
u16 ac_chain;
|
||||
int ac_allow_chain_relink;
|
||||
group_search_t *ac_group_search;
|
||||
|
||||
u64 ac_last_group;
|
||||
};
|
||||
|
||||
void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac);
|
||||
|
|
|
|||
|
|
@ -1442,8 +1442,13 @@ static int ocfs2_initialize_super(struct super_block *sb,
|
|||
|
||||
osb->bitmap_blkno = OCFS2_I(inode)->ip_blkno;
|
||||
|
||||
/* We don't have a cluster lock on the bitmap here because
|
||||
* we're only interested in static information and the extra
|
||||
* complexity at mount time isn't worht it. Don't pass the
|
||||
* inode in to the read function though as we don't want it to
|
||||
* be put in the cache. */
|
||||
status = ocfs2_read_block(osb, osb->bitmap_blkno, &bitmap_bh, 0,
|
||||
inode);
|
||||
NULL);
|
||||
iput(inode);
|
||||
if (status < 0) {
|
||||
mlog_errno(status);
|
||||
|
|
@ -1452,7 +1457,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
|
|||
|
||||
di = (struct ocfs2_dinode *) bitmap_bh->b_data;
|
||||
osb->bitmap_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg);
|
||||
osb->num_clusters = le32_to_cpu(di->id1.bitmap1.i_total);
|
||||
brelse(bitmap_bh);
|
||||
mlog(0, "cluster bitmap inode: %llu, clusters per group: %u\n",
|
||||
(unsigned long long)osb->bitmap_blkno, osb->bitmap_cpg);
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ config IBM_PARTITION
|
|||
|
||||
config MAC_PARTITION
|
||||
bool "Macintosh partition map support" if PARTITION_ADVANCED
|
||||
default y if MAC
|
||||
default y if (MAC || PPC_PMAC)
|
||||
help
|
||||
Say Y here if you would like to use hard disks under Linux which
|
||||
were partitioned on a Macintosh.
|
||||
|
|
|
|||
|
|
@ -339,6 +339,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
|
|||
p->start_sect = start;
|
||||
p->nr_sects = len;
|
||||
p->partno = part;
|
||||
p->policy = disk->policy;
|
||||
|
||||
if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1]))
|
||||
snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part);
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev)
|
|||
spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
|
||||
for (i = 0; i < 8; i++, p++) {
|
||||
unsigned long st_sector;
|
||||
int num_sectors;
|
||||
unsigned int num_sectors;
|
||||
|
||||
st_sector = be32_to_cpu(p->start_cylinder) * spc;
|
||||
num_sectors = be32_to_cpu(p->num_sectors);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
#include <linux/times.h>
|
||||
#include <linux/cpuset.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/delayacct.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
|
@ -411,7 +412,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
|
|||
|
||||
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
|
||||
%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
|
||||
%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n",
|
||||
%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
|
||||
task->pid,
|
||||
tcomm,
|
||||
state,
|
||||
|
|
@ -455,7 +456,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
|
|||
task->exit_signal,
|
||||
task_cpu(task),
|
||||
task->rt_priority,
|
||||
task->policy);
|
||||
task->policy,
|
||||
(unsigned long long)delayacct_blkio_ticks(task));
|
||||
if(mm)
|
||||
mmput(mm);
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -551,6 +551,27 @@ static int proc_fd_access_allowed(struct inode *inode)
|
|||
return allowed;
|
||||
}
|
||||
|
||||
static int proc_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
{
|
||||
int error;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
|
||||
if (attr->ia_valid & ATTR_MODE)
|
||||
return -EPERM;
|
||||
|
||||
error = inode_change_ok(inode, attr);
|
||||
if (!error) {
|
||||
error = security_inode_setattr(dentry, attr);
|
||||
if (!error)
|
||||
error = inode_setattr(inode, attr);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct inode_operations proc_def_inode_operations = {
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
extern struct seq_operations mounts_op;
|
||||
struct proc_mounts {
|
||||
struct seq_file m;
|
||||
|
|
@ -1111,7 +1132,8 @@ out:
|
|||
|
||||
static struct inode_operations proc_pid_link_inode_operations = {
|
||||
.readlink = proc_pid_readlink,
|
||||
.follow_link = proc_pid_follow_link
|
||||
.follow_link = proc_pid_follow_link,
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
|
||||
|
|
@ -1285,6 +1307,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
|
|||
ei = PROC_I(inode);
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
||||
inode->i_ino = fake_ino(task->pid, ino);
|
||||
inode->i_op = &proc_def_inode_operations;
|
||||
|
||||
/*
|
||||
* grab the reference to task.
|
||||
|
|
@ -1339,6 +1362,7 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
inode->i_uid = 0;
|
||||
inode->i_gid = 0;
|
||||
}
|
||||
inode->i_mode &= ~(S_ISUID | S_ISGID);
|
||||
security_task_to_inode(task, inode);
|
||||
put_task_struct(task);
|
||||
return 1;
|
||||
|
|
@ -1389,6 +1413,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
inode->i_uid = 0;
|
||||
inode->i_gid = 0;
|
||||
}
|
||||
inode->i_mode &= ~(S_ISUID | S_ISGID);
|
||||
security_task_to_inode(task, inode);
|
||||
put_task_struct(task);
|
||||
return 1;
|
||||
|
|
@ -1527,11 +1552,13 @@ static struct file_operations proc_task_operations = {
|
|||
*/
|
||||
static struct inode_operations proc_fd_inode_operations = {
|
||||
.lookup = proc_lookupfd,
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
static struct inode_operations proc_task_inode_operations = {
|
||||
.lookup = proc_task_lookup,
|
||||
.getattr = proc_task_getattr,
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SECURITY
|
||||
|
|
@ -1845,11 +1872,13 @@ static struct file_operations proc_tid_base_operations = {
|
|||
static struct inode_operations proc_tgid_base_inode_operations = {
|
||||
.lookup = proc_tgid_base_lookup,
|
||||
.getattr = pid_getattr,
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
static struct inode_operations proc_tid_base_inode_operations = {
|
||||
.lookup = proc_tid_base_lookup,
|
||||
.getattr = pid_getattr,
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SECURITY
|
||||
|
|
@ -1892,11 +1921,13 @@ static struct dentry *proc_tid_attr_lookup(struct inode *dir,
|
|||
static struct inode_operations proc_tgid_attr_inode_operations = {
|
||||
.lookup = proc_tgid_attr_lookup,
|
||||
.getattr = pid_getattr,
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
static struct inode_operations proc_tid_attr_inode_operations = {
|
||||
.lookup = proc_tid_attr_lookup,
|
||||
.getattr = pid_getattr,
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent)
|
|||
{
|
||||
struct inode * root_inode;
|
||||
|
||||
s->s_flags |= MS_NODIRATIME;
|
||||
s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC;
|
||||
s->s_blocksize = 1024;
|
||||
s->s_blocksize_bits = 10;
|
||||
s->s_magic = PROC_SUPER_MAGIC;
|
||||
|
|
|
|||
|
|
@ -42,8 +42,6 @@ const struct file_operations proc_kcore_operations = {
|
|||
#define kc_offset_to_vaddr(o) ((o) + PAGE_OFFSET)
|
||||
#endif
|
||||
|
||||
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
|
||||
|
||||
/* An ELF note in memory */
|
||||
struct memelfnote
|
||||
{
|
||||
|
|
@ -384,7 +382,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
|
|||
*/
|
||||
if (n) {
|
||||
if (clear_user(buffer + tsz - n,
|
||||
tsz - n))
|
||||
n))
|
||||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off,
|
|||
"Mapped: %8lu kB\n"
|
||||
"Slab: %8lu kB\n"
|
||||
"PageTables: %8lu kB\n"
|
||||
"NFS Unstable: %8lu kB\n"
|
||||
"NFS_Unstable: %8lu kB\n"
|
||||
"Bounce: %8lu kB\n"
|
||||
"CommitLimit: %8lu kB\n"
|
||||
"Committed_AS: %8lu kB\n"
|
||||
|
|
|
|||
|
|
@ -283,9 +283,9 @@ unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
|
|||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
* set up a mapping
|
||||
* set up a mapping for shared memory segments
|
||||
*/
|
||||
int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
return 0;
|
||||
return vma->vm_flags & VM_SHARED ? 0 : -ENOSYS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
|
|||
return seg;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iov_shorten);
|
||||
EXPORT_UNUSED_SYMBOL(iov_shorten); /* June 2006 */
|
||||
|
||||
/* A write operation does a read from user space and vice versa */
|
||||
#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
reiserfs_write_lock(inode->i_sb);
|
||||
mutex_lock(&inode->i_mutex);
|
||||
reiserfs_write_lock(inode->i_sb);
|
||||
/* freeing preallocation only involves relogging blocks that
|
||||
* are already in the current transaction. preallocation gets
|
||||
* freed at the end of each transaction, so it is impossible for
|
||||
|
|
@ -860,8 +860,12 @@ static int reiserfs_submit_file_region_for_write(struct reiserfs_transaction_han
|
|||
// this sets the proper flags for O_SYNC to trigger a commit
|
||||
mark_inode_dirty(inode);
|
||||
reiserfs_write_unlock(inode->i_sb);
|
||||
} else
|
||||
} else {
|
||||
reiserfs_write_lock(inode->i_sb);
|
||||
reiserfs_update_inode_transaction(inode);
|
||||
mark_inode_dirty(inode);
|
||||
reiserfs_write_unlock(inode->i_sb);
|
||||
}
|
||||
|
||||
sd_update = 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,14 +39,10 @@ void reiserfs_delete_inode(struct inode *inode)
|
|||
|
||||
/* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
|
||||
if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
|
||||
mutex_lock(&inode->i_mutex);
|
||||
|
||||
reiserfs_delete_xattrs(inode);
|
||||
|
||||
if (journal_begin(&th, inode->i_sb, jbegin_count)) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
if (journal_begin(&th, inode->i_sb, jbegin_count))
|
||||
goto out;
|
||||
}
|
||||
reiserfs_update_inode_transaction(inode);
|
||||
|
||||
err = reiserfs_delete_object(&th, inode);
|
||||
|
|
@ -57,12 +53,8 @@ void reiserfs_delete_inode(struct inode *inode)
|
|||
if (!err)
|
||||
DQUOT_FREE_INODE(inode);
|
||||
|
||||
if (journal_end(&th, inode->i_sb, jbegin_count)) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
if (journal_end(&th, inode->i_sb, jbegin_count))
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
/* check return value from reiserfs_delete_object after
|
||||
* ending the transaction
|
||||
|
|
@ -2348,6 +2340,7 @@ static int reiserfs_write_full_page(struct page *page,
|
|||
unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
|
||||
int error = 0;
|
||||
unsigned long block;
|
||||
sector_t last_block;
|
||||
struct buffer_head *head, *bh;
|
||||
int partial = 0;
|
||||
int nr = 0;
|
||||
|
|
@ -2395,10 +2388,19 @@ static int reiserfs_write_full_page(struct page *page,
|
|||
}
|
||||
bh = head;
|
||||
block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits);
|
||||
last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;
|
||||
/* first map all the buffers, logging any direct items we find */
|
||||
do {
|
||||
if ((checked || buffer_dirty(bh)) && (!buffer_mapped(bh) ||
|
||||
(buffer_mapped(bh)
|
||||
if (block > last_block) {
|
||||
/*
|
||||
* This can happen when the block size is less than
|
||||
* the page size. The corresponding bytes in the page
|
||||
* were zero filled above
|
||||
*/
|
||||
clear_buffer_dirty(bh);
|
||||
set_buffer_uptodate(bh);
|
||||
} else if ((checked || buffer_dirty(bh)) &&
|
||||
(!buffer_mapped(bh) || (buffer_mapped(bh)
|
||||
&& bh->b_blocknr ==
|
||||
0))) {
|
||||
/* not mapped yet, or it points to a direct item, search
|
||||
|
|
|
|||
|
|
@ -116,12 +116,12 @@ static int reiserfs_unpack(struct inode *inode, struct file *filp)
|
|||
if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
|
||||
return 0;
|
||||
}
|
||||
reiserfs_write_lock(inode->i_sb);
|
||||
|
||||
/* we need to make sure nobody is changing the file size beneath
|
||||
** us
|
||||
*/
|
||||
mutex_lock(&inode->i_mutex);
|
||||
reiserfs_write_lock(inode->i_sb);
|
||||
|
||||
write_from = inode->i_size & (blocksize - 1);
|
||||
/* if we are on a block boundary, we are already unpacked. */
|
||||
|
|
|
|||
|
|
@ -492,9 +492,17 @@ static void add_file(struct super_block *sb, char *name,
|
|||
|
||||
int reiserfs_proc_info_init(struct super_block *sb)
|
||||
{
|
||||
char b[BDEVNAME_SIZE];
|
||||
char *s;
|
||||
|
||||
/* Some block devices use /'s */
|
||||
strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE);
|
||||
s = strchr(b, '/');
|
||||
if (s)
|
||||
*s = '!';
|
||||
|
||||
spin_lock_init(&__PINFO(sb).lock);
|
||||
REISERFS_SB(sb)->procdir =
|
||||
proc_mkdir(reiserfs_bdevname(sb), proc_info_root);
|
||||
REISERFS_SB(sb)->procdir = proc_mkdir(b, proc_info_root);
|
||||
if (REISERFS_SB(sb)->procdir) {
|
||||
REISERFS_SB(sb)->procdir->owner = THIS_MODULE;
|
||||
REISERFS_SB(sb)->procdir->data = sb;
|
||||
|
|
@ -508,13 +516,22 @@ int reiserfs_proc_info_init(struct super_block *sb)
|
|||
return 0;
|
||||
}
|
||||
reiserfs_warning(sb, "reiserfs: cannot create /proc/%s/%s",
|
||||
proc_info_root_name, reiserfs_bdevname(sb));
|
||||
proc_info_root_name, b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int reiserfs_proc_info_done(struct super_block *sb)
|
||||
{
|
||||
struct proc_dir_entry *de = REISERFS_SB(sb)->procdir;
|
||||
char b[BDEVNAME_SIZE];
|
||||
char *s;
|
||||
|
||||
/* Some block devices use /'s */
|
||||
strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE);
|
||||
s = strchr(b, '/');
|
||||
if (s)
|
||||
*s = '!';
|
||||
|
||||
if (de) {
|
||||
remove_proc_entry("journal", de);
|
||||
remove_proc_entry("oidmap", de);
|
||||
|
|
@ -528,7 +545,7 @@ int reiserfs_proc_info_done(struct super_block *sb)
|
|||
__PINFO(sb).exiting = 1;
|
||||
spin_unlock(&__PINFO(sb).lock);
|
||||
if (proc_info_root) {
|
||||
remove_proc_entry(reiserfs_bdevname(sb), proc_info_root);
|
||||
remove_proc_entry(b, proc_info_root);
|
||||
REISERFS_SB(sb)->procdir = NULL;
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ int xattr_readdir(struct file *file, filldir_t filler, void *buf)
|
|||
int res = -ENOTDIR;
|
||||
if (!file->f_op || !file->f_op->readdir)
|
||||
goto out;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
mutex_lock_nested(&inode->i_mutex, I_MUTEX_XATTR);
|
||||
// down(&inode->i_zombie);
|
||||
res = -ENOENT;
|
||||
if (!IS_DEADDIR(inode)) {
|
||||
|
|
|
|||
240
fs/splice.c
240
fs/splice.c
|
|
@ -1306,6 +1306,85 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure there's data to read. Wait for input if we can, otherwise
|
||||
* return an appropriate error.
|
||||
*/
|
||||
static int link_ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Check ->nrbufs without the inode lock first. This function
|
||||
* is speculative anyways, so missing one is ok.
|
||||
*/
|
||||
if (pipe->nrbufs)
|
||||
return 0;
|
||||
|
||||
ret = 0;
|
||||
mutex_lock(&pipe->inode->i_mutex);
|
||||
|
||||
while (!pipe->nrbufs) {
|
||||
if (signal_pending(current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
if (!pipe->writers)
|
||||
break;
|
||||
if (!pipe->waiting_writers) {
|
||||
if (flags & SPLICE_F_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pipe_wait(pipe);
|
||||
}
|
||||
|
||||
mutex_unlock(&pipe->inode->i_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure there's writeable room. Wait for room if we can, otherwise
|
||||
* return an appropriate error.
|
||||
*/
|
||||
static int link_opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Check ->nrbufs without the inode lock first. This function
|
||||
* is speculative anyways, so missing one is ok.
|
||||
*/
|
||||
if (pipe->nrbufs < PIPE_BUFFERS)
|
||||
return 0;
|
||||
|
||||
ret = 0;
|
||||
mutex_lock(&pipe->inode->i_mutex);
|
||||
|
||||
while (pipe->nrbufs >= PIPE_BUFFERS) {
|
||||
if (!pipe->readers) {
|
||||
send_sig(SIGPIPE, current, 0);
|
||||
ret = -EPIPE;
|
||||
break;
|
||||
}
|
||||
if (flags & SPLICE_F_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
pipe->waiting_writers++;
|
||||
pipe_wait(pipe);
|
||||
pipe->waiting_writers--;
|
||||
}
|
||||
|
||||
mutex_unlock(&pipe->inode->i_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Link contents of ipipe to opipe.
|
||||
*/
|
||||
|
|
@ -1314,9 +1393,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
|
|||
size_t len, unsigned int flags)
|
||||
{
|
||||
struct pipe_buffer *ibuf, *obuf;
|
||||
int ret, do_wakeup, i, ipipe_first;
|
||||
|
||||
ret = do_wakeup = ipipe_first = 0;
|
||||
int ret = 0, i = 0, nbuf;
|
||||
|
||||
/*
|
||||
* Potential ABBA deadlock, work around it by ordering lock
|
||||
|
|
@ -1324,126 +1401,62 @@ static int link_pipe(struct pipe_inode_info *ipipe,
|
|||
* could deadlock (one doing tee from A -> B, the other from B -> A).
|
||||
*/
|
||||
if (ipipe->inode < opipe->inode) {
|
||||
ipipe_first = 1;
|
||||
mutex_lock(&ipipe->inode->i_mutex);
|
||||
mutex_lock(&opipe->inode->i_mutex);
|
||||
mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT);
|
||||
mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD);
|
||||
} else {
|
||||
mutex_lock(&opipe->inode->i_mutex);
|
||||
mutex_lock(&ipipe->inode->i_mutex);
|
||||
mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT);
|
||||
mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD);
|
||||
}
|
||||
|
||||
for (i = 0;; i++) {
|
||||
do {
|
||||
if (!opipe->readers) {
|
||||
send_sig(SIGPIPE, current, 0);
|
||||
if (!ret)
|
||||
ret = -EPIPE;
|
||||
break;
|
||||
}
|
||||
if (ipipe->nrbufs - i) {
|
||||
ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1));
|
||||
|
||||
/*
|
||||
* If we have room, fill this buffer
|
||||
*/
|
||||
if (opipe->nrbufs < PIPE_BUFFERS) {
|
||||
int nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1);
|
||||
|
||||
/*
|
||||
* Get a reference to this pipe buffer,
|
||||
* so we can copy the contents over.
|
||||
*/
|
||||
ibuf->ops->get(ipipe, ibuf);
|
||||
|
||||
obuf = opipe->bufs + nbuf;
|
||||
*obuf = *ibuf;
|
||||
|
||||
/*
|
||||
* Don't inherit the gift flag, we need to
|
||||
* prevent multiple steals of this page.
|
||||
*/
|
||||
obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
|
||||
|
||||
if (obuf->len > len)
|
||||
obuf->len = len;
|
||||
|
||||
opipe->nrbufs++;
|
||||
do_wakeup = 1;
|
||||
ret += obuf->len;
|
||||
len -= obuf->len;
|
||||
|
||||
if (!len)
|
||||
break;
|
||||
if (opipe->nrbufs < PIPE_BUFFERS)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have input available, but no output room.
|
||||
* If we already copied data, return that. If we
|
||||
* need to drop the opipe lock, it must be ordered
|
||||
* last to avoid deadlocks.
|
||||
*/
|
||||
if ((flags & SPLICE_F_NONBLOCK) || !ipipe_first) {
|
||||
if (!ret)
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
if (!ret)
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
if (do_wakeup) {
|
||||
smp_mb();
|
||||
if (waitqueue_active(&opipe->wait))
|
||||
wake_up_interruptible(&opipe->wait);
|
||||
kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
|
||||
do_wakeup = 0;
|
||||
}
|
||||
|
||||
opipe->waiting_writers++;
|
||||
pipe_wait(opipe);
|
||||
opipe->waiting_writers--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* No input buffers, do the usual checks for available
|
||||
* writers and blocking and wait if necessary
|
||||
* If we have iterated all input buffers or ran out of
|
||||
* output room, break.
|
||||
*/
|
||||
if (!ipipe->writers)
|
||||
if (i >= ipipe->nrbufs || opipe->nrbufs >= PIPE_BUFFERS)
|
||||
break;
|
||||
if (!ipipe->waiting_writers) {
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1));
|
||||
nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1);
|
||||
|
||||
/*
|
||||
* pipe_wait() drops the ipipe mutex. To avoid deadlocks
|
||||
* with another process, we can only safely do that if
|
||||
* the ipipe lock is ordered last.
|
||||
* Get a reference to this pipe buffer,
|
||||
* so we can copy the contents over.
|
||||
*/
|
||||
if ((flags & SPLICE_F_NONBLOCK) || ipipe_first) {
|
||||
if (!ret)
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
if (!ret)
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
ibuf->ops->get(ipipe, ibuf);
|
||||
|
||||
if (waitqueue_active(&ipipe->wait))
|
||||
wake_up_interruptible_sync(&ipipe->wait);
|
||||
kill_fasync(&ipipe->fasync_writers, SIGIO, POLL_OUT);
|
||||
obuf = opipe->bufs + nbuf;
|
||||
*obuf = *ibuf;
|
||||
|
||||
pipe_wait(ipipe);
|
||||
}
|
||||
/*
|
||||
* Don't inherit the gift flag, we need to
|
||||
* prevent multiple steals of this page.
|
||||
*/
|
||||
obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
|
||||
|
||||
if (obuf->len > len)
|
||||
obuf->len = len;
|
||||
|
||||
opipe->nrbufs++;
|
||||
ret += obuf->len;
|
||||
len -= obuf->len;
|
||||
i++;
|
||||
} while (len);
|
||||
|
||||
mutex_unlock(&ipipe->inode->i_mutex);
|
||||
mutex_unlock(&opipe->inode->i_mutex);
|
||||
|
||||
if (do_wakeup) {
|
||||
/*
|
||||
* If we put data in the output pipe, wakeup any potential readers.
|
||||
*/
|
||||
if (ret > 0) {
|
||||
smp_mb();
|
||||
if (waitqueue_active(&opipe->wait))
|
||||
wake_up_interruptible(&opipe->wait);
|
||||
|
|
@ -1464,14 +1477,29 @@ static long do_tee(struct file *in, struct file *out, size_t len,
|
|||
{
|
||||
struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe;
|
||||
struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe;
|
||||
int ret = -EINVAL;
|
||||
|
||||
/*
|
||||
* Link ipipe to the two output pipes, consuming as we go along.
|
||||
* Duplicate the contents of ipipe to opipe without actually
|
||||
* copying the data.
|
||||
*/
|
||||
if (ipipe && opipe)
|
||||
return link_pipe(ipipe, opipe, len, flags);
|
||||
if (ipipe && opipe && ipipe != opipe) {
|
||||
/*
|
||||
* Keep going, unless we encounter an error. The ipipe/opipe
|
||||
* ordering doesn't really matter.
|
||||
*/
|
||||
ret = link_ipipe_prep(ipipe, flags);
|
||||
if (!ret) {
|
||||
ret = link_opipe_prep(opipe, flags);
|
||||
if (!ret) {
|
||||
ret = link_pipe(ipipe, opipe, len, flags);
|
||||
if (!ret && (flags & SPLICE_F_NONBLOCK))
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags)
|
||||
|
|
|
|||
|
|
@ -109,6 +109,17 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
|
|||
inode->i_ctime = iattr->ia_ctime;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* sysfs has a different i_mutex lock order behavior for i_mutex than other
|
||||
* filesystems; sysfs i_mutex is called in many places with subsystem locks
|
||||
* held. At the same time, many of the VFS locking rules do not apply to
|
||||
* sysfs at all (cross directory rename for example). To untangle this mess
|
||||
* (which gives false positives in lockdep), we're giving sysfs inodes their
|
||||
* own class for i_mutex.
|
||||
*/
|
||||
static struct lock_class_key sysfs_inode_imutex_key;
|
||||
|
||||
struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd)
|
||||
{
|
||||
struct inode * inode = new_inode(sysfs_sb);
|
||||
|
|
@ -118,6 +129,7 @@ struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd)
|
|||
inode->i_mapping->a_ops = &sysfs_aops;
|
||||
inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
|
||||
inode->i_op = &sysfs_inode_operations;
|
||||
lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
|
||||
|
||||
if (sd->s_iattr) {
|
||||
/* sysfs_dirent has non-default attributes
|
||||
|
|
|
|||
|
|
@ -75,6 +75,12 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
|
|||
}
|
||||
*err = -ENOSPC;
|
||||
|
||||
UDF_I_UNIQUE(inode) = 0;
|
||||
UDF_I_LENEXTENTS(inode) = 0;
|
||||
UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
|
||||
UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
|
||||
UDF_I_STRAT4096(inode) = 0;
|
||||
|
||||
block = udf_new_block(dir->i_sb, NULL, UDF_I_LOCATION(dir).partitionReferenceNum,
|
||||
start, err);
|
||||
if (*err)
|
||||
|
|
@ -84,11 +90,6 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
|
|||
}
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
UDF_I_UNIQUE(inode) = 0;
|
||||
UDF_I_LENEXTENTS(inode) = 0;
|
||||
UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
|
||||
UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
|
||||
UDF_I_STRAT4096(inode) = 0;
|
||||
if (UDF_SB_LVIDBH(sb))
|
||||
{
|
||||
struct logicalVolHeaderDesc *lvhd;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,13 @@ static struct inode *udf_alloc_inode(struct super_block *sb)
|
|||
ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, SLAB_KERNEL);
|
||||
if (!ei)
|
||||
return NULL;
|
||||
|
||||
ei->i_unique = 0;
|
||||
ei->i_lenExtents = 0;
|
||||
ei->i_next_alloc_block = 0;
|
||||
ei->i_next_alloc_goal = 0;
|
||||
ei->i_strat4096 = 0;
|
||||
|
||||
return &ei->vfs_inode;
|
||||
}
|
||||
|
||||
|
|
@ -1652,7 +1659,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
|
|||
iput(inode);
|
||||
goto error_out;
|
||||
}
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
sb->s_maxbytes = 1<<30;
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
|
|
|
|||
|
|
@ -239,38 +239,52 @@ void udf_truncate_extents(struct inode * inode)
|
|||
{
|
||||
if (offset)
|
||||
{
|
||||
extoffset -= adsize;
|
||||
etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
|
||||
if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
|
||||
{
|
||||
extoffset -= adsize;
|
||||
elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
|
||||
udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
|
||||
}
|
||||
else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
|
||||
{
|
||||
kernel_lb_addr neloc = { 0, 0 };
|
||||
extoffset -= adsize;
|
||||
nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
|
||||
((elen + offset + inode->i_sb->s_blocksize - 1) &
|
||||
~(inode->i_sb->s_blocksize - 1));
|
||||
udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
|
||||
udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (elen & (inode->i_sb->s_blocksize - 1))
|
||||
{
|
||||
extoffset -= adsize;
|
||||
elen = EXT_RECORDED_ALLOCATED |
|
||||
((elen + inode->i_sb->s_blocksize - 1) &
|
||||
~(inode->i_sb->s_blocksize - 1));
|
||||
udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
|
||||
}
|
||||
/*
|
||||
* OK, there is not extent covering inode->i_size and
|
||||
* no extent above inode->i_size => truncate is
|
||||
* extending the file by 'offset'.
|
||||
*/
|
||||
if ((!bh && extoffset == udf_file_entry_alloc_offset(inode)) ||
|
||||
(bh && extoffset == sizeof(struct allocExtDesc))) {
|
||||
/* File has no extents at all! */
|
||||
memset(&eloc, 0x00, sizeof(kernel_lb_addr));
|
||||
elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
|
||||
udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
|
||||
}
|
||||
else {
|
||||
extoffset -= adsize;
|
||||
etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
|
||||
if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
|
||||
{
|
||||
extoffset -= adsize;
|
||||
elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
|
||||
udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
|
||||
}
|
||||
else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
|
||||
{
|
||||
kernel_lb_addr neloc = { 0, 0 };
|
||||
extoffset -= adsize;
|
||||
nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
|
||||
((elen + offset + inode->i_sb->s_blocksize - 1) &
|
||||
~(inode->i_sb->s_blocksize - 1));
|
||||
udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
|
||||
udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (elen & (inode->i_sb->s_blocksize - 1))
|
||||
{
|
||||
extoffset -= adsize;
|
||||
elen = EXT_RECORDED_ALLOCATED |
|
||||
((elen + inode->i_sb->s_blocksize - 1) &
|
||||
~(inode->i_sb->s_blocksize - 1));
|
||||
udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
|
||||
}
|
||||
memset(&eloc, 0x00, sizeof(kernel_lb_addr));
|
||||
elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
|
||||
udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UDF_I_LENEXTENTS(inode) = inode->i_size;
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ static void ufs_change_blocknr(struct inode *inode, unsigned int baseblk,
|
|||
|
||||
if (likely(cur_index != index)) {
|
||||
page = ufs_get_locked_page(mapping, index);
|
||||
if (IS_ERR(page))
|
||||
if (!page || IS_ERR(page)) /* it was truncated or EIO */
|
||||
continue;
|
||||
} else
|
||||
page = locked_page;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue