diff options
Diffstat (limited to 'fs')
36 files changed, 735 insertions, 633 deletions
@@ -711,10 +711,8 @@ static ssize_t aio_run_iocb(struct kiocb *iocb) */ ret = retry(iocb); - if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) { - BUG_ON(!list_empty(&iocb->ki_wait.task_list)); + if (ret != -EIOCBRETRY && ret != -EIOCBQUEUED) aio_complete(iocb, ret, 0); - } out: spin_lock_irq(&ctx->ctx_lock); @@ -866,13 +864,6 @@ static void try_queue_kicked_iocb(struct kiocb *iocb) unsigned long flags; int run = 0; - /* We're supposed to be the only path putting the iocb back on the run - * list. If we find that the iocb is *back* on a wait queue already - * than retry has happened before we could queue the iocb. This also - * means that the retry could have completed and freed our iocb, no - * good. */ - BUG_ON((!list_empty(&iocb->ki_wait.task_list))); - spin_lock_irqsave(&ctx->ctx_lock, flags); /* set this inside the lock so that we can't race with aio_run_iocb() * testing it and putting the iocb on the run list under the lock */ @@ -886,7 +877,7 @@ static void try_queue_kicked_iocb(struct kiocb *iocb) /* * kick_iocb: * Called typically from a wait queue callback context - * (aio_wake_function) to trigger a retry of the iocb. + * to trigger a retry of the iocb. * The retry is usually executed by aio workqueue * threads (See aio_kick_handler). */ @@ -1520,31 +1511,6 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) return 0; } -/* - * aio_wake_function: - * wait queue callback function for aio notification, - * Simply triggers a retry of the operation via kick_iocb. - * - * This callback is specified in the wait queue entry in - * a kiocb. - * - * Note: - * This routine is executed with the wait queue lock held. - * Since kick_iocb acquires iocb->ctx->ctx_lock, it nests - * the ioctx lock inside the wait queue lock. This is safe - * because this callback isn't used for wait queues which - * are nested inside ioctx lock (i.e. ctx->wait) - */ -static int aio_wake_function(wait_queue_t *wait, unsigned mode, - int sync, void *key) -{ - struct kiocb *iocb = container_of(wait, struct kiocb, ki_wait); - - list_del_init(&wait->task_list); - kick_iocb(iocb); - return 1; -} - static void aio_batch_add(struct address_space *mapping, struct hlist_head *batch_hash) { @@ -1642,8 +1608,6 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf; req->ki_left = req->ki_nbytes = iocb->aio_nbytes; req->ki_opcode = iocb->aio_lio_opcode; - init_waitqueue_func_entry(&req->ki_wait, aio_wake_function); - INIT_LIST_HEAD(&req->ki_wait.task_list); ret = aio_setup_iocb(req); diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 8f7cdde41733..0118d67221b2 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -60,6 +60,11 @@ do { \ current->pid, __func__, ##args); \ } while (0) +struct rehash_entry { + struct task_struct *task; + struct list_head list; +}; + /* Unified info structure. This is pointed to by both the dentry and inode structures. Each file in the filesystem has an instance of this structure. It holds a reference to the dentry, so dentries are never @@ -75,6 +80,9 @@ struct autofs_info { struct completion expire_complete; struct list_head active; + int active_count; + struct list_head rehash_list; + struct list_head expiring; struct autofs_sb_info *sbi; @@ -95,6 +103,8 @@ struct autofs_info { #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ #define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ +#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ +#define AUTOFS_INF_REHASH (1<<3) /* dentry in transit to ->lookup() */ struct autofs_wait_queue { wait_queue_head_t queue; @@ -161,7 +171,7 @@ static inline int autofs4_ispending(struct dentry *dentry) { struct autofs_info *inf = autofs4_dentry_ino(dentry); - if (dentry->d_flags & DCACHE_AUTOFS_PENDING) + if (inf->flags & AUTOFS_INF_PENDING) return 1; if (inf->flags & AUTOFS_INF_EXPIRING) @@ -264,5 +274,31 @@ out: return ret; } +static inline void autofs4_add_expiring(struct dentry *dentry) +{ + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + if (ino) { + spin_lock(&sbi->lookup_lock); + if (list_empty(&ino->expiring)) + list_add(&ino->expiring, &sbi->expiring_list); + spin_unlock(&sbi->lookup_lock); + } + return; +} + +static inline void autofs4_del_expiring(struct dentry *dentry) +{ + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + if (ino) { + spin_lock(&sbi->lookup_lock); + if (!list_empty(&ino->expiring)) + list_del_init(&ino->expiring); + spin_unlock(&sbi->lookup_lock); + } + return; +} + void autofs4_dentry_release(struct dentry *); extern void autofs4_kill_sb(struct super_block *); diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 3da18d453488..74bc9aa6df31 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -27,7 +27,7 @@ static inline int autofs4_can_expire(struct dentry *dentry, return 0; /* No point expiring a pending mount */ - if (dentry->d_flags & DCACHE_AUTOFS_PENDING) + if (ino->flags & AUTOFS_INF_PENDING) return 0; if (!do_now) { @@ -279,6 +279,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, root->d_mounted--; } ino->flags |= AUTOFS_INF_EXPIRING; + autofs4_add_expiring(root); init_completion(&ino->expire_complete); spin_unlock(&sbi->fs_lock); return root; @@ -406,6 +407,7 @@ found: expired, (int)expired->d_name.len, expired->d_name.name); ino = autofs4_dentry_ino(expired); ino->flags |= AUTOFS_INF_EXPIRING; + autofs4_add_expiring(expired); init_completion(&ino->expire_complete); spin_unlock(&sbi->fs_lock); spin_lock(&dcache_lock); @@ -433,7 +435,7 @@ int autofs4_expire_wait(struct dentry *dentry) DPRINTK("expire done status=%d", status); - if (d_unhashed(dentry)) + if (d_unhashed(dentry) && IS_DEADDIR(dentry->d_inode)) return -EAGAIN; return status; @@ -473,6 +475,7 @@ int autofs4_expire_run(struct super_block *sb, spin_lock(&sbi->fs_lock); ino = autofs4_dentry_ino(dentry); ino->flags &= ~AUTOFS_INF_EXPIRING; + autofs4_del_expiring(dentry); complete_all(&ino->expire_complete); spin_unlock(&sbi->fs_lock); @@ -503,6 +506,7 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, ino->flags &= ~AUTOFS_INF_MOUNTPOINT; } ino->flags &= ~AUTOFS_INF_EXPIRING; + autofs4_del_expiring(dentry); complete_all(&ino->expire_complete); spin_unlock(&sbi->fs_lock); dput(dentry); diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 69c8142da838..d0a3de247458 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -49,6 +49,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, ino->dentry = NULL; ino->size = 0; INIT_LIST_HEAD(&ino->active); + INIT_LIST_HEAD(&ino->rehash_list); + ino->active_count = 0; INIT_LIST_HEAD(&ino->expiring); atomic_set(&ino->count, 0); } diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index b96a3c57359d..30cc9ddf4b70 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -72,6 +72,139 @@ const struct inode_operations autofs4_dir_inode_operations = { .rmdir = autofs4_dir_rmdir, }; +static void autofs4_add_active(struct dentry *dentry) +{ + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + if (ino) { + spin_lock(&sbi->lookup_lock); + if (!ino->active_count) { + if (list_empty(&ino->active)) + list_add(&ino->active, &sbi->active_list); + } + ino->active_count++; + spin_unlock(&sbi->lookup_lock); + } + return; +} + +static void autofs4_del_active(struct dentry *dentry) +{ + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + if (ino) { + spin_lock(&sbi->lookup_lock); + ino->active_count--; + if (!ino->active_count) { + if (!list_empty(&ino->active)) + list_del_init(&ino->active); + } + spin_unlock(&sbi->lookup_lock); + } + return; +} + +static void autofs4_add_rehash_entry(struct autofs_info *ino, + struct rehash_entry *entry) +{ + entry->task = current; + INIT_LIST_HEAD(&entry->list); + list_add(&entry->list, &ino->rehash_list); + return; +} + +static void autofs4_remove_rehash_entry(struct autofs_info *ino) +{ + struct list_head *head = &ino->rehash_list; + struct rehash_entry *entry; + list_for_each_entry(entry, head, list) { + if (entry->task == current) { + list_del(&entry->list); + kfree(entry); + break; + } + } + return; +} + +static void autofs4_remove_rehash_entrys(struct autofs_info *ino) +{ + struct autofs_sb_info *sbi = ino->sbi; + struct rehash_entry *entry, *next; + struct list_head *head; + + spin_lock(&sbi->fs_lock); + spin_lock(&sbi->lookup_lock); + if (!(ino->flags & AUTOFS_INF_REHASH)) { + spin_unlock(&sbi->lookup_lock); + spin_unlock(&sbi->fs_lock); + return; + } + ino->flags &= ~AUTOFS_INF_REHASH; + head = &ino->rehash_list; + list_for_each_entry_safe(entry, next, head, list) { + list_del(&entry->list); + kfree(entry); + } + spin_unlock(&sbi->lookup_lock); + spin_unlock(&sbi->fs_lock); + dput(ino->dentry); + + return; +} + +static void autofs4_revalidate_drop(struct dentry *dentry, + struct rehash_entry *entry) +{ + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + /* + * Add to the active list so we can pick this up in + * ->lookup(). Also add an entry to a rehash list so + * we know when there are no dentrys in flight so we + * know when we can rehash the dentry. + */ + spin_lock(&sbi->lookup_lock); + if (list_empty(&ino->active)) + list_add(&ino->active, &sbi->active_list); + autofs4_add_rehash_entry(ino, entry); + spin_unlock(&sbi->lookup_lock); + if (!(ino->flags & AUTOFS_INF_REHASH)) { + ino->flags |= AUTOFS_INF_REHASH; + dget(dentry); + spin_lock(&dentry->d_lock); + __d_drop(dentry); + spin_unlock(&dentry->d_lock); + } + return; +} + +static void autofs4_revalidate_rehash(struct dentry *dentry) +{ + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + if (ino->flags & AUTOFS_INF_REHASH) { + spin_lock(&sbi->lookup_lock); + autofs4_remove_rehash_entry(ino); + if (list_empty(&ino->rehash_list)) { + spin_unlock(&sbi->lookup_lock); + ino->flags &= ~AUTOFS_INF_REHASH; + d_rehash(dentry); + dput(ino->dentry); + } else + spin_unlock(&sbi->lookup_lock); + } + return; +} + +static unsigned int autofs4_need_mount(unsigned int flags) +{ + unsigned int res = 0; + if (flags & (TRIGGER_FLAGS | TRIGGER_INTENTS)) + res = 1; + return res; +} + static int autofs4_dir_open(struct inode *inode, struct file *file) { struct dentry *dentry = file->f_path.dentry; @@ -93,7 +226,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) * it. */ spin_lock(&dcache_lock); - if (!d_mountpoint(dentry) && __simple_empty(dentry)) { + if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { spin_unlock(&dcache_lock); return -ENOENT; } @@ -103,7 +236,7 @@ out: return dcache_dir_open(inode, file); } -static int try_to_fill_dentry(struct dentry *dentry, int flags) +static int try_to_fill_dentry(struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_info *ino = autofs4_dentry_ino(dentry); @@ -116,55 +249,17 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) * Wait for a pending mount, triggering one if there * isn't one already */ - if (dentry->d_inode == NULL) { - DPRINTK("waiting for mount name=%.*s", - dentry->d_name.len, dentry->d_name.name); - - status = autofs4_wait(sbi, dentry, NFY_MOUNT); - - DPRINTK("mount done status=%d", status); - - /* Turn this into a real negative dentry? */ - if (status == -ENOENT) { - spin_lock(&dentry->d_lock); - dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; - spin_unlock(&dentry->d_lock); - return status; - } else if (status) { - /* Return a negative dentry, but leave it "pending" */ - return status; - } - /* Trigger mount for path component or follow link */ - } else if (dentry->d_flags & DCACHE_AUTOFS_PENDING || - flags & (TRIGGER_FLAGS | TRIGGER_INTENTS) || - current->link_count) { - DPRINTK("waiting for mount name=%.*s", - dentry->d_name.len, dentry->d_name.name); - - spin_lock(&dentry->d_lock); - dentry->d_flags |= DCACHE_AUTOFS_PENDING; - spin_unlock(&dentry->d_lock); - status = autofs4_wait(sbi, dentry, NFY_MOUNT); + DPRINTK("waiting for mount name=%.*s", + dentry->d_name.len, dentry->d_name.name); - DPRINTK("mount done status=%d", status); + status = autofs4_wait(sbi, dentry, NFY_MOUNT); - if (status) { - spin_lock(&dentry->d_lock); - dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; - spin_unlock(&dentry->d_lock); - return status; - } - } - - /* Initialize expiry counter after successful mount */ - if (ino) - ino->last_used = jiffies; + DPRINTK("mount done status=%d", status); - spin_lock(&dentry->d_lock); - dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; - spin_unlock(&dentry->d_lock); + /* Update expiry counter */ + ino->last_used = jiffies; - return 0; + return status; } /* For autofs direct mounts the follow link triggers the mount */ @@ -202,27 +297,39 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) autofs4_expire_wait(dentry); /* We trigger a mount for almost all flags */ - lookup_type = nd->flags & (TRIGGER_FLAGS | TRIGGER_INTENTS); - if (!(lookup_type || dentry->d_flags & DCACHE_AUTOFS_PENDING)) + lookup_type = autofs4_need_mount(nd->flags); + spin_lock(&sbi->fs_lock); + spin_lock(&dcache_lock); + if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { + spin_unlock(&dcache_lock); + spin_unlock(&sbi->fs_lock); goto follow; + } /* * If the dentry contains directories then it is an autofs * multi-mount with no root mount offset. So don't try to * mount it again. */ - spin_lock(&dcache_lock); - if (dentry->d_flags & DCACHE_AUTOFS_PENDING || - (!d_mountpoint(dentry) && __simple_empty(dentry))) { + if (ino->flags & AUTOFS_INF_PENDING || + (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { + ino->flags |= AUTOFS_INF_PENDING; spin_unlock(&dcache_lock); + spin_unlock(&sbi->fs_lock); + + status = try_to_fill_dentry(dentry); + + spin_lock(&sbi->fs_lock); + ino->flags &= ~AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); - status = try_to_fill_dentry(dentry, 0); if (status) goto out_error; goto follow; } spin_unlock(&dcache_lock); + spin_unlock(&sbi->fs_lock); follow: /* * If there is no root mount it must be an autofs @@ -254,18 +361,47 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) { struct inode *dir = dentry->d_parent->d_inode; struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); - int oz_mode = autofs4_oz_mode(sbi); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + struct rehash_entry *entry; int flags = nd ? nd->flags : 0; - int status = 1; + unsigned int mutex_aquired; + + DPRINTK("name = %.*s oz_mode = %d", + dentry->d_name.len, dentry->d_name.name, oz_mode); + + /* Daemon never causes a mount to trigger */ + if (autofs4_oz_mode(sbi)) + return 1; + + entry = kmalloc(sizeof(struct rehash_entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + mutex_aquired = mutex_trylock(&dir->i_mutex); - /* Pending dentry */ spin_lock(&sbi->fs_lock); + spin_lock(&dcache_lock); + /* Pending dentry */ if (autofs4_ispending(dentry)) { - /* The daemon never causes a mount to trigger */ - spin_unlock(&sbi->fs_lock); + int status; - if (oz_mode) - return 1; + /* + * We can only unhash and send this to ->lookup() if + * the directory mutex is held over d_revalidate() and + * ->lookup(). This prevents the VFS from incorrectly + * seeing the dentry as non-existent. + */ + ino->flags |= AUTOFS_INF_PENDING; + if (!mutex_aquired) { + autofs4_revalidate_drop(dentry, entry); + spin_unlock(&dcache_lock); + spin_unlock(&sbi->fs_lock); + return 0; + } + spin_unlock(&dcache_lock); + spin_unlock(&sbi->fs_lock); + mutex_unlock(&dir->i_mutex); + kfree(entry); /* * If the directory has gone away due to an expire @@ -279,46 +415,82 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) * A zero status is success otherwise we have a * negative error code. */ - status = try_to_fill_dentry(dentry, flags); + status = try_to_fill_dentry(dentry); + + spin_lock(&sbi->fs_lock); + ino->flags &= ~AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); + if (status == 0) return 1; return status; } - spin_unlock(&sbi->fs_lock); - - /* Negative dentry.. invalidate if "old" */ - if (dentry->d_inode == NULL) - return 0; /* Check for a non-mountpoint directory with no contents */ - spin_lock(&dcache_lock); if (S_ISDIR(dentry->d_inode->i_mode) && - !d_mountpoint(dentry) && - __simple_empty(dentry)) { + !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { DPRINTK("dentry=%p %.*s, emptydir", dentry, dentry->d_name.len, dentry->d_name.name); - spin_unlock(&dcache_lock); - /* The daemon never causes a mount to trigger */ - if (oz_mode) - return 1; + if (autofs4_need_mount(flags) || current->link_count) { + int status; - /* - * A zero status is success otherwise we have a - * negative error code. - */ - status = try_to_fill_dentry(dentry, flags); - if (status == 0) - return 1; + /* + * We can only unhash and send this to ->lookup() if + * the directory mutex is held over d_revalidate() and + * ->lookup(). This prevents the VFS from incorrectly + * seeing the dentry as non-existent. + */ + ino->flags |= AUTOFS_INF_PENDING; + if (!mutex_aquired) { + autofs4_revalidate_drop(dentry, entry); + spin_unlock(&dcache_lock); + spin_unlock(&sbi->fs_lock); + return 0; + } + spin_unlock(&dcache_lock); + spin_unlock(&sbi->fs_lock); + mutex_unlock(&dir->i_mutex); + kfree(entry); - return status; + /* + * A zero status is success otherwise we have a + * negative error code. + */ + status = try_to_fill_dentry(dentry); + + spin_lock(&sbi->fs_lock); + ino->flags &= ~AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); + + if (status == 0) + return 1; + + return status; + } } spin_unlock(&dcache_lock); + spin_unlock(&sbi->fs_lock); + + if (mutex_aquired) + mutex_unlock(&dir->i_mutex); + + kfree(entry); return 1; } +static void autofs4_free_rehash_entrys(struct autofs_info *inf) +{ + struct list_head *head = &inf->rehash_list; + struct rehash_entry *entry, *next; + list_for_each_entry_safe(entry, next, head, list) { + list_del(&entry->list); + kfree(entry); + } +} + void autofs4_dentry_release(struct dentry *de) { struct autofs_info *inf; @@ -337,6 +509,8 @@ void autofs4_dentry_release(struct dentry *de) list_del(&inf->active); if (!list_empty(&inf->expiring)) list_del(&inf->expiring); + if (!list_empty(&inf->rehash_list)) + autofs4_free_rehash_entrys(inf); spin_unlock(&sbi->lookup_lock); } @@ -359,35 +533,52 @@ static const struct dentry_operations autofs4_dentry_operations = { .d_release = autofs4_dentry_release, }; -static struct dentry *autofs4_lookup_active(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) +static struct dentry *autofs4_lookup_active(struct dentry *dentry) { + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct dentry *parent = dentry->d_parent; + struct qstr *name = &dentry->d_name; unsigned int len = name->len; unsigned int hash = name->hash; const unsigned char *str = name->name; struct list_head *p, *head; +restart: spin_lock(&dcache_lock); spin_lock(&sbi->lookup_lock); head = &sbi->active_list; list_for_each(p, head) { struct autofs_info *ino; - struct dentry *dentry; + struct dentry *active; struct qstr *qstr; ino = list_entry(p, struct autofs_info, active); - dentry = ino->dentry; + active = ino->dentry; - spin_lock(&dentry->d_lock); + spin_lock(&active->d_lock); /* Already gone? */ - if (atomic_read(&dentry->d_count) == 0) + if (atomic_read(&active->d_count) == 0) goto next; - qstr = &dentry->d_name; + if (active->d_inode && IS_DEADDIR(active->d_inode)) { + if (!list_empty(&ino->rehash_list)) { + dget(active); + spin_unlock(&active->d_lock); + spin_unlock(&sbi->lookup_lock); + spin_unlock(&dcache_lock); + autofs4_remove_rehash_entrys(ino); + dput(active); + goto restart; + } + goto next; + } + + qstr = &active->d_name; - if (dentry->d_name.hash != hash) + if (active->d_name.hash != hash) goto next; - if (dentry->d_parent != parent) + if (active->d_parent != parent) goto next; if (qstr->len != len) @@ -395,15 +586,13 @@ static struct dentry *autofs4_lookup_active(struct autofs_sb_info *sbi, struct d if (memcmp(qstr->name, str, len)) goto next; - if (d_unhashed(dentry)) { - dget(dentry); - spin_unlock(&dentry->d_lock); - spin_unlock(&sbi->lookup_lock); - spin_unlock(&dcache_lock); - return dentry; - } + dget(active); + spin_unlock(&active->d_lock); + spin_unlock(&sbi->lookup_lock); + spin_unlock(&dcache_lock); + return active; next: - spin_unlock(&dentry->d_lock); + spin_unlock(&active->d_lock); } spin_unlock(&sbi->lookup_lock); spin_unlock(&dcache_lock); @@ -411,8 +600,11 @@ next: return NULL; } -static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) +static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) { + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct dentry *parent = dentry->d_parent; + struct qstr *name = &dentry->d_name; unsigned int len = name->len; unsigned int hash = name->hash; const unsigned char *str = name->name; @@ -423,23 +615,23 @@ static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct head = &sbi->expiring_list; list_for_each(p, head) { struct autofs_info *ino; - struct dentry *dentry; + struct dentry *expiring; struct qstr *qstr; ino = list_entry(p, struct autofs_info, expiring); - dentry = ino->dentry; + expiring = ino->dentry; - spin_lock(&dentry->d_lock); + spin_lock(&expiring->d_lock); /* Bad luck, we've already been dentry_iput */ - if (!dentry->d_inode) + if (!expiring->d_inode) goto next; - qstr = &dentry->d_name; + qstr = &expiring->d_name; - if (dentry->d_name.hash != hash) + if (expiring->d_name.hash != hash) goto next; - if (dentry->d_parent != parent) + if (expiring->d_parent != parent) goto next; if (qstr->len != len) @@ -447,15 +639,13 @@ static struct dentry *autofs4_lookup_expiring(struct autofs_sb_info *sbi, struct if (memcmp(qstr->name, str, len)) goto next; - if (d_unhashed(dentry)) { - dget(dentry); - spin_unlock(&dentry->d_lock); - spin_unlock(&sbi->lookup_lock); - spin_unlock(&dcache_lock); - return dentry; - } + dget(expiring); + spin_unlock(&expiring->d_lock); + spin_unlock(&sbi->lookup_lock); + spin_unlock(&dcache_lock); + return expiring; next: - spin_unlock(&dentry->d_lock); + spin_unlock(&expiring->d_lock); } spin_unlock(&sbi->lookup_lock); spin_unlock(&dcache_lock); @@ -463,13 +653,56 @@ next: return NULL; } +static struct autofs_info *init_new_dentry(struct autofs_sb_info *sbi, + struct dentry *dentry, int oz_mode) +{ + struct autofs_info *ino; + + /* + * Mark the dentry incomplete but don't hash it. We do this + * to serialize our inode creation operations (symlink and + * mkdir) which prevents deadlock during the callback to + * the daemon. Subsequent user space lookups for the same + * dentry are placed on the wait queue while the daemon + * itself is allowed passage unresticted so the create + * operation itself can then hash the dentry. Finally, + * we check for the hashed dentry and return the newly + * hashed dentry. + */ + dentry->d_op = &autofs4_root_dentry_operations; + + /* + * And we need to ensure that the same dentry is used for + * all following lookup calls until it is hashed so that + * the dentry flags are persistent throughout the request. + */ + ino = autofs4_init_ino(NULL, sbi, 0555); + if (!ino) + return ERR_PTR(-ENOMEM); + + dentry->d_fsdata = ino; + ino->dentry = dentry; + + /* + * Only set the mount pending flag for new dentrys not created + * by the daemon. + */ + if (!oz_mode) + ino->flags |= AUTOFS_INF_PENDING; + + d_instantiate(dentry, NULL); + + return ino; +} + /* Lookups in the root directory */ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct autofs_sb_info *sbi; struct autofs_info *ino; - struct dentry *expiring, *unhashed; + struct dentry *expiring, *active; int oz_mode; + int status = 0; DPRINTK("name = %.*s", dentry->d_name.len, dentry->d_name.name); @@ -484,123 +717,100 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); - unhashed = autofs4_lookup_active(sbi, dentry->d_parent, &dentry->d_name); - if (unhashed) - dentry = unhashed; - else { - /* - * Mark the dentry incomplete but don't hash it. We do this - * to serialize our inode creation operations (symlink and - * mkdir) which prevents deadlock during the callback to - * the daemon. Subsequent user space lookups for the same - * dentry are placed on the wait queue while the daemon - * itself is allowed passage unresticted so the create - * operation itself can then hash the dentry. Finally, - * we check for the hashed dentry and return the newly - * hashed dentry. - */ - dentry->d_op = &autofs4_root_dentry_operations; - - /* - * And we need to ensure that the same dentry is used for - * all following lookup calls until it is hashed so that - * the dentry flags are persistent throughout the request. - */ - ino = autofs4_init_ino(NULL, sbi, 0555); - if (!ino) - return ERR_PTR(-ENOMEM); - - dentry->d_fsdata = ino; - ino->dentry = dentry; - - spin_lock(&sbi->lookup_lock); - list_add(&ino->active, &sbi->active_list); - spin_unlock(&sbi->lookup_lock); - - d_instantiate(dentry, NULL); + spin_lock(&sbi->fs_lock); + active = autofs4_lookup_active(dentry); + if (active) { + dentry = active; + ino = autofs4_dentry_ino(dentry); + /* If this came from revalidate, rehash it */ + autofs4_revalidate_rehash(dentry); + spin_unlock(&sbi->fs_lock); + } else { + spin_unlock(&sbi->fs_lock); + ino = init_new_dentry(sbi, dentry, oz_mode); + if (IS_ERR(ino)) + return (struct dentry *) ino; } + autofs4_add_active(dentry); + if (!oz_mode) { + expiring = autofs4_lookup_expiring(dentry); mutex_unlock(&dir->i_mutex); - expiring = autofs4_lookup_expiring(sbi, - dentry->d_parent, - &dentry->d_name); if (expiring) { /* * If we are racing with expire the request might not * be quite complete but the directory has been removed * so it must have been successful, so just wait for it. */ - ino = autofs4_dentry_ino(expiring); autofs4_expire_wait(expiring); - spin_lock(&sbi->lookup_lock); - if (!list_empty(&ino->expiring)) - list_del_init(&ino->expiring); - spin_unlock(&sbi->lookup_lock); dput(expiring); } - - spin_lock(&dentry->d_lock); - dentry->d_flags |= DCACHE_AUTOFS_PENDING; - spin_unlock(&dentry->d_lock); - if (dentry->d_op && dentry->d_op->d_revalidate) - (dentry->d_op->d_revalidate)(dentry, nd); + status = try_to_fill_dentry(dentry); mutex_lock(&dir->i_mutex); + spin_lock(&sbi->fs_lock); + ino->flags &= ~AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); } + autofs4_del_active(dentry); + /* - * If we are still pending, check if we had to handle + * If we had a mount fail, check if we had to handle * a signal. If so we can force a restart.. */ - if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { + if (status) { /* See if we were interrupted */ if (signal_pending(current)) { sigset_t *sigset = ¤t->pending.signal; if (sigismember (sigset, SIGKILL) || sigismember (sigset, SIGQUIT) || sigismember (sigset, SIGINT)) { - if (unhashed) - dput(unhashed); + if (active) + dput(active); return ERR_PTR(-ERESTARTNOINTR); } } - if (!oz_mode) { - spin_lock(&dentry->d_lock); - dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; - spin_unlock(&dentry->d_lock); + } + + /* + * User space can (and has done in the past) remove and re-create + * this directory during the callback. This can leave us with an + * unhashed dentry, but a successful mount! So we need to + * perform another cached lookup in case the dentry now exists. + */ + if (!oz_mode && !have_submounts(dentry)) { + struct dentry *new; + new = d_lookup(dentry->d_parent, &dentry->d_name); + if (new) { + if (active) + dput(active); + return new; + } else { + if (!status) + status = -ENOENT; } } /* - * If this dentry is unhashed, then we shouldn't honour this - * lookup. Returning ENOENT here doesn't do the right thing - * for all system calls, but it should be OK for the operations - * we permit from an autofs. + * If we had a mount failure, return status to user space. + * If the mount succeeded and we used a dentry from the active queue + * return it. */ - if (!oz_mode && d_unhashed(dentry)) { + if (status) { + dentry = ERR_PTR(status); + if (active) + dput(active); + return dentry; + } else { /* - * A user space application can (and has done in the past) - * remove and re-create this directory during the callback. - * This can leave us with an unhashed dentry, but a - * successful mount! So we need to perform another - * cached lookup in case the dentry now exists. + * Valid successful mount, return active dentry or NULL + * for a new dentry. */ - struct dentry *parent = dentry->d_parent; - struct dentry *new = d_lookup(parent, &dentry->d_name); - if (new != NULL) - dentry = new; - else - dentry = ERR_PTR(-ENOENT); - - if (unhashed) - dput(unhashed); - - return dentry; + if (active) + return active; } - if (unhashed) - return unhashed; - return NULL; } @@ -624,11 +834,6 @@ static int autofs4_dir_symlink(struct inode *dir, if (!ino) return -ENOMEM; - spin_lock(&sbi->lookup_lock); - if (!list_empty(&ino->active)) - list_del_init(&ino->active); - spin_unlock(&sbi->lookup_lock); - ino->size = strlen(symname); cp = kmalloc(ino->size + 1, GFP_KERNEL); if (!cp) { @@ -705,10 +910,6 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) dir->i_mtime = CURRENT_TIME; spin_lock(&dcache_lock); - spin_lock(&sbi->lookup_lock); - if (list_empty(&ino->expiring)) - list_add(&ino->expiring, &sbi->expiring_list); - spin_unlock(&sbi->lookup_lock); spin_lock(&dentry->d_lock); __d_drop(dentry); spin_unlock(&dentry->d_lock); @@ -734,10 +935,6 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) spin_unlock(&dcache_lock); return -ENOTEMPTY; } - spin_lock(&sbi->lookup_lock); - if (list_empty(&ino->expiring)) - list_add(&ino->expiring, &sbi->expiring_list); - spin_unlock(&sbi->lookup_lock); spin_lock(&dentry->d_lock); __d_drop(dentry); spin_unlock(&dentry->d_lock); @@ -775,11 +972,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (!ino) return -ENOMEM; - spin_lock(&sbi->lookup_lock); - if (!list_empty(&ino->active)) - list_del_init(&ino->active); - spin_unlock(&sbi->lookup_lock); - inode = autofs4_get_inode(dir->i_sb, ino); if (!inode) { if (!dentry->d_fsdata) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d15ea1790bfb..97b6e9efeb7f 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -44,7 +44,7 @@ static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, * If we don't support core dumping, then supply a NULL so we * don't even try. */ -#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) +#ifdef CONFIG_ELF_CORE static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); #else #define elf_core_dump NULL @@ -1101,12 +1101,7 @@ out: return error; } -/* - * Note that some platforms still use traditional core dumps and not - * the ELF core dump. Each platform can select it as appropriate. - */ -#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) - +#ifdef CONFIG_ELF_CORE /* * ELF core dumper * @@ -2063,7 +2058,7 @@ out: return has_dumped; } -#endif /* USE_ELF_CORE_DUMP */ +#endif /* CONFIG_ELF_CORE */ static int __init init_elf_binfmt(void) { diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 79d2b1aa389f..7b055385db8e 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -75,14 +75,14 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(struct elf_fdpic_params *, static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *, struct file *, struct mm_struct *); -#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) +#ifdef CONFIG_ELF_CORE static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *, unsigned long limit); #endif static struct linux_binfmt elf_fdpic_format = { .module = THIS_MODULE, .load_binary = load_elf_fdpic_binary, -#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) +#ifdef CONFIG_ELF_CORE .core_dump = elf_fdpic_core_dump, #endif .min_coredump = ELF_EXEC_PAGESIZE, @@ -1201,7 +1201,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, * * Modelled on fs/binfmt_elf.c core dumper */ -#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) +#ifdef CONFIG_ELF_CORE /* * These are the only things you should do on a core-file: use only these @@ -1826,4 +1826,4 @@ cleanup: #undef NUM_NOTES } -#endif /* USE_ELF_CORE_DUMP */ +#endif /* CONFIG_ELF_CORE */ diff --git a/fs/direct-io.c b/fs/direct-io.c index b912270942fa..4012885d027f 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -53,13 +53,6 @@ * * If blkfactor is zero then the user's request was aligned to the filesystem's * blocksize. - * - * lock_type is DIO_LOCKING for regular files on direct-IO-naive filesystems. - * This determines whether we need to do the fancy locking which prevents - * direct-IO from being able to read uninitialised disk blocks. If its zero - * (blockdev) this locking is not done, and if it is DIO_OWN_LOCKING i_mutex is - * not held for the entire direct write (taken briefly, initially, during a - * direct read though, but its never held for the duration of a direct-IO). */ struct dio { @@ -68,7 +61,7 @@ struct dio { struct inode *inode; int rw; loff_t i_size; /* i_size when submitted */ - int lock_type; /* doesn't change */ + int flags; /* doesn't change */ unsigned blkbits; /* doesn't change */ unsigned blkfactor; /* When we're using an alignment which is finer than the filesystem's soft @@ -104,6 +97,18 @@ struct dio { unsigned cur_page_len; /* Nr of bytes at cur_page_offset */ sector_t cur_page_block; /* Where it starts */ + /* BIO completion state */ + spinlock_t bio_lock; /* protects BIO fields below */ + unsigned long refcount; /* direct_io_worker() and bios */ + struct bio *bio_list; /* singly linked via bi_private */ + struct task_struct *waiter; /* waiting task (NULL if none) */ + + /* AIO related stuff */ + struct kiocb *iocb; /* kiocb */ + int is_async; /* is IO async ? */ + int io_error; /* IO error in completion path */ + ssize_t result; /* IO result */ + /* * Page fetching state. These variables belong to dio_refill_pages(). */ @@ -115,22 +120,16 @@ struct dio { * Page queue. These variables belong to dio_refill_pages() and * dio_get_page(). */ - struct page *pages[DIO_PAGES]; /* page buffer */ unsigned head; /* next page to process */ unsigned tail; /* last valid page + 1 */ int page_errors; /* errno from get_user_pages() */ - /* BIO completion state */ - spinlock_t bio_lock; /* protects BIO fields below */ - unsigned long refcount; /* direct_io_worker() and bios */ - struct bio *bio_list; /* singly linked via bi_private */ - struct task_struct *waiter; /* waiting task (NULL if none) */ - - /* AIO related stuff */ - struct kiocb *iocb; /* kiocb */ - int is_async; /* is IO async ? */ - int io_error; /* IO error in completion path */ - ssize_t result; /* IO result */ + /* + * pages[] (and any fields placed after it) are not zeroed out at + * allocation time. Don't add new fields after pages[] unless you + * wish that they not be zeroed. + */ + struct page *pages[DIO_PAGES]; /* page buffer */ }; /* @@ -240,7 +239,8 @@ static int dio_complete(struct dio *dio, loff_t offset, int ret) if (dio->end_io && dio->result) dio->end_io(dio->iocb, offset, transferred, dio->map_bh.b_private); - if (dio->lock_type == DIO_LOCKING) + + if (dio->flags & DIO_LOCKING) /* lockdep: non-owner release */ up_read_non_owner(&dio->inode->i_alloc_sem); @@ -515,21 +515,24 @@ static int get_more_blocks(struct dio *dio) map_bh->b_state = 0; map_bh->b_size = fs_count << dio->inode->i_blkbits; + /* + * For writes inside i_size on a DIO_SKIP_HOLES filesystem we + * forbid block creations: only overwrites are permitted. + * We will return early to the caller once we see an + * unmapped buffer head returned, and the caller will fall + * back to buffered I/O. + * + * Otherwise the decision is left to the get_blocks method, + * which may decide to handle it or also return an unmapped + * buffer head. + */ create = dio->rw & WRITE; - if (dio->lock_type == DIO_LOCKING) { + if (dio->flags & DIO_SKIP_HOLES) { if (dio->block_in_file < (i_size_read(dio->inode) >> dio->blkbits)) create = 0; - } else if (dio->lock_type == DIO_NO_LOCKING) { - create = 0; } - /* - * For writes inside i_size we forbid block creations: only - * overwrites are permitted. We fall back to buffered writes - * at a higher level for inside-i_size block-instantiating - * writes. - */ ret = (*dio->get_block)(dio->inode, fs_startblk, map_bh, create); } @@ -1039,7 +1042,7 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, * we can let i_mutex go now that its achieved its purpose * of protecting us from looking up uninitialized blocks. */ - if ((rw == READ) && (dio->lock_type == DIO_LOCKING)) + if (rw == READ && (dio->flags & DIO_LOCKING)) mutex_unlock(&dio->inode->i_mutex); /* @@ -1086,30 +1089,28 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, /* * This is a library function for use by filesystem drivers. - * The locking rules are governed by the dio_lock_type parameter. * - * DIO_NO_LOCKING (no locking, for raw block device access) - * For writes, i_mutex is not held on entry; it is never taken. + * The locking rules are governed by the flags parameter: + * - if the flags value contains DIO_LOCKING we use a fancy locking + * scheme for dumb filesystems. + * For writes this function is called under i_mutex and returns with + * i_mutex held, for reads, i_mutex is not held on entry, but it is + * taken and dropped again before returning. + * For reads and writes i_alloc_sem is taken in shared mode and released + * on I/O completion (which may happen asynchronously after returning to + * the caller). * - * DIO_LOCKING (simple locking for regular files) - * For writes we are called under i_mutex and return with i_mutex held, even - * though it is internally dropped. - * For reads, i_mutex is not held on entry, but it is taken and dropped before - * returning. - * - * DIO_OWN_LOCKING (filesystem provides synchronisation and handling of - * uninitialised data, allowing parallel direct readers and writers) - * For writes we are called without i_mutex, return without it, never touch it. - * For reads we are called under i_mutex and return with i_mutex held, even - * though it may be internally dropped. - * - * Additional i_alloc_sem locking requirements described inline below. + * - if the flags value does NOT contain DIO_LOCKING we don't use any + * internal locking but rather rely on the filesystem to synchronize + * direct I/O reads/writes versus each other and truncate. + * For reads and writes both i_mutex and i_alloc_sem are not held on + * entry and are never taken. */ ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, struct block_device *bdev, const struct iovec *iov, loff_t offset, unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, - int dio_lock_type) + int flags) { int seg; size_t size; @@ -1120,8 +1121,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, ssize_t retval = -EINVAL; loff_t end = offset; struct dio *dio; - int release_i_mutex = 0; - int acquire_i_mutex = 0; if (rw & WRITE) rw = WRITE_ODIRECT_PLUG; @@ -1151,48 +1150,41 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, } } - dio = kzalloc(sizeof(*dio), GFP_KERNEL); + dio = kmalloc(sizeof(*dio), GFP_KERNEL); retval = -ENOMEM; if (!dio) goto out; - /* - * For block device access DIO_NO_LOCKING is used, - * neither readers nor writers do any locking at all - * For regular files using DIO_LOCKING, - * readers need to grab i_mutex and i_alloc_sem - * writers need to grab i_alloc_sem only (i_mutex is already held) - * For regular files using DIO_OWN_LOCKING, - * neither readers nor writers take any locks here + * Believe it or not, zeroing out the page array caused a .5% + * performance regression in a database benchmark. So, we take + * care to only zero out what's needed. */ - dio->lock_type = dio_lock_type; - if (dio_lock_type != DIO_NO_LOCKING) { + memset(dio, 0, offsetof(struct dio, pages)); + + dio->flags = flags; + if (dio->flags & DIO_LOCKING) { /* watch out for a 0 len io from a tricksy fs */ if (rw == READ && end > offset) { - struct address_space *mapping; + struct address_space *mapping = + iocb->ki_filp->f_mapping; - mapping = iocb->ki_filp->f_mapping; - if (dio_lock_type != DIO_OWN_LOCKING) { - mutex_lock(&inode->i_mutex); - release_i_mutex = 1; - } + /* will be released by direct_io_worker */ + mutex_lock(&inode->i_mutex); retval = filemap_write_and_wait_range(mapping, offset, end - 1); if (retval) { + mutex_unlock(&inode->i_mutex); kfree(dio); goto out; } - - if (dio_lock_type == DIO_OWN_LOCKING) { - mutex_unlock(&inode->i_mutex); - acquire_i_mutex = 1; - } } - if (dio_lock_type == DIO_LOCKING) - /* lockdep: not the owner will release it */ - down_read_non_owner(&inode->i_alloc_sem); + /* + * Will be released at I/O completion, possibly in a + * different thread. + */ + down_read_non_owner(&inode->i_alloc_sem); } /* @@ -1210,24 +1202,19 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, /* * In case of error extending write may have instantiated a few * blocks outside i_size. Trim these off again for DIO_LOCKING. - * NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this by - * it's own meaner. + * + * NOTE: filesystems with their own locking have to handle this + * on their own. */ - if (unlikely(retval < 0 && (rw & WRITE))) { - loff_t isize = i_size_read(inode); - - if (end > isize && dio_lock_type == DIO_LOCKING) - vmtruncate(inode, isize); + if (dio->flags & DIO_LOCKING) { + if (unlikely((rw & WRITE) && retval < 0)) { + loff_t isize = i_size_read(inode); + if (end > isize) + vmtruncate(inode, isize); + } } - if (rw == READ && dio_lock_type == DIO_LOCKING) - release_i_mutex = 0; - out: - if (release_i_mutex) - mutex_unlock(&inode->i_mutex); - else if (acquire_i_mutex) - mutex_lock(&inode->i_mutex); return retval; } EXPORT_SYMBOL(__blockdev_direct_IO); diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index fc2bd05d3559..7516957273ed 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -721,5 +721,5 @@ const struct file_operations ext2_dir_operations = { #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif - .fsync = simple_fsync, + .fsync = ext2_fsync, }; diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index da318b0fa637..061914add3cf 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -155,6 +155,7 @@ extern void ext2_write_super (struct super_block *); extern const struct file_operations ext2_dir_operations; /* file.c */ +extern int ext2_fsync(struct file *file, struct dentry *dentry, int datasync); extern const struct inode_operations ext2_file_inode_operations; extern const struct file_operations ext2_file_operations; extern const struct file_operations ext2_xip_file_operations; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index a2f3afd1a1c1..586e3589d4c2 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -19,6 +19,7 @@ */ #include <linux/time.h> +#include <linux/pagemap.h> #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -38,6 +39,22 @@ static int ext2_release_file (struct inode * inode, struct file * filp) return 0; } +int ext2_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + int ret; + struct super_block *sb = dentry->d_inode->i_sb; + struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; + + ret = simple_fsync(file, dentry, datasync); + if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { + /* We don't really know where the IO error happened... */ + ext2_error(sb, __func__, + "detected IO error when writing metadata buffers"); + ret = -EIO; + } + return ret; +} + /* * We have mostly NULL's here: the current defaults are ok for * the ext2 filesystem. @@ -55,7 +72,7 @@ const struct file_operations ext2_file_operations = { .mmap = generic_file_mmap, .open = generic_file_open, .release = ext2_release_file, - .fsync = simple_fsync, + .fsync = ext2_fsync, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, }; @@ -72,7 +89,7 @@ const struct file_operations ext2_xip_file_operations = { .mmap = xip_file_mmap, .open = generic_file_open, .release = ext2_release_file, - .fsync = simple_fsync, + .fsync = ext2_fsync, }; #endif diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 1388802b7803..f9cb54a585ce 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1105,9 +1105,30 @@ failed_sbi: return ret; } +static void ext2_clear_super_error(struct super_block *sb) +{ + struct buffer_head *sbh = EXT2_SB(sb)->s_sbh; + + if (buffer_write_io_error(sbh)) { + /* + * Oh, dear. A previous attempt to write the + * superblock failed. This could happen because the + * USB device was yanked out. Or it could happen to + * be a transient write error and maybe the block will + * be remapped. Nothing we can do but to retry the + * write and hope for the best. + */ + printk(KERN_ERR "EXT2-fs: %s previous I/O error to " + "superblock detected", sb->s_id); + clear_buffer_write_io_error(sbh); + set_buffer_uptodate(sbh); + } +} + static void ext2_commit_super (struct super_block * sb, struct ext2_super_block * es) { + ext2_clear_super_error(sb); es->s_wtime = cpu_to_le32(get_seconds()); mark_buffer_dirty(EXT2_SB(sb)->s_sbh); sb->s_dirt = 0; @@ -1115,6 +1136,7 @@ static void ext2_commit_super (struct super_block * sb, static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) { + ext2_clear_super_error(sb); es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); es->s_wtime = cpu_to_le32(get_seconds()); diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 7db0979c6b72..e6efdfa0f6db 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -44,7 +44,8 @@ struct fat_mount_options { nocase:1, /* Does this need case conversion? 0=need case conversion*/ usefree:1, /* Use free_clusters for FAT32 */ tz_utc:1, /* Filesystem timestamps are in UTC */ - rodir:1; /* allow ATTR_RO for directory */ + rodir:1, /* allow ATTR_RO for directory */ + discard:1; /* Issue discard requests on deletions */ }; #define FAT_HASH_BITS 8 diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index a81037721a6f..81184d3b75a3 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -566,16 +566,21 @@ int fat_free_clusters(struct inode *inode, int cluster) goto error; } - /* - * Issue discard for the sectors we no longer care about, - * batching contiguous clusters into one request - */ - if (cluster != fatent.entry + 1) { - int nr_clus = fatent.entry - first_cl + 1; - - sb_issue_discard(sb, fat_clus_to_blknr(sbi, first_cl), - nr_clus * sbi->sec_per_clus); - first_cl = cluster; + if (sbi->options.discard) { + /* + * Issue discard for the sectors we no longer + * care about, batching contiguous clusters + * into one request + */ + if (cluster != fatent.entry + 1) { + int nr_clus = fatent.entry - first_cl + 1; + + sb_issue_discard(sb, + fat_clus_to_blknr(sbi, first_cl), + nr_clus * sbi->sec_per_clus); + + first_cl = cluster; + } } ops->ent_put(&fatent, FAT_ENT_FREE); diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 76b7961ab663..14da530b05ca 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -858,6 +858,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) seq_puts(m, ",errors=panic"); else seq_puts(m, ",errors=remount-ro"); + if (opts->discard) + seq_puts(m, ",discard"); return 0; } @@ -871,7 +873,7 @@ enum { Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, - Opt_err_panic, Opt_err_ro, Opt_err, + Opt_err_panic, Opt_err_ro, Opt_discard, Opt_err, }; static const match_table_t fat_tokens = { @@ -899,6 +901,7 @@ static const match_table_t fat_tokens = { {Opt_err_cont, "errors=continue"}, {Opt_err_panic, "errors=panic"}, {Opt_err_ro, "errors=remount-ro"}, + {Opt_discard, "discard"}, {Opt_obsolate, "conv=binary"}, {Opt_obsolate, "conv=text"}, {Opt_obsolate, "conv=auto"}, @@ -1136,6 +1139,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, case Opt_rodir: opts->rodir = 1; break; + case Opt_discard: + opts->discard = 1; + break; /* obsolete mount options */ case Opt_obsolate: diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 0f55f5cb732f..d3da05f26465 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/fs.h> #include <linux/buffer_head.h> +#include <linux/time.h> #include "fat.h" /* @@ -157,10 +158,6 @@ extern struct timezone sys_tz; #define SECS_PER_MIN 60 #define SECS_PER_HOUR (60 * 60) #define SECS_PER_DAY (SECS_PER_HOUR * 24) -#define UNIX_SECS_1980 315532800L -#if BITS_PER_LONG == 64 -#define UNIX_SECS_2108 4354819200L -#endif /* days between 1.1.70 and 1.1.80 (2 leap days) */ #define DAYS_DELTA (365 * 10 + 2) /* 120 (2100 - 1980) isn't leap year */ @@ -213,58 +210,35 @@ void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts, void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts, __le16 *time, __le16 *date, u8 *time_cs) { - time_t second = ts->tv_sec; - time_t day, leap_day, month, year; + struct tm tm; + time_to_tm(ts->tv_sec, sbi->options.tz_utc ? 0 : + -sys_tz.tz_minuteswest * 60, &tm); - if (!sbi->options.tz_utc) - second -= sys_tz.tz_minuteswest * SECS_PER_MIN; - - /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ - if (second < UNIX_SECS_1980) { + /* FAT can only support year between 1980 to 2107 */ + if (tm.tm_year < 1980 - 1900) { *time = 0; *date = cpu_to_le16((0 << 9) | (1 << 5) | 1); if (time_cs) *time_cs = 0; return; } -#if BITS_PER_LONG == 64 - if (second >= UNIX_SECS_2108) { + if (tm.tm_year > 2107 - 1900) { *time = cpu_to_le16((23 << 11) | (59 << 5) | 29); *date = cpu_to_le16((127 << 9) | (12 << 5) | 31); if (time_cs) *time_cs = 199; return; } -#endif - day = second / SECS_PER_DAY - DAYS_DELTA; - year = day / 365; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; - if (year * 365 + leap_day > day) - year--; - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; - day -= year * 365 + leap_day; - - if (IS_LEAP_YEAR(year) && day == days_in_year[3]) { - month = 2; - } else { - if (IS_LEAP_YEAR(year) && day > days_in_year[3]) - day--; - for (month = 1; month < 12; month++) { - if (days_in_year[month + 1] > day) - break; - } - } - day -= days_in_year[month]; + /* from 1900 -> from 1980 */ + tm.tm_year -= 80; + /* 0~11 -> 1~12 */ + tm.tm_mon++; + /* 0~59 -> 0~29(2sec counts) */ + tm.tm_sec >>= 1; - *time = cpu_to_le16(((second / SECS_PER_HOUR) % 24) << 11 - | ((second / SECS_PER_MIN) % 60) << 5 - | (second % SECS_PER_MIN) >> 1); - *date = cpu_to_le16((year << 9) | (month << 5) | (day + 1)); + *time = cpu_to_le16(tm.tm_hour << 11 | tm.tm_min << 5 | tm.tm_sec); + *date = cpu_to_le16(tm.tm_year << 9 | tm.tm_mon << 5 | tm.tm_mday); if (time_cs) *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000; } @@ -285,4 +259,3 @@ int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) } return err; } - diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index e590242fa41a..3221a0c7944e 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c @@ -91,7 +91,7 @@ EXPORT_SYMBOL(fscache_object_destroy); */ static struct fscache_object *fscache_objlist_lookup(loff_t *_pos) { - struct fscache_object *pobj, *obj, *minobj = NULL; + struct fscache_object *pobj, *obj = NULL, *minobj = NULL; struct rb_node *p; unsigned long pos; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index f2feaa06bf26..cadc4ce48656 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -14,6 +14,7 @@ #include <linux/magic.h> #include <linux/sched.h> #include <linux/smp_lock.h> +#include <linux/bitmap.h> /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ @@ -115,15 +116,13 @@ static void hpfs_put_super(struct super_block *s) unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) { struct quad_buffer_head qbh; - unsigned *bits; - unsigned i, count; - if (!(bits = hpfs_map_4sectors(s, secno, &qbh, 4))) return 0; - count = 0; - for (i = 0; i < 2048 / sizeof(unsigned); i++) { - unsigned b; - if (!bits[i]) continue; - for (b = bits[i]; b; b>>=1) count += b & 1; - } + unsigned long *bits; + unsigned count; + + bits = hpfs_map_4sectors(s, secno, &qbh, 4); + if (!bits) + return 0; + count = bitmap_weight(bits, 2048 * BITS_PER_BYTE); hpfs_brelse4(&qbh); return count; } diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 090c556ffed2..3b6f2fa12cff 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -700,7 +700,8 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ struct jffs2_raw_inode ri; struct jffs2_node_frag *last_frag; union jffs2_device_node dev; - char *mdata = NULL, mdatalen = 0; + char *mdata = NULL; + int mdatalen = 0; uint32_t alloclen, ilen; int ret; diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 378991cfe40f..e22de8397b74 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -1284,7 +1284,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, f->target = NULL; mutex_unlock(&f->sem); jffs2_do_clear_inode(c, f); - return -ret; + return ret; } f->target[je32_to_cpu(latest_node->csize)] = '\0'; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 6caf1e1ee26d..800171dca53b 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -23,7 +23,7 @@ int jffs2_sum_init(struct jffs2_sb_info *c) { - uint32_t sum_size = max_t(uint32_t, c->sector_size, MAX_SUMMARY_SIZE); + uint32_t sum_size = min_t(uint32_t, c->sector_size, MAX_SUMMARY_SIZE); c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index deb2b132ae5e..3dae4a13f6e4 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -547,6 +547,9 @@ bail: * * called like this: dio->get_blocks(dio->inode, fs_startblk, * fs_count, map_bh, dio->rw == WRITE); + * + * Note that we never bother to allocate blocks here, and thus ignore the + * create argument. */ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) @@ -563,14 +566,6 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); - /* - * Any write past EOF is not allowed because we'd be extending. - */ - if (create && (iblock + max_blocks) > inode_blocks) { - ret = -EIO; - goto bail; - } - /* This figures out the size of the next contiguous block, and * our logical offset */ ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, @@ -582,15 +577,6 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, goto bail; } - if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno && create) { - ocfs2_error(inode->i_sb, - "Inode %llu has a hole at block %llu\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno, - (unsigned long long)iblock); - ret = -EROFS; - goto bail; - } - /* We should already CoW the refcounted extent. */ BUG_ON(ext_flags & OCFS2_EXT_REFCOUNTED); /* @@ -601,20 +587,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, */ if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN)) map_bh(bh_result, inode->i_sb, p_blkno); - else { - /* - * ocfs2_prepare_inode_for_write() should have caught - * the case where we'd be filling a hole and triggered - * a buffered write instead. - */ - if (create) { - ret = -EIO; - mlog_errno(ret); - goto bail; - } - + else clear_buffer_mapped(bh_result); - } /* make sure we don't map more than max_blocks blocks here as that's all the kernel will handle at this point. */ diff --git a/fs/proc/base.c b/fs/proc/base.c index 4df4a464a919..18d5cc62d8ed 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2266,7 +2266,7 @@ static const struct inode_operations proc_attr_dir_inode_operations = { #endif -#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) +#ifdef CONFIG_ELF_CORE static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -2623,7 +2623,7 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_FAULT_INJECTION REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), #endif -#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) +#ifdef CONFIG_ELF_CORE REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), #endif #ifdef CONFIG_TASK_IO_ACCOUNTING diff --git a/fs/proc/generic.c b/fs/proc/generic.c index fa678abc9db1..480cb1065eec 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -429,7 +429,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, unsigned int ino; ino = de->low_ino; - de_get(de); + pde_get(de); spin_unlock(&proc_subdir_lock); error = -EINVAL; inode = proc_get_inode(dir->i_sb, ino, de); @@ -445,7 +445,7 @@ out_unlock: return NULL; } if (de) - de_put(de); + pde_put(de); return ERR_PTR(error); } @@ -509,17 +509,17 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, struct proc_dir_entry *next; /* filldir passes info to user space */ - de_get(de); + pde_get(de); spin_unlock(&proc_subdir_lock); if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino, de->mode >> 12) < 0) { - de_put(de); + pde_put(de); goto out; } spin_lock(&proc_subdir_lock); filp->f_pos++; next = de->next; - de_put(de); + pde_put(de); de = next; } while (de); spin_unlock(&proc_subdir_lock); @@ -763,7 +763,7 @@ out: return NULL; } -void free_proc_entry(struct proc_dir_entry *de) +static void free_proc_entry(struct proc_dir_entry *de) { unsigned int ino = de->low_ino; @@ -777,6 +777,12 @@ void free_proc_entry(struct proc_dir_entry *de) kfree(de); } +void pde_put(struct proc_dir_entry *pde) +{ + if (atomic_dec_and_test(&pde->count)) + free_proc_entry(pde); +} + /* * Remove a /proc entry and free it if it's not currently in use. */ @@ -845,6 +851,5 @@ continue_removing: WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " "'%s/%s', leaking at least '%s'\n", __func__, de->parent->name, de->name, de->subdir->name); - if (atomic_dec_and_test(&de->count)) - free_proc_entry(de); + pde_put(de); } diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d78ade305541..445a02bcaab3 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -24,29 +24,6 @@ #include "internal.h" -struct proc_dir_entry *de_get(struct proc_dir_entry *de) -{ - atomic_inc(&de->count); - return de; -} - -/* - * Decrements the use count and checks for deferred deletion. - */ -void de_put(struct proc_dir_entry *de) -{ - if (!atomic_read(&de->count)) { - printk("de_put: entry %s already free!\n", de->name); - return; - } - - if (atomic_dec_and_test(&de->count)) - free_proc_entry(de); -} - -/* - * Decrement the use count of the proc_dir_entry. - */ static void proc_delete_inode(struct inode *inode) { struct proc_dir_entry *de; @@ -59,7 +36,7 @@ static void proc_delete_inode(struct inode *inode) /* Let go of any associated proc directory entry */ de = PROC_I(inode)->pde; if (de) - de_put(de); + pde_put(de); if (PROC_I(inode)->sysctl) sysctl_head_put(PROC_I(inode)->sysctl); clear_inode(inode); @@ -480,7 +457,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, } unlock_new_inode(inode); } else - de_put(de); + pde_put(de); return inode; } @@ -495,7 +472,7 @@ int proc_fill_super(struct super_block *s) s->s_op = &proc_sops; s->s_time_gran = 1; - de_get(&proc_root); + pde_get(&proc_root); root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); if (!root_inode) goto out_no_root; @@ -509,6 +486,6 @@ int proc_fill_super(struct super_block *s) out_no_root: printk("proc_read_super: get root inode failed\n"); iput(root_inode); - de_put(&proc_root); + pde_put(&proc_root); return -ENOMEM; } diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 753ca37002c8..1f24a3eddd12 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -61,8 +61,6 @@ extern const struct file_operations proc_pagemap_operations; extern const struct file_operations proc_net_operations; extern const struct inode_operations proc_net_inode_operations; -void free_proc_entry(struct proc_dir_entry *de); - void proc_init_inodecache(void); static inline struct pid *proc_pid(struct inode *inode) @@ -101,8 +99,12 @@ unsigned long task_vsize(struct mm_struct *); int task_statm(struct mm_struct *, int *, int *, int *, int *); void task_mem(struct seq_file *, struct mm_struct *); -struct proc_dir_entry *de_get(struct proc_dir_entry *de); -void de_put(struct proc_dir_entry *de); +static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) +{ + atomic_inc(&pde->count); + return pde; +} +void pde_put(struct proc_dir_entry *pde); extern struct vfsmount *proc_mnt; int proc_fill_super(struct super_block *); diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c index 32f5d131a644..22e0d60e53ef 100644 --- a/fs/qnx4/bitmap.c +++ b/fs/qnx4/bitmap.c @@ -17,13 +17,6 @@ #include <linux/bitops.h> #include "qnx4.h" -#if 0 -int qnx4_new_block(struct super_block *sb) -{ - return 0; -} -#endif /* 0 */ - static void count_bits(register const char *bmPart, register int size, int *const tf) { @@ -35,22 +28,7 @@ static void count_bits(register const char *bmPart, register int size, } do { b = *bmPart++; - if ((b & 1) == 0) - tot++; - if ((b & 2) == 0) - tot++; - if ((b & 4) == 0) - tot++; - if ((b & 8) == 0) - tot++; - if ((b & 16) == 0) - tot++; - if ((b & 32) == 0) - tot++; - if ((b & 64) == 0) - tot++; - if ((b & 128) == 0) - tot++; + tot += 8 - hweight8(b); size--; } while (size != 0); *tf = tot; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 449f5a66dd34..ebf3440d28ca 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -64,25 +64,7 @@ static struct buffer_head *qnx4_getblk(struct inode *inode, int nr, result = sb_getblk(inode->i_sb, nr); return result; } - if (!create) { - return NULL; - } -#if 0 - tmp = qnx4_new_block(inode->i_sb); - if (!tmp) { - return NULL; - } - result = sb_getblk(inode->i_sb, tmp); - if (tst) { - qnx4_free_block(inode->i_sb, tmp); - brelse(result); - goto repeat; - } - tst = tmp; -#endif - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - return result; + return NULL; } struct buffer_head *qnx4_bread(struct inode *inode, int block, int create) @@ -113,8 +95,6 @@ static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_h if ( phys ) { // logical block is before EOF map_bh(bh, inode->i_sb, phys); - } else if ( create ) { - // to be done. } return 0; } diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile index 6a9e30c041dd..792b3cb2cd18 100644 --- a/fs/reiserfs/Makefile +++ b/fs/reiserfs/Makefile @@ -7,7 +7,11 @@ obj-$(CONFIG_REISERFS_FS) += reiserfs.o reiserfs-objs := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o \ super.o prints.o objectid.o lbalance.o ibalance.o stree.o \ hashes.o tail_conversion.o journal.o resize.o \ - item_ops.o ioctl.o procfs.o xattr.o lock.o + item_ops.o ioctl.o xattr.o lock.o + +ifeq ($(CONFIG_REISERFS_PROC_INFO),y) +reiserfs-objs += procfs.o +endif ifeq ($(CONFIG_REISERFS_FS_XATTR),y) reiserfs-objs += xattr_user.o xattr_trusted.o diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index 9229e5514a4e..7a9981196c1c 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c @@ -17,8 +17,6 @@ #include <linux/init.h> #include <linux/proc_fs.h> -#ifdef CONFIG_REISERFS_PROC_INFO - /* * LOCKING: * @@ -48,14 +46,6 @@ static int show_version(struct seq_file *m, struct super_block *sb) return 0; } -int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset, - int count, int *eof, void *data) -{ - *start = buffer; - *eof = 1; - return 0; -} - #define SF( x ) ( r -> x ) #define SFP( x ) SF( s_proc_info_data.x ) #define SFPL( x ) SFP( x[ level ] ) @@ -538,19 +528,6 @@ int reiserfs_proc_info_done(struct super_block *sb) return 0; } -struct proc_dir_entry *reiserfs_proc_register_global(char *name, - read_proc_t * func) -{ - return (proc_info_root) ? create_proc_read_entry(name, 0, - proc_info_root, - func, NULL) : NULL; -} - -void reiserfs_proc_unregister_global(const char *name) -{ - remove_proc_entry(name, proc_info_root); -} - int reiserfs_proc_info_global_init(void) { if (proc_info_root == NULL) { @@ -572,48 +549,6 @@ int reiserfs_proc_info_global_done(void) } return 0; } - -/* REISERFS_PROC_INFO */ -#else - -int reiserfs_proc_info_init(struct super_block *sb) -{ - return 0; -} -int reiserfs_proc_info_done(struct super_block *sb) -{ - return 0; -} - -struct proc_dir_entry *reiserfs_proc_register_global(char *name, - read_proc_t * func) -{ - return NULL; -} - -void reiserfs_proc_unregister_global(const char *name) -{; -} - -int reiserfs_proc_info_global_init(void) -{ - return 0; -} -int reiserfs_proc_info_global_done(void) -{ - return 0; -} - -int reiserfs_global_version_in_proc(char *buffer, char **start, - off_t offset, - int count, int *eof, void *data) -{ - return 0; -} - -/* REISERFS_PROC_INFO */ -#endif - /* * Revision 1.1.8.2 2001/07/15 17:08:42 god * . use get_super() in procfs.c diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 339b0baf2af6..b4a7dd03bdb9 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2222,8 +2222,6 @@ static int __init init_reiserfs_fs(void) } reiserfs_proc_info_global_init(); - reiserfs_proc_register_global("version", - reiserfs_global_version_in_proc); ret = register_filesystem(&reiserfs_fs_type); @@ -2231,7 +2229,6 @@ static int __init init_reiserfs_fs(void) return 0; } - reiserfs_proc_unregister_global("version"); reiserfs_proc_info_global_done(); destroy_inodecache(); @@ -2240,7 +2237,6 @@ static int __init init_reiserfs_fs(void) static void __exit exit_reiserfs_fs(void) { - reiserfs_proc_unregister_global("version"); reiserfs_proc_info_global_done(); unregister_filesystem(&reiserfs_fs_type); destroy_inodecache(); diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 6f671f1ac271..22af68f8b682 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -70,13 +70,13 @@ static inline unsigned long ufs_dir_pages(struct inode *inode) return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; } -ino_t ufs_inode_by_name(struct inode *dir, struct dentry *dentry) +ino_t ufs_inode_by_name(struct inode *dir, struct qstr *qstr) { ino_t res = 0; struct ufs_dir_entry *de; struct page *page; - de = ufs_find_entry(dir, dentry, &page); + de = ufs_find_entry(dir, qstr, &page); if (de) { res = fs32_to_cpu(dir->i_sb, de->d_ino); ufs_put_page(page); @@ -249,12 +249,12 @@ struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p) * (as a parameter - res_dir). Page is returned mapped and unlocked. * Entry is guaranteed to be valid. */ -struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct dentry *dentry, +struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct qstr *qstr, struct page **res_page) { struct super_block *sb = dir->i_sb; - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; + const char *name = qstr->name; + int namelen = qstr->len; unsigned reclen = UFS_DIR_REC_LEN(namelen); unsigned long start, n; unsigned long npages = ufs_dir_pages(dir); diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 23119fe7ad62..4c26d9e8bc94 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -56,7 +56,7 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru return ERR_PTR(-ENAMETOOLONG); lock_kernel(); - ino = ufs_inode_by_name(dir, dentry); + ino = ufs_inode_by_name(dir, &dentry->d_name); if (ino) { inode = ufs_iget(dir->i_sb, ino); if (IS_ERR(inode)) { @@ -237,7 +237,7 @@ static int ufs_unlink(struct inode *dir, struct dentry *dentry) struct page *page; int err = -ENOENT; - de = ufs_find_entry(dir, dentry, &page); + de = ufs_find_entry(dir, &dentry->d_name, &page); if (!de) goto out; @@ -281,7 +281,7 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, struct ufs_dir_entry *old_de; int err = -ENOENT; - old_de = ufs_find_entry(old_dir, old_dentry, &old_page); + old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page); if (!old_de) goto out; @@ -301,7 +301,7 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, goto out_dir; err = -ENOENT; - new_de = ufs_find_entry(new_dir, new_dentry, &new_page); + new_de = ufs_find_entry(new_dir, &new_dentry->d_name, &new_page); if (!new_de) goto out_dir; inode_inc_link_count(old_inode); diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 5faed7954d0a..143c20bfb04b 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -66,6 +66,7 @@ */ +#include <linux/exportfs.h> #include <linux/module.h> #include <linux/bitops.h> @@ -96,6 +97,56 @@ #include "swab.h" #include "util.h" +static struct inode *ufs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) +{ + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + struct inode *inode; + + if (ino < UFS_ROOTINO || ino > uspi->s_ncg * uspi->s_ipg) + return ERR_PTR(-ESTALE); + + inode = ufs_iget(sb, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + if (generation && inode->i_generation != generation) { + iput(inode); + return ERR_PTR(-ESTALE); + } + return inode; +} + +static struct dentry *ufs_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, ufs_nfs_get_inode); +} + +static struct dentry *ufs_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_parent(sb, fid, fh_len, fh_type, ufs_nfs_get_inode); +} + +static struct dentry *ufs_get_parent(struct dentry *child) +{ + struct qstr dot_dot = { + .name = "..", + .len = 2, + }; + ino_t ino; + + ino = ufs_inode_by_name(child->d_inode, &dot_dot); + if (!ino) + return ERR_PTR(-ENOENT); + return d_obtain_alias(ufs_iget(child->d_inode->i_sb, ino)); +} + +static const struct export_operations ufs_export_ops = { + .fh_to_dentry = ufs_fh_to_dentry, + .fh_to_parent = ufs_fh_to_parent, + .get_parent = ufs_get_parent, +}; + #ifdef CONFIG_UFS_DEBUG /* * Print contents of ufs_super_block, useful for debugging @@ -990,6 +1041,7 @@ magic_found: * Read ufs_super_block into internal data structures */ sb->s_op = &ufs_super_ops; + sb->s_export_op = &ufs_export_ops; sb->dq_op = NULL; /***/ sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic); diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 644e77e13599..0b4c39bc0d9e 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -86,9 +86,9 @@ extern void ufs_put_cylinder (struct super_block *, unsigned); /* dir.c */ extern const struct inode_operations ufs_dir_inode_operations; extern int ufs_add_link (struct dentry *, struct inode *); -extern ino_t ufs_inode_by_name(struct inode *, struct dentry *); +extern ino_t ufs_inode_by_name(struct inode *, struct qstr *); extern int ufs_make_empty(struct inode *, struct inode *); -extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct dentry *, struct page **); +extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct qstr *, struct page **); extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *); extern int ufs_empty_dir (struct inode *); extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **); diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index d798c54296eb..66abe36c1213 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -1474,19 +1474,13 @@ xfs_vm_direct_IO( bdev = xfs_find_bdev_for_inode(XFS_I(inode)); - if (rw == WRITE) { - iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN); - ret = blockdev_direct_IO_own_locking(rw, iocb, inode, - bdev, iov, offset, nr_segs, - xfs_get_blocks_direct, - xfs_end_io_direct); - } else { - iocb->private = xfs_alloc_ioend(inode, IOMAP_READ); - ret = blockdev_direct_IO_no_locking(rw, iocb, inode, - bdev, iov, offset, nr_segs, - xfs_get_blocks_direct, - xfs_end_io_direct); - } + iocb->private = xfs_alloc_ioend(inode, rw == WRITE ? + IOMAP_UNWRITTEN : IOMAP_READ); + + ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov, + offset, nr_segs, + xfs_get_blocks_direct, + xfs_end_io_direct); if (unlikely(ret != -EIOCBQUEUED && iocb->private)) xfs_destroy_ioend(iocb->private); |