linux-bk/fs/dnotify.c
<<
>>
Prefs
   1/*
   2 * Directory notifications for Linux.
   3 *
   4 * Copyright (C) 2000,2001,2002 Stephen Rothwell
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License as published by the
   8 * Free Software Foundation; either version 2, or (at your option) any
   9 * later version.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * General Public License for more details.
  15 */
  16#include <linux/fs.h>
  17#include <linux/sched.h>
  18#include <linux/dnotify.h>
  19#include <linux/init.h>
  20#include <linux/spinlock.h>
  21#include <linux/slab.h>
  22
  23extern void send_sigio(struct fown_struct *fown, int fd, int band);
  24
  25int dir_notify_enable = 1;
  26
  27static rwlock_t dn_lock = RW_LOCK_UNLOCKED;
  28static kmem_cache_t *dn_cache;
  29
  30static void redo_inode_mask(struct inode *inode)
  31{
  32        unsigned long new_mask;
  33        struct dnotify_struct *dn;
  34
  35        new_mask = 0;
  36        for (dn = inode->i_dnotify; dn != NULL; dn = dn->dn_next)
  37                new_mask |= dn->dn_mask & ~DN_MULTISHOT;
  38        inode->i_dnotify_mask = new_mask;
  39}
  40
  41void dnotify_flush(struct file *filp, fl_owner_t id)
  42{
  43        struct dnotify_struct *dn;
  44        struct dnotify_struct **prev;
  45        struct inode *inode;
  46
  47        inode = filp->f_dentry->d_inode;
  48        if (!S_ISDIR(inode->i_mode))
  49                return;
  50        write_lock(&dn_lock);
  51        prev = &inode->i_dnotify;
  52        while ((dn = *prev) != NULL) {
  53                if ((dn->dn_owner == id) && (dn->dn_filp == filp)) {
  54                        *prev = dn->dn_next;
  55                        redo_inode_mask(inode);
  56                        kmem_cache_free(dn_cache, dn);
  57                        break;
  58                }
  59                prev = &dn->dn_next;
  60        }
  61        write_unlock(&dn_lock);
  62}
  63
  64int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
  65{
  66        struct dnotify_struct *dn;
  67        struct dnotify_struct *odn;
  68        struct dnotify_struct **prev;
  69        struct inode *inode;
  70        fl_owner_t id = current->files;
  71        int error = 0;
  72
  73        if ((arg & ~DN_MULTISHOT) == 0) {
  74                dnotify_flush(filp, id);
  75                return 0;
  76        }
  77        if (!dir_notify_enable)
  78                return -EINVAL;
  79        inode = filp->f_dentry->d_inode;
  80        if (!S_ISDIR(inode->i_mode))
  81                return -ENOTDIR;
  82        dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
  83        if (dn == NULL)
  84                return -ENOMEM;
  85        write_lock(&dn_lock);
  86        prev = &inode->i_dnotify;
  87        while ((odn = *prev) != NULL) {
  88                if ((odn->dn_owner == id) && (odn->dn_filp == filp)) {
  89                        odn->dn_fd = fd;
  90                        odn->dn_mask |= arg;
  91                        inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
  92                        goto out_free;
  93                }
  94                prev = &odn->dn_next;
  95        }
  96
  97        error = f_setown(filp, current->pid, 1);
  98        if (error)
  99                goto out_free;
 100
 101        dn->dn_mask = arg;
 102        dn->dn_fd = fd;
 103        dn->dn_filp = filp;
 104        dn->dn_owner = id;
 105        inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
 106        dn->dn_next = inode->i_dnotify;
 107        inode->i_dnotify = dn;
 108out:
 109        write_unlock(&dn_lock);
 110        return error;
 111out_free:
 112        kmem_cache_free(dn_cache, dn);
 113        goto out;
 114}
 115
 116void __inode_dir_notify(struct inode *inode, unsigned long event)
 117{
 118        struct dnotify_struct * dn;
 119        struct dnotify_struct **prev;
 120        struct fown_struct *    fown;
 121        int                     changed = 0;
 122
 123        write_lock(&dn_lock);
 124        prev = &inode->i_dnotify;
 125        while ((dn = *prev) != NULL) {
 126                if ((dn->dn_mask & event) == 0) {
 127                        prev = &dn->dn_next;
 128                        continue;
 129                }
 130                fown = &dn->dn_filp->f_owner;
 131                send_sigio(fown, dn->dn_fd, POLL_MSG);
 132                if (dn->dn_mask & DN_MULTISHOT)
 133                        prev = &dn->dn_next;
 134                else {
 135                        *prev = dn->dn_next;
 136                        changed = 1;
 137                        kmem_cache_free(dn_cache, dn);
 138                }
 139        }
 140        if (changed)
 141                redo_inode_mask(inode);
 142        write_unlock(&dn_lock);
 143}
 144
 145static int __init dnotify_init(void)
 146{
 147        dn_cache = kmem_cache_create("dnotify cache",
 148                sizeof(struct dnotify_struct), 0, 0, NULL, NULL);
 149        if (!dn_cache)
 150                panic("cannot create dnotify slab cache");
 151        return 0;
 152}
 153
 154module_init(dnotify_init)
 155
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.