X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fcifs%2Ffcntl.c;h=da12b482ebe5364d1bc4e6dba9bba25ffa25e12c;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=4403fc37855b83120460a787ae263450ca818728;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 4403fc378..da12b482e 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c @@ -27,71 +27,96 @@ #include "cifsproto.h" #include "cifs_unicode.h" #include "cifs_debug.h" +#include "cifsfs.h" -int cifs_directory_notify(unsigned long arg, struct file * file) +static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags) +{ + __u32 cifs_ntfy_flags = 0; + + /* No way on Linux VFS to ask to monitor xattr + changes (and no stream support either */ + if(fcntl_notify_flags & DN_ACCESS) { + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS; + } + if(fcntl_notify_flags & DN_MODIFY) { + /* What does this mean on directories? */ + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_SIZE; + } + if(fcntl_notify_flags & DN_CREATE) { + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_LAST_WRITE; + } + if(fcntl_notify_flags & DN_DELETE) { + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE; + } + if(fcntl_notify_flags & DN_RENAME) { + /* BB review this - checking various server behaviors */ + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_FILE_NAME; + } + if(fcntl_notify_flags & DN_ATTRIB) { + cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_SECURITY | + FILE_NOTIFY_CHANGE_ATTRIBUTES; + } +/* if(fcntl_notify_flags & DN_MULTISHOT) { + cifs_ntfy_flags |= ; + } */ /* BB fixme - not sure how to handle this with CIFS yet */ + + + return cifs_ntfy_flags; +} + +int cifs_dir_notify(struct file * file, unsigned long arg) { int xid; int rc = -EINVAL; + int oplock = FALSE; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; char *full_path = NULL; + __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; + __u16 netfid; - xid = GetXid(); - cifs_sb = CIFS_SB(file->f_dentry->d_sb); - pTcon = cifs_sb->tcon; - full_path = build_path_from_dentry(file->f_dentry); - cFYI(1,("cifs dir notify on file %s",full_path)); - /* CIFSSMBNotify */ - FreeXid(xid); - return rc; -} + if(experimEnabled == 0) + return 0; -long cifs_fcntl(int file_desc, unsigned int command, unsigned long arg, - struct file * file) -{ - /* Few few file control functions need to be specially mapped. So far - only: - F_NOTIFY (for directory change notification) - And eventually: - F_GETLEASE - F_SETLEASE - need to be mapped here. The others either already are mapped downstream - or do not need to go to the server (client only sideeffects): - F_DUPFD: - F_GETFD: - F_SETFD: - F_GETFL: - F_SETFL: - F_GETLK: - F_SETLK: - F_SETLKW: - F_GETOWN: - F_SETOWN: - F_GETSIG: - F_SETSIG: - */ - long rc = 0; + xid = GetXid(); + cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); + pTcon = cifs_sb->tcon; - cFYI(1,("cifs_fcntl: command %d with arg %lx",command,arg)); /* BB removeme BB */ + full_path = build_path_from_dentry(file->f_path.dentry); - switch (command) { - case F_NOTIFY: - /* let the local call have a chance to fail first */ - rc = generic_file_fcntl(file_desc,command,arg,file); - if(rc) - return rc; - else { - /* local call succeeded try to do remote notify to - pick up changes from other clients to server file */ - cifs_directory_notify(arg, file); - /* BB add case to long and return rc from above */ - return rc; + if(full_path == NULL) { + rc = -ENOMEM; + } else { + cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg)); + rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, + GENERIC_READ | SYNCHRONIZE, 0 /* create options */, + &netfid, &oplock,NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + /* BB fixme - add this handle to a notify handle list */ + if(rc) { + cFYI(1,("Could not open directory for notify")); + } else { + filter = convert_to_cifs_notify_flags(arg); + if(filter != 0) { + rc = CIFSSMBNotify(xid, pTcon, + 0 /* no subdirs */, netfid, + filter, file, arg & DN_MULTISHOT, + cifs_sb->local_nls); + } else { + rc = -EINVAL; + } + /* BB add code to close file eventually (at unmount + it would close automatically but may be a way + to do it easily when inode freed or when + notify info is cleared/changed */ + cFYI(1,("notify rc %d",rc)); } - break; - default: - break; } - return generic_file_fcntl(file_desc,command,arg,file); + + FreeXid(xid); + return rc; } -