X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fcifs%2Ffcntl.c;h=da12b482ebe5364d1bc4e6dba9bba25ffa25e12c;hb=refs%2Fheads%2Fvserver;hp=1469a406f6ad594898feeb8439fb148c70bbab07;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 1469a406f..da12b482e 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c @@ -27,8 +27,47 @@ #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; @@ -37,86 +76,47 @@ int cifs_directory_notify(unsigned long arg, struct file * file) struct cifsTconInfo *pTcon; char *full_path = NULL; __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; - __u16 netfid; + __u16 netfid; + + + if(experimEnabled == 0) + return 0; xid = GetXid(); - cifs_sb = CIFS_SB(file->f_dentry->d_sb); + cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); pTcon = cifs_sb->tcon; - down(&file->f_dentry->d_sb->s_vfs_rename_sem); - full_path = build_path_from_dentry(file->f_dentry); - up(&file->f_dentry->d_sb->s_vfs_rename_sem); + full_path = build_path_from_dentry(file->f_path.dentry); if(full_path == NULL) { rc = -ENOMEM; } else { - cFYI(1,("cifs dir notify on file %s",full_path)); + 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); + &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 { - rc = CIFSSMBNotify(xid, pTcon, 1 /* subdirs */, netfid, - filter, cifs_sb->local_nls); + 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)); } } FreeXid(xid); return rc; } - - -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; - - cFYI(1,("cifs_fcntl: command %d with arg %lx",command,arg)); /* BB removeme BB */ - - 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; - } - break; - default: - break; - } - return generic_file_fcntl(file_desc,command,arg,file); -} -