162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Directory notifications for Linux. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2000,2001,2002 Stephen Rothwell 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2009 Eric Paris <Red Hat Inc> 862306a36Sopenharmony_ci * dnotify was largly rewritten to use the new fsnotify infrastructure 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/sched.h> 1362306a36Sopenharmony_ci#include <linux/sched/signal.h> 1462306a36Sopenharmony_ci#include <linux/dnotify.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/security.h> 1762306a36Sopenharmony_ci#include <linux/spinlock.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/fdtable.h> 2062306a36Sopenharmony_ci#include <linux/fsnotify_backend.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic int dir_notify_enable __read_mostly = 1; 2362306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 2462306a36Sopenharmony_cistatic struct ctl_table dnotify_sysctls[] = { 2562306a36Sopenharmony_ci { 2662306a36Sopenharmony_ci .procname = "dir-notify-enable", 2762306a36Sopenharmony_ci .data = &dir_notify_enable, 2862306a36Sopenharmony_ci .maxlen = sizeof(int), 2962306a36Sopenharmony_ci .mode = 0644, 3062306a36Sopenharmony_ci .proc_handler = proc_dointvec, 3162306a36Sopenharmony_ci }, 3262306a36Sopenharmony_ci {} 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_cistatic void __init dnotify_sysctl_init(void) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci register_sysctl_init("fs", dnotify_sysctls); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci#else 3962306a36Sopenharmony_ci#define dnotify_sysctl_init() do { } while (0) 4062306a36Sopenharmony_ci#endif 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic struct kmem_cache *dnotify_struct_cache __read_mostly; 4362306a36Sopenharmony_cistatic struct kmem_cache *dnotify_mark_cache __read_mostly; 4462306a36Sopenharmony_cistatic struct fsnotify_group *dnotify_group __read_mostly; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * dnotify will attach one of these to each inode (i_fsnotify_marks) which 4862306a36Sopenharmony_ci * is being watched by dnotify. If multiple userspace applications are watching 4962306a36Sopenharmony_ci * the same directory with dnotify their information is chained in dn 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistruct dnotify_mark { 5262306a36Sopenharmony_ci struct fsnotify_mark fsn_mark; 5362306a36Sopenharmony_ci struct dnotify_struct *dn; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * When a process starts or stops watching an inode the set of events which 5862306a36Sopenharmony_ci * dnotify cares about for that inode may change. This function runs the 5962306a36Sopenharmony_ci * list of everything receiving dnotify events about this directory and calculates 6062306a36Sopenharmony_ci * the set of all those events. After it updates what dnotify is interested in 6162306a36Sopenharmony_ci * it calls the fsnotify function so it can update the set of all events relevant 6262306a36Sopenharmony_ci * to this inode. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistatic void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci __u32 new_mask = 0; 6762306a36Sopenharmony_ci struct dnotify_struct *dn; 6862306a36Sopenharmony_ci struct dnotify_mark *dn_mark = container_of(fsn_mark, 6962306a36Sopenharmony_ci struct dnotify_mark, 7062306a36Sopenharmony_ci fsn_mark); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci assert_spin_locked(&fsn_mark->lock); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (dn = dn_mark->dn; dn != NULL; dn = dn->dn_next) 7562306a36Sopenharmony_ci new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT); 7662306a36Sopenharmony_ci if (fsn_mark->mask == new_mask) 7762306a36Sopenharmony_ci return; 7862306a36Sopenharmony_ci fsn_mark->mask = new_mask; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci fsnotify_recalc_mask(fsn_mark->connector); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* 8462306a36Sopenharmony_ci * Mains fsnotify call where events are delivered to dnotify. 8562306a36Sopenharmony_ci * Find the dnotify mark on the relevant inode, run the list of dnotify structs 8662306a36Sopenharmony_ci * on that mark and determine which of them has expressed interest in receiving 8762306a36Sopenharmony_ci * events of this type. When found send the correct process and signal and 8862306a36Sopenharmony_ci * destroy the dnotify struct if it was not registered to receive multiple 8962306a36Sopenharmony_ci * events. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic int dnotify_handle_event(struct fsnotify_mark *inode_mark, u32 mask, 9262306a36Sopenharmony_ci struct inode *inode, struct inode *dir, 9362306a36Sopenharmony_ci const struct qstr *name, u32 cookie) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct dnotify_mark *dn_mark; 9662306a36Sopenharmony_ci struct dnotify_struct *dn; 9762306a36Sopenharmony_ci struct dnotify_struct **prev; 9862306a36Sopenharmony_ci struct fown_struct *fown; 9962306a36Sopenharmony_ci __u32 test_mask = mask & ~FS_EVENT_ON_CHILD; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* not a dir, dnotify doesn't care */ 10262306a36Sopenharmony_ci if (!dir && !(mask & FS_ISDIR)) 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci spin_lock(&inode_mark->lock); 10862306a36Sopenharmony_ci prev = &dn_mark->dn; 10962306a36Sopenharmony_ci while ((dn = *prev) != NULL) { 11062306a36Sopenharmony_ci if ((dn->dn_mask & test_mask) == 0) { 11162306a36Sopenharmony_ci prev = &dn->dn_next; 11262306a36Sopenharmony_ci continue; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci fown = &dn->dn_filp->f_owner; 11562306a36Sopenharmony_ci send_sigio(fown, dn->dn_fd, POLL_MSG); 11662306a36Sopenharmony_ci if (dn->dn_mask & FS_DN_MULTISHOT) 11762306a36Sopenharmony_ci prev = &dn->dn_next; 11862306a36Sopenharmony_ci else { 11962306a36Sopenharmony_ci *prev = dn->dn_next; 12062306a36Sopenharmony_ci kmem_cache_free(dnotify_struct_cache, dn); 12162306a36Sopenharmony_ci dnotify_recalc_inode_mask(inode_mark); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci spin_unlock(&inode_mark->lock); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void dnotify_free_mark(struct fsnotify_mark *fsn_mark) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct dnotify_mark *dn_mark = container_of(fsn_mark, 13362306a36Sopenharmony_ci struct dnotify_mark, 13462306a36Sopenharmony_ci fsn_mark); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci BUG_ON(dn_mark->dn); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci kmem_cache_free(dnotify_mark_cache, dn_mark); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const struct fsnotify_ops dnotify_fsnotify_ops = { 14262306a36Sopenharmony_ci .handle_inode_event = dnotify_handle_event, 14362306a36Sopenharmony_ci .free_mark = dnotify_free_mark, 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * Called every time a file is closed. Looks first for a dnotify mark on the 14862306a36Sopenharmony_ci * inode. If one is found run all of the ->dn structures attached to that 14962306a36Sopenharmony_ci * mark for one relevant to this process closing the file and remove that 15062306a36Sopenharmony_ci * dnotify_struct. If that was the last dnotify_struct also remove the 15162306a36Sopenharmony_ci * fsnotify_mark. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_civoid dnotify_flush(struct file *filp, fl_owner_t id) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct fsnotify_mark *fsn_mark; 15662306a36Sopenharmony_ci struct dnotify_mark *dn_mark; 15762306a36Sopenharmony_ci struct dnotify_struct *dn; 15862306a36Sopenharmony_ci struct dnotify_struct **prev; 15962306a36Sopenharmony_ci struct inode *inode; 16062306a36Sopenharmony_ci bool free = false; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci inode = file_inode(filp); 16362306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) 16462306a36Sopenharmony_ci return; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group); 16762306a36Sopenharmony_ci if (!fsn_mark) 16862306a36Sopenharmony_ci return; 16962306a36Sopenharmony_ci dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci fsnotify_group_lock(dnotify_group); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci spin_lock(&fsn_mark->lock); 17462306a36Sopenharmony_ci prev = &dn_mark->dn; 17562306a36Sopenharmony_ci while ((dn = *prev) != NULL) { 17662306a36Sopenharmony_ci if ((dn->dn_owner == id) && (dn->dn_filp == filp)) { 17762306a36Sopenharmony_ci *prev = dn->dn_next; 17862306a36Sopenharmony_ci kmem_cache_free(dnotify_struct_cache, dn); 17962306a36Sopenharmony_ci dnotify_recalc_inode_mask(fsn_mark); 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci prev = &dn->dn_next; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci spin_unlock(&fsn_mark->lock); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* nothing else could have found us thanks to the dnotify_groups 18862306a36Sopenharmony_ci mark_mutex */ 18962306a36Sopenharmony_ci if (dn_mark->dn == NULL) { 19062306a36Sopenharmony_ci fsnotify_detach_mark(fsn_mark); 19162306a36Sopenharmony_ci free = true; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci fsnotify_group_unlock(dnotify_group); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (free) 19762306a36Sopenharmony_ci fsnotify_free_mark(fsn_mark); 19862306a36Sopenharmony_ci fsnotify_put_mark(fsn_mark); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/* this conversion is done only at watch creation */ 20262306a36Sopenharmony_cistatic __u32 convert_arg(unsigned int arg) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci __u32 new_mask = FS_EVENT_ON_CHILD; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (arg & DN_MULTISHOT) 20762306a36Sopenharmony_ci new_mask |= FS_DN_MULTISHOT; 20862306a36Sopenharmony_ci if (arg & DN_DELETE) 20962306a36Sopenharmony_ci new_mask |= (FS_DELETE | FS_MOVED_FROM); 21062306a36Sopenharmony_ci if (arg & DN_MODIFY) 21162306a36Sopenharmony_ci new_mask |= FS_MODIFY; 21262306a36Sopenharmony_ci if (arg & DN_ACCESS) 21362306a36Sopenharmony_ci new_mask |= FS_ACCESS; 21462306a36Sopenharmony_ci if (arg & DN_ATTRIB) 21562306a36Sopenharmony_ci new_mask |= FS_ATTRIB; 21662306a36Sopenharmony_ci if (arg & DN_RENAME) 21762306a36Sopenharmony_ci new_mask |= FS_RENAME; 21862306a36Sopenharmony_ci if (arg & DN_CREATE) 21962306a36Sopenharmony_ci new_mask |= (FS_CREATE | FS_MOVED_TO); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return new_mask; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/* 22562306a36Sopenharmony_ci * If multiple processes watch the same inode with dnotify there is only one 22662306a36Sopenharmony_ci * dnotify mark in inode->i_fsnotify_marks but we chain a dnotify_struct 22762306a36Sopenharmony_ci * onto that mark. This function either attaches the new dnotify_struct onto 22862306a36Sopenharmony_ci * that list, or it |= the mask onto an existing dnofiy_struct. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_cistatic int attach_dn(struct dnotify_struct *dn, struct dnotify_mark *dn_mark, 23162306a36Sopenharmony_ci fl_owner_t id, int fd, struct file *filp, __u32 mask) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct dnotify_struct *odn; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci odn = dn_mark->dn; 23662306a36Sopenharmony_ci while (odn != NULL) { 23762306a36Sopenharmony_ci /* adding more events to existing dnofiy_struct? */ 23862306a36Sopenharmony_ci if ((odn->dn_owner == id) && (odn->dn_filp == filp)) { 23962306a36Sopenharmony_ci odn->dn_fd = fd; 24062306a36Sopenharmony_ci odn->dn_mask |= mask; 24162306a36Sopenharmony_ci return -EEXIST; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci odn = odn->dn_next; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci dn->dn_mask = mask; 24762306a36Sopenharmony_ci dn->dn_fd = fd; 24862306a36Sopenharmony_ci dn->dn_filp = filp; 24962306a36Sopenharmony_ci dn->dn_owner = id; 25062306a36Sopenharmony_ci dn->dn_next = dn_mark->dn; 25162306a36Sopenharmony_ci dn_mark->dn = dn; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * When a process calls fcntl to attach a dnotify watch to a directory it ends 25862306a36Sopenharmony_ci * up here. Allocate both a mark for fsnotify to add and a dnotify_struct to be 25962306a36Sopenharmony_ci * attached to the fsnotify_mark. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ciint fcntl_dirnotify(int fd, struct file *filp, unsigned int arg) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct dnotify_mark *new_dn_mark, *dn_mark; 26462306a36Sopenharmony_ci struct fsnotify_mark *new_fsn_mark, *fsn_mark; 26562306a36Sopenharmony_ci struct dnotify_struct *dn; 26662306a36Sopenharmony_ci struct inode *inode; 26762306a36Sopenharmony_ci fl_owner_t id = current->files; 26862306a36Sopenharmony_ci struct file *f; 26962306a36Sopenharmony_ci int destroy = 0, error = 0; 27062306a36Sopenharmony_ci __u32 mask; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* we use these to tell if we need to kfree */ 27362306a36Sopenharmony_ci new_fsn_mark = NULL; 27462306a36Sopenharmony_ci dn = NULL; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (!dir_notify_enable) { 27762306a36Sopenharmony_ci error = -EINVAL; 27862306a36Sopenharmony_ci goto out_err; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* a 0 mask means we are explicitly removing the watch */ 28262306a36Sopenharmony_ci if ((arg & ~DN_MULTISHOT) == 0) { 28362306a36Sopenharmony_ci dnotify_flush(filp, id); 28462306a36Sopenharmony_ci error = 0; 28562306a36Sopenharmony_ci goto out_err; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* dnotify only works on directories */ 28962306a36Sopenharmony_ci inode = file_inode(filp); 29062306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) { 29162306a36Sopenharmony_ci error = -ENOTDIR; 29262306a36Sopenharmony_ci goto out_err; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* 29662306a36Sopenharmony_ci * convert the userspace DN_* "arg" to the internal FS_* 29762306a36Sopenharmony_ci * defined in fsnotify 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_ci mask = convert_arg(arg); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci error = security_path_notify(&filp->f_path, mask, 30262306a36Sopenharmony_ci FSNOTIFY_OBJ_TYPE_INODE); 30362306a36Sopenharmony_ci if (error) 30462306a36Sopenharmony_ci goto out_err; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* expect most fcntl to add new rather than augment old */ 30762306a36Sopenharmony_ci dn = kmem_cache_alloc(dnotify_struct_cache, GFP_KERNEL); 30862306a36Sopenharmony_ci if (!dn) { 30962306a36Sopenharmony_ci error = -ENOMEM; 31062306a36Sopenharmony_ci goto out_err; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* new fsnotify mark, we expect most fcntl calls to add a new mark */ 31462306a36Sopenharmony_ci new_dn_mark = kmem_cache_alloc(dnotify_mark_cache, GFP_KERNEL); 31562306a36Sopenharmony_ci if (!new_dn_mark) { 31662306a36Sopenharmony_ci error = -ENOMEM; 31762306a36Sopenharmony_ci goto out_err; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* set up the new_fsn_mark and new_dn_mark */ 32162306a36Sopenharmony_ci new_fsn_mark = &new_dn_mark->fsn_mark; 32262306a36Sopenharmony_ci fsnotify_init_mark(new_fsn_mark, dnotify_group); 32362306a36Sopenharmony_ci new_fsn_mark->mask = mask; 32462306a36Sopenharmony_ci new_dn_mark->dn = NULL; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* this is needed to prevent the fcntl/close race described below */ 32762306a36Sopenharmony_ci fsnotify_group_lock(dnotify_group); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* add the new_fsn_mark or find an old one. */ 33062306a36Sopenharmony_ci fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group); 33162306a36Sopenharmony_ci if (fsn_mark) { 33262306a36Sopenharmony_ci dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); 33362306a36Sopenharmony_ci spin_lock(&fsn_mark->lock); 33462306a36Sopenharmony_ci } else { 33562306a36Sopenharmony_ci error = fsnotify_add_inode_mark_locked(new_fsn_mark, inode, 0); 33662306a36Sopenharmony_ci if (error) { 33762306a36Sopenharmony_ci fsnotify_group_unlock(dnotify_group); 33862306a36Sopenharmony_ci goto out_err; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci spin_lock(&new_fsn_mark->lock); 34162306a36Sopenharmony_ci fsn_mark = new_fsn_mark; 34262306a36Sopenharmony_ci dn_mark = new_dn_mark; 34362306a36Sopenharmony_ci /* we used new_fsn_mark, so don't free it */ 34462306a36Sopenharmony_ci new_fsn_mark = NULL; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci rcu_read_lock(); 34862306a36Sopenharmony_ci f = lookup_fd_rcu(fd); 34962306a36Sopenharmony_ci rcu_read_unlock(); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* if (f != filp) means that we lost a race and another task/thread 35262306a36Sopenharmony_ci * actually closed the fd we are still playing with before we grabbed 35362306a36Sopenharmony_ci * the dnotify_groups mark_mutex and fsn_mark->lock. Since closing the 35462306a36Sopenharmony_ci * fd is the only time we clean up the marks we need to get our mark 35562306a36Sopenharmony_ci * off the list. */ 35662306a36Sopenharmony_ci if (f != filp) { 35762306a36Sopenharmony_ci /* if we added ourselves, shoot ourselves, it's possible that 35862306a36Sopenharmony_ci * the flush actually did shoot this fsn_mark. That's fine too 35962306a36Sopenharmony_ci * since multiple calls to destroy_mark is perfectly safe, if 36062306a36Sopenharmony_ci * we found a dn_mark already attached to the inode, just sod 36162306a36Sopenharmony_ci * off silently as the flush at close time dealt with it. 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci if (dn_mark == new_dn_mark) 36462306a36Sopenharmony_ci destroy = 1; 36562306a36Sopenharmony_ci error = 0; 36662306a36Sopenharmony_ci goto out; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci __f_setown(filp, task_pid(current), PIDTYPE_TGID, 0); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci error = attach_dn(dn, dn_mark, id, fd, filp, mask); 37262306a36Sopenharmony_ci /* !error means that we attached the dn to the dn_mark, so don't free it */ 37362306a36Sopenharmony_ci if (!error) 37462306a36Sopenharmony_ci dn = NULL; 37562306a36Sopenharmony_ci /* -EEXIST means that we didn't add this new dn and used an old one. 37662306a36Sopenharmony_ci * that isn't an error (and the unused dn should be freed) */ 37762306a36Sopenharmony_ci else if (error == -EEXIST) 37862306a36Sopenharmony_ci error = 0; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci dnotify_recalc_inode_mask(fsn_mark); 38162306a36Sopenharmony_ciout: 38262306a36Sopenharmony_ci spin_unlock(&fsn_mark->lock); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (destroy) 38562306a36Sopenharmony_ci fsnotify_detach_mark(fsn_mark); 38662306a36Sopenharmony_ci fsnotify_group_unlock(dnotify_group); 38762306a36Sopenharmony_ci if (destroy) 38862306a36Sopenharmony_ci fsnotify_free_mark(fsn_mark); 38962306a36Sopenharmony_ci fsnotify_put_mark(fsn_mark); 39062306a36Sopenharmony_ciout_err: 39162306a36Sopenharmony_ci if (new_fsn_mark) 39262306a36Sopenharmony_ci fsnotify_put_mark(new_fsn_mark); 39362306a36Sopenharmony_ci if (dn) 39462306a36Sopenharmony_ci kmem_cache_free(dnotify_struct_cache, dn); 39562306a36Sopenharmony_ci return error; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int __init dnotify_init(void) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci dnotify_struct_cache = KMEM_CACHE(dnotify_struct, 40162306a36Sopenharmony_ci SLAB_PANIC|SLAB_ACCOUNT); 40262306a36Sopenharmony_ci dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 40562306a36Sopenharmony_ci FSNOTIFY_GROUP_NOFS); 40662306a36Sopenharmony_ci if (IS_ERR(dnotify_group)) 40762306a36Sopenharmony_ci panic("unable to allocate fsnotify group for dnotify\n"); 40862306a36Sopenharmony_ci dnotify_sysctl_init(); 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cimodule_init(dnotify_init) 413