linux-old/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
  72        if ((arg & ~DN_MULTISHOT) == 0) {
  73                dnotify_flush(filp, id);
  74                return 0;
  75        }
  76        if (!dir_notify_enable)
  77                return -EINVAL;
  78        inode = filp->f_dentry->d_inode;
  79        if (!S_ISDIR(inode->i_mode))
  80                return -ENOTDIR;
  81        dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL);
  82        if (dn == NULL)
  83                return -ENOMEM;
  84        write_lock(&dn_lock);
  85        prev = &inode->i_dnotify;
  86        while ((odn = *prev) != NULL) {
  87                if ((odn->dn_owner == id) && (odn->dn_filp == filp)) {
  88                        odn->dn_fd = fd;
  89                        odn->dn_mask |= arg;
  90                        inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
  91                        kmem_cache_free(dn_cache, dn);
  92                        goto out;
  93                }
  94                prev = &odn->dn_next;
  95        }
  96        filp->f_owner.pid = current->pid;
  97        filp->f_owner.uid = current->uid;
  98        filp->f_owner.euid = current->euid;
  99        dn->dn_mask = arg;
 100        dn->dn_fd = fd;
 101        dn->dn_filp = filp;
 102        dn->dn_owner = id;
 103        inode->i_dnotify_mask |= arg & ~DN_MULTISHOT;
 104        dn->dn_next = inode->i_dnotify;
 105        inode->i_dnotify = dn;
 106out:
 107        write_unlock(&dn_lock);
 108        return 0;
 109}
 110
 111void __inode_dir_notify(struct inode *inode, unsigned long event)
 112{
 113        struct dnotify_struct * dn;
 114        struct dnotify_struct **prev;
 115        struct fown_struct *    fown;
 116        int                     changed = 0;
 117
 118        write_lock(&dn_lock);
 119        prev = &inode->i_dnotify;
 120        while ((dn = *prev) != NULL) {
 121                if ((dn->dn_mask & event) == 0) {
 122                        prev = &dn->dn_next;
 123                        continue;
 124                }
 125                fown = &dn->dn_filp->f_owner;
 126                if (fown->pid)
 127                        send_sigio(fown, dn->dn_fd, POLL_MSG);
 128                if (dn->dn_mask & DN_MULTISHOT)
 129                        prev = &dn->dn_next;
 130                else {
 131                        *prev = dn->dn_next;
 132                        changed = 1;
 133                        kmem_cache_free(dn_cache, dn);
 134                }
 135        }
 136        if (changed)
 137                redo_inode_mask(inode);
 138        write_unlock(&dn_lock);
 139}
 140
 141static int __init dnotify_init(void)
 142{
 143        dn_cache = kmem_cache_create("dnotify_cache",
 144                sizeof(struct dnotify_struct), 0, 0, NULL, NULL);
 145        if (!dn_cache)
 146                panic("cannot create dnotify slab cache");
 147        return 0;
 148}
 149
 150module_init(dnotify_init)
 151
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.